diff --git a/pd/doc/5.reference/fudiformat-help.pd b/pd/doc/5.reference/fudiformat-help.pd new file mode 100644 index 0000000000000000000000000000000000000000..a66f6ba7e31e1e2b31582c98e80089c0edaaadbd --- /dev/null +++ b/pd/doc/5.reference/fudiformat-help.pd @@ -0,0 +1,38 @@ +#N canvas 51 189 685 507 10; +#X text 36 21 fudiformat - convert lists to FUDI packets, f 61; +#X msg 72 127 1 2 3; +#X obj 180 312 fudiparse; +#X obj 72 311 print packet; +#X msg 342 389 disconnect; +#X obj 334 416 netsend -u -b; +#X msg 343 365 connect localhost 5000; +#X obj 335 315 list prepend send; +#X obj 335 340 list trim; +#X obj 180 337 print reassembled; +#X text 437 389 don't send; +#X text 530 364 send as UDP; +#X text 54 454 see also:; +#X obj 127 455 fudiparse; +#X obj 72 278 fudiformat; +#X msg 80 154 foo 4 5 weasel 6 7 rat; +#X text 125 128 FUDI messages with numbers and symbols.; +#X text 29 55 fudiformat makes FUDI messages suitable for sending over +the network via netsend (in UDP mode). Incoming messages are output +as FUDI messages \, byte by byte., f 61; +#X obj 439 250 fudiformat -u; +#X obj 127 475 oscformat; +#X text 281 193 The '-u' creation argument switches to "UDP" mode \, +omitting the packet separator. This saves some two bytes \, but only +works when sending single FUDI messages over UDP. It doesn't work with +TCP/IP (however \, you can use the default format even with UDP transport). +; +#X connect 1 0 14 0; +#X connect 2 0 9 0; +#X connect 4 0 5 0; +#X connect 6 0 5 0; +#X connect 7 0 8 0; +#X connect 8 0 5 0; +#X connect 14 0 3 0; +#X connect 14 0 7 0; +#X connect 14 0 2 0; +#X connect 15 0 14 0; diff --git a/pd/doc/5.reference/fudiparse-help.pd b/pd/doc/5.reference/fudiparse-help.pd new file mode 100644 index 0000000000000000000000000000000000000000..8eb5a713baa2895df7a9c0a653b171bc3304b012 --- /dev/null +++ b/pd/doc/5.reference/fudiparse-help.pd @@ -0,0 +1,39 @@ +#N canvas 6 49 673 427 10; +#X obj 171 286 fudiparse; +#X text 52 373 see also:; +#X obj 171 309 print parse-output; +#X obj 419 231 netreceive -u -b; +#X msg 419 176 listen 5000; +#X msg 431 204 listen 0; +#X text 520 203 stop listening; +#X msg 57 181 1 2 3 foo 5; +#X text 51 156 numbers and symbols; +#X obj 57 286 print packet; +#X text 416 152 packets from network; +#X text 558 231 UDP packets \, binary output, f 13; +#X text 80 11 fudiparse - parse FUDI packets into Pd messages, f 67 +; +#X obj 57 206 fudiformat; +#X obj 222 206 fudiformat -u; +#X text 220 159 without packet separator; +#X msg 222 181 flab -1 1.1; +#X obj 140 373 fudiformat; +#X obj 224 373 oscparse; +#X obj 222 226 t a a; +#X obj 57 226 t a a; +#X text 45 40 fudiparse takes incoming lists of numbers \, interpreting +them as the bytes in a FUDI message (as received when sending Pd-messages +via [netreceive -b]).; +#X text 521 176 listen on port 5000; +#X connect 0 0 2 0; +#X connect 3 0 0 0; +#X connect 4 0 3 0; +#X connect 5 0 3 0; +#X connect 7 0 13 0; +#X connect 13 0 20 0; +#X connect 14 0 19 0; +#X connect 16 0 14 0; +#X connect 19 0 0 0; +#X connect 19 1 9 0; +#X connect 20 0 0 0; +#X connect 20 1 9 0; diff --git a/pd/src/x_misc.c b/pd/src/x_misc.c index 27d489e2a9905f231f4dd465e5cfab927bd9143e..e468fe31eba04bb9e9398937f7a037180360858b 100644 --- a/pd/src/x_misc.c +++ b/pd/src/x_misc.c @@ -36,6 +36,14 @@ #define CLOCKHZ sysconf(_SC_CLK_TCK) #endif +#ifdef _WIN32 +# include <malloc.h> /* MSVC or mingw on Windows */ +#elif defined(__linux__) || defined(__APPLE__) +# include <alloca.h> /* linux, mac, mingw, cygwin */ +#else +# include <stdlib.h> /* BSDs for example */ +#endif + /* -------------------------- random ------------------------------ */ /* this is strictly homebrew and untested. */ @@ -793,6 +801,167 @@ void oscformat_setup(void) class_addlist(oscformat_class, oscformat_list); } +/* ---------- fudiparse - parse bytelists to to FUDI messages ----------------- */ + +static t_class *fudiparse_class; + +typedef struct _fudiparse { + t_object x_obj; + t_outlet *x_msgout; + char *x_bytes; + size_t x_numbytes; +} t_fudiparse; + +static void fudiparse_binbufout(t_fudiparse *x, t_binbuf *b) +{ + int msg, natom = binbuf_getnatom(b); + t_atom *at = binbuf_getvec(b); + for (msg = 0; msg < natom;) { + int emsg; + for (emsg = msg; emsg < natom && at[emsg].a_type != A_COMMA + && at[emsg].a_type != A_SEMI; emsg++) + ; + if (emsg > msg) { + int i; + /* check for illegal atoms */ + for (i = msg; i < emsg; i++) + if (at[i].a_type == A_DOLLAR || at[i].a_type == A_DOLLSYM) { + pd_error(x, "fudiparse: got dollar sign in message"); + goto nodice; + } + + if (at[msg].a_type == A_FLOAT) { + if (emsg > msg + 1) + outlet_list(x->x_msgout, 0, emsg-msg, at + msg); + else outlet_float(x->x_msgout, at[msg].a_w.w_float); + } + else if (at[msg].a_type == A_SYMBOL) { + outlet_anything(x->x_msgout, at[msg].a_w.w_symbol, + emsg-msg-1, at + msg + 1); + } + } + nodice: + msg = emsg + 1; + } +} +static void fudiparse_list(t_fudiparse *x, t_symbol*s, int argc, t_atom*argv) { + size_t len = argc; + t_binbuf* bbuf = binbuf_new(); + char*cbuf; + if((size_t)argc > x->x_numbytes) { + freebytes(x->x_bytes, x->x_numbytes); + x->x_numbytes = argc; + x->x_bytes = getbytes(x->x_numbytes); + } + cbuf = x->x_bytes; + + while(argc--) { + char b = atom_getfloat(argv++); + *cbuf++ = b; + } + binbuf_text(bbuf, x->x_bytes, len); + + fudiparse_binbufout(x, bbuf); + + binbuf_free(bbuf); +} + +static void fudiparse_free(t_fudiparse *x) { + freebytes(x->x_bytes, x->x_numbytes); + x->x_bytes = NULL; + x->x_numbytes = 0; +} + +static void *fudiparse_new(void) { + t_fudiparse *x = (t_fudiparse *)pd_new(fudiparse_class); + x->x_msgout = outlet_new(&x->x_obj, 0); + x->x_numbytes = 1024; + x->x_bytes = getbytes(x->x_numbytes); + return (void *)x; +} + +void fudiparse_setup(void) { + fudiparse_class = class_new(gensym("fudiparse"), + (t_newmethod)fudiparse_new, + (t_method)fudiparse_free, + sizeof(t_fudiparse), CLASS_DEFAULT, + 0); + class_addlist(fudiparse_class, fudiparse_list); +} +/* --------- fudiformat - format Pd (FUDI) messages to bytelists ------------ */ + +static t_class *fudiformat_class; + +typedef struct _fudiformat { + t_object x_obj; + t_outlet *x_msgout; + t_atom *x_atoms; + size_t x_numatoms; + int x_udp; +} t_fudiformat; + +static void fudiformat_any(t_fudiformat *x, t_symbol*s, int argc, t_atom*argv) { + char *buf; + int length; + int i; + t_atom at; + t_binbuf*bbuf = binbuf_new(); + SETSYMBOL(&at, s); + binbuf_add(bbuf, 1, &at); + + binbuf_add(bbuf, argc, argv); + + if(!x->x_udp) { + SETSEMI(&at); + binbuf_add(bbuf, 1, &at); + } + binbuf_gettext(bbuf, &buf, &length); + binbuf_free(bbuf); + + if((size_t)length>x->x_numatoms) { + freebytes(x->x_atoms, sizeof(*x->x_atoms) * x->x_numatoms); + x->x_numatoms = length; + x->x_atoms = getbytes(sizeof(*x->x_atoms) * x->x_numatoms); + } + + for(i=0; i<length; i++) { + SETFLOAT(x->x_atoms+i, buf[i]); + } + freebytes(buf, length); + outlet_list(x->x_msgout, 0, length, x->x_atoms); +} + +static void fudiformat_free(t_fudiformat *x) { + freebytes(x->x_atoms, sizeof(*x->x_atoms) * x->x_numatoms); + x->x_atoms = NULL; + x->x_numatoms = 0; +} + +static void *fudiformat_new(t_symbol*s) { + t_fudiformat *x = (t_fudiformat *)pd_new(fudiformat_class); + x->x_msgout = outlet_new(&x->x_obj, 0); + x->x_numatoms = 1024; + x->x_atoms = getbytes(sizeof(*x->x_atoms) * x->x_numatoms); + if (gensym("-u") == s) + x->x_udp = 1; + else if (gensym("-t") == s) + x->x_udp = 0; + else if (gensym("") != s) { + pd_error(x, "fudiformat: unsupported mode '%s'", s->s_name); + } + + return (void *)x; +} + +static void fudiformat_setup(void) { + fudiformat_class = class_new(gensym("fudiformat"), + (t_newmethod)fudiformat_new, + (t_method)fudiformat_free, + sizeof(t_fudiformat), CLASS_DEFAULT, + A_DEFSYMBOL, 0); + class_addanything(fudiformat_class, fudiformat_any); +} + void x_misc_setup(void) { random_setup(); @@ -805,4 +974,6 @@ void x_misc_setup(void) realtime_setup(); oscparse_setup(); oscformat_setup(); + fudiparse_setup(); + fudiformat_setup(); }