Update of /cvsroot/pure-data/externals/OSCx/src In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv12318/src
Added Files: INVENTORY.txt Makefile.in OSC-common.h OSC-pattern-match.c OSC-pattern-match.h OSC.001 OSC.c OSC.dsp OSC.dsw OSCroute.c TODO.txt VERSION dumpOSC.c htmsocket.c htmsocket.h sendOSC.c Log Message: changed to single external style ...
--- NEW FILE: INVENTORY.txt --- OSC protocol inventory for OSC4PD
sendOSC, dumpOSC, OSCroute ========================== INCLUDES * typed and untyped packing of OSC messages * #bundle packing * transmission of OSC messages via UDP socket
* receive OSC messages on UDP socket * unpacking of typed and untyped OSC messages * #bundle unpacking
* static address resolution * pattern matching
OMITS * working with timetags * all advanced protocol features of documentation, typesigs, etc * connection oriented communication
--- NEW FILE: Makefile.in --- # current: all # pd_linux ############################### NAME=OSC EXT=o LIBS = -lm -lc LIBOSC = ../libOSC/libOSC.a DEFS= -Dunix
prefix=$(DESTDIR)/usr
# ----------------------- LINUX i386 -----------------------
# pd_linux: $(NAME).pd_linux
SFX=@pd_suffix@
.SUFFIXES: .$(SFX)
CFLAGS += $(DEFS) -DPD -DUNIX -O2 -funroll-loops -fomit-frame-pointer \ -Wall -W -Wshadow \ -Wno-unused -Wno-parentheses -Wno-switch
# where is your m_pd.h ??? INCLUDE = -I../../build/include
# LINUXEXTERNALS = htmsocket.o OSC-pattern-match.o sendOSC.o dumpOSC.o OSCroute.o # SOURCES = $(wildcard *.c) SOURCES = OSC-pattern-match.c OSC.c dumpOSC.c \ htmsocket.c OSCroute.c sendOSC.c TARGETS = $(SOURCES:.c=.o) EXTS=sendOSC.@pd_suffix@ dumpOSC.@pd_suffix@ OSCroute.@pd_suffix@ OSC.@pd_suffix@
all: $(EXTS) sendOSC.pd_linux: htmsocket.o sendOSC.o cc -Wl,-export_dynamic -shared -o $*.@pd_suffix@ *.o -lc -lm ../libOSC/libOSC.a
dumpOSC.pd_linux: dumpOSC.o cc -Wl,-export_dynamic -shared -o $*.@pd_suffix@ $*.o -lc -lm OSCroute.pd_linux: OSCroute.o OSC-pattern-match.o cc -Wl,-export_dynamic -shared -o $*.@pd_suffix@ $? -lc -lm
OSC.pd_linux: OSC.o cc -Wl,-export_dynamic -shared -o $*.@pd_suffix@ $? -lc -lm # $(LD) $(LDFLAGS) -o OSC.$(EXT) *.$(EXT) *.o $(LIBS) $(LIBOSC) # $(LD) $(LDFLAGS) -o OSC.$(EXT) *.$(EXT) $(LIBS) $(LIBOSC) $(TARGETS): %.o : %.c cc $(CFLAGS) $(INCLUDE) -c -o $*.o $*.c
# cc -c $(CFLAGS) OSC.c
# .c.pd_linux: # cc -O2 -Wall -DPD -fPIC $(LINUXCFLAGS) $(LINUXINCLUDE) -c *.c # ld -export_dynamic -shared -o $*.pd_linux $*.o $(LINUXEXTERNALS) $(LIBS) $(LIBOSC) # strip --strip-unneeded $*.pd_linux
# ----------------------------------------------------------
install-doc: @test -d $(prefix)/lib/pd/doc/5.reference || mkdir -p $(prefix)/lib/pd/doc/5.reference cp -r ../doc/* $(prefix)/lib/pd/doc/5.reference/
install: install-doc @test -d $(prefix)/lib/pd/extra || mkdir -p $(prefix)/lib/pd/extra install -m644 *.pd_linux $(prefix)/lib/pd/extra
clean: rm -rf *.$(EXT) *.@pd_suffix@
# ----------------------- Mac OS X (Darwin) -----------------------
pd_darwin: $(NAME).pd_darwin
SFX=.pd_darwin
.SUFFIXES: $(SFX)
DARWINCFLAGS = -DPD -DUNIX -DMACOSX -O2 \ -Wall -W -Wshadow -Wstrict-prototypes \ -Wno-unused -Wno-parentheses -Wno-switch
# where is your m_pd.h ??? DARWININCLUDE = -I../../../pd/src
DARWINEXTERNALS = htmsocket.o OSC-pattern-match.o sendOSC.o dumpOSC.o OSCroute.o
.c.pd_darwin: cc $(DARWINCFLAGS) $(DARWININCLUDE) -c *.c cc -bundle -bundle_loader /usr/local/pd/bin/pd -flat_namespace -o $*.pd_darwin $*.o $(DARWINEXTERNALS) $(LIBS) $(LIBOSC)
rm -f $*.o ../$*.pd_darwin ln -s $*/$*.pd_darwin ..
--- NEW FILE: OSC-common.h --- /* 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, ...);
--- NEW FILE: OSC-pattern-match.c --- /* 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 */ #ifdef UNIX #include <stdio.h> #endif
// #ifdef MACOSX // #include <stdio.h> // #endif
#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) {
// printf("OSC-pattern-match.c: pattern: %s, test: %s\n", pattern, test);
theWholePattern = pattern;
// post("pattern: %s, test: %s", pattern, test);
if(test[0] == '*') { return TRUE; }
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++; } } }
}
--- NEW FILE: OSC-pattern-match.h --- /* 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);
--- NEW FILE: OSC.001 --- # 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
--- NEW FILE: OSC.c --- /*
pd ------------- -- tweaks for Win32 www.zeggz.com/raf 13-April-2002
*/
#if HAVE_CONFIG_H #include <config.h> #endif
#include <m_pd.h> #include "OSC-common.h"
#define VERSION "0.2"
#ifndef OSC_API #define OSC_API #endif
typedef struct _OSC { t_object x_obj; } t_OSC;
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); */
static t_class* OSC_class;
static void* OSC_new(t_symbol* s) { t_OSC *x = (t_OSC *)pd_new(OSC_class); return (x); }
OSC_API void OSC_version (t_OSC *x) {
// 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(); }
OSC_API void OSC_setup(void) { 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__); }
--- NEW FILE: OSC.dsp --- # 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
--- NEW FILE: OSC.dsw --- 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> {{{ }}}
###############################################################################
--- NEW FILE: OSCroute.c --- /* 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
*/
#if HAVE_CONFIG_H #include <config.h> #endif
/* 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 #ifdef MACOSX #include <stdio.h> #endif #ifdef UNIX #include <stdio.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? t_int x_sendmode; // use pd internal sends instead of outlets char *x_prefixes[MAX_NUM]; void *x_outlets[MAX_NUM+1]; } 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("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: jdl 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) {
t_OSCroute *x = (t_OSCroute *)pd_new(OSCroute_class); // get memory for a new object & initialize
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->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++) { for (i = 0; i <= x->x_num; 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 jdl, win32: raf.\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"); // output on unmatched outlet jdl 20020908 if (argv[0].a_type == A_FLOAT) { outlet_float(x->x_outlets[x->x_num], argv[0].a_w.w_float); } else { post("* OSC-route: unrecognized atom type!"); } } // 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); outlet_anything(x->x_outlets[x->x_num], s, argc, argv); 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); } }
// output unmatched data on rightmost outlet a la normal 'route' object, jdl 20020908 if (!matchedAnything) { outlet_anything(x->x_outlets[x->x_num], s, argc, argv); }
}
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); } }
--- NEW FILE: TODO.txt ---
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 ?
-dynamic space allocation for message buffers.
-configure proper (autoconf)
changelog:
20020903: refixed MAXPDARG vs. MAX_ARGS bug causind sendOSC to crash with msgs longer than 5 argmuents. ?
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
--- NEW FILE: VERSION --- 0.2
--- NEW FILE: dumpOSC.c --- /* 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 */
#if HAVE_CONFIG_H #include <config.h> #endif
#include "m_pd.h" //#include "m_imp.h" #include "s_stuff.h" //#include "x_osc.h"
/* declarations */
// typedef void (*t_fdpollfn)(void *ptr, int fd); void sys_addpollfn(int fd, t_fdpollfn fn, void *ptr);
#if defined(__sgi) || defined(__linux) || defined(WIN32) || defined(MACOSX)
#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;
typedef unsigned long long osc_time_t;
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); Boolean dumpOSC_SendReply(char *buf, int n, void *clientDesc, int clientDescLenght, int fd); 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, (struct sockaddr *)&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 if(!dumpOSC_SendReply(mbuf, n, &x->x_server, clilen, sockfd)) { 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 */ if ((sockfd = socket(AF_INET, (udp ? SOCK_DGRAM : SOCK_STREAM), 0)) == -1) { 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 */ {
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("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 WriteTime(char* dst, osc_time_t osctime) { *(int32_t*)dst = htonl((int32_t)(osctime >> 32)); *(int32_t*)(dst+4) = htonl((int32_t)osctime); }
void WriteMode(char* dst) { *(int32_t*)dst = htonl(0); }
osc_time_t ReadTime(const char* src) { osc_time_t osctime = ntohl(*(int32_t*)src); return (osctime << 32) + ntohl(*(int32_t*)(src+4)); }
double TimeToSeconds(osc_time_t osctime) { return (double)osctime * 2.3283064365386962890625e-10 /* 1/2^32 */; }
int timeRound(double x) { return x >= 0.0 ? x+0.5 : x-0.5; } /* void WriteLogicalTime(char* dst) { static double startTime = -1.0; double sTime;
// Initialisierung der Startzeit. // Knnte effizienter (ohne 'if') auch irgendwo vorher passieren. // Knnte wahrscheinlich auch 0.0 sein. if (startTime < 0.0) { startTime = clock_getlogicaltime(); }
sTime = clock_gettimesince(startTime) * 0.001; *(int32_t*)dst = hton'K l((int32_t)sTime); *(int32_t*)(dst+4) = htonl((int32_t)(4294967296.0 * sTime)); } */
void WriteLogicalTime(char* dst) { double sTime = clock_gettimesince(19230720) / 1000.0; double tau = sTime - timeRound(sTime); //fprintf(stderr, "sSec = %f tau = %f\n", sTime, tau); *(int32_t*)dst = htonl((int32_t)(sTime)); *(int32_t*)(dst+4) = htonl((int32_t)(4294967296 * tau)); }
Boolean dumpOSC_SendReply(char *buf, int n, void *clientDesc, int clientDescLenght, int fd) { if((n == 24) && (strcmp(buf, "#time") == 0)) { osc_time_t t0, t1, t2; double dt0, dt1, dt2;
WriteMode(buf+6); t0 = ReadTime(buf+8); WriteLogicalTime(buf+16); t1 = ReadTime(buf+16); // reverse dt0 = TimeToSeconds(t0); // client time dt1 = TimeToSeconds(t1); // server time // fprintf(stderr, "%f\t%f\t%f\n", dt0, dt1, dt0 - dt1);
sendto(fd, buf, n, 0, (struct sockaddr *)clientDesc, clientDescLenght); return TRUE; } else { return FALSE; } }
//**********************
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 if ((n == 24) && (strcmp(buf, "#time") == 0)) { complain("Time message: %s\n :).\n", htm_error_string); return;
} 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 /* Martin Peach fix for negative floats: * was: SETFLOAT(mya+myargc,ntohl(*((int *) p))); * now is: */ SETFLOAT(mya+myargc,(signed)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 */
--- NEW FILE: htmsocket.c --- /* 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. */
#if HAVE_CONFIG_H #include <config.h> #endif
#ifdef MACOSX #include <string.h> #endif
#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; int oval = 1;
#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); // enable broadcast if(setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &oval, sizeof(int)) == -1) { perror("setsockopt"); }
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); // enable broadcast if(setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &oval, sizeof(int)) == -1) { perror("setsockopt"); }
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 if(close(o->sockfd) == -1) { perror("CloseHTMSocket::closesocket failed"); return; } #endif
free(o); }
--- NEW FILE: htmsocket.h --- /* 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);
--- NEW FILE: sendOSC.c --- /* 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
*/
#if HAVE_CONFIG_H #include <config.h> #endif
//#define VERSION "http://cnmat.berkeley.edu/OpenSoundControl/sendOSC-0.1.html" #define MAX_ARGS 2000 #define SC_BUFFER_SIZE 64000
/* 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 <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <ctype.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[MAX_ARGS]; 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("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 int 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