aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjdl <x75@users.sourceforge.net>2002-08-06 12:13:57 +0000
committerjdl <x75@users.sourceforge.net>2002-08-06 12:13:57 +0000
commit189c0787586602185fea7dcbc3ef37665b75ba45 (patch)
tree06e30a3a7e166b01134cc33ccda71034c876baf8
This commit was generated by cvs2svn to compensate for changes in r75,svn2git-root
which included commits to RCS files with non-trunk default branches. svn path=/trunk/externals/OSCx/; revision=76
-rw-r--r--OSC/OSC-client.h182
-rw-r--r--OSC/OSC-common.h62
-rw-r--r--OSC/OSC-pattern-match.c192
-rw-r--r--OSC/OSC-pattern-match.h35
-rw-r--r--OSC/OSC-timetag.h93
-rw-r--r--OSC/OSC.001147
-rw-r--r--OSC/OSC.c79
-rw-r--r--OSC/OSC.dsp148
-rw-r--r--OSC/OSC.dsw29
-rw-r--r--OSC/TODO.txt20
-rw-r--r--OSC/VERSION1
-rw-r--r--OSC/dumpOSC.c889
-rw-r--r--OSC/htmsocket.c297
-rw-r--r--OSC/htmsocket.h49
-rw-r--r--OSC/makefile69
-rw-r--r--OSC/makefile.in60
-rw-r--r--OSC/routeOSC.c417
-rw-r--r--OSC/sendOSC.c875
-rw-r--r--README.txt81
-rw-r--r--doc/OSC-help.pd10
-rw-r--r--doc/OSCroute-help.pd26
-rw-r--r--doc/dumpOSC-help.pd7
-rw-r--r--doc/sendOSC-help.pd57
-rw-r--r--extra/OSC.dllbin0 -> 65536 bytes
-rw-r--r--libOSC/LIBOSC.00194
-rw-r--r--libOSC/LIBOSC.002100
-rw-r--r--libOSC/LIBOSC.DSP100
-rw-r--r--libOSC/LIBOSC.DSW29
-rw-r--r--libOSC/LIBOSC.PLG29
-rw-r--r--libOSC/Makefile21
-rw-r--r--libOSC/OSC-client.c473
-rw-r--r--libOSC/OSC-client.c.pre-htonl303
-rw-r--r--libOSC/OSC-client.h181
-rw-r--r--libOSC/OSC-timetag.c175
-rw-r--r--libOSC/OSC-timetag.h93
-rw-r--r--libOSC/test_OSC.c149
-rw-r--r--libOSC/test_OSC_timeTag.c36
-rw-r--r--send+dump/Makefile25
-rw-r--r--send+dump/dumpOSC.c716
-rw-r--r--send+dump/dumpUDP.c191
-rw-r--r--send+dump/htmsocket.c230
-rw-r--r--send+dump/htmsocket.h49
-rw-r--r--send+dump/sendOSC.c600
43 files changed, 7419 insertions, 0 deletions
diff --git a/OSC/OSC-client.h b/OSC/OSC-client.h
new file mode 100644
index 0000000..165808b
--- /dev/null
+++ b/OSC/OSC-client.h
@@ -0,0 +1,182 @@
+/*
+Copyright (c) 1996,1997. The Regents of the University of California (Regents).
+All Rights Reserved.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for educational, research, and not-for-profit purposes, without
+fee and without a signed licensing agreement, is hereby granted, provided that
+the above copyright notice, this paragraph and the following two paragraphs
+appear in all copies, modifications, and distributions. Contact The Office of
+Technology Licensing, UC Berkeley, 2150 Shattuck Avenue, Suite 510, Berkeley,
+CA 94720-1620, (510) 643-7201, for commercial licensing opportunities.
+
+Written by Matt Wright, The Center for New Music and Audio Technologies,
+University of California, Berkeley.
+
+ IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
+ ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING
+ DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS".
+ REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
+ ENHANCEMENTS, OR MODIFICATIONS.
+*/
+
+/*
+
+ OSC-client.h: library for constructing OpenSoundControl messages.
+ Derived from SynthControl.h
+ Author: Matt Wright
+ Version 0.1: 6/13/97
+ Version 0.2: 7/21/2000: Support for type-tagged messages
+
+
+ General notes:
+
+ This library abstracts away the data format for the OpenSoundControl
+ protocol. Users of this library can construct OpenSoundControl packets
+ with a function call interface instead of knowing how to lay out the bits.
+
+ All issues of memory allocation are deferred to the user of this library.
+ There are two data structures that the user must allocate. The first
+ is the actual buffer that the message will be written into. This buffer
+ can be any size, but if it's too small there's a possibility that it
+ will become overfull. The other data structure is called an OSCbuf,
+ and it holds all the state used by the library as it's constructing
+ a buffer.
+
+ All procedures that have the possibility of an error condition return int,
+ with 0 indicating no error and nonzero indicating an error. The variable
+ OSC_errorMessage will be set to point to a string containing an error
+ message explaining what the problem is.
+
+*/
+
+
+#include "OSC-timetag.h"
+
+/* The int4byte type has to be a 4-byte integer. You may have to
+ change this to long or something else on your system. */
+#ifdef __MWERKS__
+ /* In Metrowerks you can set ints to be 2 or 4 bytes on 68K, but long is
+ always 4 bytes */
+ typedef long int4byte;
+#else
+ typedef int int4byte;
+#endif
+
+/* The maximum depth of bundles within bundles within bundles within...
+ This is the size of a static array. If you exceed this limit you'll
+ get an error message. */
+#define MAX_BUNDLE_NESTING 32
+
+
+/* Don't ever manipulate the data in the OSCbuf struct directly. (It's
+ declared here in the header file only so your program will be able to
+ declare variables of type OSCbuf and have the right amount of memory
+ be allocated.) */
+
+typedef struct OSCbuf_struct {
+ char *buffer; /* The buffer to hold the OSC packet */
+ int size; /* Size of the buffer */
+ char *bufptr; /* Current position as we fill the buffer */
+ int state; /* State of partially-constructed message */
+ int4byte *thisMsgSize; /* Pointer to count field before
+ currently-being-written message */
+ int4byte *prevCounts[MAX_BUNDLE_NESTING];
+ /* Pointers to count field before each currently
+ open bundle */
+ int bundleDepth; /* How many sub-sub-bundles are we in now? */
+ char *typeStringPtr; /* This pointer advances through the type
+ tag string as you add arguments. */
+ int gettingFirstUntypedArg; /* nonzero if this message doesn't have
+ a type tag and we're waiting for the 1st arg */
+} OSCbuf;
+
+
+
+/* Initialize the given OSCbuf. The user of this module must pass in the
+ block of memory that this OSCbuf will use for a buffer, and the number of
+ bytes in that block. (It's the user's job to allocate the memory because
+ you do it differently in different systems.) */
+void OSC_initBuffer(OSCbuf *buf, int size, char *byteArray);
+
+
+/* Reset the given OSCbuf. Do this after you send out the contents of
+ the buffer and want to start writing new data into it. */
+void OSC_resetBuffer(OSCbuf *buf);
+
+
+/* Is the buffer empty? (I.e., would it be stupid to send the buffer
+ contents to the synth?) */
+int OSC_isBufferEmpty(OSCbuf *buf);
+
+
+/* How much space is left in the buffer? */
+int OSC_freeSpaceInBuffer(OSCbuf *buf);
+
+/* Does the buffer contain a valid OSC packet? (Returns nonzero if yes.) */
+int OSC_isBufferDone(OSCbuf *buf);
+
+/* When you're ready to send out the buffer (i.e., when OSC_isBufferDone()
+ returns true), call these two procedures to get the OSC packet that's been
+ assembled and its size in bytes. (And then call OSC_resetBuffer() if you
+ want to re-use this OSCbuf for the next packet.) */
+char *OSC_getPacket(OSCbuf *buf);
+int OSC_packetSize(OSCbuf *buf);
+
+
+
+/* Here's the basic model for building up OSC messages in an OSCbuf:
+
+ - Make sure the OSCbuf has been initialized with OSC_initBuffer().
+
+ - To open a bundle, call OSC_openBundle(). You can then write
+ messages or open new bundles within the bundle you opened.
+ Call OSC_closeBundle() to close the bundle. Note that a packet
+ does not have to have a bundle; it can instead consist of just a
+ single message.
+
+
+ - For each message you want to send:
+
+ - Call OSC_writeAddress() with the name of your message. (In
+ addition to writing your message name into the buffer, this
+ procedure will also leave space for the size count of this message.)
+
+ - Alternately, call OSC_writeAddressAndTypes() with the name of
+ your message and with a type string listing the types of all the
+ arguments you will be putting in this message.
+
+ - Now write each of the arguments into the buffer, by calling one of:
+ OSC_writeFloatArg()
+ OSC_writeFloatArgs()
+ OSC_writeIntArg()
+ OSC_writeStringArg()
+
+ - Now your message is complete; you can send out the buffer or you can
+ add another message to it.
+*/
+
+int OSC_openBundle(OSCbuf *buf, OSCTimeTag tt);
+int OSC_closeBundle(OSCbuf *buf);
+int OSC_closeAllBundles(OSCbuf *buf);
+
+int OSC_writeAddress(OSCbuf *buf, char *name);
+int OSC_writeAddressAndTypes(OSCbuf *buf, char *name, char *types);
+int OSC_writeFloatArg(OSCbuf *buf, float arg);
+int OSC_writeFloatArgs(OSCbuf *buf, int numFloats, float *args);
+int OSC_writeIntArg(OSCbuf *buf, int4byte arg);
+int OSC_writeStringArg(OSCbuf *buf, char *arg);
+
+//extern
+char *OSC_errorMessage;
+
+/* How many bytes will be needed in the OSC format to hold the given
+ string? The length of the string, plus the null char, plus any padding
+ needed for 4-byte alignment. */
+int OSC_effectiveStringLength(char *string);
diff --git a/OSC/OSC-common.h b/OSC/OSC-common.h
new file mode 100644
index 0000000..8eb6576
--- /dev/null
+++ b/OSC/OSC-common.h
@@ -0,0 +1,62 @@
+/*
+Copyright (c) 1998. The Regents of the University of California (Regents).
+All Rights Reserved.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for educational, research, and not-for-profit purposes, without
+fee and without a signed licensing agreement, is hereby granted, provided that
+the above copyright notice, this paragraph and the following two paragraphs
+appear in all copies, modifications, and distributions. Contact The Office of
+Technology Licensing, UC Berkeley, 2150 Shattuck Avenue, Suite 510, Berkeley,
+CA 94720-1620, (510) 643-7201, for commercial licensing opportunities.
+
+Written by Matt Wright, The Center for New Music and Audio Technologies,
+University of California, Berkeley.
+
+ IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
+ ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING
+ DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS".
+ REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
+ ENHANCEMENTS, OR MODIFICATIONS.
+
+The OpenSound Control WWW page is
+ http://www.cnmat.berkeley.edu/OpenSoundControl
+*/
+
+
+/* OSC-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, ...);
+
+
diff --git a/OSC/OSC-pattern-match.c b/OSC/OSC-pattern-match.c
new file mode 100644
index 0000000..01515f8
--- /dev/null
+++ b/OSC/OSC-pattern-match.c
@@ -0,0 +1,192 @@
+/*
+Copyright (c) 1998. The Regents of the University of California (Regents).
+All Rights Reserved.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for educational, research, and not-for-profit purposes, without
+fee and without a signed licensing agreement, is hereby granted, provided that
+the above copyright notice, this paragraph and the following two paragraphs
+appear in all copies, modifications, and distributions. Contact The Office of
+Technology Licensing, UC Berkeley, 2150 Shattuck Avenue, Suite 510, Berkeley,
+CA 94720-1620, (510) 643-7201, for commercial licensing opportunities.
+
+Written by Matt Wright, The Center for New Music and Audio Technologies,
+University of California, Berkeley.
+
+ IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
+ ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING
+ DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS".
+ REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
+ ENHANCEMENTS, OR MODIFICATIONS.
+
+The OpenSound Control WWW page is
+ http://www.cnmat.berkeley.edu/OpenSoundControl
+*/
+
+
+/*
+ OSC-pattern-match.c
+ Matt Wright, 3/16/98
+ Adapted from oscpattern.c, by Matt Wright and Amar Chaudhury
+ */
+
+#include "OSC-common.h"
+#include "OSC-pattern-match.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 '}' :
+ printf("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) {
+ printf("Unterminated [ in pattern \".../%s/...\"", theWholePattern);
+ return FALSE;
+ }
+
+ if (pattern[1] == '!') {
+ negated = TRUE;
+ p++;
+ }
+
+ while (*p != ']') {
+ if (*p == 0) {
+ printf("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) {
+ printf("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) {
+ printf("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++;
+ }
+ }
+ }
+
+}
diff --git a/OSC/OSC-pattern-match.h b/OSC/OSC-pattern-match.h
new file mode 100644
index 0000000..a5d7306
--- /dev/null
+++ b/OSC/OSC-pattern-match.h
@@ -0,0 +1,35 @@
+/*
+Copyright (c) 1998. The Regents of the University of California (Regents).
+All Rights Reserved.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for educational, research, and not-for-profit purposes, without
+fee and without a signed licensing agreement, is hereby granted, provided that
+the above copyright notice, this paragraph and the following two paragraphs
+appear in all copies, modifications, and distributions. Contact The Office of
+Technology Licensing, UC Berkeley, 2150 Shattuck Avenue, Suite 510, Berkeley,
+CA 94720-1620, (510) 643-7201, for commercial licensing opportunities.
+
+Written by Matt Wright, The Center for New Music and Audio Technologies,
+University of California, Berkeley.
+
+ IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
+ ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING
+ DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS".
+ REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
+ ENHANCEMENTS, OR MODIFICATIONS.
+
+ The OpenSound Control WWW page is http://www.cnmat.berkeley.edu/OpenSoundControl
+
+ OSC-pattern-match.h
+*/
+
+//Boolean PatternMatch (const char *pattern, const char *test);
+Boolean PatternMatch (const char *pattern, const char *test);
+
diff --git a/OSC/OSC-timetag.h b/OSC/OSC-timetag.h
new file mode 100644
index 0000000..3ce693a
--- /dev/null
+++ b/OSC/OSC-timetag.h
@@ -0,0 +1,93 @@
+/*
+Copyright (c) 1998. The Regents of the University of California (Regents).
+All Rights Reserved.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for educational, research, and not-for-profit purposes, without
+fee and without a signed licensing agreement, is hereby granted, provided that
+the above copyright notice, this paragraph and the following two paragraphs
+appear in all copies, modifications, and distributions. Contact The Office of
+Technology Licensing, UC Berkeley, 2150 Shattuck Avenue, Suite 510, Berkeley,
+CA 94720-1620, (510) 643-7201, for commercial licensing opportunities.
+
+Written by Matt Wright, The Center for New Music and Audio Technologies,
+University of California, Berkeley.
+
+ IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
+ ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING
+ DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS".
+ REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
+ ENHANCEMENTS, OR MODIFICATIONS.
+
+The OpenSound Control WWW page is
+ http://www.cnmat.berkeley.edu/OpenSoundControl
+*/
+
+/*
+ OSC_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 a 64-bit
+ unsigned long if possible, or else a struct.
+
+ NB: On many architectures with 64-bit ints, it's illegal (like maybe a bus error)
+ to dereference a pointer to a 64-bit int that's not 64-bit 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 64 bit ints on your system */
+ typedef long long int64;
+ typedef unsigned long long uint64;
+ typedef unsigned long uint32;
+#else
+ /* You may have to redefine this typedef if ints on your system
+ aren't 32 bits. */
+ typedef unsigned int uint32;
+#endif
+
+
+#ifdef HAS8BYTEINT
+ typedef uint64 OSCTimeTag;
+#else
+ typedef struct {
+ uint32 seconds;
+ uint32 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 */
diff --git a/OSC/OSC.001 b/OSC/OSC.001
new file mode 100644
index 0000000..b9dd0d4
--- /dev/null
+++ b/OSC/OSC.001
@@ -0,0 +1,147 @@
+# Microsoft Developer Studio Project File - Name="OSC" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 5.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=OSC - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "OSC.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "OSC.mak" CFG="OSC - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "OSC - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "OSC - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "OSC - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "RAFOSC_EXPORTS" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../../pd/src" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "OSC_EXPORTS" /D "NT" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
+# ADD LINK32 pd.lib libc.lib kernel32.lib wsock32.lib LIBOSC.lib /nologo /dll /machine:I386 /nodefaultlib /out:"../../../pd/extra/OSC.dll" /libpath:"../../../pd/lib" /libpath:"../../../pd/bin"
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "OSC - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /GX /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "RAFOSC_EXPORTS" /YX /FD /ZI /GZ /c
+# ADD CPP /nologo /MTd /W3 /GX /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "OSC_EXPORTS" /D "NT" /YX /FD /ZI /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 pd.lib libc.lib kernel32.lib wsock32.lib LIBOSC.lib /nologo /dll /debug /machine:I386 /nodefaultlib /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "OSC - Win32 Release"
+# Name "OSC - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\dumpOSC.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\htmsocket.c
+# End Source File
+# Begin Source File
+
+SOURCE=".\OSC-pattern-match.c"
+# End Source File
+# Begin Source File
+
+SOURCE=.\OSC.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\routeOSC.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\sendOSC.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\htmsocket.h
+# End Source File
+# Begin Source File
+
+SOURCE=".\OSC-client.h"
+# End Source File
+# Begin Source File
+
+SOURCE=".\OSC-common.h"
+# End Source File
+# Begin Source File
+
+SOURCE=".\OSC-pattern-match.h"
+# End Source File
+# Begin Source File
+
+SOURCE=".\OSC-timetag.h"
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/OSC/OSC.c b/OSC/OSC.c
new file mode 100644
index 0000000..10e719f
--- /dev/null
+++ b/OSC/OSC.c
@@ -0,0 +1,79 @@
+/*
+
+ pd
+ -------------
+ -- tweaks for Win32 www.zeggz.com/raf 13-April-2002
+
+ */
+
+
+#ifndef VERSION
+ #ifdef WIN32
+ #define VERSION "0.01-w32"
+ #else
+ #define VERSION "0.01"
+ #endif
+#endif
+
+#ifndef __DATE__
+#define __DATE__ "without using a gnu compiler"
+#endif
+
+#include <m_pd.h>
+
+
+typedef struct _OSC
+{
+ t_object x_obj;
+} t_OSC;
+
+static t_class* OSC_class;
+
+#ifdef WIN32
+ #include "OSC-common.h"
+ OSC_API void OSC_setup(void);
+ OSC_API void OSC_version(t_OSC*);
+ OSC_API void sendOSC_setup(void);
+ OSC_API void dumpOSC_setup(void);
+ OSC_API void OSCroute_setup(void);
+#else
+ void OSC_version();
+ void sendOSC_setup();
+ void dumpOSC_setup();
+ void OSCroute_setup();
+#endif
+
+static void* OSC_new(t_symbol* s) {
+ t_OSC *x = (t_OSC *)pd_new(OSC_class);
+ return (x);
+}
+
+#ifdef WIN32
+ OSC_API void OSC_version (t_OSC *x) {
+#else
+ void OSC_version (t_OSC *x) {
+#endif
+ // EnterCallback();
+ post("OSC4PD Version " VERSION
+ "\n ¯\\ original code by matt wright. pd-fication jdl@xdv.org\n"
+ " · Win32-port raf@interaccess.com\n \\_ Compiled " __TIME__ " " __DATE__);
+ // ExitCallback();
+}
+
+#ifdef WIN32
+ OSC_API void OSC_setup(void) {
+#else
+ void OSC_setup(void) {
+#endif
+ OSC_class = class_new(gensym("OSC"), (t_newmethod)OSC_new, 0,
+ sizeof(t_OSC), 0,0);
+ class_addmethod(OSC_class, (t_method)OSC_version, gensym("version"), A_NULL, 0, 0);
+
+ sendOSC_setup();
+ dumpOSC_setup();
+ OSCroute_setup();
+
+ post("O : Open Sound Control 4 PD, http://www.cnmat.berkeley.edu/OSC");
+ post(" S : original code by matt wright, pd hakcs cxc, Win32-port raf@interaccess.com");
+ post(" C: ver: "VERSION ", compiled: "__DATE__);
+}
diff --git a/OSC/OSC.dsp b/OSC/OSC.dsp
new file mode 100644
index 0000000..8f0116d
--- /dev/null
+++ b/OSC/OSC.dsp
@@ -0,0 +1,148 @@
+# Microsoft Developer Studio Project File - Name="OSC" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=OSC - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "OSC.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "OSC.mak" CFG="OSC - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "OSC - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "OSC - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "OSC - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "RAFOSC_EXPORTS" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../../pd/src" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "OSC_EXPORTS" /D "NT" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
+# ADD LINK32 pd.lib libc.lib kernel32.lib wsock32.lib LIBOSC.lib /nologo /dll /machine:I386 /nodefaultlib /out:"../../../pd/extra/OSC.dll" /libpath:"../../../pd/lib" /libpath:"../../../pd/bin"
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "OSC - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "RAFOSC_EXPORTS" /YX /FD /GZ /c
+# ADD CPP /nologo /MTd /W3 /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "OSC_EXPORTS" /D "NT" /YX /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 pd.lib libc.lib kernel32.lib wsock32.lib LIBOSC.lib /nologo /dll /debug /machine:I386 /nodefaultlib /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "OSC - Win32 Release"
+# Name "OSC - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\dumpOSC.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\htmsocket.c
+# End Source File
+# Begin Source File
+
+SOURCE=".\OSC-pattern-match.c"
+# End Source File
+# Begin Source File
+
+SOURCE=.\OSC.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\routeOSC.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\sendOSC.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\htmsocket.h
+# End Source File
+# Begin Source File
+
+SOURCE=".\OSC-client.h"
+# End Source File
+# Begin Source File
+
+SOURCE=".\OSC-common.h"
+# End Source File
+# Begin Source File
+
+SOURCE=".\OSC-pattern-match.h"
+# End Source File
+# Begin Source File
+
+SOURCE=".\OSC-timetag.h"
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/OSC/OSC.dsw b/OSC/OSC.dsw
new file mode 100644
index 0000000..293b7f7
--- /dev/null
+++ b/OSC/OSC.dsw
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "OSC"=.\OSC.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/OSC/TODO.txt b/OSC/TODO.txt
new file mode 100644
index 0000000..23f1855
--- /dev/null
+++ b/OSC/TODO.txt
@@ -0,0 +1,20 @@
+
+for win32: port also the command line utilities (send, dump)
+
+-pd object hierarchy extract and automatic address construction
+ a la [/hostname]/pd/patchname/subpatch/test ?
+
+
+changelog:
+
+20020305: -typetags in send and receive
+ sendOSC by default now send typetagged msgs
+ and dumOSC properly reads and outputs them.
+
+prior:
+
+ -added OSCroute with source adapt from max object.
+ -fixed shared htmsock bug
+ -added sendtyped separately earlier and lost it again
+
+ \ No newline at end of file
diff --git a/OSC/VERSION b/OSC/VERSION
new file mode 100644
index 0000000..689f5a7
--- /dev/null
+++ b/OSC/VERSION
@@ -0,0 +1 @@
+0.16-3
diff --git a/OSC/dumpOSC.c b/OSC/dumpOSC.c
new file mode 100644
index 0000000..76dea42
--- /dev/null
+++ b/OSC/dumpOSC.c
@@ -0,0 +1,889 @@
+/*
+Copyright (c) 1992,1993,1994,1995,1996,1997,2000.
+The Regents of the University of California (Regents).
+All Rights Reserved.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for educational, research, and not-for-profit purposes, without
+fee and without a signed licensing agreement, is hereby granted, provided that
+the above copyright notice, this paragraph and the following two paragraphs
+appear in all copies, modifications, and distributions. Contact The Office of
+Technology Licensing, UC Berkeley, 2150 Shattuck Avenue, Suite 510, Berkeley,
+CA 94720-1620, (510) 643-7201, for commercial licensing opportunities.
+
+Written by Matt Wright and Adrian Freed, The Center for New Music and Audio
+Technologies, University of California, Berkeley.
+
+ IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
+ ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING
+ DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS".
+ REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
+ ENHANCEMENTS, OR MODIFICATIONS.
+*/
+
+ /*
+
+ dumpOSC.c
+ server that displays OpenSoundControl messages sent to it
+ for debugging client udp and UNIX protocol
+
+ by Matt Wright, 6/3/97
+ modified from dumpSC.c, by Matt Wright and Adrian Freed
+
+ version 0.2: Added "-silent" option a.k.a. "-quiet"
+
+ version 0.3: Incorporated patches from Nicola Bernardini to make
+ things Linux-friendly. Also added ntohl() in the right places
+ to support little-endian architectures.
+
+
+
+ compile:
+ cc -o dumpOSC dumpOSC.c
+
+ to-do:
+
+ More robustness in saying exactly what's wrong with ill-formed
+ messages. (If they don't make sense, show exactly what was
+ received.)
+
+ Time-based features: print time-received for each packet
+
+ Clean up to separate OSC parsing code from socket/select stuff
+
+ pd
+ -------------
+ -- tweaks for Win32 www.zeggz.com/raf 13-April-2002
+
+*/
+
+
+#include "m_imp.h"
+//#include "m_pd.h"
+//#include "x_osc.h"
+
+#if defined(__sgi) || defined(__linux) || defined(WIN32)
+
+#ifdef WIN32
+ #include "OSC-common.h"
+ #include <winsock2.h>
+ #include <string.h>
+ #include <stdlib.h>
+ #include <fcntl.h>
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <ctype.h>
+ #include <signal.h>
+#else
+ #include <stdio.h>
+ #include <string.h>
+ #include <stdlib.h>
+ #include <unistd.h>
+ #include <fcntl.h>
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <netinet/in.h>
+ #include <rpc/rpc.h>
+ #include <sys/socket.h>
+ #include <sys/un.h>
+ #include <sys/times.h>
+ #include <sys/param.h>
+ #include <sys/time.h>
+ #include <sys/ioctl.h>
+ #include <ctype.h>
+ #include <arpa/inet.h>
+ #include <netdb.h>
+ #include <pwd.h>
+ #include <signal.h>
+ #include <grp.h>
+ #include <sys/file.h>
+ #include <sys/prctl.h>
+
+ #ifdef NEED_SCHEDCTL_AND_LOCK
+ #include <sys/schedctl.h>
+ #include <sys/lock.h>
+ #endif
+#endif
+
+
+char *htm_error_string;
+typedef int Boolean;
+typedef void *OBJ;
+
+typedef struct ClientAddressStruct {
+ struct sockaddr_in cl_addr;
+ int clilen;
+ int sockfd;
+} *ClientAddr;
+
+Boolean ShowBytes = FALSE;
+Boolean Silent = FALSE;
+
+/* Declarations */
+#ifndef WIN32
+static int unixinitudp(int chan);
+#endif
+
+static int initudp(int chan);
+static void closeudp(int sockfd);
+Boolean ClientReply(int packetsize, void *packet, int socketfd,
+ void *clientaddresspointer, int clientaddressbufferlength);
+void sgi_CleanExit(void);
+Boolean sgi_HaveToQuit(void);
+int RegisterPollingDevice(int fd, void (*callbackfunction)(int , void *), void *dummy);
+static void catch_sigint();
+static int Synthmessage(char *m, int n, void *clientdesc, int clientdesclength, int fd) ;
+char *DataAfterAlignedString(char *string, char *boundary) ;
+Boolean IsNiceString(char *string, char *boundary) ;
+void complain(char *s, ...);
+
+#define MAXMESG 32768
+static char mbuf[MAXMESG];
+
+/* ----------------------------- dumpOSC ------------------------- */
+
+#define MAXOUTAT 50
+
+static t_class *dumpOSC_class;
+
+typedef struct _dumpOSC
+{
+ t_object x_obj;
+ t_outlet *x_msgout;
+ t_outlet *x_connectout;
+ t_atom x_outat[MAXOUTAT];
+ int x_outatc;
+ t_binbuf *x_b;
+ int x_connectsocket;
+ int x_nconnections;
+ int x_udp;
+ struct sockaddr_in x_server;
+ int x_clilen;
+} t_dumpOSC;
+
+void dumpOSC_ParsePacket(t_dumpOSC *x, char *buf, int n, ClientAddr returnAddr);
+static void dumpOSC_Smessage(t_dumpOSC *x, char *address, void *v, int n, ClientAddr returnAddr);
+static void dumpOSC_PrintTypeTaggedArgs(t_dumpOSC *x, void *v, int n);
+static void dumpOSC_PrintHeuristicallyTypeGuessedArgs(t_dumpOSC *x, void *v, int n, int skipComma);
+
+static void dumpOSC_read(t_dumpOSC *x, int sockfd) {
+ int clilen = x->x_clilen;
+ int n;
+ struct ClientAddressStruct ras;
+ ClientAddr ra = &ras;
+
+ //catchupflag= FALSE;
+
+/* if (ShowBytes) { */
+/* int i; */
+/* printf("%d byte message:\n", n); */
+/* for (i = 0; i < n; ++i) { */
+/* printf(" %x (%c)\t", m[i], m[i]); */
+/* if (i%4 == 3) printf("\n"); */
+/* } */
+/* printf("\n"); */
+/* } */
+
+ // return catchupflag;
+ //struct sockaddr_in x->x_server;
+ //while( (n = recvfrom(sockfd, mbuf, MAXMESG, 0, &cl_addr, &clilen)) >0)
+ // while((
+ #ifdef WIN32
+ if ((n = recvfrom(sockfd, mbuf, MAXMESG, 0, (SOCKADDR*)&x->x_server, &clilen)) >0)
+ #else
+ if ((n = recvfrom(sockfd, mbuf, MAXMESG, 0, &x->x_server, &clilen)) >0)
+ #endif
+ {
+ //int r;
+ ras.cl_addr = *((struct sockaddr_in *) &x->x_server);
+ ras.clilen = x->x_clilen;
+ ras.sockfd = x->x_connectsocket;
+
+ #ifdef DEBUG
+ printf("dumpOSC_read: received UDP packet of length %d\n", n);
+ #endif
+ dumpOSC_ParsePacket(x, mbuf, n, ra);
+
+ //r = Synthmessage(mbuf, n, &x->x_server, clilen, sockfd);
+ //post ("%d", r);
+ //outlet_anything(x->x_msgout, at[msg].a_w.w_symbol,
+ // emsg-msg-1, at + msg + 1);
+ // outlet_list(x->x_msgout, 0, n, mbuf);
+ //if( sgi_HaveToQuit()) goto out;
+ //if(r>0) goto back;
+ //clilen = maxclilen;
+ }
+}
+
+static void *dumpOSC_new(t_symbol *compatflag,
+ t_floatarg fportno) {
+ t_dumpOSC *x;
+ struct sockaddr_in server;
+ int clilen=sizeof(server);
+ int sockfd;
+ int portno=fportno;
+ int udp = 1;
+
+ //x->x_b = binbuf_new();
+ //x->x_outat = binbuf_getvec(x->x_b);
+
+ //{{raf}} pointer not valid yet...moving this down
+ //x->x_outatc = 0; {{raf}}
+
+ /* create a socket */
+ sockfd = socket(AF_INET, (udp ? SOCK_DGRAM : SOCK_STREAM), 0);
+
+ if (sockfd < 0)
+ {
+ sys_sockerror("socket");
+ return (0);
+ }
+ server.sin_family = AF_INET;
+ server.sin_addr.s_addr = INADDR_ANY;
+ /* assign server port number */
+ server.sin_port = htons((u_short)portno);
+ /* name the socket */
+ if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0)
+ {
+ sys_sockerror("bind");
+ sys_closesocket(sockfd);
+ return (0);
+ }
+
+ x = (t_dumpOSC *)pd_new(dumpOSC_class);
+ x->x_outatc = 0; // {{raf}} now pointer is valid (less invalid)
+
+ x->x_msgout = outlet_new(&x->x_obj, &s_anything);
+
+ if (udp) /* datagram protocol */
+ {
+
+/* t_socketreceiver *y = socketreceiver_new((void *)x, */
+/* 0, */
+/* (x->x_msgout ? dumpOSC_doit : 0)); */
+
+ // sys_addpollfn(sockfd, (t_fdpollfn)socketreceiver_read_x, y);
+
+ sys_addpollfn(sockfd, (t_fdpollfn)dumpOSC_read, x);
+ x->x_connectout = 0;
+ }
+ // else /* streaming protocol */
+ /* { */
+ /* if (listen(sockfd, 5) < 0) */
+ /* { */
+ /* sys_sockerror("listen"); */
+ /* sys_closesocket(sockfd); */
+ /* sockfd = -1; */
+ /* } */
+ /* else */
+ /* { */
+ /* sys_addpollfn(sockfd, (t_fdpollfn)dumpOSC_connectpoll, x); */
+ /* x->x_connectout = outlet_new(&x->x_obj, &s_float); */
+ /* } */
+ /* } */
+
+ x->x_connectsocket = sockfd;
+ x->x_server = server;
+ x->x_clilen = clilen;
+ x->x_nconnections = 0;
+ x->x_udp = udp;
+
+ return (x);
+}
+
+static void dumpOSC_free(t_dumpOSC *x)
+{
+ /* LATER make me clean up open connections */
+ if (x->x_connectsocket >= 0)
+ {
+ sys_rmpollfn(x->x_connectsocket);
+ sys_closesocket(x->x_connectsocket);
+ }
+}
+
+#ifdef WIN32
+OSC_API void dumpOSC_setup(void)
+#else
+void dumpOSC_setup(void)
+#endif
+{
+ dumpOSC_class = class_new(gensym("dumpOSC"),
+ (t_newmethod)dumpOSC_new, (t_method)dumpOSC_free,
+ sizeof(t_dumpOSC), CLASS_NOINLET, A_DEFFLOAT, A_DEFFLOAT,
+ A_DEFSYM, 0);
+ class_sethelpsymbol(dumpOSC_class, gensym("OSC/dumpOSC-help.pd"));
+}
+
+
+#ifndef WIN32
+ #define UNIXDG_PATH "/tmp/htm"
+ #define UNIXDG_TMP "/tmp/htm.XXXXXX"
+ static int unixinitudp(int chan)
+ {
+ struct sockaddr_un serv_addr;
+ int sockfd;
+
+ if((sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
+ return sockfd;
+
+ bzero((char *)&serv_addr, sizeof(serv_addr));
+ serv_addr.sun_family = AF_UNIX;
+ strcpy(serv_addr.sun_path, UNIXDG_PATH);
+ sprintf(serv_addr.sun_path+strlen(serv_addr.sun_path), "%d", chan);
+ unlink(serv_addr.sun_path);
+ if(bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr.sun_family)+strlen(serv_addr.sun_path)) < 0)
+ {
+ perror("unable to bind\n");
+ return -1;
+ }
+
+ fcntl(sockfd, F_SETFL, FNDELAY);
+ return sockfd;
+ }
+#endif // #ifndef WIN32
+
+
+
+static int initudp(int chan)
+{
+
+#ifdef WIN32
+ struct sockaddr_in serv_addr;
+ unsigned int sockfd;
+ ULONG nonBlocking = (ULONG) TRUE;
+
+ if( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) != INVALID_SOCKET ) {
+ ZeroMemory((char *)&serv_addr, sizeof(serv_addr));
+ serv_addr.sin_family = AF_INET;
+ serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ serv_addr.sin_port = htons(chan);
+ if(bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) >= 0) {
+ // set for non-blocking mode
+ if(ioctlsocket(sockfd, FIONBIO, &nonBlocking) == SOCKET_ERROR) {
+ perror("unable to set non-blocking\n");
+ return -1;
+ }
+ }
+ else { perror("unable to bind\n"); return -1; }
+ }
+ return (sockfd == INVALID_SOCKET ? -1 : (int)sockfd);
+#else
+ struct sockaddr_in serv_addr;
+ int sockfd;
+
+ if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ return sockfd;
+
+ bzero((char *)&serv_addr, sizeof(serv_addr));
+ serv_addr.sin_family = AF_INET;
+ serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ serv_addr.sin_port = htons(chan);
+
+ if(bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
+ {
+ perror("unable to bind\n");
+ return -1;
+ }
+
+ fcntl(sockfd, F_SETFL, FNDELAY);
+ return sockfd;
+#endif
+}
+
+
+
+
+
+
+
+
+static void closeudp(int sockfd) {
+ #ifdef WIN32
+ closesocket(sockfd);
+ #else
+ close(sockfd);
+ #endif
+}
+
+static Boolean catchupflag=FALSE;
+Boolean ClientReply(int packetsize, void *packet, int socketfd,
+ void *clientaddresspointer, int clientaddressbufferlength)
+{
+ if(!clientaddresspointer) return FALSE;
+ catchupflag= TRUE;
+ return packetsize==sendto(socketfd, packet, packetsize, 0, clientaddresspointer, clientaddressbufferlength);
+}
+
+static Boolean exitflag= FALSE;
+void sgi_CleanExit(void) {
+ exitflag = TRUE;
+}
+
+Boolean sgi_HaveToQuit(void) {
+ return exitflag;
+}
+
+
+/* file descriptor poll table */
+static int npolldevs =0;
+typedef struct polldev
+{
+ int fd;
+ void (*callbackfunction)(int , void *);
+ void *dummy;
+} polldev;
+#define TABMAX 8
+static polldev polldevs[TABMAX];
+
+
+/* Register a device (referred to by a file descriptor that the caller
+ should have already successfully obtained from a system call) to be
+ polled as real-time constraints allowed.
+
+ When a select(2) call indicates activity on the file descriptor, the
+ callback function is called with the file descripter as first
+ argument and the given dummy argument (presumably a pointer to the
+ instance variables associated with the device).
+*/
+int RegisterPollingDevice(int fd, void (*callbackfunction)(int , void *), void *dummy)
+{
+ if(npolldevs<TABMAX)
+ {
+ polldevs[npolldevs].fd = fd;
+ polldevs[npolldevs].callbackfunction = callbackfunction;
+ polldevs[npolldevs].dummy = dummy;
+ }
+ else return -1;
+ return npolldevs++;
+}
+
+static int caught_sigint;
+
+static void catch_sigint() {
+ caught_sigint = 1;
+}
+static int sockfd, usockfd;
+
+
+void PrintClientAddr(ClientAddr CA) {
+ unsigned long addr = CA->cl_addr.sin_addr.s_addr;
+ printf("Client address %p:\n", CA);
+ printf(" clilen %d, sockfd %d\n", CA->clilen, CA->sockfd);
+ printf(" sin_family %d, sin_port %d\n", CA->cl_addr.sin_family,
+ CA->cl_addr.sin_port);
+ printf(" address: (%x) %s\n", addr, inet_ntoa(CA->cl_addr.sin_addr));
+
+ printf(" sin_zero = \"%c%c%c%c%c%c%c%c\"\n",
+ CA->cl_addr.sin_zero[0],
+ CA->cl_addr.sin_zero[1],
+ CA->cl_addr.sin_zero[2],
+ CA->cl_addr.sin_zero[3],
+ CA->cl_addr.sin_zero[4],
+ CA->cl_addr.sin_zero[5],
+ CA->cl_addr.sin_zero[6],
+ CA->cl_addr.sin_zero[7]);
+
+ printf("\n");
+}
+
+
+void dumpOSC_ParsePacket(t_dumpOSC *x, char *buf, int n, ClientAddr returnAddr) {
+ // t_dumpOSC *x;
+ int size, messageLen, i;
+ char *messageName;
+ char *args;
+
+ //#ifdef PRINTADDRS
+ #ifdef DEBUG
+ //PrintClientAddr(returnAddr);
+ #endif
+
+
+ if ((n%4) != 0) {
+ complain("SynthControl packet size (%d) not a multiple of 4 bytes: dropping", n);
+ return;
+ }
+
+ if ((n >= 8) && (strncmp(buf, "#bundle", 8) == 0)) {
+ /* This is a bundle message. */
+ #ifdef DEBUG
+ printf("dumpOSC_ParsePacket: bundle msg: bundles not yet supported\n");
+ #endif
+
+ if (n < 16) {
+ complain("Bundle message too small (%d bytes) for time tag", n);
+ return;
+ }
+
+ /* Print the time tag */
+ #ifdef DEBUG
+ printf("[ %lx%08lx\n", ntohl(*((unsigned long *)(buf+8))), ntohl(*((unsigned long *)(buf+12))));
+ #endif
+
+ /* Note: if we wanted to actually use the time tag as a little-endian
+ 64-bit int, we'd have to word-swap the two 32-bit halves of it */
+
+ i = 16; /* Skip "#group\0" and time tag */
+
+ while(i<n) {
+ size = ntohl(*((int *) (buf + i)));
+ if ((size % 4) != 0) {
+ complain("Bad size count %d in bundle (not a multiple of 4)", size);
+ return;
+ }
+ if ((size + i + 4) > n) {
+ complain("Bad size count %d in bundle (only %d bytes left in entire bundle)",
+ size, n-i-4);
+ return;
+ }
+
+ /* Recursively handle element of bundle */
+ dumpOSC_ParsePacket(x, buf+i+4, size, returnAddr);
+ i += 4 + size;
+ }
+
+ if (i != n) {
+ complain("This can't happen");
+ }
+ #ifdef DEBUG
+ printf("]\n");
+ #endif
+
+ } else {
+ /* This is not a bundle message */
+
+ messageName = buf;
+ args = DataAfterAlignedString(messageName, buf+n);
+ if (args == 0) {
+ complain("Bad message name string: %s\nDropping entire message.\n",
+ htm_error_string);
+ return;
+ }
+ messageLen = args-messageName;
+ dumpOSC_Smessage(x, messageName, (void *)args, n-messageLen, returnAddr);
+ }
+}
+
+#define SMALLEST_POSITIVE_FLOAT 0.000001f
+
+static void dumpOSC_Smessage(t_dumpOSC *x, char *address, void *v, int n, ClientAddr returnAddr) {
+ char *chars = v;
+ t_atom at;
+ //t_atom myargv[50];
+
+ int myargc = x->x_outatc;
+ t_atom* mya = x->x_outat;
+ int myi;
+
+#ifdef DEBUG
+ printf("%s ", address);
+#endif
+
+ // ztoln+cvt from envgen.c, ggee-0.18 ..
+ // outlet_anything's 'symbol' gets set to address
+ // so we dont need to append address to the atomlist
+ /*
+ SETSYMBOL(mya,gensym(address));myargc++;
+ x->x_outatc = myargc;
+ */
+
+ if (n != 0) {
+ if (chars[0] == ',') {
+ if (chars[1] != ',') {
+ /* This message begins with a type-tag string */
+ dumpOSC_PrintTypeTaggedArgs(x, v, n);
+ } else {
+ /* Double comma means an escaped real comma, not a type string */
+ dumpOSC_PrintHeuristicallyTypeGuessedArgs(x, v, n, 1);
+ }
+ } else {
+ dumpOSC_PrintHeuristicallyTypeGuessedArgs(x, v, n, 0);
+ }
+ }
+
+ outlet_anything(x->x_msgout,gensym(address),x->x_outatc,(t_atom*)&x->x_outat);
+ x->x_outatc = 0;
+#ifdef DEBUG
+ printf("\n");
+#endif
+ fflush(stdout); /* Added for Sami 5/21/98 */
+}
+
+static void dumpOSC_PrintTypeTaggedArgs(t_dumpOSC *x, void *v, int n) {
+ char *typeTags, *thisType;
+ char *p;
+
+ int myargc = x->x_outatc;
+ t_atom* mya = x->x_outat;
+ int myi;
+
+ typeTags = v;
+
+ if (!IsNiceString(typeTags, typeTags+n)) {
+ /* No null-termination, so maybe it wasn't a type tag
+ string after all */
+ dumpOSC_PrintHeuristicallyTypeGuessedArgs(x, v, n, 0);
+ return;
+ }
+
+ p = DataAfterAlignedString(typeTags, typeTags+n);
+
+
+ for (thisType = typeTags + 1; *thisType != 0; ++thisType) {
+ switch (*thisType) {
+ case 'i': case 'r': case 'm': case 'c':
+#ifdef DEBUG
+ //post("integer: %d", ntohl(*((int *) p)));
+#endif
+ SETFLOAT(mya+myargc,ntohl(*((int *) p)));
+ myargc++;
+
+ p += 4;
+ break;
+
+ case 'f': {
+ int i = ntohl(*((int *) p));
+ float *floatp = ((float *) (&i));
+#ifdef DEBUG
+ post("float: %f", *floatp);
+#endif
+ SETFLOAT(mya+myargc,*floatp);
+ myargc++;
+
+ p += 4;
+ }
+ break;
+
+ case 'h': case 't':
+#ifdef DEBUG
+ printf("[A 64-bit int] ");
+#endif
+ post("[A 64-bit int] not implemented");
+
+ p += 8;
+ break;
+
+ case 'd':
+#ifdef DEBUG
+ printf("[A 64-bit float] ");
+#endif
+ post("[A 64-bit float] not implemented");
+
+ p += 8;
+ break;
+
+ case 's': case 'S':
+ if (!IsNiceString(p, typeTags+n)) {
+ post("Type tag said this arg is a string but it's not!\n");
+ return;
+ } else {
+#ifdef DEBUG
+ post("string: \"%s\"", p);
+#endif
+ SETSYMBOL(mya+myargc,gensym(p));
+ myargc++;
+ //outlet_list(x->x_msgout, 0,sizeof(p), p);
+ //outlet_anything(x->x_msgout, 0, sizeof(p), p);
+ p = DataAfterAlignedString(p, typeTags+n);
+ // append to output vector ..
+ }
+ break;
+
+ case 'T':
+#ifdef DEBUG
+ printf("[True] ");
+#endif
+ SETFLOAT(mya+myargc,1.);
+ myargc++;
+ break;
+ case 'F':
+#ifdef DEBUG
+ printf("[False] ");
+#endif
+ SETFLOAT(mya+myargc,0.);
+ myargc++;
+ break;
+ case 'N':
+#ifdef DEBUG
+ printf("[Nil]");
+#endif
+ post("sendOSC: [Nil] not implemented");
+ break;
+ case 'I':
+#ifdef DEBUG
+ printf("[Infinitum]");
+#endif
+ post("sendOSC: [Infinitum] not implemented");
+ break;
+
+ default:
+ post("sendOSC: [Unrecognized type tag %c]", *thisType);
+ // return;
+ }
+ }
+ x->x_outatc = myargc;
+}
+
+static void dumpOSC_PrintHeuristicallyTypeGuessedArgs(t_dumpOSC *x, void *v, int n, int skipComma) {
+ int i, thisi;
+ float thisf;
+ int *ints;
+ char *chars;
+ char *string, *nextString;
+
+ int myargc= x->x_outatc;
+ t_atom* mya = x->x_outat;
+ int myi;
+
+
+ /* Go through the arguments 32 bits at a time */
+ ints = v;
+ chars = v;
+
+ for (i = 0; i<n/4; ) {
+ string = &chars[i*4];
+ thisi = ntohl(ints[i]);
+ /* Reinterpret the (potentially byte-reversed) thisi as a float */
+ thisf = *(((float *) (&thisi)));
+
+ if (thisi >= -1000 && thisi <= 1000000) {
+#ifdef DEBUG
+ printf("%d ", thisi);
+#endif
+ // append to output vector ..
+ SETFLOAT(mya+myargc,(t_float) (thisi));
+ myargc++;
+ // outlet_float(x->x_msgout, thisi);
+ i++;
+ } else if (thisf >= -1000.f && thisf <= 1000000.f &&
+ (thisf <=0.0f || thisf >= SMALLEST_POSITIVE_FLOAT)) {
+#ifdef DEBUG
+ printf("%f ", thisf);
+#endif
+ // append to output vector ..
+ SETFLOAT(mya+myargc,thisf);
+ myargc++;
+ //outlet_float(x->x_msgout, thisf);
+ i++;
+ } else if (IsNiceString(string, chars+n)) {
+ nextString = DataAfterAlignedString(string, chars+n);
+#ifdef DEBUG
+ printf("\"%s\" ", (i == 0 && skipComma) ? string +1 : string);
+#endif
+ // append to output vector ..
+ SETSYMBOL(mya+myargc,gensym(string));
+ myargc++;
+ //outlet_symbol(x->x_msgout, gensym((i == 0 && skipComma) ? string +1 : string));
+ i += (nextString-string) / 4;
+ } else {
+ // unhandled .. ;)
+#ifdef DEBUG
+ printf("0x%x xx", ints[i]);
+#endif
+ i++;
+ }
+ x->x_outatc = myargc;
+ }
+}
+
+
+#define STRING_ALIGN_PAD 4
+
+char *DataAfterAlignedString(char *string, char *boundary)
+{
+ /* 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 STRING_ALIGN_PAD
+ 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 htm_error_string */
+
+ int i;
+
+ if ((boundary - string) %4 != 0) {
+ fprintf(stderr, "Internal error: DataAfterAlignedString: bad boundary\n");
+ return 0;
+ }
+
+ for (i = 0; string[i] != '\0'; i++) {
+ if (string + i >= boundary) {
+ htm_error_string = "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) {
+ htm_error_string = "DataAfterAlignedString: Unreasonably long string";
+ return 0;
+ }
+ if (string[i] != '\0') {
+ htm_error_string = "DataAfterAlignedString: Incorrectly padded string.";
+ return 0;
+ }
+ }
+
+ return string+i;
+}
+
+Boolean IsNiceString(char *string, char *boundary)
+{
+ /* Arguments same as DataAfterAlignedString(). Is the given "string"
+ really a string? I.e., is it a sequence of isprint() characters
+ terminated with 1-4 null characters to align on a 4-byte boundary? */
+
+ int i;
+
+ if ((boundary - string) %4 != 0) {
+ fprintf(stderr, "Internal error: IsNiceString: bad boundary\n");
+ return 0;
+ }
+
+ for (i = 0; string[i] != '\0'; i++) {
+ if (!isprint(string[i])) return FALSE;
+ if (string + i >= boundary) return FALSE;
+ }
+
+ /* If we made it this far, it's a null-terminated sequence of printing characters
+ in the given boundary. Now we just make sure it's null padded... */
+
+ /* Now string[i] is the first null character */
+ i++;
+ for (; (i % STRING_ALIGN_PAD) != 0; i++) {
+ if (string[i] != '\0') return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+
+
+
+
+
+
+
+#include <stdarg.h>
+void complain(char *s, ...) {
+ va_list ap;
+ va_start(ap, s);
+ fprintf(stderr, "*** ERROR: ");
+ vfprintf(stderr, s, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+}
+
+#endif /* __sgi or LINUX or WIN32 */
diff --git a/OSC/htmsocket.c b/OSC/htmsocket.c
new file mode 100644
index 0000000..420853f
--- /dev/null
+++ b/OSC/htmsocket.c
@@ -0,0 +1,297 @@
+/*
+Copyright (c) 1992,1996,1998.
+The Regents of the University of California (Regents).
+All Rights Reserved.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for educational, research, and not-for-profit purposes, without
+fee and without a signed licensing agreement, is hereby granted, provided that
+the above copyright notice, this paragraph and the following two paragraphs
+appear in all copies, modifications, and distributions. Contact The Office of
+Technology Licensing, UC Berkeley, 2150 Shattuck Avenue, Suite 510, Berkeley,
+CA 94720-1620, (510) 643-7201, for commercial licensing opportunities.
+
+Written by Adrian Freed, The Center for New Music and Audio Technologies,
+University of California, Berkeley.
+
+ IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
+ ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING
+ DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS".
+ REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
+ ENHANCEMENTS, OR MODIFICATIONS.
+*/
+
+ /* htmsocket.c
+
+ Adrian Freed
+ send parameters to htm servers by udp or UNIX protocol
+
+ Modified 6/6/96 by Matt Wright to understand symbolic host names
+ in addition to X.X.X.X addresses.
+ */
+
+
+#ifdef WIN32
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <winsock2.h>
+ #include <ctype.h>
+ #include <signal.h>
+ #include <sys/types.h>
+ #include <stdlib.h>
+ #include "OSC-common.h"
+#else
+ #include <stdio.h>
+ #include <unistd.h>
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <netinet/in.h>
+
+ #include <rpc/rpc.h>
+ #include <sys/socket.h>
+ #include <sys/un.h>
+ #include <sys/times.h>
+ #include <sys/param.h>
+ #include <sys/time.h>
+ #include <sys/ioctl.h>
+
+ #include <ctype.h>
+ #include <arpa/inet.h>
+ #include <netdb.h>
+ #include <pwd.h>
+ #include <signal.h>
+ #include <grp.h>
+ #include <sys/fcntl.h>
+ #include <sys/file.h>
+ #include <sys/time.h>
+ #include <sys/types.h>
+ #include <sys/prctl.h>
+
+ #include <stdlib.h>
+#endif
+
+
+
+
+
+
+
+
+
+
+#define UNIXDG_PATH "/tmp/htm"
+#define UNIXDG_TMP "/tmp/htm.XXXXXX"
+#include "htmsocket.h"
+typedef struct
+{
+ float srate;
+
+ struct sockaddr_in serv_addr; /* udp socket */
+ #ifndef WIN32
+ struct sockaddr_un userv_addr; /* UNIX socket */
+ #endif
+ int sockfd; /* socket file descriptor */
+ int index, len,uservlen;
+ void *addr;
+ int id;
+} desc;
+
+/* open a socket for HTM communication to given host on given portnumber */
+/* if host is 0 then UNIX protocol is used (i.e. local communication */
+void *OpenHTMSocket(char *host, int portnumber)
+{
+ struct sockaddr_in cl_addr;
+ #ifndef WIN32
+ int sockfd;
+ struct sockaddr_un ucl_addr;
+ #else
+ unsigned int sockfd;
+ #endif
+
+ desc *o;
+ o = malloc(sizeof(*o));
+ if(!o)
+ return 0;
+
+ #ifndef WIN32
+
+ if(!host)
+ {
+ char *mktemp(char *);
+ int clilen;
+ o->len = sizeof(ucl_addr);
+ /*
+ * Fill in the structure "userv_addr" with the address of the
+ * server that we want to send to.
+ */
+
+ bzero((char *) &o->userv_addr, sizeof(o->userv_addr));
+ o->userv_addr.sun_family = AF_UNIX;
+ strcpy(o->userv_addr.sun_path, UNIXDG_PATH);
+ sprintf(o->userv_addr.sun_path+strlen(o->userv_addr.sun_path), "%d", portnumber);
+ o->uservlen = sizeof(o->userv_addr.sun_family) + strlen(o->userv_addr.sun_path);
+ o->addr = &(o->userv_addr);
+ /*
+ * Open a socket (a UNIX domain datagram socket).
+ */
+
+ if ( (sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) >= 0)
+ {
+ /*
+ * Bind a local address for us.
+ * In the UNIX domain we have to choose our own name (that
+ * should be unique). We'll use mktemp() to create a unique
+ * pathname, based on our process id.
+ */
+
+ bzero((char *) &ucl_addr, sizeof(ucl_addr)); /* zero out */
+ ucl_addr.sun_family = AF_UNIX;
+ strcpy(ucl_addr.sun_path, UNIXDG_TMP);
+
+ mktemp(ucl_addr.sun_path);
+ clilen = sizeof(ucl_addr.sun_family) + strlen(ucl_addr.sun_path);
+
+ if (bind(sockfd, (struct sockaddr *) &ucl_addr, clilen) < 0)
+ {
+ perror("client: can't bind local address");
+ close(sockfd);
+ sockfd = -1;
+ }
+ }
+ else
+ perror("unable to make socket\n");
+
+ }else
+
+ #endif
+
+ {
+ /*
+ * Fill in the structure "serv_addr" with the address of the
+ * server that we want to send to.
+ */
+ o->len = sizeof(cl_addr);
+
+ #ifdef WIN32
+ ZeroMemory((char *)&o->serv_addr, sizeof(o->serv_addr));
+ #else
+ bzero((char *)&o->serv_addr, sizeof(o->serv_addr));
+ #endif
+
+ o->serv_addr.sin_family = AF_INET;
+
+ /* MW 6/6/96: Call gethostbyname() instead of inet_addr(),
+ so that host can be either an Internet host name (e.g.,
+ "les") or an Internet address in standard dot notation
+ (e.g., "128.32.122.13") */
+ {
+ struct hostent *hostsEntry;
+ unsigned long address;
+
+ hostsEntry = gethostbyname(host);
+ if (hostsEntry == NULL) {
+ fprintf(stderr, "Couldn't decipher host name \"%s\"\n", host);
+ #ifndef WIN32
+ herror(NULL);
+ #endif
+ return 0;
+ }
+
+ address = *((unsigned long *) hostsEntry->h_addr_list[0]);
+ o->serv_addr.sin_addr.s_addr = address;
+ }
+
+ /* was: o->serv_addr.sin_addr.s_addr = inet_addr(host); */
+
+ /* End MW changes */
+
+ /*
+ * Open a socket (a UDP domain datagram socket).
+ */
+
+
+ #ifdef WIN32
+ o->serv_addr.sin_port = htons((USHORT)portnumber);
+ o->addr = &(o->serv_addr);
+ if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) != INVALID_SOCKET) {
+ ZeroMemory((char *)&cl_addr, sizeof(cl_addr));
+ cl_addr.sin_family = AF_INET;
+ cl_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ cl_addr.sin_port = htons(0);
+
+ if(bind(sockfd, (struct sockaddr *) &cl_addr, sizeof(cl_addr)) < 0) {
+ perror("could not bind\n");
+ closesocket(sockfd);
+ sockfd = -1;
+ }
+ }
+ else { perror("unable to make socket\n");}
+ #else
+ o->serv_addr.sin_port = htons(portnumber);
+ o->addr = &(o->serv_addr);
+ if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) >= 0) {
+ bzero((char *)&cl_addr, sizeof(cl_addr));
+ cl_addr.sin_family = AF_INET;
+ cl_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ cl_addr.sin_port = htons(0);
+
+ if(bind(sockfd, (struct sockaddr *) &cl_addr, sizeof(cl_addr)) < 0) {
+ perror("could not bind\n");
+ close(sockfd);
+ sockfd = -1;
+ }
+ }
+ else { perror("unable to make socket\n");}
+ #endif
+ }
+ #ifdef WIN32
+ if(sockfd == INVALID_SOCKET) {
+ #else
+ if(sockfd < 0) {
+ #endif
+ free(o);
+ o = 0;
+ }
+ else
+ o->sockfd = sockfd;
+ return o;
+}
+
+
+#include <errno.h>
+
+static bool sendudp(const struct sockaddr *sp, int sockfd,int length, int count, void *b)
+{
+ int rcount;
+ if((rcount=sendto(sockfd, b, count, 0, sp, length)) != count)
+ {
+ printf("sockfd %d count %d rcount %dlength %d errno %d\n", sockfd,count,rcount,length, errno);
+ return FALSE;
+ }
+ return TRUE;
+}
+bool SendHTMSocket(void *htmsendhandle, int length_in_bytes, void *buffer)
+{
+ desc *o = (desc *)htmsendhandle;
+ return sendudp(o->addr, o->sockfd, o->len, length_in_bytes, buffer);
+}
+void CloseHTMSocket(void *htmsendhandle)
+{
+ desc *o = (desc *)htmsendhandle;
+ #ifdef WIN32
+ if(SOCKET_ERROR == closesocket(o->sockfd)) {
+ perror("CloseHTMSocket::closesocket failed\n");
+ return;
+ }
+ #else
+ close(o->sockfd);
+ #endif
+
+ free(o);
+}
diff --git a/OSC/htmsocket.h b/OSC/htmsocket.h
new file mode 100644
index 0000000..b035b57
--- /dev/null
+++ b/OSC/htmsocket.h
@@ -0,0 +1,49 @@
+/*
+Copyright (c) 1992,1996. The Regents of the University of California (Regents).
+All Rights Reserved.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for educational, research, and not-for-profit purposes, without
+fee and without a signed licensing agreement, is hereby granted, provided that
+the above copyright notice, this paragraph and the following two paragraphs
+appear in all copies, modifications, and distributions. Contact The Office of
+Technology Licensing, UC Berkeley, 2150 Shattuck Avenue, Suite 510, Berkeley,
+CA 94720-1620, (510) 643-7201, for commercial licensing opportunities.
+
+Written by Adrian Freed, The Center for New Music and Audio Technologies,
+University of California, Berkeley.
+
+ IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
+ ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING
+ DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS".
+ REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
+ ENHANCEMENTS, OR MODIFICATIONS.
+*/
+
+ /* htmparam.h
+
+ Adrian Freed
+ send parameters to htm servers by udp or UNIX protocol
+ */
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+typedef int bool;
+
+/* open a socket for HTM communication to given host on given portnumber */
+/* if host is 0 then UNIX protocol is used (i.e. local communication) */
+void *OpenHTMSocket(char *host, int portnumber);
+
+/* send a buffer of data over htm socket, returns TRUE on success.
+ Note that udp sends rarely fail. UNIX sends fail if a kernal buffer overflows */
+bool SendHTMSocket(void *htmsendhandle, int length_in_bytes, void *buffer);
+
+/* close the socket(2) and release memory associated with it */
+void CloseHTMSocket(void *htmsendhandle);
diff --git a/OSC/makefile b/OSC/makefile
new file mode 100644
index 0000000..8534bc9
--- /dev/null
+++ b/OSC/makefile
@@ -0,0 +1,69 @@
+###############################
+# change these
+IFLAGS = -I. -I../../pd-0.34-4/src
+INSTALL_PREFIX=/usr
+
+# should be oke below ..
+EXT = o
+#DEFS = -DHAVE_LIBC=1 -DHAVE_LIBM=1 -DHAVE_LIBPTHREAD=1 -DSTDC_HEADERS=1 -DHAVE_FCNTL_H=1 -DHAVE_SYS_TIME_H=1 -DHAVE_UNISTD_H=1 -DTIME_WITH_SYS_TIME=1 -DHAVE_UNISTD_H=1 -DHAVE_GETPAGESIZE=1 -DHAVE_MMAP=1 -DHAVE_SELECT=1 -DHAVE_SOCKET=1 -DHAVE_STRERROR=1 -DPD_VERSION_MINOR=32
+DEFS =
+CC = gcc
+CXX = c++
+LD = ld
+AFLAGS =
+LFLAGS = -export_dynamic -shared
+WFLAGS =
+
+# DEBUG = -DDEBUG -g
+DEBUG =
+
+VERSION = \"$(shell cat VERSION)\"
+
+.SUFFIXES: .$(EXT)
+
+PDCFLAGS = -O2 $(DEFS) $(IFLAGS) $(WFLAGS) $(LFLAGS) $(AFLAGS) -DVERSION=$(VERSION)
+CFLAGS = -O2 $(DEFS) $(IFLAGS) $(WFLAGS) -DVERSION=$(VERSION) $(DEBUG)
+CXXFLAGS = $(CFLAGS)
+LIBOSC = ../libOSC/libOSC.a
+LIBS = -lpthread -lm -lc
+SOURCES = htmsocket.c OSC-pattern-match.c sendOSC.c dumpOSC.c routeOSC.c
+TARGETS = $(SOURCES:.c=.$(EXT))
+
+all: $(TARGETS)
+
+OSC: $(TARGETS)
+ cc -c $(CFLAGS) -DPD OSC.c
+ $(LD) -export_dynamic -shared -o OSC.pd_linux *.o $(LIBS) $(LIBOSC)
+ strip --strip-unneeded OSC.pd_linux
+
+clean::
+ -rm *.$(EXT) *.pd_linux *~
+
+distclean: clean
+ -rm config.cache config.log config.status makefile
+
+
+distcleancvs:
+ -rm -r CVS reference/CVS
+
+
+.c.o:
+ $(CC) -c -o $@ $(CFLAGS) -DPD $*.c
+
+# cp $@ $*_stat.o
+
+#.o.pd_linux:
+# $(CC) -o $@ $(PDCFLAGS) -DPD $*.o
+
+
+
+install::
+ install -d $(INSTALL_PREFIX)/lib/pd/externs
+# install -m 644 *.pd_linux $(INSTALL_PREFIX)/lib/pd/externs
+ install -m 644 OSC.pd_linux $(INSTALL_PREFIX)/lib/pd/externs
+ install -d $(INSTALL_PREFIX)/lib/pd/doc/5.reference/OSC
+ install -m 644 ../doc/*.pd $(INSTALL_PREFIX)/lib/pd/doc/5.reference/OSC
+
+
+#dist: distclean
+# (cd ..;tar czvf ggext.tgz ggext)
diff --git a/OSC/makefile.in b/OSC/makefile.in
new file mode 100644
index 0000000..1f951b6
--- /dev/null
+++ b/OSC/makefile.in
@@ -0,0 +1,60 @@
+EXT = o
+DEFS = -DHAVE_LIBC=1 -DHAVE_LIBM=1 -DHAVE_LIBPTHREAD=1 -DSTDC_HEADERS=1 -DHAVE_FCNTL_H=1 -DHAVE_SYS_TIME_H=1 -DHAVE_UNISTD_H=1 -DTIME_WITH_SYS_TIME=1 -DHAVE_UNISTD_H=1 -DHAVE_GETPAGESIZE=1 -DHAVE_MMAP=1 -DHAVE_SELECT=1 -DHAVE_SOCKET=1 -DHAVE_STRERROR=1 -DPD_VERSION_MINOR=32
+CC = gcc
+CXX = c++
+LD = ld
+AFLAGS =
+LFLAGS = -export_dynamic -shared
+WFLAGS =
+IFLAGS = -I. -I../../pd/src
+INSTALL_PREFIX=@prefix@
+
+VERSION = \"$(shell cat VERSION)\"
+
+.SUFFIXES: .$(EXT)
+
+PDCFLAGS = -g -O2 $(DEFS) $(IFLAGS) $(WFLAGS) $(LFLAGS) $(AFLAGS) -DVERSION=$(VERSION)
+CFLAGS = -g -O2 $(DEFS) $(IFLAGS) $(WFLAGS) -DVERSION=$(VERSION)
+CXXFLAGS = $(CFLAGS)
+LIBOSC = ../libOSC/libOSC.a
+LIBS = -lpthread -lm -lc
+SOURCES = htmsocket.c OSC-pattern-match.c sendOSC.c dumpOSC.c routeOSC.c
+TARGETS = $(SOURCES:.c=.$(EXT))
+
+all: $(TARGETS)
+
+OSC: $(TARGETS)
+ cc -c $(CFLAGS) -DPD osc.c
+ $(LD) -export_dynamic -shared -o OSC.pd_linux *.o $(LIBS) $(LIBOSC)
+ strip --strip-unneeded OSC.pd_linux
+
+clean::
+ -rm *.$(EXT) *.pd_linux *~
+
+distclean: clean
+ -rm config.cache config.log config.status makefile
+
+
+distcleancvs:
+ -rm -r CVS reference/CVS
+
+
+.c.o:
+ $(CC) -c -o $@ $(CFLAGS) -DPD $*.c
+
+# cp $@ $*_stat.o
+
+#.o.pd_linux:
+# $(CC) -o $@ $(PDCFLAGS) -DPD $*.o
+
+
+
+install::
+ install -d $(INSTALL_PREFIX)/lib/pd/externs
+ install -m 644 *.pd_linux $(INSTALL_PREFIX)/lib/pd/externs
+ -install -m 644 OSC.pd_linux $(INSTALL_PREFIX)/lib/pd/externs
+ install -m 644 *.pd $(INSTALL_PREFIX)/lib/pd/doc/5.reference
+
+
+dist: distclean
+ (cd ..;tar czvf ggext.tgz ggext)
diff --git a/OSC/routeOSC.c b/OSC/routeOSC.c
new file mode 100644
index 0000000..4ff38cb
--- /dev/null
+++ b/OSC/routeOSC.c
@@ -0,0 +1,417 @@
+/*
+Copyright (c) 1999, 2000, 20010 The Regents of the University of
+California (Regents).
+All Rights Reserved.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for educational, research, and not-for-profit purposes, without
+fee and without a signed licensing agreement, is hereby granted, provided that
+the above copyright notice, this paragraph and the following two paragraphs
+appear in all copies, modifications, and distributions. Contact The Office of
+Technology Licensing, UC Berkeley, 2150 Shattuck Avenue, Suite 510, Berkeley,
+CA 94720-1620, (510) 643-7201, for commercial licensing opportunities.
+
+Written by Matt Wright, The Center for New Music and Audio Technologies,
+University of California, Berkeley.
+
+ IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
+ ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING
+ DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS".
+ REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
+ ENHANCEMENTS, OR MODIFICATIONS.
+
+The OpenSound Control WWW page is
+ http://www.cnmat.berkeley.edu/OpenSoundControl
+
+ OSC-route.c
+ Max object for OSC-style dispatching
+
+ To-do:
+
+ Match a pattern against a pattern?
+ Declare outlet types / distinguish leaf nodes from other children
+ More sophisticated (2-pass?) allmessages scheme
+ set message?
+
+
+ pd
+ -------------
+ -- tweaks for Win32 www.zeggz.com/raf 13-April-2002
+
+
+ */
+
+
+
+/* the required include files */
+#include "m_pd.h"
+#include "OSC-common.h"
+#include "OSC-pattern-match.h"
+
+#ifdef WIN32
+ #include <stdlib.h>
+ #include <string.h>
+#endif
+
+
+/* structure definition of your object */
+#define MAX_NUM 20
+#define OSC_ROUTE_VERSION "1.05"
+/* Version 1.04: Allows #1 thru #9 as typed-in arguments
+ Version 1.05: Allows "list" messages as well as "message" messages.
+*/
+
+static t_class *OSCroute_class;
+
+typedef struct _OSCroute
+{
+ t_object x_obj; // required header
+ t_int x_num; // Number of address prefixes we store
+ t_int x_complainmode; // Do we print a message if no match?
+ char *x_prefixes[MAX_NUM];
+ void *x_outlets[MAX_NUM];
+} t_OSCroute;
+
+t_symbol *ps_list, *ps_complain, *ps_emptySymbol;
+
+/* prototypes */
+
+void OSCroute_doanything(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv);
+void OSCroute_anything(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv);
+void OSCroute_list(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv);
+/* //void *OSCroute_new(t_symbol *s, int argc, atom *argv); */
+void *OSCroute_new(t_symbol *s, int argc, t_atom *argv);
+void OSCroute_version (t_OSCroute *x);
+/* void OSCroute_assist (OSCroute *x, void *box, long msg, long arg, */
+/* char *dstString); */
+void OSCroute_allmessages(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv);
+
+static char *NextSlashOrNull(char *p);
+static void StrCopyUntilSlash(char *target, const char *source);
+
+
+// free
+static void OSCroute_free(t_OSCroute *x)
+{
+ // freebytes(x->x_vec, x->x_nelement * sizeof(*x->x_vec));
+}
+
+/* initialization routine */
+
+// setup
+#ifdef WIN32
+ OSC_API void OSCroute_setup(void) {
+#else
+ void OSCroute_setup(void) {
+#endif
+ OSCroute_class = class_new(gensym("OSCroute"), (t_newmethod)OSCroute_new,
+ (t_method)OSCroute_free,sizeof(t_OSCroute), 0, A_GIMME, 0);
+ class_addlist(OSCroute_class, OSCroute_list);
+ class_addanything(OSCroute_class, OSCroute_anything);
+ class_addmethod(OSCroute_class, (t_method)OSCroute_version, gensym("version"), A_NULL, 0, 0);
+ class_sethelpsymbol(OSCroute_class, gensym("OSC/OSCroute-help.pd"));
+
+ /*
+ class_addmethod(OSCroute_class, (t_method)OSCroute_connect,
+ gensym("connect"), A_SYMBOL, A_FLOAT, 0);
+ class_addmethod(OSCroute_class, (t_method)OSCroute_disconnect,
+ gensym("disconnect"), 0);
+ class_addmethod(OSCroute_class, (t_method)OSCroute_send, gensym("send"),
+ A_GIMME, 0);
+ */
+/* ps_list = gensym("list"); */
+/* ps_complain = gensym("complain"); */
+ ps_emptySymbol = gensym("");
+
+ post("OSCroute object version " OSC_ROUTE_VERSION " by Matt Wright. pd-fication cxc. Win32 raf.");
+ post("OSCroute Copyright © 1999 Regents of the University of California. All Rights Reserved.");
+}
+
+
+
+/* instance creation routine */
+
+void *OSCroute_new(t_symbol *s, int argc, t_atom *argv)
+{
+ //OSCroute *x;
+ t_OSCroute *x = (t_OSCroute *)pd_new(OSCroute_class); // get memory for a new object & initialize
+
+ //int i, n;
+ int i; //{{raf}} n not used
+
+ // EnterCallback();
+
+ if (argc > MAX_NUM) {
+ post("* OSC-route: too many arguments: %ld (max %ld)", argc, MAX_NUM);
+ // ExitCallback();
+ return 0;
+ }
+
+ //x = newobject(OSCroute_class); // get memory for a new object & initialize
+
+ x->x_complainmode = 0;
+ x->x_num = 0;
+ for (i = 0; i < argc; ++i) {
+ if (argv[i].a_type == A_SYMBOL) {
+ if (argv[i].a_w.w_symbol->s_name[0] == '/') {
+ /* Now that's a nice prefix */
+ x->x_prefixes[i] = argv[i].a_w.w_symbol->s_name;
+ ++(x->x_num);
+ } else if (argv[i].a_w.w_symbol->s_name[0] == '#' &&
+ argv[i].a_w.w_symbol->s_name[1] >= '1' &&
+ argv[i].a_w.w_symbol->s_name[1] <= '9') {
+ /* The Max programmer is trying to make a patch that will be
+ a subpatch with arguments. We have to make an outlet for this
+ argument. */
+ x->x_prefixes[i] = "dummy";
+ ++(x->x_num);
+ } else {
+ /* Maybe this is an option we support */
+
+/* if (argv[i].a_w.w_sym == ps_complain) { */
+/* x->x_complainmode = 1; */
+/* } else { */
+/* post("* OSC-route: Unrecognized argument %s", argv[i].a_w.w_sym->s_name); */
+/* } */
+
+ }
+
+ // no LONG
+
+/* } else if (argv[i].a_type == A_FLOAD) { */
+/* // Convert to a numeral. Max ints are -2147483648 to 2147483647 */
+/* char *string = getbytes(12); */
+/* // I can't be bothered to plug this 12 byte memory leak */
+/* if (string == 0) { */
+/* post("* OSC-route: out of memory!"); */
+/* // ExitCallback(); */
+/* return 0; */
+/* } */
+/* sprintf(string, "%d", argv[i].a_w.w_long); */
+/* x->x_prefixes[i] = string; */
+/* ++(x->x_num); */
+
+ } else if (argv[i].a_type == A_FLOAT) {
+ post("* OSC-route: float arguments are not OK.");
+ // ExitCallback();
+ return 0;
+ } else {
+ post("* OSC-route: unrecognized argument type!");
+ // ExitCallback();
+ return 0;
+ }
+ }
+
+
+ /* Have to create the outlets in reverse order */
+ /* well, not in pd ? */
+ // for (i = x->x_num-1; i >= 0; --i) {
+ for (i = 0; i <= x->x_num-1; i++) {
+ // x->x_outlets[i] = listout(x);
+ x->x_outlets[i] = outlet_new(&x->x_obj, &s_list);
+ }
+
+ // ExitCallback();
+ return (x);
+}
+
+
+void OSCroute_version (t_OSCroute *x) {
+ // EnterCallback();
+ post("OSCroute Version " OSC_ROUTE_VERSION
+ ", by Matt Wright. pd-fication cxc@web.fm\nOSCroute Compiled " __TIME__ " " __DATE__);
+ // ExitCallback();
+}
+
+/* I don't know why these aren't defined in some Max #include file. */
+#define ASSIST_INLET 1
+#define ASSIST_OUTLET 2
+
+void OSCroute_assist (t_OSCroute *x, void *box, long msg, long arg,
+ char *dstString) {
+ // EnterCallback();
+
+ if (msg==ASSIST_INLET) {
+ sprintf(dstString, "Incoming OSC messages");
+ } else if (msg==ASSIST_OUTLET) {
+ if (arg < 0 || arg >= x->x_num) {
+ post("* OSCroute_assist: No outlet corresponds to arg %ld!", arg);
+ } else {
+ sprintf(dstString, "subaddress + args for prefix %s", x->x_prefixes[arg]);
+ }
+ } else {
+ post("* OSCroute_assist: unrecognized message %ld", msg);
+ }
+
+ // ExitCallback();
+}
+
+void OSCroute_list(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv) {
+ // EnterCallback();
+ if (argc > 0 && argv[0].a_type == A_SYMBOL) {
+ /* Ignore the fact that this is a "list" */
+ OSCroute_doanything(x, argv[0].a_w.w_symbol, argc-1, argv+1);
+ } else {
+ post("* OSC-route: invalid list beginning with a number");
+ }
+ // ExitCallback();
+}
+
+
+void OSCroute_anything(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv) {
+ // EnterCallback();
+ OSCroute_doanything(x, s, argc, argv);
+ // ExitCallback();
+}
+
+
+
+
+void OSCroute_doanything(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv) {
+ char *pattern, *nextSlash;
+ int i;
+ int matchedAnything;
+ // post("*** OSCroute_anything(s %s, argc %ld)", s->s_name, (long) argc);
+
+ pattern = s->s_name;
+ if (pattern[0] != '/') {
+ post("* OSC-route: invalid message pattern %s does not begin with /", s->s_name);
+ return;
+ }
+
+ matchedAnything = 0;
+
+ nextSlash = NextSlashOrNull(pattern+1);
+ if (*nextSlash == '\0') {
+ /* last level of the address, so we'll output the argument list */
+
+
+#ifdef NULL_IS_DIFFERENT_FROM_BANG
+ if (argc==0) {
+ post("* OSC-route: why are you matching one level pattern %s with no args?",
+ pattern);
+ return;
+ }
+#endif
+
+ for (i = 0; i < x->x_num; ++i) {
+ if (PatternMatch(pattern+1, x->x_prefixes[i]+1)) {
+ ++matchedAnything;
+
+ // I hate stupid Max lists with a special first element
+ if (argc == 0) {
+ outlet_bang(x->x_outlets[i]);
+ } else if (argv[0].a_type == A_SYMBOL) {
+ // Promote the symbol that was argv[0] to the special symbol
+
+ outlet_anything(x->x_outlets[i], argv[0].a_w.w_symbol, argc-1, argv+1);
+ } else if (argc > 1) {
+ // Multiple arguments starting with a number, so naturally we have
+ // to use a special function to output this "list", since it's what
+ // Max originally meant by "list".
+ outlet_list(x->x_outlets[i], 0L, argc, argv);
+ } else {
+ // There was only one argument, and it was a number, so we output it
+ // not as a list
+/* if (argv[0].a_type == A_LONG) { */
+
+/* outlet_int(x->x_outlets[i], argv[0].a_w.w_long); */
+ // } else
+ if (argv[0].a_type == A_FLOAT) {
+
+ outlet_float(x->x_outlets[i], argv[0].a_w.w_float);
+ } else {
+ post("* OSC-route: unrecognized atom type!");
+ }
+ }
+ }
+ }
+ } else {
+ /* There's more address after this part, so our output list will begin with
+ the next slash. */
+ t_symbol *restOfPattern = 0; /* avoid the gensym unless we have to output */
+ char patternBegin[1000];
+
+
+ /* Get the first level of the incoming pattern to match against all our prefixes */
+ StrCopyUntilSlash(patternBegin, pattern+1);
+
+ for (i = 0; i < x->x_num; ++i) {
+ if (PatternMatch(patternBegin, x->x_prefixes[i]+1)) {
+ ++matchedAnything;
+ if (restOfPattern == 0) {
+ restOfPattern = gensym(nextSlash);
+ }
+ outlet_anything(x->x_outlets[i], restOfPattern, argc, argv);
+ }
+ }
+ }
+
+ if (x->x_complainmode) {
+ if (!matchedAnything) {
+ post("* OSC-route: pattern %s did not match any prefixes", pattern);
+ }
+ }
+}
+
+static char *NextSlashOrNull(char *p) {
+ while (*p != '/' && *p != '\0') {
+ p++;
+ }
+ return p;
+}
+
+static void StrCopyUntilSlash(char *target, const char *source) {
+ while (*source != '/' && *source != '\0') {
+ *target = *source;
+ ++target;
+ ++source;
+ }
+ *target = 0;
+}
+
+static int MyStrCopy(char *target, const char *source) {
+ int i = 0;
+ while (*source != '\0') {
+ *target = *source;
+ ++target;
+ ++source;
+ ++i;
+ }
+ *target = 0;
+ return i;
+}
+
+
+
+void OSCroute_allmessages(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv) {
+ int i;
+ t_symbol *prefixSymbol = 0;
+ char prefixBuf[1000];
+ char *endOfPrefix;
+ t_atom a[1];
+
+ if (argc >= 1 && argv[0].a_type == A_SYMBOL) {
+ prefixSymbol = argv[0].a_w.w_symbol;
+ endOfPrefix = prefixBuf + MyStrCopy(prefixBuf,
+ prefixSymbol->s_name);
+ } else {
+ prefixSymbol = ps_emptySymbol;
+ prefixBuf[0] = '\0';
+ endOfPrefix = prefixBuf;
+ }
+
+
+ for (i = 0; i < x->x_num; ++i) {
+ post("OSC: %s%s", prefixSymbol->s_name, x->x_prefixes[i]);
+ MyStrCopy(endOfPrefix, x->x_prefixes[i]);
+ SETSYMBOL(a, gensym(prefixBuf));
+ outlet_anything(x->x_outlets[i], s, 1, a);
+ }
+}
diff --git a/OSC/sendOSC.c b/OSC/sendOSC.c
new file mode 100644
index 0000000..ce4e6ee
--- /dev/null
+++ b/OSC/sendOSC.c
@@ -0,0 +1,875 @@
+/*
+Copyright (c) 1996,1997. The Regents of the University of California (Regents).
+All Rights Reserved.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for educational, research, and not-for-profit purposes, without
+fee and without a signed licensing agreement, is hereby granted, provided that
+the above copyright notice, this paragraph and the following two paragraphs
+appear in all copies, modifications, and distributions. Contact The Office of
+Technology Licensing, UC Berkeley, 2150 Shattuck Avenue, Suite 510, Berkeley,
+CA 94720-1620, (510) 643-7201, for commercial licensing opportunities.
+
+Written by Matt Wright, The Center for New Music and Audio Technologies,
+University of California, Berkeley.
+
+ IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
+ ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING
+ DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS".
+ REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
+ ENHANCEMENTS, OR MODIFICATIONS.
+*/
+
+/* sendOSC.c
+
+ Matt Wright, 6/3/97
+ based on sendOSC.c, which was based on a version by Adrian Freed
+
+ Text-based OpenSoundControl client. User can enter messages via command
+ line arguments or standard input.
+
+ Version 0.1: "play" feature
+ Version 0.2: Message type tags.
+
+
+
+ pd
+ -------------
+ -- added bundle stuff to send. jdl 20020416
+ -- tweaks for Win32 www.zeggz.com/raf 13-April-2002
+ -- ost_at_test.at + i22_at_test.at, 2000-2002
+ modified to compile as pd externel
+
+*/
+
+//#define VERSION "http://cnmat.berkeley.edu/OpenSoundControl/sendOSC-0.1.html"
+#define MAX_ARGS 2000
+#define SC_BUFFER_SIZE 32000
+
+/*
+compiling:
+ cc -o sendOSC sendOSC.c htmsocket.c OpenSoundControl.c OSC_timeTag.c
+*/
+
+#ifdef WIN32
+ #include "m_pd.h"
+ #include "OSC-client.h"
+ #include "htmsocket.h"
+ #include "OSC-common.h"
+ #include <winsock2.h>
+ #include <io.h>
+ #include <errno.h>
+ #include <fcntl.h>
+ #include <sys/stat.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <sys/types.h>
+#else
+ #include "m_pd.h"
+ //#include "x_osc.h"
+ #include "OSC-client.h"
+ #include "htmsocket.h"
+
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <sys/types.h>
+ #include <netinet/in.h>
+ #include <netdb.h>
+#endif
+
+///////////////////////
+// from sendOSC
+
+typedef struct {
+ //enum {INT, FLOAT, STRING} type;
+ enum {INT_osc, FLOAT_osc, STRING_osc} type;
+ union {
+ int i;
+ float f;
+ char *s;
+ } datum;
+} typedArg;
+
+void CommandLineMode(int argc, char *argv[], void *htmsocket);
+//void InteractiveMode(void *htmsocket);
+OSCTimeTag ParseTimeTag(char *s);
+void ParseInteractiveLine(OSCbuf *buf, char *mesg);
+typedArg ParseToken(char *token);
+int WriteMessage(OSCbuf *buf, char *messageName, int numArgs, typedArg *args);
+void SendBuffer(void *htmsocket, OSCbuf *buf);
+void SendData(void *htmsocket, int size, char *data);
+void fatal_error(char *s);
+void send_complain(char *s, ...);
+
+//static void *htmsocket;
+static int exitStatus = 0;
+static int useTypeTags = 0;
+
+static char bufferForOSCbuf[SC_BUFFER_SIZE];
+
+
+/////////
+// end from sendOSC
+
+static t_class *sendOSC_class;
+
+typedef struct _sendOSC
+{
+ t_object x_obj;
+ int x_protocol; // UDP/TCP (udp only atm)
+ t_int x_typetags; // typetag flag
+ void *x_htmsocket; // sending socket
+ int x_bundle; // bundle open flag
+ OSCbuf x_oscbuf[1]; // OSCbuffer
+ t_outlet *x_bdpthout;// bundle-depth floatoutlet
+} t_sendOSC;
+
+static void *sendOSC_new(t_floatarg udpflag)
+{
+ t_sendOSC *x = (t_sendOSC *)pd_new(sendOSC_class);
+ outlet_new(&x->x_obj, &s_float);
+ x->x_htmsocket = 0; // {{raf}}
+ // set udp
+ x->x_protocol = SOCK_STREAM;
+ // set typetags to 1 by default
+ x->x_typetags = 1;
+ // bunlde is closed
+ x->x_bundle = 0;
+ OSC_initBuffer(x->x_oscbuf, SC_BUFFER_SIZE, bufferForOSCbuf);
+ x->x_bdpthout = outlet_new(&x->x_obj, 0); // outlet_float();
+ //x->x_oscbuf =
+ return (x);
+}
+
+
+void sendOSC_openbundle(t_sendOSC *x)
+{
+ if (x->x_oscbuf->bundleDepth + 1 >= MAX_BUNDLE_NESTING ||
+ OSC_openBundle(x->x_oscbuf, OSCTT_Immediately()))
+ {
+ send_complain("Problem opening bundle: %s\n", OSC_errorMessage);
+ return;
+ }
+ x->x_bundle = 1;
+ outlet_float(x->x_bdpthout, (float)x->x_oscbuf->bundleDepth);
+}
+
+static void sendOSC_closebundle(t_sendOSC *x)
+{
+ if (OSC_closeBundle(x->x_oscbuf)) {
+ send_complain("Problem closing bundle: %s\n", OSC_errorMessage);
+ return;
+ }
+ outlet_float(x->x_bdpthout, (float)x->x_oscbuf->bundleDepth);
+ // in bundle mode we send when bundle is closed?
+ if(!OSC_isBufferEmpty(x->x_oscbuf) > 0 && OSC_isBufferDone(x->x_oscbuf)) {
+ // post("x_oscbuf: something inside me?");
+ if (x->x_htmsocket) {
+ SendBuffer(x->x_htmsocket, x->x_oscbuf);
+ } else {
+ post("sendOSC: not connected");
+ }
+ OSC_initBuffer(x->x_oscbuf, SC_BUFFER_SIZE, bufferForOSCbuf);
+ x->x_bundle = 0;
+ return;
+ }
+ // post("x_oscbuf: something went wrong");
+}
+
+static void sendOSC_settypetags(t_sendOSC *x, t_float *f)
+ {
+ x->x_typetags = (int)f;
+ post("sendOSC.c: setting typetags %d",x->x_typetags);
+ }
+
+
+static void sendOSC_connect(t_sendOSC *x, t_symbol *hostname,
+ t_floatarg fportno)
+{
+ int portno = fportno;
+ /* create a socket */
+
+ // make sure handle is available
+ if(x->x_htmsocket == 0) {
+ //
+ x->x_htmsocket = OpenHTMSocket(hostname->s_name, portno);
+ if (!x->x_htmsocket)
+ post("Couldn't open socket: ");
+ else {
+ post("connected to port %s:%d (hSock=%d)", hostname->s_name, portno, x->x_htmsocket);
+ outlet_float(x->x_obj.ob_outlet, 1);
+ }
+ }
+ else
+ perror("call to sendOSC_connect() against UNavailable socket handle");
+}
+
+void sendOSC_disconnect(t_sendOSC *x)
+{
+ if (x->x_htmsocket)
+ {
+ post("disconnecting htmsock (hSock=%d)...", x->x_htmsocket);
+ CloseHTMSocket(x->x_htmsocket);
+ x->x_htmsocket = 0; // {{raf}} semi-quasi-semaphorize this
+ outlet_float(x->x_obj.ob_outlet, 0);
+ }
+ else {
+ perror("call to sendOSC_disconnect() against unused socket handle");
+ }
+}
+
+void sendOSC_senduntyped(t_sendOSC *x, t_symbol *s, int argc, t_atom *argv)
+{
+ char* targv[MAXPDARG];
+ char tmparg[MAXPDSTRING];
+ char* tmp = tmparg;
+ //char testarg[MAXPDSTRING];
+ int c;
+
+ post("sendOSC: use typetags 0/1 message and plain send method so send untypetagged...");
+ return;
+
+ //atom_string(argv,testarg, MAXPDSTRING);
+ for (c=0;c<argc;c++) {
+ atom_string(argv+c,tmp, 80);
+ // post ("sendOSC: %d, %s",c, tmp);
+ targv[c] = tmp;
+ tmp += strlen(tmp)+1;
+ //post ("sendOSC: %d, %s",c, targv[c]);
+ }
+ // this sock needs to be larger than 0, not >= ..
+ if (x->x_htmsocket)
+ {
+ CommandLineMode(argc, targv, x->x_htmsocket);
+ // post("test %d", c);
+ }
+ else {
+ post("sendOSC: not connected");
+ // exit(3);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////
+// this is the real and only sending routine now, for both typed and undtyped mode.
+
+static void sendOSC_sendtyped(t_sendOSC *x, t_symbol *s, int argc, t_atom *argv)
+{
+ char* targv[MAXPDARG];
+ char tmparg[MAXPDSTRING];
+ char* tmp = tmparg;
+ int c;
+
+ char *messageName;
+ char *token;
+ typedArg args[MAX_ARGS];
+ int i,j;
+ int numArgs = 0;
+
+ messageName = "";
+#ifdef DEBUG
+ post ("sendOSC: messageName: %s", messageName);
+#endif
+
+
+
+ for (c=0;c<argc;c++) {
+ atom_string(argv+c,tmp, 80);
+
+#ifdef DEBUG
+ // post ("sendOSC: %d, %s",c, tmp);
+#endif
+
+ targv[c] = tmp;
+ tmp += strlen(tmp)+1;
+
+#ifdef DEBUG
+ // post ("sendOSC: %d, %s",c, targv[c]);
+#endif
+ }
+
+ // this sock needs to be larger than 0, not >= ..
+ if (x->x_htmsocket > 0)
+ {
+#ifdef DEBUG
+ post ("sendOSC: type tags? %d", useTypeTags);
+#endif
+
+ messageName = strtok(targv[0], ",");
+ j = 1;
+ for (i = j; i < argc; i++) {
+ token = strtok(targv[i],",");
+ args[i-j] = ParseToken(token);
+#ifdef DEBUG
+ printf("cell-cont: %s\n", targv[i]);
+ printf(" type-id: %d\n", args[i-j]);
+#endif
+ numArgs = i;
+ }
+
+
+ if(WriteMessage(x->x_oscbuf, messageName, numArgs, args)) {
+ post("sendOSC: usage error, write-msg failed: %s", OSC_errorMessage);
+ return;
+ }
+
+ if(!x->x_bundle) {
+/* // post("sendOSC: accumulating bundle, not sending things ..."); */
+/* } else { */
+ // post("sendOSC: yeah and OUT!");
+ SendBuffer(x->x_htmsocket, x->x_oscbuf);
+ OSC_initBuffer(x->x_oscbuf, SC_BUFFER_SIZE, bufferForOSCbuf);
+ }
+
+ //CommandLineMode(argc, targv, x->x_htmsocket);
+ //useTypeTags = 0;
+ }
+ else {
+ post("sendOSC: not connected");
+ // exit(3);
+ }
+}
+
+void sendOSC_send(t_sendOSC *x, t_symbol *s, int argc, t_atom *argv)
+{
+ if(!argc) {
+ post("not sending empty message.");
+ return;
+ }
+ if(x->x_typetags) {
+ useTypeTags = 1;
+ sendOSC_sendtyped(x,s,argc,argv);
+ useTypeTags = 0;
+ } else {
+ sendOSC_sendtyped(x,s,argc,argv);
+ }
+}
+
+static void sendOSC_free(t_sendOSC *x)
+{
+ sendOSC_disconnect(x);
+}
+
+#ifdef WIN32
+ OSC_API void sendOSC_setup(void) {
+#else
+ void sendOSC_setup(void) {
+#endif
+ sendOSC_class = class_new(gensym("sendOSC"), (t_newmethod)sendOSC_new,
+ (t_method)sendOSC_free,
+ sizeof(t_sendOSC), 0, A_DEFFLOAT, 0);
+ class_addmethod(sendOSC_class, (t_method)sendOSC_connect,
+ gensym("connect"), A_SYMBOL, A_FLOAT, 0);
+ class_addmethod(sendOSC_class, (t_method)sendOSC_disconnect,
+ gensym("disconnect"), 0);
+ class_addmethod(sendOSC_class, (t_method)sendOSC_settypetags,
+ gensym("typetags"),
+ A_FLOAT, 0);
+ class_addmethod(sendOSC_class, (t_method)sendOSC_send,
+ gensym("send"),
+ A_GIMME, 0);
+ class_addmethod(sendOSC_class, (t_method)sendOSC_send,
+ gensym("senduntyped"),
+ A_GIMME, 0);
+ class_addmethod(sendOSC_class, (t_method)sendOSC_send,
+ gensym("sendtyped"),
+ A_GIMME, 0);
+ class_addmethod(sendOSC_class, (t_method)sendOSC_openbundle,
+ gensym("["),
+ 0, 0);
+ class_addmethod(sendOSC_class, (t_method)sendOSC_closebundle,
+ gensym("]"),
+ 0, 0);
+ class_sethelpsymbol(sendOSC_class, gensym("OSC/sendOSC-help.pd"));
+}
+
+
+
+
+
+/* Exit status codes:
+ 0: successful
+ 2: Message(s) dropped because of buffer overflow
+ 3: Socket error
+ 4: Usage error
+ 5: Internal error
+*/
+
+void CommandLineMode(int argc, char *argv[], void *htmsocket) {
+ char *messageName;
+ char *token;
+ typedArg args[MAX_ARGS];
+ int i,j, numArgs;
+ OSCbuf buf[1];
+
+ OSC_initBuffer(buf, SC_BUFFER_SIZE, bufferForOSCbuf);
+
+ if (argc > 1) {
+ post("argc (%d) > 1", argc);
+/* if (OSC_openBundle(buf, OSCTT_Immediately())) { */
+/* send_complain("Problem opening bundle: %s\n", OSC_errorMessage); */
+/* return; */
+/* } */
+ }
+
+ // ParseInteractiveLine(buf, argv);
+ messageName = strtok(argv[0], ",");
+
+ j = 1;
+ for (i = j; i < argc; i++) {
+ token = strtok(argv[i],",");
+ args[i-j] = ParseToken(token);
+#ifdef DEBUG
+ printf("cell-cont: %s\n", argv[i]);
+ printf(" type-id: %d\n", args[i-j]);
+#endif
+ numArgs = i;
+ }
+
+ if(WriteMessage(buf, messageName, numArgs, args)) {
+ post("sendOSC: usage error. write-msg failed: %s", OSC_errorMessage);
+ return;
+ }
+
+/* for (i = 0; i < argc; i++) { */
+/* messageName = strtok(argv[i], ","); */
+/* //send_complain ("commandlinemode: count: %d %s\n",i, messageName); */
+/* if (messageName == NULL) { */
+/* break; */
+/* } */
+
+/* j = 0; */
+/* while ((token = strtok(NULL, ",")) != NULL) { */
+/* args[j] = ParseToken(token); */
+/* j++; */
+/* if (j >= MAX_ARGS) { */
+/* send_complain("Sorry; your message has more than MAX_ARGS (%d) arguments; ignoring the rest.\n", */
+/* MAX_ARGS); */
+/* break; */
+/* } */
+/* } */
+/* numArgs = j; */
+
+/* WriteMessage(buf, messageName, numArgs, args); */
+
+/* } */
+
+/* if (argc > 1) { */
+/* if (OSC_closeBundle(buf)) { */
+/* send_complain("Problem closing bundle: %s\n", OSC_errorMessage); */
+/* return; */
+/* } */
+/* } */
+
+ SendBuffer(htmsocket, buf);
+}
+
+#define MAXMESG 2048
+
+void InteractiveMode(void *htmsocket) {
+ char mesg[MAXMESG];
+ OSCbuf buf[1];
+ int bundleDepth = 0; /* At first, we haven't seen "[". */
+
+ OSC_initBuffer(buf, SC_BUFFER_SIZE, bufferForOSCbuf);
+
+ while (fgets(mesg, MAXMESG, stdin) != NULL) {
+ if (mesg[0] == '\n') {
+ if (bundleDepth > 0) {
+ /* Ignore blank lines inside a group. */
+ } else {
+ /* blank line => repeat previous send */
+ SendBuffer(htmsocket, buf);
+ }
+ continue;
+ }
+
+ if (bundleDepth == 0) {
+ OSC_resetBuffer(buf);
+ }
+
+ if (mesg[0] == '[') {
+ OSCTimeTag tt = ParseTimeTag(mesg+1);
+ if (OSC_openBundle(buf, tt)) {
+ send_complain("Problem opening bundle: %s\n", OSC_errorMessage);
+ OSC_resetBuffer(buf);
+ bundleDepth = 0;
+ continue;
+ }
+ bundleDepth++;
+ } else if (mesg[0] == ']' && mesg[1] == '\n' && mesg[2] == '\0') {
+ if (bundleDepth == 0) {
+ send_complain("Unexpected ']': not currently in a bundle.\n");
+ } else {
+ if (OSC_closeBundle(buf)) {
+ send_complain("Problem closing bundle: %s\n", OSC_errorMessage);
+ OSC_resetBuffer(buf);
+ bundleDepth = 0;
+ continue;
+ }
+
+ bundleDepth--;
+ if (bundleDepth == 0) {
+ SendBuffer(htmsocket, buf);
+ }
+ }
+ } else {
+ ParseInteractiveLine(buf, mesg);
+ if (bundleDepth != 0) {
+ /* Don't send anything until we close all bundles */
+ } else {
+ SendBuffer(htmsocket, buf);
+ }
+ }
+ }
+}
+
+OSCTimeTag ParseTimeTag(char *s) {
+ char *p, *newline;
+ typedArg arg;
+
+ p = s;
+ while (isspace(*p)) p++;
+ if (*p == '\0') return OSCTT_Immediately();
+
+ if (*p == '+') {
+ /* Time tag is for some time in the future. It should be a
+ number of seconds as an int or float */
+
+ newline = strchr(s, '\n');
+ if (newline != NULL) *newline = '\0';
+
+ p++; /* Skip '+' */
+ while (isspace(*p)) p++;
+
+ arg = ParseToken(p);
+ if (arg.type == STRING_osc) {
+ send_complain("warning: inscrutable time tag request: %s\n", s);
+ return OSCTT_Immediately();
+ } else if (arg.type == INT_osc) {
+ return OSCTT_PlusSeconds(OSCTT_CurrentTime(),
+ (float) arg.datum.i);
+ } else if (arg.type == FLOAT_osc) {
+ return OSCTT_PlusSeconds(OSCTT_CurrentTime(), arg.datum.f);
+ } else {
+ fatal_error("This can't happen!");
+ }
+ }
+
+ if (isdigit(*p) || (*p >= 'a' && *p <='f') || (*p >= 'A' && *p <='F')) {
+ /* They specified the 8-byte tag in hex */
+ OSCTimeTag tt;
+ if (sscanf(p, "%llx", &tt) != 1) {
+ send_complain("warning: couldn't parse time tag %s\n", s);
+ return OSCTT_Immediately();
+ }
+#ifndef HAS8BYTEINT
+ if (ntohl(1) != 1) {
+ /* tt is a struct of seconds and fractional part,
+ and this machine is little-endian, so sscanf
+ wrote each half of the time tag in the wrong half
+ of the struct. */
+ uint32 temp;
+ temp = tt.seconds;
+ tt.seconds = tt.fraction ;
+ tt.fraction = temp;
+ }
+#endif
+ return tt;
+ }
+
+ send_complain("warning: invalid time tag: %s\n", s);
+ return OSCTT_Immediately();
+}
+
+
+void ParseInteractiveLine(OSCbuf *buf, char *mesg) {
+ char *messageName, *token, *p;
+ typedArg args[MAX_ARGS];
+ int thisArg;
+
+ p = mesg;
+ while (isspace(*p)) p++;
+ if (*p == '\0') return;
+
+ messageName = p;
+
+ if (strcmp(messageName, "play\n") == 0) {
+ /* Special kludge feature to save typing */
+ typedArg arg;
+
+ if (OSC_openBundle(buf, OSCTT_Immediately())) {
+ send_complain("Problem opening bundle: %s\n", OSC_errorMessage);
+ return;
+ }
+
+ arg.type = INT_osc;
+ arg.datum.i = 0;
+ WriteMessage(buf, "/voices/0/tp/timbre_index", 1, &arg);
+
+ arg.type = FLOAT_osc;
+ arg.datum.i = 0.0f;
+ WriteMessage(buf, "/voices/0/tm/goto", 1, &arg);
+
+ if (OSC_closeBundle(buf)) {
+ send_complain("Problem closing bundle: %s\n", OSC_errorMessage);
+ }
+
+ return;
+ }
+
+ while (!isspace(*p) && *p != '\0') p++;
+ if (isspace(*p)) {
+ *p = '\0';
+ p++;
+ }
+
+ thisArg = 0;
+ while (*p != '\0') {
+ /* flush leading whitespace */
+ while (isspace(*p)) p++;
+ if (*p == '\0') break;
+
+ if (*p == '"') {
+ /* A string argument: scan for close quotes */
+ p++;
+ args[thisArg].type = STRING_osc;
+ args[thisArg].datum.s = p;
+
+ while (*p != '"') {
+ if (*p == '\0') {
+ send_complain("Unterminated quote mark: ignoring line\n");
+ return;
+ }
+ p++;
+ }
+ *p = '\0';
+ p++;
+ } else {
+ token = p;
+ while (!isspace(*p) && (*p != '\0')) p++;
+ if (isspace(*p)) {
+ *p = '\0';
+ p++;
+ }
+ args[thisArg] = ParseToken(token);
+ }
+ thisArg++;
+ if (thisArg >= MAX_ARGS) {
+ send_complain("Sorry, your message has more than MAX_ARGS (%d) arguments; ignoring the rest.\n",
+ MAX_ARGS);
+ break;
+ }
+ }
+
+ if (WriteMessage(buf, messageName, thisArg, args) != 0) {
+ send_complain("Problem sending message: %s\n", OSC_errorMessage);
+ }
+}
+
+typedArg ParseToken(char *token) {
+ char *p = token;
+ typedArg returnVal;
+
+ /* It might be an int, a float, or a string */
+
+ if (*p == '-') p++;
+
+ if (isdigit(*p) || *p == '.') {
+ while (isdigit(*p)) p++;
+ if (*p == '\0') {
+ returnVal.type = INT_osc;
+ returnVal.datum.i = atoi(token);
+ return returnVal;
+ }
+ if (*p == '.') {
+ p++;
+ while (isdigit(*p)) p++;
+ if (*p == '\0') {
+ returnVal.type = FLOAT_osc;
+ returnVal.datum.f = atof(token);
+ return returnVal;
+ }
+ }
+ }
+
+ returnVal.type = STRING_osc;
+ returnVal.datum.s = token;
+ return returnVal;
+}
+
+int WriteMessage(OSCbuf *buf, char *messageName, int numArgs, typedArg *args) {
+ int j, returnVal;
+ const wmERROR = -1;
+
+ returnVal = 0;
+
+#ifdef DEBUG
+ printf("WriteMessage: %s ", messageName);
+
+ for (j = 0; j < numArgs; j++) {
+ switch (args[j].type) {
+ case INT_osc:
+ printf("%d ", args[j].datum.i);
+ break;
+
+ case FLOAT_osc:
+ printf("%f ", args[j].datum.f);
+ break;
+
+ case STRING_osc:
+ printf("%s ", args[j].datum.s);
+ break;
+
+ default:
+ fatal_error("Unrecognized arg type, (not exiting)");
+ return(wmERROR);
+ // exit(5);
+ }
+ }
+ printf("\n");
+#endif
+
+ if (!useTypeTags) {
+ returnVal = OSC_writeAddress(buf, messageName);
+ if (returnVal) {
+ send_complain("Problem writing address: %s\n", OSC_errorMessage);
+ }
+ } else {
+ /* First figure out the type tags */
+ char typeTags[MAX_ARGS+2];
+ int i;
+
+ typeTags[0] = ',';
+
+ for (i = 0; i < numArgs; ++i) {
+ switch (args[i].type) {
+ case INT_osc:
+ typeTags[i+1] = 'i';
+ break;
+
+ case FLOAT_osc:
+ typeTags[i+1] = 'f';
+ break;
+
+ case STRING_osc:
+ typeTags[i+1] = 's';
+ break;
+
+ default:
+ fatal_error("Unrecognized arg type (not exiting)");
+ return(wmERROR);
+ // exit(5);
+ }
+ }
+ typeTags[i+1] = '\0';
+
+ returnVal = OSC_writeAddressAndTypes(buf, messageName, typeTags);
+ if (returnVal) {
+ send_complain("Problem writing address: %s\n", OSC_errorMessage);
+ }
+ }
+
+ for (j = 0; j < numArgs; j++) {
+ switch (args[j].type) {
+ case INT_osc:
+ if ((returnVal = OSC_writeIntArg(buf, args[j].datum.i)) != 0) {
+ return returnVal;
+ }
+ break;
+
+ case FLOAT_osc:
+ if ((returnVal = OSC_writeFloatArg(buf, args[j].datum.f)) != 0) {
+ return returnVal;
+ }
+ break;
+
+ case STRING_osc:
+ if ((returnVal = OSC_writeStringArg(buf, args[j].datum.s)) != 0) {
+ return returnVal;
+ }
+ break;
+
+ default:
+ fatal_error("Unrecognized arg type (not exiting)");
+ returnVal = wmERROR;
+ // exit(5);
+ }
+ }
+ return returnVal;
+}
+
+void SendBuffer(void *htmsocket, OSCbuf *buf) {
+#ifdef DEBUG
+ printf("Sending buffer...\n");
+#endif
+ if (OSC_isBufferEmpty(buf)) {
+ post("SendBuffer() called but buffer empty");
+ return;
+ }
+ if (!OSC_isBufferDone(buf)) {
+ fatal_error("SendBuffer() called but buffer not ready!, not exiting");
+ // exit(5);
+ return; //{{raf}}
+ }
+ SendData(htmsocket, OSC_packetSize(buf), OSC_getPacket(buf));
+}
+
+void SendData(void *htmsocket, int size, char *data) {
+ if (!SendHTMSocket(htmsocket, size, data)) {
+ post("SendData::SendHTMSocket()failure -- not connected");
+ CloseHTMSocket(htmsocket);
+ // sendOSC_disconnect();
+ //exit(3);
+ // return;
+ }
+}
+
+void fatal_error(char *s) {
+ fprintf(stderr, "FATAL ERROR: %s\n", s);
+ post("fatal error, not exiting ...");
+ //exit(4);
+}
+
+#include <stdarg.h>
+void send_complain(char *s, ...) {
+ va_list ap;
+ va_start(ap, s);
+ vfprintf(stderr, s, ap);
+ va_end(ap);
+}
+
+
+#ifdef COMPUTE_MESSAGE_SIZE
+ /* Unused code to find the size of a message */
+
+ /* Compute size */
+ size = SynthControl_effectiveStringLength(messageName);
+
+ for (j = 0; j < numArgs; j++) {
+ switch (args[j].type) {
+ case INT_osc: case FLOAT_osc:
+ size += 4;
+ break;
+
+ case STRING_osc:
+ size += SynthControl_effectiveStringLength(args[j].datum.s);
+ break;
+
+ default:
+ fatal_error("Unrecognized token type ( not exiting)");
+ // exit(4);
+ }
+ }
+
+ if (!SynthControl_willMessageFit(buf, size)) {
+ send_complain("Message \"%s\" won't fit in buffer: dropping.", messageName);
+ return;
+ }
+#endif
diff --git a/README.txt b/README.txt
new file mode 100644
index 0000000..4a0dc8c
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,81 @@
+OSC, OpenSoundControl for pd
+============================
+OSC: http://cnmat.cnmat.berkeley.edu/OSC
+pd: http://lena.ucsd.edu/~msp/
+
+ok, merged the windows and linux trees.
+for linux do the usual makes etc, for window either use extra/OSC.dll,
+.dsw and .dsp files are also included.
+
+
+files:
+
+OSC/ contains the code for OSC pd objects (send,dump,route)
+README.txt this file
+doc/ pd help files
+extra/ OSC.dll, the windows binary
+libOSC/ CNMAT's OSC library
+send+dump/ CNMAT's OSC commandline utils
+ http://cnmat.cnmat.berkeley.edu/OpenSoundControl/
+
+
+log:
+
+ 20020417: 0.16-2: more changes by raf + jdl (send with no argument fix, send / fix,
+ ...)
+
+ 20020416: added bundle stuff to sendOSC
+
+ 200204: 0.15b1: windowified version and implied linux enhancements
+ by raf@interaccess.com
+ for now get it at http://207.208.254.239/pd/win32_osc_02.zip
+ most importantly: enhanced connect->disconnect-connect behaviour
+ (the win modifications to libOSC are still missing in _this_
+ package but coming ..)
+
+
+ 200203: 0-0.1b1: all the rest
+ ost_at_test.at + i22_at_test.at, 2000-2002
+ modified to compile as pd externel
+
+
+
+
+INSTALL:
+ (linux)
+
+tar zxvf OSCx.tgz
+cd OSCx
+cat README
+cd libOSC && make
+cd ../OSC && "adjust makefile" && make OSC && make install
+cd ../..
+pd -lib OSC OSCx/doc/OSC-help.pd
+
+ PITFALLS:
+make sure you compile libOSC before OSC objects
+maybe adjust include path so pd include files will be found
+
+
+ (windo$)
+
+unzip and put .dll file in a pd-searched folder.
+
+
+TYPETAGS:
+supported and on by default. can be swtiched off with the "typetags 0"
+message and on with 1.
+
+
+TODO
+====
+-timetags: output timetag when receiving a bundle for scheduling
+-TCP mode
+-address space integration with pd patch/subpatch/receive hierarchy ?
+
+see also TODO.txt in OSC/
+
+--
+jdl at xdv.org, http://barely.a.live.fm/pd/OSC
+windows version:
+raf at interaccess.com, http://207.208.254.239/pd/win32_osc_02.zip
diff --git a/doc/OSC-help.pd b/doc/OSC-help.pd
new file mode 100644
index 0000000..b3b7a9a
--- /dev/null
+++ b/doc/OSC-help.pd
@@ -0,0 +1,10 @@
+#N canvas 608 335 423 300 10;
+#X obj 21 149 sendOSC-help;
+#X obj 21 174 dumpOSC-help;
+#X obj 21 200 OSCroute-help;
+#X obj 17 43 OSC;
+#X msg 17 19 version;
+#X text 15 79 1 click sendOSC-help 2 click connect button 3 randomly
+click the 3 available messages 4 watch console;
+#X text 102 19 version 0.16;
+#X connect 4 0 3 0;
diff --git a/doc/OSCroute-help.pd b/doc/OSCroute-help.pd
new file mode 100644
index 0000000..3d9dd2a
--- /dev/null
+++ b/doc/OSCroute-help.pd
@@ -0,0 +1,26 @@
+#N canvas 112 247 446 321 10;
+#X msg 20 72 version;
+#X obj 86 72 r rcvOSC;
+#X obj 86 109 OSCroute /test /ix /yps;
+#X obj 161 143 print ix;
+#X obj 242 142 print yps;
+#X obj 85 183 OSCroute /bla /bli /blo;
+#X obj 85 212 unpack f f f;
+#X floatatom 85 239 4 0 0;
+#X floatatom 124 239 4 0 0;
+#X floatatom 164 239 4 0 0;
+#X text 20 11 OSCroute works pretty much like route but outputs remainder
+of routing tag after match.;
+#X obj 68 143 print test;
+#X connect 0 0 2 0;
+#X connect 1 0 2 0;
+#X connect 2 0 5 0;
+#X connect 2 0 11 0;
+#X connect 2 1 3 0;
+#X connect 2 1 5 0;
+#X connect 2 2 4 0;
+#X connect 2 2 5 0;
+#X connect 5 0 6 0;
+#X connect 6 0 7 0;
+#X connect 6 1 8 0;
+#X connect 6 2 9 0;
diff --git a/doc/dumpOSC-help.pd b/doc/dumpOSC-help.pd
new file mode 100644
index 0000000..ab769ef
--- /dev/null
+++ b/doc/dumpOSC-help.pd
@@ -0,0 +1,7 @@
+#N canvas 485 432 461 199 12;
+#X obj 17 105 print rcvOSC;
+#X obj 17 53 dumpOSC 9999;
+#X obj 45 78 s rcvOSC;
+#X text 15 7 dumpOSC listens on specified port / UDP \, outputs everything received on its only outlet. seems to be pretty stable.;
+#X connect 1 0 0 0;
+#X connect 1 0 2 0;
diff --git a/doc/sendOSC-help.pd b/doc/sendOSC-help.pd
new file mode 100644
index 0000000..dec1d76
--- /dev/null
+++ b/doc/sendOSC-help.pd
@@ -0,0 +1,57 @@
+#N canvas 496 472 848 467 10;
+#X obj 59 396 sendOSC;
+#X floatatom 59 423 5 0 0;
+#X msg 44 119 disconnect;
+#X msg 79 163 send /test/bla 1 2 3;
+#X msg 26 93 connect localhost 9999;
+#X msg 91 187 send /ix/bli 4 fuenf 6;
+#X msg 103 211 send /yps/blo 7.8 9.1 zehnkommaelf;
+#X text 8 142 ========================================;
+#X msg 274 92 connect localhost 10001;
+#X msg 149 301 typetags 1;
+#X msg 144 333 typetags 0;
+#X text 475 112 typetags;
+#X text 475 129 sendOSC now by default uses;
+#X text 477 145 typetags.;
+#X text 477 166 dumOSC on the other hand;
+#X text 477 186 should be able to interpret;
+#X text 478 208 this.;
+#X text 474 93 new (or again):;
+#X msg 423 294 [;
+#X msg 423 321 ];
+#X msg 256 249 send /bla 1 2 3 \, send /bli 3 4 5 \, send /blo 4 5
+6;
+#X text 462 312 when last bundle is closed the buffer is sent.;
+#X text 463 333 so: first "[" \, then add messages with send /bla;
+#X text 466 351 open nested nudle etc \, close with "]";
+#X floatatom 113 425 5 0 0;
+#X text 162 428 bundleDepth;
+#X text 24 11 sendOSC: send OSC formatted packet to network. at the
+moment over UDP only is supported.;
+#X text 28 38 supported int \, flot + string.;
+#X text 462 291 open / close bundles here.;
+#X text 465 372 watch the bundleDepth index change while you do this.
+;
+#X text 231 299 switch usage of typetags;
+#X text 232 316 on/off.;
+#X text 231 332 default: on;
+#X text 465 392 MAX_BUNDLE_NESTING: 32;
+#X msg 315 154 send;
+#X msg 315 179 send /;
+#X msg 368 156 send /bang;
+#X connect 0 0 1 0;
+#X connect 0 1 24 0;
+#X connect 2 0 0 0;
+#X connect 3 0 0 0;
+#X connect 4 0 0 0;
+#X connect 5 0 0 0;
+#X connect 6 0 0 0;
+#X connect 8 0 0 0;
+#X connect 9 0 0 0;
+#X connect 10 0 0 0;
+#X connect 18 0 0 0;
+#X connect 19 0 0 0;
+#X connect 20 0 0 0;
+#X connect 34 0 0 0;
+#X connect 35 0 0 0;
+#X connect 36 0 0 0;
diff --git a/extra/OSC.dll b/extra/OSC.dll
new file mode 100644
index 0000000..2cb0455
--- /dev/null
+++ b/extra/OSC.dll
Binary files differ
diff --git a/libOSC/LIBOSC.001 b/libOSC/LIBOSC.001
new file mode 100644
index 0000000..d1b40cc
--- /dev/null
+++ b/libOSC/LIBOSC.001
@@ -0,0 +1,94 @@
+# Microsoft Developer Studio Project File - Name="LIBOSC" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 5.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=LIBOSC - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "LIBOSC.MAK".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "LIBOSC.MAK" CFG="LIBOSC - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "LIBOSC - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "LIBOSC - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE
+
+# Begin Project
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+
+!IF "$(CFG)" == "LIBOSC - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ELSEIF "$(CFG)" == "LIBOSC - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ENDIF
+
+# Begin Target
+
+# Name "LIBOSC - Win32 Release"
+# Name "LIBOSC - Win32 Debug"
+# Begin Source File
+
+SOURCE=".\OSC-client.c"
+# End Source File
+# Begin Source File
+
+SOURCE=".\OSC-client.h"
+# End Source File
+# Begin Source File
+
+SOURCE=".\OSC-timetag.c"
+# End Source File
+# Begin Source File
+
+SOURCE=".\OSC-timetag.h"
+# End Source File
+# End Target
+# End Project
diff --git a/libOSC/LIBOSC.002 b/libOSC/LIBOSC.002
new file mode 100644
index 0000000..d2c0fe8
--- /dev/null
+++ b/libOSC/LIBOSC.002
@@ -0,0 +1,100 @@
+# Microsoft Developer Studio Project File - Name="LIBOSC" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 5.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=LIBOSC - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "LIBOSC.MAK".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "LIBOSC.MAK" CFG="LIBOSC - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "LIBOSC - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "LIBOSC - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE
+
+# Begin Project
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+
+!IF "$(CFG)" == "LIBOSC - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+RSC=rc.exe
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /I "../../pd/src" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"..\..\..\pd\lib\LIBOSC.lib"
+
+!ELSEIF "$(CFG)" == "LIBOSC - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Target_Dir ""
+RSC=rc.exe
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /Z7 /Od /I "../../pd/src" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ENDIF
+
+# Begin Target
+
+# Name "LIBOSC - Win32 Release"
+# Name "LIBOSC - Win32 Debug"
+# Begin Source File
+
+SOURCE=".\OSC-client.c"
+# End Source File
+# Begin Source File
+
+SOURCE=".\OSC-client.h"
+# End Source File
+# Begin Source File
+
+SOURCE=".\OSC-timetag.c"
+# End Source File
+# Begin Source File
+
+SOURCE=".\OSC-timetag.h"
+# End Source File
+# End Target
+# End Project
diff --git a/libOSC/LIBOSC.DSP b/libOSC/LIBOSC.DSP
new file mode 100644
index 0000000..99e661a
--- /dev/null
+++ b/libOSC/LIBOSC.DSP
@@ -0,0 +1,100 @@
+# Microsoft Developer Studio Project File - Name="LIBOSC" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=LIBOSC - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "LIBOSC.MAK".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "LIBOSC.MAK" CFG="LIBOSC - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "LIBOSC - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "LIBOSC - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "LIBOSC - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /I "../../pd/src" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"..\..\..\pd\lib\LIBOSC.lib"
+
+!ELSEIF "$(CFG)" == "LIBOSC - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /Z7 /Od /I "../../pd/src" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ENDIF
+
+# Begin Target
+
+# Name "LIBOSC - Win32 Release"
+# Name "LIBOSC - Win32 Debug"
+# Begin Source File
+
+SOURCE=".\OSC-client.c"
+# End Source File
+# Begin Source File
+
+SOURCE=".\OSC-client.h"
+# End Source File
+# Begin Source File
+
+SOURCE=".\OSC-timetag.c"
+# End Source File
+# Begin Source File
+
+SOURCE=".\OSC-timetag.h"
+# End Source File
+# End Target
+# End Project
diff --git a/libOSC/LIBOSC.DSW b/libOSC/LIBOSC.DSW
new file mode 100644
index 0000000..ef47907
--- /dev/null
+++ b/libOSC/LIBOSC.DSW
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "LIBOSC"=.\LIBOSC.DSP - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/libOSC/LIBOSC.PLG b/libOSC/LIBOSC.PLG
new file mode 100644
index 0000000..d011835
--- /dev/null
+++ b/libOSC/LIBOSC.PLG
@@ -0,0 +1,29 @@
+<html>
+<body>
+<pre>
+<h1>Build Log</h1>
+<h3>
+--------------------Configuration: LIBOSC - Win32 Release--------------------
+</h3>
+<h3>Command Lines</h3>
+Creating temporary file "C:\DOCUME~1\gustav\LOCALS~1\Temp\RSPB.tmp" with contents
+[
+/nologo /ML /W3 /GX /O2 /I "../../pd/src" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /Fp"Release/LIBOSC.pch" /YX /Fo"Release/" /Fd"Release/" /FD /c
+"D:\pd\OSC\LIBOSC\OSC-client.c"
+"D:\pd\OSC\LIBOSC\OSC-timetag.c"
+]
+Creating command line "cl.exe @C:\DOCUME~1\gustav\LOCALS~1\Temp\RSPB.tmp"
+Creating command line "link.exe -lib /nologo /out:"..\..\..\pd\lib\LIBOSC.lib" ".\Release\OSC-client.obj" ".\Release\OSC-timetag.obj" "
+<h3>Output Window</h3>
+Compiling...
+OSC-client.c
+OSC-timetag.c
+Creating library...
+
+
+
+<h3>Results</h3>
+LIBOSC.lib - 0 error(s), 0 warning(s)
+</pre>
+</body>
+</html>
diff --git a/libOSC/Makefile b/libOSC/Makefile
new file mode 100644
index 0000000..6261b37
--- /dev/null
+++ b/libOSC/Makefile
@@ -0,0 +1,21 @@
+CFLAGS= -O2
+LIB=libOSC.a
+
+LIBOBJS= ${LIB}(OSC-client.o) ${LIB}(OSC-timetag.o)
+
+all: ${LIBOBJS}
+
+.c.a:
+ ${CC} -c ${CFLAGS} $<
+ ${AR} ${ARFLAGS} $@ $*.o
+ rm -f $*.o
+
+test_OSC: test_OSC.o ${LIB}
+ cc -o test_OSC test_OSC.o ${LIB}
+
+test_OSC_timeTag: test_OSC_timeTag.o OSC-timetag.o
+ cc -o test_OSC_timeTag test_OSC_timeTag.o OSC-timetag.o
+
+
+clean:
+ rm -f ${LIB} *.o
diff --git a/libOSC/OSC-client.c b/libOSC/OSC-client.c
new file mode 100644
index 0000000..27b07d0
--- /dev/null
+++ b/libOSC/OSC-client.c
@@ -0,0 +1,473 @@
+/*
+Copyright (c) 1996. The Regents of the University of California (Regents).
+All Rights Reserved.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for educational, research, and not-for-profit purposes, without
+fee and without a signed licensing agreement, is hereby granted, provided that
+the above copyright notice, this paragraph and the following two paragraphs
+appear in all copies, modifications, and distributions. Contact The Office of
+Technology Licensing, UC Berkeley, 2150 Shattuck Avenue, Suite 510, Berkeley,
+CA 94720-1620, (510) 643-7201, for commercial licensing opportunities.
+
+Written by Matt Wright, The Center for New Music and Audio Technologies,
+University of California, Berkeley.
+
+ IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
+ ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING
+ DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS".
+ REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
+ ENHANCEMENTS, OR MODIFICATIONS.
+*/
+
+
+/*
+ Author: Matt Wright
+ Version 2.2: Calls htonl in the right places 20000620
+ Version 2.3: Gets typed messages right.
+ */
+
+/*
+ pd
+ -------------
+
+ raf@interaccess.com:
+ rev. for Win32 build (verified under Win-2ooo) 11-April-2002
+
+*/
+
+/* Here are the possible values of the state field: */
+
+#define EMPTY 0 /* Nothing written to packet yet */
+#define ONE_MSG_ARGS 1 /* Packet has a single message; gathering arguments */
+#define NEED_COUNT 2 /* Just opened a bundle; must write message name or
+ open another bundle */
+#define GET_ARGS 3 /* Getting arguments to a message. If we see a message
+ name or a bundle open/close then the current message
+ will end. */
+#define DONE 4 /* All open bundles have been closed, so can't write
+ anything else */
+
+#ifdef WIN32
+ #include <winsock2.h>
+ #include <io.h>
+ #include <stdio.h>
+ #include <errno.h>
+ #include <fcntl.h>
+ #include <sys/types.h>
+ #include <sys/stat.h>
+#endif
+
+
+#include "OSC-client.h"
+
+char *OSC_errorMessage;
+
+#ifndef WIN32
+ static int strlen(char *s);
+#endif
+static int OSC_padString(char *dest, char *str);
+static int OSC_padStringWithAnExtraStupidComma(char *dest, char *str);
+static int OSC_WritePadding(char *dest, int i);
+static int CheckTypeTag(OSCbuf *buf, char expectedType);
+
+void OSC_initBuffer(OSCbuf *buf, int size, char *byteArray) {
+ buf->buffer = byteArray;
+ buf->size = size;
+ OSC_resetBuffer(buf);
+}
+
+void OSC_resetBuffer(OSCbuf *buf) {
+ buf->bufptr = buf->buffer;
+ buf->state = EMPTY;
+ buf->bundleDepth = 0;
+ buf->prevCounts[0] = 0;
+ buf->gettingFirstUntypedArg = 0;
+ buf->typeStringPtr = 0;
+}
+
+int OSC_isBufferEmpty(OSCbuf *buf) {
+ return buf->bufptr == buf->buffer;
+}
+
+int OSC_freeSpaceInBuffer(OSCbuf *buf) {
+ return buf->size - (buf->bufptr - buf->buffer);
+}
+
+int OSC_isBufferDone(OSCbuf *buf) {
+ return (buf->state == DONE || buf->state == ONE_MSG_ARGS);
+}
+
+char *OSC_getPacket(OSCbuf *buf) {
+#ifdef ERROR_CHECK_GETPACKET
+ if (buf->state == DONE || buf->state == ONE_MSG_ARGS) {
+ return buf->buffer;
+ } else {
+ OSC_errorMessage = "Packet has unterminated bundles";
+ return 0;
+ }
+#else
+ return buf->buffer;
+#endif
+}
+
+int OSC_packetSize(OSCbuf *buf) {
+#ifdef ERROR_CHECK_PACKETSIZE
+ if (buf->state == DONE || buf->state == ONE_MSG_ARGS) {
+ return (buf->bufptr - buf->buffer);
+ } else {
+ OSC_errorMessage = "Packet has unterminated bundles";
+ return 0;
+ }
+#else
+ return (buf->bufptr - buf->buffer);
+#endif
+}
+
+#define CheckOverflow(buf, bytesNeeded) { \
+ if ((bytesNeeded) > OSC_freeSpaceInBuffer(buf)) { \
+ OSC_errorMessage = "buffer overflow"; \
+ return 1; \
+ } \
+}
+
+static void PatchMessageSize(OSCbuf *buf) {
+ int4byte size;
+ size = buf->bufptr - ((char *) buf->thisMsgSize) - 4;
+ *(buf->thisMsgSize) = htonl(size);
+}
+
+int OSC_openBundle(OSCbuf *buf, OSCTimeTag tt) {
+ if (buf->state == ONE_MSG_ARGS) {
+ OSC_errorMessage = "Can't open a bundle in a one-message packet";
+ return 3;
+ }
+
+ if (buf->state == DONE) {
+ OSC_errorMessage = "This packet is finished; can't open a new bundle";
+ return 4;
+ }
+
+ if (++(buf->bundleDepth) >= MAX_BUNDLE_NESTING) {
+ OSC_errorMessage = "Bundles nested too deeply; change MAX_BUNDLE_NESTING in OpenSoundControl.h";
+ return 2;
+ }
+
+ if (CheckTypeTag(buf, '\0')) return 9;
+
+ if (buf->state == GET_ARGS) {
+ PatchMessageSize(buf);
+ }
+
+ if (buf->state == EMPTY) {
+ /* Need 16 bytes for "#bundle" and time tag */
+ CheckOverflow(buf, 16);
+ } else {
+ /* This bundle is inside another bundle, so we need to leave
+ a blank size count for the size of this current bundle. */
+ CheckOverflow(buf, 20);
+ *((int4byte *)buf->bufptr) = 0xaaaaaaaa;
+ buf->prevCounts[buf->bundleDepth] = (int4byte *)buf->bufptr;
+
+ buf->bufptr += 4;
+ }
+
+ buf->bufptr += OSC_padString(buf->bufptr, "#bundle");
+
+
+ *((OSCTimeTag *) buf->bufptr) = tt;
+
+ if (htonl(1) != 1) {
+ /* Byte swap the 8-byte integer time tag */
+ int4byte *intp = (int4byte *)buf->bufptr;
+ intp[0] = htonl(intp[0]);
+ intp[1] = htonl(intp[1]);
+
+#ifdef HAS8BYTEINT
+ { /* tt is a 64-bit int so we have to swap the two 32-bit words.
+ (Otherwise tt is a struct of two 32-bit words, and even though
+ each word was wrong-endian, they were in the right order
+ in the struct.) */
+ int4byte temp = intp[0];
+ intp[0] = intp[1];
+ intp[1] = temp;
+ }
+#endif
+ }
+
+ buf->bufptr += sizeof(OSCTimeTag);
+
+ buf->state = NEED_COUNT;
+
+ buf->gettingFirstUntypedArg = 0;
+ buf->typeStringPtr = 0;
+ return 0;
+}
+
+
+int OSC_closeBundle(OSCbuf *buf) {
+ if (buf->bundleDepth == 0) {
+ /* This handles EMPTY, ONE_MSG, ARGS, and DONE */
+ OSC_errorMessage = "Can't close bundle; no bundle is open!";
+ return 5;
+ }
+
+ if (CheckTypeTag(buf, '\0')) return 9;
+
+ if (buf->state == GET_ARGS) {
+ PatchMessageSize(buf);
+ }
+
+ if (buf->bundleDepth == 1) {
+ /* Closing the last bundle: No bundle size to patch */
+ buf->state = DONE;
+ } else {
+ /* Closing a sub-bundle: patch bundle size */
+ int size = buf->bufptr - ((char *) buf->prevCounts[buf->bundleDepth]) - 4;
+ *(buf->prevCounts[buf->bundleDepth]) = htonl(size);
+ buf->state = NEED_COUNT;
+ }
+
+ --buf->bundleDepth;
+ buf->gettingFirstUntypedArg = 0;
+ buf->typeStringPtr = 0;
+ return 0;
+}
+
+
+int OSC_closeAllBundles(OSCbuf *buf) {
+ if (buf->bundleDepth == 0) {
+ /* This handles EMPTY, ONE_MSG, ARGS, and DONE */
+ OSC_errorMessage = "Can't close all bundles; no bundle is open!";
+ return 6;
+ }
+
+ if (CheckTypeTag(buf, '\0')) return 9;
+
+ while (buf->bundleDepth > 0) {
+ OSC_closeBundle(buf);
+ }
+ buf->typeStringPtr = 0;
+ return 0;
+}
+
+int OSC_writeAddress(OSCbuf *buf, char *name) {
+ int4byte paddedLength;
+
+ if (buf->state == ONE_MSG_ARGS) {
+ OSC_errorMessage = "This packet is not a bundle, so you can't write another address";
+ return 7;
+ }
+
+ if (buf->state == DONE) {
+ OSC_errorMessage = "This packet is finished; can't write another address";
+ return 8;
+ }
+
+ if (CheckTypeTag(buf, '\0')) return 9;
+
+ paddedLength = OSC_effectiveStringLength(name);
+
+ if (buf->state == EMPTY) {
+ /* This will be a one-message packet, so no sizes to worry about */
+ CheckOverflow(buf, paddedLength);
+ buf->state = ONE_MSG_ARGS;
+ } else {
+ /* GET_ARGS or NEED_COUNT */
+ CheckOverflow(buf, 4+paddedLength);
+ if (buf->state == GET_ARGS) {
+ /* Close the old message */
+ PatchMessageSize(buf);
+ }
+ buf->thisMsgSize = (int4byte *)buf->bufptr;
+ *(buf->thisMsgSize) = 0xbbbbbbbb;
+ buf->bufptr += 4;
+ buf->state = GET_ARGS;
+ }
+
+ /* Now write the name */
+ buf->bufptr += OSC_padString(buf->bufptr, name);
+ buf->typeStringPtr = 0;
+ buf->gettingFirstUntypedArg = 1;
+
+ return 0;
+}
+
+int OSC_writeAddressAndTypes(OSCbuf *buf, char *name, char *types) {
+ int result;
+ int4byte paddedLength;
+
+ if (CheckTypeTag(buf, '\0')) return 9;
+
+ result = OSC_writeAddress(buf, name);
+
+ if (result) return result;
+
+ paddedLength = OSC_effectiveStringLength(types);
+
+ CheckOverflow(buf, paddedLength);
+
+ buf->typeStringPtr = buf->bufptr + 1; /* skip comma */
+ buf->bufptr += OSC_padString(buf->bufptr, types);
+
+ buf->gettingFirstUntypedArg = 0;
+ return 0;
+}
+
+static int CheckTypeTag(OSCbuf *buf, char expectedType) {
+ if (buf->typeStringPtr) {
+ if (*(buf->typeStringPtr) != expectedType) {
+ if (expectedType == '\0') {
+ OSC_errorMessage =
+ "According to the type tag I expected more arguments.";
+ } else if (*(buf->typeStringPtr) == '\0') {
+ OSC_errorMessage =
+ "According to the type tag I didn't expect any more arguments.";
+ } else {
+ OSC_errorMessage =
+ "According to the type tag I expected an argument of a different type.";
+ printf("* Expected %c, string now %s\n", expectedType, buf->typeStringPtr);
+ }
+ return 9;
+ }
+ ++(buf->typeStringPtr);
+ }
+ return 0;
+}
+
+
+int OSC_writeFloatArg(OSCbuf *buf, float arg) {
+ int4byte *intp;
+ //int result;
+
+ CheckOverflow(buf, 4);
+
+ if (CheckTypeTag(buf, 'f')) return 9;
+
+ /* Pretend arg is a long int so we can use htonl() */
+ intp = ((int4byte *) &arg);
+ *((int4byte *) buf->bufptr) = htonl(*intp);
+
+ buf->bufptr += 4;
+
+ buf->gettingFirstUntypedArg = 0;
+ return 0;
+}
+
+
+
+int OSC_writeFloatArgs(OSCbuf *buf, int numFloats, float *args) {
+ int i;
+ int4byte *intp;
+
+ CheckOverflow(buf, 4 * numFloats);
+
+ /* Pretend args are long ints so we can use htonl() */
+ intp = ((int4byte *) args);
+
+ for (i = 0; i < numFloats; i++) {
+ if (CheckTypeTag(buf, 'f')) return 9;
+ *((int4byte *) buf->bufptr) = htonl(intp[i]);
+ buf->bufptr += 4;
+ }
+
+ buf->gettingFirstUntypedArg = 0;
+ return 0;
+}
+
+int OSC_writeIntArg(OSCbuf *buf, int4byte arg) {
+ CheckOverflow(buf, 4);
+ if (CheckTypeTag(buf, 'i')) return 9;
+
+ *((int4byte *) buf->bufptr) = htonl(arg);
+ buf->bufptr += 4;
+
+ buf->gettingFirstUntypedArg = 0;
+ return 0;
+}
+
+int OSC_writeStringArg(OSCbuf *buf, char *arg) {
+ int len;
+
+ if (CheckTypeTag(buf, 's')) return 9;
+
+ len = OSC_effectiveStringLength(arg);
+
+ if (buf->gettingFirstUntypedArg && arg[0] == ',') {
+ /* This un-type-tagged message starts with a string
+ that starts with a comma, so we have to escape it
+ (with a double comma) so it won't look like a type
+ tag string. */
+
+ CheckOverflow(buf, len+4); /* Too conservative */
+ buf->bufptr +=
+ OSC_padStringWithAnExtraStupidComma(buf->bufptr, arg);
+
+ } else {
+ CheckOverflow(buf, len);
+ buf->bufptr += OSC_padString(buf->bufptr, arg);
+ }
+
+ buf->gettingFirstUntypedArg = 0;
+ return 0;
+
+}
+
+/* String utilities */
+
+#ifndef WIN32
+static int strlen(char *s) {
+ int i;
+ for (i=0; s[i] != '\0'; i++) /* Do nothing */ ;
+ return i;
+}
+#endif
+
+#define STRING_ALIGN_PAD 4
+int OSC_effectiveStringLength(char *string) {
+ int len = strlen(string) + 1; /* We need space for the null char. */
+
+ /* Round up len to next multiple of STRING_ALIGN_PAD to account for alignment padding */
+ if ((len % STRING_ALIGN_PAD) != 0) {
+ len += STRING_ALIGN_PAD - (len % STRING_ALIGN_PAD);
+ }
+ return len;
+}
+
+static int OSC_padString(char *dest, char *str) {
+ int i;
+
+ for (i = 0; str[i] != '\0'; i++) {
+ dest[i] = str[i];
+ }
+
+ return OSC_WritePadding(dest, i);
+}
+
+static int OSC_padStringWithAnExtraStupidComma(char *dest, char *str) {
+ int i;
+
+ dest[0] = ',';
+ for (i = 0; str[i] != '\0'; i++) {
+ dest[i+1] = str[i];
+ }
+
+ return OSC_WritePadding(dest, i+1);
+}
+
+static int OSC_WritePadding(char *dest, int i) {
+ dest[i] = '\0';
+ i++;
+
+ for (; (i % STRING_ALIGN_PAD) != 0; i++) {
+ dest[i] = '\0';
+ }
+
+ return i;
+}
diff --git a/libOSC/OSC-client.c.pre-htonl b/libOSC/OSC-client.c.pre-htonl
new file mode 100644
index 0000000..6aebfe2
--- /dev/null
+++ b/libOSC/OSC-client.c.pre-htonl
@@ -0,0 +1,303 @@
+/*
+Copyright (c) 1996. The Regents of the University of California (Regents).
+All Rights Reserved.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for educational, research, and not-for-profit purposes, without
+fee and without a signed licensing agreement, is hereby granted, provided that
+the above copyright notice, this paragraph and the following two paragraphs
+appear in all copies, modifications, and distributions. Contact The Office of
+Technology Licensing, UC Berkeley, 2150 Shattuck Avenue, Suite 510, Berkeley,
+CA 94720-1620, (510) 643-7201, for commercial licensing opportunities.
+
+Written by Matt Wright, The Center for New Music and Audio Technologies,
+University of California, Berkeley.
+
+ IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
+ ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING
+ DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS".
+ REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
+ ENHANCEMENTS, OR MODIFICATIONS.
+*/
+
+
+/*
+ Author: Matt Wright
+ Version 2.1
+ */
+
+
+/* Here are the possible values of the state field: */
+
+#define EMPTY 0 /* Nothing written to packet yet */
+#define ONE_MSG_ARGS 1 /* Packet has a single message; gathering arguments */
+#define NEED_COUNT 2 /* Just opened a bundle; must write message name or
+ open another bundle */
+#define GET_ARGS 3 /* Getting arguments to a message. If we see a message
+ name or a bundle open/close then the current message
+ will end. */
+#define DONE 4 /* All open bundles have been closed, so can't write
+ anything else */
+
+#include "OSC-client.h"
+
+char *OSC_errorMessage;
+
+
+static int strlen(char *s);
+static int OSC_padString(char *dest, char *str);
+
+void OSC_initBuffer(OSCbuf *buf, int size, char *byteArray) {
+ buf->buffer = byteArray;
+ buf->size = size;
+ OSC_resetBuffer(buf);
+}
+
+void OSC_resetBuffer(OSCbuf *buf) {
+ buf->bufptr = buf->buffer;
+ buf->state = EMPTY;
+ buf->bundleDepth = 0;
+ buf->prevCounts[0] = 0;
+}
+
+int OSC_isBufferEmpty(OSCbuf *buf) {
+ return buf->bufptr == buf->buffer;
+}
+
+int OSC_freeSpaceInBuffer(OSCbuf *buf) {
+ return buf->size - (buf->bufptr - buf->buffer);
+}
+
+int OSC_isBufferDone(OSCbuf *buf) {
+ return (buf->state == DONE || buf->state == ONE_MSG_ARGS);
+}
+
+char *OSC_getPacket(OSCbuf *buf) {
+#ifdef ERROR_CHECK_GETPACKET
+ if (buf->state == DONE || buf->state == ONE_MSG_ARGS) {
+ return buf->buffer;
+ } else {
+ OSC_errorMessage = "Packet has unterminated bundles";
+ return 0;
+ }
+#else
+ return buf->buffer;
+#endif
+}
+
+int OSC_packetSize(OSCbuf *buf) {
+#ifdef ERROR_CHECK_PACKETSIZE
+ if (buf->state == DONE || buf->state == ONE_MSG_ARGS) {
+ return (buf->bufptr - buf->buffer);
+ } else {
+ OSC_errorMessage = "Packet has unterminated bundles";
+ return 0;
+ }
+#else
+ return (buf->bufptr - buf->buffer);
+#endif
+}
+
+#define CheckOverflow(buf, bytesNeeded) { \
+ if ((bytesNeeded) > OSC_freeSpaceInBuffer(buf)) { \
+ OSC_errorMessage = "buffer overflow"; \
+ return 1; \
+ } \
+}
+
+static void PatchMessageSize(OSCbuf *buf) {
+ int4byte size;
+ size = buf->bufptr - ((char *) buf->thisMsgSize) - 4;
+ *(buf->thisMsgSize) = size;
+}
+
+int OSC_openBundle(OSCbuf *buf, OSCTimeTag tt) {
+ if (buf->state == ONE_MSG_ARGS) {
+ OSC_errorMessage = "Can't open a bundle in a one-message packet";
+ return 3;
+ }
+
+ if (buf->state == DONE) {
+ OSC_errorMessage = "This packet is finished; can't open a new bundle";
+ return 4;
+ }
+
+ if (++(buf->bundleDepth) >= MAX_BUNDLE_NESTING) {
+ OSC_errorMessage = "Bundles nested too deeply; change MAX_BUNDLE_NESTING in OpenSoundControl.h";
+ return 2;
+ }
+
+ if (buf->state == GET_ARGS) {
+ PatchMessageSize(buf);
+ }
+
+ if (buf->state == EMPTY) {
+ /* Need 16 bytes for "#bundle" and time tag */
+ CheckOverflow(buf, 16);
+ } else {
+ /* This bundle is inside another bundle, so we need to leave
+ a blank size count for the size of this current bundle. */
+ CheckOverflow(buf, 20);
+ *((int4byte *)buf->bufptr) = 0xaaaaaaaa;
+ buf->prevCounts[buf->bundleDepth] = (int4byte *)buf->bufptr;
+
+ buf->bufptr += 4;
+ }
+
+ buf->bufptr += OSC_padString(buf->bufptr, "#bundle");
+ *((OSCTimeTag *) buf->bufptr) = tt;
+ buf->bufptr += sizeof(OSCTimeTag);
+
+ buf->state = NEED_COUNT;
+ return 0;
+}
+
+
+int OSC_closeBundle(OSCbuf *buf) {
+ if (buf->bundleDepth == 0) {
+ /* This handles EMPTY, ONE_MSG, ARGS, and DONE */
+ OSC_errorMessage = "Can't close bundle; no bundle is open!";
+ return 5;
+ }
+
+ if (buf->state == GET_ARGS) {
+ PatchMessageSize(buf);
+ }
+
+ if (buf->bundleDepth == 1) {
+ /* Closing the last bundle: No bundle size to patch */
+ buf->state = DONE;
+ } else {
+ /* Closing a sub-bundle: patch bundle size */
+ int size = buf->bufptr - ((char *) buf->prevCounts[buf->bundleDepth]) - 4;
+ *(buf->prevCounts[buf->bundleDepth]) = size;
+ buf->state = NEED_COUNT;
+ }
+
+ --buf->bundleDepth;
+ return 0;
+}
+
+
+int OSC_closeAllBundles(OSCbuf *buf) {
+ if (buf->bundleDepth == 0) {
+ /* This handles EMPTY, ONE_MSG, ARGS, and DONE */
+ OSC_errorMessage = "Can't close all bundles; no bundle is open!";
+ return 6;
+ }
+
+ while (buf->bundleDepth > 0) {
+ OSC_closeBundle(buf);
+ }
+ return 0;
+}
+
+int OSC_writeAddress(OSCbuf *buf, char *name) {
+ int4byte paddedLength;
+
+ if (buf->state == ONE_MSG_ARGS) {
+ OSC_errorMessage = "This packet is not a bundle, so you can't write another address";
+ return 7;
+ }
+
+ if (buf->state == DONE) {
+ OSC_errorMessage = "This packet is finished; can't write another address";
+ return 8;
+ }
+
+ paddedLength = OSC_effectiveStringLength(name);
+
+ if (buf->state == EMPTY) {
+ /* This will be a one-message packet, so no sizes to worry about */
+ CheckOverflow(buf, paddedLength);
+ buf->state = ONE_MSG_ARGS;
+ } else {
+ /* GET_ARGS or NEED_COUNT */
+ CheckOverflow(buf, 4+paddedLength);
+ if (buf->state == GET_ARGS) {
+ /* Close the old message */
+ PatchMessageSize(buf);
+ }
+ buf->thisMsgSize = (int4byte *)buf->bufptr;
+ *(buf->thisMsgSize) = 0xbbbbbbbb;
+ buf->bufptr += 4;
+ buf->state = GET_ARGS;
+ }
+
+ /* Now write the name */
+ buf->bufptr += OSC_padString(buf->bufptr, name);
+ return 0;
+}
+
+int OSC_writeFloatArg(OSCbuf *buf, float arg) {
+ CheckOverflow(buf, 4);
+ *((float *) buf->bufptr) = arg;
+ buf->bufptr += 4;
+ return 0;
+}
+
+int OSC_writeFloatArgs(OSCbuf *buf, int numFloats, float *args) {
+ int i;
+ CheckOverflow(buf, 4 * numFloats);
+ for (i = 0; i < numFloats; i++) {
+ *((float *) buf->bufptr) = args[i];
+ buf->bufptr += 4;
+ }
+ return 0;
+}
+
+int OSC_writeIntArg(OSCbuf *buf, int4byte arg) {
+ CheckOverflow(buf, 4);
+ *((int4byte *) buf->bufptr) = arg;
+ buf->bufptr += 4;
+ return 0;
+}
+
+int OSC_writeStringArg(OSCbuf *buf, char *arg) {
+ CheckOverflow(buf, OSC_effectiveStringLength(arg));
+ buf->bufptr += OSC_padString(buf->bufptr, arg);
+ return 0;
+}
+
+/* String utilities */
+
+static int strlen(char *s) {
+ int i;
+ for (i=0; s[i] != '\0'; i++) /* Do nothing */ ;
+ return i;
+}
+
+#define STRING_ALIGN_PAD 4
+int OSC_effectiveStringLength(char *string) {
+ int len = strlen(string) + 1; /* We need space for the null char. */
+
+ /* Round up len to next multiple of STRING_ALIGN_PAD to account for alignment padding */
+ if ((len % STRING_ALIGN_PAD) != 0) {
+ len += STRING_ALIGN_PAD - (len % STRING_ALIGN_PAD);
+ }
+ return len;
+}
+
+static int OSC_padString(char *dest, char *str) {
+ int i;
+
+ for (i = 0; str[i] != '\0'; i++) {
+ dest[i] = str[i];
+ }
+
+ dest[i] = '\0';
+ i++;
+
+ for (; (i % STRING_ALIGN_PAD) != 0; i++) {
+ dest[i] = '\0';
+ }
+
+ return i;
+}
+
diff --git a/libOSC/OSC-client.h b/libOSC/OSC-client.h
new file mode 100644
index 0000000..b1fd833
--- /dev/null
+++ b/libOSC/OSC-client.h
@@ -0,0 +1,181 @@
+/*
+Copyright (c) 1996,1997. The Regents of the University of California (Regents).
+All Rights Reserved.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for educational, research, and not-for-profit purposes, without
+fee and without a signed licensing agreement, is hereby granted, provided that
+the above copyright notice, this paragraph and the following two paragraphs
+appear in all copies, modifications, and distributions. Contact The Office of
+Technology Licensing, UC Berkeley, 2150 Shattuck Avenue, Suite 510, Berkeley,
+CA 94720-1620, (510) 643-7201, for commercial licensing opportunities.
+
+Written by Matt Wright, The Center for New Music and Audio Technologies,
+University of California, Berkeley.
+
+ IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
+ ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING
+ DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS".
+ REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
+ ENHANCEMENTS, OR MODIFICATIONS.
+*/
+
+/*
+
+ OSC-client.h: library for constructing OpenSoundControl messages.
+ Derived from SynthControl.h
+ Author: Matt Wright
+ Version 0.1: 6/13/97
+ Version 0.2: 7/21/2000: Support for type-tagged messages
+
+
+ General notes:
+
+ This library abstracts away the data format for the OpenSoundControl
+ protocol. Users of this library can construct OpenSoundControl packets
+ with a function call interface instead of knowing how to lay out the bits.
+
+ All issues of memory allocation are deferred to the user of this library.
+ There are two data structures that the user must allocate. The first
+ is the actual buffer that the message will be written into. This buffer
+ can be any size, but if it's too small there's a possibility that it
+ will become overfull. The other data structure is called an OSCbuf,
+ and it holds all the state used by the library as it's constructing
+ a buffer.
+
+ All procedures that have the possibility of an error condition return int,
+ with 0 indicating no error and nonzero indicating an error. The variable
+ OSC_errorMessage will be set to point to a string containing an error
+ message explaining what the problem is.
+
+*/
+
+
+#include "OSC-timetag.h"
+
+/* The int4byte type has to be a 4-byte integer. You may have to
+ change this to long or something else on your system. */
+#ifdef __MWERKS__
+ /* In Metrowerks you can set ints to be 2 or 4 bytes on 68K, but long is
+ always 4 bytes */
+ typedef long int4byte;
+#else
+ typedef int int4byte;
+#endif
+
+/* The maximum depth of bundles within bundles within bundles within...
+ This is the size of a static array. If you exceed this limit you'll
+ get an error message. */
+#define MAX_BUNDLE_NESTING 32
+
+
+/* Don't ever manipulate the data in the OSCbuf struct directly. (It's
+ declared here in the header file only so your program will be able to
+ declare variables of type OSCbuf and have the right amount of memory
+ be allocated.) */
+
+typedef struct OSCbuf_struct {
+ char *buffer; /* The buffer to hold the OSC packet */
+ int size; /* Size of the buffer */
+ char *bufptr; /* Current position as we fill the buffer */
+ int state; /* State of partially-constructed message */
+ int4byte *thisMsgSize; /* Pointer to count field before
+ currently-being-written message */
+ int4byte *prevCounts[MAX_BUNDLE_NESTING];
+ /* Pointers to count field before each currently
+ open bundle */
+ int bundleDepth; /* How many sub-sub-bundles are we in now? */
+ char *typeStringPtr; /* This pointer advances through the type
+ tag string as you add arguments. */
+ int gettingFirstUntypedArg; /* nonzero if this message doesn't have
+ a type tag and we're waiting for the 1st arg */
+} OSCbuf;
+
+
+
+/* Initialize the given OSCbuf. The user of this module must pass in the
+ block of memory that this OSCbuf will use for a buffer, and the number of
+ bytes in that block. (It's the user's job to allocate the memory because
+ you do it differently in different systems.) */
+void OSC_initBuffer(OSCbuf *buf, int size, char *byteArray);
+
+
+/* Reset the given OSCbuf. Do this after you send out the contents of
+ the buffer and want to start writing new data into it. */
+void OSC_resetBuffer(OSCbuf *buf);
+
+
+/* Is the buffer empty? (I.e., would it be stupid to send the buffer
+ contents to the synth?) */
+int OSC_isBufferEmpty(OSCbuf *buf);
+
+
+/* How much space is left in the buffer? */
+int OSC_freeSpaceInBuffer(OSCbuf *buf);
+
+/* Does the buffer contain a valid OSC packet? (Returns nonzero if yes.) */
+int OSC_isBufferDone(OSCbuf *buf);
+
+/* When you're ready to send out the buffer (i.e., when OSC_isBufferDone()
+ returns true), call these two procedures to get the OSC packet that's been
+ assembled and its size in bytes. (And then call OSC_resetBuffer() if you
+ want to re-use this OSCbuf for the next packet.) */
+char *OSC_getPacket(OSCbuf *buf);
+int OSC_packetSize(OSCbuf *buf);
+
+
+
+/* Here's the basic model for building up OSC messages in an OSCbuf:
+
+ - Make sure the OSCbuf has been initialized with OSC_initBuffer().
+
+ - To open a bundle, call OSC_openBundle(). You can then write
+ messages or open new bundles within the bundle you opened.
+ Call OSC_closeBundle() to close the bundle. Note that a packet
+ does not have to have a bundle; it can instead consist of just a
+ single message.
+
+
+ - For each message you want to send:
+
+ - Call OSC_writeAddress() with the name of your message. (In
+ addition to writing your message name into the buffer, this
+ procedure will also leave space for the size count of this message.)
+
+ - Alternately, call OSC_writeAddressAndTypes() with the name of
+ your message and with a type string listing the types of all the
+ arguments you will be putting in this message.
+
+ - Now write each of the arguments into the buffer, by calling one of:
+ OSC_writeFloatArg()
+ OSC_writeFloatArgs()
+ OSC_writeIntArg()
+ OSC_writeStringArg()
+
+ - Now your message is complete; you can send out the buffer or you can
+ add another message to it.
+*/
+
+int OSC_openBundle(OSCbuf *buf, OSCTimeTag tt);
+int OSC_closeBundle(OSCbuf *buf);
+int OSC_closeAllBundles(OSCbuf *buf);
+
+int OSC_writeAddress(OSCbuf *buf, char *name);
+int OSC_writeAddressAndTypes(OSCbuf *buf, char *name, char *types);
+int OSC_writeFloatArg(OSCbuf *buf, float arg);
+int OSC_writeFloatArgs(OSCbuf *buf, int numFloats, float *args);
+int OSC_writeIntArg(OSCbuf *buf, int4byte arg);
+int OSC_writeStringArg(OSCbuf *buf, char *arg);
+
+extern char *OSC_errorMessage;
+
+/* How many bytes will be needed in the OSC format to hold the given
+ string? The length of the string, plus the null char, plus any padding
+ needed for 4-byte alignment. */
+int OSC_effectiveStringLength(char *string);
diff --git a/libOSC/OSC-timetag.c b/libOSC/OSC-timetag.c
new file mode 100644
index 0000000..639eae9
--- /dev/null
+++ b/libOSC/OSC-timetag.c
@@ -0,0 +1,175 @@
+/*
+Copyright (c) 1998. The Regents of the University of California (Regents).
+All Rights Reserved.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for educational, research, and not-for-profit purposes, without
+fee and without a signed licensing agreement, is hereby granted, provided that
+the above copyright notice, this paragraph and the following two paragraphs
+appear in all copies, modifications, and distributions. Contact The Office of
+Technology Licensing, UC Berkeley, 2150 Shattuck Avenue, Suite 510, Berkeley,
+CA 94720-1620, (510) 643-7201, for commercial licensing opportunities.
+
+Written by Matt Wright, The Center for New Music and Audio Technologies,
+University of California, Berkeley.
+
+ IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
+ ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING
+ DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS".
+ REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
+ ENHANCEMENTS, OR MODIFICATIONS.
+
+The OpenSound Control WWW page is
+ http://www.cnmat.berkeley.edu/OpenSoundControl
+*/
+
+/*
+
+ OSC_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 "OSC-timetag.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) {
+ int64 offset = (int64) (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) {
+ uint64 result;
+ uint32 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 */
+
diff --git a/libOSC/OSC-timetag.h b/libOSC/OSC-timetag.h
new file mode 100644
index 0000000..3ce693a
--- /dev/null
+++ b/libOSC/OSC-timetag.h
@@ -0,0 +1,93 @@
+/*
+Copyright (c) 1998. The Regents of the University of California (Regents).
+All Rights Reserved.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for educational, research, and not-for-profit purposes, without
+fee and without a signed licensing agreement, is hereby granted, provided that
+the above copyright notice, this paragraph and the following two paragraphs
+appear in all copies, modifications, and distributions. Contact The Office of
+Technology Licensing, UC Berkeley, 2150 Shattuck Avenue, Suite 510, Berkeley,
+CA 94720-1620, (510) 643-7201, for commercial licensing opportunities.
+
+Written by Matt Wright, The Center for New Music and Audio Technologies,
+University of California, Berkeley.
+
+ IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
+ ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING
+ DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS".
+ REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
+ ENHANCEMENTS, OR MODIFICATIONS.
+
+The OpenSound Control WWW page is
+ http://www.cnmat.berkeley.edu/OpenSoundControl
+*/
+
+/*
+ OSC_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 a 64-bit
+ unsigned long if possible, or else a struct.
+
+ NB: On many architectures with 64-bit ints, it's illegal (like maybe a bus error)
+ to dereference a pointer to a 64-bit int that's not 64-bit 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 64 bit ints on your system */
+ typedef long long int64;
+ typedef unsigned long long uint64;
+ typedef unsigned long uint32;
+#else
+ /* You may have to redefine this typedef if ints on your system
+ aren't 32 bits. */
+ typedef unsigned int uint32;
+#endif
+
+
+#ifdef HAS8BYTEINT
+ typedef uint64 OSCTimeTag;
+#else
+ typedef struct {
+ uint32 seconds;
+ uint32 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 */
diff --git a/libOSC/test_OSC.c b/libOSC/test_OSC.c
new file mode 100644
index 0000000..4593ec6
--- /dev/null
+++ b/libOSC/test_OSC.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 1997 Regents of the University of California.
+ * All rights reserved.
+ *
+ * The name of the University may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission. THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE
+ * IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/*
+ test_OSC.c
+ Trivial program to test OpenSoundControl.[ch]
+
+ Matt Wright 6/2/97
+*/
+
+#include <stdio.h>
+#include <ctype.h>
+#include "OpenSoundControl.h"
+
+#define SIZE 10000
+
+void PrintBuf(OSCbuf *b) {
+ printf("Buffer is %sempty.\n", OSC_isBufferEmpty(b) ? "" : "not ");
+ printf("%d bytes free in buffer\n", OSC_freeSpaceInBuffer(b));
+ printf("Buffer is %sready to send\n", OSC_isBufferDone(b) ?"":"not ");
+
+ printf("Buffer: bufptr %p, state %d, thisMsgSize %p, bundleDepth %d\n"
+ "prevCounts[%d] %p\n", b->bufptr, b->state, b->thisMsgSize,
+ b->bundleDepth, b->bundleDepth, b->prevCounts[b->bundleDepth]);
+}
+
+void PrintPacket(OSCbuf *b) {
+ char *p = OSC_getPacket(b);
+ int size = OSC_packetSize(b);
+ unsigned int *intp;
+ int i;
+
+ printf("PrintPacket: packet at %p, size %d\n", p, size);
+ if (p == 0 || size == 0) return;
+
+ printf("Hex version:");
+ for (i = 0, intp = (unsigned int *)p; i < size; i += 4, intp++) {
+ if (i % 40 == 0) printf("\n");
+ printf("%x ", *intp);
+ }
+
+ printf("\n\nString version:");
+ for (i = 0; i < size; i++) {
+ if (i % 40 == 0) printf("\n");
+ if (isprint(p[i])) {
+ printf("%c", p[i]);
+ } else {
+ printf("\\%x", p[i] & 0x000000ff);
+ }
+ }
+ printf("\n");
+}
+
+
+main() {
+ OSCbuf myBuf;
+ OSCbuf *b = &myBuf;
+ char bytes[SIZE];
+ OSCTimeTag tt;
+
+ printf("OSC_initBuffer\n");
+ OSC_initBuffer(b, SIZE, bytes);
+
+ PrintBuf(b);
+
+ printf("Testing one-message packet\n");
+ if (OSC_writeAddress(b, "/blah/bleh/singlemessage")) {
+ printf("** ERROR: %s\n", OSC_errorMessage);
+ }
+
+ if (OSC_writeFloatArg(b, 1.23456f)) {
+ printf("** ERROR: %s\n", OSC_errorMessage);
+ }
+
+ {
+ float floatarray[10];
+ int i;
+ for (i = 0; i < 10; ++i) {
+ floatarray[i] = i * 10.0f;
+ }
+ if (OSC_writeFloatArgs(b, 10, floatarray)) {
+ printf("** ERROR: %s\n", OSC_errorMessage);
+ }
+ }
+
+ if (OSC_writeIntArg(b, 123456)) {
+ printf("** ERROR: %s\n", OSC_errorMessage);
+ }
+
+ if (OSC_writeStringArg(b, "This is a cool string, dude.")) {
+ printf("** ERROR: %s\n", OSC_errorMessage);
+ }
+
+ PrintBuf(b);
+ PrintPacket(b);
+
+ printf("Resetting\n");
+ OSC_resetBuffer(b);
+
+ printf("Testing time tags\n");
+ tt = OSCTT_CurrentTime();
+ printf("Time now is %llx\n", tt);
+
+ printf("Testing bundles\n");
+ if (OSC_openBundle(b, tt)) {
+ printf("** ERROR: %s\n", OSC_errorMessage);
+ }
+
+ if (OSC_writeAddress(b, "/a/hello")) {
+ printf("** ERROR: %s\n", OSC_errorMessage);
+ }
+
+ if (OSC_writeIntArg(b, 16)) {
+ printf("** ERROR: %s\n", OSC_errorMessage);
+ }
+
+ if (OSC_writeIntArg(b, 32)) {
+ printf("** ERROR: %s\n", OSC_errorMessage);
+ }
+
+ if (OSC_openBundle(b, OSCTT_PlusSeconds(tt, 1.0f))) {
+ printf("** ERROR: %s\n", OSC_errorMessage);
+ }
+
+ if (OSC_writeAddress(b, "/b/hello")) {
+ printf("** ERROR: %s\n", OSC_errorMessage);
+ }
+
+ if (OSC_writeAddress(b, "/c/hello")) {
+ printf("** ERROR: %s\n", OSC_errorMessage);
+ }
+
+ OSC_closeAllBundles(b);
+
+ PrintBuf(b);
+ PrintPacket(b);
+}
+
+
+
diff --git a/libOSC/test_OSC_timeTag.c b/libOSC/test_OSC_timeTag.c
new file mode 100644
index 0000000..8a1cabf
--- /dev/null
+++ b/libOSC/test_OSC_timeTag.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 1997 Regents of the University of California.
+ * All rights reserved.
+ *
+ * The name of the University may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission. THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE
+ * IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/*
+ test_OSC_timeTag.c
+ Matt Wright, 5/30/97
+*/
+
+#include <stdio.h>
+#include "OSC_timeTag.h"
+
+main() {
+ OSCTimeTag now, later;
+
+ now = OSCTT_CurrentTime();
+ printf("Now it's %llu (0x%llx)\n", now, now);
+
+ printf("Immediately would be %llu (0x%llx)\n", OSCTT_Immediately(),
+ OSCTT_Immediately());
+
+ later = OSCTT_PlusSeconds(now, 1.0f);
+ printf("One second from now would be %llu (0x%llx)\n", later, later);
+
+ now = OSCTT_CurrentTime();
+ printf("And *now* it's %llu (0x%llx)\n", now, now);
+}
+
diff --git a/send+dump/Makefile b/send+dump/Makefile
new file mode 100644
index 0000000..7b14a43
--- /dev/null
+++ b/send+dump/Makefile
@@ -0,0 +1,25 @@
+LIBOSCDIR = ../libOSC
+LIBOSC = ${LIBOSCDIR}/libOSC.a
+CFLAGS= -O2 -I$(LIBOSCDIR)
+
+DUMPOBJS=dumpOSC.o
+
+
+both: sendOSC dumpOSC
+
+sendOSC: sendOSC.o htmsocket.o ${LIBOSC}
+ ${CC} -o sendOSC sendOSC.o htmsocket.o ${LIBOSC}
+
+dumpOSC: ${DUMPOBJS}
+ ${CC} -o $@ ${DUMPOBJS}
+
+dumpUDP: dumpUDP.o
+ ${CC} -o dumpUDP dumpUDP.o
+
+${LIBOSC}:
+ echo "You need to go to " ${LIBOSCDIR} " and do a make."
+
+clean:
+ rm -f sendOSC dumpOSC *.o
+
+
diff --git a/send+dump/dumpOSC.c b/send+dump/dumpOSC.c
new file mode 100644
index 0000000..143a994
--- /dev/null
+++ b/send+dump/dumpOSC.c
@@ -0,0 +1,716 @@
+/*
+Copyright (c) 1992,1993,1994,1995,1996,1997,2000.
+The Regents of the University of California (Regents).
+All Rights Reserved.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for educational, research, and not-for-profit purposes, without
+fee and without a signed licensing agreement, is hereby granted, provided that
+the above copyright notice, this paragraph and the following two paragraphs
+appear in all copies, modifications, and distributions. Contact The Office of
+Technology Licensing, UC Berkeley, 2150 Shattuck Avenue, Suite 510, Berkeley,
+CA 94720-1620, (510) 643-7201, for commercial licensing opportunities.
+
+Written by Matt Wright and Adrian Freed, The Center for New Music and Audio
+Technologies, University of California, Berkeley.
+
+ IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
+ ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING
+ DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS".
+ REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
+ ENHANCEMENTS, OR MODIFICATIONS.
+*/
+
+ /*
+
+ dumpOSC.c
+ server that displays OpenSoundControl messages sent to it
+ for debugging client udp and UNIX protocol
+
+ by Matt Wright, 6/3/97
+ modified from dumpSC.c, by Matt Wright and Adrian Freed
+
+ version 0.2: Added "-silent" option a.k.a. "-quiet"
+
+ version 0.3: Incorporated patches from Nicola Bernardini to make
+ things Linux-friendly. Also added ntohl() in the right places
+ to support little-endian architectures.
+
+
+
+ compile:
+ cc -o dumpOSC dumpOSC.c
+
+ to-do:
+
+ More robustness in saying exactly what's wrong with ill-formed
+ messages. (If they don't make sense, show exactly what was
+ received.)
+
+ Time-based features: print time-received for each packet
+
+ Clean up to separate OSC parsing code from socket/select stuff
+
+*/
+
+
+#if defined(__sgi) || defined(__linux)
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <rpc/rpc.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/times.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <ctype.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <signal.h>
+#include <grp.h>
+#include <sys/file.h>
+#include <sys/prctl.h>
+
+#ifdef NEED_SCHEDCTL_AND_LOCK
+#include <sys/schedctl.h>
+#include <sys/lock.h>
+#endif
+
+
+char *htm_error_string;
+typedef int Boolean;
+typedef void *OBJ;
+
+typedef struct ClientAddressStruct {
+ struct sockaddr_in cl_addr;
+ int clilen;
+ int sockfd;
+} *ClientAddr;
+
+Boolean ShowBytes = FALSE;
+Boolean Silent = FALSE;
+
+/* Declarations */
+static int unixinitudp(int chan);
+static int initudp(int chan);
+static void closeudp(int sockfd);
+Boolean ClientReply(int packetsize, void *packet, int socketfd,
+ void *clientaddresspointer, int clientaddressbufferlength);
+void sgi_CleanExit(void);
+Boolean sgi_HaveToQuit(void);
+int RegisterPollingDevice(int fd, void (*callbackfunction)(int , void *), void *dummy);
+static void catch_sigint();
+static int Synthmessage(char *m, int n, void *clientdesc, int clientdesclength, int fd) ;
+void ParseOSCPacket(char *buf, int n, ClientAddr returnAddr);
+static void Smessage(char *address, void *v, int n, ClientAddr returnAddr);
+static void PrintTypeTaggedArgs(void *v, int n);
+static void PrintHeuristicallyTypeGuessedArgs(void *v, int n, int skipComma);
+char *DataAfterAlignedString(char *string, char *boundary) ;
+Boolean IsNiceString(char *string, char *boundary) ;
+void complain(char *s, ...);
+
+
+#define UNIXDG_PATH "/tmp/htm"
+#define UNIXDG_TMP "/tmp/htm.XXXXXX"
+static int unixinitudp(int chan)
+{
+ struct sockaddr_un serv_addr;
+ int sockfd;
+
+ if((sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
+ return sockfd;
+
+ bzero((char *)&serv_addr, sizeof(serv_addr));
+ serv_addr.sun_family = AF_UNIX;
+ strcpy(serv_addr.sun_path, UNIXDG_PATH);
+ sprintf(serv_addr.sun_path+strlen(serv_addr.sun_path), "%d", chan);
+ unlink(serv_addr.sun_path);
+ if(bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr.sun_family)+strlen(serv_addr.sun_path)) < 0)
+ {
+ perror("unable to bind\n");
+ return -1;
+ }
+
+ fcntl(sockfd, F_SETFL, FNDELAY);
+ return sockfd;
+}
+
+static int initudp(int chan)
+{
+ struct sockaddr_in serv_addr;
+ int sockfd;
+
+ if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ return sockfd;
+ bzero((char *)&serv_addr, sizeof(serv_addr));
+ serv_addr.sin_family = AF_INET;
+ serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ serv_addr.sin_port = htons(chan);
+
+ if(bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
+ {
+ perror("unable to bind\n");
+ return -1;
+ }
+
+ fcntl(sockfd, F_SETFL, FNDELAY);
+ return sockfd;
+}
+
+static void closeudp(int sockfd) {
+ close(sockfd);
+}
+
+static Boolean catchupflag=FALSE;
+Boolean ClientReply(int packetsize, void *packet, int socketfd,
+ void *clientaddresspointer, int clientaddressbufferlength)
+{
+ if(!clientaddresspointer) return FALSE;
+ catchupflag= TRUE;
+ return packetsize==sendto(socketfd, packet, packetsize, 0, clientaddresspointer, clientaddressbufferlength);
+}
+
+static Boolean exitflag= FALSE;
+void sgi_CleanExit(void) {
+ exitflag = TRUE;
+}
+
+Boolean sgi_HaveToQuit(void) {
+ return exitflag;
+}
+
+
+/* file descriptor poll table */
+static int npolldevs =0;
+typedef struct polldev
+{
+ int fd;
+ void (*callbackfunction)(int , void *);
+ void *dummy;
+} polldev;
+#define TABMAX 8
+static polldev polldevs[TABMAX];
+
+
+/* Register a device (referred to by a file descriptor that the caller
+ should have already successfully obtained from a system call) to be
+ polled as real-time constraints allowed.
+
+ When a select(2) call indicates activity on the file descriptor, the
+ callback function is called with the file descripter as first
+ argument and the given dummy argument (presumably a pointer to the
+ instance variables associated with the device).
+*/
+int RegisterPollingDevice(int fd, void (*callbackfunction)(int , void *), void *dummy)
+{
+ if(npolldevs<TABMAX)
+ {
+ polldevs[npolldevs].fd = fd;
+ polldevs[npolldevs].callbackfunction = callbackfunction;
+ polldevs[npolldevs].dummy = dummy;
+ }
+ else return -1;
+ return npolldevs++;
+}
+
+static int caught_sigint;
+
+static void catch_sigint() {
+ caught_sigint = 1;
+}
+static int sockfd, usockfd;
+
+
+
+static int Synthmessage(char *m, int n, void *clientdesc, int clientdesclength, int fd) {
+ struct ClientAddressStruct ras;
+ ClientAddr ra = &ras;
+
+ catchupflag= FALSE;
+
+ ras.cl_addr = *((struct sockaddr_in *) clientdesc);
+ ras.clilen = clientdesclength;
+ ras.sockfd = fd;
+
+ if (ShowBytes) {
+ int i;
+ printf("%d byte message:\n", n);
+ for (i = 0; i < n; ++i) {
+ printf(" %x (%c)\t", m[i], m[i]);
+ if (i%4 == 3) printf("\n");
+ }
+ printf("\n");
+ }
+
+ ParseOSCPacket(m, n, ra);
+ return catchupflag;
+}
+
+void PrintClientAddr(ClientAddr CA) {
+ unsigned long addr = CA->cl_addr.sin_addr.s_addr;
+ printf("Client address %p:\n", CA);
+ printf(" clilen %d, sockfd %d\n", CA->clilen, CA->sockfd);
+ printf(" sin_family %d, sin_port %d\n", CA->cl_addr.sin_family,
+ CA->cl_addr.sin_port);
+ printf(" address: (%x) %s\n", addr, inet_ntoa(CA->cl_addr.sin_addr));
+
+ printf(" sin_zero = \"%c%c%c%c%c%c%c%c\"\n",
+ CA->cl_addr.sin_zero[0],
+ CA->cl_addr.sin_zero[1],
+ CA->cl_addr.sin_zero[2],
+ CA->cl_addr.sin_zero[3],
+ CA->cl_addr.sin_zero[4],
+ CA->cl_addr.sin_zero[5],
+ CA->cl_addr.sin_zero[6],
+ CA->cl_addr.sin_zero[7]);
+
+ printf("\n");
+}
+
+
+void ParseOSCPacket(char *buf, int n, ClientAddr returnAddr) {
+ int size, messageLen, i;
+ char *messageName;
+ char *args;
+
+#ifdef PRINTADDRS
+ PrintClientAddr(returnAddr);
+#endif
+
+
+ if ((n%4) != 0) {
+ complain("SynthControl packet size (%d) not a multiple of 4 bytes: dropping",
+ n);
+ return;
+ }
+
+ if ((n >= 8) && (strncmp(buf, "#bundle", 8) == 0)) {
+ /* This is a bundle message. */
+
+ if (n < 16) {
+ complain("Bundle message too small (%d bytes) for time tag", n);
+ return;
+ }
+
+ /* Print the time tag */
+ printf("[ %lx%08lx\n", ntohl(*((unsigned long *)(buf+8))),
+ ntohl(*((unsigned long *)(buf+12))));
+ /* Note: if we wanted to actually use the time tag as a little-endian
+ 64-bit int, we'd have to word-swap the two 32-bit halves of it */
+
+ i = 16; /* Skip "#group\0" and time tag */
+ while(i<n) {
+ size = ntohl(*((int *) (buf + i)));
+ if ((size % 4) != 0) {
+ complain("Bad size count %d in bundle (not a multiple of 4)", size);
+ return;
+ }
+ if ((size + i + 4) > n) {
+ complain("Bad size count %d in bundle (only %d bytes left in entire bundle)",
+ size, n-i-4);
+ return;
+ }
+
+ /* Recursively handle element of bundle */
+ ParseOSCPacket(buf+i+4, size, returnAddr);
+ i += 4 + size;
+ }
+ if (i != n) {
+ complain("This can't happen");
+ }
+ printf("]\n");
+ } else {
+ /* This is not a bundle message */
+
+ messageName = buf;
+ args = DataAfterAlignedString(messageName, buf+n);
+ if (args == 0) {
+ complain("Bad message name string: %s\nDropping entire message.\n",
+ htm_error_string);
+ return;
+ }
+ messageLen = args-messageName;
+ Smessage(messageName, (void *)args, n-messageLen, returnAddr);
+ }
+}
+
+#define SMALLEST_POSITIVE_FLOAT 0.000001f
+
+static void Smessage(char *address, void *v, int n, ClientAddr returnAddr) {
+ char *chars = v;
+
+ printf("%s ", address);
+
+ if (n != 0) {
+ if (chars[0] == ',') {
+ if (chars[1] != ',') {
+ /* This message begins with a type-tag string */
+ PrintTypeTaggedArgs(v, n);
+ } else {
+ /* Double comma means an escaped real comma, not a type string */
+ PrintHeuristicallyTypeGuessedArgs(v, n, 1);
+ }
+ } else {
+ PrintHeuristicallyTypeGuessedArgs(v, n, 0);
+ }
+ }
+
+ printf("\n");
+ fflush(stdout); /* Added for Sami 5/21/98 */
+}
+
+static void PrintTypeTaggedArgs(void *v, int n) {
+ char *typeTags, *thisType;
+ char *p;
+
+ typeTags = v;
+
+ if (!IsNiceString(typeTags, typeTags+n)) {
+ /* No null-termination, so maybe it wasn't a type tag
+ string after all */
+ PrintHeuristicallyTypeGuessedArgs(v, n, 0);
+ return;
+ }
+
+ p = DataAfterAlignedString(typeTags, typeTags+n);
+
+
+ for (thisType = typeTags + 1; *thisType != 0; ++thisType) {
+ switch (*thisType) {
+ case 'i': case 'r': case 'm': case 'c':
+ printf("%d ", ntohl(*((int *) p)));
+ p += 4;
+ break;
+
+ case 'f': {
+ int i = ntohl(*((int *) p));
+ float *floatp = ((float *) (&i));
+ printf("%f ", *floatp);
+ p += 4;
+ }
+ break;
+
+ case 'h': case 't':
+ printf("[A 64-bit int] ");
+ p += 8;
+ break;
+
+ case 'd':
+ printf("[A 64-bit float] ");
+ p += 8;
+ break;
+
+ case 's': case 'S':
+ if (!IsNiceString(p, typeTags+n)) {
+ printf("Type tag said this arg is a string but it's not!\n");
+ return;
+ } else {
+ printf("\"%s\" ", p);
+ p = DataAfterAlignedString(p, typeTags+n);
+ }
+ break;
+
+ case 'T': printf("[True] "); break;
+ case 'F': printf("[False] "); break;
+ case 'N': printf("[Nil]"); break;
+ case 'I': printf("[Infinitum]"); break;
+
+ default:
+ printf("[Unrecognized type tag %c]", *thisType);
+ return;
+ }
+ }
+}
+
+static void PrintHeuristicallyTypeGuessedArgs(void *v, int n, int skipComma) {
+ int i, thisi;
+ float thisf;
+ int *ints;
+ char *chars;
+ char *string, *nextString;
+
+
+ /* Go through the arguments 32 bits at a time */
+ ints = v;
+ chars = v;
+
+ for (i = 0; i<n/4; ) {
+ string = &chars[i*4];
+ thisi = ntohl(ints[i]);
+ /* Reinterpret the (potentially byte-reversed) thisi as a float */
+ thisf = *(((float *) (&thisi)));
+
+ if (thisi >= -1000 && thisi <= 1000000) {
+ printf("%d ", thisi);
+ i++;
+ } else if (thisf >= -1000.f && thisf <= 1000000.f &&
+ (thisf <=0.0f || thisf >= SMALLEST_POSITIVE_FLOAT)) {
+ printf("%f ", thisf);
+ i++;
+ } else if (IsNiceString(string, chars+n)) {
+ nextString = DataAfterAlignedString(string, chars+n);
+ printf("\"%s\" ", (i == 0 && skipComma) ? string +1 : string);
+ i += (nextString-string) / 4;
+ } else {
+ printf("0x%x ", ints[i]);
+ i++;
+ }
+ }
+}
+
+
+#define STRING_ALIGN_PAD 4
+
+char *DataAfterAlignedString(char *string, char *boundary)
+{
+ /* 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 STRING_ALIGN_PAD
+ 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 htm_error_string */
+
+ int i;
+
+ if ((boundary - string) %4 != 0) {
+ fprintf(stderr, "Internal error: DataAfterAlignedString: bad boundary\n");
+ return 0;
+ }
+
+ for (i = 0; string[i] != '\0'; i++) {
+ if (string + i >= boundary) {
+ htm_error_string = "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) {
+ htm_error_string = "DataAfterAlignedString: Unreasonably long string";
+ return 0;
+ }
+ if (string[i] != '\0') {
+ htm_error_string = "DataAfterAlignedString: Incorrectly padded string.";
+ return 0;
+ }
+ }
+
+ return string+i;
+}
+
+Boolean IsNiceString(char *string, char *boundary)
+{
+ /* Arguments same as DataAfterAlignedString(). Is the given "string"
+ really a string? I.e., is it a sequence of isprint() characters
+ terminated with 1-4 null characters to align on a 4-byte boundary? */
+
+ int i;
+
+ if ((boundary - string) %4 != 0) {
+ fprintf(stderr, "Internal error: IsNiceString: bad boundary\n");
+ return 0;
+ }
+
+ for (i = 0; string[i] != '\0'; i++) {
+ if (!isprint(string[i])) return FALSE;
+ if (string + i >= boundary) return FALSE;
+ }
+
+ /* If we made it this far, it's a null-terminated sequence of printing characters
+ in the given boundary. Now we just make sure it's null padded... */
+
+ /* Now string[i] is the first null character */
+ i++;
+ for (; (i % STRING_ALIGN_PAD) != 0; i++) {
+ if (string[i] != '\0') return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+
+
+
+
+
+#define MAXMESG 32768
+static char mbuf[MAXMESG];
+
+int main(int argc, char **argv) {
+ int udp_port; /* port to receive parameter updates from */
+
+ struct sockaddr_in cl_addr;
+ int clilen,maxclilen=sizeof(cl_addr);
+ struct sockaddr_un ucl_addr;
+ int uclilen,umaxclilen=sizeof(ucl_addr);
+ int i,n;
+
+
+ clilen = maxclilen;
+ uclilen = umaxclilen;
+
+ udp_port = -1;
+ for (i=1; i < argc; ++i) {
+ if (strcmp(argv[i], "-showbytes") == 0) {
+ ShowBytes = TRUE;
+ } else if (strcmp(argv[i], "-silent") == 0 ||
+ strcmp(argv[i], "-quiet") == 0) {
+ Silent = TRUE;
+ } else if (udp_port != -1) {
+ goto usageError;
+ } else {
+ udp_port = atoi(argv[i]);
+ if (udp_port == 0) {
+ goto usageError;
+ }
+ }
+ }
+
+ if (udp_port == -1) {
+ usageError:
+ fprintf(stderr, "Usage\n\tdumpOSC portno [-showbytes] [-quiet]\n\t(responds to udp and UNIX packets on that port no)\n");
+ exit(1);
+ }
+
+
+ n = recvfrom(0, mbuf, MAXMESG, 0, &cl_addr, &clilen);
+ if(n>0)
+ {
+ sockfd = 0;
+ udp_port = -1;
+ Synthmessage(mbuf, n, &cl_addr, clilen,sockfd) ;
+ }
+ else
+ { sockfd=initudp(udp_port);
+ usockfd=unixinitudp(udp_port);
+ }
+
+ if (!Silent) {
+ printf("dumpOSC version 0.2 (6/18/97 Matt Wright). Unix/UDP Port %d \n", udp_port);
+ printf("Copyright (c) 1992,1996,1997 Regents of the University of California.\n");
+ }
+ if(sockfd>=0 && usockfd>=0)
+ {
+ fd_set read_fds, write_fds;
+ int nfds;
+#define max(a,b) (((a) > (b)) ? (a) : (b))
+ nfds = max(sockfd, usockfd)+ 1;
+ {
+ int j;
+ for(j=0;j<npolldevs;++j)
+ if(polldevs[j].fd>=nfds)
+ {
+ nfds = polldevs[j].fd+1;
+/*
+printf("polldev %d\n", polldevs[j].fd);
+*/
+ }
+ }
+/*
+ printf("nfds %d\n", nfds);
+*/
+ caught_sigint = 0;
+ sigset(SIGINT, catch_sigint); /* set sig handler */
+
+ while(!caught_sigint)
+ {
+
+ int r;
+
+ back:
+
+ FD_ZERO(&read_fds); /* clear read_fds */
+ FD_ZERO(&write_fds); /* clear write_fds */
+ FD_SET(sockfd, &read_fds);
+ FD_SET(usockfd, &read_fds);
+ {
+ int j;
+
+ for(j=0;j<npolldevs;++j)
+ FD_SET(polldevs[j].fd, &read_fds);
+ }
+
+ r = select(nfds, &read_fds, &write_fds, (fd_set *)0,
+ (struct timeval *)0);
+ if (r < 0) /* select reported an error */
+ goto out;
+ {
+ int j;
+
+ for(j=0;j<npolldevs;++j)
+ if(FD_ISSET(polldevs[j].fd, &read_fds))
+ (*(polldevs[j].callbackfunction))(polldevs[j].fd,polldevs[j].dummy );
+ }
+ if(FD_ISSET(sockfd, &read_fds))
+ {
+ clilen = maxclilen;
+ while( (n = recvfrom(sockfd, mbuf, MAXMESG, 0, &cl_addr, &clilen)) >0)
+ {
+ int r;
+ /* printf("received UDP packet of length %d\n", n); */
+ r = Synthmessage(mbuf, n, &cl_addr, clilen, sockfd) ;
+
+ if( sgi_HaveToQuit()) goto out;
+ if(r>0) goto back;
+ clilen = maxclilen;
+ }
+ }
+ if(FD_ISSET(usockfd, &read_fds))
+ {
+ uclilen = umaxclilen;
+ while( (n = recvfrom(usockfd, mbuf, MAXMESG, 0, &ucl_addr, &uclilen)) >0)
+ {
+ int r;
+ /* printf("received UNIX packet of length %d\n", n); */
+
+ r=Synthmessage(mbuf, n, &ucl_addr, uclilen,usockfd) ;
+
+ if( sgi_HaveToQuit()) goto out;
+ if(r>0) goto back;
+ uclilen = umaxclilen;
+ }
+ }
+ } /* End of while(!caught_sigint) */
+
+
+out: ;
+ }
+ else
+ perror("initudp");
+
+ return 0;
+}
+
+
+#include <stdarg.h>
+void complain(char *s, ...) {
+ va_list ap;
+ va_start(ap, s);
+ fprintf(stderr, "*** ERROR: ");
+ vfprintf(stderr, s, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+}
+
+#endif /* __sgi or LINUX */
diff --git a/send+dump/dumpUDP.c b/send+dump/dumpUDP.c
new file mode 100644
index 0000000..3876812
--- /dev/null
+++ b/send+dump/dumpUDP.c
@@ -0,0 +1,191 @@
+/*
+Copyright (c) 1998. The Regents of the University of California (Regents).
+All Rights Reserved.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for educational, research, and not-for-profit purposes, without
+fee and without a signed licensing agreement, is hereby granted, provided that
+the above copyright notice, this paragraph and the following two paragraphs
+appear in all copies, modifications, and distributions. Contact The Office of
+Technology Licensing, UC Berkeley, 2150 Shattuck Avenue, Suite 510, Berkeley,
+CA 94720-1620, (510) 643-7201, for commercial licensing opportunities.
+
+Written by Matt Wright, The Center for New Music and Audio Technologies,
+University of California, Berkeley.
+
+ IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
+ ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING
+ DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS".
+ REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
+ ENHANCEMENTS, OR MODIFICATIONS.
+
+dumpUDP.c: smallest UDP receiving application
+by Matt Wright, 9/9/98
+
+*/
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <rpc/rpc.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/times.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <ctype.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <signal.h>
+#include <grp.h>
+#include <sys/file.h>
+#include <bstring.h>
+#include <sys/prctl.h>
+#include <sys/schedctl.h>
+#include <sys/lock.h>
+
+
+typedef struct ClientAddressStruct {
+ struct sockaddr_in cl_addr;
+ int clilen;
+ int sockfd;
+} *ClientAddr;
+
+void PrintClientAddr(ClientAddr CA) {
+ unsigned long addr = CA->cl_addr.sin_addr.s_addr;
+ printf("Client address %p:\n", CA);
+ printf(" clilen %d, sockfd %d\n", CA->clilen, CA->sockfd);
+ printf(" sin_family %d, sin_port %d\n", CA->cl_addr.sin_family,
+ CA->cl_addr.sin_port);
+ printf(" address: (%x) %s\n", addr, inet_ntoa(CA->cl_addr.sin_addr));
+
+ printf(" sin_zero = \"%c%c%c%c%c%c%c%c\"\n",
+ CA->cl_addr.sin_zero[0],
+ CA->cl_addr.sin_zero[1],
+ CA->cl_addr.sin_zero[2],
+ CA->cl_addr.sin_zero[3],
+ CA->cl_addr.sin_zero[4],
+ CA->cl_addr.sin_zero[5],
+ CA->cl_addr.sin_zero[6],
+ CA->cl_addr.sin_zero[7]);
+
+ printf("\n");
+}
+
+
+static int initudp(int port) {
+ struct sockaddr_in serv_addr;
+ int n, sockfd;
+
+ if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ return sockfd;
+ bzero((char *)&serv_addr, sizeof(serv_addr));
+ serv_addr.sin_family = AF_INET;
+ serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ serv_addr.sin_port = htons(port);
+
+ if(bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
+ {
+ perror("unable to bind\n");
+ return -1;
+ }
+
+ fcntl(sockfd, F_SETFL, FNDELAY);
+ return sockfd;
+}
+
+
+static void closeudp(int sockfd) {
+ close(sockfd);
+}
+
+
+static int time_to_quit;
+
+static void catch_sigint() {
+ time_to_quit = 1;
+}
+
+void GotAPacket(char *buf, int n, ClientAddr returnAddr) {
+ printf("received UDP packet of length %d\n", n);
+ PrintClientAddr(returnAddr);
+}
+
+#define MAXMESG 32768
+static char mbuf[MAXMESG];
+
+void ReceivePacket(int sockfd) {
+ struct ClientAddressStruct returnAddress;
+ int maxclilen=sizeof(returnAddress.cl_addr);
+ int n;
+
+ returnAddress.clilen = maxclilen;
+ while( (n = recvfrom(sockfd, mbuf, MAXMESG, 0, &(returnAddress.cl_addr),
+ &(returnAddress.clilen))) >0) {
+ GotAPacket(mbuf, n, &returnAddress);
+
+ if (time_to_quit) return;
+ returnAddress.clilen = maxclilen;
+ }
+}
+
+void main(int argc, char **argv) {
+ int udp_port; /* port to receive parameter updates from */
+ int sockfd;
+ int i;
+
+ fd_set read_fds, write_fds;
+ int nfds;
+
+ udp_port = 7000;
+
+ sockfd=initudp(udp_port);
+
+ if(sockfd<0) {
+ perror("initudp");
+ return;
+ }
+
+ nfds = sockfd + 1;
+
+ time_to_quit = 0;
+ sigset(SIGINT, catch_sigint); /* set sig handler */
+
+ while(!time_to_quit)
+ {
+
+ int c,r;
+
+ back:
+
+ FD_ZERO(&read_fds); /* clear read_fds */
+ FD_ZERO(&write_fds); /* clear write_fds */
+ FD_SET(sockfd, &read_fds);
+
+
+ r = select(nfds, &read_fds, &write_fds, (fd_set *)0,
+ (struct timeval *)0);
+ if (r < 0) /* select reported an error */
+ goto out;
+
+ if(FD_ISSET(sockfd, &read_fds)) {
+ ReceivePacket(sockfd);
+ }
+
+ } /* End of while(!time_to_quit) */
+out: ;
+}
diff --git a/send+dump/htmsocket.c b/send+dump/htmsocket.c
new file mode 100644
index 0000000..e4f447f
--- /dev/null
+++ b/send+dump/htmsocket.c
@@ -0,0 +1,230 @@
+/*
+Copyright (c) 1992,1996,1998.
+The Regents of the University of California (Regents).
+All Rights Reserved.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for educational, research, and not-for-profit purposes, without
+fee and without a signed licensing agreement, is hereby granted, provided that
+the above copyright notice, this paragraph and the following two paragraphs
+appear in all copies, modifications, and distributions. Contact The Office of
+Technology Licensing, UC Berkeley, 2150 Shattuck Avenue, Suite 510, Berkeley,
+CA 94720-1620, (510) 643-7201, for commercial licensing opportunities.
+
+Written by Adrian Freed, The Center for New Music and Audio Technologies,
+University of California, Berkeley.
+
+ IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
+ ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING
+ DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS".
+ REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
+ ENHANCEMENTS, OR MODIFICATIONS.
+*/
+
+ /* htmsocket.c
+
+ Adrian Freed
+ send parameters to htm servers by udp or UNIX protocol
+
+ Modified 6/6/96 by Matt Wright to understand symbolic host names
+ in addition to X.X.X.X addresses.
+ */
+
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+
+#include <rpc/rpc.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/times.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+
+#include <ctype.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <signal.h>
+#include <grp.h>
+#include <sys/fcntl.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/prctl.h>
+
+#include <stdlib.h>
+
+#define UNIXDG_PATH "/tmp/htm"
+#define UNIXDG_TMP "/tmp/htm.XXXXXX"
+#include "htmsocket.h"
+typedef struct
+{
+ float srate;
+
+ struct sockaddr_in serv_addr; /* udp socket */
+ struct sockaddr_un userv_addr; /* UNIX socket */
+ int sockfd; /* socket file descriptor */
+ int index, len,uservlen;
+ void *addr;
+ int id;
+} desc;
+
+/* open a socket for HTM communication to given host on given portnumber */
+/* if host is 0 then UNIX protocol is used (i.e. local communication */
+void *OpenHTMSocket(char *host, int portnumber)
+{
+ int sockfd;
+ struct sockaddr_in cl_addr;
+ struct sockaddr_un ucl_addr;
+ desc *o;
+ o = malloc(sizeof(*o));
+ if(!o)
+ return 0;
+ if(!host)
+ {
+ char *mktemp(char *);
+ int clilen;
+ o->len = sizeof(ucl_addr);
+ /*
+ * Fill in the structure "userv_addr" with the address of the
+ * server that we want to send to.
+ */
+
+ bzero((char *) &o->userv_addr, sizeof(o->userv_addr));
+ o->userv_addr.sun_family = AF_UNIX;
+ strcpy(o->userv_addr.sun_path, UNIXDG_PATH);
+ sprintf(o->userv_addr.sun_path+strlen(o->userv_addr.sun_path), "%d", portnumber);
+ o->uservlen = sizeof(o->userv_addr.sun_family) + strlen(o->userv_addr.sun_path);
+ o->addr = &(o->userv_addr);
+ /*
+ * Open a socket (a UNIX domain datagram socket).
+ */
+
+ if ( (sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) >= 0)
+ {
+ /*
+ * Bind a local address for us.
+ * In the UNIX domain we have to choose our own name (that
+ * should be unique). We'll use mktemp() to create a unique
+ * pathname, based on our process id.
+ */
+
+ bzero((char *) &ucl_addr, sizeof(ucl_addr)); /* zero out */
+ ucl_addr.sun_family = AF_UNIX;
+ strcpy(ucl_addr.sun_path, UNIXDG_TMP);
+
+ mktemp(ucl_addr.sun_path);
+ clilen = sizeof(ucl_addr.sun_family) + strlen(ucl_addr.sun_path);
+
+ if (bind(sockfd, (struct sockaddr *) &ucl_addr, clilen) < 0)
+ {
+ perror("client: can't bind local address");
+ close(sockfd);
+ sockfd = -1;
+ }
+ }
+ else
+ perror("unable to make socket\n");
+
+ }else
+ {
+ /*
+ * Fill in the structure "serv_addr" with the address of the
+ * server that we want to send to.
+ */
+ o->len = sizeof(cl_addr);
+ bzero((char *)&o->serv_addr, sizeof(o->serv_addr));
+ o->serv_addr.sin_family = AF_INET;
+
+ /* MW 6/6/96: Call gethostbyname() instead of inet_addr(),
+ so that host can be either an Internet host name (e.g.,
+ "les") or an Internet address in standard dot notation
+ (e.g., "128.32.122.13") */
+ {
+ struct hostent *hostsEntry;
+ unsigned long address;
+
+ hostsEntry = gethostbyname(host);
+ if (hostsEntry == NULL) {
+ fprintf(stderr, "Couldn't decipher host name \"%s\"\n",
+ host);
+ herror(NULL);
+ return 0;
+ }
+
+ address = *((unsigned long *) hostsEntry->h_addr_list[0]);
+ o->serv_addr.sin_addr.s_addr = address;
+ }
+
+ /* was: o->serv_addr.sin_addr.s_addr = inet_addr(host); */
+
+ /* End MW changes */
+
+ o->serv_addr.sin_port = htons(portnumber);
+ o->addr = &(o->serv_addr);
+ /*
+ * Open a socket (a UDP domain datagram socket).
+ */
+ if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) >= 0)
+ {
+ bzero((char *)&cl_addr, sizeof(cl_addr));
+ cl_addr.sin_family = AF_INET;
+ cl_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ cl_addr.sin_port = htons(0);
+
+ if(bind(sockfd, (struct sockaddr *) &cl_addr, sizeof(cl_addr)) < 0)
+ {
+ perror("could not bind\n");
+ close(sockfd);
+ sockfd = -1;
+ }
+ }
+ else
+ {
+ perror("unable to make socket\n");
+ }
+
+ }
+ if(sockfd<0)
+ {
+ free(o); o = 0;
+ }
+ else
+ o->sockfd = sockfd;
+ return o;
+}
+#include <errno.h>
+
+static bool sendudp(const struct sockaddr *sp, int sockfd,int length, int count, void *b)
+{
+ int rcount;
+ if((rcount=sendto(sockfd, b, count, 0, sp, length)) != count)
+ {
+/* printf("sockfd %d count %d rcount %dlength %d errno %d\n", sockfd,count,rcount,length,
+ errno); */
+ return FALSE;
+ }
+ return TRUE;
+}
+bool SendHTMSocket(void *htmsendhandle, int length_in_bytes, void *buffer)
+{
+ desc *o = (desc *)htmsendhandle;
+ return sendudp(o->addr, o->sockfd, o->len, length_in_bytes, buffer);
+}
+void CloseHTMSocket(void *htmsendhandle)
+{
+ desc *o = (desc *)htmsendhandle;
+ close(o->sockfd);
+ free(o);
+}
diff --git a/send+dump/htmsocket.h b/send+dump/htmsocket.h
new file mode 100644
index 0000000..b035b57
--- /dev/null
+++ b/send+dump/htmsocket.h
@@ -0,0 +1,49 @@
+/*
+Copyright (c) 1992,1996. The Regents of the University of California (Regents).
+All Rights Reserved.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for educational, research, and not-for-profit purposes, without
+fee and without a signed licensing agreement, is hereby granted, provided that
+the above copyright notice, this paragraph and the following two paragraphs
+appear in all copies, modifications, and distributions. Contact The Office of
+Technology Licensing, UC Berkeley, 2150 Shattuck Avenue, Suite 510, Berkeley,
+CA 94720-1620, (510) 643-7201, for commercial licensing opportunities.
+
+Written by Adrian Freed, The Center for New Music and Audio Technologies,
+University of California, Berkeley.
+
+ IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
+ ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING
+ DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS".
+ REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
+ ENHANCEMENTS, OR MODIFICATIONS.
+*/
+
+ /* htmparam.h
+
+ Adrian Freed
+ send parameters to htm servers by udp or UNIX protocol
+ */
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+typedef int bool;
+
+/* open a socket for HTM communication to given host on given portnumber */
+/* if host is 0 then UNIX protocol is used (i.e. local communication) */
+void *OpenHTMSocket(char *host, int portnumber);
+
+/* send a buffer of data over htm socket, returns TRUE on success.
+ Note that udp sends rarely fail. UNIX sends fail if a kernal buffer overflows */
+bool SendHTMSocket(void *htmsendhandle, int length_in_bytes, void *buffer);
+
+/* close the socket(2) and release memory associated with it */
+void CloseHTMSocket(void *htmsendhandle);
diff --git a/send+dump/sendOSC.c b/send+dump/sendOSC.c
new file mode 100644
index 0000000..db188dd
--- /dev/null
+++ b/send+dump/sendOSC.c
@@ -0,0 +1,600 @@
+/*
+Copyright (c) 1996,1997. The Regents of the University of California (Regents).
+All Rights Reserved.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for educational, research, and not-for-profit purposes, without
+fee and without a signed licensing agreement, is hereby granted, provided that
+the above copyright notice, this paragraph and the following two paragraphs
+appear in all copies, modifications, and distributions. Contact The Office of
+Technology Licensing, UC Berkeley, 2150 Shattuck Avenue, Suite 510, Berkeley,
+CA 94720-1620, (510) 643-7201, for commercial licensing opportunities.
+
+Written by Matt Wright, The Center for New Music and Audio Technologies,
+University of California, Berkeley.
+
+ IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
+ ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING
+ DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS".
+ REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
+ ENHANCEMENTS, OR MODIFICATIONS.
+*/
+
+/* sendOSC.c
+
+ Matt Wright, 6/3/97
+ based on sendSC.c, which was based on a version by Adrian Freed
+
+ Text-based OpenSoundControl client. User can enter messages via command
+ line arguments or standard input.
+
+ Version 0.1: "play" feature
+ Version 0.2: Message type tags.
+
+*/
+
+#define VERSION "http://cnmat.berkeley.edu/OpenSoundControl/sendOSC-0.1.html"
+
+/*
+compiling:
+ cc -o sendOSC sendOSC.c htmsocket.c OpenSoundControl.c OSC_timeTag.c
+*/
+
+
+#include "OSC-client.h"
+#include "htmsocket.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+/* #include <bstring.h> */
+#include <string.h>
+
+
+typedef struct {
+ enum {INT, FLOAT, STRING} type;
+ union {
+ int i;
+ float f;
+ char *s;
+ } datum;
+} typedArg;
+
+void CommandLineMode(int argc, char *argv[], void *htmsocket);
+void InteractiveMode(void *htmsocket);
+OSCTimeTag ParseTimeTag(char *s);
+void ParseInteractiveLine(OSCbuf *buf, char *mesg);
+typedArg ParseToken(char *token);
+int WriteMessage(OSCbuf *buf, char *messageName, int numArgs, typedArg *args);
+void SendBuffer(void *htmsocket, OSCbuf *buf);
+void SendData(void *htmsocket, int size, char *data);
+void fatal_error(char *s);
+void complain(char *s, ...);
+
+/* Exit status codes:
+ 0: successful
+ 2: Message(s) dropped because of buffer overflow
+ 3: Socket error
+ 4: Usage error
+ 5: Internal error
+*/
+static int exitStatus = 0;
+
+
+static int useTypeTags = 1;
+
+main(int argc, char *argv[]) {
+ int portnumber;
+ char *hostname = 0;
+ void *htmsocket;
+
+ argc--;
+ argv++;
+
+ if (argc == 0) {
+ goto usageerror;
+ }
+
+ if (argc >= 1 && (strncmp(*argv, "-notypetags", 2) == 0)) {
+ useTypeTags = 0;
+ argv++;
+ argc--;
+ }
+
+ if (argc >= 2 && (strncmp(*argv, "-r", 2) == 0)) {
+ hostname = getenv("REMOTE_ADDR");
+ if (hostname == NULL) {
+ complain("sendSC -r: REMOTE_ADDR not in environment\n");
+ exit(4);
+ }
+ argv++;
+ argc--;
+ }
+
+ if (argc >= 3 && (strncmp(*argv, "-h", 2) == 0)) {
+ hostname = argv[1];
+ argv += 2;
+ argc -= 2;
+ }
+ portnumber = atoi(*argv);
+ argv++;
+ argc--;
+
+ htmsocket = OpenHTMSocket(hostname, portnumber);
+ if (!htmsocket) {
+ perror("Couldn't open socket: ");
+ exit(3);
+ }
+
+ if (argc > 0) {
+ printf("host %s, port %d, %s\n", hostname, portnumber,
+ useTypeTags ? "use type tags" : "don't use type tags");
+ CommandLineMode(argc, argv, htmsocket);
+ } else {
+ printf("sendOSC version " VERSION "\n");
+ printf("by Matt Wright. Copyright (c) 1996, 1997 Regents of the University of California.\n");
+ printf("host %s, port %d, %s\n", hostname, portnumber,
+ useTypeTags ? "use type tags" : "don't use type tags");
+ InteractiveMode(htmsocket);
+ }
+ CloseHTMSocket(htmsocket);
+ exit(exitStatus);
+
+
+ usageerror:
+ complain("usage: %s [-notypetags] [-r] [-h target_host_name] port_number [message...]\n",
+ argv[-1]);
+ exit(4);
+
+}
+
+
+#define MAX_ARGS 2000
+#define SC_BUFFER_SIZE 32000
+static char bufferForOSCbuf[SC_BUFFER_SIZE];
+
+void CommandLineMode(int argc, char *argv[], void *htmsocket) {
+ char *messageName;
+ char *token;
+ typedArg args[MAX_ARGS];
+ int i,j, numArgs;
+ OSCbuf buf[1];
+
+ OSC_initBuffer(buf, SC_BUFFER_SIZE, bufferForOSCbuf);
+
+ if (argc > 1) {
+ if (OSC_openBundle(buf, OSCTT_Immediately())) {
+ complain("Problem opening bundle: %s\n", OSC_errorMessage);
+ return;
+ }
+ }
+
+ for (i = 0; i < argc; i++) {
+ messageName = strtok(argv[i], ",");
+ if (messageName == NULL) {
+ break;
+ }
+
+ j = 0;
+ while ((token = strtok(NULL, ",")) != NULL) {
+ args[j] = ParseToken(token);
+ j++;
+ if (j >= MAX_ARGS) {
+ complain("Sorry; your message has more than MAX_ARGS (%d) arguments; ignoring the rest.\n",
+ MAX_ARGS);
+ break;
+ }
+ }
+ numArgs = j;
+
+ WriteMessage(buf, messageName, numArgs, args);
+ }
+
+ if (argc > 1) {
+ if (OSC_closeBundle(buf)) {
+ complain("Problem closing bundle: %s\n", OSC_errorMessage);
+ return;
+ }
+ }
+
+ SendBuffer(htmsocket, buf);
+}
+
+#define MAXMESG 2048
+
+void InteractiveMode(void *htmsocket) {
+ char mesg[MAXMESG];
+ OSCbuf buf[1];
+ int bundleDepth = 0; /* At first, we haven't seen "[". */
+
+ OSC_initBuffer(buf, SC_BUFFER_SIZE, bufferForOSCbuf);
+
+ while (fgets(mesg, MAXMESG, stdin) != NULL) {
+ if (mesg[0] == '\n') {
+ if (bundleDepth > 0) {
+ /* Ignore blank lines inside a group. */
+ } else {
+ /* blank line => repeat previous send */
+ SendBuffer(htmsocket, buf);
+ }
+ continue;
+ }
+
+ if (bundleDepth == 0) {
+ OSC_resetBuffer(buf);
+ }
+
+ if (mesg[0] == '[') {
+ OSCTimeTag tt = ParseTimeTag(mesg+1);
+ if (OSC_openBundle(buf, tt)) {
+ complain("Problem opening bundle: %s\n", OSC_errorMessage);
+ OSC_resetBuffer(buf);
+ bundleDepth = 0;
+ continue;
+ }
+ bundleDepth++;
+ } else if (mesg[0] == ']' && mesg[1] == '\n' && mesg[2] == '\0') {
+ if (bundleDepth == 0) {
+ complain("Unexpected ']': not currently in a bundle.\n");
+ } else {
+ if (OSC_closeBundle(buf)) {
+ complain("Problem closing bundle: %s\n", OSC_errorMessage);
+ OSC_resetBuffer(buf);
+ bundleDepth = 0;
+ continue;
+ }
+
+ bundleDepth--;
+ if (bundleDepth == 0) {
+ SendBuffer(htmsocket, buf);
+ }
+ }
+ } else {
+ ParseInteractiveLine(buf, mesg);
+ if (bundleDepth != 0) {
+ /* Don't send anything until we close all bundles */
+ } else {
+ SendBuffer(htmsocket, buf);
+ }
+ }
+ }
+}
+
+OSCTimeTag ParseTimeTag(char *s) {
+ char *p, *newline;
+ typedArg arg;
+
+ p = s;
+ while (isspace(*p)) p++;
+ if (*p == '\0') return OSCTT_Immediately();
+
+ if (*p == '+') {
+ /* Time tag is for some time in the future. It should be a
+ number of seconds as an int or float */
+
+ newline = strchr(s, '\n');
+ if (newline != NULL) *newline = '\0';
+
+ p++; /* Skip '+' */
+ while (isspace(*p)) p++;
+
+ arg = ParseToken(p);
+ if (arg.type == STRING) {
+ complain("warning: inscrutable time tag request: %s\n", s);
+ return OSCTT_Immediately();
+ } else if (arg.type == INT) {
+ return OSCTT_PlusSeconds(OSCTT_CurrentTime(),
+ (float) arg.datum.i);
+ } else if (arg.type == FLOAT) {
+ return OSCTT_PlusSeconds(OSCTT_CurrentTime(), arg.datum.f);
+ } else {
+ fatal_error("This can't happen!");
+ }
+ }
+
+ if (isdigit(*p) || (*p >= 'a' && *p <='f') || (*p >= 'A' && *p <='F')) {
+ /* They specified the 8-byte tag in hex */
+ OSCTimeTag tt;
+ if (sscanf(p, "%llx", &tt) != 1) {
+ complain("warning: couldn't parse time tag %s\n", s);
+ return OSCTT_Immediately();
+ }
+#ifndef HAS8BYTEINT
+ if (ntohl(1) != 1) {
+ /* tt is a struct of seconds and fractional part,
+ and this machine is little-endian, so sscanf
+ wrote each half of the time tag in the wrong half
+ of the struct. */
+ uint32 temp;
+ temp = tt.seconds;
+ tt.seconds = tt.fraction ;
+ tt.fraction = temp;
+ }
+#endif
+ return tt;
+ }
+
+ complain("warning: invalid time tag: %s\n", s);
+ return OSCTT_Immediately();
+}
+
+
+void ParseInteractiveLine(OSCbuf *buf, char *mesg) {
+ char *messageName, *token, *p;
+ typedArg args[MAX_ARGS];
+ int thisArg;
+
+ p = mesg;
+ while (isspace(*p)) p++;
+ if (*p == '\0') return;
+
+ messageName = p;
+
+ if (strcmp(messageName, "play\n") == 0) {
+ /* Special kludge feature to save typing */
+ typedArg arg;
+
+ if (OSC_openBundle(buf, OSCTT_Immediately())) {
+ complain("Problem opening bundle: %s\n", OSC_errorMessage);
+ return;
+ }
+
+ arg.type = INT;
+ arg.datum.i = 0;
+ WriteMessage(buf, "/voices/0/tp/timbre_index", 1, &arg);
+
+ arg.type = FLOAT;
+ arg.datum.i = 0.0f;
+ WriteMessage(buf, "/voices/0/tm/goto", 1, &arg);
+
+ if (OSC_closeBundle(buf)) {
+ complain("Problem closing bundle: %s\n", OSC_errorMessage);
+ }
+
+ return;
+ }
+
+ while (!isspace(*p) && *p != '\0') p++;
+ if (isspace(*p)) {
+ *p = '\0';
+ p++;
+ }
+
+ thisArg = 0;
+ while (*p != '\0') {
+ /* flush leading whitespace */
+ while (isspace(*p)) p++;
+ if (*p == '\0') break;
+
+ if (*p == '"') {
+ /* A string argument: scan for close quotes */
+ p++;
+ args[thisArg].type = STRING;
+ args[thisArg].datum.s = p;
+
+ while (*p != '"') {
+ if (*p == '\0') {
+ complain("Unterminated quote mark: ignoring line\n");
+ return;
+ }
+ p++;
+ }
+ *p = '\0';
+ p++;
+ } else {
+ token = p;
+ while (!isspace(*p) && (*p != '\0')) p++;
+ if (isspace(*p)) {
+ *p = '\0';
+ p++;
+ }
+ args[thisArg] = ParseToken(token);
+ }
+ thisArg++;
+ if (thisArg >= MAX_ARGS) {
+ complain("Sorry, your message has more than MAX_ARGS (%d) arguments; ignoring the rest.\n",
+ MAX_ARGS);
+ break;
+ }
+ }
+
+ if (WriteMessage(buf, messageName, thisArg, args) != 0) {
+ complain("Problem sending message: %s\n", OSC_errorMessage);
+ }
+}
+
+typedArg ParseToken(char *token) {
+ char *p = token;
+ typedArg returnVal;
+
+ /* It might be an int, a float, or a string */
+
+ if (*p == '-') p++;
+
+ if (isdigit(*p) || *p == '.') {
+ while (isdigit(*p)) p++;
+ if (*p == '\0') {
+ returnVal.type = INT;
+ returnVal.datum.i = atoi(token);
+ return returnVal;
+ }
+ if (*p == '.') {
+ p++;
+ while (isdigit(*p)) p++;
+ if (*p == '\0') {
+ returnVal.type = FLOAT;
+ returnVal.datum.f = atof(token);
+ return returnVal;
+ }
+ }
+ }
+
+ returnVal.type = STRING;
+ returnVal.datum.s = token;
+ return returnVal;
+}
+
+int WriteMessage(OSCbuf *buf, char *messageName, int numArgs, typedArg *args) {
+ int j, returnVal;
+
+ returnVal = 0;
+
+#ifdef DEBUG
+ printf("WriteMessage: %s ", messageName);
+
+ for (j = 0; j < numArgs; j++) {
+ switch (args[j].type) {
+ case INT:
+ printf("%d ", args[j].datum.i);
+ break;
+
+ case FLOAT:
+ printf("%f ", args[j].datum.f);
+ break;
+
+ case STRING:
+ printf("%s ", args[j].datum.s);
+ break;
+
+ default:
+ fatal_error("Unrecognized arg type");
+ exit(5);
+ }
+ }
+ printf("\n");
+#endif
+
+ if (!useTypeTags) {
+ returnVal = OSC_writeAddress(buf, messageName);
+ if (returnVal) {
+ complain("Problem writing address: %s\n", OSC_errorMessage);
+ }
+ } else {
+ /* First figure out the type tags */
+ char typeTags[MAX_ARGS+2];
+ int i;
+
+ typeTags[0] = ',';
+
+ for (i = 0; i < numArgs; ++i) {
+ switch (args[i].type) {
+ case INT:
+ typeTags[i+1] = 'i';
+ break;
+
+ case FLOAT:
+ typeTags[i+1] = 'f';
+ break;
+
+ case STRING:
+ typeTags[i+1] = 's';
+ break;
+
+ default:
+ fatal_error("Unrecognized arg type");
+ exit(5);
+ }
+ }
+ typeTags[i+1] = '\0';
+
+ returnVal = OSC_writeAddressAndTypes(buf, messageName, typeTags);
+ if (returnVal) {
+ complain("Problem writing address: %s\n", OSC_errorMessage);
+ }
+ }
+
+ for (j = 0; j < numArgs; j++) {
+ switch (args[j].type) {
+ case INT:
+ if ((returnVal = OSC_writeIntArg(buf, args[j].datum.i)) != 0) {
+ return returnVal;
+ }
+ break;
+
+ case FLOAT:
+ if ((returnVal = OSC_writeFloatArg(buf, args[j].datum.f)) != 0) {
+ return returnVal;
+ }
+ break;
+
+ case STRING:
+ if ((returnVal = OSC_writeStringArg(buf, args[j].datum.s)) != 0) {
+ return returnVal;
+ }
+ break;
+
+ default:
+ fatal_error("Unrecognized arg type");
+ exit(5);
+ }
+ }
+
+ return returnVal;
+}
+
+void SendBuffer(void *htmsocket, OSCbuf *buf) {
+#ifdef DEBUG
+ printf("Sending buffer...\n");
+#endif
+ if (OSC_isBufferEmpty(buf)) return;
+ if (!OSC_isBufferDone(buf)) {
+ fatal_error("SendBuffer() called but buffer not ready!");
+ exit(5);
+ }
+ SendData(htmsocket, OSC_packetSize(buf), OSC_getPacket(buf));
+}
+
+void SendData(void *htmsocket, int size, char *data) {
+ if (!SendHTMSocket(htmsocket, size, data)) {
+ perror("Couldn't send out socket: ");
+ CloseHTMSocket(htmsocket);
+ exit(3);
+ }
+}
+
+void fatal_error(char *s) {
+ fprintf(stderr, "%s\n", s);
+ exit(4);
+}
+
+#include <stdarg.h>
+void complain(char *s, ...) {
+ va_list ap;
+ va_start(ap, s);
+ vfprintf(stderr, s, ap);
+ va_end(ap);
+}
+
+
+#ifdef COMPUTE_MESSAGE_SIZE
+ /* Unused code to find the size of a message */
+
+ /* Compute size */
+ size = SynthControl_effectiveStringLength(messageName);
+
+ for (j = 0; j < numArgs; j++) {
+ switch (args[j].type) {
+ case INT: case FLOAT:
+ size += 4;
+ break;
+
+ case STRING:
+ size += SynthControl_effectiveStringLength(args[j].datum.s);
+ break;
+
+ default:
+ fatal_error("Unrecognized token type");
+ exit(4);
+ }
+ }
+
+ if (!SynthControl_willMessageFit(buf, size)) {
+ complain("Message \"%s\" won't fit in buffer: dropping.", messageName);
+ return;
+ }
+#endif