From 189c0787586602185fea7dcbc3ef37665b75ba45 Mon Sep 17 00:00:00 2001 From: jdl Date: Tue, 6 Aug 2002 12:13:57 +0000 Subject: This commit was generated by cvs2svn to compensate for changes in r75, which included commits to RCS files with non-trunk default branches. svn path=/trunk/externals/OSCx/; revision=76 --- send+dump/Makefile | 25 ++ send+dump/dumpOSC.c | 716 ++++++++++++++++++++++++++++++++++++++++++++++++++ send+dump/dumpUDP.c | 191 ++++++++++++++ send+dump/htmsocket.c | 230 ++++++++++++++++ send+dump/htmsocket.h | 49 ++++ send+dump/sendOSC.c | 600 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 1811 insertions(+) create mode 100644 send+dump/Makefile create mode 100644 send+dump/dumpOSC.c create mode 100644 send+dump/dumpUDP.c create mode 100644 send+dump/htmsocket.c create mode 100644 send+dump/htmsocket.h create mode 100644 send+dump/sendOSC.c (limited to 'send+dump') diff --git a/send+dump/Makefile b/send+dump/Makefile new file mode 100644 index 0000000..7b14a43 --- /dev/null +++ b/send+dump/Makefile @@ -0,0 +1,25 @@ +LIBOSCDIR = ../libOSC +LIBOSC = ${LIBOSCDIR}/libOSC.a +CFLAGS= -O2 -I$(LIBOSCDIR) + +DUMPOBJS=dumpOSC.o + + +both: sendOSC dumpOSC + +sendOSC: sendOSC.o htmsocket.o ${LIBOSC} + ${CC} -o sendOSC sendOSC.o htmsocket.o ${LIBOSC} + +dumpOSC: ${DUMPOBJS} + ${CC} -o $@ ${DUMPOBJS} + +dumpUDP: dumpUDP.o + ${CC} -o dumpUDP dumpUDP.o + +${LIBOSC}: + echo "You need to go to " ${LIBOSCDIR} " and do a make." + +clean: + rm -f sendOSC dumpOSC *.o + + diff --git a/send+dump/dumpOSC.c b/send+dump/dumpOSC.c new file mode 100644 index 0000000..143a994 --- /dev/null +++ b/send+dump/dumpOSC.c @@ -0,0 +1,716 @@ +/* +Copyright (c) 1992,1993,1994,1995,1996,1997,2000. +The Regents of the University of California (Regents). +All Rights Reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for educational, research, and not-for-profit purposes, without +fee and without a signed licensing agreement, is hereby granted, provided that +the above copyright notice, this paragraph and the following two paragraphs +appear in all copies, modifications, and distributions. Contact The Office of +Technology Licensing, UC Berkeley, 2150 Shattuck Avenue, Suite 510, Berkeley, +CA 94720-1620, (510) 643-7201, for commercial licensing opportunities. + +Written by Matt Wright and Adrian Freed, The Center for New Music and Audio +Technologies, University of California, Berkeley. + + IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, + SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, + ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF + REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING + DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". + REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, + ENHANCEMENTS, OR MODIFICATIONS. +*/ + + /* + + dumpOSC.c + server that displays OpenSoundControl messages sent to it + for debugging client udp and UNIX protocol + + by Matt Wright, 6/3/97 + modified from dumpSC.c, by Matt Wright and Adrian Freed + + version 0.2: Added "-silent" option a.k.a. "-quiet" + + version 0.3: Incorporated patches from Nicola Bernardini to make + things Linux-friendly. Also added ntohl() in the right places + to support little-endian architectures. + + + + compile: + cc -o dumpOSC dumpOSC.c + + to-do: + + More robustness in saying exactly what's wrong with ill-formed + messages. (If they don't make sense, show exactly what was + received.) + + Time-based features: print time-received for each packet + + Clean up to separate OSC parsing code from socket/select stuff + +*/ + + +#if defined(__sgi) || defined(__linux) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef NEED_SCHEDCTL_AND_LOCK +#include +#include +#endif + + +char *htm_error_string; +typedef int Boolean; +typedef void *OBJ; + +typedef struct ClientAddressStruct { + struct sockaddr_in cl_addr; + int clilen; + int sockfd; +} *ClientAddr; + +Boolean ShowBytes = FALSE; +Boolean Silent = FALSE; + +/* Declarations */ +static int unixinitudp(int chan); +static int initudp(int chan); +static void closeudp(int sockfd); +Boolean ClientReply(int packetsize, void *packet, int socketfd, + void *clientaddresspointer, int clientaddressbufferlength); +void sgi_CleanExit(void); +Boolean sgi_HaveToQuit(void); +int RegisterPollingDevice(int fd, void (*callbackfunction)(int , void *), void *dummy); +static void catch_sigint(); +static int Synthmessage(char *m, int n, void *clientdesc, int clientdesclength, int fd) ; +void ParseOSCPacket(char *buf, int n, ClientAddr returnAddr); +static void Smessage(char *address, void *v, int n, ClientAddr returnAddr); +static void PrintTypeTaggedArgs(void *v, int n); +static void PrintHeuristicallyTypeGuessedArgs(void *v, int n, int skipComma); +char *DataAfterAlignedString(char *string, char *boundary) ; +Boolean IsNiceString(char *string, char *boundary) ; +void complain(char *s, ...); + + +#define UNIXDG_PATH "/tmp/htm" +#define UNIXDG_TMP "/tmp/htm.XXXXXX" +static int unixinitudp(int chan) +{ + struct sockaddr_un serv_addr; + int sockfd; + + if((sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) + return sockfd; + + bzero((char *)&serv_addr, sizeof(serv_addr)); + serv_addr.sun_family = AF_UNIX; + strcpy(serv_addr.sun_path, UNIXDG_PATH); + sprintf(serv_addr.sun_path+strlen(serv_addr.sun_path), "%d", chan); + unlink(serv_addr.sun_path); + if(bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr.sun_family)+strlen(serv_addr.sun_path)) < 0) + { + perror("unable to bind\n"); + return -1; + } + + fcntl(sockfd, F_SETFL, FNDELAY); + return sockfd; +} + +static int initudp(int chan) +{ + struct sockaddr_in serv_addr; + int sockfd; + + if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + return sockfd; + bzero((char *)&serv_addr, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); + serv_addr.sin_port = htons(chan); + + if(bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) + { + perror("unable to bind\n"); + return -1; + } + + fcntl(sockfd, F_SETFL, FNDELAY); + return sockfd; +} + +static void closeudp(int sockfd) { + close(sockfd); +} + +static Boolean catchupflag=FALSE; +Boolean ClientReply(int packetsize, void *packet, int socketfd, + void *clientaddresspointer, int clientaddressbufferlength) +{ + if(!clientaddresspointer) return FALSE; + catchupflag= TRUE; + return packetsize==sendto(socketfd, packet, packetsize, 0, clientaddresspointer, clientaddressbufferlength); +} + +static Boolean exitflag= FALSE; +void sgi_CleanExit(void) { + exitflag = TRUE; +} + +Boolean sgi_HaveToQuit(void) { + return exitflag; +} + + +/* file descriptor poll table */ +static int npolldevs =0; +typedef struct polldev +{ + int fd; + void (*callbackfunction)(int , void *); + void *dummy; +} polldev; +#define TABMAX 8 +static polldev polldevs[TABMAX]; + + +/* Register a device (referred to by a file descriptor that the caller + should have already successfully obtained from a system call) to be + polled as real-time constraints allowed. + + When a select(2) call indicates activity on the file descriptor, the + callback function is called with the file descripter as first + argument and the given dummy argument (presumably a pointer to the + instance variables associated with the device). +*/ +int RegisterPollingDevice(int fd, void (*callbackfunction)(int , void *), void *dummy) +{ + if(npolldevscl_addr.sin_addr.s_addr; + printf("Client address %p:\n", CA); + printf(" clilen %d, sockfd %d\n", CA->clilen, CA->sockfd); + printf(" sin_family %d, sin_port %d\n", CA->cl_addr.sin_family, + CA->cl_addr.sin_port); + printf(" address: (%x) %s\n", addr, inet_ntoa(CA->cl_addr.sin_addr)); + + printf(" sin_zero = \"%c%c%c%c%c%c%c%c\"\n", + CA->cl_addr.sin_zero[0], + CA->cl_addr.sin_zero[1], + CA->cl_addr.sin_zero[2], + CA->cl_addr.sin_zero[3], + CA->cl_addr.sin_zero[4], + CA->cl_addr.sin_zero[5], + CA->cl_addr.sin_zero[6], + CA->cl_addr.sin_zero[7]); + + printf("\n"); +} + + +void ParseOSCPacket(char *buf, int n, ClientAddr returnAddr) { + int size, messageLen, i; + char *messageName; + char *args; + +#ifdef PRINTADDRS + PrintClientAddr(returnAddr); +#endif + + + if ((n%4) != 0) { + complain("SynthControl packet size (%d) not a multiple of 4 bytes: dropping", + n); + return; + } + + if ((n >= 8) && (strncmp(buf, "#bundle", 8) == 0)) { + /* This is a bundle message. */ + + if (n < 16) { + complain("Bundle message too small (%d bytes) for time tag", n); + return; + } + + /* Print the time tag */ + printf("[ %lx%08lx\n", ntohl(*((unsigned long *)(buf+8))), + ntohl(*((unsigned long *)(buf+12)))); + /* Note: if we wanted to actually use the time tag as a little-endian + 64-bit int, we'd have to word-swap the two 32-bit halves of it */ + + i = 16; /* Skip "#group\0" and time tag */ + while(i n) { + complain("Bad size count %d in bundle (only %d bytes left in entire bundle)", + size, n-i-4); + return; + } + + /* Recursively handle element of bundle */ + ParseOSCPacket(buf+i+4, size, returnAddr); + i += 4 + size; + } + if (i != n) { + complain("This can't happen"); + } + printf("]\n"); + } else { + /* This is not a bundle message */ + + messageName = buf; + args = DataAfterAlignedString(messageName, buf+n); + if (args == 0) { + complain("Bad message name string: %s\nDropping entire message.\n", + htm_error_string); + return; + } + messageLen = args-messageName; + Smessage(messageName, (void *)args, n-messageLen, returnAddr); + } +} + +#define SMALLEST_POSITIVE_FLOAT 0.000001f + +static void Smessage(char *address, void *v, int n, ClientAddr returnAddr) { + char *chars = v; + + printf("%s ", address); + + if (n != 0) { + if (chars[0] == ',') { + if (chars[1] != ',') { + /* This message begins with a type-tag string */ + PrintTypeTaggedArgs(v, n); + } else { + /* Double comma means an escaped real comma, not a type string */ + PrintHeuristicallyTypeGuessedArgs(v, n, 1); + } + } else { + PrintHeuristicallyTypeGuessedArgs(v, n, 0); + } + } + + printf("\n"); + fflush(stdout); /* Added for Sami 5/21/98 */ +} + +static void PrintTypeTaggedArgs(void *v, int n) { + char *typeTags, *thisType; + char *p; + + typeTags = v; + + if (!IsNiceString(typeTags, typeTags+n)) { + /* No null-termination, so maybe it wasn't a type tag + string after all */ + PrintHeuristicallyTypeGuessedArgs(v, n, 0); + return; + } + + p = DataAfterAlignedString(typeTags, typeTags+n); + + + for (thisType = typeTags + 1; *thisType != 0; ++thisType) { + switch (*thisType) { + case 'i': case 'r': case 'm': case 'c': + printf("%d ", ntohl(*((int *) p))); + p += 4; + break; + + case 'f': { + int i = ntohl(*((int *) p)); + float *floatp = ((float *) (&i)); + printf("%f ", *floatp); + p += 4; + } + break; + + case 'h': case 't': + printf("[A 64-bit int] "); + p += 8; + break; + + case 'd': + printf("[A 64-bit float] "); + p += 8; + break; + + case 's': case 'S': + if (!IsNiceString(p, typeTags+n)) { + printf("Type tag said this arg is a string but it's not!\n"); + return; + } else { + printf("\"%s\" ", p); + p = DataAfterAlignedString(p, typeTags+n); + } + break; + + case 'T': printf("[True] "); break; + case 'F': printf("[False] "); break; + case 'N': printf("[Nil]"); break; + case 'I': printf("[Infinitum]"); break; + + default: + printf("[Unrecognized type tag %c]", *thisType); + return; + } + } +} + +static void PrintHeuristicallyTypeGuessedArgs(void *v, int n, int skipComma) { + int i, thisi; + float thisf; + int *ints; + char *chars; + char *string, *nextString; + + + /* Go through the arguments 32 bits at a time */ + ints = v; + chars = v; + + for (i = 0; i= -1000 && thisi <= 1000000) { + printf("%d ", thisi); + i++; + } else if (thisf >= -1000.f && thisf <= 1000000.f && + (thisf <=0.0f || thisf >= SMALLEST_POSITIVE_FLOAT)) { + printf("%f ", thisf); + i++; + } else if (IsNiceString(string, chars+n)) { + nextString = DataAfterAlignedString(string, chars+n); + printf("\"%s\" ", (i == 0 && skipComma) ? string +1 : string); + i += (nextString-string) / 4; + } else { + printf("0x%x ", ints[i]); + i++; + } + } +} + + +#define STRING_ALIGN_PAD 4 + +char *DataAfterAlignedString(char *string, char *boundary) +{ + /* The argument is a block of data beginning with a string. The + string has (presumably) been padded with extra null characters + so that the overall length is a multiple of STRING_ALIGN_PAD + bytes. Return a pointer to the next byte after the null + byte(s). The boundary argument points to the character after + the last valid character in the buffer---if the string hasn't + ended by there, something's wrong. + + If the data looks wrong, return 0, and set htm_error_string */ + + int i; + + if ((boundary - string) %4 != 0) { + fprintf(stderr, "Internal error: DataAfterAlignedString: bad boundary\n"); + return 0; + } + + for (i = 0; string[i] != '\0'; i++) { + if (string + i >= boundary) { + htm_error_string = "DataAfterAlignedString: Unreasonably long string"; + return 0; + } + } + + /* Now string[i] is the first null character */ + i++; + + for (; (i % STRING_ALIGN_PAD) != 0; i++) { + if (string + i >= boundary) { + htm_error_string = "DataAfterAlignedString: Unreasonably long string"; + return 0; + } + if (string[i] != '\0') { + htm_error_string = "DataAfterAlignedString: Incorrectly padded string."; + return 0; + } + } + + return string+i; +} + +Boolean IsNiceString(char *string, char *boundary) +{ + /* Arguments same as DataAfterAlignedString(). Is the given "string" + really a string? I.e., is it a sequence of isprint() characters + terminated with 1-4 null characters to align on a 4-byte boundary? */ + + int i; + + if ((boundary - string) %4 != 0) { + fprintf(stderr, "Internal error: IsNiceString: bad boundary\n"); + return 0; + } + + for (i = 0; string[i] != '\0'; i++) { + if (!isprint(string[i])) return FALSE; + if (string + i >= boundary) return FALSE; + } + + /* If we made it this far, it's a null-terminated sequence of printing characters + in the given boundary. Now we just make sure it's null padded... */ + + /* Now string[i] is the first null character */ + i++; + for (; (i % STRING_ALIGN_PAD) != 0; i++) { + if (string[i] != '\0') return FALSE; + } + + return TRUE; +} + + + + + + + +#define MAXMESG 32768 +static char mbuf[MAXMESG]; + +int main(int argc, char **argv) { + int udp_port; /* port to receive parameter updates from */ + + struct sockaddr_in cl_addr; + int clilen,maxclilen=sizeof(cl_addr); + struct sockaddr_un ucl_addr; + int uclilen,umaxclilen=sizeof(ucl_addr); + int i,n; + + + clilen = maxclilen; + uclilen = umaxclilen; + + udp_port = -1; + for (i=1; i < argc; ++i) { + if (strcmp(argv[i], "-showbytes") == 0) { + ShowBytes = TRUE; + } else if (strcmp(argv[i], "-silent") == 0 || + strcmp(argv[i], "-quiet") == 0) { + Silent = TRUE; + } else if (udp_port != -1) { + goto usageError; + } else { + udp_port = atoi(argv[i]); + if (udp_port == 0) { + goto usageError; + } + } + } + + if (udp_port == -1) { + usageError: + fprintf(stderr, "Usage\n\tdumpOSC portno [-showbytes] [-quiet]\n\t(responds to udp and UNIX packets on that port no)\n"); + exit(1); + } + + + n = recvfrom(0, mbuf, MAXMESG, 0, &cl_addr, &clilen); + if(n>0) + { + sockfd = 0; + udp_port = -1; + Synthmessage(mbuf, n, &cl_addr, clilen,sockfd) ; + } + else + { sockfd=initudp(udp_port); + usockfd=unixinitudp(udp_port); + } + + if (!Silent) { + printf("dumpOSC version 0.2 (6/18/97 Matt Wright). Unix/UDP Port %d \n", udp_port); + printf("Copyright (c) 1992,1996,1997 Regents of the University of California.\n"); + } + if(sockfd>=0 && usockfd>=0) + { + fd_set read_fds, write_fds; + int nfds; +#define max(a,b) (((a) > (b)) ? (a) : (b)) + nfds = max(sockfd, usockfd)+ 1; + { + int j; + for(j=0;j=nfds) + { + nfds = polldevs[j].fd+1; +/* +printf("polldev %d\n", polldevs[j].fd); +*/ + } + } +/* + printf("nfds %d\n", nfds); +*/ + caught_sigint = 0; + sigset(SIGINT, catch_sigint); /* set sig handler */ + + while(!caught_sigint) + { + + int r; + + back: + + FD_ZERO(&read_fds); /* clear read_fds */ + FD_ZERO(&write_fds); /* clear write_fds */ + FD_SET(sockfd, &read_fds); + FD_SET(usockfd, &read_fds); + { + int j; + + for(j=0;j0) + { + int r; + /* printf("received UDP packet of length %d\n", n); */ + r = Synthmessage(mbuf, n, &cl_addr, clilen, sockfd) ; + + if( sgi_HaveToQuit()) goto out; + if(r>0) goto back; + clilen = maxclilen; + } + } + if(FD_ISSET(usockfd, &read_fds)) + { + uclilen = umaxclilen; + while( (n = recvfrom(usockfd, mbuf, MAXMESG, 0, &ucl_addr, &uclilen)) >0) + { + int r; + /* printf("received UNIX packet of length %d\n", n); */ + + r=Synthmessage(mbuf, n, &ucl_addr, uclilen,usockfd) ; + + if( sgi_HaveToQuit()) goto out; + if(r>0) goto back; + uclilen = umaxclilen; + } + } + } /* End of while(!caught_sigint) */ + + +out: ; + } + else + perror("initudp"); + + return 0; +} + + +#include +void complain(char *s, ...) { + va_list ap; + va_start(ap, s); + fprintf(stderr, "*** ERROR: "); + vfprintf(stderr, s, ap); + fprintf(stderr, "\n"); + va_end(ap); +} + +#endif /* __sgi or LINUX */ diff --git a/send+dump/dumpUDP.c b/send+dump/dumpUDP.c new file mode 100644 index 0000000..3876812 --- /dev/null +++ b/send+dump/dumpUDP.c @@ -0,0 +1,191 @@ +/* +Copyright (c) 1998. The Regents of the University of California (Regents). +All Rights Reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for educational, research, and not-for-profit purposes, without +fee and without a signed licensing agreement, is hereby granted, provided that +the above copyright notice, this paragraph and the following two paragraphs +appear in all copies, modifications, and distributions. Contact The Office of +Technology Licensing, UC Berkeley, 2150 Shattuck Avenue, Suite 510, Berkeley, +CA 94720-1620, (510) 643-7201, for commercial licensing opportunities. + +Written by Matt Wright, The Center for New Music and Audio Technologies, +University of California, Berkeley. + + IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, + SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, + ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF + REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING + DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". + REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, + ENHANCEMENTS, OR MODIFICATIONS. + +dumpUDP.c: smallest UDP receiving application +by Matt Wright, 9/9/98 + +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +typedef struct ClientAddressStruct { + struct sockaddr_in cl_addr; + int clilen; + int sockfd; +} *ClientAddr; + +void PrintClientAddr(ClientAddr CA) { + unsigned long addr = CA->cl_addr.sin_addr.s_addr; + printf("Client address %p:\n", CA); + printf(" clilen %d, sockfd %d\n", CA->clilen, CA->sockfd); + printf(" sin_family %d, sin_port %d\n", CA->cl_addr.sin_family, + CA->cl_addr.sin_port); + printf(" address: (%x) %s\n", addr, inet_ntoa(CA->cl_addr.sin_addr)); + + printf(" sin_zero = \"%c%c%c%c%c%c%c%c\"\n", + CA->cl_addr.sin_zero[0], + CA->cl_addr.sin_zero[1], + CA->cl_addr.sin_zero[2], + CA->cl_addr.sin_zero[3], + CA->cl_addr.sin_zero[4], + CA->cl_addr.sin_zero[5], + CA->cl_addr.sin_zero[6], + CA->cl_addr.sin_zero[7]); + + printf("\n"); +} + + +static int initudp(int port) { + struct sockaddr_in serv_addr; + int n, sockfd; + + if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + return sockfd; + bzero((char *)&serv_addr, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); + serv_addr.sin_port = htons(port); + + if(bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) + { + perror("unable to bind\n"); + return -1; + } + + fcntl(sockfd, F_SETFL, FNDELAY); + return sockfd; +} + + +static void closeudp(int sockfd) { + close(sockfd); +} + + +static int time_to_quit; + +static void catch_sigint() { + time_to_quit = 1; +} + +void GotAPacket(char *buf, int n, ClientAddr returnAddr) { + printf("received UDP packet of length %d\n", n); + PrintClientAddr(returnAddr); +} + +#define MAXMESG 32768 +static char mbuf[MAXMESG]; + +void ReceivePacket(int sockfd) { + struct ClientAddressStruct returnAddress; + int maxclilen=sizeof(returnAddress.cl_addr); + int n; + + returnAddress.clilen = maxclilen; + while( (n = recvfrom(sockfd, mbuf, MAXMESG, 0, &(returnAddress.cl_addr), + &(returnAddress.clilen))) >0) { + GotAPacket(mbuf, n, &returnAddress); + + if (time_to_quit) return; + returnAddress.clilen = maxclilen; + } +} + +void main(int argc, char **argv) { + int udp_port; /* port to receive parameter updates from */ + int sockfd; + int i; + + fd_set read_fds, write_fds; + int nfds; + + udp_port = 7000; + + sockfd=initudp(udp_port); + + if(sockfd<0) { + perror("initudp"); + return; + } + + nfds = sockfd + 1; + + time_to_quit = 0; + sigset(SIGINT, catch_sigint); /* set sig handler */ + + while(!time_to_quit) + { + + int c,r; + + back: + + FD_ZERO(&read_fds); /* clear read_fds */ + FD_ZERO(&write_fds); /* clear write_fds */ + FD_SET(sockfd, &read_fds); + + + r = select(nfds, &read_fds, &write_fds, (fd_set *)0, + (struct timeval *)0); + if (r < 0) /* select reported an error */ + goto out; + + if(FD_ISSET(sockfd, &read_fds)) { + ReceivePacket(sockfd); + } + + } /* End of while(!time_to_quit) */ +out: ; +} diff --git a/send+dump/htmsocket.c b/send+dump/htmsocket.c new file mode 100644 index 0000000..e4f447f --- /dev/null +++ b/send+dump/htmsocket.c @@ -0,0 +1,230 @@ +/* +Copyright (c) 1992,1996,1998. +The Regents of the University of California (Regents). +All Rights Reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for educational, research, and not-for-profit purposes, without +fee and without a signed licensing agreement, is hereby granted, provided that +the above copyright notice, this paragraph and the following two paragraphs +appear in all copies, modifications, and distributions. Contact The Office of +Technology Licensing, UC Berkeley, 2150 Shattuck Avenue, Suite 510, Berkeley, +CA 94720-1620, (510) 643-7201, for commercial licensing opportunities. + +Written by Adrian Freed, The Center for New Music and Audio Technologies, +University of California, Berkeley. + + IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, + SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, + ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF + REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING + DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". + REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, + ENHANCEMENTS, OR MODIFICATIONS. +*/ + + /* htmsocket.c + + Adrian Freed + send parameters to htm servers by udp or UNIX protocol + + Modified 6/6/96 by Matt Wright to understand symbolic host names + in addition to X.X.X.X addresses. + */ + + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define UNIXDG_PATH "/tmp/htm" +#define UNIXDG_TMP "/tmp/htm.XXXXXX" +#include "htmsocket.h" +typedef struct +{ + float srate; + + struct sockaddr_in serv_addr; /* udp socket */ + struct sockaddr_un userv_addr; /* UNIX socket */ + int sockfd; /* socket file descriptor */ + int index, len,uservlen; + void *addr; + int id; +} desc; + +/* open a socket for HTM communication to given host on given portnumber */ +/* if host is 0 then UNIX protocol is used (i.e. local communication */ +void *OpenHTMSocket(char *host, int portnumber) +{ + int sockfd; + struct sockaddr_in cl_addr; + struct sockaddr_un ucl_addr; + desc *o; + o = malloc(sizeof(*o)); + if(!o) + return 0; + if(!host) + { + char *mktemp(char *); + int clilen; + o->len = sizeof(ucl_addr); + /* + * Fill in the structure "userv_addr" with the address of the + * server that we want to send to. + */ + + bzero((char *) &o->userv_addr, sizeof(o->userv_addr)); + o->userv_addr.sun_family = AF_UNIX; + strcpy(o->userv_addr.sun_path, UNIXDG_PATH); + sprintf(o->userv_addr.sun_path+strlen(o->userv_addr.sun_path), "%d", portnumber); + o->uservlen = sizeof(o->userv_addr.sun_family) + strlen(o->userv_addr.sun_path); + o->addr = &(o->userv_addr); + /* + * Open a socket (a UNIX domain datagram socket). + */ + + if ( (sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) >= 0) + { + /* + * Bind a local address for us. + * In the UNIX domain we have to choose our own name (that + * should be unique). We'll use mktemp() to create a unique + * pathname, based on our process id. + */ + + bzero((char *) &ucl_addr, sizeof(ucl_addr)); /* zero out */ + ucl_addr.sun_family = AF_UNIX; + strcpy(ucl_addr.sun_path, UNIXDG_TMP); + + mktemp(ucl_addr.sun_path); + clilen = sizeof(ucl_addr.sun_family) + strlen(ucl_addr.sun_path); + + if (bind(sockfd, (struct sockaddr *) &ucl_addr, clilen) < 0) + { + perror("client: can't bind local address"); + close(sockfd); + sockfd = -1; + } + } + else + perror("unable to make socket\n"); + + }else + { + /* + * Fill in the structure "serv_addr" with the address of the + * server that we want to send to. + */ + o->len = sizeof(cl_addr); + bzero((char *)&o->serv_addr, sizeof(o->serv_addr)); + o->serv_addr.sin_family = AF_INET; + + /* MW 6/6/96: Call gethostbyname() instead of inet_addr(), + so that host can be either an Internet host name (e.g., + "les") or an Internet address in standard dot notation + (e.g., "128.32.122.13") */ + { + struct hostent *hostsEntry; + unsigned long address; + + hostsEntry = gethostbyname(host); + if (hostsEntry == NULL) { + fprintf(stderr, "Couldn't decipher host name \"%s\"\n", + host); + herror(NULL); + return 0; + } + + address = *((unsigned long *) hostsEntry->h_addr_list[0]); + o->serv_addr.sin_addr.s_addr = address; + } + + /* was: o->serv_addr.sin_addr.s_addr = inet_addr(host); */ + + /* End MW changes */ + + o->serv_addr.sin_port = htons(portnumber); + o->addr = &(o->serv_addr); + /* + * Open a socket (a UDP domain datagram socket). + */ + if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) >= 0) + { + bzero((char *)&cl_addr, sizeof(cl_addr)); + cl_addr.sin_family = AF_INET; + cl_addr.sin_addr.s_addr = htonl(INADDR_ANY); + cl_addr.sin_port = htons(0); + + if(bind(sockfd, (struct sockaddr *) &cl_addr, sizeof(cl_addr)) < 0) + { + perror("could not bind\n"); + close(sockfd); + sockfd = -1; + } + } + else + { + perror("unable to make socket\n"); + } + + } + if(sockfd<0) + { + free(o); o = 0; + } + else + o->sockfd = sockfd; + return o; +} +#include + +static bool sendudp(const struct sockaddr *sp, int sockfd,int length, int count, void *b) +{ + int rcount; + if((rcount=sendto(sockfd, b, count, 0, sp, length)) != count) + { +/* printf("sockfd %d count %d rcount %dlength %d errno %d\n", sockfd,count,rcount,length, + errno); */ + return FALSE; + } + return TRUE; +} +bool SendHTMSocket(void *htmsendhandle, int length_in_bytes, void *buffer) +{ + desc *o = (desc *)htmsendhandle; + return sendudp(o->addr, o->sockfd, o->len, length_in_bytes, buffer); +} +void CloseHTMSocket(void *htmsendhandle) +{ + desc *o = (desc *)htmsendhandle; + close(o->sockfd); + free(o); +} diff --git a/send+dump/htmsocket.h b/send+dump/htmsocket.h new file mode 100644 index 0000000..b035b57 --- /dev/null +++ b/send+dump/htmsocket.h @@ -0,0 +1,49 @@ +/* +Copyright (c) 1992,1996. The Regents of the University of California (Regents). +All Rights Reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for educational, research, and not-for-profit purposes, without +fee and without a signed licensing agreement, is hereby granted, provided that +the above copyright notice, this paragraph and the following two paragraphs +appear in all copies, modifications, and distributions. Contact The Office of +Technology Licensing, UC Berkeley, 2150 Shattuck Avenue, Suite 510, Berkeley, +CA 94720-1620, (510) 643-7201, for commercial licensing opportunities. + +Written by Adrian Freed, The Center for New Music and Audio Technologies, +University of California, Berkeley. + + IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, + SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, + ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF + REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING + DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". + REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, + ENHANCEMENTS, OR MODIFICATIONS. +*/ + + /* htmparam.h + + Adrian Freed + send parameters to htm servers by udp or UNIX protocol + */ +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif +typedef int bool; + +/* open a socket for HTM communication to given host on given portnumber */ +/* if host is 0 then UNIX protocol is used (i.e. local communication) */ +void *OpenHTMSocket(char *host, int portnumber); + +/* send a buffer of data over htm socket, returns TRUE on success. + Note that udp sends rarely fail. UNIX sends fail if a kernal buffer overflows */ +bool SendHTMSocket(void *htmsendhandle, int length_in_bytes, void *buffer); + +/* close the socket(2) and release memory associated with it */ +void CloseHTMSocket(void *htmsendhandle); diff --git a/send+dump/sendOSC.c b/send+dump/sendOSC.c new file mode 100644 index 0000000..db188dd --- /dev/null +++ b/send+dump/sendOSC.c @@ -0,0 +1,600 @@ +/* +Copyright (c) 1996,1997. The Regents of the University of California (Regents). +All Rights Reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for educational, research, and not-for-profit purposes, without +fee and without a signed licensing agreement, is hereby granted, provided that +the above copyright notice, this paragraph and the following two paragraphs +appear in all copies, modifications, and distributions. Contact The Office of +Technology Licensing, UC Berkeley, 2150 Shattuck Avenue, Suite 510, Berkeley, +CA 94720-1620, (510) 643-7201, for commercial licensing opportunities. + +Written by Matt Wright, The Center for New Music and Audio Technologies, +University of California, Berkeley. + + IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, + SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, + ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF + REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING + DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". + REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, + ENHANCEMENTS, OR MODIFICATIONS. +*/ + +/* sendOSC.c + + Matt Wright, 6/3/97 + based on sendSC.c, which was based on a version by Adrian Freed + + Text-based OpenSoundControl client. User can enter messages via command + line arguments or standard input. + + Version 0.1: "play" feature + Version 0.2: Message type tags. + +*/ + +#define VERSION "http://cnmat.berkeley.edu/OpenSoundControl/sendOSC-0.1.html" + +/* +compiling: + cc -o sendOSC sendOSC.c htmsocket.c OpenSoundControl.c OSC_timeTag.c +*/ + + +#include "OSC-client.h" +#include "htmsocket.h" + +#include +#include +/* #include */ +#include + + +typedef struct { + enum {INT, FLOAT, STRING} type; + union { + int i; + float f; + char *s; + } datum; +} typedArg; + +void CommandLineMode(int argc, char *argv[], void *htmsocket); +void InteractiveMode(void *htmsocket); +OSCTimeTag ParseTimeTag(char *s); +void ParseInteractiveLine(OSCbuf *buf, char *mesg); +typedArg ParseToken(char *token); +int WriteMessage(OSCbuf *buf, char *messageName, int numArgs, typedArg *args); +void SendBuffer(void *htmsocket, OSCbuf *buf); +void SendData(void *htmsocket, int size, char *data); +void fatal_error(char *s); +void complain(char *s, ...); + +/* Exit status codes: + 0: successful + 2: Message(s) dropped because of buffer overflow + 3: Socket error + 4: Usage error + 5: Internal error +*/ +static int exitStatus = 0; + + +static int useTypeTags = 1; + +main(int argc, char *argv[]) { + int portnumber; + char *hostname = 0; + void *htmsocket; + + argc--; + argv++; + + if (argc == 0) { + goto usageerror; + } + + if (argc >= 1 && (strncmp(*argv, "-notypetags", 2) == 0)) { + useTypeTags = 0; + argv++; + argc--; + } + + if (argc >= 2 && (strncmp(*argv, "-r", 2) == 0)) { + hostname = getenv("REMOTE_ADDR"); + if (hostname == NULL) { + complain("sendSC -r: REMOTE_ADDR not in environment\n"); + exit(4); + } + argv++; + argc--; + } + + if (argc >= 3 && (strncmp(*argv, "-h", 2) == 0)) { + hostname = argv[1]; + argv += 2; + argc -= 2; + } + portnumber = atoi(*argv); + argv++; + argc--; + + htmsocket = OpenHTMSocket(hostname, portnumber); + if (!htmsocket) { + perror("Couldn't open socket: "); + exit(3); + } + + if (argc > 0) { + printf("host %s, port %d, %s\n", hostname, portnumber, + useTypeTags ? "use type tags" : "don't use type tags"); + CommandLineMode(argc, argv, htmsocket); + } else { + printf("sendOSC version " VERSION "\n"); + printf("by Matt Wright. Copyright (c) 1996, 1997 Regents of the University of California.\n"); + printf("host %s, port %d, %s\n", hostname, portnumber, + useTypeTags ? "use type tags" : "don't use type tags"); + InteractiveMode(htmsocket); + } + CloseHTMSocket(htmsocket); + exit(exitStatus); + + + usageerror: + complain("usage: %s [-notypetags] [-r] [-h target_host_name] port_number [message...]\n", + argv[-1]); + exit(4); + +} + + +#define MAX_ARGS 2000 +#define SC_BUFFER_SIZE 32000 +static char bufferForOSCbuf[SC_BUFFER_SIZE]; + +void CommandLineMode(int argc, char *argv[], void *htmsocket) { + char *messageName; + char *token; + typedArg args[MAX_ARGS]; + int i,j, numArgs; + OSCbuf buf[1]; + + OSC_initBuffer(buf, SC_BUFFER_SIZE, bufferForOSCbuf); + + if (argc > 1) { + if (OSC_openBundle(buf, OSCTT_Immediately())) { + complain("Problem opening bundle: %s\n", OSC_errorMessage); + return; + } + } + + for (i = 0; i < argc; i++) { + messageName = strtok(argv[i], ","); + if (messageName == NULL) { + break; + } + + j = 0; + while ((token = strtok(NULL, ",")) != NULL) { + args[j] = ParseToken(token); + j++; + if (j >= MAX_ARGS) { + complain("Sorry; your message has more than MAX_ARGS (%d) arguments; ignoring the rest.\n", + MAX_ARGS); + break; + } + } + numArgs = j; + + WriteMessage(buf, messageName, numArgs, args); + } + + if (argc > 1) { + if (OSC_closeBundle(buf)) { + complain("Problem closing bundle: %s\n", OSC_errorMessage); + return; + } + } + + SendBuffer(htmsocket, buf); +} + +#define MAXMESG 2048 + +void InteractiveMode(void *htmsocket) { + char mesg[MAXMESG]; + OSCbuf buf[1]; + int bundleDepth = 0; /* At first, we haven't seen "[". */ + + OSC_initBuffer(buf, SC_BUFFER_SIZE, bufferForOSCbuf); + + while (fgets(mesg, MAXMESG, stdin) != NULL) { + if (mesg[0] == '\n') { + if (bundleDepth > 0) { + /* Ignore blank lines inside a group. */ + } else { + /* blank line => repeat previous send */ + SendBuffer(htmsocket, buf); + } + continue; + } + + if (bundleDepth == 0) { + OSC_resetBuffer(buf); + } + + if (mesg[0] == '[') { + OSCTimeTag tt = ParseTimeTag(mesg+1); + if (OSC_openBundle(buf, tt)) { + complain("Problem opening bundle: %s\n", OSC_errorMessage); + OSC_resetBuffer(buf); + bundleDepth = 0; + continue; + } + bundleDepth++; + } else if (mesg[0] == ']' && mesg[1] == '\n' && mesg[2] == '\0') { + if (bundleDepth == 0) { + complain("Unexpected ']': not currently in a bundle.\n"); + } else { + if (OSC_closeBundle(buf)) { + complain("Problem closing bundle: %s\n", OSC_errorMessage); + OSC_resetBuffer(buf); + bundleDepth = 0; + continue; + } + + bundleDepth--; + if (bundleDepth == 0) { + SendBuffer(htmsocket, buf); + } + } + } else { + ParseInteractiveLine(buf, mesg); + if (bundleDepth != 0) { + /* Don't send anything until we close all bundles */ + } else { + SendBuffer(htmsocket, buf); + } + } + } +} + +OSCTimeTag ParseTimeTag(char *s) { + char *p, *newline; + typedArg arg; + + p = s; + while (isspace(*p)) p++; + if (*p == '\0') return OSCTT_Immediately(); + + if (*p == '+') { + /* Time tag is for some time in the future. It should be a + number of seconds as an int or float */ + + newline = strchr(s, '\n'); + if (newline != NULL) *newline = '\0'; + + p++; /* Skip '+' */ + while (isspace(*p)) p++; + + arg = ParseToken(p); + if (arg.type == STRING) { + complain("warning: inscrutable time tag request: %s\n", s); + return OSCTT_Immediately(); + } else if (arg.type == INT) { + return OSCTT_PlusSeconds(OSCTT_CurrentTime(), + (float) arg.datum.i); + } else if (arg.type == FLOAT) { + return OSCTT_PlusSeconds(OSCTT_CurrentTime(), arg.datum.f); + } else { + fatal_error("This can't happen!"); + } + } + + if (isdigit(*p) || (*p >= 'a' && *p <='f') || (*p >= 'A' && *p <='F')) { + /* They specified the 8-byte tag in hex */ + OSCTimeTag tt; + if (sscanf(p, "%llx", &tt) != 1) { + complain("warning: couldn't parse time tag %s\n", s); + return OSCTT_Immediately(); + } +#ifndef HAS8BYTEINT + if (ntohl(1) != 1) { + /* tt is a struct of seconds and fractional part, + and this machine is little-endian, so sscanf + wrote each half of the time tag in the wrong half + of the struct. */ + uint32 temp; + temp = tt.seconds; + tt.seconds = tt.fraction ; + tt.fraction = temp; + } +#endif + return tt; + } + + complain("warning: invalid time tag: %s\n", s); + return OSCTT_Immediately(); +} + + +void ParseInteractiveLine(OSCbuf *buf, char *mesg) { + char *messageName, *token, *p; + typedArg args[MAX_ARGS]; + int thisArg; + + p = mesg; + while (isspace(*p)) p++; + if (*p == '\0') return; + + messageName = p; + + if (strcmp(messageName, "play\n") == 0) { + /* Special kludge feature to save typing */ + typedArg arg; + + if (OSC_openBundle(buf, OSCTT_Immediately())) { + complain("Problem opening bundle: %s\n", OSC_errorMessage); + return; + } + + arg.type = INT; + arg.datum.i = 0; + WriteMessage(buf, "/voices/0/tp/timbre_index", 1, &arg); + + arg.type = FLOAT; + arg.datum.i = 0.0f; + WriteMessage(buf, "/voices/0/tm/goto", 1, &arg); + + if (OSC_closeBundle(buf)) { + complain("Problem closing bundle: %s\n", OSC_errorMessage); + } + + return; + } + + while (!isspace(*p) && *p != '\0') p++; + if (isspace(*p)) { + *p = '\0'; + p++; + } + + thisArg = 0; + while (*p != '\0') { + /* flush leading whitespace */ + while (isspace(*p)) p++; + if (*p == '\0') break; + + if (*p == '"') { + /* A string argument: scan for close quotes */ + p++; + args[thisArg].type = STRING; + args[thisArg].datum.s = p; + + while (*p != '"') { + if (*p == '\0') { + complain("Unterminated quote mark: ignoring line\n"); + return; + } + p++; + } + *p = '\0'; + p++; + } else { + token = p; + while (!isspace(*p) && (*p != '\0')) p++; + if (isspace(*p)) { + *p = '\0'; + p++; + } + args[thisArg] = ParseToken(token); + } + thisArg++; + if (thisArg >= MAX_ARGS) { + complain("Sorry, your message has more than MAX_ARGS (%d) arguments; ignoring the rest.\n", + MAX_ARGS); + break; + } + } + + if (WriteMessage(buf, messageName, thisArg, args) != 0) { + complain("Problem sending message: %s\n", OSC_errorMessage); + } +} + +typedArg ParseToken(char *token) { + char *p = token; + typedArg returnVal; + + /* It might be an int, a float, or a string */ + + if (*p == '-') p++; + + if (isdigit(*p) || *p == '.') { + while (isdigit(*p)) p++; + if (*p == '\0') { + returnVal.type = INT; + returnVal.datum.i = atoi(token); + return returnVal; + } + if (*p == '.') { + p++; + while (isdigit(*p)) p++; + if (*p == '\0') { + returnVal.type = FLOAT; + returnVal.datum.f = atof(token); + return returnVal; + } + } + } + + returnVal.type = STRING; + returnVal.datum.s = token; + return returnVal; +} + +int WriteMessage(OSCbuf *buf, char *messageName, int numArgs, typedArg *args) { + int j, returnVal; + + returnVal = 0; + +#ifdef DEBUG + printf("WriteMessage: %s ", messageName); + + for (j = 0; j < numArgs; j++) { + switch (args[j].type) { + case INT: + printf("%d ", args[j].datum.i); + break; + + case FLOAT: + printf("%f ", args[j].datum.f); + break; + + case STRING: + printf("%s ", args[j].datum.s); + break; + + default: + fatal_error("Unrecognized arg type"); + exit(5); + } + } + printf("\n"); +#endif + + if (!useTypeTags) { + returnVal = OSC_writeAddress(buf, messageName); + if (returnVal) { + complain("Problem writing address: %s\n", OSC_errorMessage); + } + } else { + /* First figure out the type tags */ + char typeTags[MAX_ARGS+2]; + int i; + + typeTags[0] = ','; + + for (i = 0; i < numArgs; ++i) { + switch (args[i].type) { + case INT: + typeTags[i+1] = 'i'; + break; + + case FLOAT: + typeTags[i+1] = 'f'; + break; + + case STRING: + typeTags[i+1] = 's'; + break; + + default: + fatal_error("Unrecognized arg type"); + exit(5); + } + } + typeTags[i+1] = '\0'; + + returnVal = OSC_writeAddressAndTypes(buf, messageName, typeTags); + if (returnVal) { + complain("Problem writing address: %s\n", OSC_errorMessage); + } + } + + for (j = 0; j < numArgs; j++) { + switch (args[j].type) { + case INT: + if ((returnVal = OSC_writeIntArg(buf, args[j].datum.i)) != 0) { + return returnVal; + } + break; + + case FLOAT: + if ((returnVal = OSC_writeFloatArg(buf, args[j].datum.f)) != 0) { + return returnVal; + } + break; + + case STRING: + if ((returnVal = OSC_writeStringArg(buf, args[j].datum.s)) != 0) { + return returnVal; + } + break; + + default: + fatal_error("Unrecognized arg type"); + exit(5); + } + } + + return returnVal; +} + +void SendBuffer(void *htmsocket, OSCbuf *buf) { +#ifdef DEBUG + printf("Sending buffer...\n"); +#endif + if (OSC_isBufferEmpty(buf)) return; + if (!OSC_isBufferDone(buf)) { + fatal_error("SendBuffer() called but buffer not ready!"); + exit(5); + } + SendData(htmsocket, OSC_packetSize(buf), OSC_getPacket(buf)); +} + +void SendData(void *htmsocket, int size, char *data) { + if (!SendHTMSocket(htmsocket, size, data)) { + perror("Couldn't send out socket: "); + CloseHTMSocket(htmsocket); + exit(3); + } +} + +void fatal_error(char *s) { + fprintf(stderr, "%s\n", s); + exit(4); +} + +#include +void complain(char *s, ...) { + va_list ap; + va_start(ap, s); + vfprintf(stderr, s, ap); + va_end(ap); +} + + +#ifdef COMPUTE_MESSAGE_SIZE + /* Unused code to find the size of a message */ + + /* Compute size */ + size = SynthControl_effectiveStringLength(messageName); + + for (j = 0; j < numArgs; j++) { + switch (args[j].type) { + case INT: case FLOAT: + size += 4; + break; + + case STRING: + size += SynthControl_effectiveStringLength(args[j].datum.s); + break; + + default: + fatal_error("Unrecognized token type"); + exit(4); + } + } + + if (!SynthControl_willMessageFit(buf, size)) { + complain("Message \"%s\" won't fit in buffer: dropping.", messageName); + return; + } +#endif -- cgit v1.2.1