OSC-0.1/0000755002537200234200000000000011616511531012244 5ustar zmoelnigiemusersOSC-0.1/Makefile0000644002537200234200000003233011616511523013706 0ustar zmoelnigiemusers## Pd library template version 1.0.9 # For instructions on how to use this template, see: # http://puredata.info/docs/developer/MakefileTemplate # # the name of this library # must not contain any spaces or weird characters (as it's used for # filenames,...) LIBRARY_NAME = OSC # add your .c source files, one object per file, to the SOURCES # variable, help files will be included automatically, and for GUI # objects, the matching .tcl file too SOURCES = packOSC.c pipelist.c routeOSC.c unpackOSC.c # list all pd objects (i.e. myobject.pd) files here, and their helpfiles will # be included automatically PDOBJECTS = packOSCstream.pd unpackOSCstream.pd # example patches and related files, in the 'examples' subfolder EXAMPLES = # manuals and related files, in the 'manual' subfolder MANUAL = # if you want to include any other files in the source and binary tarballs, # list them here. This can be anything from header files, test patches, # documentation, etc. README.txt and LICENSE.txt are required and therefore # automatically included EXTRA_DIST = packingOSC.h HELPPATCHES = \ packOSC-help.pd \ packOSCstream-help.pd \ pipelist-help.pd routeOSC-help.pd \ unpackOSCstream-help.pd #------------------------------------------------------------------------------# # # things you might need to edit if you are using other C libraries # #------------------------------------------------------------------------------# # -I"$(PD_INCLUDE)" supports the header location for 0.43 ALL_CFLAGS = -I"$(PD_INCLUDE)" ALL_LDFLAGS = ALL_LIBS = #------------------------------------------------------------------------------# # # you shouldn't need to edit anything below here, if we did it right :) # #------------------------------------------------------------------------------# # these can be set from outside without (usually) breaking the build CFLAGS = -Wall -W -g LDFLAGS= LIBS= # get library version from meta file LIBRARY_VERSION = $(shell sed -n 's|^\#X text [0-9][0-9]* [0-9][0-9]* VERSION \(.*\);|\1|p' $(LIBRARY_NAME)-meta.pd) ALL_CFLAGS += -DPD -DVERSION='"$(LIBRARY_VERSION)"' PD_INCLUDE = $(PD_PATH)/include/pd # where to install the library, overridden below depending on platform prefix = /usr/local libdir = $(prefix)/lib pkglibdir = $(libdir)/pd-externals objectsdir = $(pkglibdir) INSTALL = install INSTALL_PROGRAM = $(INSTALL) -p -m 644 INSTALL_DATA = $(INSTALL) -p -m 644 INSTALL_DIR = $(INSTALL) -p -m 755 -d ALLSOURCES := $(SOURCES) $(SOURCES_android) $(SOURCES_cygwin) $(SOURCES_macosx) \ $(SOURCES_iphoneos) $(SOURCES_linux) $(SOURCES_windows) DISTDIR=$(LIBRARY_NAME)-$(LIBRARY_VERSION) ORIGDIR=pd-$(LIBRARY_NAME:~=)_$(LIBRARY_VERSION) UNAME := $(shell uname -s) ifeq ($(UNAME),Darwin) CPU := $(shell uname -p) ifeq ($(CPU),arm) # iPhone/iPod Touch SOURCES += $(SOURCES_iphoneos) EXTENSION = pd_darwin OS = iphoneos PD_PATH = /Applications/Pd-extended.app/Contents/Resources IPHONE_BASE=/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin CC=$(IPHONE_BASE)/gcc CPP=$(IPHONE_BASE)/cpp CXX=$(IPHONE_BASE)/g++ ISYSROOT = -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.0.sdk IPHONE_CFLAGS = -miphoneos-version-min=3.0 $(ISYSROOT) -arch armv6 OPT_CFLAGS = -fast -funroll-loops -fomit-frame-pointer ALL_CFLAGS := $(IPHONE_CFLAGS) $(ALL_CFLAGS) ALL_LDFLAGS += -arch armv6 -bundle -undefined dynamic_lookup $(ISYSROOT) ALL_LIBS += -lc STRIP = strip -x DISTBINDIR=$(DISTDIR)-$(OS) else # Mac OS X SOURCES += $(SOURCES_macosx) EXTENSION = pd_darwin OS = macosx PD_PATH = /Applications/Pd-extended.app/Contents/Resources OPT_CFLAGS = -ftree-vectorize -ftree-vectorizer-verbose=2 -fast # build universal 32-bit on 10.4 and 32/64 on newer ifeq ($(shell uname -r | sed 's|\([0-9][0-9]*\)\.[0-9][0-9]*\.[0-9][0-9]*|\1|'), 8) FAT_FLAGS = -arch ppc -arch i386 -mmacosx-version-min=10.4 else FAT_FLAGS = -arch ppc -arch i386 -arch x86_64 -mmacosx-version-min=10.4 SOURCES += $(SOURCES_iphoneos) endif ALL_CFLAGS += $(FAT_FLAGS) -fPIC -I/sw/include ALL_LDFLAGS += $(FAT_FLAGS) -bundle -undefined dynamic_lookup -L/sw/lib # if the 'pd' binary exists, check the linking against it to aid with stripping ALL_LDFLAGS += $(shell test -e $(PD_PATH)/bin/pd && echo -bundle_loader $(PD_PATH)/bin/pd) ALL_LIBS += -lc STRIP = strip -x DISTBINDIR=$(DISTDIR)-$(OS) # install into ~/Library/Pd on Mac OS X since /usr/local isn't used much pkglibdir=$(HOME)/Library/Pd endif endif # Tho Android uses Linux, we use this fake uname to provide an easy way to # setup all this things needed to cross-compile for Android using the NDK ifeq ($(UNAME),ANDROID) CPU := arm SOURCES += $(SOURCES_android) EXTENSION = pd_linux OS = android PD_PATH = /usr NDK_BASE := /usr/local/android-ndk NDK_PLATFORM_VERSION := 5 NDK_SYSROOT=$(NDK_BASE)/platforms/android-$(NDK_PLATFORM_VERSION)/arch-arm NDK_UNAME := $(shell uname -s | tr '[A-Z]' '[a-z]') NDK_TOOLCHAIN_BASE=$(NDK_BASE)/toolchains/arm-linux-androideabi-4.4.3/prebuilt/$(NDK_UNAME)-x86 CC := $(NDK_TOOLCHAIN_BASE)/bin/arm-linux-androideabi-gcc --sysroot=$(NDK_SYSROOT) OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer CFLAGS += LDFLAGS += -Wl,--export-dynamic -shared LIBS += -lc STRIP := $(NDK_TOOLCHAIN_BASE)/bin/arm-linux-androideabi-strip \ --strip-unneeded -R .note -R .comment DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m) endif ifeq ($(UNAME),Linux) CPU := $(shell uname -m) SOURCES += $(SOURCES_linux) EXTENSION = pd_linux OS = linux PD_PATH = /usr OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer ALL_CFLAGS += -fPIC ALL_LDFLAGS += -Wl,--export-dynamic -shared -fPIC ALL_LIBS += -lc STRIP = strip --strip-unneeded -R .note -R .comment DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m) endif ifeq ($(UNAME),GNU) # GNU/Hurd, should work like GNU/Linux for basically all externals CPU := $(shell uname -m) SOURCES += $(SOURCES_linux) EXTENSION = pd_linux OS = linux PD_PATH = /usr OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer ALL_CFLAGS += -fPIC ALL_LDFLAGS += -Wl,--export-dynamic -shared -fPIC ALL_LIBS += -lc STRIP = strip --strip-unneeded -R .note -R .comment DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m) endif ifeq ($(UNAME),GNU/kFreeBSD) # Debian GNU/kFreeBSD, should work like GNU/Linux for basically all externals CPU := $(shell uname -m) SOURCES += $(SOURCES_linux) EXTENSION = pd_linux OS = linux PD_PATH = /usr OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer ALL_CFLAGS += -fPIC ALL_LDFLAGS += -Wl,--export-dynamic -shared -fPIC ALL_LIBS += -lc STRIP = strip --strip-unneeded -R .note -R .comment DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m) endif ifeq (CYGWIN,$(findstring CYGWIN,$(UNAME))) CPU := $(shell uname -m) SOURCES += $(SOURCES_cygwin) EXTENSION = dll OS = cygwin PD_PATH = $(cygpath $(PROGRAMFILES))/pd OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer ALL_CFLAGS += ALL_LDFLAGS += -Wl,--export-dynamic -shared -L"$(PD_PATH)/src" -L"$(PD_PATH)/bin" ALL_LIBS += -lc -lpd STRIP = strip --strip-unneeded -R .note -R .comment DISTBINDIR=$(DISTDIR)-$(OS) endif ifeq (MINGW,$(findstring MINGW,$(UNAME))) CPU := $(shell uname -m) SOURCES += $(SOURCES_windows) EXTENSION = dll OS = windows PD_PATH = $(shell cd "$(PROGRAMFILES)"/pd && pwd) OPT_CFLAGS = -O3 -funroll-loops -fomit-frame-pointer ALL_CFLAGS += -mms-bitfields ALL_LDFLAGS += -s -shared -Wl,--enable-auto-import ALL_LIBS += -L"$(PD_PATH)/src" -L"$(PD_PATH)/bin" -L"$(PD_PATH)/obj" -lpd -lwsock32 -lkernel32 -luser32 -lgdi32 STRIP = strip --strip-unneeded -R .note -R .comment DISTBINDIR=$(DISTDIR)-$(OS) endif # in case somebody manually set the HELPPATCHES above HELPPATCHES ?= $(SOURCES:.c=-help.pd) $(PDOBJECTS:.pd=-help.pd) CFLAGS += $(OPT_CFLAGS) ALL_CFLAGS := $(ALL_CFLAGS) $(CFLAGS) ALL_LDFLAGS := $(LDFLAGS) $(ALL_LDFLAGS) ALL_LIBS := $(LIBS) $(ALL_LIBS) .PHONY = install libdir_install single_install install-doc install-exec install-examples install-manual clean dist etags $(LIBRARY_NAME) all: $(SOURCES:.c=.$(EXTENSION)) %.o: %.c $(CC) $(ALL_CFLAGS) -o "$*.o" -c "$*.c" %.$(EXTENSION): %.o $(CC) $(ALL_LDFLAGS) -o "$*.$(EXTENSION)" "$*.o" $(ALL_LIBS) chmod a-x "$*.$(EXTENSION)" # this links everything into a single binary file $(LIBRARY_NAME): $(SOURCES:.c=.o) $(LIBRARY_NAME).o $(CC) $(ALL_LDFLAGS) -o $(LIBRARY_NAME).$(EXTENSION) $(SOURCES:.c=.o) $(LIBRARY_NAME).o $(ALL_LIBS) chmod a-x $(LIBRARY_NAME).$(EXTENSION) install: libdir_install # The meta and help files are explicitly installed to make sure they are # actually there. Those files are not optional, then need to be there. libdir_install: $(SOURCES:.c=.$(EXTENSION)) install-doc install-examples install-manual $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) $(INSTALL_DATA) $(LIBRARY_NAME)-meta.pd \ $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) test -z "$(strip $(SOURCES))" || (\ $(INSTALL_PROGRAM) $(SOURCES:.c=.$(EXTENSION)) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) && \ $(STRIP) $(addprefix $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/,$(SOURCES:.c=.$(EXTENSION)))) test -z "$(strip $(shell ls $(SOURCES:.c=.tcl)))" || \ $(INSTALL_DATA) $(shell ls $(SOURCES:.c=.tcl)) \ $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) test -z "$(strip $(PDOBJECTS))" || \ $(INSTALL_DATA) $(PDOBJECTS) \ $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) # install library linked as single binary single_install: $(LIBRARY_NAME) install-doc install-exec $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) $(INSTALL_PROGRAM) $(LIBRARY_NAME).$(EXTENSION) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) $(STRIP) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/$(LIBRARY_NAME).$(EXTENSION) install-doc: $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) test -z "$(strip $(SOURCES) $(PDOBJECTS))" || \ $(INSTALL_DATA) $(HELPPATCHES) \ $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) $(INSTALL_DATA) README.txt $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/README.txt $(INSTALL_DATA) LICENSE.txt $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/LICENSE.txt install-examples: test -z "$(strip $(EXAMPLES))" || \ $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/examples && \ for file in $(EXAMPLES); do \ $(INSTALL_DATA) examples/$$file $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/examples; \ done install-manual: test -z "$(strip $(MANUAL))" || \ $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/manual && \ for file in $(MANUAL); do \ $(INSTALL_DATA) manual/$$file $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/manual; \ done clean: -rm -f -- $(SOURCES:.c=.o) $(SOURCES_LIB:.c=.o) -rm -f -- $(SOURCES:.c=.$(EXTENSION)) -rm -f -- $(LIBRARY_NAME).o -rm -f -- $(LIBRARY_NAME).$(EXTENSION) distclean: clean -rm -f -- $(DISTBINDIR).tar.gz -rm -rf -- $(DISTBINDIR) -rm -f -- $(DISTDIR).tar.gz -rm -rf -- $(DISTDIR) -rm -f -- $(ORIGDIR).tar.gz -rm -rf -- $(ORIGDIR) $(DISTBINDIR): $(INSTALL_DIR) $(DISTBINDIR) libdir: all $(DISTBINDIR) $(INSTALL_DATA) $(LIBRARY_NAME)-meta.pd $(DISTBINDIR) $(INSTALL_DATA) $(SOURCES) $(DISTBINDIR) $(INSTALL_DATA) $(HELPPATCHES) $(DISTBINDIR) test -z "$(strip $(EXTRA_DIST))" || \ $(INSTALL_DATA) $(EXTRA_DIST) $(DISTBINDIR) # tar --exclude-vcs -czpf $(DISTBINDIR).tar.gz $(DISTBINDIR) $(DISTDIR): $(INSTALL_DIR) $(DISTDIR) $(ORIGDIR): $(INSTALL_DIR) $(ORIGDIR) dist: $(DISTDIR) $(INSTALL_DATA) Makefile $(DISTDIR) $(INSTALL_DATA) README.txt $(DISTDIR) $(INSTALL_DATA) LICENSE.txt $(DISTDIR) $(INSTALL_DATA) $(LIBRARY_NAME)-meta.pd $(DISTDIR) test -z "$(strip $(ALLSOURCES))" || \ $(INSTALL_DATA) $(ALLSOURCES) $(DISTDIR) test -z "$(strip $(shell ls $(ALLSOURCES:.c=.tcl)))" || \ $(INSTALL_DATA) $(shell ls $(ALLSOURCES:.c=.tcl)) $(DISTDIR) test -z "$(strip $(PDOBJECTS))" || \ $(INSTALL_DATA) $(PDOBJECTS) $(DISTDIR) test -z "$(strip $(HELPPATCHES))" || \ $(INSTALL_DATA) $(HELPPATCHES) $(DISTDIR) test -z "$(strip $(EXTRA_DIST))" || \ $(INSTALL_DATA) $(EXTRA_DIST) $(DISTDIR) test -z "$(strip $(EXAMPLES))" || \ $(INSTALL_DIR) $(DISTDIR)/examples && \ for file in $(EXAMPLES); do \ $(INSTALL_DATA) examples/$$file $(DISTDIR)/examples; \ done test -z "$(strip $(MANUAL))" || \ $(INSTALL_DIR) $(DISTDIR)/manual && \ for file in $(MANUAL); do \ $(INSTALL_DATA) manual/$$file $(DISTDIR)/manual; \ done tar --exclude-vcs -czpf $(DISTDIR).tar.gz $(DISTDIR) # make a Debian source package dpkg-source: debclean make distclean dist mv $(DISTDIR) $(ORIGDIR) tar --exclude-vcs -czpf ../$(ORIGDIR).orig.tar.gz $(ORIGDIR) rm -f -- $(DISTDIR).tar.gz rm -rf -- $(DISTDIR) $(ORIGDIR) cd .. && dpkg-source -b $(LIBRARY_NAME) etags: etags *.h $(SOURCES) ../../pd/src/*.[ch] /usr/include/*.h /usr/include/*/*.h showsetup: @echo "CFLAGS: $(CFLAGS)" @echo "LDFLAGS: $(LDFLAGS)" @echo "LIBS: $(LIBS)" @echo "ALL_CFLAGS: $(ALL_CFLAGS)" @echo "ALL_LDFLAGS: $(ALL_LDFLAGS)" @echo "ALL_LIBS: $(ALL_LIBS)" @echo "PD_INCLUDE: $(PD_INCLUDE)" @echo "PD_PATH: $(PD_PATH)" @echo "objectsdir: $(objectsdir)" @echo "LIBRARY_NAME: $(LIBRARY_NAME)" @echo "LIBRARY_VERSION: $(LIBRARY_VERSION)" @echo "SOURCES: $(SOURCES)" @echo "PDOBJECTS: $(PDOBJECTS)" @echo "ALLSOURCES: $(ALLSOURCES)" @echo "UNAME: $(UNAME)" @echo "CPU: $(CPU)" @echo "pkglibdir: $(pkglibdir)" @echo "DISTDIR: $(DISTDIR)" @echo "ORIGDIR: $(ORIGDIR)" OSC-0.1/README.txt0000644002537200234200000000232311616510704013743 0ustar zmoelnigiemusersOpenSoundControl (OSC) for Pd ============================= a collection of Pd objectclasses for OSC-messages. these objects only convert between Pd-messages and OSC-messages (binary format), so you will need a separate set of objects that implement the transport (OSI-Layer 4), for instance [udpsend]/[udpreceive] for sending OSC over UDP. Author: Martin Peach objectclasses - [packOSC] convert a Pd-message to an OSC (binary) message (useful if you want to transmit OSC over UDP or other protocols that have the concept of variable length packets) - [unpackOSC] convert an OSC (binary) message to a Pd-message (useful if you want to transmit OSC over UDP or other protocols that have the concept of variable length packets) - [routeOSC] route OSC-like Pd-messages according to the first element in the path - [pipelist] delay lists (useful if you want to respect timestamps) - [packOSCstream] convert a Pd-message to an OSC (binary) message suitable for streaming transport (useful if you want to transmit OSC over TCP/IP or a serial line) - [unpackOSCstream] convert an OSC (binary) message suitable for streaming transport to a Pd-message (useful if you want to transmit OSC over TCP/IP or a serial line) OSC-0.1/LICENSE.txt0000644002537200234200000000133211616504143014067 0ustar zmoelnigiemusers OpenSoundControl for Pure data Copyright (C) 2006-2011 Martin Peach This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . OSC-0.1/OSC-meta.pd0000644002537200234200000000030411616502255014141 0ustar zmoelnigiemusers#N canvas 18 212 200 200 10; #N canvas 28 50 420 300 META 1; #X text 13 61 NAME OSC; #X text 13 85 VERSION 0.1; #X text 13 129 AUTHOR Martin Peach; #X text 19 189 NOTE:; #X restore 10 10 pd META; OSC-0.1/packOSC.c0000644002537200234200000013063311616502333013701 0ustar zmoelnigiemusers/* packOSC is like sendOSC but outputs a list of floats which are the bytes making up the OSC packet. */ /* This allows for the separation of the protocol and its transport. */ /* Started by Martin Peach 20060403 */ /* 20060425 version independent of libOSC */ /* 20070620 added packOSC_path and packOSC_anything methods by zmoelnig */ /* packOSC.c makes extensive use of code from OSC-client.c and sendOSC.c */ /* as well as some from OSC-timetag.c. These files have the following header: */ /* Written by Matt Wright, The Center for New Music and Audio Technologies, University of California, Berkeley. Copyright (c) 1996,97,98,99,2000,01,02,03 The Regents of the University of California (Regents). Permission to use, copy, modify, distribute, and distribute modified versions of this software and its documentation without fee and without a signed licensing agreement, is hereby granted, provided that the above copyright notice, this paragraph and the following two paragraphs appear in all copies, modifications, and distributions. IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. The OSC webpage is http://cnmat.cnmat.berkeley.edu/OpenSoundControl */ #define SC_BUFFER_SIZE 64000 #include "packingOSC.h" /* This is from OSC-client.h :*/ /* 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. */ /* OSC_timeTag.h: library for manipulating OSC time tags Matt Wright, 5/29/97 Time tags in OSC have the same format as in NTP: 64 bit fixed point, with the top 32 bits giving number of seconds sinve midnight 1/1/1900 and the bottom 32 bits giving fractional parts of a second. We represent this by an 8-byte unsigned long if possible, or else a struct. NB: On many architectures with 8-byte ints, it's illegal (like maybe a bus error) to dereference a pointer to an 8 byte int that's not 8-byte aligned. */ /* Return the time tag 0x0000000000000001, indicating to the receiving device that it should process the message immediately. */ static OSCTimeTag OSCTT_Immediately(void); static OSCTimeTag OSCTT_Infinite(void); static OSCTimeTag OSCTT_CurrentTimePlusOffset(uint4 offset); /* The int4byte type has to be a 4-byte integer. You may have to change this to long or something else on your system. */ typedef int int4byte; /* 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 */ size_t 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; typedef struct { enum {INT_osc, FLOAT_osc, STRING_osc, BLOB_osc, NOTYPE_osc} type; union { int i; float f; char *s; } datum; } typedArg; /* 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 */ static int OSC_strlen(char *s); static int OSC_padString(char *dest, char *str); static int OSC_padStringWithAnExtraStupidComma(char *dest, char *str); static int OSC_WriteStringPadding(char *dest, int i); static int OSC_WriteBlobPadding(char *dest, int i); static int CheckTypeTag(OSCbuf *buf, char expectedType); /* 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.) */ static void OSC_initBuffer(OSCbuf *buf, size_t 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. */ static void OSC_resetBuffer(OSCbuf *buf); /* Is the buffer empty? (I.e., would it be stupid to send the buffer contents to the synth?) */ static int OSC_isBufferEmpty(OSCbuf *buf); /* How much space is left in the buffer? */ static size_t OSC_freeSpaceInBuffer(OSCbuf *buf); /* Does the buffer contain a valid OSC packet? (Returns nonzero if yes.) */ static 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.) */ static char *OSC_getPacket(OSCbuf *buf); static int OSC_packetSize(OSCbuf *buf); static int OSC_CheckOverflow(OSCbuf *buf, size_t bytesNeeded); /* 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_writeIntArg() OSC_writeStringArg() OSC_writeNullArg() - Now your message is complete; you can send out the buffer or you can add another message to it. */ static int OSC_openBundle(OSCbuf *buf, OSCTimeTag tt); static int OSC_closeBundle(OSCbuf *buf); static int OSC_writeAddress(OSCbuf *buf, char *name); static int OSC_writeAddressAndTypes(OSCbuf *buf, char *name, char *types); static int OSC_writeFloatArg(OSCbuf *buf, float arg); static int OSC_writeIntArg(OSCbuf *buf, int4byte arg); static int OSC_writeBlobArg(OSCbuf *buf, typedArg *arg, size_t nArgs); static int OSC_writeStringArg(OSCbuf *buf, char *arg); static int OSC_writeNullArg(OSCbuf *buf, char type); /* 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. */ static int OSC_effectiveStringLength(char *string); static t_class *packOSC_class; typedef struct _packOSC { t_object x_obj; t_int x_typetags; /* typetag flag */ t_int x_timeTagOffset; int x_bundle; /* bundle open flag */ OSCbuf x_oscbuf[1]; /* OSCbuffer */ t_outlet *x_bdpthout; /* bundle-depth floatoutlet */ t_outlet *x_listout; /* OSC packet list ouput */ size_t x_buflength; /* number of elements in x_bufferForOSCbuf and x_bufferForOSClist */ char *x_bufferForOSCbuf; /*[SC_BUFFER_SIZE];*/ t_atom *x_bufferForOSClist; /*[SC_BUFFER_SIZE];*/ char *x_prefix; } t_packOSC; static void *packOSC_new(void); static void packOSC_path(t_packOSC *x, t_symbol*s); static void packOSC_openbundle(t_packOSC *x); static void packOSC_closebundle(t_packOSC *x); static void packOSC_settypetags(t_packOSC *x, t_floatarg f); static void packOSC_setbufsize(t_packOSC *x, t_floatarg f); static void packOSC_setTimeTagOffset(t_packOSC *x, t_floatarg f); static void packOSC_sendtyped(t_packOSC *x, t_symbol *s, int argc, t_atom *argv); static void packOSC_send_type_forced(t_packOSC *x, t_symbol *s, int argc, t_atom *argv); static void packOSC_send(t_packOSC *x, t_symbol *s, int argc, t_atom *argv); static void packOSC_anything(t_packOSC *x, t_symbol *s, int argc, t_atom *argv); static void packOSC_free(t_packOSC *x); void packOSC_setup(void); static typedArg packOSC_parseatom(t_atom *a); static typedArg packOSC_forceatom(t_atom *a, char ctype); static typedArg packOSC_blob(t_atom *a); static int packOSC_writetypedmessage(t_packOSC *x, OSCbuf *buf, char *messageName, int numArgs, typedArg *args, char *typeStr); static int packOSC_writemessage(t_packOSC *x, OSCbuf *buf, char *messageName, int numArgs, typedArg *args); static void packOSC_sendbuffer(t_packOSC *x); static void *packOSC_new(void) { t_packOSC *x = (t_packOSC *)pd_new(packOSC_class); x->x_typetags = 1; /* set typetags to 1 by default */ x->x_bundle = 0; /* bundle is closed */ x->x_buflength = SC_BUFFER_SIZE; x->x_bufferForOSCbuf = (char *)getbytes(sizeof(char)*x->x_buflength); if(x->x_bufferForOSCbuf == NULL) error("packOSC: unable to allocate %lu bytes for x_bufferForOSCbuf", (long)(sizeof(char)*x->x_buflength)); x->x_bufferForOSClist = (t_atom *)getbytes(sizeof(t_atom)*x->x_buflength); if(x->x_bufferForOSClist == NULL) error("packOSC: unable to allocate %lu bytes for x_bufferForOSClist", (long)(sizeof(t_atom)*x->x_buflength)); if (x->x_oscbuf != NULL) OSC_initBuffer(x->x_oscbuf, x->x_buflength, x->x_bufferForOSCbuf); x->x_listout = outlet_new(&x->x_obj, &s_list); x->x_bdpthout = outlet_new(&x->x_obj, &s_float); x->x_timeTagOffset = -1; /* immediately */ return (x); } static void packOSC_path(t_packOSC *x, t_symbol*s) { /* Set a default prefix to the OSC path */ if(s == gensym("")) { x->x_prefix = 0; return; } if ((*s->s_name) != '/') { pd_error(x, "packOSC: bad path: '%s'", s->s_name); return; } x->x_prefix = s->s_name; } static void packOSC_openbundle(t_packOSC *x) { int result; if (x->x_timeTagOffset == -1) result = OSC_openBundle(x->x_oscbuf, OSCTT_Immediately()); else result = OSC_openBundle(x->x_oscbuf, OSCTT_CurrentTimePlusOffset((uint4)x->x_timeTagOffset)); if (result != 0) { /* reset the buffer */ OSC_initBuffer(x->x_oscbuf, x->x_buflength, x->x_bufferForOSCbuf); x->x_bundle = 0; } else x->x_bundle = 1; outlet_float(x->x_bdpthout, (float)x->x_oscbuf->bundleDepth); } static void packOSC_closebundle(t_packOSC *x) { if (OSC_closeBundle(x->x_oscbuf)) { error("packOSC: Problem closing bundle."); 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)) { packOSC_sendbuffer(x); OSC_initBuffer(x->x_oscbuf, x->x_buflength, x->x_bufferForOSCbuf); x->x_bundle = 0; return; } } static void packOSC_settypetags(t_packOSC *x, t_floatarg f) { x->x_typetags = (f != 0)?1:0; post("packOSC: setting typetags %d", x->x_typetags); } static void packOSC_setbufsize(t_packOSC *x, t_floatarg f) { if (x->x_bufferForOSCbuf != NULL) freebytes((void *)x->x_bufferForOSCbuf, sizeof(char)*x->x_buflength); if (x->x_bufferForOSClist != NULL) freebytes((void *)x->x_bufferForOSClist, sizeof(t_atom)*x->x_buflength); post("packOSC: bufsize arg is %f (%lu)", f, (long)f); x->x_buflength = (long)f; x->x_bufferForOSCbuf = (char *)getbytes(sizeof(char)*x->x_buflength); if(x->x_bufferForOSCbuf == NULL) error("packOSC unable to allocate %lu bytes for x_bufferForOSCbuf", (long)(sizeof(char)*x->x_buflength)); x->x_bufferForOSClist = (t_atom *)getbytes(sizeof(t_atom)*x->x_buflength); if(x->x_bufferForOSClist == NULL) error("packOSC unable to allocate %lu bytes for x_bufferForOSClist", (long)(sizeof(t_atom)*x->x_buflength)); OSC_initBuffer(x->x_oscbuf, x->x_buflength, x->x_bufferForOSCbuf); post("packOSC: bufsize is now %d",x->x_buflength); } static void packOSC_setTimeTagOffset(t_packOSC *x, t_floatarg f) { x->x_timeTagOffset = (t_int)f; } /* this is the real and only sending routine now, for both typed and */ /* undtyped mode. */ static void packOSC_sendtyped(t_packOSC *x, t_symbol *s, int argc, t_atom *argv) { char messageName[MAXPDSTRING]; unsigned int nTypeTags = 0, typeStrTotalSize = 0; unsigned int argsSize = sizeof(typedArg)*argc; char* typeStr = NULL; /* might not be used */ typedArg* args = (typedArg*)getbytes(argsSize); unsigned int i, nTagsWithData, nArgs, blobCount; unsigned int m, j, k; char c; if (args == NULL) { error("packOSC: unable to allocate %lu bytes for args", (long)argsSize); return; } messageName[0] = '\0'; /* empty */ if(x->x_prefix) /* if there is a prefix, prefix it to the path */ { size_t len = strlen(x->x_prefix); if(len >= MAXPDSTRING) len = MAXPDSTRING-1; strncpy(messageName, x->x_prefix, MAXPDSTRING); atom_string(&argv[0], messageName+len, (unsigned)(MAXPDSTRING-len)); } else atom_string(&argv[0], messageName, MAXPDSTRING); /* the OSC address string */ if (x->x_typetags & 2) { /* second arg is typestring */ /* we need to find out how long the type string is before we copy it*/ nTypeTags = (unsigned int)strlen(atom_getsymbol(&argv[1])->s_name); typeStrTotalSize = nTypeTags + 2; typeStr = (char*)getzbytes(typeStrTotalSize); if (typeStr == NULL) { error("packOSC: unable to allocate %u bytes for typeStr", nTypeTags); return; } typeStr[0] = ','; atom_string(&argv[1], &typeStr[1], typeStrTotalSize); #ifdef DEBUG post("typeStr: %s, nTypeTags %lu", typeStr, nTypeTags); #endif nArgs = argc-2; for (m = nTagsWithData = blobCount = 0; m < nTypeTags; ++m) { #ifdef DEBUG post("typeStr[%d] %c", m+1, typeStr[m+1]); #endif if ((c = typeStr[m+1]) == 0) break; if (!(c == 'T' || c == 'F' || c == 'N' || c == 'I')) { ++nTagsWithData; /* anything other than these tags have at least one data byte */ /* OSC-blob An int32 size count, followed by that many 8-bit bytes of arbitrary binary data, followed by 0-3 additional zero bytes to make the total number of bits a multiple of 32. */ if (c == 'b') blobCount++; /* b probably has more than one byte, so set a flag */ } } if (((blobCount == 0)&&(nTagsWithData != nArgs)) || ((blobCount != 0)&&(nTagsWithData > nArgs))) { error("packOSC: Tags count %d doesn't match argument count %d", nTagsWithData, nArgs); goto cleanup; } if (blobCount > 1) { error("packOSC: Only one blob per packet at the moment..."); goto cleanup; } for (j = k = 0; j < m; ++j) /* m is the number of tags */ { c = typeStr[j+1]; if (c == 'b') { /* A blob has to be the last item, until we get more elaborate. */ if (j != m-1) { error("packOSC: Since I don't know how big the blob is, Blob must be the last item in the list"); goto cleanup; } /* Pack all the remaining arguments as a blob */ for (; k < nArgs; ++k) { args[k] = packOSC_blob(&argv[k+2]); } } else if (!(c == 'T' || c == 'F' || c == 'N' || c == 'I')) /* not no data */ { args[k] = packOSC_forceatom(&argv[k+2], c); ++k; } } if(packOSC_writetypedmessage(x, x->x_oscbuf, messageName, nArgs, args, typeStr)) { error("packOSC: usage error, write-msg failed."); goto cleanup; } } else { for (i = 0; i < (unsigned)(argc-1); i++) { args[i] = packOSC_parseatom(&argv[i+1]); #ifdef DEBUG switch (args[i].type) { case INT_osc: post("packOSC: cell-cont: %d\n", args[i].datum.i); break; case FLOAT_osc: post("packOSC: cell-cont: %f\n", args[i].datum.f); break; case STRING_osc: post("packOSC: cell-cont: %s\n", args[i].datum.s); break; case NOTYPE_osc: post("packOSC: unknown type\n"); break; } post("packOSC: type-id: %d\n", args[i].type); #endif } if(packOSC_writemessage(x, x->x_oscbuf, messageName, i, args)) { error("packOSC: usage error, write-msg failed."); goto cleanup; } } if(!x->x_bundle) { packOSC_sendbuffer(x); OSC_initBuffer(x->x_oscbuf, x->x_buflength, x->x_bufferForOSCbuf); } cleanup: if (typeStr != NULL) freebytes(typeStr, typeStrTotalSize); if (args != NULL) freebytes(args, argsSize); } static void packOSC_send_type_forced(t_packOSC *x, t_symbol *s, int argc, t_atom *argv) { /* typetags are the argument following the OSC path */ x->x_typetags |= 2;/* tell packOSC_sendtyped to use the specified typetags... */ packOSC_sendtyped(x, s, argc, argv); x->x_typetags &= ~2;/* ...this time only */ } static void packOSC_send(t_packOSC *x, t_symbol *s, int argc, t_atom *argv) { if(!argc) { post("packOSC: not sending empty message."); return; } packOSC_sendtyped(x, s, argc, argv); } static void packOSC_anything(t_packOSC *x, t_symbol *s, int argc, t_atom *argv) { /* If the message starts with '/', assume it's an OSC path and send it */ t_atom*ap = 0; if ((*s->s_name)!='/') { pd_error(x, "packOSC: bad path: '%s'", s->s_name); return; } ap = (t_atom*)getbytes((argc+1)*sizeof(t_atom)); SETSYMBOL(ap, s); memcpy(ap+1, argv, argc * sizeof(t_atom)); packOSC_send(x, gensym("send"), argc+1, ap); freebytes(ap, (argc+1)*sizeof(t_atom)); } static void packOSC_free(t_packOSC *x) { if (x->x_bufferForOSCbuf != NULL) freebytes((void *)x->x_bufferForOSCbuf, sizeof(char)*x->x_buflength); if (x->x_bufferForOSClist != NULL) freebytes((void *)x->x_bufferForOSClist, sizeof(t_atom)*x->x_buflength); } void packOSC_setup(void) { packOSC_class = class_new(gensym("packOSC"), (t_newmethod)packOSC_new, (t_method)packOSC_free, sizeof(t_packOSC), 0, A_DEFFLOAT, 0); class_addmethod(packOSC_class, (t_method)packOSC_path, gensym("prefix"), A_DEFSYM, 0); class_addmethod(packOSC_class, (t_method)packOSC_settypetags, gensym("typetags"), A_DEFFLOAT, 0); class_addmethod(packOSC_class, (t_method)packOSC_setbufsize, gensym("bufsize"), A_DEFFLOAT, 0); class_addmethod(packOSC_class, (t_method)packOSC_setTimeTagOffset, gensym("timetagoffset"), A_DEFFLOAT, 0); class_addmethod(packOSC_class, (t_method)packOSC_send, gensym("send"), A_GIMME, 0); class_addmethod(packOSC_class, (t_method)packOSC_send, gensym("senduntyped"), A_GIMME, 0); class_addmethod(packOSC_class, (t_method)packOSC_send_type_forced, gensym("sendtyped"), A_GIMME, 0); class_addmethod(packOSC_class, (t_method)packOSC_openbundle, gensym("["), 0, 0); class_addmethod(packOSC_class, (t_method)packOSC_closebundle, gensym("]"), 0, 0); class_addanything(packOSC_class, (t_method)packOSC_anything); } static typedArg packOSC_parseatom(t_atom *a) { typedArg returnVal; t_float f; t_int i; t_symbol s; char buf[MAXPDSTRING]; atom_string(a, buf, MAXPDSTRING); #ifdef DEBUG post("packOSC: atom type %d (%s)", a->a_type, buf); #endif /* It might be an int, a float, or a string */ switch (a->a_type) { case A_FLOAT: f = atom_getfloat(a); i = atom_getint(a); if (f == (t_float)i) { /* assume that if the int and float are the same, it's an int */ returnVal.type = INT_osc; returnVal.datum.i = i; } else { returnVal.type = FLOAT_osc; returnVal.datum.f = f; } return returnVal; case A_SYMBOL: s = *atom_getsymbol(a); returnVal.type = STRING_osc; returnVal.datum.s = s.s_name; return returnVal; default: atom_string(a, buf, MAXPDSTRING); error("packOSC: atom type %d not implemented (%s)", a->a_type, buf); returnVal.type = NOTYPE_osc; returnVal.datum.s = NULL; return returnVal; } } static typedArg packOSC_blob(t_atom *a) { /* ctype is one of i,f,s,T,F,N,I*/ typedArg returnVal; t_float f; t_int i; t_symbol s; static char buf[MAXPDSTRING]; returnVal.type = NOTYPE_osc; returnVal.datum.s = NULL; #ifdef DEBUG post("packOSC_blob %d:", nArgs); #endif /* the atoms must all be bytesl */ if(a->a_type != A_FLOAT) { error("packOSC_blob: all values must be floats"); return returnVal; } f = atom_getfloat(a); i = (int)f; if (i != f) { error("packOSC_blob: all values must be whole numbers"); return returnVal; } if ((i < -128) || (i > 255)) { error("packOSC_blob: all values must be bytes"); return returnVal; } returnVal.type = BLOB_osc; returnVal.datum.i = i; return returnVal; } static typedArg packOSC_forceatom(t_atom *a, char ctype) { /* ctype is one of i,f,s,T,F,N,I*/ typedArg returnVal; t_float f; t_int i; t_symbol s; static char buf[MAXPDSTRING]; #ifdef DEBUG atom_string(a, buf, MAXPDSTRING); post("packOSC: atom type %d (%s)", a->a_type, buf); #endif /* the atom might be a float, or a symbol */ switch (a->a_type) { case A_FLOAT: switch (ctype) { case 'i': returnVal.type = INT_osc; returnVal.datum.i = atom_getint(a); #ifdef DEBUG post("packOSC_forceatom: float to integer %d", returnVal.datum.i); #endif break; case 'f': returnVal.type = FLOAT_osc; returnVal.datum.f = atom_getfloat(a); #ifdef DEBUG post("packOSC_forceatom: float to float %f", returnVal.datum.f); #endif break; case 's': f = atom_getfloat(a); sprintf(buf, "%f", f); returnVal.type = STRING_osc; returnVal.datum.s = buf; #ifdef DEBUG post("packOSC_forceatom: float to string %s", returnVal.datum.s); #endif break; default: post("packOSC: unknown OSC type %c", ctype); returnVal.type = NOTYPE_osc; returnVal.datum.s = NULL; break; } break; case A_SYMBOL: s = *atom_getsymbol(a); switch (ctype) { case 'i': i = atoi(s.s_name); returnVal.type = INT_osc; returnVal.datum.i = i; #ifdef DEBUG post("packOSC_forceatom: symbol to integer %d", returnVal.datum.i); #endif break; case 'f': f = atof(s.s_name); returnVal.type = FLOAT_osc; returnVal.datum.f = f; #ifdef DEBUG post("packOSC_forceatom: symbol to float %f", returnVal.datum.f); #endif break; case 's': returnVal.type = STRING_osc; returnVal.datum.s = s.s_name; #ifdef DEBUG post("packOSC_forceatom: symbol to string %s", returnVal.datum.s); #endif break; default: post("packOSC: unknown OSC type %c", ctype); returnVal.type = NOTYPE_osc; returnVal.datum.s = NULL; break; } break; default: atom_string(a, buf, MAXPDSTRING); error("packOSC: atom type %d not implemented (%s)", a->a_type, buf); returnVal.type = NOTYPE_osc; returnVal.datum.s = NULL; break; } return returnVal; } static int packOSC_writetypedmessage (t_packOSC *x, OSCbuf *buf, char *messageName, int numArgs, typedArg *args, char *typeStr) { int i, j, returnVal = OSC_writeAddressAndTypes(buf, messageName, typeStr); if (returnVal) { error("packOSC: Problem writing address. (%d)", returnVal); return returnVal; } for (j = i = 0; (typeStr[i+1]!= 0) || (j < numArgs); j++, i++) { while (typeStr[i+1] == 'T' || typeStr[i+1] == 'F' || typeStr[i+1] == 'I' || typeStr[i+1] == 'N') { #ifdef DEBUG post("packOSC_writetypedmessage: NULL [%c]", typeStr[i+1]); #endif returnVal = OSC_writeNullArg(buf, typeStr[i+1]); ++i; } if (j < numArgs) { switch (args[j].type) { case INT_osc: #ifdef DEBUG post("packOSC_writetypedmessage: int [%d]", args[j].datum.i); #endif returnVal = OSC_writeIntArg(buf, args[j].datum.i); break; case FLOAT_osc: #ifdef DEBUG post("packOSC_writetypedmessage: float [%f]", args[j].datum.f); #endif returnVal = OSC_writeFloatArg(buf, args[j].datum.f); break; case STRING_osc: #ifdef DEBUG post("packOSC_writetypedmessage: string [%s]", args[j].datum.s); #endif returnVal = OSC_writeStringArg(buf, args[j].datum.s); break; case BLOB_osc: /* write all the blob elements at once */ #ifdef DEBUG post("packOSC_writetypedmessage calling OSC_writeBlobArg\n"); #endif return OSC_writeBlobArg(buf, &args[j], numArgs-j); default: break; /* types with no data */ } } } return returnVal; } static int packOSC_writemessage(t_packOSC *x, OSCbuf *buf, char *messageName, int numArgs, typedArg *args) { int j, returnVal = 0, numTags; if (!x->x_typetags) { returnVal = OSC_writeAddress(buf, messageName); if (returnVal) { post("packOSC: Problem writing address."); } } else { char *typeTags; /* First figure out the type tags */ for (numTags = 0; numTags < numArgs; numTags++) { if (args[numTags].type == BLOB_osc) break; /* blob has one type tag and is the last element */ } typeTags=(char*)getbytes(sizeof(char)*(numTags+2)); /* number of args + ',' + '\0' */ typeTags[0] = ','; for (j = 0; j < numTags; ++j) { switch (args[j].type) { case INT_osc: typeTags[j+1] = 'i'; break; case FLOAT_osc: typeTags[j+1] = 'f'; break; case STRING_osc: typeTags[j+1] = 's'; break; case BLOB_osc: typeTags[j+1] = 'b'; break; default: error("packOSC: arg %d type is unrecognized(%d)", j, args[j].type); break; } } typeTags[j+1] = '\0'; returnVal = OSC_writeAddressAndTypes(buf, messageName, typeTags); if (returnVal) { error("packOSC: Problem writing address."); } freebytes(typeTags, sizeof(char)*(numTags+2)); } for (j = 0; j < numArgs; j++) { switch (args[j].type) { case INT_osc: returnVal = OSC_writeIntArg(buf, args[j].datum.i); break; case FLOAT_osc: returnVal = OSC_writeFloatArg(buf, args[j].datum.f); break; case STRING_osc: returnVal = OSC_writeStringArg(buf, args[j].datum.s); break; case BLOB_osc: #ifdef DEBUG post ("packOSC_writemessage calling OSC_writeBlobArg\n"); #endif return OSC_writeBlobArg(buf, &args[j], numArgs-j); /* All the remaining args are blob */ default: break; /* just skip bad types (which we won't get anyway unless this code is buggy) */ } } return returnVal; } static void packOSC_sendbuffer(t_packOSC *x) { int i; int length; unsigned char *buf; #ifdef DEBUG post("packOSC_sendbuffer: Sending buffer...\n"); #endif if (OSC_isBufferEmpty(x->x_oscbuf)) { post("packOSC_sendbuffer() called but buffer empty"); return; } if (!OSC_isBufferDone(x->x_oscbuf)) { post("packOSC_sendbuffer() called but buffer not ready!, not exiting"); return; } length = OSC_packetSize(x->x_oscbuf); buf = (unsigned char *)OSC_getPacket(x->x_oscbuf); #ifdef DEBUG post ("packOSC_sendbuffer: length: %lu", length); #endif /* convert the bytes in the buffer to floats in a list */ for (i = 0; i < length; ++i) SETFLOAT(&x->x_bufferForOSClist[i], buf[i]); /* send the list out the outlet */ outlet_list(x->x_listout, &s_list, length, x->x_bufferForOSClist); } /* The next part is copied and morphed from OSC-client.c. */ /* 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 -- changed licence part (20040820) jdl -- Version 2.4 changes not in here (20040820) jdl */ static void OSC_initBuffer(OSCbuf *buf, size_t size, char *byteArray) { buf->buffer = byteArray; buf->size = size; OSC_resetBuffer(buf); } static 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; } static int OSC_isBufferEmpty(OSCbuf *buf) { return buf->bufptr == buf->buffer; } static size_t OSC_freeSpaceInBuffer(OSCbuf *buf) { return buf->size - (buf->bufptr - buf->buffer); } static int OSC_isBufferDone(OSCbuf *buf) { return (buf->state == DONE || buf->state == ONE_MSG_ARGS); } static char *OSC_getPacket(OSCbuf *buf) { return buf->buffer; } static int OSC_packetSize(OSCbuf *buf) { return (buf->bufptr - buf->buffer); } static int OSC_CheckOverflow(OSCbuf *buf, size_t bytesNeeded) { if ((bytesNeeded) > OSC_freeSpaceInBuffer(buf)) { error("packOSC: buffer overflow"); return 1; } return 0; } static void PatchMessageSize(OSCbuf *buf) { int4byte size = buf->bufptr - ((char *) buf->thisMsgSize) - 4; *(buf->thisMsgSize) = htonl(size); } static int OSC_openBundle(OSCbuf *buf, OSCTimeTag tt) { if (buf->state == ONE_MSG_ARGS) { post("packOSC: Can't open a bundle in a one-message packet"); return 3; } if (buf->state == DONE) { post("packOSC: This packet is finished; can't open a new bundle"); return 4; } if (++(buf->bundleDepth) >= MAX_BUNDLE_NESTING) { post("packOSC: Bundles nested too deeply: maybe change MAX_BUNDLE_NESTING from %d and recompile", MAX_BUNDLE_NESTING); 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 */ if(OSC_CheckOverflow(buf, 16)) return 1; } else { /* This bundle is inside another bundle, so we need to leave a blank size count for the size of this current bundle. */ if(OSC_CheckOverflow(buf, 20))return 1; *((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]); /* 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.) */ } buf->bufptr += sizeof(OSCTimeTag); buf->state = NEED_COUNT; buf->gettingFirstUntypedArg = 0; buf->typeStringPtr = 0; return 0; } static int OSC_closeBundle(OSCbuf *buf) { if (buf->bundleDepth == 0) { /* This handles EMPTY, ONE_MSG, ARGS, and DONE */ post("packOSC: 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; } static int OSC_writeAddress(OSCbuf *buf, char *name) { int4byte paddedLength; if (buf->state == ONE_MSG_ARGS) { post("packOSC: This packet is not a bundle, so you can't write another address"); return 7; } if (buf->state == DONE) { post("packOSC: 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 */ if(OSC_CheckOverflow(buf, paddedLength))return 1; buf->state = ONE_MSG_ARGS; } else { /* GET_ARGS or NEED_COUNT */ if(OSC_CheckOverflow(buf, 4+paddedLength))return 1; 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; } static int OSC_writeAddressAndTypes(OSCbuf *buf, char *name, char *types) { int result; int4byte paddedLength; if (buf == NULL) return 10; if (CheckTypeTag(buf, '\0')) return 9; result = OSC_writeAddress(buf, name); if (result) return result; paddedLength = OSC_effectiveStringLength(types); if(OSC_CheckOverflow(buf, paddedLength))return 1; 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) { char c; if (buf->typeStringPtr) { c = *(buf->typeStringPtr); if (c != expectedType) { if (expectedType == '\0') { post("packOSC: According to the type tag (%c) I expected more arguments.", c); } else if (*(buf->typeStringPtr) == '\0') { post("packOSC: According to the type tag I didn't expect any more arguments."); } else { post("packOSC: According to the type tag I expected an argument of a different type."); post("* Expected %c, string now %s\n", expectedType, buf->typeStringPtr); } return 9; } ++(buf->typeStringPtr); } return 0; } static int OSC_writeFloatArg(OSCbuf *buf, float arg) { union intfloat32 { int i; float f; }; union intfloat32 if32; if(OSC_CheckOverflow(buf, 4))return 1; if (CheckTypeTag(buf, 'f')) return 9; /* Pretend arg is a long int so we can use htonl() */ if32.f = arg; *((int4byte *) buf->bufptr) = htonl(if32.i); buf->bufptr += 4; buf->gettingFirstUntypedArg = 0; return 0; } static int OSC_writeIntArg(OSCbuf *buf, int4byte arg) { if(OSC_CheckOverflow(buf, 4))return 1; if (CheckTypeTag(buf, 'i')) return 9; *((int4byte *) buf->bufptr) = htonl(arg); buf->bufptr += 4; buf->gettingFirstUntypedArg = 0; return 0; } static int OSC_writeBlobArg(OSCbuf *buf, typedArg *arg, size_t nArgs) { size_t i; unsigned char b; /* pack all the args as single bytes following a 4-byte length */ if(OSC_CheckOverflow(buf, nArgs+4))return 1; if (CheckTypeTag(buf, 'b')) return 9; *((int4byte *) buf->bufptr) = htonl(nArgs); #ifdef DEBUG post ("OSC_writeBlobArg length : %lu", nArgs); #endif buf->bufptr += 4; for (i = 0; i < nArgs; i++) { if (arg[i].type != BLOB_osc) { error("packOSC: blob element %i not blob type", i); return 9; } b = (unsigned char)((arg[i].datum.i)&0x0FF);/* force int to 8-bit byte */ #ifdef DEBUG post ("OSC_writeBlobArg : %d, %d", arg[i].datum.i, b); #endif buf->bufptr[i] = b; } i = OSC_WriteBlobPadding(buf->bufptr, i); buf->bufptr += i; buf->gettingFirstUntypedArg = 0; return 0; } static 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. */ if(OSC_CheckOverflow(buf, len+4))return 1; /* Too conservative */ buf->bufptr += OSC_padStringWithAnExtraStupidComma(buf->bufptr, arg); } else { if(OSC_CheckOverflow(buf, len))return 1; buf->bufptr += OSC_padString(buf->bufptr, arg); } buf->gettingFirstUntypedArg = 0; return 0; } static int OSC_writeNullArg(OSCbuf *buf, char type) { /* Don't write any data, just check the type tag */ if(OSC_CheckOverflow(buf, 4))return 1; if (CheckTypeTag(buf, type)) return 9; buf->gettingFirstUntypedArg = 0; return 0; } /* String utilities */ static int OSC_strlen(char *s) { int i; for (i = 0; s[i] != '\0'; i++) /* Do nothing */ ; return i; } #define STRING_ALIGN_PAD 4 static int OSC_effectiveStringLength(char *string) { int len = OSC_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_WriteStringPadding(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_WriteStringPadding(dest, i+1); } static int OSC_WriteStringPadding(char *dest, int i) { /* pad with at least one zero to fit 4-byte */ dest[i] = '\0'; i++; for (; (i % STRING_ALIGN_PAD) != 0; i++) dest[i] = '\0'; return i; } static int OSC_WriteBlobPadding(char *dest, int i) { /* pad if necessary to fit 4-byte */ for (; (i % STRING_ALIGN_PAD) != 0; i++) dest[i] = '\0'; return i; } /* The next bit is modified from OSC-timetag.c. */ /* 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. */ static OSCTimeTag OSCTT_Immediately(void) { OSCTimeTag tt; tt.fraction = 1; tt.seconds = 0; return tt; } static OSCTimeTag OSCTT_Infinite(void) { OSCTimeTag tt; tt.fraction = 0xffffffffL; tt.seconds = 0xffffffffL; return tt; } #define SECONDS_FROM_1900_to_1970 2208988800LL /* 17 leap years */ #define TWO_TO_THE_32_OVER_ONE_MILLION 4295LL static OSCTimeTag OSCTT_CurrentTimePlusOffset(uint4 offset) { /* offset is in microseconds */ OSCTimeTag tt; static unsigned int onemillion = 1000000; static unsigned int onethousand = 1000; #ifdef _WIN32 struct _timeb tb; _ftime(&tb); /* First get the seconds right */ tt.seconds = (unsigned)SECONDS_FROM_1900_to_1970 + (unsigned)tb.time+ (unsigned)offset/onemillion; /* Now get the fractional part. */ tt.fraction = (unsigned)tb.millitm*onethousand + (unsigned)(offset%onemillion); /* in usec */ #else struct timeval tv; struct timezone tz; gettimeofday(&tv, &tz); /* First get the seconds right */ tt.seconds = (unsigned) SECONDS_FROM_1900_to_1970 + (unsigned) tv.tv_sec + (unsigned) offset/onemillion; /* Now get the fractional part. */ tt.fraction = (unsigned) tv.tv_usec + (unsigned)(offset%onemillion); /* in usec */ #endif if (tt.fraction > onemillion) { tt.fraction -= onemillion; tt.seconds++; } tt.fraction *= (unsigned) TWO_TO_THE_32_OVER_ONE_MILLION; /* convert usec to 32-bit fraction of 1 sec */ return tt; } /* end packOSC.c*/ OSC-0.1/pipelist.c0000644002537200234200000001241711057453664014261 0ustar zmoelnigiemusers/* pipelist.c 20070711 Martin Peach based on pipe from x_time.c */ /* 20080706 added anything method for meta-messages */ #include "m_pd.h" /* -------------------------- pipe -------------------------- */ static t_class *pipelist_class; typedef struct _hang { t_clock *h_clock; struct _hang *h_next; struct _pipelist *h_owner; int h_n; /* number of atoms in h_list */ t_atom *h_atoms; /* pointer to a list of h_n t_atoms */ } t_hang; typedef struct _pipelist { t_object x_obj; float x_deltime; t_outlet *x_pipelistout; t_hang *x_hang; } t_pipelist; static void *pipelist_new(t_symbol *s, int argc, t_atom *argv); static void pipelist_hang_free(t_hang *h); static void pipelist_hang_tick(t_hang *h); static void pipelist_any_hang_tick(t_hang *h); static void pipelist_list(t_pipelist *x, t_symbol *s, int ac, t_atom *av); static void pipelist_anything(t_pipelist *x, t_symbol *s, int ac, t_atom *av); static void pipelist_flush(t_pipelist *x); static void pipelist_clear(t_pipelist *x); void pipelist_setup(void); static void *pipelist_new(t_symbol *s, int argc, t_atom *argv) { t_pipelist *x = (t_pipelist *)pd_new(pipelist_class); float deltime; if (argc) { /* We accept one argument to set the delay time, ignore any further args */ if (argv[0].a_type != A_FLOAT) { char stupid[80]; atom_string(&argv[argc-1], stupid, 79); post("pipelist: %s: bad time delay value", stupid); deltime = 0; } else deltime = argv[argc-1].a_w.w_float; } else deltime = 0; x->x_pipelistout = outlet_new(&x->x_obj, &s_list); floatinlet_new(&x->x_obj, &x->x_deltime); x->x_hang = NULL; x->x_deltime = deltime; return (x); } static void pipelist_hang_free(t_hang *h) { freebytes(h->h_atoms, h->h_n*sizeof(t_atom)); clock_free(h->h_clock); freebytes(h, sizeof(t_hang)); } static void pipelist_hang_tick(t_hang *h) { t_pipelist *x = h->h_owner; t_hang *h2, *h3; /* excise h from the linked list of hangs */ if (x->x_hang == h) x->x_hang = h->h_next; else for (h2 = x->x_hang; ((h3 = h2->h_next)!=NULL); h2 = h3) { if (h3 == h) { h2->h_next = h3->h_next; break; } } /* output h's list */ outlet_list(x->x_pipelistout, &s_list, h->h_n, h->h_atoms); /* free h */ pipelist_hang_free(h); } static void pipelist_any_hang_tick(t_hang *h) { t_pipelist *x = h->h_owner; t_hang *h2, *h3; /* excise h from the linked list of hangs */ if (x->x_hang == h) x->x_hang = h->h_next; else for (h2 = x->x_hang; ((h3 = h2->h_next)!=NULL); h2 = h3) { if (h3 == h) { h2->h_next = h3->h_next; break; } } /* output h's atoms */ outlet_anything(x->x_pipelistout, h->h_atoms[0].a_w.w_symbol, h->h_n-1, &h->h_atoms[1]); /* free h */ pipelist_hang_free(h); } static void pipelist_list(t_pipelist *x, t_symbol *s, int ac, t_atom *av) { if (x->x_deltime > 0) { /* if delay is real, save the list for output in delay milliseconds */ t_hang *h; int i; h = (t_hang *)getbytes(sizeof(t_hang)); h->h_n = ac; h->h_atoms = (t_atom *)getbytes(h->h_n*sizeof(t_atom)); for (i = 0; i < h->h_n; ++i) h->h_atoms[i] = av[i]; h->h_next = x->x_hang; x->x_hang = h; h->h_owner = x; h->h_clock = clock_new(h, (t_method)pipelist_hang_tick); clock_delay(h->h_clock, (x->x_deltime >= 0 ? x->x_deltime : 0)); } /* otherwise just pass the list straight through */ else outlet_list(x->x_pipelistout, &s_list, ac, av); } static void pipelist_anything(t_pipelist *x, t_symbol *s, int ac, t_atom *av) { if (x->x_deltime > 0) { /* if delay is real, save the list for output in delay milliseconds */ t_hang *h; int i; h = (t_hang *)getbytes(sizeof(t_hang)); h->h_n = ac+1; h->h_atoms = (t_atom *)getbytes(h->h_n*sizeof(t_atom)); SETSYMBOL(&h->h_atoms[0], s); for (i = 1; i < h->h_n; ++i) h->h_atoms[i] = av[i-1]; h->h_next = x->x_hang; x->x_hang = h; h->h_owner = x; h->h_clock = clock_new(h, (t_method)pipelist_any_hang_tick); clock_delay(h->h_clock, (x->x_deltime >= 0 ? x->x_deltime : 0)); } /* otherwise just pass it straight through */ else outlet_anything(x->x_pipelistout, s, ac, av); } static void pipelist_flush(t_pipelist *x) { while (x->x_hang) pipelist_hang_tick(x->x_hang); } static void pipelist_clear(t_pipelist *x) { t_hang *hang; while ((hang = x->x_hang) != NULL) { x->x_hang = hang->h_next; pipelist_hang_free(hang); } } void pipelist_setup(void) { pipelist_class = class_new(gensym("pipelist"), (t_newmethod)pipelist_new, (t_method)pipelist_clear, sizeof(t_pipelist), 0, A_GIMME, 0); class_addlist(pipelist_class, pipelist_list); class_addanything(pipelist_class, pipelist_anything); class_addmethod(pipelist_class, (t_method)pipelist_flush, gensym("flush"), 0); class_addmethod(pipelist_class, (t_method)pipelist_clear, gensym("clear"), 0); } /* end of pipelist.c*/ OSC-0.1/routeOSC.c0000644002537200234200000004571411616502255014131 0ustar zmoelnigiemusers/* routeOSC.c 20060424 by Martin Peach, based on OSCroute and OSC-pattern-match.c. */ /* OSCroute.c header follows: */ /* Written by Adrian Freed, The Center for New Music and Audio Technologies, University of California, Berkeley. Copyright (c) 1992,93,94,95,96,97,98,99,2000,01,02,03,04 The Regents of the University of California (Regents). Permission to use, copy, modify, distribute, and distribute modified versions of this software and its documentation without fee and without a signed licensing agreement, is hereby granted, provided that the above copyright notice, this paragraph and the following two paragraphs appear in all copies, modifications, and distributions. IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. The OSC webpage is http://cnmat.cnmat.berkeley.edu/OpenSoundControl */ /* OSC-route.c Max object for OSC-style dispatching To-do: Match a pattern against a pattern? [Done: Only Slash-Star is allowed, see MyPatternMatch.] 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 */ /* OSC-pattern-match.c header follows: */ /* Copyright © 1998. The Regents of the University of California (Regents). All Rights Reserved. Written by Matt Wright, The Center for New Music and Audio Technologies, University of California, Berkeley. Permission to use, copy, modify, distribute, and distribute modified versions of this software and its documentation without fee and without a signed licensing agreement, is hereby granted, provided that the above copyright notice, this paragraph and the following two paragraphs appear in all copies, modifications, and distributions. IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. The OpenSound Control WWW page is http://www.cnmat.berkeley.edu/OpenSoundControl */ /* OSC-pattern-match.c Matt Wright, 3/16/98 Adapted from oscpattern.c, by Matt Wright and Amar Chaudhury */ /* the required include files */ #include "m_pd.h" #define MAX_NUM 128 // maximum number of paths (prefixes) we can route typedef struct _routeOSC { t_object x_obj; /* required header */ t_int x_num; /* Number of prefixes we store */ t_int x_verbosity; /* level of debug output required */ // char *x_prefixes[MAX_NUM]; /* the OSC addresses to be matched */ // int x_prefix_depth[MAX_NUM]; /* the number of slashes in each prefix */ // void *x_outlets[MAX_NUM+1]; /* one for each prefix plus one for everything else */ char **x_prefixes; /* the OSC addresses to be matched */ int *x_prefix_depth; /* the number of slashes in each prefix */ void **x_outlets; /* one for each prefix plus one for everything else */ } t_routeOSC; /* prototypes */ void routeOSC_setup(void); static void routeOSC_free(t_routeOSC *x); static int MyPatternMatch (const char *pattern, const char *test); static void routeOSC_doanything(t_routeOSC *x, t_symbol *s, int argc, t_atom *argv); static void *routeOSC_new(t_symbol *s, int argc, t_atom *argv); static void routeOSC_set(t_routeOSC *x, t_symbol *s, int argc, t_atom *argv); static void routeOSC_paths(t_routeOSC *x, t_symbol *s, int argc, t_atom *argv); static void routeOSC_verbosity(t_routeOSC *x, t_floatarg v); static int routeOSC_count_slashes(char *prefix); static char *NextSlashOrNull(char *p); static char *NthSlashOrNull(char *p, int n); static void StrCopyUntilSlash(char *target, const char *source); static void StrCopyUntilNthSlash(char *target, const char *source, int n); /* from OSC-pattern-match.c */ static const char *theWholePattern; /* Just for warning messages */ static int MatchBrackets (const char *pattern, const char *test); static int MatchList (const char *pattern, const char *test); static int PatternMatch (const char * pattern, const char * test); static t_class *routeOSC_class; t_symbol *ps_list, *ps_complain, *ps_emptySymbol; static int MyPatternMatch (const char *pattern, const char *test) { // This allows the special case of "routeOSC /* " to be an outlet that // matches anything; i.e., it always outputs the input with the first level // of the address stripped off. if (test[0] == '*' && test[1] == '\0') return 1; else return PatternMatch(pattern, test); } static void routeOSC_free(t_routeOSC *x) { freebytes(x->x_prefixes, x->x_num*sizeof(char *)); /* the OSC addresses to be matched */ freebytes(x->x_prefix_depth, x->x_num*sizeof(int)); /* the number of slashes in each prefix */ freebytes(x->x_outlets, (x->x_num+1)*sizeof(void *)); /* one for each prefix plus one for everything else */ } /* initialization routine */ // setup void routeOSC_setup(void) { routeOSC_class = class_new(gensym("routeOSC"), (t_newmethod)routeOSC_new, (t_method)routeOSC_free, sizeof(t_routeOSC), 0, A_GIMME, 0); class_addanything(routeOSC_class, routeOSC_doanything); class_addmethod(routeOSC_class, (t_method)routeOSC_set, gensym("set"), A_GIMME, 0); class_addmethod(routeOSC_class, (t_method)routeOSC_paths, gensym("paths"), A_GIMME, 0); class_addmethod(routeOSC_class, (t_method)routeOSC_verbosity, gensym("verbosity"), A_DEFFLOAT, 0); ps_emptySymbol = gensym(""); // post("routeOSC object version 1.0 by Martin Peach, based on OSCroute by Matt Wright. pd: jdl Win32 raf."); // post("OSCroute Copyright © 1999 Regents of the Univ. of California. All Rights Reserved."); } /* instance creation routine */ static void *routeOSC_new(t_symbol *s, int argc, t_atom *argv) { t_routeOSC *x = (t_routeOSC *)pd_new(routeOSC_class); // get memory for a new object & initialize int i; if (argc > MAX_NUM) { error("* routeOSC: too many arguments: %d (max %d)", argc, MAX_NUM); return 0; } x->x_num = 0; /* first verify that all arguments are symbols whose first character is '/' */ 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_num); } else { error("routeOSC: argument %d does not begin with a slash(/).", i); return(0); } } else { error("routeOSC: argument %d is not a symbol.", i); return 0; } } /* now allocate the storage for each path */ x->x_prefixes = (char **)getzbytes(x->x_num*sizeof(char *)); /* the OSC addresses to be matched */ x->x_prefix_depth = (int *)getzbytes(x->x_num*sizeof(int)); /* the number of slashes in each prefix */ x->x_outlets = (void **)getzbytes((x->x_num+1)*sizeof(void *)); /* one for each prefix plus one for everything else */ /* put the pointer to the path in x_prefixes */ /* put the number of levels in x_prefix_depth */ for (i = 0; i < x->x_num; ++i) { x->x_prefixes[i] = argv[i].a_w.w_symbol->s_name; x->x_prefix_depth[i] = routeOSC_count_slashes(x->x_prefixes[i]); } /* Have to create the outlets in reverse order */ /* well, not in pd ? */ for (i = 0; i <= x->x_num; i++) { x->x_outlets[i] = outlet_new(&x->x_obj, &s_list); } x->x_verbosity = 0; /* quiet by default */ return (x); } static void routeOSC_set(t_routeOSC *x, t_symbol *s, int argc, t_atom *argv) { int i; if (argc > x->x_num) { pd_error (x, "routeOSC: too many paths"); return; } for (i = 0; i < argc; ++i) { if (argv[i].a_type != A_SYMBOL) { pd_error (x, "routeOSC: path %d not a symbol", i); return; } if (argv[i].a_w.w_symbol->s_name[0] != '/') { pd_error (x, "routeOSC: path %d doesn't start with /", i); return; } } for (i = 0; i < argc; ++i) { 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_prefix_depth[i] = routeOSC_count_slashes(x->x_prefixes[i]); } } } static void routeOSC_paths(t_routeOSC *x, t_symbol *s, int argc, t_atom *argv) { /* print out the paths we are matching */ int i; for (i = 0; i < x->x_num; ++i) post("path[%d]: %s (depth %d)", i, x->x_prefixes[i], x->x_prefix_depth[i]); } static void routeOSC_verbosity(t_routeOSC *x, t_floatarg v) { x->x_verbosity = (v == 0)? 0: 1; if (x->x_verbosity) post("routeOSC_verbosity(%p) is %d", x, x->x_verbosity); } static int routeOSC_count_slashes(char *prefix) { /* find the path depth of the prefix by counting the numberof slashes */ int i = 0; char *p = prefix; while (*p != '\0') if (*p++ == '/') i++; return i; } static void routeOSC_doanything(t_routeOSC *x, t_symbol *s, int argc, t_atom *argv) { char *pattern, *nextSlash; int i, pattern_depth = 0, matchedAnything = 0; int noPath = 0; // nonzero if we are dealing with a simple list (as from a previous [routeOSC]) pattern = s->s_name; if (x->x_verbosity) post("routeOSC_doanything(%p): pattern is %s", x, pattern); if (pattern[0] != '/') { // make a path '/'. Now s is actually the first item in the arguments list pattern = gensym("/")->s_name; noPath = 1; if (x->x_verbosity) post("routeOSC_doanything(%p): message pattern \"%s\" does not begin with /, setting path to %s", x, s->s_name, pattern); } pattern_depth = routeOSC_count_slashes(pattern); if (x->x_verbosity) post("routeOSC_doanything(%p): pattern_depth is %i", x, pattern_depth); nextSlash = NextSlashOrNull(pattern+1); if (*nextSlash == '\0') { /* pattern_depth == 1 */ /* last level of the address, so we'll output the argument list */ for (i = 0; i < x->x_num; ++i) { if ( (x->x_prefix_depth[i] <= pattern_depth) && (MyPatternMatch(pattern+1, x->x_prefixes[i]+1)) ) { ++matchedAnything; if (noPath) { // just a list starting with a symbol // The special symbol is s outlet_anything(x->x_outlets[i], s, argc, argv); } else // normal OSC path { // 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_FLOAT) { outlet_float(x->x_outlets[i], argv[0].a_w.w_float); } else { pd_error(x, "* routeOSC: 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 incoming pattern to match against all our prefixes */ for (i = 0; i < x->x_num; ++i) { restOfPattern = 0; if (x->x_prefix_depth[i] <= pattern_depth) { StrCopyUntilNthSlash(patternBegin, pattern+1, x->x_prefix_depth[i]); if (x->x_verbosity) post("routeOSC_doanything(%p): (%d) patternBegin is %s", x, i, patternBegin); if (MyPatternMatch(patternBegin, x->x_prefixes[i]+1)) { if (x->x_verbosity) post("routeOSC_doanything(%p): (%d) matched %s depth %d", x, i, x->x_prefixes[i], x->x_prefix_depth[i]); ++matchedAnything; nextSlash = NthSlashOrNull(pattern+1, x->x_prefix_depth[i]); if (x->x_verbosity) post("routeOSC_doanything(%p): (%d) nextSlash %s", x, i, nextSlash); if (restOfPattern == 0) restOfPattern = gensym(nextSlash); outlet_anything(x->x_outlets[i], restOfPattern, argc, argv); } } } } if (!matchedAnything) { // output unmatched data on rightmost outlet a la normal 'route' object, jdl 20020908 outlet_anything(x->x_outlets[x->x_num], s, argc, argv); } } static char *NextSlashOrNull(char *p) { while (*p != '/' && *p != '\0') p++; return p; } static char *NthSlashOrNull(char *p, int n) { int i; for (i = 0; i < n; ++i) { while (*p != '/') { if (*p == '\0') return p; p++; } if (i < n-1) p++; /* skip the slash unless it's the nth slash */ } return p; } static void StrCopyUntilSlash(char *target, const char *source) { while (*source != '/' && *source != '\0') { *target = *source; ++target; ++source; } *target = 0; } static void StrCopyUntilNthSlash(char *target, const char *source, int n) { /* copy the path up but not including the nth slash */ int i = n; while (i > 0) { while (*source != '/') { *target = *source; if (*source == '\0') return; ++target; ++source; } i--; /* got a slash. If it's the nth, don't include it */ if (i == 0) { *target = 0; return; } *target = *source; ++source; ++target; } } /* from OSC-pattern-match.c Matt Wright, 3/16/98 Adapted from oscpattern.c, by Matt Wright and Amar Chaudhury */ static int 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); return 0; } switch (pattern[0]) { case 0: return test[0] == 0; case '?': return PatternMatch (pattern+1, test+1); case '*': if (PatternMatch (pattern+1, test)) return 1; return PatternMatch (pattern, test+1); case ']': case '}': error("routeOSC: Spurious %c in pattern \".../%s/...\"",pattern[0], theWholePattern); return 0; case '[': return MatchBrackets (pattern,test); case '{': return MatchList (pattern,test); case '\\': if (pattern[1] == 0) return test[0] == 0; if (pattern[1] == test[0]) return PatternMatch (pattern+2,test+1); return 0; default: if (pattern[0] == test[0]) return PatternMatch (pattern+1,test+1); return 0; } } /* we know that pattern[0] == '[' and test[0] != 0 */ static int MatchBrackets (const char *pattern, const char *test) { int result; int negated = 0; const char *p = pattern; if (pattern[1] == 0) { error("routeOSC: Unterminated [ in pattern \".../%s/...\"", theWholePattern); return 0; } if (pattern[1] == '!') { negated = 1; p++; } while (*p != ']') { if (*p == 0) { error("Unterminated [ in pattern \".../%s/...\"", theWholePattern); return 0; } 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 0; while (*p != ']') { if (*p == 0) { error("Unterminated [ in pattern \".../%s/...\"", theWholePattern); return 0; } p++; } return PatternMatch (p+1,test+1); } static int MatchList (const char *pattern, const char *test) { const char *restOfPattern, *tp = test; for(restOfPattern = pattern; *restOfPattern != '}'; restOfPattern++) { if (*restOfPattern == 0) { error("Unterminated { in pattern \".../%s/...\"", theWholePattern); return 0; } } restOfPattern++; /* skip close curly brace */ pattern++; /* skip open curly brace */ while (1) { if (*pattern == ',') { if (PatternMatch (restOfPattern, tp)) return 1; 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++; } } } /* end of routeOSC.c */ OSC-0.1/unpackOSC.c0000644002537200234200000005052311515611372014245 0ustar zmoelnigiemusers/* unpackOSC is like dumpOSC but outputs a list consisting of a single symbol for the path */ /* and a list of floats and/or symbols for the data, and adds an outlet for a time delay. */ /* This allows for the separation of the protocol and its transport. */ /* Started by Martin Peach 20060420 */ /* dumpOSC.c header follows: */ /* Written by Matt Wright and Adrian Freed, The Center for New Music and Audio Technologies, University of California, Berkeley. Copyright (c) 1992,93,94,95,96,97,98,99,2000,01,02,03,04 The Regents of the University of California (Regents). Permission to use, copy, modify, distribute, and distribute modified versions of this software and its documentation without fee and without a signed licensing agreement, is hereby granted, provided that the above copyright notice, this paragraph and the following two paragraphs appear in all copies, modifications, and distributions. IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. The OSC webpage is http://cnmat.cnmat.berkeley.edu/OpenSoundControl */ /* 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. 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: branched from http://www.cnmat.berkeley.edu/OpenSoundControl/src/dumpOSC/dumpOSC.c ------------- -- added pd functions -- socket is made differently than original via pd mechanisms -- tweaks for Win32 www.zeggz.com/raf 13-April-2002 -- the OSX changes from cnmat didnt make it here yet but this compiles on OSX anyway. */ #include "packingOSC.h" static t_class *unpackOSC_class; typedef struct _unpackOSC { t_object x_obj; t_outlet *x_data_out; t_outlet *x_delay_out; t_atom x_data_at[MAX_MESG];/* symbols making up the path + payload */ int x_data_atc;/* number of symbols to be output */ char x_raw[MAX_MESG];/* bytes making up the entire OSC message */ int x_raw_c;/* number of bytes in OSC message */ int x_bundle_flag;/* non-zero if we are processing a bundle */ int x_recursion_level;/* number of times we reenter unpackOSC_list */ int x_abort_bundle;/* non-zero if unpackOSC_list is not well formed */ } t_unpackOSC; void unpackOSC_setup(void); static void *unpackOSC_new(void); static void unpackOSC_free(t_unpackOSC *x); static void unpackOSC_list(t_unpackOSC *x, t_symbol *s, int argc, t_atom *argv); static int unpackOSC_path(t_unpackOSC *x, char *path); static void unpackOSC_Smessage(t_unpackOSC *x, void *v, int n); static void unpackOSC_PrintTypeTaggedArgs(t_unpackOSC *x, void *v, int n); static void unpackOSC_PrintHeuristicallyTypeGuessedArgs(t_unpackOSC *x, void *v, int n, int skipComma); static char *unpackOSC_DataAfterAlignedString(char *string, char *boundary); static int unpackOSC_IsNiceString(char *string, char *boundary); static t_float unpackOSC_DeltaTime(OSCTimeTag tt); static void *unpackOSC_new(void) { t_unpackOSC *x; x = (t_unpackOSC *)pd_new(unpackOSC_class); x->x_data_out = outlet_new(&x->x_obj, &s_list); x->x_delay_out = outlet_new(&x->x_obj, &s_float); x->x_raw_c = x->x_data_atc = 0; x->x_bundle_flag = 0; x->x_recursion_level = 0; x->x_abort_bundle = 0; return (x); } static void unpackOSC_free(t_unpackOSC *x) { } void unpackOSC_setup(void) { unpackOSC_class = class_new(gensym("unpackOSC"), (t_newmethod)unpackOSC_new, (t_method)unpackOSC_free, sizeof(t_unpackOSC), 0, 0); class_addlist(unpackOSC_class, (t_method)unpackOSC_list); class_sethelpsymbol(unpackOSC_class, gensym("routeOSC")); /* same help patch as routeOSC*/ } /* unpackOSC_list expects an OSC packet in the form of a list of floats on [0..255] */ static void unpackOSC_list(t_unpackOSC *x, t_symbol *s, int argc, t_atom *argv) { int size, messageLen, i, j; char *messageName, *args, *buf; OSCTimeTag tt; if(x->x_abort_bundle) return; /* if backing quietly out of the recursive stack */ if ((argc%4) != 0) { post("unpackOSC: Packet size (%d) not a multiple of 4 bytes: dropping packet", argc); x->x_recursion_level = 0; return; } if(argc > MAX_MESG) { post("unpackOSC: Packet size (%d) greater than max (%d). Change MAX_MESG and recompile if you want more.", argc, MAX_MESG); x->x_recursion_level = 0; return; } /* copy the list to a byte buffer, checking for bytes only */ for (i = 0; i < argc; ++i) { if (argv[i].a_type == A_FLOAT) { j = (int)argv[i].a_w.w_float; /* if ((j == argv[i].a_w.w_float) && (j >= 0) && (j <= 255)) */ /* this can miss bytes between 128 and 255 because they are interpreted somewhere as negative */ /* , so change to this: */ if ((j == argv[i].a_w.w_float) && (j >= -128) && (j <= 255)) { x->x_raw[i] = (char)j; } else { post("unpackOSC: Data out of range (%d), dropping packet", argv[i].a_w.w_float); x->x_recursion_level = 0; return; } } else { post("unpackOSC: Data not float, dropping packet"); x->x_recursion_level = 0; return; } } x->x_raw_c = argc; buf = x->x_raw; if ((argc >= 8) && (strncmp(buf, "#bundle", 8) == 0)) { /* This is a bundle message. */ #ifdef DEBUG post("unpackOSC: bundle msg:\n"); #endif if (argc < 16) { post("unpackOSC: Bundle message too small (%d bytes) for time tag", argc); x->x_recursion_level = 0; return; } x->x_bundle_flag = 1; /* Print the time tag */ #ifdef DEBUG printf("unpackOSC: [ %lx%08lx\n", ntohl(*((unsigned long *)(buf+8))), ntohl(*((unsigned long *)(buf+12)))); #endif /* convert the timetag into a millisecond delay from now */ tt.seconds = ntohl(*((unsigned long *)(buf+8))); tt.fraction = ntohl(*((unsigned long *)(buf+12))); /* pd can use a delay in milliseconds */ outlet_float(x->x_delay_out, unpackOSC_DeltaTime(tt)); /* 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 < argc) { size = ntohl(*((int *) (buf + i))); if ((size % 4) != 0) { post("unpackOSC: Bad size count %d in bundle (not a multiple of 4)", size); x->x_recursion_level = 0; return; } if ((size + i + 4) > argc) { post("unpackOSC: Bad size count %d in bundle (only %d bytes left in entire bundle)", size, argc-i-4); x->x_recursion_level = 0; return; } /* Recursively handle element of bundle */ x->x_recursion_level++; if (x->x_recursion_level > MAX_BUNDLE_NESTING) { post("unpackOSC: bundle depth %d exceeded", MAX_BUNDLE_NESTING); x->x_recursion_level = 0; x->x_abort_bundle = 1;/* we need to back out of the recursive stack*/ return; } unpackOSC_list(x, s, size, &argv[i+4]); i += 4 + size; } if (i != argc) { post("unpackOSC: This can't happen"); } x->x_bundle_flag = 0; /* end of bundle */ #ifdef DEBUG printf("]\n"); #endif } else if ((argc == 24) && (strcmp(buf, "#time") == 0)) { post("unpackOSC: Time message: %s\n :).\n", buf); x->x_recursion_level = 0; return; } else { /* This is not a bundle message or a time message */ messageName = buf; args = unpackOSC_DataAfterAlignedString(messageName, buf+x->x_raw_c); if (args == 0) { post("unpackOSC: Bad message name string: Dropping entire message."); x->x_recursion_level = 0; return; } #ifdef DEBUG post("unpackOSC: message name string: %s", messageName); #endif messageLen = args-messageName; /* put the OSC path into a single symbol */ x->x_data_atc = unpackOSC_path(x, messageName); /* returns 1 if path OK, else 0 */ if (x->x_data_atc == 1) { unpackOSC_Smessage(x, (void *)args, x->x_raw_c-messageLen); if (0 == x->x_bundle_flag) outlet_float(x->x_delay_out, 0); /* no delay for message not in a bundle */ } } /*if (x->x_data_atc >= 1) outlet_list(x->x_data_out, &s_list, x->x_data_atc, x->x_data_at);*/ if (x->x_data_atc >= 1) outlet_anything(x->x_data_out, atom_getsymbol(x->x_data_at), x->x_data_atc-1, x->x_data_at+1); x->x_data_atc = 0; x->x_recursion_level = 0; x->x_abort_bundle = 0; } static int unpackOSC_path(t_unpackOSC *x, char *path) { int i; if (path[0] != '/') { for (i = 0; i < 16; ++i) if ('\0' == path[i]) break; path[i] = '\0'; post("unpackOSC: Path doesn't begin with \"/\", dropping message"); return 0; } for (i = 1; i < MAX_MESG; ++i) { if (path[i] == '\0') { /* the end of the path: turn path into a symbol */ SETSYMBOL(&x->x_data_at[0],gensym(path)); return 1; } } post("unpackOSC: Path too long, dropping message"); return 0; } #define SMALLEST_POSITIVE_FLOAT 0.000001f static void unpackOSC_Smessage(t_unpackOSC *x, void *v, int n) { char *chars = v; if (n != 0) { if (chars[0] == ',') { if (chars[1] != ',') { /* This message begins with a type-tag string */ unpackOSC_PrintTypeTaggedArgs(x, v, n); } else { /* Double comma means an escaped real comma, not a type string */ unpackOSC_PrintHeuristicallyTypeGuessedArgs(x, v, n, 1); } } else { unpackOSC_PrintHeuristicallyTypeGuessedArgs(x, v, n, 0); } } } static void unpackOSC_PrintTypeTaggedArgs(t_unpackOSC *x, void *v, int n) { char *typeTags, *thisType, *p; int myargc = x->x_data_atc; t_atom *mya = x->x_data_at; typeTags = v; if (!unpackOSC_IsNiceString(typeTags, typeTags+n)) { /* No null-termination, so maybe it wasn't a type tag string after all */ unpackOSC_PrintHeuristicallyTypeGuessedArgs(x, v, n, 0); return; } p = unpackOSC_DataAfterAlignedString(typeTags, typeTags+n); for (thisType = typeTags + 1; *thisType != 0; ++thisType) { switch (*thisType) { case 'b': /* blob: an int32 size count followed by that many 8-bit bytes */ { int i, blob_bytes = ntohl(*((int *) p)); #ifdef DEBUG post("blob: %lu bytes", blob_bytes); #endif p += 4; for (i = 0; i < blob_bytes; ++i, ++p, ++myargc) SETFLOAT(mya+myargc,(*(unsigned char *)p)); while (i%4) { ++i; ++p; } break; } case 'i': case 'r': case 'm': case 'c': #ifdef DEBUG post("integer: %d", ntohl(*((int *) p))); #endif SETFLOAT(mya+myargc,(signed)ntohl(*((int *) p))); myargc++; p += 4; break; case 'f': { intfloat32 thisif; thisif.i = ntohl(*((int *) p)); #ifdef DEBUG post("float: %f", thisif.f); #endif SETFLOAT(mya+myargc, thisif.f); myargc++; p += 4; break; } case 'h': case 't': #ifdef DEBUG printf("[A 64-bit int] "); #endif post("unpackOSC: PrintTypeTaggedArgs: [A 64-bit int] not implemented"); p += 8; break; case 'd': #ifdef DEBUG printf("[A 64-bit float] "); #endif post("unpackOSC: PrintTypeTaggedArgs: [A 64-bit float] not implemented"); p += 8; break; case 's': case 'S': if (!unpackOSC_IsNiceString(p, typeTags+n)) { post("unpackOSC: PrintTypeTaggedArgs: 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++; p = unpackOSC_DataAfterAlignedString(p, typeTags+n); } 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 SETFLOAT(mya+myargc,0.); myargc++; break; case 'I': #ifdef DEBUG printf("[Infinitum]"); #endif SETSYMBOL(mya+myargc,gensym("INF")); myargc++; break; default: post("unpackOSC: PrintTypeTaggedArgs: [Unrecognized type tag %c]", *thisType); myargc++; } } x->x_data_atc = myargc; } static void unpackOSC_PrintHeuristicallyTypeGuessedArgs(t_unpackOSC *x, void *v, int n, int skipComma) { int i; int *ints; intfloat32 thisif; char *chars, *string, *nextString; int myargc= x->x_data_atc; t_atom* mya = x->x_data_at; /* Go through the arguments 32 bits at a time */ ints = v; chars = v; for (i = 0; i < n/4; ) { string = &chars[i*4]; thisif.i = ntohl(ints[i]); /* Reinterpret the (potentially byte-reversed) thisif as a float */ if (thisif.i >= -1000 && thisif.i <= 1000000) { #ifdef DEBUG printf("%d ", thisif.i); #endif SETFLOAT(mya+myargc,(t_float) (thisif.i)); myargc++; i++; } else if (thisif.f >= -1000.f && thisif.f <= 1000000.f && (thisif.f <=0.0f || thisif.f >= SMALLEST_POSITIVE_FLOAT)) { #ifdef DEBUG printf("%f ", thisif.f); #endif SETFLOAT(mya+myargc,thisif.f); myargc++; i++; } else if (unpackOSC_IsNiceString(string, chars+n)) { nextString = unpackOSC_DataAfterAlignedString(string, chars+n); #ifdef DEBUG printf("\"%s\" ", (i == 0 && skipComma) ? string +1 : string); #endif SETSYMBOL(mya+myargc,gensym(string)); myargc++; i += (nextString-string) / 4; } else { /* unhandled .. ;) */ post("unpackOSC: PrintHeuristicallyTypeGuessedArgs: indeterminate type: 0x%x xx", ints[i]); i++; } x->x_data_atc = myargc; } } #define STRING_ALIGN_PAD 4 static char *unpackOSC_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 */ int i; if ((boundary - string) %4 != 0) { post("unpackOSC: DataAfterAlignedString: bad boundary"); return 0; } for (i = 0; string[i] != '\0'; i++) { if (string + i >= boundary) { post("unpackOSC: 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) { post("unpackOSC: DataAfterAlignedString: Unreasonably long string"); return 0; } if (string[i] != '\0') { post("unpackOSC: DataAfterAlignedString: Incorrectly padded string"); return 0; } } return string+i; } static int unpackOSC_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? Returns 1 if true, else 0. */ int i; if ((boundary - string) %4 != 0) { post("unpackOSC: IsNiceString: bad boundary\n"); return 0; } for (i = 0; string[i] != '\0'; i++) if ((!isprint(string[i])) || (string + i >= boundary)) return 0; /* 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 0; return 1; } #define SECONDS_FROM_1900_to_1970 2208988800LL /* 17 leap years */ #define TWO_TO_THE_32_OVER_ONE_MILLION 4295LL #define ONE_MILLION_OVER_TWO_TO_THE_32 0.00023283064365386963 /* return the time difference in milliseconds between an OSC timetag and now */ static t_float unpackOSC_DeltaTime(OSCTimeTag tt) { static double onemillion = 1000000.0f; #ifdef _WIN32 static double onethousand = 1000.0f; #endif /* ifdef _WIN32 */ if (tt.fraction == 1 && tt.seconds == 0) return 0.0; /* immediate */ else { OSCTimeTag ttnow; double ttusec, nowusec, delta; #ifdef _WIN32 struct _timeb tb; _ftime(&tb); /* find now */ /* First get the seconds right */ ttnow.seconds = (unsigned) SECONDS_FROM_1900_to_1970 + (unsigned) tb.time; /* find usec in tt */ ttusec = tt.seconds*onemillion + ONE_MILLION_OVER_TWO_TO_THE_32*tt.fraction; nowusec = ttnow.seconds*onemillion + tb.millitm*onethousand; #else struct timeval tv; struct timezone tz; gettimeofday(&tv, &tz); /* find now */ /* First get the seconds right */ ttnow.seconds = (unsigned) SECONDS_FROM_1900_to_1970 + (unsigned) tv.tv_sec; /* find usec in tt */ ttusec = tt.seconds*onemillion + ONE_MILLION_OVER_TWO_TO_THE_32*tt.fraction; nowusec = ttnow.seconds*onemillion + tv.tv_usec; #endif /* ifdef _WIN32 */ /* subtract now from tt to get delta time */ /* if (ttusec < nowusec) return 0.0; */ /*negative delays are all right */ delta = ttusec - nowusec; return (float)(delta*0.001f); } } /* end of unpackOSC.c */ OSC-0.1/packOSCstream.pd0000644002537200234200000000045711524213045015273 0ustar zmoelnigiemusers#N canvas 642 471 204 215 10; #X obj 9 35 packOSC; #X obj 9 14 inlet; #X obj 9 139 outlet; #X text 36 157 Author: Roman Haefeli; #X obj 135 139 outlet; #X obj 9 80 mrpeach/slipenc 65536; #X text 36 173 version: 2011-02-01; #X connect 0 0 5 0; #X connect 0 1 4 0; #X connect 1 0 0 0; #X connect 5 0 2 0; OSC-0.1/unpackOSCstream.pd0000644002537200234200000000046211524213045015632 0ustar zmoelnigiemusers#N canvas 693 326 361 208 10; #X obj 9 7 inlet; #X obj 9 135 unpackOSC; #X obj 9 158 outlet; #X obj 60 158 outlet; #X text 172 144 Author: Roman Haefeli; #X text 172 160 Version: 2011-02-01; #X obj 9 71 mrpeach/slipdec 65536; #X connect 0 0 6 0; #X connect 1 0 2 0; #X connect 1 1 3 0; #X connect 6 0 1 0; OSC-0.1/packOSC-help.pd0000644002537200234200000000743611547265575015035 0ustar zmoelnigiemusers#N canvas 1 53 1141 651 12; #X obj 301 434 cnv 15 100 40 empty empty empty 20 12 0 14 -4034 -66577 0; #X obj 330 548 udpsend; #X msg 323 521 disconnect; #X msg 301 499 connect 127.0.0.1 9997; #X obj 330 447 packOSC; #X obj 330 583 tgl 15 0 empty empty 1=connected 20 8 0 8 -4034 -257985 -1 0 1; #X msg -130 -33 send /test/one/two/three zz 88 T; #X msg -84 13 send /test 1 2 3; #X msg -107 -10 send /west 35; #X msg -38 59 send /*/left 22; #X msg -13 84 send /?est/ 1; #X text 293 13 packOSC is like sendOSC except that it outputs a list of floats instead of directly connecting to the network; #X text 103 -33 send a type-guessed message; #X obj 515 541 routeOSC; #X text 436 540 see also:; #X msg 318 415 typetags \$1; #X obj 318 397 tgl 15 0 empty empty empty 17 7 0 10 -257985 -258113 -1 0 1; #X text 401 414 typetags are on by default; #X text 529 107 Useable types are:; #X text 529 125 i: 32 bit integer; #X text 529 143 f: 32-bit float; #X text 529 161 s: string; #X text 310 107 send a type-forced message; #X msg 10 107 sendtyped /test/one/two/three sis zz 88 T; #X msg 33 130 sendtyped /left/right TTiTIFNfisf 1.1 2.1 3.1 4.1 5.1 ; #X text 529 179 T: true (no argument); #X text 529 197 F: false (no argument); #X text 529 215 I: infinitum (no argument); #X text 529 232 N: Nil (no argument); #X msg 277 374 bufsize 100; #X text 364 374 set buffer size (default is 64000 bytes); #X msg 79 176 prefix /test; #X text 174 175 set the OSC path prefix for subsequent messages; #X msg -61 36 /left one two; #X msg 56 153 /right 88; #X text 129 153 'send' prefix is not required; #X msg 55 209 [; #X msg 9 210 ]; #X text -81 211 close bundle; #X msg 157 254 timetagoffset 0; #X msg 180 277 timetagoffset -1; #X text 270 254 send current time as timetag; #X text 135 229 (timetags are sent in bundle messages only); #X obj 9 186 t b a b; #X msg -90 166 /test 5 6 7; #X text 301 277 immediate time tag (default); #X floatatom 376 476 5 0 0 0 - - -; #X text 426 476 bundle depth; #X obj 469 499 cnv 15 380 30 empty empty empty 20 12 0 14 -24198 -66577 0; #X text 597 540 and http://opensoundcontrol.org/cnmat; #X msg 203 300 timetagoffset 1e+06; #X text 473 506 <- First open routeOSC-help \, then connect; #X text 85 210 open a bundle (and generate time tag); #X obj 418 568 packOSCstream; #X text 383 567 see:; #X text 518 568 for a way to send OSC over TCP or serial connections. ; #X text 353 299 current time plus 1 second (delay is in microseconds) ; #X text -75 570 2009_06_08 Martin Peach; #X text 529 248 b: blob (a list of bytes \, or floats on [0..255]) ; #X text 659 341 send a blob; #X msg 253 334 sendtyped /left b 0 1 2 3 124 125 126 127 128 129 255 254 253 252 -14 -15 -16 17 18 19 20 21 22 23 24 25 26 27 28; #N canvas 497 62 494 344 META 0; #X text 12 185 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; #X text 12 25 LICENSE GPL v2 or later; #X text 12 165 AUTHOR Martin Peach; #X text 12 5 KEYWORDS control network; #X text 12 45 DESCRIPTION packOSC is like sendOSC except it outputs a list of floats instead of directly connecting to the network; #X text 12 85 INLET_0 anything send sendtyped prefix timetagoffset bufsize typetags; #X text 12 125 OUTLET_0 anything; #X text 12 145 OUTLET_1 float; #X restore 832 595 pd META; #X connect 1 0 5 0; #X connect 2 0 1 0; #X connect 3 0 1 0; #X connect 4 0 1 0; #X connect 4 1 46 0; #X connect 6 0 4 0; #X connect 7 0 4 0; #X connect 8 0 4 0; #X connect 9 0 4 0; #X connect 10 0 4 0; #X connect 15 0 4 0; #X connect 16 0 15 0; #X connect 23 0 4 0; #X connect 24 0 4 0; #X connect 29 0 4 0; #X connect 31 0 4 0; #X connect 33 0 4 0; #X connect 34 0 4 0; #X connect 36 0 4 0; #X connect 37 0 4 0; #X connect 39 0 4 0; #X connect 40 0 4 0; #X connect 43 0 37 0; #X connect 43 1 4 0; #X connect 43 2 36 0; #X connect 44 0 43 0; #X connect 50 0 4 0; #X connect 60 0 4 0; OSC-0.1/packOSCstream-help.pd0000644002537200234200000000420011547265575016233 0ustar zmoelnigiemusers#N canvas 1 53 609 569 10; #X obj 69 119 packOSCstream; #X obj 69 451 tcpsend; #X text -24 496 check also:; #X obj -22 513 unpackOSCstream; #X obj 93 513 packOSC; #X msg 38 403 connect localhost 9995; #X obj 208 513 tcpreceive; #X obj 151 513 tcpsend; #X obj 286 513 tcpserver; #X obj 357 513 tcpclient; #X msg 58 423 disconnect; #X obj 69 473 tgl 15 0 empty empty empty 17 7 0 10 -4034 -257985 -1 0 1; #X obj 181 403 cnv 15 380 30 empty empty empty 20 12 0 14 -24198 -66577 0; #X text 196 408 <- First open unpackOSCstream-help \, then connect ; #X text 440 501 Author: Roman Haefeli; #X text 440 517 Version: 2008-09-09; #X text 74 254 [packOSCstream] uses the same methods as [packOSC]. Please consult packOSC-help.pd for the complete documentation.; #X text 75 189 [packOSstream] puts a frame length header (int32) in front of every OSC packet or bundle \, so that the receiving side knows \, how to split the incoming stream into OSC packets again.; #X msg -24 9 /first/message 1 \, /second/message 2; #X text 79 330 reference:; #X text 80 347 http://archive.cnmat.berkeley.edu/OpenSoundControl/OSC-spec.html : Section "OSC Packets"; #X msg -4 29 send /test/one/two/three zz 88 T; #X msg 16 49 sendtyped /test/one/two/three sis zz 88 T; #X msg 36 69 prefix /test; #X msg 56 89 [ \, /previous/page 666 \, /next/page 999 \, ]; #X text 72 142 [packOSCstream] is meant to be a replacement for [packOSC] \, when sending over a stream based protocol \, such as TCP.; #N canvas 499 120 494 344 META 0; #X text 12 135 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; #X text 12 25 LICENSE GPL v2 or later; #X text 12 115 AUTHOR Roman Haefeli; #X text 12 75 INLET_0 anything send sendtyped prefix connect disconnect ; #X text 12 45 DESCRIPTION meant to be a replacement for [packOSC] \, when sending over a stream based protocol \, such as TCP; #X text 12 95 OUTLET_0 float; #X text 12 5 KEYWORDS control network abstraction; #X restore 532 544 pd META; #X connect 0 0 1 0; #X connect 1 0 11 0; #X connect 5 0 1 0; #X connect 10 0 1 0; #X connect 18 0 0 0; #X connect 21 0 0 0; #X connect 22 0 0 0; #X connect 23 0 0 0; #X connect 24 0 0 0; OSC-0.1/pipelist-help.pd0000644002537200234200000000262511547265575015376 0ustar zmoelnigiemusers#N canvas 1 53 558 300 10; #X obj 112 129 pipelist 1000; #X msg 198 83 5000; #X floatatom 198 107 5 0 0 0 - - -; #X floatatom 222 42 5 0 0 0 - - -; #X floatatom 181 42 5 0 0 0 - - -; #X obj 112 62 pack s s 3 4 5; #X obj 112 0 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 -1; #X msg 135 -1 tik; #X msg 57 13 alpha; #X msg 50 41 beta; #X floatatom 63 90 5 0 0 0 - - -; #X obj 112 196 print; #X obj 130 107 symbol; #X msg 135 83 bb; #X text 195 1 pipelist delays lists.; #X text 237 106 Delay time is in milliseconds.; #X text 208 131 Argument sets initial delay time.; #X text 242 218 2007/07/11 Martin Peach; #X text 229 182 see also:; #X obj 305 183 pipe; #X obj 339 183 delay; #X obj 379 183 timer; #X obj 135 21 symbol; #N canvas 500 149 494 344 META 0; #X text 12 145 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; #X text 12 25 LICENSE GPL v2 or later; #X text 12 125 AUTHOR Roman Haefeli; #X text 12 5 KEYWORDS control list_op; #X text 12 45 DESCRIPTION delay lists; #X text 12 65 INLET_0 anything; #X text 12 85 INLET_1 float; #X text 12 105 OUTLET_0 list; #X restore 492 265 pd META; #X connect 0 0 11 0; #X connect 1 0 2 0; #X connect 2 0 0 1; #X connect 3 0 5 4; #X connect 4 0 5 3; #X connect 5 0 0 0; #X connect 6 0 5 0; #X connect 7 0 22 0; #X connect 8 0 5 0; #X connect 9 0 5 0; #X connect 10 0 0 0; #X connect 12 0 0 0; #X connect 13 0 12 0; #X connect 22 0 5 1; OSC-0.1/routeOSC-help.pd0000644002537200234200000000522411547265575015246 0ustar zmoelnigiemusers#N canvas 1 53 923 562 12; #X obj 81 389 cnv 15 200 40 empty empty empty 20 12 0 14 -4034 -66577 0; #X obj -76 40 udpreceive 9997; #X floatatom 91 111 3 0 0 0 - - -; #X floatatom 118 111 3 0 0 0 - - -; #X floatatom 145 111 3 0 0 0 - - -; #X floatatom 172 111 3 0 0 0 - - -; #X text 51 110 from; #X obj -76 164 unpackOSC; #X obj 112 399 routeOSC /test /west; #X msg 76 343 set /left; #X msg 53 320 set /left /right; #X text 324 108 see also:; #X obj 396 109 packOSC; #X floatatom 483 184 10 0 0 1 millisecond_delay - -; #X obj -76 191 pipelist; #X text 283 398 arguments are OSC addresses to be routed; #X text -117 517 see:; #X text 30 518 for a way to send OSC over TCP or serial connections. ; #X obj -82 518 unpackOSCstream; #X text 231 341 (but new outlets can't be created); #X obj -110 218 print unpacked; #X text 503 476 2011/01/17 Martin Peach; #X obj 91 87 unpack 0 0 0 0 0; #X floatatom 200 111 8 0 0 0 - - -; #X obj 26 64 route received from; #X floatatom 26 132 5 0 0 0 - - -; #X text 66 132 bytes; #X msg 99 366 set /test/one/two/three; #X msg 27 294 paths; #X msg 4 271 verbosity \$1; #X obj 4 253 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1 ; #X text 22 249 set to 1 for debugging; #X text 275 365 routeOSC will match deep paths; #X text 245 40 [routeOSC] parses lists of floats (only integers on [0..255]) as OSC packets.; #X text 246 77 Open [packOSC-help] to send packets to this patch.; #X text -6 186 If the OSC packet has a timetag \, [pipelist] will delay it until the time occurs; #X obj 112 480 print match_1; #X obj 180 457 print match_2; #X obj 249 434 print no_match; #X text 177 319 [set( reassigns outputs from left to right; #X text 81 294 [paths( will print the current OSC addresses to Pd console ; #N canvas 498 257 494 344 META 0; #X text 12 155 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; #X text 12 25 LICENSE GPL v2 or later; #X text 12 135 AUTHOR Roman Haefeli; #X text 12 5 KEYWORDS control list_op; #X text 12 45 DESCRIPTION parses lists of floats (only integers on [0..255]) as OSC packets.; #X text 12 75 INLET_0 list verbosity paths set; #X text 12 95 OUTLET_N list; #X text 12 115 OUTLET_R list; #X restore 708 522 pd META; #X connect 1 0 7 0; #X connect 1 1 24 0; #X connect 7 0 14 0; #X connect 7 0 20 0; #X connect 7 1 13 0; #X connect 7 1 14 1; #X connect 8 0 36 0; #X connect 8 1 37 0; #X connect 8 2 38 0; #X connect 9 0 8 0; #X connect 10 0 8 0; #X connect 14 0 8 0; #X connect 22 0 2 0; #X connect 22 1 3 0; #X connect 22 2 4 0; #X connect 22 3 5 0; #X connect 22 4 23 0; #X connect 24 0 25 0; #X connect 24 1 22 0; #X connect 27 0 8 0; #X connect 28 0 8 0; #X connect 29 0 8 0; #X connect 30 0 29 0; OSC-0.1/unpackOSCstream-help.pd0000644002537200234200000000272611547265575016611 0ustar zmoelnigiemusers#N canvas 1 53 638 435 10; #X text 8 369 check also:; #X obj 240 386 tcpreceive; #X obj 183 386 tcpsend; #X obj 318 386 tcpserver; #X obj 389 386 tcpclient; #X text 472 374 Author: Roman Haefeli; #X text 472 390 Version: 2008-09-09; #X text 158 65 [unpackOSCstream] is meant to be a replacement for [unpackOSC] \, when receiving from a stream based protocol \, such as TCP.; #X obj 18 197 unpackOSCstream; #X obj 18 17 tcpreceive 9995; #X obj 18 222 print; #X floatatom 105 221 5 0 0 0 - - -; #X text 159 283 reference:; #X obj 10 386 packOSCstream; #X obj 110 386 unpackOSC; #X text 160 300 http://archive.cnmat.berkeley.edu/OpenSoundControl/OSC-spec.html : Section "OSC Packets"; #X text 141 221 milliseconds delay; #X text 158 119 [unpackOSCstream] will only be able to decode OSC packets or bundles created by [packOSCstream]. OSC packets that were generated by [packOSC] will cause errors or wrong output.; #N canvas 507 340 494 344 META 0; #X text 12 155 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; #X text 12 25 LICENSE GPL v2 or later; #X text 12 5 KEYWORDS control network abstraction; #X text 12 46 DESCRIPTION meant to be a replacement for [unpackOSC] \, when receiving from a stream based protocol \, such as TCP.; #X text 12 75 INLET_0 anything; #X text 12 95 OUTLET_0 anything; #X text 12 115 OUTLET_1 float; #X text 12 135 AUTHOR Roman Haefeli; #X restore 591 413 pd META; #X connect 8 0 10 0; #X connect 8 1 11 0; #X connect 9 0 8 0; OSC-0.1/packingOSC.h0000644002537200234200000000171511515611372014404 0ustar zmoelnigiemusers/* packingOSC.h */ #ifndef _PACKINGOSC #include "m_pd.h" #include #include #include #ifdef _WIN32 #include #include #else #include #include #include #include #endif /* _WIN32 */ /* Declarations */ #ifdef WIN32 typedef unsigned __int64 osc_time_t; #else typedef unsigned long long osc_time_t; #endif #define MAX_MESG 65536 /* same as MAX_UDP_PACKET */ /* 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 /* You may have to redefine this typedef if ints on your system aren't 4 bytes. */ typedef unsigned int uint4; typedef struct { uint4 seconds; uint4 fraction; } OSCTimeTag; typedef union { int i; float f; } intfloat32; #endif // _PACKINGOSC