mirror of
https://github.com/game-stop/veejay.git
synced 2025-12-20 06:40:01 +01:00
further work on veejay-ng , prepare freeframe support, prepared handling of output parameters, removed OSC (moving to liblo), minor modifications and bugfixes
git-svn-id: svn://code.dyne.org/veejay/trunk@583 eb8d1916-c9e9-0310-b8de-cf0c9472ead5
This commit is contained in:
@@ -1,12 +1,9 @@
|
||||
# Process with automake to produce Makefile.in
|
||||
|
||||
SUBDIRS = bio2jack libOSC libhash libvjmsg libvjmem
|
||||
SUBDIRS = bio2jack libhash libvjmsg libvjmem
|
||||
SUBDIRS += libvevo libplugger libvjnet libyuv libel libvjaudio vevosample veejay
|
||||
SUBDIRS += man
|
||||
|
||||
#SUBDIRS = ffmpeg bio2jack libOSC libhash libvjmsg libvjmem libpostproc libvje libsample libvjnet libyuv libel libstream liblavjpeg libsamplerec plugins veejay gveejay tools man
|
||||
|
||||
#bin_SCRIPTS = veejay-config
|
||||
|
||||
#
|
||||
# Add any non autoconf'd files here, extra readmes and other misc
|
||||
|
||||
@@ -764,7 +764,6 @@ dnl Output a Makefile or two and the lib/header descriptor script
|
||||
dnl
|
||||
AC_CONFIG_FILES([
|
||||
Makefile
|
||||
libOSC/Makefile
|
||||
libhash/Makefile
|
||||
libvjmsg/Makefile
|
||||
libvevo/Makefile
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
INCLUDES = -I$(top_srcdir)/libOSC -I$(includedir)
|
||||
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
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
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);
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
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);
|
||||
@@ -1,7 +0,0 @@
|
||||
#include <netinet/in.h>
|
||||
|
||||
struct NetworkReturnAddressStruct {
|
||||
struct sockaddr_in cl_addr;
|
||||
int clilen;
|
||||
int sockfd;
|
||||
};
|
||||
@@ -1,599 +0,0 @@
|
||||
/*
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1,364 +0,0 @@
|
||||
/*
|
||||
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);
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
/*
|
||||
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;
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
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);
|
||||
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
/*
|
||||
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);*/
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
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, ...);
|
||||
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
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);
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
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.");
|
||||
}
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
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);
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
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);
|
||||
@@ -1,193 +0,0 @@
|
||||
/*
|
||||
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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
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);
|
||||
|
||||
@@ -1,190 +0,0 @@
|
||||
/*
|
||||
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) {
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
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);
|
||||
@@ -1,893 +0,0 @@
|
||||
/*
|
||||
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;
|
||||
}
|
||||
@@ -1,242 +0,0 @@
|
||||
/*
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
/*
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
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);
|
||||
@@ -1,56 +0,0 @@
|
||||
#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
|
||||
@@ -1,174 +0,0 @@
|
||||
/*
|
||||
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 */
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
/*
|
||||
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 */
|
||||
@@ -1,26 +0,0 @@
|
||||
#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
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
@@ -14,19 +15,35 @@
|
||||
#define LINUX 1
|
||||
#include <libplugger/specs/FreeFrame.h>
|
||||
#define V_BITS 32
|
||||
#include <libplugger/freeframe-loader.h>
|
||||
|
||||
#ifdef STRICT_CHECKING
|
||||
#include <assert.h>
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int w;
|
||||
int h;
|
||||
uint8_t *rgb;
|
||||
} ff_frame_t;
|
||||
|
||||
|
||||
/** \defgroup freeframe FreeFrame Host
|
||||
*
|
||||
* Provides a host implementation for FreeFrame plugins, see http://freeframe.sourceforge.net
|
||||
*/
|
||||
|
||||
#if (V_BITS == 32)
|
||||
//#if (V_BITS == 32)
|
||||
#define FF_CAP_V_BITS_VIDEO FF_CAP_32BITVIDEO
|
||||
#elif (V_BITS == 24)
|
||||
static int freeframe_signature_ = VEVO_PLUG_FF;
|
||||
|
||||
|
||||
/*#elif (V_BITS == 24)
|
||||
#define FF_CAP_V_BITS_VIDEO FF_CAP_24BITVIDEO
|
||||
#else // V_BITS = 16
|
||||
#define FF_CAP_V_BITS_VIDEO FF_CAP_16BITVIDEO
|
||||
#endif
|
||||
#endif*/
|
||||
|
||||
void* deal_with_ff( void *handle, char *name )
|
||||
{
|
||||
@@ -36,7 +53,7 @@ void* deal_with_ff( void *handle, char *name )
|
||||
|
||||
if( q == NULL )
|
||||
{
|
||||
veejay_msg(VEEJAY_MSG_ERROR,"\tBorked FF plugin '%s': %s", name, dlerror());
|
||||
veejay_msg(VEEJAY_MSG_ERROR,"\tBad FreeFrame plugin '%s': %s", name, dlerror());
|
||||
vevo_port_free( port );
|
||||
return NULL;
|
||||
}
|
||||
@@ -45,7 +62,7 @@ void* deal_with_ff( void *handle, char *name )
|
||||
|
||||
if ((q(FF_GETPLUGINCAPS, (LPVOID)FF_CAP_V_BITS_VIDEO, 0)).ivalue != FF_TRUE)
|
||||
{
|
||||
veejay_msg(VEEJAY_MSG_ERROR, "%s:%d", __FUNCTION__,__LINE__ );
|
||||
veejay_msg(VEEJAY_MSG_ERROR, "FreeFrame plugin '%s' cannot handle 32 bit",name);
|
||||
vevo_port_free(port);
|
||||
return NULL;
|
||||
}
|
||||
@@ -53,7 +70,7 @@ void* deal_with_ff( void *handle, char *name )
|
||||
|
||||
if (pis->APIMajorVersion < 1)
|
||||
{
|
||||
veejay_msg(VEEJAY_MSG_ERROR, "Cowardly refusing FF API version < 1.0" );
|
||||
veejay_msg(VEEJAY_MSG_ERROR, "Cowardly refusing FreeFrame API version < 1.0 (%s)",name );
|
||||
vevo_port_free(port);
|
||||
return NULL;
|
||||
}
|
||||
@@ -61,7 +78,7 @@ void* deal_with_ff( void *handle, char *name )
|
||||
plugin_name = strdup( pis->pluginName );
|
||||
if ( (q(FF_INITIALISE, NULL, 0 )).ivalue == FF_FAIL )
|
||||
{
|
||||
veejay_msg(VEEJAY_MSG_ERROR, "Cannot call init()");
|
||||
veejay_msg(VEEJAY_MSG_ERROR, "Plugin '%s' unable to initialize", name);
|
||||
vevo_port_free(port);
|
||||
if(plugin_name) free(plugin_name);
|
||||
return NULL;
|
||||
@@ -70,50 +87,64 @@ void* deal_with_ff( void *handle, char *name )
|
||||
int n_params = q( FF_GETNUMPARAMETERS, NULL, 0 ).ivalue;
|
||||
if( n_params == FF_FAIL )
|
||||
{
|
||||
veejay_msg(VEEJAY_MSG_ERROR, "Cannot get number of parameters");
|
||||
veejay_msg(VEEJAY_MSG_ERROR, "Cannot get number of parameters for plugin %s",name);
|
||||
vevo_port_free(port);
|
||||
if(plugin_name) free(plugin_name);
|
||||
return NULL;
|
||||
}
|
||||
int mix = 0;
|
||||
void *base = (void*) q;
|
||||
|
||||
int n_inputs = (q(FF_GETPLUGINCAPS, (LPVOID)FF_CAP_MINIMUMINPUTFRAMES, 0)).ivalue;
|
||||
|
||||
vevo_property_set( port, "handle", VEVO_ATOM_TYPE_VOIDPTR,1, &handle );
|
||||
vevo_property_set( port, "name", VEVO_ATOM_TYPE_STRING,1, &plugin_name );
|
||||
vevo_property_set( port, "base", VEVO_ATOM_TYPE_VOIDPTR, 1, &base );
|
||||
vevo_property_set( port, "instance", VEVO_ATOM_TYPE_INT, 0, NULL );
|
||||
vevo_property_set( port, "n_params", VEVO_ATOM_TYPE_INT, 1,&n_params );
|
||||
vevo_property_set( port, "mixer", VEVO_ATOM_TYPE_INT, 1,&mix );
|
||||
vevo_property_set( port, "num_params", VEVO_ATOM_TYPE_INT, 1,&n_params );
|
||||
vevo_property_set( port, "num_inputs", VEVO_ATOM_TYPE_INT,1, &n_inputs );
|
||||
vevo_property_set( port, "HOST_plugin_type", VEVO_ATOM_TYPE_INT, 1, &freeframe_signature_ );
|
||||
|
||||
veejay_msg(VEEJAY_MSG_INFO, "FF Load: '%s' , %d params, %d inputs", plugin_name, n_params, n_inputs );
|
||||
|
||||
int p;
|
||||
for( p= 0; p < n_params; p ++ )
|
||||
{
|
||||
void *parameter = vevo_port_new( VEVO_FF_PARAM_PORT );
|
||||
|
||||
int type = q( FF_GETPARAMETERTYPE, (LPVOID) p, 0 ).ivalue;
|
||||
// name, kind, flags, description, min,max,default,transition
|
||||
vevo_property_set( parameter, "type", VEVO_ATOM_TYPE_INT, 1, &type);
|
||||
|
||||
int min = 0;
|
||||
int max = 100;
|
||||
double min = 0;
|
||||
double max = 1.0;
|
||||
int kind = 0;
|
||||
|
||||
if( type == FF_TYPE_BOOLEAN )
|
||||
switch( type )
|
||||
{
|
||||
min = 0;
|
||||
max = 1;
|
||||
}
|
||||
else if( type == FF_TYPE_TEXT )
|
||||
{
|
||||
min = 0;
|
||||
max = 0;
|
||||
case FF_TYPE_BOOLEAN:
|
||||
kind = HOST_PARAM_SWITCH;
|
||||
break;
|
||||
case FF_TYPE_RED:
|
||||
case FF_TYPE_BLUE:
|
||||
case FF_TYPE_GREEN:
|
||||
case FF_TYPE_XPOS:
|
||||
case FF_TYPE_YPOS:
|
||||
case FF_TYPE_STANDARD:
|
||||
kind = HOST_PARAM_NUMBER;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
vevo_property_set( parameter, "min", VEVO_ATOM_TYPE_INT,1, &min );
|
||||
vevo_property_set( parameter, "max", VEVO_ATOM_TYPE_INT,1, &max );
|
||||
if(kind)
|
||||
continue;
|
||||
|
||||
float dvalue = 0.0;
|
||||
dvalue = q( FF_GETPARAMETERDEFAULT, (LPVOID) p, 0).fvalue;
|
||||
int ivalue = (int)(dvalue * 100.0);
|
||||
vevo_property_set( parameter, "default", VEVO_ATOM_TYPE_INT,1 ,&ivalue );
|
||||
void *parameter = vevo_port_new( VEVO_FF_PARAM_PORT );
|
||||
|
||||
double ivalue = (double)q( FF_GETPARAMETERDEFAULT, (LPVOID) p, 0).fvalue;
|
||||
|
||||
vevo_property_set( parameter, "default", VEVO_ATOM_TYPE_DOUBLE,1 ,&ivalue );
|
||||
vevo_property_set( parameter, "value" , VEVO_ATOM_TYPE_DOUBLE,1, &ivalue );
|
||||
vevo_property_set( parameter, "min", VEVO_ATOM_TYPE_DOUBLE, 1, &min );
|
||||
vevo_property_set( parameter, "max", VEVO_ATOM_TYPE_DOUBLE,1, &max );
|
||||
vevo_property_set( parameter, "HOST_kind", VEVO_ATOM_TYPE_INT,1,&kind );
|
||||
|
||||
char key[20];
|
||||
snprintf(key,20, "p%02d", p );
|
||||
@@ -123,6 +154,158 @@ void* deal_with_ff( void *handle, char *name )
|
||||
return port;
|
||||
}
|
||||
|
||||
void freeframe_plug_retrieve_default_values( void *instance, void *fx_values )
|
||||
{
|
||||
void *base = NULL;
|
||||
int error = vevo_property_get( instance, "base", 0, &base);
|
||||
#ifdef STRICT_CHECING
|
||||
assert( error == LIVIDO_NO_ERROR );
|
||||
#endif
|
||||
|
||||
plugMainType *q = (plugMainType*) base;
|
||||
|
||||
int n = q( FF_GETNUMPARAMETERS, NULL, 0 ).ivalue;
|
||||
int i;
|
||||
|
||||
for( i = 0; i < n; i ++ )
|
||||
{
|
||||
char vkey[64];
|
||||
double ivalue = (double)q( FF_GETPARAMETERDEFAULT, (LPVOID) i, 0).fvalue;
|
||||
sprintf(vkey, "p%02d",i);
|
||||
vevo_property_set( fx_values, vkey, VEVO_ATOM_TYPE_DOUBLE,1, &ivalue );
|
||||
}
|
||||
}
|
||||
|
||||
void freeframe_plug_retrieve_current_values( void *instance, void *fx_values )
|
||||
{
|
||||
void *base = NULL;
|
||||
int error = vevo_property_get( instance, "base", 0, &base);
|
||||
#ifdef STRICT_CHECING
|
||||
assert( error == LIVIDO_NO_ERROR );
|
||||
#endif
|
||||
|
||||
plugMainType *q = (plugMainType*) base;
|
||||
|
||||
int n = q( FF_GETNUMPARAMETERS, NULL, 0 ).ivalue;
|
||||
int i;
|
||||
|
||||
for( i = 0; i < n; i ++ )
|
||||
{
|
||||
char vkey[64];
|
||||
double ivalue = (double)q( FF_GETPARAMETER, (LPVOID) i, 0).fvalue;
|
||||
sprintf(vkey, "p%02d",i);
|
||||
vevo_property_set( fx_values, vkey, VEVO_ATOM_TYPE_DOUBLE,1, &ivalue );
|
||||
}
|
||||
}
|
||||
|
||||
void freeframe_reverse_clone_parameter( void *instance, int seq, void *fx_values )
|
||||
{
|
||||
void *base = NULL;
|
||||
int error = vevo_property_get( instance, "base", 0, &base);
|
||||
#ifdef STRICT_CHECING
|
||||
assert( error == LIVIDO_NO_ERROR );
|
||||
#endif
|
||||
|
||||
plugMainType *q = (plugMainType*) base;
|
||||
|
||||
int n = q( FF_GETNUMPARAMETERS, NULL, 0 ).ivalue;
|
||||
int i;
|
||||
|
||||
for( i = 0; i < n; i ++ )
|
||||
{
|
||||
char vkey[64];
|
||||
double ivalue = (double)q( FF_GETPARAMETER, (LPVOID) i, 0).fvalue;
|
||||
sprintf(vkey, "p%02d",i);
|
||||
vevo_property_set( fx_values, vkey, VEVO_ATOM_TYPE_DOUBLE,1, &ivalue );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void freeframe_clone_parameter( void *instance, int seq, void *fx_values )
|
||||
{
|
||||
// put fx_values to freeframe
|
||||
void *base = NULL;
|
||||
int error = vevo_property_get( instance, "base", 0, &base);
|
||||
#ifdef STRICT_CHECING
|
||||
assert( error == LIVIDO_NO_ERROR );
|
||||
#endif
|
||||
|
||||
plugMainType *q = (plugMainType*) base;
|
||||
|
||||
int n = q( FF_GETNUMPARAMETERS, NULL, 0 ).ivalue;
|
||||
int i;
|
||||
|
||||
for( i = 0; i < n; i ++ )
|
||||
{
|
||||
char key[64];
|
||||
sprintf(key, "p%02d",i);
|
||||
|
||||
float value = 0.0;
|
||||
SetParameterStruct v;
|
||||
|
||||
vevo_property_get( fx_values, key, 0, &value );
|
||||
|
||||
v.value = value;
|
||||
v.index = i;
|
||||
|
||||
q( FF_SETPARAMETER, &v, instance );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
int freeframe_set_parameter_from_string( void *instance, int p, const char *str, void *fx_values )
|
||||
{
|
||||
void *base = NULL;
|
||||
int error = vevo_property_get( instance, "base", 0, &base);
|
||||
#ifdef STRICT_CHECING
|
||||
assert( error == LIVIDO_NO_ERROR );
|
||||
#endif
|
||||
|
||||
int kind = 0;
|
||||
error = vevo_property_get( instance, "HOST_kind",0,&kind );
|
||||
#ifdef STRICT_CHECKING
|
||||
assert( error == VEVO_NO_ERROR );
|
||||
#endif
|
||||
|
||||
|
||||
plugMainType *q = (plugMainType*) base;
|
||||
int instance_id = 0;
|
||||
error = vevo_property_get( instance, "instance",0, &instance_id );
|
||||
#ifdef STRICT_CHECING
|
||||
assert( error == LIVIDO_NO_ERROR );
|
||||
#endif
|
||||
int res = 0;
|
||||
char vkey[64];
|
||||
sprintf(vkey, "p%02d", p );
|
||||
|
||||
switch(kind)
|
||||
{
|
||||
case HOST_PARAM_INDEX:
|
||||
res = vevo_property_from_string( fx_values,str, vkey,1, VEVO_ATOM_TYPE_INT );
|
||||
break;
|
||||
case HOST_PARAM_NUMBER:
|
||||
res = vevo_property_from_string( fx_values,str, vkey,1, VEVO_ATOM_TYPE_DOUBLE );
|
||||
break;
|
||||
case HOST_PARAM_SWITCH:
|
||||
res = vevo_property_from_string( fx_values,str, vkey,1, VEVO_ATOM_TYPE_BOOL );
|
||||
break;
|
||||
case HOST_PARAM_COORD:
|
||||
res = vevo_property_from_string( fx_values ,str, vkey,2, VEVO_ATOM_TYPE_DOUBLE );
|
||||
break;
|
||||
case HOST_PARAM_COLOR:
|
||||
res = vevo_property_from_string( fx_values,str, vkey,3, VEVO_ATOM_TYPE_DOUBLE );
|
||||
break;
|
||||
case HOST_PARAM_TEXT:
|
||||
res = vevo_property_from_string( fx_values,str, vkey,1, VEVO_ATOM_TYPE_STRING );
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int freeframe_plug_init( void *plugin, int w, int h )
|
||||
{
|
||||
VideoInfoStruct v;
|
||||
@@ -145,6 +328,76 @@ int freeframe_plug_init( void *plugin, int w, int h )
|
||||
return 0;
|
||||
}
|
||||
vevo_property_set( plugin, "instance", VEVO_ATOM_TYPE_INT, 1, &instance );
|
||||
|
||||
int num_channels = 0;
|
||||
int i;
|
||||
vevo_property_get( plugin, "num_inputs", 0, &num_channels );
|
||||
|
||||
void *buf = vevo_port_new( VEVO_ANONYMOUS_PORT );
|
||||
error = vevo_property_set( instance, "HOST_buffers",
|
||||
VEVO_ATOM_TYPE_PORTPTR,1,&buf);
|
||||
#ifdef STRICT_CHECKING
|
||||
assert( error == VEVO_NO_ERROR );
|
||||
#endif
|
||||
// input channels
|
||||
for( i = 0; i < num_channels; i ++ )
|
||||
{
|
||||
// reserve rgb buffer
|
||||
char key[10];
|
||||
uint8_t *space = (uint8_t*) vj_malloc(sizeof(uint8_t) * w * h * 4 );
|
||||
sprintf(key ,"in%02d",i);
|
||||
// store space
|
||||
vevo_property_set( buf, key, VEVO_ATOM_TYPE_VOIDPTR,1,&space);
|
||||
}
|
||||
// output channel
|
||||
|
||||
uint8_t *space = (uint8_t*) vj_malloc(sizeof(uint8_t) * w * h * 4 );
|
||||
vevo_property_set( buf, "output", VEVO_ATOM_TYPE_VOIDPTR,1,&space);
|
||||
|
||||
|
||||
generic_process_f gpf = freeframe_plug_process;
|
||||
vevo_property_set( instance,
|
||||
"HOST_plugin_process_f",
|
||||
VEVO_ATOM_TYPE_VOIDPTR,
|
||||
1,
|
||||
&gpf );
|
||||
|
||||
generic_push_channel_f gpu = freeframe_push_channel;
|
||||
vevo_property_set( instance,
|
||||
"HOST_plugin_push_f",
|
||||
VEVO_ATOM_TYPE_VOIDPTR,
|
||||
1,
|
||||
&gpu );
|
||||
|
||||
generic_clone_parameter_f gcc = freeframe_clone_parameter;
|
||||
vevo_property_set( instance,
|
||||
"HOST_plugin_param_clone_f",
|
||||
VEVO_ATOM_TYPE_VOIDPTR,
|
||||
1,
|
||||
&gcc );
|
||||
|
||||
generic_reverse_clone_parameter_f grc = freeframe_reverse_clone_parameter;
|
||||
vevo_property_set( instance,
|
||||
"HOST_plugin_param_reverse_f",
|
||||
VEVO_ATOM_TYPE_VOIDPTR,
|
||||
1,
|
||||
&grc );
|
||||
|
||||
generic_default_values_f gdb = freeframe_plug_retrieve_default_values;
|
||||
vevo_property_set( instance,
|
||||
"HOST_plugin_defaults_f",
|
||||
VEVO_ATOM_TYPE_VOIDPTR,
|
||||
1,
|
||||
&gdb );
|
||||
|
||||
generic_deinit_f gin = freeframe_plug_deinit;
|
||||
vevo_property_set( instance,
|
||||
"HOST_plugin_deinit_f",
|
||||
VEVO_ATOM_TYPE_VOIDPTR,
|
||||
1,
|
||||
&gin );
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -154,19 +407,44 @@ void freeframe_plug_deinit( void *plugin )
|
||||
void *base = NULL;
|
||||
int error = vevo_property_get( plugin, "base", 0, &base);
|
||||
#ifdef STRICT_CHECING
|
||||
assert( error == LIVIDO_NO_ERROR );
|
||||
assert( error == VEVO_NO_ERROR );
|
||||
#endif
|
||||
|
||||
plugMainType *q = (plugMainType*) base;
|
||||
|
||||
int instance = 0;
|
||||
error = vevo_property_get( plugin, "instance", 0, &instance );
|
||||
#ifdef STRICT_CHECING
|
||||
assert( error == LIVIDO_NO_ERROR );
|
||||
#ifdef STRICT_CHECKING
|
||||
assert( error == VEVO_NO_ERROR );
|
||||
#endif
|
||||
|
||||
if( instance )
|
||||
q( FF_DEINSTANTIATE, NULL, instance );
|
||||
if(! instance )
|
||||
return;
|
||||
|
||||
q( FF_DEINSTANTIATE, NULL, instance );
|
||||
|
||||
void *channels = NULL;
|
||||
error = vevo_property_get( plugin, "HOST_buffers",0,&channels);
|
||||
#ifdef STRICT_CHECKING
|
||||
assert( error == VEVO_NO_ERROR );
|
||||
#endif
|
||||
char **items = vevo_list_properties( channels );
|
||||
int i;
|
||||
for( i = 0; items[i] != NULL ; i ++ )
|
||||
{
|
||||
uint8_t *space = NULL;
|
||||
error = vevo_property_get( channels, items[i], 0, &space );
|
||||
#ifdef STRICT_CHECKING
|
||||
assert( error == VEVO_NO_ERROR );
|
||||
#endif
|
||||
free(space);
|
||||
}
|
||||
|
||||
uint8_t *space = NULL;
|
||||
error = vevo_property_get( plugin , "output", 0, &space );
|
||||
#ifdef STRICT_CHECKING
|
||||
assert( error == VEVO_NO_ERROR );
|
||||
#endif
|
||||
free(space);
|
||||
}
|
||||
|
||||
void freeframe_plug_free( void *plugin )
|
||||
@@ -181,7 +459,37 @@ void freeframe_plug_free( void *plugin )
|
||||
q( FF_DEINITIALISE, NULL, 0 );
|
||||
}
|
||||
|
||||
int freeframe_plug_process( void *plugin, void *in )
|
||||
void freeframe_push_channel( void *instance, const char *key,int n, VJFrame *frame )
|
||||
{
|
||||
char inkey[10];
|
||||
int i;
|
||||
void *chan = NULL;
|
||||
uint8_t *space = NULL;
|
||||
int error;
|
||||
if(key[0] == 'o' )
|
||||
{
|
||||
vevo_property_set( instance, "HOST_output", VEVO_ATOM_TYPE_VOIDPTR,1,&frame );
|
||||
}
|
||||
else
|
||||
{
|
||||
//@ convert rgb data
|
||||
sprintf(inkey, "in%02d",n );
|
||||
error = vevo_property_get( instance, "HOST_buffers",0,&chan );
|
||||
#ifdef STRICT_CHECKING
|
||||
assert( error == VEVO_NO_ERROR );
|
||||
#endif
|
||||
error = vevo_property_get( chan, inkey, 0, &space );
|
||||
#ifdef STRICT_CHECKING
|
||||
assert( error == VEVO_NO_ERROR );
|
||||
#endif
|
||||
util_convertrgba32( frame->data,frame->width,frame->height,frame->pixfmt, frame->shift_v,
|
||||
space );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
int freeframe_plug_process( void *plugin, double timecode )
|
||||
{
|
||||
void *base = NULL;
|
||||
int error = vevo_property_get( plugin, "base", 0, &base);
|
||||
@@ -196,47 +504,28 @@ int freeframe_plug_process( void *plugin, void *in )
|
||||
assert( error == LIVIDO_NO_ERROR );
|
||||
#endif
|
||||
|
||||
char *key = "in00";
|
||||
void *channels = NULL;
|
||||
error = vevo_property_get( plugin, "HOST_buffers",0,&channels );
|
||||
void *in = NULL;
|
||||
#ifdef STRICT_CHECING
|
||||
assert( error == LIVIDO_NO_ERROR );
|
||||
#endif
|
||||
error = vevo_property_get( channels, key, 0, &in );
|
||||
#ifdef STRICT_CHECING
|
||||
assert( error == LIVIDO_NO_ERROR );
|
||||
#endif
|
||||
q( FF_PROCESSFRAME, in, instance );
|
||||
|
||||
VJFrame *output_frame = NULL;
|
||||
|
||||
error = vevo_property_get( plugin, "HOST_output", 0,&output_frame );
|
||||
#ifdef STRICT_CHECING
|
||||
assert( error == LIVIDO_NO_ERROR );
|
||||
#endif
|
||||
util_convertsrc( in, output_frame->width, output_frame->height, output_frame->pixfmt,
|
||||
output_frame->data );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void freeframe_plug_control( void *port, int *args )
|
||||
{
|
||||
SetParameterStruct v;
|
||||
void *base = NULL;
|
||||
vevo_property_get( port, "base", 0, &base);
|
||||
plugMainType *q = (plugMainType*) base;
|
||||
int p,num_params=0;
|
||||
int instance = 0;
|
||||
int error = 0;
|
||||
error = vevo_property_get( port, "n_params", 0, &num_params);
|
||||
#ifdef STRICT_CHECING
|
||||
assert( error == LIVIDO_NO_ERROR );
|
||||
#endif
|
||||
error = vevo_property_get( port, "instance", 0, &instance );
|
||||
#ifdef STRICT_CHECING
|
||||
assert( error == LIVIDO_NO_ERROR );
|
||||
#endif
|
||||
|
||||
for( p = 0; p < num_params; p ++ )
|
||||
{
|
||||
v.value = ((float) args[p]) * 0.01;
|
||||
v.index = p;
|
||||
q( FF_SETPARAMETER, &v, instance );
|
||||
}
|
||||
}
|
||||
|
||||
void freeframe_plug_process_ext( void *port, void *in0, void *in1, void *out)
|
||||
{
|
||||
|
||||
#ifdef STRICT_CHECING
|
||||
assert(0);
|
||||
#endif
|
||||
/* void *base = NULL;
|
||||
vevo_property_get( plugin, "base", 0, &base);
|
||||
plugMainType *q = (plugMainType*) base;
|
||||
int instance = 0;
|
||||
vevo_property_get( plugin, "instance",0, &instance );
|
||||
q( FF_PROCESSFRAME, buffer, instance );*/
|
||||
|
||||
}
|
||||
|
||||
@@ -2,11 +2,23 @@
|
||||
#define FREEFRAME_LOADER
|
||||
void* deal_with_ff( void *handle, char *name );
|
||||
|
||||
int freeframe_plug_init( void *plugin , int w, int h );
|
||||
void freeframe_plug_deinit( void *plugin );
|
||||
|
||||
int freeframe_plug_process( void *plugin, double timecode );
|
||||
|
||||
|
||||
void freeframe_push_channel( void *instance, const char *key,int n, VJFrame *frame );
|
||||
|
||||
|
||||
void freeframe_plug_free( void *plugin );
|
||||
int freeframe_plug_process( void *plugin, void *in );
|
||||
void freeframe_plug_process_ext( void *plugin, void *in0, void *in1, void *out);
|
||||
void freeframe_plug_control( void *plugin, int *args );
|
||||
|
||||
void freeframe_plug_deinit( void *plugin );
|
||||
|
||||
|
||||
int freeframe_plug_init( void *plugin, int w, int h );
|
||||
|
||||
void freeframe_plug_retrieve_current_values( void *instance, void *fx_values );
|
||||
|
||||
void freeframe_plug_retrieve_default_values( void *instance, void *fx_values );
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -512,7 +512,7 @@ void *livido_plug_init(void *plugin,int w, int h )
|
||||
int num_out_params = init_ports_from_template(
|
||||
filter_instance, filter_templ,
|
||||
LIVIDO_PORT_TYPE_PARAMETER,
|
||||
"in_parameter_templates", "in_parameters",
|
||||
"out_parameter_templates", "out_parameters",
|
||||
w,h,0 );
|
||||
|
||||
if( num_out_params < 0 )
|
||||
@@ -520,6 +520,7 @@ void *livido_plug_init(void *plugin,int w, int h )
|
||||
|
||||
#ifdef STRICT_CHECKING
|
||||
assert( num_in_params >= 0 );
|
||||
assert( num_out_params >= 0 );
|
||||
assert( num_in_channels >= 0 );
|
||||
assert( num_out_channels >= 0 );
|
||||
#endif
|
||||
@@ -711,6 +712,26 @@ void livido_plug_retrieve_values( void *instance, void *fx_values )
|
||||
}
|
||||
}
|
||||
|
||||
void livido_plug_read_output_parameters( void *instance, void *fx_values )
|
||||
{
|
||||
int np = vevo_property_num_elements( instance, "out_parameters" );
|
||||
int i;
|
||||
for( i = 0; i < np ; i ++ )
|
||||
{
|
||||
char vkey[10];
|
||||
void *param = NULL;
|
||||
void *param_templ = NULL;
|
||||
|
||||
int error = vevo_property_get( instance, "out_parameters", i, ¶m );
|
||||
#ifdef STRICT_CHECKING
|
||||
assert( error == VEVO_NO_ERROR );
|
||||
#endif
|
||||
sprintf(vkey, "p%02d", i );
|
||||
clone_prop_vevo( param, fx_values, "value", vkey );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int livido_set_parameter_from_string( void *instance, int p, const char *str, void *fx_values )
|
||||
{
|
||||
void *param = NULL;
|
||||
|
||||
@@ -34,5 +34,6 @@ void livido_set_parameters_scaled( void *plugin, int *args );
|
||||
|
||||
void livido_exit( void );
|
||||
|
||||
void livido_plug_read_output_parameters( void *instance, void *fx_values );
|
||||
|
||||
#endif
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
* -# Frei0r plugins
|
||||
* -# FreeFrame plugins
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
@@ -64,25 +65,6 @@ static int n_fr_ = 0;
|
||||
static int n_lvd_ = 0;
|
||||
static int base_fmt_ = -1;
|
||||
|
||||
/*
|
||||
* port of plugins by name
|
||||
*
|
||||
* by name: get a value of a parameter, set a value of a parameter
|
||||
*
|
||||
* get parameter description
|
||||
* get plugin name etc
|
||||
*
|
||||
* this will make libvje obsolete
|
||||
* this will make the fx chain structure in libsample obsolete
|
||||
* this will change vj performer
|
||||
* this will change vj event
|
||||
*
|
||||
*
|
||||
* merge vevo-sample to sampleadm and merge with libstream
|
||||
* before continuing.
|
||||
*
|
||||
*/
|
||||
|
||||
static int select_f( const struct dirent *d )
|
||||
{
|
||||
return ( strstr( d->d_name, ".so" ) != NULL );
|
||||
@@ -107,25 +89,27 @@ static void *instantiate_plugin( void *plugin, int w , int h )
|
||||
#ifdef STRICT_CHECKING
|
||||
assert( error == VEVO_NO_ERROR );
|
||||
#endif
|
||||
/*
|
||||
if( type == VEVO_FF_PORT )
|
||||
{
|
||||
return freeframe_plug_init( plugin,w,h );
|
||||
}
|
||||
else if( type == VEVO_FR_PORT )
|
||||
{
|
||||
return frei0r_plug_init( plugin,w,h);
|
||||
}
|
||||
*/
|
||||
if ( type == VEVO_PLUG_LIVIDO )
|
||||
return livido_plug_init(plugin,w,h);
|
||||
|
||||
switch( type )
|
||||
{
|
||||
case VEVO_PLUG_LIVIDO:
|
||||
return livido_plug_init( plugin,w,h );
|
||||
break;
|
||||
case VEVO_PLUG_FF:
|
||||
return freeframe_plug_init( plugin,w,h);
|
||||
break;
|
||||
case VEVO_PLUG_FR:
|
||||
return frei0r_plug_init( plugin,w,h );
|
||||
break;
|
||||
default:
|
||||
#ifdef STRICT_CHECKING
|
||||
assert( type == VEVO_PLUG_LIVIDO );
|
||||
assert(0);
|
||||
#endif
|
||||
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}//@ warning: if init fails, plugin data should be freed (failed plugin)
|
||||
}
|
||||
|
||||
|
||||
static void deinstantiate_plugin( void *instance )
|
||||
{
|
||||
@@ -134,10 +118,11 @@ static void deinstantiate_plugin( void *instance )
|
||||
#endif
|
||||
generic_deinit_f gin;
|
||||
int error = vevo_property_get( instance, "HOST_plugin_deinit_f", 0, &gin );
|
||||
|
||||
#ifdef STRICT_CHECKING
|
||||
assert( error == 0 );
|
||||
assert( error == VEVO_NO_ERROR );
|
||||
#endif
|
||||
(*gin)( instance );
|
||||
(*gin)(instance);
|
||||
}
|
||||
|
||||
static void add_to_plugin_list( const char *path )
|
||||
@@ -270,39 +255,13 @@ static void free_plugin(void *plugin)
|
||||
__FUNCTION__,name,plugin,type );
|
||||
free(name);
|
||||
|
||||
int n = 0;
|
||||
|
||||
// freeframe_plug_free( plugin );
|
||||
// frei0r_plug_free( plugin );
|
||||
// livido_plug_free( plugin );
|
||||
|
||||
|
||||
// free_parameters(plugin,n);
|
||||
|
||||
void *handle = NULL;
|
||||
error = vevo_property_get( plugin, "handle", 0 , &handle );
|
||||
#ifdef STRICT_CHECKING
|
||||
assert( error == 0 );
|
||||
#endif
|
||||
if( handle ) dlclose( handle );
|
||||
// vevo_port_free( plugin );
|
||||
/*
|
||||
// livido_port_rrfree( plugin );
|
||||
switch(type)
|
||||
{
|
||||
case VEVO_PLUG_LIVIDO: livido_plug_free( plugin ); break;
|
||||
case VEVO_PLUG_FR:break;
|
||||
case VEVO_PLUG_FF:break;
|
||||
}
|
||||
*/
|
||||
|
||||
// livido_port_rrfree( plugin );
|
||||
if( type == VEVO_PLUG_LIVIDO )
|
||||
{
|
||||
//@FIXME
|
||||
// livido_port_free( plugin );
|
||||
vevo_port_recursive_free( plugin );
|
||||
}
|
||||
vevo_port_recursive_free( plugin );
|
||||
|
||||
}
|
||||
|
||||
@@ -349,19 +308,6 @@ static int scan_plugins()
|
||||
add_to_plugin_list( pch );
|
||||
pch = strtok( NULL, "\n");
|
||||
}
|
||||
|
||||
/*
|
||||
for( j=0; j < len; j ++ )
|
||||
{
|
||||
if(data[j] == '\0' )
|
||||
break;
|
||||
if( data[j] == '\n' )
|
||||
{ add_to_plugin_list( value ); bzero(value,PATH_MAX); k =0;}
|
||||
|
||||
if( isascii( data[j] ) && data[j] != '\n')
|
||||
{ value[k] = data[j]; if( k < PATH_MAX) k ++; }
|
||||
|
||||
}*/
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@@ -460,10 +406,30 @@ void plug_clone_from_parameters(void *instance, void *fx_values)
|
||||
generic_reverse_clone_parameter_f grc;
|
||||
int error = vevo_property_get( instance, "HOST_plugin_param_reverse_f", 0, &grc );
|
||||
#ifdef STRICT_CHECKING
|
||||
assert( error == 0 );
|
||||
assert( error == VEVO_NO_ERROR );
|
||||
#endif
|
||||
(*grc)( instance ,0, fx_values );
|
||||
|
||||
(*grc)( instance ,0, fx_values );
|
||||
}
|
||||
|
||||
void plug_clone_from_output_parameters( void *instance, void *fx_values )
|
||||
{
|
||||
#ifdef STRICT_CHECKING
|
||||
assert( instance != NULL );
|
||||
#endif
|
||||
int type = 0;
|
||||
int error = vevo_property_get( instance, "HOST_plugin_type", 0, &type);
|
||||
#ifdef STRICT_CHECKING
|
||||
assert( error == VEVO_NO_ERROR );
|
||||
#endif
|
||||
switch( type )
|
||||
{
|
||||
case VEVO_PLUG_LIVIDO:
|
||||
livido_plug_read_output_parameters( instance, fx_values );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void plug_clone_parameters( void *instance, void *fx_values )
|
||||
@@ -474,7 +440,7 @@ void plug_clone_parameters( void *instance, void *fx_values )
|
||||
generic_clone_parameter_f gcc;
|
||||
int error = vevo_property_get( instance, "HOST_plugin_param_clone_f", 0, &gcc );
|
||||
#ifdef STRICT_CHECKING
|
||||
assert( error == 0 );
|
||||
assert( error == VEVO_NO_ERROR );
|
||||
#endif
|
||||
(*gcc)( instance, 0, fx_values );
|
||||
}
|
||||
@@ -486,10 +452,14 @@ void plug_set_parameter( void *instance, int seq_num,int n_elements,void *value
|
||||
#endif
|
||||
generic_push_parameter_f gpp;
|
||||
int error = vevo_property_get( instance, "HOST_plugin_param_f", 0, &gpp );
|
||||
if( error == VEVO_NO_ERROR)
|
||||
(*gpp)( instance, seq_num, value );
|
||||
#ifdef STRICT_CHECKING
|
||||
assert( error == 0 );
|
||||
else
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
#endif
|
||||
(*gpp)( instance, seq_num, value );
|
||||
}
|
||||
|
||||
void plug_get_defaults( void *instance, void *fx_values )
|
||||
@@ -500,9 +470,10 @@ void plug_get_defaults( void *instance, void *fx_values )
|
||||
generic_default_values_f gdv;
|
||||
int error = vevo_property_get( instance, "HOST_plugin_defaults_f", 0, &gdv );
|
||||
#ifdef STRICT_CHECKING
|
||||
assert( error == 0 );
|
||||
assert( error == VEVO_NO_ERROR );
|
||||
#endif
|
||||
(*gdv)( instance, fx_values );
|
||||
|
||||
}
|
||||
void plug_set_defaults( void *instance, void *fx_values )
|
||||
{
|
||||
@@ -511,11 +482,13 @@ void plug_set_defaults( void *instance, void *fx_values )
|
||||
#endif
|
||||
generic_clone_parameter_f gcp;
|
||||
int error = vevo_property_get( instance, "HOST_plugin_param_clone_f", 0, &gcp );
|
||||
|
||||
#ifdef STRICT_CHECKING
|
||||
assert( error == 0 );
|
||||
assert( error == VEVO_NO_ERROR);
|
||||
#endif
|
||||
(*gcp)( instance, 0,fx_values );
|
||||
}
|
||||
|
||||
void plug_deactivate( void *instance )
|
||||
{
|
||||
deinstantiate_plugin( instance );
|
||||
@@ -586,87 +559,12 @@ int plug_get_num_parameters( int fx_id )
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
void plug_control( int fx_id, void *instance, int *args )
|
||||
{
|
||||
vevo_port_t *port = index_map_[ fx_id ];
|
||||
#ifdef STRICT_CHECKING
|
||||
assert ( port != NULL );
|
||||
#endif
|
||||
int type = 0;
|
||||
int error= 0;
|
||||
error = vevo_property_get( port, "type", 0, &type);
|
||||
#ifdef STRICT_CHECKING
|
||||
assert( error == LIVIDO_NO_ERROR );
|
||||
#endif
|
||||
if( type == VEVO_FF_PORT )
|
||||
{
|
||||
freeframe_plug_control( port, args );
|
||||
}
|
||||
else if ( type == VEVO_FR_PORT )
|
||||
{
|
||||
frei0r_plug_control( port, args );
|
||||
}
|
||||
else if ( type == VEVO_LIVIDO_PORT )
|
||||
{
|
||||
// livido_plug_control( port, args );
|
||||
livido_set_parameters_scaled( port, args );
|
||||
}
|
||||
}*/
|
||||
|
||||
void plug_sys_set_palette( int pref_palette )
|
||||
{
|
||||
base_fmt_ = pref_palette;
|
||||
livido_set_pref_palette( base_fmt_ );
|
||||
}
|
||||
|
||||
/*
|
||||
static void plug_process_mix( VJFrame *frame, VJFrame *frame_b,int fx_id )
|
||||
{
|
||||
void *plugin = index_map_[fx_id];
|
||||
#ifdef STRICT_CHECKING
|
||||
assert( plugin != NULL );
|
||||
assert( frame != NULL );
|
||||
assert( frame_b != NULL );
|
||||
#endif
|
||||
util_convertrgba32( frame->data, base_width_, base_height_, base_format_, frame->shift_v, buffer_ );
|
||||
|
||||
util_convertrgba32( frame_b->data,base_width_,base_height_, base_format_, frame_b->shift_v, buffer_b_ );
|
||||
|
||||
process_mix_plugin( plugin, buffer_, buffer_b_, buffer2_ );
|
||||
#ifdef STRICT_CHECKING
|
||||
assert( buffer2_ != NULL);
|
||||
#endif
|
||||
|
||||
#ifdef STRICT_CHECKING
|
||||
if( base_fmt_ == 0 )
|
||||
{
|
||||
assert( (frame->width * frame->height) == frame->len );
|
||||
assert( (frame->uv_width * frame->uv_height) == frame->uv_len );
|
||||
|
||||
assert( (frame->width / 2 ) == frame->uv_width );
|
||||
assert( (frame->height /2 ) == frame->uv_height );
|
||||
|
||||
assert( frame->shift_v == 1 );
|
||||
assert( frame->shift_h == 1 );
|
||||
|
||||
}
|
||||
if( base_fmt_ == 1 )
|
||||
{
|
||||
assert( (frame->width * frame->height) == frame->len );
|
||||
assert( (frame->uv_width * frame->uv_height) == frame->uv_len );
|
||||
assert( frame->width /2 == frame->uv_width );
|
||||
assert( (frame->height ) == frame->uv_height );
|
||||
assert( frame->shift_v == 0 );
|
||||
assert( frame->shift_h == 1 );
|
||||
|
||||
}
|
||||
assert( base_fmt_ == 0 || base_fmt_ == 1 );
|
||||
#endif
|
||||
|
||||
util_convertsrc( buffer2_, base_width_, base_height_, base_format_, frame->data );
|
||||
}*/
|
||||
|
||||
void plug_push_frame( void *instance, int out, int seq_num, void *frame_info )
|
||||
{
|
||||
VJFrame *frame = (VJFrame*) frame_info;
|
||||
@@ -681,6 +579,8 @@ void plug_push_frame( void *instance, int out, int seq_num, void *frame_info )
|
||||
(*gpu)( instance, (out ? "out_channels" : "in_channels" ), seq_num, frame );
|
||||
}
|
||||
|
||||
|
||||
|
||||
void plug_process( void *instance )
|
||||
{
|
||||
#ifdef STRICT_CHECKING
|
||||
@@ -691,30 +591,6 @@ void plug_process( void *instance )
|
||||
#ifdef STRICT_CHECKING
|
||||
assert( error == 0 );
|
||||
#endif
|
||||
|
||||
(*gpf)( instance,0.0 );
|
||||
|
||||
/*
|
||||
// it is frei0r or freeframe mixing plugin
|
||||
int is_mix = 0;
|
||||
error = vevo_property_get( plugin, "mixer", 0, &is_mix );
|
||||
#ifdef HAVE_STRICT_
|
||||
assert( error == LIVIDO_NO_ERROR );
|
||||
#endif
|
||||
if( is_mix )
|
||||
{
|
||||
plug_process_mix( frame, b, fx_id );
|
||||
return;
|
||||
}
|
||||
|
||||
util_convertrgba32( frame->data, base_width_, base_height_, base_format_, frame->shift_v, buffer_ );
|
||||
|
||||
void *res_frame = process_plug_plugin( plugin, buffer_, buffer2_ );
|
||||
#ifdef STRICT_CHECKING
|
||||
assert( res_frame != NULL );
|
||||
#endif
|
||||
|
||||
util_convertsrc( res_frame, base_width_, base_height_, base_format_, frame->data );
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,8 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
video plugin loader library to wrap up all kinds of standards
|
||||
veejay plugin loader
|
||||
* library to wrap up all kinds of "plugin standards"
|
||||
*/
|
||||
|
||||
void plug_sys_free(void);
|
||||
@@ -30,14 +31,13 @@ int plug_sys_detect_plugins(void);
|
||||
char *plug_get_name( int fx_id );
|
||||
int plug_get_fx_id_by_name( const char *name );
|
||||
int plug_get_num_input_channels( int fx_id );
|
||||
int plug_set_param_from_str( void *plugin , int p, const char *str, void *fx_values );
|
||||
//@ initialize plugin
|
||||
int plug_set_param_from_str( void *plugin , int p, const char *str, void *fx_values );
|
||||
void *plug_activate( int fx_id );
|
||||
void plug_deactivate( void *instance );
|
||||
void plug_push_frame( void *instance, int out, int seq_num, void *frame );
|
||||
void plug_process( void *instance );
|
||||
void plug_get_defaults( void *instance, void *fx_values );
|
||||
void plug_set_parameter( void *instance, int seq_num, int n_elements,void *value );
|
||||
int plug_inplace( void *instance );
|
||||
void plug_clone_from_output_parameters( void *instance, void *fx_values );
|
||||
|
||||
#endif
|
||||
|
||||
@@ -108,7 +108,78 @@ int auto_scale_int( void *port, const char *key, int n, int *dst)
|
||||
return LIVIDO_NO_ERROR;
|
||||
}
|
||||
|
||||
void clone_prop_vevo( void *port, void *to_port, const char *key, const char *as_key )
|
||||
void clone_prop_vevo( void *port, void *to_port, const char *key, const char *as_key )
|
||||
{
|
||||
int num = vevo_property_num_elements( port, key );
|
||||
int type= vevo_property_atom_type( port, key );
|
||||
int i;
|
||||
|
||||
if( num <= 0 )
|
||||
return;
|
||||
|
||||
int itmp[num];
|
||||
double dtemp[num];
|
||||
char *stmp[num];
|
||||
|
||||
int error;
|
||||
|
||||
switch( type )
|
||||
{
|
||||
case VEVO_ATOM_TYPE_INT:
|
||||
case VEVO_ATOM_TYPE_BOOL:
|
||||
for( i= 0; i < num; i ++ )
|
||||
{
|
||||
error = vevo_property_get( port,key,i, &(itmp[i]) );
|
||||
#ifdef STRICT_CHECKING
|
||||
assert( error == VEVO_NO_ERROR );
|
||||
#endif
|
||||
}
|
||||
error = vevo_property_set( to_port, as_key, type, num, &itmp );
|
||||
#ifdef STRICT_CHECKING
|
||||
assert( error == VEVO_NO_ERROR );
|
||||
#endif
|
||||
break;
|
||||
case VEVO_ATOM_TYPE_DOUBLE:
|
||||
for( i = 0; i < num ; i++ )
|
||||
{
|
||||
error = vevo_property_get( port, key, i, &(itmp[i]));
|
||||
#ifdef STRICT_CHECKING
|
||||
assert( error == VEVO_NO_ERROR );
|
||||
#endif
|
||||
}
|
||||
error = vevo_property_set( to_port, as_key, type, num, &itmp );
|
||||
#ifdef STRICT_CHECKING
|
||||
assert( error == VEVO_NO_ERROR );
|
||||
#endif
|
||||
case VEVO_ATOM_TYPE_STRING:
|
||||
for( i = 0; i < num; i ++)
|
||||
{
|
||||
size_t len = vevo_property_element_size( port,key,i);
|
||||
stmp[i] = NULL;
|
||||
if( len > 0 ) continue;
|
||||
stmp[i] = (char*) malloc(sizeof(char) * len );
|
||||
error = vevo_property_get( port, key, i, &(stmp[i]) );
|
||||
#ifdef STRICT_CHECKING
|
||||
assert( error == VEVO_NO_ERROR );
|
||||
#endif
|
||||
}
|
||||
error = vevo_property_set( to_port, as_key, type, num, &stmp );
|
||||
#ifdef STRICT_CHECKING
|
||||
assert( error == VEVO_NO_ERROR );
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
veejay_msg(0, "Internal error. Cannot clone this type of atom");
|
||||
#ifdef STRICT_CHECKING
|
||||
assert(0);
|
||||
#endif
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void clone_prop_vevo2( void *port, void *to_port, const char *key, const char *as_key )
|
||||
{
|
||||
int n = vevo_property_atom_type( port ,key);
|
||||
#ifdef STRICT_CHECKING
|
||||
|
||||
@@ -169,7 +169,6 @@ void vevo_pool_free( void *p, void *ptr, unsigned int k )
|
||||
if( n == ROUNDS_PER_MAG )
|
||||
{
|
||||
space_t *l = space;
|
||||
space_t *n = NULL;
|
||||
while( l != NULL )
|
||||
{
|
||||
if( l->rounds < ROUNDS_PER_MAG )
|
||||
@@ -266,7 +265,6 @@ void vevo_pool_slice_free( void *p, void *ptr )
|
||||
if( n == ROUNDS_PER_MAG )
|
||||
{
|
||||
space_t *l = space;
|
||||
space_t *n = NULL;
|
||||
while( l != NULL )
|
||||
{
|
||||
if( l->rounds < ROUNDS_PER_MAG )
|
||||
|
||||
@@ -88,6 +88,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <libhash/hash.h>
|
||||
#include <veejay/portdef.h>
|
||||
#include <libvjmem/vjmem.h>
|
||||
#include <libvjmsg/vj-common.h>
|
||||
#ifdef STRICT_CHECKING
|
||||
#include <assert.h>
|
||||
#endif
|
||||
|
||||
@@ -494,7 +494,6 @@ char *get_memcpy_descr( void )
|
||||
{
|
||||
int i = 1;
|
||||
int best = 1;
|
||||
unsigned long long t=0;
|
||||
for (i=1; memcpy_method[i].name; i++)
|
||||
{
|
||||
if( memcpy_method[i].time <= memcpy_method[best].time )
|
||||
@@ -513,8 +512,8 @@ void find_best_memcpy()
|
||||
char *buf1, *buf2;
|
||||
int i, j, best = 0;
|
||||
|
||||
veejay_memcpy = memcpy;
|
||||
veejay_memset = memset;
|
||||
veejay_memcpy = (void*) memcpy;
|
||||
veejay_memset = (void*) memset;
|
||||
return;
|
||||
|
||||
if (!(buf1 = (char*) malloc( BUFSIZE * 2000 * sizeof(char) )))
|
||||
@@ -560,7 +559,7 @@ void find_best_memcpy()
|
||||
}
|
||||
|
||||
if (best) {
|
||||
veejay_memset = memset_method[best].function;
|
||||
veejay_memset = (void*) memset_method[best].function;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include "vj-common.h"
|
||||
|
||||
#define TXT_RED "\033[0;31m"
|
||||
|
||||
@@ -4,7 +4,7 @@ MAINTAINERCLEANFILES = Makefile.in
|
||||
|
||||
INCLUDES = -I$(top_srcdir) -I$(includedir) \
|
||||
-DG_LOG_DOMAIN=\"veejay\" -DVEEJAY_VERSION=\"$(VERSION)\" \
|
||||
-I /usr/X11R6/include -I$(top_srcdir)/libOSC \
|
||||
-I /usr/X11R6/include \
|
||||
-I$(top_srcdir)/libhash \
|
||||
-I$(top_srcdir)/libvje \
|
||||
-I$(top_srcdir)/libplugger \
|
||||
@@ -39,8 +39,7 @@ libveejay_la_SOURCES = vj-misc.c \
|
||||
|
||||
libveejay_la_LDFLAGS = $(VEEJAY_ALL_LIB_OPTS )
|
||||
|
||||
libveejay_la_LIBADD = -L$(top_builddir)/libOSC / -lOSC \
|
||||
-L$(top_builddir)/libhash / -lhash \
|
||||
libveejay_la_LIBADD = -L$(top_builddir)/libhash / -lhash \
|
||||
-L$(top_builddir)/bio2jack/ -lbio2jack \
|
||||
-L$(top_builddir)/libvjmsg -lvjmsg \
|
||||
-L$(top_builddir)/libvjmem/ -lvjmem \
|
||||
|
||||
@@ -177,6 +177,7 @@ static struct
|
||||
{ "fx_alpha", VEVO_ATOM_TYPE_INT }, /* alpha */
|
||||
{ "fx_instance", VEVO_ATOM_TYPE_VOIDPTR }, /* plugin instance point */
|
||||
{ "fx_values", VEVO_ATOM_TYPE_PORTPTR }, /* port of p0 .. pN, containing copy of fx parameter values */
|
||||
{ "fx_out_values", VEVO_ATOM_TYPE_PORTPTR }, /* output parmaters, p0 ... pN */
|
||||
{ "fx_channels", VEVO_ATOM_TYPE_PORTPTR }, /* contains list of sample pointers to use as input channels */
|
||||
};
|
||||
|
||||
@@ -689,6 +690,7 @@ int sample_process_fx( void *sample, int fx_entry )
|
||||
unsigned int i,k;
|
||||
void *fx_instance = NULL;
|
||||
void *fx_values = NULL;
|
||||
void *fx_out_values = NULL;
|
||||
|
||||
void *port = sample_get_fx_port_ptr( sample,fx_entry );
|
||||
#ifdef STRICT_CHECKING
|
||||
@@ -696,17 +698,28 @@ int sample_process_fx( void *sample, int fx_entry )
|
||||
#endif
|
||||
int error = vevo_property_get( port, "fx_instance", 0, &fx_instance );
|
||||
#ifdef STRICT_CHECKING
|
||||
assert( error == 0 );
|
||||
assert( error == VEVO_NO_ERROR );
|
||||
#endif
|
||||
plug_process( fx_instance );
|
||||
|
||||
error = vevo_property_get( port, "fx_values", 0, &fx_values );
|
||||
#ifdef STRICT_CHECKING
|
||||
assert( error == 0 );
|
||||
assert( error == VEVO_NO_ERROR );
|
||||
#endif
|
||||
|
||||
error = vevo_property_get( port, "fx_out_values",0,&fx_out_values );
|
||||
#ifdef STRICT_CHECKING
|
||||
assert( error == VEVO_NO_ERROR );
|
||||
#endif
|
||||
|
||||
|
||||
//update internal parameter values
|
||||
plug_clone_from_parameters( fx_instance, fx_values );
|
||||
|
||||
//get the output parameters,if any
|
||||
|
||||
plug_clone_from_output_parameters( fx_instance, fx_out_values );
|
||||
|
||||
return VEVO_NO_ERROR;
|
||||
}
|
||||
|
||||
@@ -968,16 +981,20 @@ static void sample_new_fx_chain_entry( void *sample, int id )
|
||||
#endif
|
||||
void *fx_values = vevo_port_new( VEVO_FX_VALUES_PORT );
|
||||
void *fx_channels = vevo_port_new( VEVO_ANONYMOUS_PORT );
|
||||
void *fx_out_values = vevo_port_new( VEVO_FX_VALUES_PORT );
|
||||
|
||||
error = vevo_property_set( port, "fx_values", VEVO_ATOM_TYPE_PORTPTR,1,&fx_values);
|
||||
#ifdef STRICT_CHECKING
|
||||
assert( error == VEVO_NO_ERROR );
|
||||
#endif
|
||||
error = vevo_property_set( port, "fx_out_values", VEVO_ATOM_TYPE_PORTPTR,1,&fx_out_values);
|
||||
#ifdef STRICT_CHECKING
|
||||
assert( error == VEVO_NO_ERROR );
|
||||
#endif
|
||||
error = vevo_property_set( port, "fx_channels",VEVO_ATOM_TYPE_PORTPTR,1,&fx_channels );
|
||||
#ifdef STRICT_CHECKING
|
||||
assert( error == VEVO_NO_ERROR );
|
||||
#endif
|
||||
|
||||
error = vevo_property_set( port, "fx_instance", VEVO_ATOM_TYPE_PORTPTR,0,NULL );
|
||||
#ifdef STRICT_CHECKING
|
||||
assert( error == VEVO_NO_ERROR );
|
||||
|
||||
Reference in New Issue
Block a user