Initial checkin of veejay 1.4

git-svn-id: svn://code.dyne.org/veejay/trunk@1172 eb8d1916-c9e9-0310-b8de-cf0c9472ead5
This commit is contained in:
Niels Elburg
2008-11-10 20:16:24 +00:00
parent d81258c54c
commit d8e6f98d53
793 changed files with 244409 additions and 0 deletions

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1,16 @@
INCLUDES = -I$(top_srcdir)/libOSC -I$(includedir)
AM_CFLAGS=$(OP_CFLAGS)
OSC_LIB_FILE = libOSC.la
noinst_LTLIBRARIES = $(OSC_LIB_FILE)
libOSC_la_CFLAGS = $(AM_CFLAGS)
libOSC_la_SOURCES = OSC-address-space.c \
OSC-callbacklist.c \
OSC-drop.c \
OSC-pattern-match.c \
OSC-priority-queue.c \
OSC-receive.c \
OSC-string-help.c \
OSC-common.c \
OSC-timetag.c \
NetworkReturnAddress.c

View File

View File

@@ -0,0 +1,58 @@
/*
Copyright <20> 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
*/
/*
NetworkReturnAddress.c
This version implements UDP return addresses on SGI
Matt Wright,
9/11/98
*/
#include <libOSC/OSC-common.h>
#include <libOSC/OSC-timetag.h>
#include <libOSC/OSC-address-space.h>
#include <libOSC/NetworkReturnAddress.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <libOSC/NetworkUDP.h>
int SizeOfNetworkReturnAddress(void) {
return sizeof(struct NetworkReturnAddressStruct);
}
Boolean NetworkSendReturnMessage(NetworkReturnAddressPtr addr,
int n,
void *buf) {
if (addr == 0) return FALSE;
return n == sendto(addr->sockfd, buf, n, 0, &(addr->cl_addr), addr->clilen);
}

View File

@@ -0,0 +1,52 @@
/*
Copyright <20> 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
*/
/*
NetworkReturnAddress.h
API that the OSC Kit uses to deal with network return addresses. You will
fill in parts of this file and write NetworkReturnAddress.c to implement
this API via whatever network services you use.
NB: This API is the only interface the Kit uses for dealing with network
addresses, but of course the part of the application that accepts incoming
packets needs to know about network return addresses so it can fill in the
correct return address when it receives a packet.
Matt Wright,
6/3/98
*/
/* Return sizeof(struct NetworkReturnAddressStruct). */
int SizeOfNetworkReturnAddress(void);
/* Send a packet back to the client, or do nothing if addr==0 */
Boolean NetworkSendReturnMessage(NetworkReturnAddressPtr addr,
int n,
void *buf);

View File

@@ -0,0 +1,7 @@
#include <netinet/in.h>
struct NetworkReturnAddressStruct {
struct sockaddr_in cl_addr;
int clilen;
int sockfd;
};

View File

@@ -0,0 +1,599 @@
/*
Copyright <20> 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-address-space.c
Matt Wright, 3/16/98
*/
#include <config.h>
#include <libOSC/OSC-common.h>
#include <libOSC/OSC-timetag.h>
#include <libOSC/OSC-address-space.h>
#include <string.h>
#include <stdio.h>
#define MAX_ALIASES_PER_CONTAINER 3
#define MAX_CHILDREN_PER_CONTAINER 20
#define MAX_METHODS_PER_CONTAINER 30
#define BASE_NUM_TO_REALLOCATE 10
struct OSCContainerStruct {
struct OSCContainerStruct *parent;
int numChildren;
Name childrenNames[MAX_CHILDREN_PER_CONTAINER];
struct OSCContainerStruct *children[MAX_CHILDREN_PER_CONTAINER];
int numMethods;
Name methodNames[MAX_METHODS_PER_CONTAINER];
OSCMethod methods[MAX_METHODS_PER_CONTAINER];
struct OSCContainerQueryResponseInfoStruct QueryResponseInfo;
struct OSCContainerStruct *next;
};
struct OSCMethodStruct {
methodCallback callback;
void *context;
struct OSCMethodQueryResponseInfoStruct QueryResponseInfo;
struct OSCMethodStruct *next;
};
/* Globals */
static Boolean Initialized = FALSE;
static OSCcontainer OSCTopLevelContainer;
static OSCcontainer freeContainers; /* Linked list via next field. */
static OSCMethod freeMethods; /* Linked list via next field. */
static void *(*RealTimeMemoryAllocator)(int numBytes);
/* Note: The free list of containers should actually be a "free forest", so
that all the subcontainers recursively under a freed container are
automatically freed.
FREE: just stick the freed subtree on the front of the list.
ALLOC: Take all the children of the first container on the list and
insert them in the free list, then return that first container.
*/
/************************ Initialization and Memory ************************/
static void MakeFreeContainersList(int n) {
int i;
for (i = 0; i+1 < n; ++i) {
freeContainers[i].next = &(freeContainers[i+1]);
}
freeContainers[n-1].next = 0;
}
static void MakeFreeMethodsList(int n) {
int i;
for (i = 0; i+1 < n; ++i) {
freeMethods[i].next = &(freeMethods[i+1]);
}
freeMethods[n-1].next = 0;
}
OSCcontainer OSCInitAddressSpace(struct OSCAddressSpaceMemoryTuner *t) {
int bytesNeeded;
if (Initialized)
fatal_error("OSCInitAddressSpace: already initialized!");
Initialized = TRUE;
RealTimeMemoryAllocator = t->RealTimeMemoryAllocator;
bytesNeeded = (1 + t->initNumContainers) * sizeof(*freeContainers);
freeContainers = (OSCcontainer) (*(t->InitTimeMemoryAllocator))(bytesNeeded);
if (freeContainers == 0) {
fatal_error("OSCInitAddressSpace: couldn't allocate %d bytes for %d containers",
bytesNeeded, t->initNumContainers);
}
OSCTopLevelContainer = &freeContainers[t->initNumContainers];
MakeFreeContainersList(t->initNumContainers);
bytesNeeded = t->initNumMethods * sizeof(*freeMethods);
freeMethods = (OSCMethod) (*(t->InitTimeMemoryAllocator))(bytesNeeded);
if (freeMethods == 0) {
fatal_error("OSCInitAddressSpace: couldn't allocate %d bytes for %d methods",
bytesNeeded, t->initNumMethods);
}
MakeFreeMethodsList(t->initNumMethods);
/* Initialize the top-level container */
OSCTopLevelContainer->parent = 0;
OSCTopLevelContainer->numChildren = 0;
OSCTopLevelContainer->numMethods = 0;
OSCTopLevelContainer->QueryResponseInfo.comment = "OSC top-level container";
OSCTopLevelContainer->next = 0;
return OSCTopLevelContainer;
}
/* Container and method memory management: linked lists of free objects */
static OSCcontainer AllocContainer(void) {
static int numExtraAllocs = 0;
OSCcontainer result;
if (freeContainers != 0) {
result = freeContainers;
freeContainers = freeContainers->next;
return result;
}
OSCWarning("Out of memory for containers; trying to allocate more in real time");
{
int num = BASE_NUM_TO_REALLOCATE * ++numExtraAllocs;
freeContainers = (*RealTimeMemoryAllocator)(num * sizeof(*freeContainers));
if (freeContainers == 0) {
OSCWarning("Real-time allocation failed");
return 0;
}
MakeFreeContainersList(num);
return AllocContainer();
}
}
//static void FreeContainer(OSCcontainer c) {
// c->next = freeContainers;
// freeContainers = c;
//}
static OSCMethod AllocMethod(void) {
static int numExtraAllocs = 0;
OSCMethod result;
if (freeMethods != 0) {
result = freeMethods;
freeMethods = freeMethods->next;
return result;
}
OSCWarning("Out of memory for methods; trying to allocate more in real time");
{
int num = BASE_NUM_TO_REALLOCATE * ++numExtraAllocs;
freeMethods = (*RealTimeMemoryAllocator)(num * sizeof(*freeMethods));
if (freeMethods == 0) {
OSCWarning("Real-time allocation failed");
return 0;
}
MakeFreeMethodsList(num);
return AllocMethod();
}
}
//static void FreeMethod(OSCMethod c) {
// c->next = freeMethods;
// freeMethods = c;
//}
/**************************** Containers ****************************/
/* Managing the tree of containers and subcontainers, with aliases */
void AddSubContainer(OSCcontainer parent, OSCcontainer child, Name name) {
if (parent->numChildren >= MAX_CHILDREN_PER_CONTAINER) {
fatal_error("AddSubContainer: exceeded MAX_CHILDREN_PER_CONTAINER (%d)\n"
"Increase the value in OSC-address-space.c and recompile.",
MAX_CHILDREN_PER_CONTAINER);
}
parent->childrenNames[parent->numChildren] = name;
parent->children[parent->numChildren] = child;
++(parent->numChildren);
}
Boolean OSCAddContainerAlias(OSCcontainer container, Name otherName) {
if (container->parent->numChildren >= MAX_CHILDREN_PER_CONTAINER) {
return FALSE;
}
AddSubContainer(container->parent, container, otherName);
return TRUE;
}
void RemoveSubContainer(OSCcontainer parent, OSCcontainer child) {
int i, numRemoved;
/* Remove every pointer to the container, even if it has multiple aliases */
numRemoved = 0;
for (i = 0; i < parent->numChildren; ++i) {
if (parent->children[i] != child) {
parent->children[i-numRemoved] = parent->children[i];
parent->childrenNames[i-numRemoved] = parent->childrenNames[i];
} else {
++numRemoved;
}
}
parent->numChildren -= numRemoved;
if (numRemoved == 0) {
fatal_error("RemoveSubContainer: subcontainer not found!\n");
}
}
Boolean OSCRemoveContainerAlias(OSCcontainer container, Name otherName) {
int i, j;
OSCcontainer parent = container->parent;
Boolean found = FALSE;
for (i = 0; i < parent->numChildren; ++i) {
if (parent->childrenNames[i] == otherName) {
if (parent->children[i] != container) {
fatal_error("OSCRemoveContainerAlias: %s is actually a sibling's name!",
otherName);
}
found = TRUE;
for (j = i+1; j < parent->numChildren; ++j) {
parent->children[j-1] = parent->children[j];
parent->childrenNames[j-1] = parent->childrenNames[j];
--(parent->numChildren);
}
}
}
if (!found) {
fatal_error("OSCRemoveContainerAlias: %s not found!", otherName);
}
/* Now make sure the child still exists under another name */
for (i = 0; i < parent->numChildren; ++i) {
if (parent->children[i] == container) return TRUE;
}
OSCWarning("OSCRemoveContainerAlias: %s was the last name for that subcontainer");
/* xxx should recursively free the container and its children... */
return TRUE;
}
OSCcontainer OSCNewContainer(Name name, OSCcontainer parent,
struct OSCContainerQueryResponseInfoStruct *QueryResponseInfo) {
OSCcontainer me;
me = AllocContainer();
if (me == 0) return 0;
if (strchr(name, '/') != NULL) {
OSCProblem("Container name \"%s\" contains a slash --- not good.",
name);
return 0;
}
me->parent = parent;
AddSubContainer(me->parent, me, name);
me->numChildren = 0;
me->numMethods = 0;
me->QueryResponseInfo = (*QueryResponseInfo);
return me;
}
static const char *ContainerName(OSCcontainer c) {
/* Return the first name associated with me in my parent's child list.
(Assume all later ones are aliases.) */
int i;
for (i = 0; i < c->parent->numChildren; ++i) {
if (c->parent->children[i] == c) {
return c->parent->childrenNames[i];
}
}
fatal_error("ContainerName: Container %p isn't in its parent's child list.", c);
return 0;
}
static int gasHelp(char *target, int maxlength, OSCcontainer c );
Boolean OSCGetAddressString(char *target, int maxLength, OSCcontainer c) {
int lenNeeded;
if (maxLength <= 1) return FALSE;
lenNeeded = gasHelp(target, maxLength-1, c) + 1; /* -1, +1 are for null char. */
if (lenNeeded > maxLength) {
OSCProblem("Address string too long (room for %d chars; need %d)",
maxLength, lenNeeded);
target[0] = '\0';
return FALSE;
}
return TRUE;
}
static int gasHelp(char *target, int maxLength, OSCcontainer c) {
int sublength, length;
const char *myName;
/* printf("*** gasHelp %s %d %p %s\n", target, maxLength, c, c->name); */
if (c == OSCTopLevelContainer) {
target[0] = '/';
target[1] = '\0';
return 1;
}
myName = ContainerName(c);
sublength = gasHelp(target, maxLength, c->parent);
length = sublength + strlen(myName) + 1; /* +1 is for trailing slash */
if (length > maxLength) {
return length;
}
strcpy(target+sublength, myName);
target[length-1] = '/';
target[length] = '\0';
return length;
}
/**************************** Methods ****************************/
#define LONG_ADDR_SIZE 1000 /* Just for error messages */
OSCMethod OSCNewMethod(Name name, OSCcontainer me, methodCallback callback,
void *context, struct OSCMethodQueryResponseInfoStruct *QueryResponseInfo) {
char addr[LONG_ADDR_SIZE];
OSCMethod m;
if (strchr(name, '/') != NULL) {
OSCProblem("Method name \"%s\" contains a slash --- not good.",
name);
return 0;
}
if (me->numMethods >= MAX_METHODS_PER_CONTAINER) {
addr[0] = '\0';
OSCGetAddressString(addr, LONG_ADDR_SIZE, me);
OSCProblem("OSCNewMethod: container %s already has %d methods; can't add another\n"
"Change MAX_METHODS_PER_CONTAINER in OSC-address-space.c and recompile.",
addr, me->numMethods);
return 0;
}
m = AllocMethod();
if (!m) return 0;
m->callback = callback;
m->context = context;
m->QueryResponseInfo = *QueryResponseInfo;
me->methodNames[me->numMethods] = name;
me->methods[me->numMethods] = m;
++(me->numMethods);
return m;
}
/**************************** Queries ****************************/
void OSCInitContainerQueryResponseInfo(struct OSCContainerQueryResponseInfoStruct *i) {
i->comment = 0;
}
void OSCInitMethodQueryResponseInfo(struct OSCMethodQueryResponseInfoStruct *i) {
i->description = 0;
i->pvq = 0;
}
/******************************* Debug ********************************/
static int ContainerAliases(OSCcontainer c, char *target) {
/* Write a space-delimited list of alias names in the given string,
and return the number */
int i, n;
if (c == OSCTopLevelContainer) return 0;
target[0] = '\0';
n = 0;
for (i = 0; i < c->parent->numChildren; ++i) {
if (c->parent->children[i] == c) {
if (n > 0) {
strcat(target, " ");
strcat(target, c->parent->childrenNames[i]);
}
++n;
}
}
if (n == 0) fatal_error("ContainerAliases: internal inconsistency");
return n-1;
}
#define BIG_ADDRESS 50
static void PrintHelp(OSCcontainer c) {
char addr[BIG_ADDRESS];
char aliasNames[1000];
int i, j, numAliases;
if (OSCGetAddressString(addr, BIG_ADDRESS, c) == FALSE) {
printf(" /.../%s", ContainerName(c));
} else {
printf(" %s", addr);
}
numAliases = ContainerAliases(c, aliasNames);
if (numAliases > 0) {
printf(" (%d aliases:%s)", numAliases, aliasNames);
}
printf("\n");
for (i = 0; i < c->numMethods; ++i) {
printf(" %s%s: %s\n", addr, c->methodNames[i],
c->methods[i]->QueryResponseInfo.description);
}
/* Forgive this quadratic kludge: */
for (i = 0; i < c->numChildren; ++i) {
int matches = 0;
for (j = 0; j < i; ++j) {
if (c->children[j] == c->children[i]) {
/* c->children[i] is just an alias to c->children[j],
which we already printed, so ignore it. */
matches ++;
}
}
if(matches == 0 ) PrintHelp(c->children[i]);
}
}
void OSCPrintWholeAddressSpace(void) {
printf("\n----- The OSC address space -----\n");
PrintHelp(OSCTopLevelContainer);
printf("...end of OSC address space.\n\n\n");
}
/***************************** Dispatching *****************************/
#include <libOSC/OSC-dispatch.h>
#include <libOSC/OSC-callbacklist.h>
#include <libOSC/OSC-pattern-match.h>
/* To do quick concatenation of singly-linked lists, we pass around
this data structure that points to the first and last elements: */
typedef struct callbackListEnds_struct {
callbackList begin;
callbackList end;
} callbackListEnds;
/* Helper proc. declarations */
static callbackListEnds DispatchSubMessage(char *pattern, OSCcontainer c);
static char *NextSlashOrNull(char *p);
callbackList OSCDispatchMessage(char *pattern) {
callbackListEnds result;
if (pattern[0] != '/') {
OSCProblem("Invalid address \"%s\" does not begin with /", pattern);
return 0;
}
result = DispatchSubMessage(pattern+1, OSCTopLevelContainer);
return result.begin;
}
#define LONG_ADDR_LEN 100
static callbackListEnds DispatchSubMessage(char *pattern, OSCcontainer c) {
callbackListEnds result;
char *nextSlash, *restOfPattern;
char offendingAddr[LONG_ADDR_LEN];
int i;
result.begin = result.end = 0;
nextSlash = NextSlashOrNull(pattern);
if (*nextSlash == '\0') {
/* Base case: the pattern names methods of this container. */
for (i = 0; i < c->numMethods; i++) {
if (PatternMatch(pattern, c->methodNames[i])) {
callbackList node = AllocCallbackListNode(c->methods[i]->callback,
c->methods[i]->context,
result.begin);
if (node == 0) {
/* Excuse the hairyness of the code to generate the error message. */
if (OSCGetAddressString(offendingAddr,
LONG_ADDR_LEN-strlen(c->methodNames[i]),
c)) {
strcat(offendingAddr, c->methodNames[i]);
} else {
strcpy(offendingAddr, c->methodNames[i]);
}
OSCWarning("No memory for callback node; not invoking %s",
offendingAddr);
} else {
if (result.end == 0) {
result.end = node;
}
result.begin = node;
}
}
}
} else {
/* Recursive case: in the middle of an address, so the job at this
step is to look for containers that match. We temporarily turn
the next slash into a null so pattern will be a null-terminated
string of the stuff between the slashes. */
*nextSlash = '\0';
restOfPattern = nextSlash + 1;
for (i = 0; i < c->numChildren; ++i) {
if (PatternMatch(pattern, c->childrenNames[i])) {
callbackListEnds subResult =
DispatchSubMessage(restOfPattern, c->children[i]);
if (result.end == 0) {
result = subResult;
} else {
subResult.end->next = result.begin;
result.begin = subResult.begin;
}
}
}
*nextSlash = '/';
}
return result;
}
static char *NextSlashOrNull(char *p) {
while (*p != '/' && *p != '\0') {
p++;
}
return p;
}

View File

@@ -0,0 +1,364 @@
/*
Copyright <20> 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-address-space.h
Matt Wright, 11/20/97
Version 2.0 5/28/98
C interface for registering the nodes in the OSC address space for an
application.
include OSC-timetag.h before this file
****************************** Introduction ******************************
The model is based on our original C++ design and consists of two kinds of
objects:
methods are the leaf nodes of the address space hierarchy. A complete OSC
address corresponds to a particular method, which has a corresponding
callback procedure that will be invoked to implement commands sent by an
OSC client.
containers are branch nodes of the address space hierarchy, and contain
methods and other containers. Each container has a single namespace;
it cannot contain a method and a subcontainer with the same name.
For example, let's examine the OSC message "/resonators/foo/decay 2.5". The
address of this message is "/resonators/foo/decay" and the message has a
single argument, 2.5. We'd say that the object corresponding to the prefix
"/resonators" is a container, and that it contains another container whose
address is "/resonators/foo". The "/resonators/foo" container has a method
"decay".
The memory model used by this module is pre-allocation of fixed-size objects
for containers, methods, and other internal objects. This preallocated
memory is dynamically managed internally by a custom high-performance memory
allocator. When the preallocated memory runs out, this module calls an
optional realtime memory allocator that you provide. If your memory allocator
gives this module more memory, it will add it to the pool of objects and
never free the memory. If your system does not have a realtime memory
allocator, provide a procedure that always returns 0.
*/
/*************************** Type Definitions ******************************/
/* Users of this module don't get to see what's inside these objects */
typedef struct OSCContainerStruct *OSCcontainer;
typedef struct OSCMethodStruct *OSCMethod;
/* This makes it easy to change the way we represent symbolic names: */
typedef const char *Name;
/************************ Initialization and Memory ************************/
/* You will fill an OSCAddressSpaceMemoryTuner struct with the parameters that
determine how memory will be allocated.
initNumContainers is the number of containers that will be allocated at
initialization time. This should be the maximum number of containers you
ever expect to have in your address space.
initNumMethods is the number of methods that will be allocated at
initialization time. If you register the same method callback procedure
multiple times at different places in the address space, each of these
locations counts as a separate method as far as memory allocation is
concerned.
The MemoryAllocator fields are procedures you will provide that allocate
memory. Like malloc(), they take the number of bytes as arguments and return
either a pointer to the new memory or 0 for failure. This memory will never
be freed.
The InitTimeMemoryAllocator will be called only at initialization time,
i.e., before OSCInitAddressSpace() returns. If it ever returns 0, that's
a fatal error.
The RealTimeMemoryAllocator will be called if, while the application is
running, the address space grows larger than can fit in what was allocated
at initialization time. If the RealTimeMemoryAllocator() returns 0, the
operation attempting to grow the address space will fail. If your system
does not have real-time memory allocation, RealTimeMemoryAllocator should
be a procedure that always returns 0.
*/
struct OSCAddressSpaceMemoryTuner {
int initNumContainers;
int initNumMethods;
void *(*InitTimeMemoryAllocator)(int numBytes);
void *(*RealTimeMemoryAllocator)(int numBytes);
};
/* Given an OSCAddressSpaceMemoryTuner, return the number of bytes of
memory that would be allocated if OSCInitAddressSpace() were called
on it. */
int OSCAddressSpaceMemoryThatWouldBeAllocated(struct OSCAddressSpaceMemoryTuner *t);
/* Call this before you call anything else. It returns the container that
corresponds to the address "/" and is the root of the address space tree.
*/
OSCcontainer OSCInitAddressSpace(struct OSCAddressSpaceMemoryTuner *t);
/**************************** Containers ****************************/
/* Here's how this system deals with the standard OSC queries addressed to
containers. This module handles the details of listening for these queries
and returning a correctly-formatted answer; all it needs from you is the
actual data that constitute the answers to these queries.
You pass this data in an OSCContainerQueryResponseInfo structure. Future versions
of this module may have new kinds of queries that they can deal with, so
the list of fields in this structure may grow. That's why your code should
call OSCInitContainerQueryResponseInfo() on your struct before putting new values
into it; this procedure will initialize all of the fields to 0, meaning
"don't have that information", which will cause the associated queries to
fail.
The "null" message, i.e., a message with a trailing slash, requesting the
list of addresses under a given container, is handled automatically.
*/
struct OSCContainerQueryResponseInfoStruct {
char *comment;
/* Other fields may go here */
};
void OSCInitContainerQueryResponseInfo(struct OSCContainerQueryResponseInfoStruct *i);
/* Allocate a new container and initialize it. Returns 0 if it cannot
allocate a new container, e.g., if you've exceeded the initNumContainers
limit of the OSCAddressSpaceMemoryTuner() and the RealTimeMemoryAllocator()
didn't return any new memory.
This procedure doesn't make a copy of the name string or any of the
contents of the OSCContainerQueryResponseInfoStruct. It does copy the fields
of the OSCContainerQueryResponseInfoStruct.
*/
OSCcontainer OSCNewContainer(Name name, OSCcontainer parent,
struct OSCContainerQueryResponseInfoStruct *queryInfo);
/* Remove a container from the address space. This also removes all the
container's methods and recursively removes all sub-containers. Memory
freed by removing a container is kept in this module's internal pool.
*/
void OSCRemoveContainer(OSCcontainer container);
/* Given a pointer to a container, and another name for that container, add or
remove that name as an alias for the container. Return FALSE for failure. */
Boolean OSCAddContainerAlias(OSCcontainer container, Name otherName);
Boolean OSCRemoveContainerAlias(OSCcontainer container, Name otherName);
/* Write the OSC address of the given container into the given string.
Return FALSE if the address won't fit in the string. */
Boolean OSCGetAddressString(char *target, int maxLength, OSCcontainer c);
/* Given an address (not a pattern!), return the single OSCcontainer it names,
or 0 if there is no container at that address */
OSCcontainer OSCLookUpContainer(Name address);
/**************************** Methods ****************************/
/* A methodCallback is a procedure that you write that will be called at the
time that an OSC message is to take effect. It will be called with 5
arguments:
- A context pointer that was registered with the methodNode
this is a method of. (Something like the C++ "this" pointer.)
- The number of bytes of argument data
- A pointer to the argument portion of the OSC message
- The time tag at which this message is supposed to take effect.
- A "return address" object you can use to send a message back to the
client that sent this message. This return channel is guaranteed
to be usable only during the invocation of your method, so your method
must use the return address immediately or ignore it, not store it away
for later use.
*/
typedef struct NetworkReturnAddressStruct *NetworkReturnAddressPtr;
/* removed const */
typedef void (*methodCallback)(void *context, int arglen, const void *args,
OSCTimeTag when, NetworkReturnAddressPtr returnAddr);
/* A ParamValQuerier is a procedure that the OSC system will call when the
user wants to know the current value of a parameter. It will be passed the
same context pointer as the associated method. It should write its return
value in the given buffer in the same format as the associated
methodCallback would expect its "args" argument, and should return the
length of data just like the method would expect in its "arglen" argument.
It doesn't have to worry about the address portion of the OSC message.
*/
typedef char OSCData; /* For pointers to OSC-formatted data */
typedef int (*ParamValQuerier)(OSCData *result, void *context);
/* This system deals with other standard per-method queries, such as
documentation, valid parameter types and ranges, units, default values,
etc., pretty much just like per-container queries.
*/
struct OSCMethodQueryResponseInfoStruct {
char *description;
ParamValQuerier pvq;
/* For each argument of the method:
min, max, default, units */
};
void OSCInitMethodQueryResponseInfo(struct OSCMethodQueryResponseInfoStruct *i);
/* Allocate a new method, initialize it, and add it to a container. Returns 0
for failure, e.g., if you've exceeded the initNumMethods limit of the
OSCAddressSpaceMemoryTuner() and the RealTimeMemoryAllocator() didn't return any
new memory.
This procedure doesn't make a copy of the name string or any of the
contents of the OSCMethodQueryResponseInfoStruct.
*/
OSCMethod OSCNewMethod(Name name, OSCcontainer container, methodCallback meth,
void *context, struct OSCMethodQueryResponseInfoStruct *queryInfo);
/******************************* Debug ********************************/
void OSCPrintWholeAddressSpace(void);
/**************************** Sample Code *****************************/
/* Here's a gross approximation of how your application will invoke the
procedures in this module. It registers an address space with
containers with addresses "/foo", "/foo/foochild", and "/bar",
and gives each of them "play" and "shuddup" messages.
#include "OSC-common.h"
#include "OSC-timetag.h"
#include "OSC-address-space.h"
typedef struct {
int playing;
int param;
float otherParam;
} Player;
void PlayCallback(void *context, int arglen, const void *vargs,
OSCTimeTag when, NetworkReturnAddressPtr ra) {
Player *p = context;
const int *args = vargs;
p->playing = 1;
if (arglen >= 4) {
p->param = args[0];
}
}
void ShuddupCallback(void *context, int arglen, const void *vargs,
OSCTimeTag when, NetworkReturnAddressPtr ra) {
Player *p = context;
const float *args = vargs;
p->playing = 0;
if (arglen >= 4) {
p->otherParam = args[0];
}
}
void *InitTimeMalloc(int numBytes) {
return malloc(numBytes);
}
void *NoRealTimeMalloc(int numBytes) {
return 0;
}
main() {
struct OSCAddressSpaceMemoryTuner oasmt;
OSCcontainer topLevelContainer, foo, foochild, bar;
struct OSCContainerQueryResponseInfoStruct ocqris;
struct OSCMethodQueryResponseInfoStruct omqris;
Player *players;
players = (Player *) malloc(3 * sizeof(*players));
if (!players) exit(1);
oasmt.initNumContainers = 10;
oasmt.initNumMethods = 10;
oasmt.InitTimeMemoryAllocator = InitTimeMalloc;
oasmt.RealTimeMemoryAllocator = NoRealTimeMalloc;
topLevelContainer = OSCInitAddressSpace(&oasmt);
OSCInitContainerQueryResponseInfo(&ocqris);
ocqris.comment = "Foo for you";
foo = OSCNewContainer("foo", topLevelContainer, &ocqris);
OSCInitContainerQueryResponseInfo(&ocqris);
ocqris.comment = "Beware the son of foo!";
foochild = OSCNewContainer("foochild", foo, &ocqris);
OSCInitContainerQueryResponseInfo(&ocqris);
ocqris.comment = "Belly up to the bar";
bar = OSCNewContainer("bar", topLevelContainer, &ocqris);
if (foo == 0 || foochild == 0 || bar == 0) {
fprintf(stderr, "Problem!\n");
exit(1);
}
OSCInitMethodQueryResponseInfo(&omqris);
OSCNewMethod("play", foo, PlayCallback, &(players[0]), &omqris);
OSCNewMethod("shuddup", foo, ShuddupCallback, &(players[0]), &omqris);
OSCNewMethod("play", foochild, PlayCallback, &(players[1]), &omqris);
OSCNewMethod("shuddup", foochild, ShuddupCallback, &(players[1]), &omqris);
OSCNewMethod("play", bar, PlayCallback, &(players[2]), &omqris);
OSCNewMethod("shuddup", bar, ShuddupCallback, &(players[2]), &omqris);
}
*/

View File

@@ -0,0 +1,95 @@
/*
Copyright <20> 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-callbacklist.c
Linked lists of methods
Matt Wright, 11/20/97
Allocator is a simple linked list of free nodes.
*/
#include <libOSC/OSC-common.h>
#include <libOSC/OSC-timetag.h>
#include <libOSC/OSC-address-space.h>
#include <libOSC/OSC-dispatch.h>
#include <libOSC/OSC-callbacklist.h>
static callbackList allNodes;
static callbackList freeNodes;
/* Call this before you call anything else */
Boolean InitCallbackListNodes(int numNodes, void *(*InitTimeMalloc)(int numBytes)) {
int i;
allNodes = (*InitTimeMalloc)(numNodes * sizeof(*allNodes));
if (allNodes == 0) return FALSE;
/* Initialize list of freeNodes */
freeNodes = &(allNodes[0]);
for (i = 0; i < numNodes-1; ++i) {
allNodes[i].next = &(allNodes[i+1]);
}
allNodes[numNodes-1].next = 0;
return TRUE;
}
callbackList AllocCallbackListNode(methodCallback callback, void *context,
struct callbackListNode *next) {
callbackList result;
if (freeNodes == 0) {
/* OSCProblem("Out of memory for callback lists!"); */
return 0;
}
result = freeNodes;
freeNodes = freeNodes->next;
result->callback = callback;
result->context = context;
result->next = next;
#ifdef DEBUG_CBL
printf("AllocCallbackListNode: returning %p (cb %p, context %p, next %p)\n",
result, result->callback, result->context, result->next);
#endif
return result;
}
void FreeCallbackListNode(callbackList cb) {
#ifdef DEBUG_CBL
printf("FreeCallbackListNode(%p)\n", cb);
#endif
cb->next = freeNodes;
freeNodes = cb;
}

View File

@@ -0,0 +1,49 @@
/*
Copyright <20> 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-callbacklist.h
Linked lists of methods
Matt Wright, 3/13/98
include "OSC-dispatch.h" before this file.
*/
/* Call this before you call anything else. */
Boolean InitCallbackListNodes(int numNodes, void *(*InitTimeMalloc)(int numBytes));
callbackList AllocCallbackListNode(methodCallback callback, void *context,
struct callbackListNode *next);
void FreeCallbackListNode(callbackList);

View File

@@ -0,0 +1,87 @@
/*
Copyright <20> 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-system-dependent.c
Matt Wright, 3/13/98
File of procedures OSC has to call that are not part of the OSC package
and that you, the developer adding OSC addressability to an application,
must write in a way that makes sense in the context of your system.
You should also look at OSC-timetag.c and see if there's a better way
to handle time tags on your system.
*/
#include <libOSC/OSC-common.h>
/* Printing stuff: for now, use stderr. Some cleverer stuff we could do:
- Make a silent mode where these don't do anything.
- Return error messages via OSC to some client
*/
#include <stdarg.h>
#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <stdint.h>
void fatal_error(char *s, ...) {
va_list ap;
fprintf(stderr, "Fatal error: ");
va_start(ap, s);
vfprintf(stderr, s, ap);
fprintf(stderr, "\n");
va_end(ap);
exit(-321);
}
void OSCProblem(char *s, ...) {
va_list ap;
fprintf(stderr, "OSC Problem: ");
va_start(ap, s);
vfprintf(stderr, s, ap);
fprintf(stderr, "\n");
va_end(ap);
}
void OSCWarning(char *s, ...) {
/* va_list ap;
fprintf(stderr, "OSC Warning: ");
va_start(ap, s);
vfprintf(stderr, s, ap);
fprintf(stderr, "\n");
va_end(ap);*/
}

View File

@@ -0,0 +1,60 @@
/*
Copyright <20> 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-common.h
Simple stuff to #include everywhere in the OSC package
by Matt Wright, 3/13/98
*/
/* Boolean type */
#ifndef TRUE
typedef int Boolean;
#define TRUE 1
#define FALSE 0
#endif
/* Fixed byte width types */
typedef int int4; /* 4 byte int */
/* Printing type procedures. All take printf-style format string */
/* Catastrophic failure: print message and halt system */
void fatal_error(char *s, ...);
/* Error message for user */
void OSCProblem(char *s, ...);
/* Warning for user */
void OSCWarning(char *s, ...);

View File

@@ -0,0 +1,52 @@
/*
Copyright <20> 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-dispatch.h
Given an OSC message pattern from an incoming message, match the
pattern against the OSC address space and produce a list of the
callbacks corresponding to all the addresses that were matched.
Matt Wright, 6/5/98
*/
/***************************** Dispatching *****************************/
typedef struct callbackListNode {
methodCallback callback;
void *context;
struct callbackListNode *next;
} *callbackList;
/* Given an OSC message pattern from an incoming message, match the
pattern against the OSC address space and produce a list of the
callbacks corresponding to all the addresses that were matched. */
callbackList OSCDispatchMessage(char *pattern);

View File

@@ -0,0 +1,58 @@
/*
Copyright <20> 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-drop.c
This implementation just prints a warning.
Matt Wright, 3/16/98
*/
#include <stdint.h>
#include <sys/types.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <libOSC/OSC-common.h>
#include <libOSC/OSC-timetag.h>
#include <libOSC/OSC-address-space.h>
#include <libOSC/NetworkReturnAddress.h>
#include <libOSC/OSC-receive.h>
#include <libOSC/OSC-drop.h>
void DropPacket(OSCPacketBuffer p) {
OSCWarning("Packet dropped.");
}
void DropBundle(char *buf, int n, OSCPacketBuffer p) {
OSCWarning("Bundle dropped.");
}
void DropMessage(char *buf, int n, OSCPacketBuffer p) {
OSCWarning("Message dropped.");
}

View File

@@ -0,0 +1,43 @@
/*
Copyright <20> 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-drop.h
These procedures will be called on a packet, bundle, or message that's
being dropped for whatever reason. They can do nothing, print (or
otherwise inform the user of) a warning, save the offending data somewhere,
etc.
Matt Wright, 3/16/98
*/
void DropPacket(OSCPacketBuffer p);
void DropBundle(char *buf, int n, OSCPacketBuffer p);
void DropMessage(char *buf, int n, OSCPacketBuffer p);

View File

@@ -0,0 +1,70 @@
/*
Copyright <20> 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-internal-messages.h
Interface for having an application send OSC messages to itself
internally.
All these procedures return FALSE if unable to deliver the message.
Matt Wright, 3/17/98
*/
/* Send a message immediately, with no return address. This procedure
returns after the message has been sent (or has failed to be sent),
so the memory for address and args can be on the stack. Returns FALSE
if there's a problem; TRUE otherwise. */
Boolean OSCSendInternalMessage(char *address, int arglen, void *args);
/* Same thing, but with a return address supplied. */
Boolean OSCSendInternalMessageWithRSVP(char *address, int arglen, void *args,
NetworkReturnAddressPtr returnAddr);
/* Schedule some messages to occur at a given time. This allocates one of the
OSCPacketBuffer structures (see OSC-receive.h) to hold the addresses and argument
data until the messages take effect, so if you're going to call this, you
should take this use of packets into account in setting the
numReceiveBuffers argument to OSCInitReceive().
This provides an less general interface than OSC's bundle mechanism, because
the bundle of messages you provide cannot include subbundles.
The addresses, arglens, and args arguments are arrays of size numMessages.
There's no return address argument because you're not allowed to save a network
return address for later use.
*/
Boolean OSCScheduleInternalMessages(OSCTimeTag when, int numMessages,
char **addresses, int *arglens,
void **args);

View File

@@ -0,0 +1,193 @@
/*
Copyright <20> 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
*/
#include <libOSC/OSC-common.h>
#include <libOSC/OSC-pattern-match.h>
#include <stdint.h>
#include <sys/time.h>
static const char *theWholePattern; /* Just for warning messages */
static Boolean MatchBrackets (const char *pattern, const char *test);
static Boolean MatchList (const char *pattern, const char *test);
Boolean 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);
else
return FALSE;
}
switch (pattern[0]) {
case 0 : return test[0] == 0;
case '?' : return PatternMatch (pattern + 1, test + 1);
case '*' :
if (PatternMatch (pattern+1, test)) {
return TRUE;
} else {
return PatternMatch (pattern, test+1);
}
case ']' :
case '}' :
OSCWarning("Spurious %c in pattern \".../%s/...\"",pattern[0], theWholePattern);
return FALSE;
case '[' :
return MatchBrackets (pattern,test);
case '{' :
return MatchList (pattern,test);
case '\\' :
if (pattern[1] == 0) {
return test[0] == 0;
} else if (pattern[1] == test[0]) {
return PatternMatch (pattern+2,test+1);
} else {
return FALSE;
}
default :
if (pattern[0] == test[0]) {
return PatternMatch (pattern+1,test+1);
} else {
return FALSE;
}
}
}
/* we know that pattern[0] == '[' and test[0] != 0 */
static Boolean MatchBrackets (const char *pattern, const char *test) {
Boolean result;
Boolean negated = FALSE;
const char *p = pattern;
if (pattern[1] == 0) {
OSCWarning("Unterminated [ in pattern \".../%s/...\"", theWholePattern);
return FALSE;
}
if (pattern[1] == '!') {
negated = TRUE;
p++;
}
while (*p != ']') {
if (*p == 0) {
OSCWarning("Unterminated [ in pattern \".../%s/...\"", theWholePattern);
return FALSE;
}
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 FALSE;
while (*p != ']') {
if (*p == 0) {
OSCWarning("Unterminated [ in pattern \".../%s/...\"", theWholePattern);
return FALSE;
}
p++;
}
return PatternMatch (p+1,test+1);
}
static Boolean MatchList (const char *pattern, const char *test) {
const char *restOfPattern, *tp = test;
for(restOfPattern = pattern; *restOfPattern != '}'; restOfPattern++) {
if (*restOfPattern == 0) {
OSCWarning("Unterminated { in pattern \".../%s/...\"", theWholePattern);
return FALSE;
}
}
restOfPattern++; /* skip close curly brace */
pattern++; /* skip open curly brace */
while (1) {
if (*pattern == ',') {
if (PatternMatch (restOfPattern, tp)) {
return TRUE;
} else {
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++;
}
}
}
}

View File

@@ -0,0 +1,35 @@
/*
Copyright <20> 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.h
*/
Boolean PatternMatch (const char *pattern, const char *test);

View File

@@ -0,0 +1,190 @@
/*
Copyright <20> 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-priority-queue.c
Priority queue used by OSC time tag scheduler
This is the most trivial implementation, an unsorted array of queued
objects, mostly for debug purposes.
Matt Wright, 9/17/98
*/
#include <libOSC/OSC-common.h>
#include <libOSC/OSC-timetag.h>
#include <libOSC/OSC-priority-queue.h>
#include <stdint.h>
#include <sys/time.h>
#define PRINT_PRIORITY_QUEUE
#ifdef DEBUG_OSC_PRIORITY_QUEUE
#define PRINT_PRIORITY_QUEUE
#endif
#if defined(PRINT_PRIORITY_QUEUE) || defined(DEBUG_OSC_PRIORITY_QUEUE)
#include <stdio.h>
void OSCQueuePrint(OSCQueue q);
#endif
#define CAPACITY 1000
struct OSCQueueStruct {
OSCSchedulableObject list[CAPACITY];
int n;
int scanIndex;
};
OSCQueue OSCNewQueue(int maxItems, void *(*InitTimeMalloc)(int numBytes)) {
OSCQueue result;
if (maxItems > CAPACITY) fatal_error("Increase CAPACITY in OSC-priority-queue.c");
result = (*InitTimeMalloc)(sizeof(*result));
if (result == 0) return 0;
result->n = 0;
#ifdef DEBUG_OSC_PRIORITY_QUEUE
OSCQueuePrint(result);
#endif
return result;
}
int OSCQueueInsert(OSCQueue q, OSCSchedulableObject new) {
if (q->n == CAPACITY) return FALSE;
q->list[q->n] = new;
++(q->n);
#ifdef DEBUG_OSC_PRIORITY_QUEUE
printf("OSCQueueInsert: just inserted %p\n", new);
OSCQueuePrint(q);
#endif
return TRUE;
}
OSCTimeTag OSCQueueEarliestTimeTag(OSCQueue q) {
int i;
OSCTimeTag smallest = OSCTT_BiggestPossibleTimeTag();
for (i = 0; i < q->n; ++i) {
if (OSCTT_Compare(smallest, q->list[i]->timetag) > 0) {
smallest = q->list[i]->timetag;
}
}
#ifdef DEBUG_OSC_PRIORITY_QUEUE
printf("OSCQueueEarliestTimeTag: about to return %llx\n", smallest);
OSCQueuePrint(q);
#endif
return smallest;
}
static void RemoveElement(int goner, OSCQueue q) {
int i;
--(q->n);
for (i = goner; i < q->n; ++i) {
q->list[i] = q->list[i+1];
}
}
OSCSchedulableObject OSCQueueRemoveEarliest(OSCQueue q) {
OSCSchedulableObject result;
int i, smallestIndex;
if (q->n == 0) {
OSCWarning("OSCQueueRemoveEarliest: empty queue");
return NULL;
}
#ifdef DEBUG_OSC_PRIORITY_QUEUE
printf("OSCQueueRemoveEarliest: begin\n");
OSCQueuePrint(q);
#endif
smallestIndex = 0;
for (i = 1; i < q->n; ++i) {
if (OSCTT_Compare(q->list[smallestIndex]->timetag, q->list[i]->timetag) > 0) {
smallestIndex = i;
}
}
result = q->list[smallestIndex];
RemoveElement(smallestIndex, q);
#ifdef DEBUG_OSC_PRIORITY_QUEUE
printf("OSCQueueRemoveEarliest: done\n");
OSCQueuePrint(q);
#endif
return result;
}
#ifdef PRINT_PRIORITY_QUEUE
void OSCQueuePrint(OSCQueue q) {
int i;
printf("OSC Priority queue at %p has %d elements:\n", q, q->n);
for (i = 0; i < q->n; ++i) {
printf(" list[%2d] is %p, timetag = %llx\n", i, q->list[i], q->list[i]->timetag);
}
printf("\n\n");
}
#endif
void OSCQueueScanStart(OSCQueue q) {
q->scanIndex = 0;
}
OSCSchedulableObject OSCQueueScanNext(OSCQueue q) {
if (q->scanIndex >= q->n) return 0;
return (q->list[(q->scanIndex)++]);
}
void OSCQueueRemoveCurrentScanItem(OSCQueue q) {
/* Remember that q->scanIndex is the index of the *next*
item that will be returned, so the "current" item, i.e.,
the one most recently returned by OSCQueueScanNext(),
is q->scanIndex-1. */
RemoveElement(q->scanIndex-1, q);
--(q->scanIndex);
}
void CheckWholeQueue(void) {
}

View File

@@ -0,0 +1,90 @@
/*
Copyright <20> 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-priority-queue.h
Interface to priority queue used by OSC time tag scheduler
Matt Wright, 3/13/98
*/
/* include OSC-timetag.h before this file. */
/* This queue manages pointers to data objects. It doesn't care what's in the
objects except that the first element has to be an OSCTimeTag. So whatever
data you want to store, cast your pointer to it to a pointer to this type. */
typedef struct {
OSCTimeTag timetag;
/* There will be other stuff... */
} *OSCSchedulableObject;
typedef struct OSCQueueStruct *OSCQueue;
/* Make a new queue, or return 0 for failure. */
OSCQueue OSCNewQueue(int maxItems, void *(*InitTimeMalloc)(int numBytes));
/* Put something into the queue. Return FALSE if quque is full. */
Boolean OSCQueueInsert(OSCQueue q, OSCSchedulableObject o);
/* What's the time tag of the earliest item in the queue?
Return OSCTT_BiggestPossibleTimeTag() if queue is empty. */
OSCTimeTag OSCQueueEarliestTimeTag(OSCQueue q);
/* Remove the item from the front of the queue. Fatal error
if the queue is empty. */
OSCSchedulableObject OSCQueueRemoveEarliest(OSCQueue q);
/* Interface for examining items currently stored on the queue:
- To start, call OSCQueueScanStart().
- Then each subsequent call to OSCQueueScanNext() returns a pointer to an
OSCSchedulableObject that is stored on the queue, until
OSCQueueScanNext() returns 0 to indicate that all objects on the queue
have been scanned.
The objects returned by OSCQueueScanNext() come in chronological order (or
approximately chronological order, depending on the underlying queue data
structure).
If you call OSCQueueRemoveCurrentScanItem(), the object most recently
returned by OSCQueueScanNext() will be removed from the queue.
If there are any insertions or deletions to the queue, the sequence of
scanned objects must still include every object in the queue. This may
cause a particular object to be returned more than once by
OSCQueueScanNext().
*/
void OSCQueueScanStart(OSCQueue q);
OSCSchedulableObject OSCQueueScanNext(OSCQueue q);
void OSCQueueRemoveCurrentScanItem(OSCQueue q);

View File

@@ -0,0 +1,893 @@
/*
Copyright <20> 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
*/
#define PARANOID 0
/*
OSC-receive.c
Matt Wright, 3/13/98, 6/3/98
Adapted from OSC-addressability.c (and seriously cleaned up!)
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdint.h>
#include <sys/time.h>
#include <libOSC/OSC-common.h>
#include <libOSC/OSC-timetag.h>
#include <libOSC/OSC-address-space.h>
#include <libOSC/NetworkReturnAddress.h>
#include <libOSC/OSC-receive.h>
#include <libOSC/OSC-priority-queue.h>
#include <libOSC/OSC-string-help.h>
#include <libOSC/OSC-drop.h>
#include <libOSC/OSC-dispatch.h>
#include <libOSC/NetworkUDP.h>
#include <libOSC/OSC-callbacklist.h>
#if defined(DEBUG_INTERNAL) || defined(DEBUG) || defined(DEBUG_PACKET_MEM) || defined(DEBUG_QD_MEM) || defined(DEBUG_8BYTE_ALIGN) || defined(SUSPECT_QD_PROB)
#include <stdio.h>
#endif
static int use_mcast_ = 0;
static char mcast_groupname[200];
struct {
OSCQueue TheQueue; /* The Priority Queue */
OSCTimeTag lastTimeTag; /* Best approximation to current time */
Boolean timePassed; /* TRUE if OSCInvokeMessagesThatAreReady() has been
called since the last time OSCBeProductiveWhileWaiting() was. */
int recvBufSize; /* Size of all receive buffers */
void *(*InitTimeMalloc)(int numBytes);
void *(*RealTimeMemoryAllocator)(int numBytes);
} globals;
/* Data structures */
struct OSCPacketBuffer_struct {
char *buf; /* Contents of network packet go here */
int n; /* Overall size of packet */
int refcount; /* # queued things using memory from this buffer */
struct OSCPacketBuffer_struct *nextFree; /* For linked list of free packets */
Boolean returnAddrOK; /* Because returnAddr points to memory we need to
store future return addresses, we set this
field to FALSE in situations where a packet
buffer "has no return address" instead of
setting returnAddr to 0 */
NetworkReturnAddressPtr returnAddr;
//void *returnAddr; /* Addr of client this packet is from */
/* This was of type NetworkReturnAddressPtr, but the constness
was making it impossible for me to initialize it. There's
probably a better way that I don't understand. */
};
/* These are the data objects that are inserted and removed from the
scheduler. The idea is that we can insert a single message or
an entire bundle on the scheduler, and we can leave it in various
states of being parsed and pattern matched. */
#define NOT_DISPATCHED_YET ((callbackList) -1)
typedef struct queuedDataStruct {
OSCTimeTag timetag; /* When this bundle or message is supposed to happen */
OSCPacketBuffer myPacket; /* Ptr. to buffer this is contained in */
enum {MESSAGE, BUNDLE} type;
union {
struct {
char *bytes;
int length;
} bundle;
struct {
char *messageName; /* Ptr. into receive buffer */
int length; /* Includes name and arugments */
void *args; /* 0 if not yet parsed */
int argLength;
callbackList callbacks; /* May be NOT_DISPATCHED_YET */
} message;
} data;
struct queuedDataStruct *nextFree; /* For linked list of free structures */
} queuedData;
/* Static procedure declatations */
static Boolean InitPackets(int receiveBufferSize, int clientAddrSize, int numReceiveBuffers);
static Boolean InitQueuedData(int numQueuedObjects);
static queuedData *AllocQD(void);
static void FreeQD(queuedData *qd);
static void CallWholeCallbackList(callbackList l, int argLength, void *args, OSCTimeTag when, NetworkReturnAddressPtr returnAddr);
static void InsertBundleOrMessage(char *buf, int n, OSCPacketBuffer packet, OSCTimeTag enclosingTimeTag);
static void ParseBundle(queuedData *qd);
static Boolean ParseMessage(queuedData *qd);
/* static void CheckPacketRefcount(OSCPacketBuffer packet); */
static void PacketAddRef(OSCPacketBuffer packet);
static void PacketRemoveRef(OSCPacketBuffer packet);
/**************************************************
Initialization and memory pre-allocation
**************************************************/
Boolean OSCInitReceive(struct OSCReceiveMemoryTuner *t) {
globals.recvBufSize = t->receiveBufferSize;
globals.InitTimeMalloc = t->InitTimeMemoryAllocator;
globals.RealTimeMemoryAllocator = t->RealTimeMemoryAllocator;
globals.TheQueue = OSCNewQueue(t->numQueuedObjects, t->InitTimeMemoryAllocator);
if (globals.TheQueue == 0) return FALSE;
globals.lastTimeTag = OSCTT_Immediately();
globals.timePassed = TRUE;
if (InitPackets(t->receiveBufferSize, SizeOfNetworkReturnAddress(),
t->numReceiveBuffers) == FALSE) return FALSE;
if (InitQueuedData(t->numQueuedObjects) == FALSE) return FALSE;
if (InitCallbackListNodes(t->numCallbackListNodes, t->InitTimeMemoryAllocator)
== FALSE) return FALSE;
return TRUE;
}
/**************************************************
Managing packet data structures
**************************************************/
static struct OSCPacketBuffer_struct *freePackets;
#ifdef DEBUG_PACKET_MEM
static void PrintPacketFreeList(void) {
struct OSCPacketBuffer_struct *p;
printf("- freePackets:");
if (freePackets == 0) {
printf(" [none]");
}
for (p = freePackets; p != 0; p = p->nextFree) {
printf(" %p", p);
}
printf("\n");
}
#endif
#define MIN_REASONABLE_RCV_BUFSIZE 128
void OSCFreeReceiver(void)
{
if( freePackets) free(freePackets);
if( globals.TheQueue ) free( globals.TheQueue );
}
static Boolean InitPackets(int receiveBufferSize, int clientAddrSize, int numReceiveBuffers) {
int i;
struct OSCPacketBuffer_struct *allPackets;
if (receiveBufferSize < MIN_REASONABLE_RCV_BUFSIZE) {
fatal_error("OSCInitReceive: receiveBufferSize of %d is unreasonably small.",
receiveBufferSize);
}
allPackets = (*(globals.InitTimeMalloc))(numReceiveBuffers * sizeof(*allPackets));
if (allPackets == 0) return FALSE;
for (i = 0; i < numReceiveBuffers; ++i) {
allPackets[i].returnAddr = (*(globals.InitTimeMalloc))(clientAddrSize);
if (allPackets[i].returnAddr == 0) return FALSE;
allPackets[i].buf = (*(globals.InitTimeMalloc))(receiveBufferSize);
if (allPackets[i].buf == 0) return FALSE;
allPackets[i].nextFree = &(allPackets[i+1]);
}
allPackets[numReceiveBuffers-1].nextFree = ((struct OSCPacketBuffer_struct *) 0);
freePackets = allPackets;
return TRUE;
}
char *OSCPacketBufferGetBuffer(OSCPacketBuffer p) {
return p->buf;
}
int *OSCPacketBufferGetSize(OSCPacketBuffer p) {
return &(p->n);
}
int OSCGetReceiveBufferSize(void) {
return globals.recvBufSize;
}
NetworkReturnAddressPtr OSCPacketBufferGetClientAddr(OSCPacketBuffer p) {
return p->returnAddr;
}
#ifdef DEBUG
void PrintPacket(OSCPacketBuffer p) {
printf("Packet %p. buf %p, n %d, refcount %d, nextFree %p\n",
p, p->buf, p->n, p->refcount, p->nextFree);
}
#endif
OSCPacketBuffer OSCAllocPacketBuffer(void) {
OSCPacketBuffer result;
if (freePackets == 0) {
/* Could try to call the real-time memory allocator here */
OSCWarning("OSCAllocPacketBuffer: no free packets!");
return 0;
}
result = freePackets;
freePackets = result->nextFree;
result->refcount = 0;
#ifdef DEBUG_PACKET_MEM
printf("OSCAllocPacketBuffer: allocating %p ", result);
PrintPacketFreeList();
#endif
return result;
}
void OSCFreePacket(OSCPacketBuffer p) {
#ifdef PARANOID
if (p->refcount != 0) {
OSCWarning("OSCFreePacket: %p's refcount is %d!\n", p, p->refcount);
}
#endif
p->nextFree = freePackets;
freePackets = p;
#ifdef DEBUG_PACKET_MEM
printf("OSCFreePacket: freed %p ", p);
PrintPacketFreeList();
#endif
}
/**************************************************
Dealing with OpenSoundControl packets and
making the messages take effect.
**************************************************/
static queuedData *freeQDList;
#ifdef DEBUG_QD_MEM
static void PrintQDFreeList(void) {
static queuedData *p;
printf("- freeQDList:");
if (freeQDList == 0) {
printf(" [none]");
}
for (p = freeQDList; p != 0; p = p->nextFree) {
printf(" %p", p);
}
printf("\n");
}
#endif
static Boolean InitQueuedData(int numQueuedObjects) {
int i;
queuedData *allQD;
allQD = (*(globals.InitTimeMalloc))(numQueuedObjects * (sizeof(*allQD)));
if (allQD == 0) return FALSE;
for (i = 0; i < numQueuedObjects; ++i) {
allQD[i].nextFree = &(allQD[i+1]);
}
allQD[numQueuedObjects-1].nextFree = 0;
freeQDList = &(allQD[0]);
return TRUE;
}
static queuedData *AllocQD(void) {
queuedData *result;
if (freeQDList == 0) {
/* Could try to call realtime malloc() */
OSCWarning("AllocQD: no QD objects free now; returning 0.");
return 0;
}
result = freeQDList;
freeQDList = freeQDList->nextFree;
return result;
}
static void FreeQD(queuedData *qd) {
qd->nextFree = freeQDList;
freeQDList = qd;
}
void OSCAcceptPacket(OSCPacketBuffer packet) {
if ((packet->n % 4) != 0) {
OSCProblem("OSC packet size (%d bytes) not a multiple of 4.", packet->n);
DropPacket(packet);
return;
}
#ifdef DEBUG
printf("OSCAcceptPacket(OSCPacketBuffer %p, buf %p, size %d)\n",
packet, packet->buf, packet->n);
#endif
/* If the packet came from the user, it's return address is OK. */
packet->returnAddrOK = TRUE;
InsertBundleOrMessage(packet->buf, packet->n, packet, OSCTT_Immediately());
#ifdef PARANOID
if (packet->refcount == 0) {
if (freePackets != packet) {
fatal_error("OSCAcceptPacket: packet refcount 0, but it's not the head of the free list!");
}
}
#endif
OSCInvokeAllMessagesThatAreReady(globals.lastTimeTag);
}
Boolean OSCBeProductiveWhileWaiting(void) {
/* Here's where we could be clever if an allocation fails.
(I.e., if we're out of QD objects, we should avoid
parsing bundles.) The code isn't that smart yet. */
queuedData *qd;
if (globals.timePassed) {
OSCQueueScanStart(globals.TheQueue);
}
while (1) {
qd = (queuedData *) OSCQueueScanNext(globals.TheQueue);
if (qd == 0) return FALSE;
if (qd->type == BUNDLE) {
ParseBundle(qd);
OSCQueueRemoveCurrentScanItem(globals.TheQueue);
return TRUE;
} else {
if (qd->data.message.callbacks == NOT_DISPATCHED_YET) {
if (ParseMessage(qd) == FALSE) {
/* Problem with this message - flush it. */
DropMessage(qd->data.message.messageName,
qd->data.message.length,
qd->myPacket);
OSCQueueRemoveCurrentScanItem(globals.TheQueue);
PacketRemoveRef(qd->myPacket);
FreeQD(qd);
}
return TRUE;
}
/* The item we found was an already-dispatched message,
so continue the while loop. */
}
}
}
Boolean OSCInvokeMessagesThatAreReady(OSCTimeTag now) {
queuedData *x;
OSCTimeTag thisTimeTag;
globals.lastTimeTag = now;
globals.timePassed = TRUE;
thisTimeTag = OSCQueueEarliestTimeTag(globals.TheQueue);
if (OSCTT_Compare(thisTimeTag, now) > 0) {
/* No messages ready yet. */
return FALSE;
}
#ifdef DEBUG
printf("OSCInvokeMessagesThatAreReady(%llx) - yes, some are ready; earliest %llx\n", now, thisTimeTag);
#endif
while (OSCTT_Compare(thisTimeTag, OSCQueueEarliestTimeTag(globals.TheQueue)) == 0) {
x = (queuedData *) OSCQueueRemoveEarliest(globals.TheQueue);
if (!x) return FALSE;
#ifdef DEBUG
printf("...Just removed earliest entry from queue: %p, TT %llx, %s\n",
x, x->timetag, x->type == MESSAGE ? "message" : "bundle");
if (x->type == MESSAGE) {
printf("...message %s, len %d, args %p, arglen %d, callbacks %p\n",
x->data.message.messageName, x->data.message.length, x->data.message.args,
x->data.message.argLength, x->data.message.callbacks);
} else {
if (x->data.bundle.length == 0) {
printf("...bundle is empty.\n");
} else {
printf("...bundle len %d, first count %d, first msg %s\n",
x->data.bundle.length, *((int *) x->data.bundle.bytes), x->data.bundle.bytes+4);
}
}
PrintPacket(x->myPacket);
#endif
if (x->type == BUNDLE) {
ParseBundle(x);
} else {
if (x->data.message.callbacks == NOT_DISPATCHED_YET) {
if (ParseMessage(x) == FALSE) {
/* Problem with this message - flush it. */
PacketRemoveRef(x->myPacket);
FreeQD(x);
continue;
}
}
CallWholeCallbackList(x->data.message.callbacks,
x->data.message.argLength,
x->data.message.args,
thisTimeTag,
x->myPacket->returnAddrOK ? x->myPacket->returnAddr : 0);
PacketRemoveRef(x->myPacket);
FreeQD(x);
}
}
#ifdef PARANOID
if (OSCTT_Compare(thisTimeTag, OSCQueueEarliestTimeTag(globals.TheQueue)) > 0) {
fatal_error("OSCInvokeMessagesThatAreReady: corrupt queue!\n"
" just did %llx; earliest in queue is now %llx",
thisTimeTag, OSCQueueEarliestTimeTag(globals.TheQueue));
}
#endif
return OSCTT_Compare(OSCQueueEarliestTimeTag(globals.TheQueue), now) <= 0;
}
void OSCInvokeAllMessagesThatAreReady(OSCTimeTag now) {
while (OSCInvokeMessagesThatAreReady(now)) {
/* Do nothing */
}
}
static void CallWholeCallbackList(callbackList l, int argLength, void *args, OSCTimeTag when,
NetworkReturnAddressPtr returnAddr) {
/* In a multithreaded application, this might run in a different thread
than the thread that deals with the priority queue. */
callbackList next;
while (l != 0) {
(*(l->callback))(l->context, argLength, args, when, returnAddr);
next = l->next;
FreeCallbackListNode(l);
l = next;
}
}
static void InsertBundleOrMessage(char *buf, int n, OSCPacketBuffer packet, OSCTimeTag enclosingTimeTag) {
Boolean IsBundle;
queuedData *qd;
/* We add the reference first thing so in case any of the upcoming
potential failure situations come we can call PacketRemoveRef, thereby
freeing the packet if necessary. */
PacketAddRef(packet);
if ((n % 4) != 0) {
OSCProblem("OSC message or bundle size (%d bytes) not a multiple of 4.", n);
DropMessage(buf, n, packet);
PacketRemoveRef(packet);
return;
}
if ((n >= 8) && (strncmp(buf, "#bundle", 8) == 0)) {
IsBundle = TRUE;
if (n < 16) {
OSCProblem("Bundle message too small (%d bytes) for time tag.", n);
DropBundle(buf, n, packet);
PacketRemoveRef(packet);
return;
}
} else {
IsBundle = FALSE;
}
qd = AllocQD();
if (qd == 0) {
OSCProblem("Not enough memory for queued data!");
DropBundle(buf, n, packet);
PacketRemoveRef(packet);
return;
}
qd->myPacket = packet;
qd->type = IsBundle ? BUNDLE : MESSAGE;
if (IsBundle) {
/* Be careful of 8-byte alignment when copying the time tag. Here's a good
way to get a bus error when buf happens not to be 8-byte aligned:
qd->timetag = *((OSCTimeTag *)(buf+8));
*/
memcpy(&(qd->timetag), buf+8, sizeof(OSCTimeTag));
if (OSCTT_Compare(qd->timetag, enclosingTimeTag) < 0) {
OSCProblem("Time tag of sub-bundle is before time tag of enclosing bundle.");
DropBundle(buf, n, packet);
PacketRemoveRef(packet);
FreeQD(qd);
return;
}
qd->data.bundle.bytes = buf + 16;
qd->data.bundle.length = n - 16;
} else {
qd->timetag = enclosingTimeTag;
qd->data.message.messageName = buf;
qd->data.message.length = n;
qd->data.message.callbacks = NOT_DISPATCHED_YET;
}
OSCQueueInsert(globals.TheQueue, (OSCSchedulableObject) qd);
}
static void ParseBundle(queuedData *qd) {
/* A queued bundle has been removed from the scheduler queue, and now it's
time to parse all the stuff inside it and schedule the enclosed
messages and bundles. Once all the contents of the bundle have been
parsed and scheduled, we trash the bundle, decrementing the packet
count and freeing the QD. */
int size;
int i = 0;
if (qd->type != BUNDLE) {
fatal_error("This can't happen: bundle isn't a bundle!");
}
while (i < qd->data.bundle.length) {
size = *((int *) (qd->data.bundle.bytes + i));
if ((size % 4) != 0) {
OSCProblem("Bad size count %d in bundle (not a multiple of 4).", size);
DropBundle(qd->data.bundle.bytes, qd->data.bundle.length, qd->myPacket);
goto bag;
}
if ((size + i + 4) > qd->data.bundle.length) {
OSCProblem("Bad size count %d in bundle (only %d bytes left in entire bundle).",
size, qd->data.bundle.length-i-4);
DropBundle(qd->data.bundle.bytes, qd->data.bundle.length, qd->myPacket);
goto bag;
}
/* Recursively handle element of bundle */
InsertBundleOrMessage(qd->data.bundle.bytes+i+4, size, qd->myPacket, qd->timetag);
i += 4 + size;
}
if (i != qd->data.bundle.length) {
fatal_error("This can't happen: internal logic error parsing bundle");
}
bag:
/* If we got here successfully, we've added to the packet's reference count for
each message or subbundle by calling InsertBundleOrMessage(), so we remove the one
reference for bundle that we just parsed. If we got here by "goto bag", there's a
problem with the bundle so we also want to lose the reference count. */
PacketRemoveRef(qd->myPacket);
FreeQD(qd);
}
static Boolean ParseMessage(queuedData *qd) {
/* Fill in all the information we'll need to execute the message as
quickly as possible when the time comes. This means figuring out where
the address ends and the arguments begin, and also pattern matching the
address to find the callbacks associated with it.
The message may be something we have to invoke now, or it may be some
message scheduled for the future that's just waiting on the queue; this
procedure doesn't care. */
char *args; /* char * so we can do pointer subtraction */
int messageLen;
char *DAAS_errormsg;
if (qd->type != MESSAGE) {
fatal_error("This can't happen: message isn't a message!");
}
args = OSCDataAfterAlignedString(qd->data.message.messageName,
qd->data.message.messageName+qd->data.message.length,
&DAAS_errormsg);
if (args == 0) {
OSCProblem("Bad message name string: %s\n", DAAS_errormsg);
DropMessage(qd->data.message.messageName, qd->data.message.length, qd->myPacket);
return FALSE;
}
qd->data.message.args = args;
messageLen = args - qd->data.message.messageName;
qd->data.message.argLength = qd->data.message.length - messageLen;
qd->data.message.callbacks = OSCDispatchMessage(qd->data.message.messageName);
if (qd->data.message.callbacks == 0) {
OSCWarning("Message pattern \"%s\" did not correspond to any address in the synth.",
qd->data.message.messageName);
return FALSE;
}
return TRUE;
}
static void PacketAddRef(OSCPacketBuffer packet) {
++(packet->refcount);
}
static void PacketRemoveRef(OSCPacketBuffer packet) {
--(packet->refcount);
if (packet->refcount == 0) {
OSCFreePacket(packet);
}
}
/**************************************************
Implementation of procedures declared in
OSC-internal-messages.h
**************************************************/
#include <libOSC/OSC-internal-messages.h>
Boolean OSCSendInternalMessage(char *address, int arglen, void *args) {
return OSCSendInternalMessageWithRSVP(address, arglen, args, 0);
}
Boolean OSCSendInternalMessageWithRSVP(char *address, int arglen, void *args,
NetworkReturnAddressPtr returnAddr) {
callbackList l = OSCDispatchMessage(address);
if (l == 0) return FALSE;
CallWholeCallbackList(l, arglen, args, OSCTT_Immediately(), returnAddr);
return TRUE;
}
Boolean OSCScheduleInternalMessages(OSCTimeTag when, int numMessages,
char **addresses, int *arglens, void **args) {
int i, bufSizeNeeded;
OSCPacketBuffer p;
queuedData *qd;
char *bufPtr;
/* Figure out how big of a buffer we'll need to hold this huge bundle.
We don't store the "#bundle" string or the time tag, just the 4-byte
size counts, the addresses, possible extra null padding for the
addresses, and the arguments. */
bufSizeNeeded = 0;
for (i = 0; i < numMessages; ++i) {
bufSizeNeeded += 4 + OSCPaddedStrlen(addresses[i]) + arglens[i];
}
if (bufSizeNeeded > OSCGetReceiveBufferSize()) {
return FALSE;
}
/* Now try to allocate the data objects to hold these messages */
qd = AllocQD();
if (qd == 0) return FALSE;
p = OSCAllocPacketBuffer();
if (p == 0) {
FreeQD(qd);
return FALSE;
}
/* Now fill in the buffer with a fake #bundle message. This is almost like
putting a real #bundle message in the buffer and then calling OSCAcceptPacket,
except that we save a little time and memory by not writing "#bundle" or the time tag,
and by pre-parsing the messages a little. Thus, this code duplicates a lot
of what's in InsertBundleOrMessage() */
bufPtr = p->buf;
for (i = 0; i < numMessages; ++i) {
/* First the size count of this bundle element */
*((int4 *) bufPtr) = OSCPaddedStrlen(addresses[i]) + arglens[i];
bufPtr += sizeof(int4);
/* Then the address */
bufPtr = OSCPaddedStrcpy(bufPtr, addresses[i]);
/* Then the arguments */
memcpy(bufPtr, args[i], arglens[i]);
bufPtr += arglens[i];
}
#ifdef PARANOID
if (bufPtr != p->buf+bufSizeNeeded) {
fatal_error("OSCScheduleInternalMessages: internal error");
}
#endif
/* Fill in the rest of the packet fields */
p->n = bufSizeNeeded;
p->returnAddrOK = FALSE;
PacketAddRef(p);
/* Now fill in the queuedData object */
qd->timetag = when;
qd->myPacket = p;
qd->type = BUNDLE;
qd->data.bundle.length = bufSizeNeeded;
qd->data.bundle.bytes = p->buf;
/* Now we can put it into the scheduling queue. */
OSCQueueInsert(globals.TheQueue, (OSCSchedulableObject) qd);
return TRUE;
}
Boolean NetworkPacketWaiting(OSCPacketBuffer packet) {
int n;
NetworkReturnAddressPtr na = OSCPacketBufferGetClientAddr(packet);
// if( use_mcast_ )
// {
fd_set fds;
struct timeval no_wait;
int status;
memset( &no_wait, 0, sizeof(no_wait));
FD_ZERO(&fds);
FD_SET( na->sockfd , &fds );
status = select( na->sockfd + 1, &fds, 0, 0, &no_wait );
if(status <= 0)
return FALSE;
if(FD_ISSET( na->sockfd, &fds ))
return TRUE;
// }
// else
// {
// if( ioctl( na->sockfd, FIONREAD, &n, 0)==-1) return FALSE;
// if( n==0 ) return FALSE;
// }
// return TRUE;
return FALSE;
}
Boolean NetworkReceivePacket( OSCPacketBuffer packet ) {
int n;
NetworkReturnAddressPtr na = OSCPacketBufferGetClientAddr(packet);
if( use_mcast_ )
{
n = recv( na->sockfd, packet->buf, 100, 0 );
if( n<= 0)
return FALSE;
packet->n = n;
}
else
{
n = recvfrom( na->sockfd, packet->buf, 100, 0,
(struct sockaddr*) &(na->cl_addr), &(na->clilen));
if(n<=0) {
return FALSE;
}
packet->n = n;
}
return TRUE;
}
void GoMultiCast( const char *group_name )
{
use_mcast_ = 1;
strncpy( mcast_groupname, group_name, strlen(group_name ));
}
int IsMultiCast( char *dst )
{
if(use_mcast_)
sprintf(dst, "%s", mcast_groupname );
return use_mcast_;
}
Boolean NetworkStartUDPServer(OSCPacketBuffer packet, int port_id) {
struct sockaddr_in my_addr;
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(port_id);
my_addr.sin_addr.s_addr = INADDR_ANY;
memset( &(my_addr.sin_zero), 0, 8);
if( use_mcast_ )
{
struct ip_mreq mcast_req;
int on = 1;
int err= 0;
memset( &mcast_req, 0, sizeof(mcast_req));
packet->returnAddr->sockfd = socket( AF_INET, SOCK_DGRAM, 0);
#ifdef SO_REUSEADDR
setsockopt( packet->returnAddr->sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
#endif
#ifdef SO_REUSEPORT
setsockopt( packet->returnAddr->sockfd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
#endif
err = bind( packet->returnAddr->sockfd, (struct sockaddr*) &my_addr, sizeof( my_addr ));
if( err < 0 )
return FALSE;
mcast_req.imr_multiaddr.s_addr = inet_addr( mcast_groupname );
mcast_req.imr_interface.s_addr = htonl( INADDR_ANY );
setsockopt( packet->returnAddr->sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
&mcast_req, sizeof(mcast_req) );
}
else
{
packet->returnAddr->sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if( bind( packet->returnAddr->sockfd,
(struct sockaddr*) &my_addr,
sizeof(struct sockaddr)) == -1) return FALSE;
packet->returnAddr->clilen = sizeof(struct sockaddr);
}
return TRUE;
}

View File

@@ -0,0 +1,242 @@
/*
Copyright <20> 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-receive.h
Matt Wright, 11/18/97
include OSC-timetag.h and NetworkReturnAddress.h before this file.
*/
/**************************************************
Initialization and memory pre-allocation
**************************************************/
/* The memory model used by this module is pre-allocation of fixed-size
objects for network buffers and other internal objects. This preallocated
memory is dynamically managed internally by a custom high-performance memory
allocator. When the preallocated memory runs out, this module calls an
optional realtime memory allocator that you provide. If your memory
allocator gives this module more memory, it will add it to the pool of
objects and never free the memory. If your system does not have a realtime
memory allocator, provide a procedure that always returns 0.
You will fill an OSCReceiveMemoryTuner struct with the parameters that
determine how memory will be allocated.
The MemoryAllocator fields are procedures you will provide that allocate
memory. Like malloc(), they take the number of bytes as arguments and return
either a pointer to the new memory or 0 for failure. This memory will never
be freed.
- The InitTimeMemoryAllocator will be called only at initialization time,
i.e., before OSCInitAddressSpace() returns. If it ever returns 0, that's
a fatal error.
- The RealTimeMemoryAllocator will be called if, while the application is
running, the address space grows larger than can fit in what was allocated
at initialization time. If the RealTimeMemoryAllocator() returns 0, the
operation attempting to grow the address space will fail. If your system
does not have real-time memory allocation, RealTimeMemoryAllocator should
be a procedure that always returns 0.
The remaining fields say how much memory to allocate at initialization time:
- receiveBufferSize is the maximum packet size that can be received. Is the
maximum UDP packet size 4096? OSC clients can send a query to this system
asking for this maximum packet size.
- numReceiveBuffers determines how many packets at a time can be sitting
on the scheduler with messages waiting to take effect. If all the
receive buffers are tied up like this, you won't be able to receive
new packets.
- numQueuedObjects is the number of messages and packets that can be sitting
on the scheduler waiting to take effect.
- Because a message pattern may be dispatched before the message takes effect,
we need memory to store the callback pointers corresponding to a message.
numCallbackListNodes is the number of callbacks that may be stored in this
fashion. It must be at least as large as the maximum number of methods that
any one message pattern may match, but if you want to take advantage of
pre-dispatching, this should be large enough to hold all the callbacks for
all the messages waiting in the scheduler.
*/
struct OSCReceiveMemoryTuner {
void *(*InitTimeMemoryAllocator)(int numBytes);
void *(*RealTimeMemoryAllocator)(int numBytes);
int receiveBufferSize;
int numReceiveBuffers;
int numQueuedObjects;
int numCallbackListNodes;
};
/* Given an OSCReceiveMemoryTuner, return the number of bytes of
memory that would be allocated if OSCInitReceive() were called
on it. */
int OSCReceiveMemoryThatWouldBeAllocated(struct OSCReceiveMemoryTuner *t);
/* Returns FALSE if it fails to initialize */
Boolean OSCInitReceive(struct OSCReceiveMemoryTuner *t);
/**************************************************
Managing packet data structures
**************************************************/
/* You don't get to know what's in an OSCPacketBuffer. */
typedef struct OSCPacketBuffer_struct *OSCPacketBuffer;
/* Get an unused packet. Returns 0 if none are free. If you get a packet
with this procedure, it is your responsibility either to call
OSCAcceptPacket() on it (in which case the internals of the OSC Kit free
the OSCPacketBuffer after the last message in it takes effect) or to call
OSCFreePacket() on it. */
OSCPacketBuffer OSCAllocPacketBuffer(void);
/* Free. This is called automatically after the last message that was
in the packet is invoked. You shouldn't need to call this unless
you get a packet with OSCAllocPacketBuffer() and then for some reason
decide not to call OSCAcceptPacket() on it. */
void OSCFreePacket(OSCPacketBuffer p);
void OSCFreeReceiver(void);
/* Whatever code actually gets packets from the network should use these
three selectors to access the fields in the packet structure that need
to be filled in with the data from the network. */
/* Selector to get the buffer from a packet. This buffer's size will be
equal to the receiveBufferSize you passed to OSCInitReceive(). */
char *OSCPacketBufferGetBuffer(OSCPacketBuffer p);
/* Selector to get a pointer to the int that's the size count for the
data currently in a packet. (Not the capacity of the packet's buffer,
but the size of the packet that's actually stored in the buffer.) */
int *OSCPacketBufferGetSize(OSCPacketBuffer);
/* Selector to get the client's network address from a packet. This buffer's
size will be equal to the clientAddrSize you passed to OSCInitReceive().
Note that the NetworkReturnAddressPtr type is full of "const"s, so your
code that fills in the return address will probably have to cast the return
value of this procedure to some non-const type to be able to write into it. */
NetworkReturnAddressPtr OSCPacketBufferGetClientAddr(OSCPacketBuffer p);
/* Returns the capacity of packet buffers (the receiveBufferSize you passed
to OSCInitReceive()). */
int OSCGetReceiveBufferSize(void);
/**************************************************
Dealing with OpenSoundControl packets and
making the messages take effect.
**************************************************/
/* Call this as soon as a packet comes in from the network.
It will take care of anything that has to happen immediately,
but put off as much as possible of the work of parsing the
packet. (This tries to be as fast as possible in case a
lot of packets come in.) */
void OSCAcceptPacket(OSCPacketBuffer packet);
/* Call this during an otherwise idle time. It goes through
everything that's sitting in the OSC scheduler waiting to
happen and does some of the work of parsing, pattern
matching, dispatching, etc., that will have to be done
at some point before the scheduled messages can take
effect.
The return value indicates whether there is more work of
this sort that could be done. (Each time you call this,
it does only a small unit of this kind of work. If it
returns TRUE and you still have time before the next thing
you have to do, call it again.) */
Boolean OSCBeProductiveWhileWaiting(void);
/* Call this whenever enough time has passed that you want to see which
messages are now ready and have them take effect. (For example, in a
synthesizer, you might call this once per synthesis frame, just before
synthesizing the audio for that frame.)
This procedure finds the earliest time tag of all the queued messages
and invokes *all* of the queued messages with that time tag. (OSC
guarantees that messages with the same tag take effect atomically.)
If there are more messages that are ready, but with a different time
tag, this procedure does not invoke them, but returns TRUE to indicate
that more messages are ready.
*/
Boolean OSCInvokeMessagesThatAreReady(OSCTimeTag now);
/* Same thing, but invokes all of the messages whose time has come. */
void OSCInvokeAllMessagesThatAreReady(OSCTimeTag now);
Boolean NetworkReceivePacket(OSCPacketBuffer packet);
Boolean NetworkStartUDPServer(OSCPacketBuffer packet, int port_id);
Boolean NetworkPacketWaiting(OSCPacketBuffer packet);
void GoMultiCast(const char *groupname);
int IsMultiCast( char *dst);
/**************************************************
How to use this stuff
**************************************************/
/* Here's a gross approximation of how your application will invoke the
procedures in this module:
while (1) {
OSCTimeTag now = CurrentTime();
do {
if (WeAreSoLateThatWeNeedToDelayOSCMessagesToAvoidACrisis()) break;
} while (OSCInvokeMessagesThatAreReady(now) == TRUE);
SynthesizeSomeSound();
if (NetworkPacketWaiting()) {
OSCPacketBuffer p = OSCAllocPacketBuffer();
if (!p) {
Bummer();
} else {
NetworkReceivePacket(p);
OSCAcceptPacket(p);
}
}
while (TimeLeftBeforeWeHaveDoSomething()) {
if (!OSCBeProductiveWhileWaiting()) break;
}
}
*/

View File

@@ -0,0 +1,123 @@
/*
Copyright <20> 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-string-help.c
Procedures that could be useful to programmers writing OSC methods that
take string arguments.
by Matt Wright, 3/19/98
*/
#include <libOSC/OSC-common.h> /* For Boolean */
#include <stdint.h>
#include <sys/time.h>
#define STRING_ALIGN_PAD 4
char *OSCDataAfterAlignedString(const char *string, const char *boundary, char **errorMsg) {
int i;
if ((boundary - string) %4 != 0) {
fatal_error("DataAfterAlignedString: bad boundary\n");
}
for (i = 0; string[i] != '\0'; i++) {
if (string + i >= boundary) {
(*errorMsg) = "DataAfterAlignedString: Unreasonably long string";
return 0;
}
}
/* Now string[i] is the first null character */
i++;
for (; (i % STRING_ALIGN_PAD) != 0; i++) {
if (string + i >= boundary) {
(*errorMsg) = "Unreasonably long string";
return 0;
}
if (string[i] != '\0') {
(*errorMsg) = "Incorrectly padded string.";
return 0;
}
}
return (char *) (string+i);
}
int OSCPaddedStrlen(const char *s) {
int i;
for (i = 0; *s != '\0'; s++, i++) {
/* do nothing */
}
/* Now i is the length with no null bytes. We need 1-4 null bytes,
to make the total length a multiple of 4. So we add 4, as if
we need 4 null bytes, then & 0xfffffffc to round down to the nearest
multiple of 4. */
return (i + 4) & 0xfffffffc;
}
char *OSCPaddedStrcpy(char *target, const char *source) {
while ( (*target++) = (*source++)) {
/* do nothing */
}
/* That copied one null byte */
while (((int) target) % 4 != 0) {
*target = '\0';
target++;
}
return target;
}
Boolean OSCParseStringList(const char *result[], int *numStrings, int maxStrings,
const char *args, int numBytes) {
int numFound;
const char *p;
const char *boundary = args + numBytes;
char *errorMessage;
p = args;
for (numFound = 0; numFound < maxStrings; ++numFound) {
if (p == boundary) {
*numStrings = numFound;
return TRUE;
}
result[numFound] = p;
p = OSCDataAfterAlignedString(p, boundary, &errorMessage);
if (p == 0) return FALSE;
}
return FALSE;
}

View File

@@ -0,0 +1,70 @@
/*
Copyright <20> 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-string-help.h
Procedures that could be useful to programmers writing OSC methods that
take string arguments.
by Matt Wright, 3/19/98
*/
/* Use this to deal with OSC null-padded 4 byte-aligned strings
The argument is a block of data beginning with a string. The string
has (presumably) been padded with extra null characters so that the
overall length is a multiple of 4 bytes. Return a pointer to the next
byte after the null byte(s). The boundary argument points to the
character after the last valid character in the buffer---if the string
hasn't ended by there, something's wrong.
If the data looks wrong, return 0, and set *errorMsg */
char *OSCDataAfterAlignedString(const char *string, const char *boundary, char **errorMsg);
/* Given a normal C-style string with a single padding byte, return the
length of the string including the necessary 1-4 padding bytes.
(Basically strlen()+1 rounded up to the next multiple of 4.) */
int OSCPaddedStrlen(const char *s);
/* Copy a given C-style string into the given destination, including the
requisite padding byte(s). Unlike strcpy(), this returns a pointer to
the next character after the copied string's null bytes, like
what OSCDataAfterAlignedString() returns. */
char *OSCPaddedStrcpy(char *target, const char *source);
/* Given an args pointer that should be nothing but a list of strings, fill
result[] with pointers to the beginnings of each string, and set
*numStrings to be the number of strings found. maxStrings gives the size
of the result array. Return FALSE if any strings are malformatted or if
there are more than maxStrings many strings. */
Boolean OSCParseStringList(const char *result[], int *numStrings, int maxStrings,
const char *args, int numBytes);

View File

@@ -0,0 +1,56 @@
#include <netinet/in.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#ifndef OSCH
#define OSCH
#ifndef TRUE
typedef int Boolean;
#define TRUE 1
#define FALSE 0
#endif
/* Fixed byte width types */
typedef int int4; /* 4 byte int */
typedef struct NetworkReturnAddressStruct_t {
struct sockaddr_in cl_addr; /* client information */
struct sockaddr_in my_addr; /* us */
int clilen;
int sockfd;
fd_set readfds;
struct timeval tv;
int fdmax;
} NetworkReturnAddressStruct;
typedef struct OSCPacketBuffer_struct {
char *buf; /* Contents of network packet go here */
int n; /* Overall size of packet */
int refcount; /* # queued things using memory from this buffer */
struct OSCPacketBuffer_struct *nextFree; /* For linked list of free packets */
Boolean returnAddrOK; /* Because returnAddr points to memory we need to
store future return addresses, we set this
field to FALSE in situations where a packet
buffer "has no return address" instead of
setting returnAddr to 0 */
void *returnAddr; /* Addr of client this packet is from */
/* This was of type NetworkReturnAddressPtr, but the constness
was making it impossible for me to initialize it. There's
probably a better way that I don't understand. */
} OSCPacketBuffer;
struct OSCReceiveMemoryTuner {
void *(*InitTimeMemoryAllocator)(int numBytes);
void *(*RealTimeMemoryAllocator)(int numBytes);
int receiveBufferSize;
int numReceiveBuffers;
int numQueuedObjects;
int numCallbackListNodes;
};
#endif

View File

@@ -0,0 +1,174 @@
/*
Copyright <20> 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_timeTag.c: library for manipulating OSC time tags
Matt Wright, 5/29/97
Version 0.2 (9/11/98): cleaned up so no explicit type names in the .c file.
*/
#include <libOSC/OSC-timetag.h>
#include <stdint.h>
#include <sys/time.h>
#ifdef HAS8BYTEINT
#define TWO_TO_THE_32_FLOAT 4294967296.0f
OSCTimeTag OSCTT_Immediately(void) {
return (OSCTimeTag) 1;
}
OSCTimeTag OSCTT_BiggestPossibleTimeTag(void) {
return (OSCTimeTag) 0xffffffffffffffff;
}
OSCTimeTag OSCTT_PlusSeconds(OSCTimeTag original, float secondsOffset) {
int8 offset = (int8) (secondsOffset * TWO_TO_THE_32_FLOAT);
/* printf("* OSCTT_PlusSeconds %llx plus %f seconds (i.e., %lld offset) is %llx\n", original,
secondsOffset, offset, original + offset); */
return original + offset;
}
int OSCTT_Compare(OSCTimeTag left, OSCTimeTag right) {
#if 0
printf("***** OSCTT_Compare(%llx, %llx): %d\n", left, right,
(left<right) ? -1 : ((left == right) ? 0 : 1));
#endif
if (left < right) {
return -1;
} else if (left == right) {
return 0;
} else {
return 1;
}
}
#ifdef __sgi
#include <sys/time.h>
#define SECONDS_FROM_1900_to_1970 2208988800 /* 17 leap years */
#define TWO_TO_THE_32_OVER_ONE_MILLION 4295
OSCTimeTag OSCTT_CurrentTime(void) {
uint8 result;
uint4 usecOffset;
struct timeval tv;
struct timezone tz;
BSDgettimeofday(&tv, &tz);
/* First get the seconds right */
result = (unsigned) SECONDS_FROM_1900_to_1970 +
(unsigned) tv.tv_sec -
(unsigned) 60 * tz.tz_minuteswest +
(unsigned) (tz.tz_dsttime ? 3600 : 0);
#if 0
/* No timezone, no DST version ... */
result = (unsigned) SECONDS_FROM_1900_to_1970 +
(unsigned) tv.tv_sec;
#endif
/* make seconds the high-order 32 bits */
result = result << 32;
/* Now get the fractional part. */
usecOffset = (unsigned) tv.tv_usec * (unsigned) TWO_TO_THE_32_OVER_ONE_MILLION;
/* printf("** %ld microsec is offset %x\n", tv.tv_usec, usecOffset); */
result += usecOffset;
/* printf("* OSCTT_CurrentTime is %llx\n", result); */
return result;
}
#else /* __sgi */
/* Instead of asking your operating system what time it is, it might be
clever to find out the current time at the instant your application
starts audio processing, and then keep track of the number of samples
output to know how much time has passed. */
/* Loser version for systems that have no ability to tell the current time: */
OSCTimeTag OSCTT_CurrentTime(void) {
return (OSCTimeTag) 1;
}
#endif /* __sgi */
#else /* Not HAS8BYTEINT */
OSCTimeTag OSCTT_CurrentTime(void) {
OSCTimeTag result;
result.seconds = 0;
result.fraction = 1;
return result;
}
OSCTimeTag OSCTT_BiggestPossibleTimeTag(void) {
OSCTimeTag result;
result.seconds = 0xffffffff;
result.fraction = 0xffffffff;
return result;
}
OSCTimeTag OSCTT_Immediately(void) {
OSCTimeTag result;
result.seconds = 0;
result.fraction = 1;
return result;
}
OSCTimeTag OSCTT_PlusSeconds(OSCTimeTag original, float secondsOffset) {
OSCTimeTag result;
result.seconds = 0;
result.fraction = 1;
return result;
}
int OSCTT_Compare(OSCTimeTag left, OSCTimeTag right) {
/* Untested! */
int highResult = left.seconds - right.seconds;
if (highResult != 0) return highResult;
return left.fraction - right.fraction;
}
#endif /* HAS8BYTEINT */

View File

@@ -0,0 +1,91 @@
/*
Copyright <20> 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_timeTag.h: library for manipulating OSC time tags
Matt Wright, 5/29/97
Time tags in OSC have the same format as in NTP: 64 bit fixed point, with the
top 32 bits giving number of seconds sinve midnight 1/1/1900 and the bottom
32 bits giving fractional parts of a second. We represent this by an 8-byte
unsigned long if possible, or else a struct.
NB: On many architectures with 8-byte ints, it's illegal (like maybe a bus error)
to dereference a pointer to an 8 byte int that's not 8-byte aligned.
*/
#ifndef OSC_TIMETAG
#define OSC_TIMETAG
#ifdef __sgi
#define HAS8BYTEINT
/* You may have to change this typedef if there's some other
way to specify 8 byte ints on your system */
typedef long long int8;
typedef unsigned long long uint8;
typedef unsigned long uint4;
#else
/* You may have to redefine this typedef if ints on your system
aren't 4 bytes. */
typedef unsigned int uint4;
#endif
#ifdef HAS8BYTEINT
typedef uint8 OSCTimeTag;
#else
typedef struct {
uint4 seconds;
uint4 fraction;
} OSCTimeTag;
#endif
/* Return a time tag representing the current time (as of when this
procedure is called). */
OSCTimeTag OSCTT_CurrentTime(void);
/* Return the time tag 0x0000000000000001, indicating to the receiving device
that it should process the message immediately. */
OSCTimeTag OSCTT_Immediately(void);
/* Return the time tag 0xffffffffffffffff, a time so far in the future that
it's effectively infinity. */
OSCTimeTag OSCTT_BiggestPossibleTimeTag(void);
/* Given a time tag and a number of seconds to add to the time tag, return
the new time tag */
OSCTimeTag OSCTT_PlusSeconds(OSCTimeTag original, float secondsOffset);
/* Compare two time tags. Return negative if first is < second, 0 if
they're equal, and positive if first > second. */
int OSCTT_Compare(OSCTimeTag left, OSCTimeTag right);
#endif /* OSC_TIMETAG */

View File

@@ -0,0 +1,26 @@
#ifndef _LIBOSC_H_INCLUDED
#define _LIBOSC_H_INCLUDED
#ifdef __cplusplus
extern "C" {
#endif
#include <libOSC/OSC-common.h>
#include <libOSC/OSC-timetag.h>
#include <libOSC/OSC-address-space.h>
#include <libOSC/OSC-dispatch.h>
#include <libOSC/OSC-receive.h>
#include <libOSC/OSC-callbacklist.h>
#include <libOSC/OSC-drop.h>
#include <libOSC/OSC-internal-messages.h>
#include <libOSC/OSC-pattern-match.h>
#include <libOSC/OSC-priority-queue.h>
#include <libOSC/OSC-string-help.h>
#include <libOSC/NetworkReturnAddress.h>
#include <libOSC/NetworkUDP.h>
#ifdef __cplusplus
}
#endif
#endif