diff options
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 Binary files differnew file mode 100644 index 0000000..2cb0455 --- /dev/null +++ b/extra/OSC.dll 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 |