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
|
# 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 += libvevo libplugger libvjnet libyuv libel libvjaudio vevosample veejay
|
||||||
SUBDIRS += man
|
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
|
# 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
|
dnl
|
||||||
AC_CONFIG_FILES([
|
AC_CONFIG_FILES([
|
||||||
Makefile
|
Makefile
|
||||||
libOSC/Makefile
|
|
||||||
libhash/Makefile
|
libhash/Makefile
|
||||||
libvjmsg/Makefile
|
libvjmsg/Makefile
|
||||||
libvevo/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 <config.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@@ -14,19 +15,35 @@
|
|||||||
#define LINUX 1
|
#define LINUX 1
|
||||||
#include <libplugger/specs/FreeFrame.h>
|
#include <libplugger/specs/FreeFrame.h>
|
||||||
#define V_BITS 32
|
#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
|
/** \defgroup freeframe FreeFrame Host
|
||||||
*
|
*
|
||||||
* Provides a host implementation for FreeFrame plugins, see http://freeframe.sourceforge.net
|
* 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
|
#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
|
#define FF_CAP_V_BITS_VIDEO FF_CAP_24BITVIDEO
|
||||||
#else // V_BITS = 16
|
#else // V_BITS = 16
|
||||||
#define FF_CAP_V_BITS_VIDEO FF_CAP_16BITVIDEO
|
#define FF_CAP_V_BITS_VIDEO FF_CAP_16BITVIDEO
|
||||||
#endif
|
#endif*/
|
||||||
|
|
||||||
void* deal_with_ff( void *handle, char *name )
|
void* deal_with_ff( void *handle, char *name )
|
||||||
{
|
{
|
||||||
@@ -36,7 +53,7 @@ void* deal_with_ff( void *handle, char *name )
|
|||||||
|
|
||||||
if( q == NULL )
|
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 );
|
vevo_port_free( port );
|
||||||
return NULL;
|
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)
|
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);
|
vevo_port_free(port);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -53,7 +70,7 @@ void* deal_with_ff( void *handle, char *name )
|
|||||||
|
|
||||||
if (pis->APIMajorVersion < 1)
|
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);
|
vevo_port_free(port);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -61,7 +78,7 @@ void* deal_with_ff( void *handle, char *name )
|
|||||||
plugin_name = strdup( pis->pluginName );
|
plugin_name = strdup( pis->pluginName );
|
||||||
if ( (q(FF_INITIALISE, NULL, 0 )).ivalue == FF_FAIL )
|
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);
|
vevo_port_free(port);
|
||||||
if(plugin_name) free(plugin_name);
|
if(plugin_name) free(plugin_name);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -70,51 +87,65 @@ void* deal_with_ff( void *handle, char *name )
|
|||||||
int n_params = q( FF_GETNUMPARAMETERS, NULL, 0 ).ivalue;
|
int n_params = q( FF_GETNUMPARAMETERS, NULL, 0 ).ivalue;
|
||||||
if( n_params == FF_FAIL )
|
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);
|
vevo_port_free(port);
|
||||||
if(plugin_name) free(plugin_name);
|
if(plugin_name) free(plugin_name);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
int mix = 0;
|
|
||||||
void *base = (void*) q;
|
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, "handle", VEVO_ATOM_TYPE_VOIDPTR,1, &handle );
|
||||||
vevo_property_set( port, "name", VEVO_ATOM_TYPE_STRING,1, &plugin_name );
|
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, "base", VEVO_ATOM_TYPE_VOIDPTR, 1, &base );
|
||||||
vevo_property_set( port, "instance", VEVO_ATOM_TYPE_INT, 0, NULL );
|
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, "num_params", VEVO_ATOM_TYPE_INT, 1,&n_params );
|
||||||
vevo_property_set( port, "mixer", VEVO_ATOM_TYPE_INT, 1,&mix );
|
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;
|
int p;
|
||||||
for( p= 0; p < n_params; p ++ )
|
for( p= 0; p < n_params; p ++ )
|
||||||
{
|
{
|
||||||
|
|
||||||
|
int type = q( FF_GETPARAMETERTYPE, (LPVOID) p, 0 ).ivalue;
|
||||||
|
|
||||||
|
double min = 0;
|
||||||
|
double max = 1.0;
|
||||||
|
int kind = 0;
|
||||||
|
|
||||||
|
switch( type )
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(kind)
|
||||||
|
continue;
|
||||||
|
|
||||||
void *parameter = vevo_port_new( VEVO_FF_PARAM_PORT );
|
void *parameter = vevo_port_new( VEVO_FF_PARAM_PORT );
|
||||||
|
|
||||||
int type = q( FF_GETPARAMETERTYPE, (LPVOID) p, 0 ).ivalue;
|
double ivalue = (double)q( FF_GETPARAMETERDEFAULT, (LPVOID) p, 0).fvalue;
|
||||||
// name, kind, flags, description, min,max,default,transition
|
|
||||||
vevo_property_set( parameter, "type", VEVO_ATOM_TYPE_INT, 1, &type);
|
vevo_property_set( parameter, "default", VEVO_ATOM_TYPE_DOUBLE,1 ,&ivalue );
|
||||||
|
vevo_property_set( parameter, "value" , VEVO_ATOM_TYPE_DOUBLE,1, &ivalue );
|
||||||
int min = 0;
|
vevo_property_set( parameter, "min", VEVO_ATOM_TYPE_DOUBLE, 1, &min );
|
||||||
int max = 100;
|
vevo_property_set( parameter, "max", VEVO_ATOM_TYPE_DOUBLE,1, &max );
|
||||||
|
vevo_property_set( parameter, "HOST_kind", VEVO_ATOM_TYPE_INT,1,&kind );
|
||||||
if( type == FF_TYPE_BOOLEAN )
|
|
||||||
{
|
|
||||||
min = 0;
|
|
||||||
max = 1;
|
|
||||||
}
|
|
||||||
else if( type == FF_TYPE_TEXT )
|
|
||||||
{
|
|
||||||
min = 0;
|
|
||||||
max = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
vevo_property_set( parameter, "min", VEVO_ATOM_TYPE_INT,1, &min );
|
|
||||||
vevo_property_set( parameter, "max", VEVO_ATOM_TYPE_INT,1, &max );
|
|
||||||
|
|
||||||
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 );
|
|
||||||
|
|
||||||
char key[20];
|
char key[20];
|
||||||
snprintf(key,20, "p%02d", p );
|
snprintf(key,20, "p%02d", p );
|
||||||
vevo_property_set( port, key, VEVO_ATOM_TYPE_VOIDPTR, 1, ¶meter );
|
vevo_property_set( port, key, VEVO_ATOM_TYPE_VOIDPTR, 1, ¶meter );
|
||||||
@@ -123,6 +154,158 @@ void* deal_with_ff( void *handle, char *name )
|
|||||||
return port;
|
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 )
|
int freeframe_plug_init( void *plugin, int w, int h )
|
||||||
{
|
{
|
||||||
VideoInfoStruct v;
|
VideoInfoStruct v;
|
||||||
@@ -145,6 +328,76 @@ int freeframe_plug_init( void *plugin, int w, int h )
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
vevo_property_set( plugin, "instance", VEVO_ATOM_TYPE_INT, 1, &instance );
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,19 +407,44 @@ void freeframe_plug_deinit( void *plugin )
|
|||||||
void *base = NULL;
|
void *base = NULL;
|
||||||
int error = vevo_property_get( plugin, "base", 0, &base);
|
int error = vevo_property_get( plugin, "base", 0, &base);
|
||||||
#ifdef STRICT_CHECING
|
#ifdef STRICT_CHECING
|
||||||
assert( error == LIVIDO_NO_ERROR );
|
assert( error == VEVO_NO_ERROR );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
plugMainType *q = (plugMainType*) base;
|
plugMainType *q = (plugMainType*) base;
|
||||||
|
|
||||||
int instance = 0;
|
int instance = 0;
|
||||||
error = vevo_property_get( plugin, "instance", 0, &instance );
|
error = vevo_property_get( plugin, "instance", 0, &instance );
|
||||||
#ifdef STRICT_CHECING
|
#ifdef STRICT_CHECKING
|
||||||
assert( error == LIVIDO_NO_ERROR );
|
assert( error == VEVO_NO_ERROR );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if( instance )
|
if(! instance )
|
||||||
q( FF_DEINSTANTIATE, NULL, 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 )
|
void freeframe_plug_free( void *plugin )
|
||||||
@@ -181,7 +459,37 @@ void freeframe_plug_free( void *plugin )
|
|||||||
q( FF_DEINITIALISE, NULL, 0 );
|
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;
|
void *base = NULL;
|
||||||
int error = vevo_property_get( plugin, "base", 0, &base);
|
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 );
|
assert( error == LIVIDO_NO_ERROR );
|
||||||
#endif
|
#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 );
|
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;
|
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
|
#define FREEFRAME_LOADER
|
||||||
void* deal_with_ff( void *handle, char *name );
|
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 );
|
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_deinit( void *plugin );
|
||||||
void freeframe_plug_control( void *plugin, int *args );
|
|
||||||
|
|
||||||
|
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
|
#endif
|
||||||
|
|||||||
@@ -512,7 +512,7 @@ void *livido_plug_init(void *plugin,int w, int h )
|
|||||||
int num_out_params = init_ports_from_template(
|
int num_out_params = init_ports_from_template(
|
||||||
filter_instance, filter_templ,
|
filter_instance, filter_templ,
|
||||||
LIVIDO_PORT_TYPE_PARAMETER,
|
LIVIDO_PORT_TYPE_PARAMETER,
|
||||||
"in_parameter_templates", "in_parameters",
|
"out_parameter_templates", "out_parameters",
|
||||||
w,h,0 );
|
w,h,0 );
|
||||||
|
|
||||||
if( num_out_params < 0 )
|
if( num_out_params < 0 )
|
||||||
@@ -520,6 +520,7 @@ void *livido_plug_init(void *plugin,int w, int h )
|
|||||||
|
|
||||||
#ifdef STRICT_CHECKING
|
#ifdef STRICT_CHECKING
|
||||||
assert( num_in_params >= 0 );
|
assert( num_in_params >= 0 );
|
||||||
|
assert( num_out_params >= 0 );
|
||||||
assert( num_in_channels >= 0 );
|
assert( num_in_channels >= 0 );
|
||||||
assert( num_out_channels >= 0 );
|
assert( num_out_channels >= 0 );
|
||||||
#endif
|
#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 )
|
int livido_set_parameter_from_string( void *instance, int p, const char *str, void *fx_values )
|
||||||
{
|
{
|
||||||
void *param = NULL;
|
void *param = NULL;
|
||||||
|
|||||||
@@ -34,5 +34,6 @@ void livido_set_parameters_scaled( void *plugin, int *args );
|
|||||||
|
|
||||||
void livido_exit( void );
|
void livido_exit( void );
|
||||||
|
|
||||||
|
void livido_plug_read_output_parameters( void *instance, void *fx_values );
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
* -# Frei0r plugins
|
* -# Frei0r plugins
|
||||||
* -# FreeFrame plugins
|
* -# FreeFrame plugins
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
@@ -64,25 +65,6 @@ static int n_fr_ = 0;
|
|||||||
static int n_lvd_ = 0;
|
static int n_lvd_ = 0;
|
||||||
static int base_fmt_ = -1;
|
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 )
|
static int select_f( const struct dirent *d )
|
||||||
{
|
{
|
||||||
return ( strstr( d->d_name, ".so" ) != NULL );
|
return ( strstr( d->d_name, ".so" ) != NULL );
|
||||||
@@ -107,25 +89,27 @@ static void *instantiate_plugin( void *plugin, int w , int h )
|
|||||||
#ifdef STRICT_CHECKING
|
#ifdef STRICT_CHECKING
|
||||||
assert( error == VEVO_NO_ERROR );
|
assert( error == VEVO_NO_ERROR );
|
||||||
#endif
|
#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
|
#ifdef STRICT_CHECKING
|
||||||
assert( type == VEVO_PLUG_LIVIDO );
|
assert(0);
|
||||||
#endif
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}//@ warning: if init fails, plugin data should be freed (failed plugin)
|
}
|
||||||
|
|
||||||
|
|
||||||
static void deinstantiate_plugin( void *instance )
|
static void deinstantiate_plugin( void *instance )
|
||||||
{
|
{
|
||||||
@@ -134,10 +118,11 @@ static void deinstantiate_plugin( void *instance )
|
|||||||
#endif
|
#endif
|
||||||
generic_deinit_f gin;
|
generic_deinit_f gin;
|
||||||
int error = vevo_property_get( instance, "HOST_plugin_deinit_f", 0, &gin );
|
int error = vevo_property_get( instance, "HOST_plugin_deinit_f", 0, &gin );
|
||||||
|
|
||||||
#ifdef STRICT_CHECKING
|
#ifdef STRICT_CHECKING
|
||||||
assert( error == 0 );
|
assert( error == VEVO_NO_ERROR );
|
||||||
#endif
|
#endif
|
||||||
(*gin)( instance );
|
(*gin)(instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void add_to_plugin_list( const char *path )
|
static void add_to_plugin_list( const char *path )
|
||||||
@@ -270,39 +255,13 @@ static void free_plugin(void *plugin)
|
|||||||
__FUNCTION__,name,plugin,type );
|
__FUNCTION__,name,plugin,type );
|
||||||
free(name);
|
free(name);
|
||||||
|
|
||||||
int n = 0;
|
|
||||||
|
|
||||||
// freeframe_plug_free( plugin );
|
|
||||||
// frei0r_plug_free( plugin );
|
|
||||||
// livido_plug_free( plugin );
|
|
||||||
|
|
||||||
|
|
||||||
// free_parameters(plugin,n);
|
|
||||||
|
|
||||||
void *handle = NULL;
|
void *handle = NULL;
|
||||||
error = vevo_property_get( plugin, "handle", 0 , &handle );
|
error = vevo_property_get( plugin, "handle", 0 , &handle );
|
||||||
#ifdef STRICT_CHECKING
|
#ifdef STRICT_CHECKING
|
||||||
assert( error == 0 );
|
assert( error == 0 );
|
||||||
#endif
|
#endif
|
||||||
if( handle ) dlclose( handle );
|
if( handle ) dlclose( handle );
|
||||||
// vevo_port_free( plugin );
|
vevo_port_recursive_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 );
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -349,19 +308,6 @@ static int scan_plugins()
|
|||||||
add_to_plugin_list( pch );
|
add_to_plugin_list( pch );
|
||||||
pch = strtok( NULL, "\n");
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -460,10 +406,30 @@ void plug_clone_from_parameters(void *instance, void *fx_values)
|
|||||||
generic_reverse_clone_parameter_f grc;
|
generic_reverse_clone_parameter_f grc;
|
||||||
int error = vevo_property_get( instance, "HOST_plugin_param_reverse_f", 0, &grc );
|
int error = vevo_property_get( instance, "HOST_plugin_param_reverse_f", 0, &grc );
|
||||||
#ifdef STRICT_CHECKING
|
#ifdef STRICT_CHECKING
|
||||||
assert( error == 0 );
|
assert( error == VEVO_NO_ERROR );
|
||||||
#endif
|
#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 )
|
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;
|
generic_clone_parameter_f gcc;
|
||||||
int error = vevo_property_get( instance, "HOST_plugin_param_clone_f", 0, &gcc );
|
int error = vevo_property_get( instance, "HOST_plugin_param_clone_f", 0, &gcc );
|
||||||
#ifdef STRICT_CHECKING
|
#ifdef STRICT_CHECKING
|
||||||
assert( error == 0 );
|
assert( error == VEVO_NO_ERROR );
|
||||||
#endif
|
#endif
|
||||||
(*gcc)( instance, 0, fx_values );
|
(*gcc)( instance, 0, fx_values );
|
||||||
}
|
}
|
||||||
@@ -486,10 +452,14 @@ void plug_set_parameter( void *instance, int seq_num,int n_elements,void *value
|
|||||||
#endif
|
#endif
|
||||||
generic_push_parameter_f gpp;
|
generic_push_parameter_f gpp;
|
||||||
int error = vevo_property_get( instance, "HOST_plugin_param_f", 0, &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
|
#ifdef STRICT_CHECKING
|
||||||
assert( error == 0 );
|
else
|
||||||
#endif
|
{
|
||||||
(*gpp)( instance, seq_num, value );
|
assert(0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void plug_get_defaults( void *instance, void *fx_values )
|
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;
|
generic_default_values_f gdv;
|
||||||
int error = vevo_property_get( instance, "HOST_plugin_defaults_f", 0, &gdv );
|
int error = vevo_property_get( instance, "HOST_plugin_defaults_f", 0, &gdv );
|
||||||
#ifdef STRICT_CHECKING
|
#ifdef STRICT_CHECKING
|
||||||
assert( error == 0 );
|
assert( error == VEVO_NO_ERROR );
|
||||||
#endif
|
#endif
|
||||||
(*gdv)( instance, fx_values );
|
(*gdv)( instance, fx_values );
|
||||||
|
|
||||||
}
|
}
|
||||||
void plug_set_defaults( void *instance, void *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
|
#endif
|
||||||
generic_clone_parameter_f gcp;
|
generic_clone_parameter_f gcp;
|
||||||
int error = vevo_property_get( instance, "HOST_plugin_param_clone_f", 0, &gcp );
|
int error = vevo_property_get( instance, "HOST_plugin_param_clone_f", 0, &gcp );
|
||||||
|
|
||||||
#ifdef STRICT_CHECKING
|
#ifdef STRICT_CHECKING
|
||||||
assert( error == 0 );
|
assert( error == VEVO_NO_ERROR);
|
||||||
#endif
|
#endif
|
||||||
(*gcp)( instance, 0,fx_values );
|
(*gcp)( instance, 0,fx_values );
|
||||||
}
|
}
|
||||||
|
|
||||||
void plug_deactivate( void *instance )
|
void plug_deactivate( void *instance )
|
||||||
{
|
{
|
||||||
deinstantiate_plugin( instance );
|
deinstantiate_plugin( instance );
|
||||||
@@ -586,87 +559,12 @@ int plug_get_num_parameters( int fx_id )
|
|||||||
return res;
|
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 )
|
void plug_sys_set_palette( int pref_palette )
|
||||||
{
|
{
|
||||||
base_fmt_ = pref_palette;
|
base_fmt_ = pref_palette;
|
||||||
livido_set_pref_palette( base_fmt_ );
|
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 )
|
void plug_push_frame( void *instance, int out, int seq_num, void *frame_info )
|
||||||
{
|
{
|
||||||
VJFrame *frame = (VJFrame*) 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 );
|
(*gpu)( instance, (out ? "out_channels" : "in_channels" ), seq_num, frame );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void plug_process( void *instance )
|
void plug_process( void *instance )
|
||||||
{
|
{
|
||||||
#ifdef STRICT_CHECKING
|
#ifdef STRICT_CHECKING
|
||||||
@@ -691,30 +591,6 @@ void plug_process( void *instance )
|
|||||||
#ifdef STRICT_CHECKING
|
#ifdef STRICT_CHECKING
|
||||||
assert( error == 0 );
|
assert( error == 0 );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
(*gpf)( instance,0.0 );
|
(*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);
|
void plug_sys_free(void);
|
||||||
@@ -30,14 +31,13 @@ int plug_sys_detect_plugins(void);
|
|||||||
char *plug_get_name( int fx_id );
|
char *plug_get_name( int fx_id );
|
||||||
int plug_get_fx_id_by_name( const char *name );
|
int plug_get_fx_id_by_name( const char *name );
|
||||||
int plug_get_num_input_channels( int fx_id );
|
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 );
|
int plug_set_param_from_str( void *plugin , int p, const char *str, void *fx_values );
|
||||||
//@ initialize plugin
|
|
||||||
void *plug_activate( int fx_id );
|
void *plug_activate( int fx_id );
|
||||||
void plug_deactivate( void *instance );
|
void plug_deactivate( void *instance );
|
||||||
void plug_push_frame( void *instance, int out, int seq_num, void *frame );
|
void plug_push_frame( void *instance, int out, int seq_num, void *frame );
|
||||||
void plug_process( void *instance );
|
void plug_process( void *instance );
|
||||||
void plug_get_defaults( void *instance, void *fx_values );
|
void plug_get_defaults( void *instance, void *fx_values );
|
||||||
void plug_set_parameter( void *instance, int seq_num, int n_elements,void *value );
|
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
|
#endif
|
||||||
|
|||||||
@@ -108,7 +108,78 @@ int auto_scale_int( void *port, const char *key, int n, int *dst)
|
|||||||
return LIVIDO_NO_ERROR;
|
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);
|
int n = vevo_property_atom_type( port ,key);
|
||||||
#ifdef STRICT_CHECKING
|
#ifdef STRICT_CHECKING
|
||||||
|
|||||||
@@ -169,7 +169,6 @@ void vevo_pool_free( void *p, void *ptr, unsigned int k )
|
|||||||
if( n == ROUNDS_PER_MAG )
|
if( n == ROUNDS_PER_MAG )
|
||||||
{
|
{
|
||||||
space_t *l = space;
|
space_t *l = space;
|
||||||
space_t *n = NULL;
|
|
||||||
while( l != NULL )
|
while( l != NULL )
|
||||||
{
|
{
|
||||||
if( l->rounds < ROUNDS_PER_MAG )
|
if( l->rounds < ROUNDS_PER_MAG )
|
||||||
@@ -266,7 +265,6 @@ void vevo_pool_slice_free( void *p, void *ptr )
|
|||||||
if( n == ROUNDS_PER_MAG )
|
if( n == ROUNDS_PER_MAG )
|
||||||
{
|
{
|
||||||
space_t *l = space;
|
space_t *l = space;
|
||||||
space_t *n = NULL;
|
|
||||||
while( l != NULL )
|
while( l != NULL )
|
||||||
{
|
{
|
||||||
if( l->rounds < ROUNDS_PER_MAG )
|
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 <libhash/hash.h>
|
||||||
#include <veejay/portdef.h>
|
#include <veejay/portdef.h>
|
||||||
#include <libvjmem/vjmem.h>
|
#include <libvjmem/vjmem.h>
|
||||||
|
#include <libvjmsg/vj-common.h>
|
||||||
#ifdef STRICT_CHECKING
|
#ifdef STRICT_CHECKING
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -494,7 +494,6 @@ char *get_memcpy_descr( void )
|
|||||||
{
|
{
|
||||||
int i = 1;
|
int i = 1;
|
||||||
int best = 1;
|
int best = 1;
|
||||||
unsigned long long t=0;
|
|
||||||
for (i=1; memcpy_method[i].name; i++)
|
for (i=1; memcpy_method[i].name; i++)
|
||||||
{
|
{
|
||||||
if( memcpy_method[i].time <= memcpy_method[best].time )
|
if( memcpy_method[i].time <= memcpy_method[best].time )
|
||||||
@@ -513,8 +512,8 @@ void find_best_memcpy()
|
|||||||
char *buf1, *buf2;
|
char *buf1, *buf2;
|
||||||
int i, j, best = 0;
|
int i, j, best = 0;
|
||||||
|
|
||||||
veejay_memcpy = memcpy;
|
veejay_memcpy = (void*) memcpy;
|
||||||
veejay_memset = memset;
|
veejay_memset = (void*) memset;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!(buf1 = (char*) malloc( BUFSIZE * 2000 * sizeof(char) )))
|
if (!(buf1 = (char*) malloc( BUFSIZE * 2000 * sizeof(char) )))
|
||||||
@@ -560,7 +559,7 @@ void find_best_memcpy()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (best) {
|
if (best) {
|
||||||
veejay_memset = memset_method[best].function;
|
veejay_memset = (void*) memset_method[best].function;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,9 @@
|
|||||||
#include <config.h>
|
#include <config.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <strings.h>
|
||||||
|
|
||||||
#include "vj-common.h"
|
#include "vj-common.h"
|
||||||
|
|
||||||
#define TXT_RED "\033[0;31m"
|
#define TXT_RED "\033[0;31m"
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ MAINTAINERCLEANFILES = Makefile.in
|
|||||||
|
|
||||||
INCLUDES = -I$(top_srcdir) -I$(includedir) \
|
INCLUDES = -I$(top_srcdir) -I$(includedir) \
|
||||||
-DG_LOG_DOMAIN=\"veejay\" -DVEEJAY_VERSION=\"$(VERSION)\" \
|
-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)/libhash \
|
||||||
-I$(top_srcdir)/libvje \
|
-I$(top_srcdir)/libvje \
|
||||||
-I$(top_srcdir)/libplugger \
|
-I$(top_srcdir)/libplugger \
|
||||||
@@ -39,8 +39,7 @@ libveejay_la_SOURCES = vj-misc.c \
|
|||||||
|
|
||||||
libveejay_la_LDFLAGS = $(VEEJAY_ALL_LIB_OPTS )
|
libveejay_la_LDFLAGS = $(VEEJAY_ALL_LIB_OPTS )
|
||||||
|
|
||||||
libveejay_la_LIBADD = -L$(top_builddir)/libOSC / -lOSC \
|
libveejay_la_LIBADD = -L$(top_builddir)/libhash / -lhash \
|
||||||
-L$(top_builddir)/libhash / -lhash \
|
|
||||||
-L$(top_builddir)/bio2jack/ -lbio2jack \
|
-L$(top_builddir)/bio2jack/ -lbio2jack \
|
||||||
-L$(top_builddir)/libvjmsg -lvjmsg \
|
-L$(top_builddir)/libvjmsg -lvjmsg \
|
||||||
-L$(top_builddir)/libvjmem/ -lvjmem \
|
-L$(top_builddir)/libvjmem/ -lvjmem \
|
||||||
|
|||||||
@@ -177,6 +177,7 @@ static struct
|
|||||||
{ "fx_alpha", VEVO_ATOM_TYPE_INT }, /* alpha */
|
{ "fx_alpha", VEVO_ATOM_TYPE_INT }, /* alpha */
|
||||||
{ "fx_instance", VEVO_ATOM_TYPE_VOIDPTR }, /* plugin instance point */
|
{ "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_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 */
|
{ "fx_channels", VEVO_ATOM_TYPE_PORTPTR }, /* contains list of sample pointers to use as input channels */
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -689,24 +690,36 @@ int sample_process_fx( void *sample, int fx_entry )
|
|||||||
unsigned int i,k;
|
unsigned int i,k;
|
||||||
void *fx_instance = NULL;
|
void *fx_instance = NULL;
|
||||||
void *fx_values = NULL;
|
void *fx_values = NULL;
|
||||||
|
void *fx_out_values = NULL;
|
||||||
|
|
||||||
void *port = sample_get_fx_port_ptr( sample,fx_entry );
|
void *port = sample_get_fx_port_ptr( sample,fx_entry );
|
||||||
#ifdef STRICT_CHECKING
|
#ifdef STRICT_CHECKING
|
||||||
assert( port != NULL );
|
assert( port != NULL );
|
||||||
#endif
|
#endif
|
||||||
int error = vevo_property_get( port, "fx_instance", 0, &fx_instance );
|
int error = vevo_property_get( port, "fx_instance", 0, &fx_instance );
|
||||||
#ifdef STRICT_CHECKING
|
#ifdef STRICT_CHECKING
|
||||||
assert( error == 0 );
|
assert( error == VEVO_NO_ERROR );
|
||||||
#endif
|
#endif
|
||||||
plug_process( fx_instance );
|
plug_process( fx_instance );
|
||||||
|
|
||||||
error = vevo_property_get( port, "fx_values", 0, &fx_values );
|
error = vevo_property_get( port, "fx_values", 0, &fx_values );
|
||||||
#ifdef STRICT_CHECKING
|
#ifdef STRICT_CHECKING
|
||||||
assert( error == 0 );
|
assert( error == VEVO_NO_ERROR );
|
||||||
#endif
|
#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
|
//update internal parameter values
|
||||||
plug_clone_from_parameters( fx_instance, fx_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;
|
return VEVO_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -968,16 +981,20 @@ static void sample_new_fx_chain_entry( void *sample, int id )
|
|||||||
#endif
|
#endif
|
||||||
void *fx_values = vevo_port_new( VEVO_FX_VALUES_PORT );
|
void *fx_values = vevo_port_new( VEVO_FX_VALUES_PORT );
|
||||||
void *fx_channels = vevo_port_new( VEVO_ANONYMOUS_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);
|
error = vevo_property_set( port, "fx_values", VEVO_ATOM_TYPE_PORTPTR,1,&fx_values);
|
||||||
#ifdef STRICT_CHECKING
|
#ifdef STRICT_CHECKING
|
||||||
assert( error == VEVO_NO_ERROR );
|
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
|
#endif
|
||||||
error = vevo_property_set( port, "fx_channels",VEVO_ATOM_TYPE_PORTPTR,1,&fx_channels );
|
error = vevo_property_set( port, "fx_channels",VEVO_ATOM_TYPE_PORTPTR,1,&fx_channels );
|
||||||
#ifdef STRICT_CHECKING
|
#ifdef STRICT_CHECKING
|
||||||
assert( error == VEVO_NO_ERROR );
|
assert( error == VEVO_NO_ERROR );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
error = vevo_property_set( port, "fx_instance", VEVO_ATOM_TYPE_PORTPTR,0,NULL );
|
error = vevo_property_set( port, "fx_instance", VEVO_ATOM_TYPE_PORTPTR,0,NULL );
|
||||||
#ifdef STRICT_CHECKING
|
#ifdef STRICT_CHECKING
|
||||||
assert( error == VEVO_NO_ERROR );
|
assert( error == VEVO_NO_ERROR );
|
||||||
|
|||||||
Reference in New Issue
Block a user