Add FS #10214. Initial commit of the original PDa code for the GSoC Pure Data plugin...
[kugel-rb.git] / apps / plugins / pdbox / PDa / extra / sendOSC.c
blobc00f693280a040ea1bf108ca8154af9852e4c27c
1 /*
2 Written by Matt Wright, The Center for New Music and Audio Technologies,
3 University of California, Berkeley. Copyright (c) 1996,97,98,99,2000,01,02,03
4 The Regents of the University of California (Regents).
6 Permission to use, copy, modify, distribute, and distribute modified versions
7 of this software and its documentation without fee and without a signed
8 licensing agreement, is hereby granted, provided that the above copyright
9 notice, this paragraph and the following two paragraphs appear in all copies,
10 modifications, and distributions.
12 IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
13 SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
14 OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
15 BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17 REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
20 HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
21 MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24 The OSC webpage is http://cnmat.cnmat.berkeley.edu/OpenSoundControl
28 /* sendOSC.c
30 Matt Wright, 6/3/97
31 based on sendOSC.c, which was based on a version by Adrian Freed
33 Text-based OpenSoundControl client. User can enter messages via command
34 line arguments or standard input.
36 Version 0.1: "play" feature
37 Version 0.2: Message type tags.
39 pd version branched from http://www.cnmat.berkeley.edu/OpenSoundControl/src/sendOSC/sendOSC.c
40 -------------
41 -- added bundle stuff to send. jdl 20020416
42 -- tweaks for Win32 www.zeggz.com/raf 13-April-2002
43 -- ost_at_test.at + i22_at_test.at, 2000-2002
44 modified to compile as pd externel
47 #define MAX_ARGS 2000
48 #define SC_BUFFER_SIZE 64000
50 #include "m_pd.h"
51 #include "OSC-client.h"
53 #include <string.h>
54 #include <sys/types.h>
55 #include <stdlib.h>
56 #include <stdio.h>
57 #include <sys/stat.h>
58 #include <sys/types.h>
60 #ifdef WIN32
61 #include <winsock2.h>
62 #include <io.h>
63 #include <errno.h>
64 #include <fcntl.h>
65 #include <winsock2.h>
66 #include <ctype.h>
67 #include <signal.h>
68 #else
69 #include <sys/socket.h>
70 #include <netinet/in.h>
71 #include <rpc/rpc.h>
72 #include <sys/times.h>
73 #include <sys/param.h>
74 #include <sys/time.h>
75 #include <sys/ioctl.h>
76 #include <netdb.h>
77 #endif
79 #ifdef __APPLE__
80 #include <string.h>
81 #endif
83 #define UNIXDG_PATH "/tmp/htm"
84 #define UNIXDG_TMP "/tmp/htm.XXXXXX"
88 OSCTimeTag OSCTT_Immediately(void) {
89 OSCTimeTag result;
90 result.seconds = 0;
91 result.fraction = 1;
92 return result;
96 OSCTimeTag OSCTT_CurrentTime(void) {
97 OSCTimeTag result;
98 result.seconds = 0;
99 result.fraction = 1;
100 return result;
103 OSCTimeTag OSCTT_PlusSeconds(OSCTimeTag original, float secondsOffset) {
104 OSCTimeTag result;
105 result.seconds = 0;
106 result.fraction = 1;
107 return result;
111 typedef int bool;
113 typedef struct
115 float srate;
117 struct sockaddr_in serv_addr; /* udp socket */
118 #ifndef WIN32
119 struct sockaddr_un userv_addr; /* UNIX socket */
120 #endif
121 int sockfd; /* socket file descriptor */
122 int index, len,uservlen;
123 void *addr;
124 int id;
125 } desc;
128 /* open a socket for HTM communication to given host on given portnumber */
129 /* if host is 0 then UNIX protocol is used (i.e. local communication */
130 void *OpenHTMSocket(char *host, int portnumber)
132 struct sockaddr_in cl_addr;
133 #ifndef WIN32
134 int sockfd;
135 struct sockaddr_un ucl_addr;
136 #else
137 unsigned int sockfd;
138 #endif
140 desc *o;
141 int oval = 1;
142 o = malloc(sizeof(*o));
143 if(!o) return 0;
145 #ifndef WIN32
147 if(!host)
149 char *mktemp(char *);
150 int clilen;
151 o->len = sizeof(ucl_addr);
153 * Fill in the structure "userv_addr" with the address of the
154 * server that we want to send to.
157 bzero((char *) &o->userv_addr, sizeof(o->userv_addr));
158 o->userv_addr.sun_family = AF_UNIX;
159 strcpy(o->userv_addr.sun_path, UNIXDG_PATH);
160 sprintf(o->userv_addr.sun_path+strlen(o->userv_addr.sun_path), "%d", portnumber);
161 o->uservlen = sizeof(o->userv_addr.sun_family) + strlen(o->userv_addr.sun_path);
162 o->addr = &(o->userv_addr);
164 * Open a socket (a UNIX domain datagram socket).
167 if ( (sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) >= 0)
170 * Bind a local address for us.
171 * In the UNIX domain we have to choose our own name (that
172 * should be unique). We'll use mktemp() to create a unique
173 * pathname, based on our process id.
176 bzero((char *) &ucl_addr, sizeof(ucl_addr)); /* zero out */
177 ucl_addr.sun_family = AF_UNIX;
178 strcpy(ucl_addr.sun_path, UNIXDG_TMP);
180 mktemp(ucl_addr.sun_path);
181 clilen = sizeof(ucl_addr.sun_family) + strlen(ucl_addr.sun_path);
183 if (bind(sockfd, (struct sockaddr *) &ucl_addr, clilen) < 0)
185 perror("client: can't bind local address");
186 close(sockfd);
187 sockfd = -1;
190 else
191 perror("unable to make socket\n");
193 }else
195 #endif
199 * Fill in the structure "serv_addr" with the address of the
200 * server that we want to send to.
202 o->len = sizeof(cl_addr);
204 #ifdef WIN32
205 ZeroMemory((char *)&o->serv_addr, sizeof(o->serv_addr));
206 #else
207 bzero((char *)&o->serv_addr, sizeof(o->serv_addr));
208 #endif
210 o->serv_addr.sin_family = AF_INET;
212 /* MW 6/6/96: Call gethostbyname() instead of inet_addr(),
213 so that host can be either an Internet host name (e.g.,
214 "les") or an Internet address in standard dot notation
215 (e.g., "128.32.122.13") */
217 struct hostent *hostsEntry;
218 unsigned long address;
220 hostsEntry = gethostbyname(host);
221 if (hostsEntry == NULL) {
222 fprintf(stderr, "Couldn't decipher host name \"%s\"\n", host);
223 #ifndef WIN32
224 herror(NULL);
225 #endif
226 return 0;
228 address = *((unsigned long *) hostsEntry->h_addr_list[0]);
229 o->serv_addr.sin_addr.s_addr = address;
232 /* was: o->serv_addr.sin_addr.s_addr = inet_addr(host); */
234 /* End MW changes */
237 * Open a socket (a UDP domain datagram socket).
241 #ifdef WIN32
242 o->serv_addr.sin_port = htons((USHORT)portnumber);
243 o->addr = &(o->serv_addr);
244 if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) != INVALID_SOCKET) {
245 ZeroMemory((char *)&cl_addr, sizeof(cl_addr));
246 cl_addr.sin_family = AF_INET;
247 cl_addr.sin_addr.s_addr = htonl(INADDR_ANY);
248 cl_addr.sin_port = htons(0);
250 // enable broadcast: jdl ~2003
251 if(setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &oval, sizeof(int)) == -1) {
252 perror("setsockopt");
255 if(bind(sockfd, (struct sockaddr *) &cl_addr, sizeof(cl_addr)) < 0) {
256 perror("could not bind\n");
257 closesocket(sockfd);
258 sockfd = -1;
261 else { perror("unable to make socket\n");}
262 #else
263 o->serv_addr.sin_port = htons(portnumber);
264 o->addr = &(o->serv_addr);
265 if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) >= 0) {
266 bzero((char *)&cl_addr, sizeof(cl_addr));
267 cl_addr.sin_family = AF_INET;
268 cl_addr.sin_addr.s_addr = htonl(INADDR_ANY);
269 cl_addr.sin_port = htons(0);
271 // enable broadcast: jdl ~2003
272 if(setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &oval, sizeof(int)) == -1) {
273 perror("setsockopt");
276 if(bind(sockfd, (struct sockaddr *) &cl_addr, sizeof(cl_addr)) < 0) {
277 perror("could not bind\n");
278 close(sockfd);
279 sockfd = -1;
282 else { perror("unable to make socket\n");}
283 #endif
285 #ifdef WIN32
286 if(sockfd == INVALID_SOCKET) {
287 #else
288 if(sockfd < 0) {
289 #endif
290 free(o);
291 o = 0;
293 else
294 o->sockfd = sockfd;
295 return o;
298 static bool sendudp(const struct sockaddr *sp, int sockfd,int length, int count, void *b)
300 int rcount;
301 if((rcount=sendto(sockfd, b, count, 0, sp, length)) != count)
303 printf("sockfd %d count %d rcount %dlength %d\n", sockfd,count,rcount,length);
304 return FALSE;
306 return TRUE;
309 bool SendHTMSocket(void *htmsendhandle, int length_in_bytes, void *buffer)
311 desc *o = (desc *)htmsendhandle;
312 return sendudp(o->addr, o->sockfd, o->len, length_in_bytes, buffer);
314 void CloseHTMSocket(void *htmsendhandle)
316 desc *o = (desc *)htmsendhandle;
317 #ifdef WIN32
318 if(SOCKET_ERROR == closesocket(o->sockfd)) {
319 perror("CloseHTMSocket::closesocket failed\n");
320 return;
322 #else
323 if(close(o->sockfd) == -1)
325 perror("CloseHTMSocket::closesocket failed");
326 return;
328 #endif
330 free(o);
334 ///////////////////////
335 // from sendOSC
337 typedef struct {
338 //enum {INT, FLOAT, STRING} type;
339 enum {INT_osc, FLOAT_osc, STRING_osc} type;
340 union {
341 int i;
342 float f;
343 char *s;
344 } datum;
345 } typedArg;
347 void CommandLineMode(int argc, char *argv[], void *htmsocket);
348 OSCTimeTag ParseTimeTag(char *s);
349 void ParseInteractiveLine(OSCbuf *buf, char *mesg);
350 typedArg ParseToken(char *token);
351 int WriteMessage(OSCbuf *buf, char *messageName, int numArgs, typedArg *args);
352 void SendBuffer(void *htmsocket, OSCbuf *buf);
353 void SendData(void *htmsocket, int size, char *data);
354 /* defined in OSC-system-dependent.c now */
356 //static void *htmsocket;
357 static int exitStatus = 0;
358 static int useTypeTags = 0;
360 static char bufferForOSCbuf[SC_BUFFER_SIZE];
363 /////////
364 // end from sendOSC
366 static t_class *sendOSC_class;
368 typedef struct _sendOSC
370 t_object x_obj;
371 int x_protocol; // UDP/TCP (udp only atm)
372 t_int x_typetags; // typetag flag
373 void *x_htmsocket; // sending socket
374 int x_bundle; // bundle open flag
375 OSCbuf x_oscbuf[1]; // OSCbuffer
376 t_outlet *x_bdpthout;// bundle-depth floatoutlet
377 } t_sendOSC;
379 static void *sendOSC_new(t_floatarg udpflag)
381 t_sendOSC *x = (t_sendOSC *)pd_new(sendOSC_class);
382 outlet_new(&x->x_obj, &s_float);
383 x->x_htmsocket = 0; // {{raf}}
384 // set udp
385 x->x_protocol = SOCK_STREAM;
386 // set typetags to 1 by default
387 x->x_typetags = 1;
388 // bunlde is closed
389 x->x_bundle = 0;
390 OSC_initBuffer(x->x_oscbuf, SC_BUFFER_SIZE, bufferForOSCbuf);
391 x->x_bdpthout = outlet_new(&x->x_obj, 0); // outlet_float();
392 //x->x_oscbuf =
393 return (x);
397 void sendOSC_openbundle(t_sendOSC *x)
399 if (x->x_oscbuf->bundleDepth + 1 >= MAX_BUNDLE_NESTING ||
400 OSC_openBundle(x->x_oscbuf, OSCTT_Immediately()))
402 post("Problem opening bundle: %s\n", OSC_errorMessage);
403 return;
405 x->x_bundle = 1;
406 outlet_float(x->x_bdpthout, (float)x->x_oscbuf->bundleDepth);
409 static void sendOSC_closebundle(t_sendOSC *x)
411 if (OSC_closeBundle(x->x_oscbuf)) {
412 post("Problem closing bundle: %s\n", OSC_errorMessage);
413 return;
415 outlet_float(x->x_bdpthout, (float)x->x_oscbuf->bundleDepth);
416 // in bundle mode we send when bundle is closed?
417 if(!OSC_isBufferEmpty(x->x_oscbuf) > 0 && OSC_isBufferDone(x->x_oscbuf)) {
418 // post("x_oscbuf: something inside me?");
419 if (x->x_htmsocket) {
420 SendBuffer(x->x_htmsocket, x->x_oscbuf);
421 } else {
422 post("sendOSC: not connected");
424 OSC_initBuffer(x->x_oscbuf, SC_BUFFER_SIZE, bufferForOSCbuf);
425 x->x_bundle = 0;
426 return;
428 // post("x_oscbuf: something went wrong");
431 static void sendOSC_settypetags(t_sendOSC *x, t_float *f)
433 x->x_typetags = (int)f;
434 post("sendOSC.c: setting typetags %d",x->x_typetags);
438 static void sendOSC_connect(t_sendOSC *x, t_symbol *hostname,
439 t_floatarg fportno)
441 int portno = fportno;
442 /* create a socket */
444 // make sure handle is available
445 if(x->x_htmsocket == 0) {
447 x->x_htmsocket = OpenHTMSocket(hostname->s_name, portno);
448 if (!x->x_htmsocket)
449 post("Couldn't open socket: ");
450 else {
451 post("connected to port %s:%d (hSock=%d)", hostname->s_name, portno, x->x_htmsocket);
452 outlet_float(x->x_obj.ob_outlet, 1);
455 else
456 perror("call to sendOSC_connect() against UNavailable socket handle");
459 void sendOSC_disconnect(t_sendOSC *x)
461 if (x->x_htmsocket)
463 post("disconnecting htmsock (hSock=%d)...", x->x_htmsocket);
464 CloseHTMSocket(x->x_htmsocket);
465 x->x_htmsocket = 0; // {{raf}} semi-quasi-semaphorize this
466 outlet_float(x->x_obj.ob_outlet, 0);
468 else {
469 perror("call to sendOSC_disconnect() against unused socket handle");
473 void sendOSC_senduntyped(t_sendOSC *x, t_symbol *s, int argc, t_atom *argv)
475 char* targv[MAXPDARG];
476 char tmparg[MAXPDSTRING];
477 char* tmp = tmparg;
478 //char testarg[MAXPDSTRING];
479 int c;
481 post("sendOSC: use typetags 0/1 message and plain send method so send untypetagged...");
482 return;
484 //atom_string(argv,testarg, MAXPDSTRING);
485 for (c=0;c<argc;c++) {
486 atom_string(argv+c,tmp, 80);
487 targv[c] = tmp;
488 tmp += strlen(tmp)+1;
491 // this sock needs to be larger than 0, not >= ..
492 if (x->x_htmsocket)
494 CommandLineMode(argc, targv, x->x_htmsocket);
495 // post("test %d", c);
497 else {
498 post("sendOSC: not connected");
502 //////////////////////////////////////////////////////////////////////
503 // this is the real and only sending routine now, for both typed and
504 // undtyped mode.
506 static void sendOSC_sendtyped(t_sendOSC *x, t_symbol *s, int argc, t_atom *argv)
508 char* targv[MAX_ARGS];
509 char tmparg[MAXPDSTRING];
510 char* tmp = tmparg;
511 int c;
513 char *messageName;
514 char *token;
515 typedArg args[MAX_ARGS];
516 int i,j;
517 int numArgs = 0;
519 messageName = "";
520 #ifdef DEBUG
521 post ("sendOSC: messageName: %s", messageName);
522 #endif
526 for (c=0;c<argc;c++) {
527 atom_string(argv+c,tmp, 80);
529 #ifdef DEBUG
530 // post ("sendOSC: %d, %s",c, tmp);
531 #endif
533 targv[c] = tmp;
534 tmp += strlen(tmp)+1;
536 #ifdef DEBUG
537 // post ("sendOSC: %d, %s",c, targv[c]);
538 #endif
541 // this sock needs to be larger than 0, not >= ..
542 if (x->x_htmsocket > 0)
544 #ifdef DEBUG
545 post ("sendOSC: type tags? %d", useTypeTags);
546 #endif
548 messageName = strtok(targv[0], ",");
549 j = 1;
550 for (i = j; i < argc; i++) {
551 token = strtok(targv[i],",");
552 args[i-j] = ParseToken(token);
553 #ifdef DEBUG
554 printf("cell-cont: %s\n", targv[i]);
555 printf(" type-id: %d\n", args[i-j]);
556 #endif
557 numArgs = i;
561 if(WriteMessage(x->x_oscbuf, messageName, numArgs, args)) {
562 post("sendOSC: usage error, write-msg failed: %s", OSC_errorMessage);
563 return;
566 if(!x->x_bundle) {
567 SendBuffer(x->x_htmsocket, x->x_oscbuf);
568 OSC_initBuffer(x->x_oscbuf, SC_BUFFER_SIZE, bufferForOSCbuf);
571 //CommandLineMode(argc, targv, x->x_htmsocket);
572 //useTypeTags = 0;
574 else {
575 post("sendOSC: not connected");
579 void sendOSC_send(t_sendOSC *x, t_symbol *s, int argc, t_atom *argv)
581 if(!argc) {
582 post("not sending empty message.");
583 return;
585 if(x->x_typetags) {
586 useTypeTags = 1;
587 sendOSC_sendtyped(x,s,argc,argv);
588 useTypeTags = 0;
589 } else {
590 sendOSC_sendtyped(x,s,argc,argv);
594 static void sendOSC_free(t_sendOSC *x)
596 sendOSC_disconnect(x);
599 #ifdef WIN32
600 OSC_API void sendOSC_setup(void) {
601 #else
602 void sendOSC_setup(void) {
603 #endif
604 sendOSC_class = class_new(gensym("sendOSC"), (t_newmethod)sendOSC_new,
605 (t_method)sendOSC_free,
606 sizeof(t_sendOSC), 0, A_DEFFLOAT, 0);
607 class_addmethod(sendOSC_class, (t_method)sendOSC_connect,
608 gensym("connect"), A_SYMBOL, A_FLOAT, 0);
609 class_addmethod(sendOSC_class, (t_method)sendOSC_disconnect,
610 gensym("disconnect"), 0);
611 class_addmethod(sendOSC_class, (t_method)sendOSC_settypetags,
612 gensym("typetags"),
613 A_FLOAT, 0);
614 class_addmethod(sendOSC_class, (t_method)sendOSC_send,
615 gensym("send"),
616 A_GIMME, 0);
617 class_addmethod(sendOSC_class, (t_method)sendOSC_send,
618 gensym("senduntyped"),
619 A_GIMME, 0);
620 class_addmethod(sendOSC_class, (t_method)sendOSC_send,
621 gensym("sendtyped"),
622 A_GIMME, 0);
623 class_addmethod(sendOSC_class, (t_method)sendOSC_openbundle,
624 gensym("["),
625 0, 0);
626 class_addmethod(sendOSC_class, (t_method)sendOSC_closebundle,
627 gensym("]"),
628 0, 0);
629 class_sethelpsymbol(sendOSC_class, gensym("sendOSC-help.pd"));
636 /* Exit status codes:
637 0: successful
638 2: Message(s) dropped because of buffer overflow
639 3: Socket error
640 4: Usage error
641 5: Internal error
644 void CommandLineMode(int argc, char *argv[], void *htmsocket) {
645 char *messageName;
646 char *token;
647 typedArg args[MAX_ARGS];
648 int i,j, numArgs;
649 OSCbuf buf[1];
651 OSC_initBuffer(buf, SC_BUFFER_SIZE, bufferForOSCbuf);
653 if (argc > 1) {
654 post("argc (%d) > 1", argc);
657 // ParseInteractiveLine(buf, argv);
658 messageName = strtok(argv[0], ",");
660 j = 1;
661 for (i = j; i < argc; i++) {
662 token = strtok(argv[i],",");
663 args[i-j] = ParseToken(token);
664 #ifdef DEBUG
665 printf("cell-cont: %s\n", argv[i]);
666 printf(" type-id: %d\n", args[i-j]);
667 #endif
668 numArgs = i;
671 if(WriteMessage(buf, messageName, numArgs, args)) {
672 post("sendOSC: usage error. write-msg failed: %s", OSC_errorMessage);
673 return;
676 SendBuffer(htmsocket, buf);
679 #define MAXMESG 2048
681 void InteractiveMode(void *htmsocket) {
682 char mesg[MAXMESG];
683 OSCbuf buf[1];
684 int bundleDepth = 0; /* At first, we haven't seen "[". */
686 OSC_initBuffer(buf, SC_BUFFER_SIZE, bufferForOSCbuf);
688 while (fgets(mesg, MAXMESG, stdin) != NULL) {
689 if (mesg[0] == '\n') {
690 if (bundleDepth > 0) {
691 /* Ignore blank lines inside a group. */
692 } else {
693 /* blank line => repeat previous send */
694 SendBuffer(htmsocket, buf);
696 continue;
699 if (bundleDepth == 0) {
700 OSC_resetBuffer(buf);
703 if (mesg[0] == '[') {
704 OSCTimeTag tt = ParseTimeTag(mesg+1);
705 if (OSC_openBundle(buf, tt)) {
706 post("Problem opening bundle: %s\n", OSC_errorMessage);
707 OSC_resetBuffer(buf);
708 bundleDepth = 0;
709 continue;
711 bundleDepth++;
712 } else if (mesg[0] == ']' && mesg[1] == '\n' && mesg[2] == '\0') {
713 if (bundleDepth == 0) {
714 post("Unexpected ']': not currently in a bundle.\n");
715 } else {
716 if (OSC_closeBundle(buf)) {
717 post("Problem closing bundle: %s\n", OSC_errorMessage);
718 OSC_resetBuffer(buf);
719 bundleDepth = 0;
720 continue;
723 bundleDepth--;
724 if (bundleDepth == 0) {
725 SendBuffer(htmsocket, buf);
728 } else {
729 ParseInteractiveLine(buf, mesg);
730 if (bundleDepth != 0) {
731 /* Don't send anything until we close all bundles */
732 } else {
733 SendBuffer(htmsocket, buf);
739 OSCTimeTag ParseTimeTag(char *s) {
740 char *p, *newline;
741 typedArg arg;
743 p = s;
744 while (isspace(*p)) p++;
745 if (*p == '\0') return OSCTT_Immediately();
747 if (*p == '+') {
748 /* Time tag is for some time in the future. It should be a
749 number of seconds as an int or float */
751 newline = strchr(s, '\n');
752 if (newline != NULL) *newline = '\0';
754 p++; /* Skip '+' */
755 while (isspace(*p)) p++;
757 arg = ParseToken(p);
758 if (arg.type == STRING_osc) {
759 post("warning: inscrutable time tag request: %s\n", s);
760 return OSCTT_Immediately();
761 } else if (arg.type == INT_osc) {
762 return OSCTT_PlusSeconds(OSCTT_CurrentTime(),
763 (float) arg.datum.i);
764 } else if (arg.type == FLOAT_osc) {
765 return OSCTT_PlusSeconds(OSCTT_CurrentTime(), arg.datum.f);
766 } else {
767 error("This can't happen!");
771 if (isdigit(*p) || (*p >= 'a' && *p <='f') || (*p >= 'A' && *p <='F')) {
772 /* They specified the 8-byte tag in hex */
773 OSCTimeTag tt;
774 if (sscanf(p, "%llx", &tt) != 1) {
775 post("warning: couldn't parse time tag %s\n", s);
776 return OSCTT_Immediately();
778 #ifndef HAS8BYTEINT
779 if (ntohl(1) != 1) {
780 /* tt is a struct of seconds and fractional part,
781 and this machine is little-endian, so sscanf
782 wrote each half of the time tag in the wrong half
783 of the struct. */
784 int temp;
785 temp = tt.seconds;
786 tt.seconds = tt.fraction ;
787 tt.fraction = temp;
789 #endif
790 return tt;
793 post("warning: invalid time tag: %s\n", s);
794 return OSCTT_Immediately();
798 void ParseInteractiveLine(OSCbuf *buf, char *mesg) {
799 char *messageName, *token, *p;
800 typedArg args[MAX_ARGS];
801 int thisArg;
803 p = mesg;
804 while (isspace(*p)) p++;
805 if (*p == '\0') return;
807 messageName = p;
809 if (strcmp(messageName, "play\n") == 0) {
810 /* Special kludge feature to save typing */
811 typedArg arg;
813 if (OSC_openBundle(buf, OSCTT_Immediately())) {
814 post("Problem opening bundle: %s\n", OSC_errorMessage);
815 return;
818 arg.type = INT_osc;
819 arg.datum.i = 0;
820 WriteMessage(buf, "/voices/0/tp/timbre_index", 1, &arg);
822 arg.type = FLOAT_osc;
823 arg.datum.i = 0.0f;
824 WriteMessage(buf, "/voices/0/tm/goto", 1, &arg);
826 if (OSC_closeBundle(buf)) {
827 post("Problem closing bundle: %s\n", OSC_errorMessage);
830 return;
833 while (!isspace(*p) && *p != '\0') p++;
834 if (isspace(*p)) {
835 *p = '\0';
836 p++;
839 thisArg = 0;
840 while (*p != '\0') {
841 /* flush leading whitespace */
842 while (isspace(*p)) p++;
843 if (*p == '\0') break;
845 if (*p == '"') {
846 /* A string argument: scan for close quotes */
847 p++;
848 args[thisArg].type = STRING_osc;
849 args[thisArg].datum.s = p;
851 while (*p != '"') {
852 if (*p == '\0') {
853 post("Unterminated quote mark: ignoring line\n");
854 return;
856 p++;
858 *p = '\0';
859 p++;
860 } else {
861 token = p;
862 while (!isspace(*p) && (*p != '\0')) p++;
863 if (isspace(*p)) {
864 *p = '\0';
865 p++;
867 args[thisArg] = ParseToken(token);
869 thisArg++;
870 if (thisArg >= MAX_ARGS) {
871 post("Sorry, your message has more than MAX_ARGS (%d) arguments; ignoring the rest.\n",
872 MAX_ARGS);
873 break;
877 if (WriteMessage(buf, messageName, thisArg, args) != 0) {
878 post("Problem sending message: %s\n", OSC_errorMessage);
882 typedArg ParseToken(char *token) {
883 char *p = token;
884 typedArg returnVal;
886 /* It might be an int, a float, or a string */
888 if (*p == '-') p++;
890 if (isdigit(*p) || *p == '.') {
891 while (isdigit(*p)) p++;
892 if (*p == '\0') {
893 returnVal.type = INT_osc;
894 returnVal.datum.i = atoi(token);
895 return returnVal;
897 if (*p == '.') {
898 p++;
899 while (isdigit(*p)) p++;
900 if (*p == '\0') {
901 returnVal.type = FLOAT_osc;
902 returnVal.datum.f = atof(token);
903 return returnVal;
908 returnVal.type = STRING_osc;
909 returnVal.datum.s = token;
910 return returnVal;
913 int WriteMessage(OSCbuf *buf, char *messageName, int numArgs, typedArg *args) {
914 int j, returnVal;
915 const int wmERROR = -1;
917 returnVal = 0;
919 #ifdef DEBUG
920 printf("WriteMessage: %s ", messageName);
922 for (j = 0; j < numArgs; j++) {
923 switch (args[j].type) {
924 case INT_osc:
925 printf("%d ", args[j].datum.i);
926 break;
928 case FLOAT_osc:
929 printf("%f ", args[j].datum.f);
930 break;
932 case STRING_osc:
933 printf("%s ", args[j].datum.s);
934 break;
936 default:
937 error("Unrecognized arg type, (not exiting)");
938 return(wmERROR);
941 printf("\n");
942 #endif
944 if (!useTypeTags) {
945 returnVal = OSC_writeAddress(buf, messageName);
946 if (returnVal) {
947 post("Problem writing address: %s\n", OSC_errorMessage);
949 } else {
950 /* First figure out the type tags */
951 char typeTags[MAX_ARGS+2];
952 int i;
954 typeTags[0] = ',';
956 for (i = 0; i < numArgs; ++i) {
957 switch (args[i].type) {
958 case INT_osc:
959 typeTags[i+1] = 'i';
960 break;
962 case FLOAT_osc:
963 typeTags[i+1] = 'f';
964 break;
966 case STRING_osc:
967 typeTags[i+1] = 's';
968 break;
970 default:
971 error("Unrecognized arg type (not exiting)");
972 return(wmERROR);
975 typeTags[i+1] = '\0';
977 returnVal = OSC_writeAddressAndTypes(buf, messageName, typeTags);
978 if (returnVal) {
979 post("Problem writing address: %s\n", OSC_errorMessage);
983 for (j = 0; j < numArgs; j++) {
984 switch (args[j].type) {
985 case INT_osc:
986 if ((returnVal = OSC_writeIntArg(buf, args[j].datum.i)) != 0) {
987 return returnVal;
989 break;
991 case FLOAT_osc:
992 if ((returnVal = OSC_writeFloatArg(buf, args[j].datum.f)) != 0) {
993 return returnVal;
995 break;
997 case STRING_osc:
998 if ((returnVal = OSC_writeStringArg(buf, args[j].datum.s)) != 0) {
999 return returnVal;
1001 break;
1003 default:
1004 error("Unrecognized arg type (not exiting)");
1005 returnVal = wmERROR;
1008 return returnVal;
1011 void SendBuffer(void *htmsocket, OSCbuf *buf) {
1012 #ifdef DEBUG
1013 printf("Sending buffer...\n");
1014 #endif
1015 if (OSC_isBufferEmpty(buf)) {
1016 post("SendBuffer() called but buffer empty");
1017 return;
1019 if (!OSC_isBufferDone(buf)) {
1020 error("SendBuffer() called but buffer not ready!, not exiting");
1021 return; //{{raf}}
1023 SendData(htmsocket, OSC_packetSize(buf), OSC_getPacket(buf));
1026 void SendData(void *htmsocket, int size, char *data) {
1027 if (!SendHTMSocket(htmsocket, size, data)) {
1028 post("SendData::SendHTMSocket()failure -- not connected");
1029 CloseHTMSocket(htmsocket);
1035 /* ----------------------
1036 OSC-client code
1040 /* Here are the possible values of the state field: */
1042 #define EMPTY 0 /* Nothing written to packet yet */
1043 #define ONE_MSG_ARGS 1 /* Packet has a single message; gathering arguments */
1044 #define NEED_COUNT 2 /* Just opened a bundle; must write message name or
1045 open another bundle */
1046 #define GET_ARGS 3 /* Getting arguments to a message. If we see a message
1047 name or a bundle open/close then the current message
1048 will end. */
1049 #define DONE 4 /* All open bundles have been closed, so can't write
1050 anything else */
1052 #ifdef WIN32
1053 #include <winsock2.h>
1054 #include <io.h>
1055 #include <stdio.h>
1056 #include <errno.h>
1057 #include <fcntl.h>
1058 #include <sys/types.h>
1059 #include <sys/stat.h>
1060 #endif
1062 #ifdef __APPLE__
1063 #include <sys/types.h>
1064 #endif
1066 #ifdef unix
1067 #include <netinet/in.h>
1068 #include <stdio.h>
1069 #endif
1072 char *OSC_errorMessage;
1074 static int OSC_padString(char *dest, char *str);
1075 static int OSC_padStringWithAnExtraStupidComma(char *dest, char *str);
1076 static int OSC_WritePadding(char *dest, int i);
1077 static int CheckTypeTag(OSCbuf *buf, char expectedType);
1079 void OSC_initBuffer(OSCbuf *buf, int size, char *byteArray) {
1080 buf->buffer = byteArray;
1081 buf->size = size;
1082 OSC_resetBuffer(buf);
1085 void OSC_resetBuffer(OSCbuf *buf) {
1086 buf->bufptr = buf->buffer;
1087 buf->state = EMPTY;
1088 buf->bundleDepth = 0;
1089 buf->prevCounts[0] = 0;
1090 buf->gettingFirstUntypedArg = 0;
1091 buf->typeStringPtr = 0;
1094 int OSC_isBufferEmpty(OSCbuf *buf) {
1095 return buf->bufptr == buf->buffer;
1098 int OSC_freeSpaceInBuffer(OSCbuf *buf) {
1099 return buf->size - (buf->bufptr - buf->buffer);
1102 int OSC_isBufferDone(OSCbuf *buf) {
1103 return (buf->state == DONE || buf->state == ONE_MSG_ARGS);
1106 char *OSC_getPacket(OSCbuf *buf) {
1107 #ifdef ERROR_CHECK_GETPACKET
1108 if (buf->state == DONE || buf->state == ONE_MSG_ARGS) {
1109 return buf->buffer;
1110 } else {
1111 OSC_errorMessage = "Packet has unterminated bundles";
1112 return 0;
1114 #else
1115 return buf->buffer;
1116 #endif
1119 int OSC_packetSize(OSCbuf *buf) {
1120 #ifdef ERROR_CHECK_PACKETSIZE
1121 if (buf->state == DONE || buf->state == ONE_MSG_ARGS) {
1122 return (buf->bufptr - buf->buffer);
1123 } else {
1124 OSC_errorMessage = "Packet has unterminated bundles";
1125 return 0;
1127 #else
1128 return (buf->bufptr - buf->buffer);
1129 #endif
1132 #define CheckOverflow(buf, bytesNeeded) { if ((bytesNeeded) > OSC_freeSpaceInBuffer(buf)) {OSC_errorMessage = "buffer overflow"; return 1;}}
1134 static void PatchMessageSize(OSCbuf *buf) {
1135 int4byte size;
1136 size = buf->bufptr - ((char *) buf->thisMsgSize) - 4;
1137 *(buf->thisMsgSize) = htonl(size);
1140 int OSC_openBundle(OSCbuf *buf, OSCTimeTag tt) {
1141 if (buf->state == ONE_MSG_ARGS) {
1142 OSC_errorMessage = "Can't open a bundle in a one-message packet";
1143 return 3;
1146 if (buf->state == DONE) {
1147 OSC_errorMessage = "This packet is finished; can't open a new bundle";
1148 return 4;
1151 if (++(buf->bundleDepth) >= MAX_BUNDLE_NESTING) {
1152 OSC_errorMessage = "Bundles nested too deeply; change MAX_BUNDLE_NESTING in OpenSoundControl.h";
1153 return 2;
1156 if (CheckTypeTag(buf, '\0')) return 9;
1158 if (buf->state == GET_ARGS) {
1159 PatchMessageSize(buf);
1162 if (buf->state == EMPTY) {
1163 /* Need 16 bytes for "#bundle" and time tag */
1164 CheckOverflow(buf, 16);
1165 } else {
1166 /* This bundle is inside another bundle, so we need to leave
1167 a blank size count for the size of this current bundle. */
1168 CheckOverflow(buf, 20);
1169 *((int4byte *)buf->bufptr) = 0xaaaaaaaa;
1170 buf->prevCounts[buf->bundleDepth] = (int4byte *)buf->bufptr;
1172 buf->bufptr += 4;
1175 buf->bufptr += OSC_padString(buf->bufptr, "#bundle");
1178 *((OSCTimeTag *) buf->bufptr) = tt;
1180 if (htonl(1) != 1) {
1181 /* Byte swap the 8-byte integer time tag */
1182 int4byte *intp = (int4byte *)buf->bufptr;
1183 intp[0] = htonl(intp[0]);
1184 intp[1] = htonl(intp[1]);
1186 #ifdef HAS8BYTEINT
1187 { /* tt is a 64-bit int so we have to swap the two 32-bit words.
1188 (Otherwise tt is a struct of two 32-bit words, and even though
1189 each word was wrong-endian, they were in the right order
1190 in the struct.) */
1191 int4byte temp = intp[0];
1192 intp[0] = intp[1];
1193 intp[1] = temp;
1195 #endif
1198 buf->bufptr += sizeof(OSCTimeTag);
1200 buf->state = NEED_COUNT;
1202 buf->gettingFirstUntypedArg = 0;
1203 buf->typeStringPtr = 0;
1204 return 0;
1208 int OSC_closeBundle(OSCbuf *buf) {
1209 if (buf->bundleDepth == 0) {
1210 /* This handles EMPTY, ONE_MSG, ARGS, and DONE */
1211 OSC_errorMessage = "Can't close bundle; no bundle is open!";
1212 return 5;
1215 if (CheckTypeTag(buf, '\0')) return 9;
1217 if (buf->state == GET_ARGS) {
1218 PatchMessageSize(buf);
1221 if (buf->bundleDepth == 1) {
1222 /* Closing the last bundle: No bundle size to patch */
1223 buf->state = DONE;
1224 } else {
1225 /* Closing a sub-bundle: patch bundle size */
1226 int size = buf->bufptr - ((char *) buf->prevCounts[buf->bundleDepth]) - 4;
1227 *(buf->prevCounts[buf->bundleDepth]) = htonl(size);
1228 buf->state = NEED_COUNT;
1231 --buf->bundleDepth;
1232 buf->gettingFirstUntypedArg = 0;
1233 buf->typeStringPtr = 0;
1234 return 0;
1238 int OSC_closeAllBundles(OSCbuf *buf) {
1239 if (buf->bundleDepth == 0) {
1240 /* This handles EMPTY, ONE_MSG, ARGS, and DONE */
1241 OSC_errorMessage = "Can't close all bundles; no bundle is open!";
1242 return 6;
1245 if (CheckTypeTag(buf, '\0')) return 9;
1247 while (buf->bundleDepth > 0) {
1248 OSC_closeBundle(buf);
1250 buf->typeStringPtr = 0;
1251 return 0;
1254 int OSC_writeAddress(OSCbuf *buf, char *name) {
1255 int4byte paddedLength;
1257 if (buf->state == ONE_MSG_ARGS) {
1258 OSC_errorMessage = "This packet is not a bundle, so you can't write another address";
1259 return 7;
1262 if (buf->state == DONE) {
1263 OSC_errorMessage = "This packet is finished; can't write another address";
1264 return 8;
1267 if (CheckTypeTag(buf, '\0')) return 9;
1269 paddedLength = OSC_effectiveStringLength(name);
1271 if (buf->state == EMPTY) {
1272 /* This will be a one-message packet, so no sizes to worry about */
1273 CheckOverflow(buf, paddedLength);
1274 buf->state = ONE_MSG_ARGS;
1275 } else {
1276 /* GET_ARGS or NEED_COUNT */
1277 CheckOverflow(buf, 4+paddedLength);
1278 if (buf->state == GET_ARGS) {
1279 /* Close the old message */
1280 PatchMessageSize(buf);
1282 buf->thisMsgSize = (int4byte *)buf->bufptr;
1283 *(buf->thisMsgSize) = 0xbbbbbbbb;
1284 buf->bufptr += 4;
1285 buf->state = GET_ARGS;
1288 /* Now write the name */
1289 buf->bufptr += OSC_padString(buf->bufptr, name);
1290 buf->typeStringPtr = 0;
1291 buf->gettingFirstUntypedArg = 1;
1293 return 0;
1296 int OSC_writeAddressAndTypes(OSCbuf *buf, char *name, char *types) {
1297 int result;
1298 int4byte paddedLength;
1300 if (CheckTypeTag(buf, '\0')) return 9;
1302 result = OSC_writeAddress(buf, name);
1304 if (result) return result;
1306 paddedLength = OSC_effectiveStringLength(types);
1308 CheckOverflow(buf, paddedLength);
1310 buf->typeStringPtr = buf->bufptr + 1; /* skip comma */
1311 buf->bufptr += OSC_padString(buf->bufptr, types);
1313 buf->gettingFirstUntypedArg = 0;
1314 return 0;
1317 static int CheckTypeTag(OSCbuf *buf, char expectedType) {
1318 if (buf->typeStringPtr) {
1319 if (*(buf->typeStringPtr) != expectedType) {
1320 if (expectedType == '\0') {
1321 OSC_errorMessage =
1322 "According to the type tag I expected more arguments.";
1323 } else if (*(buf->typeStringPtr) == '\0') {
1324 OSC_errorMessage =
1325 "According to the type tag I didn't expect any more arguments.";
1326 } else {
1327 OSC_errorMessage =
1328 "According to the type tag I expected an argument of a different type.";
1329 printf("* Expected %c, string now %s\n", expectedType, buf->typeStringPtr);
1331 return 9;
1333 ++(buf->typeStringPtr);
1335 return 0;
1339 int OSC_writeFloatArg(OSCbuf *buf, float arg) {
1340 int4byte *intp;
1341 //int result;
1343 CheckOverflow(buf, 4);
1345 if (CheckTypeTag(buf, 'f')) return 9;
1347 /* Pretend arg is a long int so we can use htonl() */
1348 intp = ((int4byte *) &arg);
1349 *((int4byte *) buf->bufptr) = htonl(*intp);
1351 buf->bufptr += 4;
1353 buf->gettingFirstUntypedArg = 0;
1354 return 0;
1359 int OSC_writeFloatArgs(OSCbuf *buf, int numFloats, float *args) {
1360 int i;
1361 int4byte *intp;
1363 CheckOverflow(buf, 4 * numFloats);
1365 /* Pretend args are long ints so we can use htonl() */
1366 intp = ((int4byte *) args);
1368 for (i = 0; i < numFloats; i++) {
1369 if (CheckTypeTag(buf, 'f')) return 9;
1370 *((int4byte *) buf->bufptr) = htonl(intp[i]);
1371 buf->bufptr += 4;
1374 buf->gettingFirstUntypedArg = 0;
1375 return 0;
1378 int OSC_writeIntArg(OSCbuf *buf, int4byte arg) {
1379 CheckOverflow(buf, 4);
1380 if (CheckTypeTag(buf, 'i')) return 9;
1382 *((int4byte *) buf->bufptr) = htonl(arg);
1383 buf->bufptr += 4;
1385 buf->gettingFirstUntypedArg = 0;
1386 return 0;
1389 int OSC_writeStringArg(OSCbuf *buf, char *arg) {
1390 int len;
1392 if (CheckTypeTag(buf, 's')) return 9;
1394 len = OSC_effectiveStringLength(arg);
1396 if (buf->gettingFirstUntypedArg && arg[0] == ',') {
1397 /* This un-type-tagged message starts with a string
1398 that starts with a comma, so we have to escape it
1399 (with a double comma) so it won't look like a type
1400 tag string. */
1402 CheckOverflow(buf, len+4); /* Too conservative */
1403 buf->bufptr +=
1404 OSC_padStringWithAnExtraStupidComma(buf->bufptr, arg);
1406 } else {
1407 CheckOverflow(buf, len);
1408 buf->bufptr += OSC_padString(buf->bufptr, arg);
1411 buf->gettingFirstUntypedArg = 0;
1412 return 0;
1416 /* String utilities */
1418 #define STRING_ALIGN_PAD 4
1419 int OSC_effectiveStringLength(char *string) {
1420 int len = strlen(string) + 1; /* We need space for the null char. */
1422 /* Round up len to next multiple of STRING_ALIGN_PAD to account for alignment padding */
1423 if ((len % STRING_ALIGN_PAD) != 0) {
1424 len += STRING_ALIGN_PAD - (len % STRING_ALIGN_PAD);
1426 return len;
1429 static int OSC_padString(char *dest, char *str) {
1430 int i;
1432 for (i = 0; str[i] != '\0'; i++) {
1433 dest[i] = str[i];
1436 return OSC_WritePadding(dest, i);
1439 static int OSC_padStringWithAnExtraStupidComma(char *dest, char *str) {
1440 int i;
1442 dest[0] = ',';
1443 for (i = 0; str[i] != '\0'; i++) {
1444 dest[i+1] = str[i];
1447 return OSC_WritePadding(dest, i+1);
1450 static int OSC_WritePadding(char *dest, int i) {
1451 dest[i] = '\0';
1452 i++;
1454 for (; (i % STRING_ALIGN_PAD) != 0; i++) {
1455 dest[i] = '\0';
1458 return i;
1463 Written by Matt Wright, The Center for New Music and Audio Technologies,
1464 University of California, Berkeley. Copyright (c) 1996,97,98,99,2000,01,02,03
1465 The Regents of the University of California (Regents).
1467 Permission to use, copy, modify, distribute, and distribute modified versions
1468 of this software and its documentation without fee and without a signed
1469 licensing agreement, is hereby granted, provided that the above copyright
1470 notice, this paragraph and the following two paragraphs appear in all copies,
1471 modifications, and distributions.
1473 IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
1474 SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
1475 OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
1476 BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1478 REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
1479 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1480 PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
1481 HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
1482 MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
1485 The OSC webpage is http://cnmat.cnmat.berkeley.edu/OpenSoundControl
1489 /* sendOSC.c
1491 Matt Wright, 6/3/97
1492 based on sendOSC.c, which was based on a version by Adrian Freed
1494 Text-based OpenSoundControl client. User can enter messages via command
1495 line arguments or standard input.
1497 Version 0.1: "play" feature
1498 Version 0.2: Message type tags.
1500 pd version branched from http://www.cnmat.berkeley.edu/OpenSoundControl/src/sendOSC/sendOSC.c
1501 -------------
1502 -- added bundle stuff to send. jdl 20020416
1503 -- tweaks for Win32 www.zeggz.com/raf 13-April-2002
1504 -- ost_at_test.at + i22_at_test.at, 2000-2002
1505 modified to compile as pd externel
1508 #define MAX_ARGS 2000
1509 #define SC_BUFFER_SIZE 64000
1511 #include "m_pd.h"
1512 #include "OSC-client.h"
1514 #include <string.h>
1515 #include <sys/types.h>
1516 #include <stdlib.h>
1517 #include <stdio.h>
1518 #include <sys/stat.h>
1519 #include <sys/types.h>
1521 #ifdef WIN32
1522 #include <winsock2.h>
1523 #include <io.h>
1524 #include <errno.h>
1525 #include <fcntl.h>
1526 #include <winsock2.h>
1527 #include <ctype.h>
1528 #include <signal.h>
1529 #else
1530 #include <sys/socket.h>
1531 #include <netinet/in.h>
1532 #include <rpc/rpc.h>
1533 #include <sys/times.h>
1534 #include <sys/param.h>
1535 #include <sys/time.h>
1536 #include <sys/ioctl.h>
1537 #include <netdb.h>
1538 #endif
1540 #ifdef __APPLE__
1541 #include <string.h>
1542 #endif
1544 #define UNIXDG_PATH "/tmp/htm"
1545 #define UNIXDG_TMP "/tmp/htm.XXXXXX"
1549 OSCTimeTag OSCTT_Immediately(void) {
1550 OSCTimeTag result;
1551 result.seconds = 0;
1552 result.fraction = 1;
1553 return result;
1557 OSCTimeTag OSCTT_CurrentTime(void) {
1558 OSCTimeTag result;
1559 result.seconds = 0;
1560 result.fraction = 1;
1561 return result;
1564 OSCTimeTag OSCTT_PlusSeconds(OSCTimeTag original, float secondsOffset) {
1565 OSCTimeTag result;
1566 result.seconds = 0;
1567 result.fraction = 1;
1568 return result;
1572 typedef int bool;
1574 typedef struct
1576 float srate;
1578 struct sockaddr_in serv_addr; /* udp socket */
1579 #ifndef WIN32
1580 struct sockaddr_un userv_addr; /* UNIX socket */
1581 #endif
1582 int sockfd; /* socket file descriptor */
1583 int index, len,uservlen;
1584 void *addr;
1585 int id;
1586 } desc;
1589 /* open a socket for HTM communication to given host on given portnumber */
1590 /* if host is 0 then UNIX protocol is used (i.e. local communication */
1591 void *OpenHTMSocket(char *host, int portnumber)
1593 struct sockaddr_in cl_addr;
1594 #ifndef WIN32
1595 int sockfd;
1596 struct sockaddr_un ucl_addr;
1597 #else
1598 unsigned int sockfd;
1599 #endif
1601 desc *o;
1602 int oval = 1;
1603 o = malloc(sizeof(*o));
1604 if(!o) return 0;
1606 #ifndef WIN32
1608 if(!host)
1610 char *mktemp(char *);
1611 int clilen;
1612 o->len = sizeof(ucl_addr);
1614 * Fill in the structure "userv_addr" with the address of the
1615 * server that we want to send to.
1618 bzero((char *) &o->userv_addr, sizeof(o->userv_addr));
1619 o->userv_addr.sun_family = AF_UNIX;
1620 strcpy(o->userv_addr.sun_path, UNIXDG_PATH);
1621 sprintf(o->userv_addr.sun_path+strlen(o->userv_addr.sun_path), "%d", portnumber);
1622 o->uservlen = sizeof(o->userv_addr.sun_family) + strlen(o->userv_addr.sun_path);
1623 o->addr = &(o->userv_addr);
1625 * Open a socket (a UNIX domain datagram socket).
1628 if ( (sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) >= 0)
1631 * Bind a local address for us.
1632 * In the UNIX domain we have to choose our own name (that
1633 * should be unique). We'll use mktemp() to create a unique
1634 * pathname, based on our process id.
1637 bzero((char *) &ucl_addr, sizeof(ucl_addr)); /* zero out */
1638 ucl_addr.sun_family = AF_UNIX;
1639 strcpy(ucl_addr.sun_path, UNIXDG_TMP);
1641 mktemp(ucl_addr.sun_path);
1642 clilen = sizeof(ucl_addr.sun_family) + strlen(ucl_addr.sun_path);
1644 if (bind(sockfd, (struct sockaddr *) &ucl_addr, clilen) < 0)
1646 perror("client: can't bind local address");
1647 close(sockfd);
1648 sockfd = -1;
1651 else
1652 perror("unable to make socket\n");
1654 }else
1656 #endif
1660 * Fill in the structure "serv_addr" with the address of the
1661 * server that we want to send to.
1663 o->len = sizeof(cl_addr);
1665 #ifdef WIN32
1666 ZeroMemory((char *)&o->serv_addr, sizeof(o->serv_addr));
1667 #else
1668 bzero((char *)&o->serv_addr, sizeof(o->serv_addr));
1669 #endif
1671 o->serv_addr.sin_family = AF_INET;
1673 /* MW 6/6/96: Call gethostbyname() instead of inet_addr(),
1674 so that host can be either an Internet host name (e.g.,
1675 "les") or an Internet address in standard dot notation
1676 (e.g., "128.32.122.13") */
1678 struct hostent *hostsEntry;
1679 unsigned long address;
1681 hostsEntry = gethostbyname(host);
1682 if (hostsEntry == NULL) {
1683 fprintf(stderr, "Couldn't decipher host name \"%s\"\n", host);
1684 #ifndef WIN32
1685 herror(NULL);
1686 #endif
1687 return 0;
1689 address = *((unsigned long *) hostsEntry->h_addr_list[0]);
1690 o->serv_addr.sin_addr.s_addr = address;
1693 /* was: o->serv_addr.sin_addr.s_addr = inet_addr(host); */
1695 /* End MW changes */
1698 * Open a socket (a UDP domain datagram socket).
1702 #ifdef WIN32
1703 o->serv_addr.sin_port = htons((USHORT)portnumber);
1704 o->addr = &(o->serv_addr);
1705 if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) != INVALID_SOCKET) {
1706 ZeroMemory((char *)&cl_addr, sizeof(cl_addr));
1707 cl_addr.sin_family = AF_INET;
1708 cl_addr.sin_addr.s_addr = htonl(INADDR_ANY);
1709 cl_addr.sin_port = htons(0);
1711 // enable broadcast: jdl ~2003
1712 if(setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &oval, sizeof(int)) == -1) {
1713 perror("setsockopt");
1716 if(bind(sockfd, (struct sockaddr *) &cl_addr, sizeof(cl_addr)) < 0) {
1717 perror("could not bind\n");
1718 closesocket(sockfd);
1719 sockfd = -1;
1722 else { perror("unable to make socket\n");}
1723 #else
1724 o->serv_addr.sin_port = htons(portnumber);
1725 o->addr = &(o->serv_addr);
1726 if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) >= 0) {
1727 bzero((char *)&cl_addr, sizeof(cl_addr));
1728 cl_addr.sin_family = AF_INET;
1729 cl_addr.sin_addr.s_addr = htonl(INADDR_ANY);
1730 cl_addr.sin_port = htons(0);
1732 // enable broadcast: jdl ~2003
1733 if(setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &oval, sizeof(int)) == -1) {
1734 perror("setsockopt");
1737 if(bind(sockfd, (struct sockaddr *) &cl_addr, sizeof(cl_addr)) < 0) {
1738 perror("could not bind\n");
1739 close(sockfd);
1740 sockfd = -1;
1743 else { perror("unable to make socket\n");}
1744 #endif
1746 #ifdef WIN32
1747 if(sockfd == INVALID_SOCKET) {
1748 #else
1749 if(sockfd < 0) {
1750 #endif
1751 free(o);
1752 o = 0;
1754 else
1755 o->sockfd = sockfd;
1756 return o;
1759 static bool sendudp(const struct sockaddr *sp, int sockfd,int length, int count, void *b)
1761 int rcount;
1762 if((rcount=sendto(sockfd, b, count, 0, sp, length)) != count)
1764 printf("sockfd %d count %d rcount %dlength %d\n", sockfd,count,rcount,length);
1765 return FALSE;
1767 return TRUE;
1770 bool SendHTMSocket(void *htmsendhandle, int length_in_bytes, void *buffer)
1772 desc *o = (desc *)htmsendhandle;
1773 return sendudp(o->addr, o->sockfd, o->len, length_in_bytes, buffer);
1775 void CloseHTMSocket(void *htmsendhandle)
1777 desc *o = (desc *)htmsendhandle;
1778 #ifdef WIN32
1779 if(SOCKET_ERROR == closesocket(o->sockfd)) {
1780 perror("CloseHTMSocket::closesocket failed\n");
1781 return;
1783 #else
1784 if(close(o->sockfd) == -1)
1786 perror("CloseHTMSocket::closesocket failed");
1787 return;
1789 #endif
1791 free(o);
1795 ///////////////////////
1796 // from sendOSC
1798 typedef struct {
1799 //enum {INT, FLOAT, STRING} type;
1800 enum {INT_osc, FLOAT_osc, STRING_osc} type;
1801 union {
1802 int i;
1803 float f;
1804 char *s;
1805 } datum;
1806 } typedArg;
1808 void CommandLineMode(int argc, char *argv[], void *htmsocket);
1809 OSCTimeTag ParseTimeTag(char *s);
1810 void ParseInteractiveLine(OSCbuf *buf, char *mesg);
1811 typedArg ParseToken(char *token);
1812 int WriteMessage(OSCbuf *buf, char *messageName, int numArgs, typedArg *args);
1813 void SendBuffer(void *htmsocket, OSCbuf *buf);
1814 void SendData(void *htmsocket, int size, char *data);
1815 /* defined in OSC-system-dependent.c now */
1817 //static void *htmsocket;
1818 static int exitStatus = 0;
1819 static int useTypeTags = 0;
1821 static char bufferForOSCbuf[SC_BUFFER_SIZE];
1824 /////////
1825 // end from sendOSC
1827 static t_class *sendOSC_class;
1829 typedef struct _sendOSC
1831 t_object x_obj;
1832 int x_protocol; // UDP/TCP (udp only atm)
1833 t_int x_typetags; // typetag flag
1834 void *x_htmsocket; // sending socket
1835 int x_bundle; // bundle open flag
1836 OSCbuf x_oscbuf[1]; // OSCbuffer
1837 t_outlet *x_bdpthout;// bundle-depth floatoutlet
1838 } t_sendOSC;
1840 static void *sendOSC_new(t_floatarg udpflag)
1842 t_sendOSC *x = (t_sendOSC *)pd_new(sendOSC_class);
1843 outlet_new(&x->x_obj, &s_float);
1844 x->x_htmsocket = 0; // {{raf}}
1845 // set udp
1846 x->x_protocol = SOCK_STREAM;
1847 // set typetags to 1 by default
1848 x->x_typetags = 1;
1849 // bunlde is closed
1850 x->x_bundle = 0;
1851 OSC_initBuffer(x->x_oscbuf, SC_BUFFER_SIZE, bufferForOSCbuf);
1852 x->x_bdpthout = outlet_new(&x->x_obj, 0); // outlet_float();
1853 //x->x_oscbuf =
1854 return (x);
1858 void sendOSC_openbundle(t_sendOSC *x)
1860 if (x->x_oscbuf->bundleDepth + 1 >= MAX_BUNDLE_NESTING ||
1861 OSC_openBundle(x->x_oscbuf, OSCTT_Immediately()))
1863 post("Problem opening bundle: %s\n", OSC_errorMessage);
1864 return;
1866 x->x_bundle = 1;
1867 outlet_float(x->x_bdpthout, (float)x->x_oscbuf->bundleDepth);
1870 static void sendOSC_closebundle(t_sendOSC *x)
1872 if (OSC_closeBundle(x->x_oscbuf)) {
1873 post("Problem closing bundle: %s\n", OSC_errorMessage);
1874 return;
1876 outlet_float(x->x_bdpthout, (float)x->x_oscbuf->bundleDepth);
1877 // in bundle mode we send when bundle is closed?
1878 if(!OSC_isBufferEmpty(x->x_oscbuf) > 0 && OSC_isBufferDone(x->x_oscbuf)) {
1879 // post("x_oscbuf: something inside me?");
1880 if (x->x_htmsocket) {
1881 SendBuffer(x->x_htmsocket, x->x_oscbuf);
1882 } else {
1883 post("sendOSC: not connected");
1885 OSC_initBuffer(x->x_oscbuf, SC_BUFFER_SIZE, bufferForOSCbuf);
1886 x->x_bundle = 0;
1887 return;
1889 // post("x_oscbuf: something went wrong");
1892 static void sendOSC_settypetags(t_sendOSC *x, t_float *f)
1894 x->x_typetags = (int)f;
1895 post("sendOSC.c: setting typetags %d",x->x_typetags);
1899 static void sendOSC_connect(t_sendOSC *x, t_symbol *hostname,
1900 t_floatarg fportno)
1902 int portno = fportno;
1903 /* create a socket */
1905 // make sure handle is available
1906 if(x->x_htmsocket == 0) {
1908 x->x_htmsocket = OpenHTMSocket(hostname->s_name, portno);
1909 if (!x->x_htmsocket)
1910 post("Couldn't open socket: ");
1911 else {
1912 post("connected to port %s:%d (hSock=%d)", hostname->s_name, portno, x->x_htmsocket);
1913 outlet_float(x->x_obj.ob_outlet, 1);
1916 else
1917 perror("call to sendOSC_connect() against UNavailable socket handle");
1920 void sendOSC_disconnect(t_sendOSC *x)
1922 if (x->x_htmsocket)
1924 post("disconnecting htmsock (hSock=%d)...", x->x_htmsocket);
1925 CloseHTMSocket(x->x_htmsocket);
1926 x->x_htmsocket = 0; // {{raf}} semi-quasi-semaphorize this
1927 outlet_float(x->x_obj.ob_outlet, 0);
1929 else {
1930 perror("call to sendOSC_disconnect() against unused socket handle");
1934 void sendOSC_senduntyped(t_sendOSC *x, t_symbol *s, int argc, t_atom *argv)
1936 char* targv[MAXPDARG];
1937 char tmparg[MAXPDSTRING];
1938 char* tmp = tmparg;
1939 //char testarg[MAXPDSTRING];
1940 int c;
1942 post("sendOSC: use typetags 0/1 message and plain send method so send untypetagged...");
1943 return;
1945 //atom_string(argv,testarg, MAXPDSTRING);
1946 for (c=0;c<argc;c++) {
1947 atom_string(argv+c,tmp, 80);
1948 targv[c] = tmp;
1949 tmp += strlen(tmp)+1;
1952 // this sock needs to be larger than 0, not >= ..
1953 if (x->x_htmsocket)
1955 CommandLineMode(argc, targv, x->x_htmsocket);
1956 // post("test %d", c);
1958 else {
1959 post("sendOSC: not connected");
1963 //////////////////////////////////////////////////////////////////////
1964 // this is the real and only sending routine now, for both typed and
1965 // undtyped mode.
1967 static void sendOSC_sendtyped(t_sendOSC *x, t_symbol *s, int argc, t_atom *argv)
1969 char* targv[MAX_ARGS];
1970 char tmparg[MAXPDSTRING];
1971 char* tmp = tmparg;
1972 int c;
1974 char *messageName;
1975 char *token;
1976 typedArg args[MAX_ARGS];
1977 int i,j;
1978 int numArgs = 0;
1980 messageName = "";
1981 #ifdef DEBUG
1982 post ("sendOSC: messageName: %s", messageName);
1983 #endif
1987 for (c=0;c<argc;c++) {
1988 atom_string(argv+c,tmp, 80);
1990 #ifdef DEBUG
1991 // post ("sendOSC: %d, %s",c, tmp);
1992 #endif
1994 targv[c] = tmp;
1995 tmp += strlen(tmp)+1;
1997 #ifdef DEBUG
1998 // post ("sendOSC: %d, %s",c, targv[c]);
1999 #endif
2002 // this sock needs to be larger than 0, not >= ..
2003 if (x->x_htmsocket > 0)
2005 #ifdef DEBUG
2006 post ("sendOSC: type tags? %d", useTypeTags);
2007 #endif
2009 messageName = strtok(targv[0], ",");
2010 j = 1;
2011 for (i = j; i < argc; i++) {
2012 token = strtok(targv[i],",");
2013 args[i-j] = ParseToken(token);
2014 #ifdef DEBUG
2015 printf("cell-cont: %s\n", targv[i]);
2016 printf(" type-id: %d\n", args[i-j]);
2017 #endif
2018 numArgs = i;
2022 if(WriteMessage(x->x_oscbuf, messageName, numArgs, args)) {
2023 post("sendOSC: usage error, write-msg failed: %s", OSC_errorMessage);
2024 return;
2027 if(!x->x_bundle) {
2028 SendBuffer(x->x_htmsocket, x->x_oscbuf);
2029 OSC_initBuffer(x->x_oscbuf, SC_BUFFER_SIZE, bufferForOSCbuf);
2032 //CommandLineMode(argc, targv, x->x_htmsocket);
2033 //useTypeTags = 0;
2035 else {
2036 post("sendOSC: not connected");
2040 void sendOSC_send(t_sendOSC *x, t_symbol *s, int argc, t_atom *argv)
2042 if(!argc) {
2043 post("not sending empty message.");
2044 return;
2046 if(x->x_typetags) {
2047 useTypeTags = 1;
2048 sendOSC_sendtyped(x,s,argc,argv);
2049 useTypeTags = 0;
2050 } else {
2051 sendOSC_sendtyped(x,s,argc,argv);
2055 static void sendOSC_free(t_sendOSC *x)
2057 sendOSC_disconnect(x);
2060 #ifdef WIN32
2061 OSC_API void sendOSC_setup(void) {
2062 #else
2063 void sendOSC_setup(void) {
2064 #endif
2065 sendOSC_class = class_new(gensym("sendOSC"), (t_newmethod)sendOSC_new,
2066 (t_method)sendOSC_free,
2067 sizeof(t_sendOSC), 0, A_DEFFLOAT, 0);
2068 class_addmethod(sendOSC_class, (t_method)sendOSC_connect,
2069 gensym("connect"), A_SYMBOL, A_FLOAT, 0);
2070 class_addmethod(sendOSC_class, (t_method)sendOSC_disconnect,
2071 gensym("disconnect"), 0);
2072 class_addmethod(sendOSC_class, (t_method)sendOSC_settypetags,
2073 gensym("typetags"),
2074 A_FLOAT, 0);
2075 class_addmethod(sendOSC_class, (t_method)sendOSC_send,
2076 gensym("send"),
2077 A_GIMME, 0);
2078 class_addmethod(sendOSC_class, (t_method)sendOSC_send,
2079 gensym("senduntyped"),
2080 A_GIMME, 0);
2081 class_addmethod(sendOSC_class, (t_method)sendOSC_send,
2082 gensym("sendtyped"),
2083 A_GIMME, 0);
2084 class_addmethod(sendOSC_class, (t_method)sendOSC_openbundle,
2085 gensym("["),
2086 0, 0);
2087 class_addmethod(sendOSC_class, (t_method)sendOSC_closebundle,
2088 gensym("]"),
2089 0, 0);
2090 class_sethelpsymbol(sendOSC_class, gensym("sendOSC-help.pd"));
2097 /* Exit status codes:
2098 0: successful
2099 2: Message(s) dropped because of buffer overflow
2100 3: Socket error
2101 4: Usage error
2102 5: Internal error
2105 void CommandLineMode(int argc, char *argv[], void *htmsocket) {
2106 char *messageName;
2107 char *token;
2108 typedArg args[MAX_ARGS];
2109 int i,j, numArgs;
2110 OSCbuf buf[1];
2112 OSC_initBuffer(buf, SC_BUFFER_SIZE, bufferForOSCbuf);
2114 if (argc > 1) {
2115 post("argc (%d) > 1", argc);
2118 // ParseInteractiveLine(buf, argv);
2119 messageName = strtok(argv[0], ",");
2121 j = 1;
2122 for (i = j; i < argc; i++) {
2123 token = strtok(argv[i],",");
2124 args[i-j] = ParseToken(token);
2125 #ifdef DEBUG
2126 printf("cell-cont: %s\n", argv[i]);
2127 printf(" type-id: %d\n", args[i-j]);
2128 #endif
2129 numArgs = i;
2132 if(WriteMessage(buf, messageName, numArgs, args)) {
2133 post("sendOSC: usage error. write-msg failed: %s", OSC_errorMessage);
2134 return;
2137 SendBuffer(htmsocket, buf);
2140 #define MAXMESG 2048
2142 void InteractiveMode(void *htmsocket) {
2143 char mesg[MAXMESG];
2144 OSCbuf buf[1];
2145 int bundleDepth = 0; /* At first, we haven't seen "[". */
2147 OSC_initBuffer(buf, SC_BUFFER_SIZE, bufferForOSCbuf);
2149 while (fgets(mesg, MAXMESG, stdin) != NULL) {
2150 if (mesg[0] == '\n') {
2151 if (bundleDepth > 0) {
2152 /* Ignore blank lines inside a group. */
2153 } else {
2154 /* blank line => repeat previous send */
2155 SendBuffer(htmsocket, buf);
2157 continue;
2160 if (bundleDepth == 0) {
2161 OSC_resetBuffer(buf);
2164 if (mesg[0] == '[') {
2165 OSCTimeTag tt = ParseTimeTag(mesg+1);
2166 if (OSC_openBundle(buf, tt)) {
2167 post("Problem opening bundle: %s\n", OSC_errorMessage);
2168 OSC_resetBuffer(buf);
2169 bundleDepth = 0;
2170 continue;
2172 bundleDepth++;
2173 } else if (mesg[0] == ']' && mesg[1] == '\n' && mesg[2] == '\0') {
2174 if (bundleDepth == 0) {
2175 post("Unexpected ']': not currently in a bundle.\n");
2176 } else {
2177 if (OSC_closeBundle(buf)) {
2178 post("Problem closing bundle: %s\n", OSC_errorMessage);
2179 OSC_resetBuffer(buf);
2180 bundleDepth = 0;
2181 continue;
2184 bundleDepth--;
2185 if (bundleDepth == 0) {
2186 SendBuffer(htmsocket, buf);
2189 } else {
2190 ParseInteractiveLine(buf, mesg);
2191 if (bundleDepth != 0) {
2192 /* Don't send anything until we close all bundles */
2193 } else {
2194 SendBuffer(htmsocket, buf);
2200 OSCTimeTag ParseTimeTag(char *s) {
2201 char *p, *newline;
2202 typedArg arg;
2204 p = s;
2205 while (isspace(*p)) p++;
2206 if (*p == '\0') return OSCTT_Immediately();
2208 if (*p == '+') {
2209 /* Time tag is for some time in the future. It should be a
2210 number of seconds as an int or float */
2212 newline = strchr(s, '\n');
2213 if (newline != NULL) *newline = '\0';
2215 p++; /* Skip '+' */
2216 while (isspace(*p)) p++;
2218 arg = ParseToken(p);
2219 if (arg.type == STRING_osc) {
2220 post("warning: inscrutable time tag request: %s\n", s);
2221 return OSCTT_Immediately();
2222 } else if (arg.type == INT_osc) {
2223 return OSCTT_PlusSeconds(OSCTT_CurrentTime(),
2224 (float) arg.datum.i);
2225 } else if (arg.type == FLOAT_osc) {
2226 return OSCTT_PlusSeconds(OSCTT_CurrentTime(), arg.datum.f);
2227 } else {
2228 error("This can't happen!");
2232 if (isdigit(*p) || (*p >= 'a' && *p <='f') || (*p >= 'A' && *p <='F')) {
2233 /* They specified the 8-byte tag in hex */
2234 OSCTimeTag tt;
2235 if (sscanf(p, "%llx", &tt) != 1) {
2236 post("warning: couldn't parse time tag %s\n", s);
2237 return OSCTT_Immediately();
2239 #ifndef HAS8BYTEINT
2240 if (ntohl(1) != 1) {
2241 /* tt is a struct of seconds and fractional part,
2242 and this machine is little-endian, so sscanf
2243 wrote each half of the time tag in the wrong half
2244 of the struct. */
2245 int temp;
2246 temp = tt.seconds;
2247 tt.seconds = tt.fraction ;
2248 tt.fraction = temp;
2250 #endif
2251 return tt;
2254 post("warning: invalid time tag: %s\n", s);
2255 return OSCTT_Immediately();
2259 void ParseInteractiveLine(OSCbuf *buf, char *mesg) {
2260 char *messageName, *token, *p;
2261 typedArg args[MAX_ARGS];
2262 int thisArg;
2264 p = mesg;
2265 while (isspace(*p)) p++;
2266 if (*p == '\0') return;
2268 messageName = p;
2270 if (strcmp(messageName, "play\n") == 0) {
2271 /* Special kludge feature to save typing */
2272 typedArg arg;
2274 if (OSC_openBundle(buf, OSCTT_Immediately())) {
2275 post("Problem opening bundle: %s\n", OSC_errorMessage);
2276 return;
2279 arg.type = INT_osc;
2280 arg.datum.i = 0;
2281 WriteMessage(buf, "/voices/0/tp/timbre_index", 1, &arg);
2283 arg.type = FLOAT_osc;
2284 arg.datum.i = 0.0f;
2285 WriteMessage(buf, "/voices/0/tm/goto", 1, &arg);
2287 if (OSC_closeBundle(buf)) {
2288 post("Problem closing bundle: %s\n", OSC_errorMessage);
2291 return;
2294 while (!isspace(*p) && *p != '\0') p++;
2295 if (isspace(*p)) {
2296 *p = '\0';
2297 p++;
2300 thisArg = 0;
2301 while (*p != '\0') {
2302 /* flush leading whitespace */
2303 while (isspace(*p)) p++;
2304 if (*p == '\0') break;
2306 if (*p == '"') {
2307 /* A string argument: scan for close quotes */
2308 p++;
2309 args[thisArg].type = STRING_osc;
2310 args[thisArg].datum.s = p;
2312 while (*p != '"') {
2313 if (*p == '\0') {
2314 post("Unterminated quote mark: ignoring line\n");
2315 return;
2317 p++;
2319 *p = '\0';
2320 p++;
2321 } else {
2322 token = p;
2323 while (!isspace(*p) && (*p != '\0')) p++;
2324 if (isspace(*p)) {
2325 *p = '\0';
2326 p++;
2328 args[thisArg] = ParseToken(token);
2330 thisArg++;
2331 if (thisArg >= MAX_ARGS) {
2332 post("Sorry, your message has more than MAX_ARGS (%d) arguments; ignoring the rest.\n",
2333 MAX_ARGS);
2334 break;
2338 if (WriteMessage(buf, messageName, thisArg, args) != 0) {
2339 post("Problem sending message: %s\n", OSC_errorMessage);
2343 typedArg ParseToken(char *token) {
2344 char *p = token;
2345 typedArg returnVal;
2347 /* It might be an int, a float, or a string */
2349 if (*p == '-') p++;
2351 if (isdigit(*p) || *p == '.') {
2352 while (isdigit(*p)) p++;
2353 if (*p == '\0') {
2354 returnVal.type = INT_osc;
2355 returnVal.datum.i = atoi(token);
2356 return returnVal;
2358 if (*p == '.') {
2359 p++;
2360 while (isdigit(*p)) p++;
2361 if (*p == '\0') {
2362 returnVal.type = FLOAT_osc;
2363 returnVal.datum.f = atof(token);
2364 return returnVal;
2369 returnVal.type = STRING_osc;
2370 returnVal.datum.s = token;
2371 return returnVal;
2374 int WriteMessage(OSCbuf *buf, char *messageName, int numArgs, typedArg *args) {
2375 int j, returnVal;
2376 const int wmERROR = -1;
2378 returnVal = 0;
2380 #ifdef DEBUG
2381 printf("WriteMessage: %s ", messageName);
2383 for (j = 0; j < numArgs; j++) {
2384 switch (args[j].type) {
2385 case INT_osc:
2386 printf("%d ", args[j].datum.i);
2387 break;
2389 case FLOAT_osc:
2390 printf("%f ", args[j].datum.f);
2391 break;
2393 case STRING_osc:
2394 printf("%s ", args[j].datum.s);
2395 break;
2397 default:
2398 error("Unrecognized arg type, (not exiting)");
2399 return(wmERROR);
2402 printf("\n");
2403 #endif
2405 if (!useTypeTags) {
2406 returnVal = OSC_writeAddress(buf, messageName);
2407 if (returnVal) {
2408 post("Problem writing address: %s\n", OSC_errorMessage);
2410 } else {
2411 /* First figure out the type tags */
2412 char typeTags[MAX_ARGS+2];
2413 int i;
2415 typeTags[0] = ',';
2417 for (i = 0; i < numArgs; ++i) {
2418 switch (args[i].type) {
2419 case INT_osc:
2420 typeTags[i+1] = 'i';
2421 break;
2423 case FLOAT_osc:
2424 typeTags[i+1] = 'f';
2425 break;
2427 case STRING_osc:
2428 typeTags[i+1] = 's';
2429 break;
2431 default:
2432 error("Unrecognized arg type (not exiting)");
2433 return(wmERROR);
2436 typeTags[i+1] = '\0';
2438 returnVal = OSC_writeAddressAndTypes(buf, messageName, typeTags);
2439 if (returnVal) {
2440 post("Problem writing address: %s\n", OSC_errorMessage);
2444 for (j = 0; j < numArgs; j++) {
2445 switch (args[j].type) {
2446 case INT_osc:
2447 if ((returnVal = OSC_writeIntArg(buf, args[j].datum.i)) != 0) {
2448 return returnVal;
2450 break;
2452 case FLOAT_osc:
2453 if ((returnVal = OSC_writeFloatArg(buf, args[j].datum.f)) != 0) {
2454 return returnVal;
2456 break;
2458 case STRING_osc:
2459 if ((returnVal = OSC_writeStringArg(buf, args[j].datum.s)) != 0) {
2460 return returnVal;
2462 break;
2464 default:
2465 error("Unrecognized arg type (not exiting)");
2466 returnVal = wmERROR;
2469 return returnVal;
2472 void SendBuffer(void *htmsocket, OSCbuf *buf) {
2473 #ifdef DEBUG
2474 printf("Sending buffer...\n");
2475 #endif
2476 if (OSC_isBufferEmpty(buf)) {
2477 post("SendBuffer() called but buffer empty");
2478 return;
2480 if (!OSC_isBufferDone(buf)) {
2481 error("SendBuffer() called but buffer not ready!, not exiting");
2482 return; //{{raf}}
2484 SendData(htmsocket, OSC_packetSize(buf), OSC_getPacket(buf));
2487 void SendData(void *htmsocket, int size, char *data) {
2488 if (!SendHTMSocket(htmsocket, size, data)) {
2489 post("SendData::SendHTMSocket()failure -- not connected");
2490 CloseHTMSocket(htmsocket);
2496 /* ----------------------
2497 OSC-client code
2501 /* Here are the possible values of the state field: */
2503 #define EMPTY 0 /* Nothing written to packet yet */
2504 #define ONE_MSG_ARGS 1 /* Packet has a single message; gathering arguments */
2505 #define NEED_COUNT 2 /* Just opened a bundle; must write message name or
2506 open another bundle */
2507 #define GET_ARGS 3 /* Getting arguments to a message. If we see a message
2508 name or a bundle open/close then the current message
2509 will end. */
2510 #define DONE 4 /* All open bundles have been closed, so can't write
2511 anything else */
2513 #ifdef WIN32
2514 #include <winsock2.h>
2515 #include <io.h>
2516 #include <stdio.h>
2517 #include <errno.h>
2518 #include <fcntl.h>
2519 #include <sys/types.h>
2520 #include <sys/stat.h>
2521 #endif
2523 #ifdef __APPLE__
2524 #include <sys/types.h>
2525 #endif
2527 #ifdef unix
2528 #include <netinet/in.h>
2529 #include <stdio.h>
2530 #endif
2533 char *OSC_errorMessage;
2535 static int OSC_padString(char *dest, char *str);
2536 static int OSC_padStringWithAnExtraStupidComma(char *dest, char *str);
2537 static int OSC_WritePadding(char *dest, int i);
2538 static int CheckTypeTag(OSCbuf *buf, char expectedType);
2540 void OSC_initBuffer(OSCbuf *buf, int size, char *byteArray) {
2541 buf->buffer = byteArray;
2542 buf->size = size;
2543 OSC_resetBuffer(buf);
2546 void OSC_resetBuffer(OSCbuf *buf) {
2547 buf->bufptr = buf->buffer;
2548 buf->state = EMPTY;
2549 buf->bundleDepth = 0;
2550 buf->prevCounts[0] = 0;
2551 buf->gettingFirstUntypedArg = 0;
2552 buf->typeStringPtr = 0;
2555 int OSC_isBufferEmpty(OSCbuf *buf) {
2556 return buf->bufptr == buf->buffer;
2559 int OSC_freeSpaceInBuffer(OSCbuf *buf) {
2560 return buf->size - (buf->bufptr - buf->buffer);
2563 int OSC_isBufferDone(OSCbuf *buf) {
2564 return (buf->state == DONE || buf->state == ONE_MSG_ARGS);
2567 char *OSC_getPacket(OSCbuf *buf) {
2568 #ifdef ERROR_CHECK_GETPACKET
2569 if (buf->state == DONE || buf->state == ONE_MSG_ARGS) {
2570 return buf->buffer;
2571 } else {
2572 OSC_errorMessage = "Packet has unterminated bundles";
2573 return 0;
2575 #else
2576 return buf->buffer;
2577 #endif
2580 int OSC_packetSize(OSCbuf *buf) {
2581 #ifdef ERROR_CHECK_PACKETSIZE
2582 if (buf->state == DONE || buf->state == ONE_MSG_ARGS) {
2583 return (buf->bufptr - buf->buffer);
2584 } else {
2585 OSC_errorMessage = "Packet has unterminated bundles";
2586 return 0;
2588 #else
2589 return (buf->bufptr - buf->buffer);
2590 #endif
2593 #define CheckOverflow(buf, bytesNeeded) { if ((bytesNeeded) > OSC_freeSpaceInBuffer(buf)) {OSC_errorMessage = "buffer overflow"; return 1;}}
2595 static void PatchMessageSize(OSCbuf *buf) {
2596 int4byte size;
2597 size = buf->bufptr - ((char *) buf->thisMsgSize) - 4;
2598 *(buf->thisMsgSize) = htonl(size);
2601 int OSC_openBundle(OSCbuf *buf, OSCTimeTag tt) {
2602 if (buf->state == ONE_MSG_ARGS) {
2603 OSC_errorMessage = "Can't open a bundle in a one-message packet";
2604 return 3;
2607 if (buf->state == DONE) {
2608 OSC_errorMessage = "This packet is finished; can't open a new bundle";
2609 return 4;
2612 if (++(buf->bundleDepth) >= MAX_BUNDLE_NESTING) {
2613 OSC_errorMessage = "Bundles nested too deeply; change MAX_BUNDLE_NESTING in OpenSoundControl.h";
2614 return 2;
2617 if (CheckTypeTag(buf, '\0')) return 9;
2619 if (buf->state == GET_ARGS) {
2620 PatchMessageSize(buf);
2623 if (buf->state == EMPTY) {
2624 /* Need 16 bytes for "#bundle" and time tag */
2625 CheckOverflow(buf, 16);
2626 } else {
2627 /* This bundle is inside another bundle, so we need to leave
2628 a blank size count for the size of this current bundle. */
2629 CheckOverflow(buf, 20);
2630 *((int4byte *)buf->bufptr) = 0xaaaaaaaa;
2631 buf->prevCounts[buf->bundleDepth] = (int4byte *)buf->bufptr;
2633 buf->bufptr += 4;
2636 buf->bufptr += OSC_padString(buf->bufptr, "#bundle");
2639 *((OSCTimeTag *) buf->bufptr) = tt;
2641 if (htonl(1) != 1) {
2642 /* Byte swap the 8-byte integer time tag */
2643 int4byte *intp = (int4byte *)buf->bufptr;
2644 intp[0] = htonl(intp[0]);
2645 intp[1] = htonl(intp[1]);
2647 #ifdef HAS8BYTEINT
2648 { /* tt is a 64-bit int so we have to swap the two 32-bit words.
2649 (Otherwise tt is a struct of two 32-bit words, and even though
2650 each word was wrong-endian, they were in the right order
2651 in the struct.) */
2652 int4byte temp = intp[0];
2653 intp[0] = intp[1];
2654 intp[1] = temp;
2656 #endif
2659 buf->bufptr += sizeof(OSCTimeTag);
2661 buf->state = NEED_COUNT;
2663 buf->gettingFirstUntypedArg = 0;
2664 buf->typeStringPtr = 0;
2665 return 0;
2669 int OSC_closeBundle(OSCbuf *buf) {
2670 if (buf->bundleDepth == 0) {
2671 /* This handles EMPTY, ONE_MSG, ARGS, and DONE */
2672 OSC_errorMessage = "Can't close bundle; no bundle is open!";
2673 return 5;
2676 if (CheckTypeTag(buf, '\0')) return 9;
2678 if (buf->state == GET_ARGS) {
2679 PatchMessageSize(buf);
2682 if (buf->bundleDepth == 1) {
2683 /* Closing the last bundle: No bundle size to patch */
2684 buf->state = DONE;
2685 } else {
2686 /* Closing a sub-bundle: patch bundle size */
2687 int size = buf->bufptr - ((char *) buf->prevCounts[buf->bundleDepth]) - 4;
2688 *(buf->prevCounts[buf->bundleDepth]) = htonl(size);
2689 buf->state = NEED_COUNT;
2692 --buf->bundleDepth;
2693 buf->gettingFirstUntypedArg = 0;
2694 buf->typeStringPtr = 0;
2695 return 0;
2699 int OSC_closeAllBundles(OSCbuf *buf) {
2700 if (buf->bundleDepth == 0) {
2701 /* This handles EMPTY, ONE_MSG, ARGS, and DONE */
2702 OSC_errorMessage = "Can't close all bundles; no bundle is open!";
2703 return 6;
2706 if (CheckTypeTag(buf, '\0')) return 9;
2708 while (buf->bundleDepth > 0) {
2709 OSC_closeBundle(buf);
2711 buf->typeStringPtr = 0;
2712 return 0;
2715 int OSC_writeAddress(OSCbuf *buf, char *name) {
2716 int4byte paddedLength;
2718 if (buf->state == ONE_MSG_ARGS) {
2719 OSC_errorMessage = "This packet is not a bundle, so you can't write another address";
2720 return 7;
2723 if (buf->state == DONE) {
2724 OSC_errorMessage = "This packet is finished; can't write another address";
2725 return 8;
2728 if (CheckTypeTag(buf, '\0')) return 9;
2730 paddedLength = OSC_effectiveStringLength(name);
2732 if (buf->state == EMPTY) {
2733 /* This will be a one-message packet, so no sizes to worry about */
2734 CheckOverflow(buf, paddedLength);
2735 buf->state = ONE_MSG_ARGS;
2736 } else {
2737 /* GET_ARGS or NEED_COUNT */
2738 CheckOverflow(buf, 4+paddedLength);
2739 if (buf->state == GET_ARGS) {
2740 /* Close the old message */
2741 PatchMessageSize(buf);
2743 buf->thisMsgSize = (int4byte *)buf->bufptr;
2744 *(buf->thisMsgSize) = 0xbbbbbbbb;
2745 buf->bufptr += 4;
2746 buf->state = GET_ARGS;
2749 /* Now write the name */
2750 buf->bufptr += OSC_padString(buf->bufptr, name);
2751 buf->typeStringPtr = 0;
2752 buf->gettingFirstUntypedArg = 1;
2754 return 0;
2757 int OSC_writeAddressAndTypes(OSCbuf *buf, char *name, char *types) {
2758 int result;
2759 int4byte paddedLength;
2761 if (CheckTypeTag(buf, '\0')) return 9;
2763 result = OSC_writeAddress(buf, name);
2765 if (result) return result;
2767 paddedLength = OSC_effectiveStringLength(types);
2769 CheckOverflow(buf, paddedLength);
2771 buf->typeStringPtr = buf->bufptr + 1; /* skip comma */
2772 buf->bufptr += OSC_padString(buf->bufptr, types);
2774 buf->gettingFirstUntypedArg = 0;
2775 return 0;
2778 static int CheckTypeTag(OSCbuf *buf, char expectedType) {
2779 if (buf->typeStringPtr) {
2780 if (*(buf->typeStringPtr) != expectedType) {
2781 if (expectedType == '\0') {
2782 OSC_errorMessage =
2783 "According to the type tag I expected more arguments.";
2784 } else if (*(buf->typeStringPtr) == '\0') {
2785 OSC_errorMessage =
2786 "According to the type tag I didn't expect any more arguments.";
2787 } else {
2788 OSC_errorMessage =
2789 "According to the type tag I expected an argument of a different type.";
2790 printf("* Expected %c, string now %s\n", expectedType, buf->typeStringPtr);
2792 return 9;
2794 ++(buf->typeStringPtr);
2796 return 0;
2800 int OSC_writeFloatArg(OSCbuf *buf, float arg) {
2801 int4byte *intp;
2802 //int result;
2804 CheckOverflow(buf, 4);
2806 if (CheckTypeTag(buf, 'f')) return 9;
2808 /* Pretend arg is a long int so we can use htonl() */
2809 intp = ((int4byte *) &arg);
2810 *((int4byte *) buf->bufptr) = htonl(*intp);
2812 buf->bufptr += 4;
2814 buf->gettingFirstUntypedArg = 0;
2815 return 0;
2820 int OSC_writeFloatArgs(OSCbuf *buf, int numFloats, float *args) {
2821 int i;
2822 int4byte *intp;
2824 CheckOverflow(buf, 4 * numFloats);
2826 /* Pretend args are long ints so we can use htonl() */
2827 intp = ((int4byte *) args);
2829 for (i = 0; i < numFloats; i++) {
2830 if (CheckTypeTag(buf, 'f')) return 9;
2831 *((int4byte *) buf->bufptr) = htonl(intp[i]);
2832 buf->bufptr += 4;
2835 buf->gettingFirstUntypedArg = 0;
2836 return 0;
2839 int OSC_writeIntArg(OSCbuf *buf, int4byte arg) {
2840 CheckOverflow(buf, 4);
2841 if (CheckTypeTag(buf, 'i')) return 9;
2843 *((int4byte *) buf->bufptr) = htonl(arg);
2844 buf->bufptr += 4;
2846 buf->gettingFirstUntypedArg = 0;
2847 return 0;
2850 int OSC_writeStringArg(OSCbuf *buf, char *arg) {
2851 int len;
2853 if (CheckTypeTag(buf, 's')) return 9;
2855 len = OSC_effectiveStringLength(arg);
2857 if (buf->gettingFirstUntypedArg && arg[0] == ',') {
2858 /* This un-type-tagged message starts with a string
2859 that starts with a comma, so we have to escape it
2860 (with a double comma) so it won't look like a type
2861 tag string. */
2863 CheckOverflow(buf, len+4); /* Too conservative */
2864 buf->bufptr +=
2865 OSC_padStringWithAnExtraStupidComma(buf->bufptr, arg);
2867 } else {
2868 CheckOverflow(buf, len);
2869 buf->bufptr += OSC_padString(buf->bufptr, arg);
2872 buf->gettingFirstUntypedArg = 0;
2873 return 0;
2877 /* String utilities */
2879 #define STRING_ALIGN_PAD 4
2880 int OSC_effectiveStringLength(char *string) {
2881 int len = strlen(string) + 1; /* We need space for the null char. */
2883 /* Round up len to next multiple of STRING_ALIGN_PAD to account for alignment padding */
2884 if ((len % STRING_ALIGN_PAD) != 0) {
2885 len += STRING_ALIGN_PAD - (len % STRING_ALIGN_PAD);
2887 return len;
2890 static int OSC_padString(char *dest, char *str) {
2891 int i;
2893 for (i = 0; str[i] != '\0'; i++) {
2894 dest[i] = str[i];
2897 return OSC_WritePadding(dest, i);
2900 static int OSC_padStringWithAnExtraStupidComma(char *dest, char *str) {
2901 int i;
2903 dest[0] = ',';
2904 for (i = 0; str[i] != '\0'; i++) {
2905 dest[i+1] = str[i];
2908 return OSC_WritePadding(dest, i+1);
2911 static int OSC_WritePadding(char *dest, int i) {
2912 dest[i] = '\0';
2913 i++;
2915 for (; (i % STRING_ALIGN_PAD) != 0; i++) {
2916 dest[i] = '\0';
2919 return i;