mrpeach/0000755000175000017500000000000013605444731012736 5ustar zmoelnigzmoelnigmrpeach/osc/0000755000175000017500000000000013605444730013521 5ustar zmoelnigzmoelnigmrpeach/osc/unpackOSC-help.pd0000644000175000017500000000357311716546644016642 0ustar zmoelnigzmoelnig#N canvas 4 80 664 396 10; #X obj -104 176 cnv 15 100 60 empty empty empty 20 12 0 14 -4034 -66577 0; #X obj -85 190 unpackOSC; #X floatatom 16 207 10 0 0 1 - - -; #X obj -85 257 pipelist; #X text -126 337 see:; #X text 21 337 for a way to send OSC over TCP or serial connections. ; #X obj -91 338 unpackOSCstream; #X obj -92 214 print unpacked; #X text -29 253 If the OSC packet has a timetag \, [pipelist] will delay it until the time occurs; #N canvas 521 651 494 344 META 0; #X text 12 155 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; #X text 12 25 LICENSE GPL v2 or later; #X text 12 5 KEYWORDS control list_op; #X text 12 45 DESCRIPTION parses lists of floats (only integers on [0..255]) assuming they represent OSC packets.; #X text 12 75 INLET_0 list of floats on [0..255]; #X text 12 95 OUTLET_0 OSC message; #X text 13 115 OUTLET_1 milliseconds until timetag time; #X text 12 135 AUTHOR Martin Peach; #X restore 449 362 pd META; #X obj -85 73 packOSC; #X obj -62 113 print bytes; #X msg -113 28 /some/path 1 2 3; #X msg -134 7 [ \, /another/one/ 4 \, ]; #X obj -85 284 print delayed; #X msg -92 49 timetagoffset 1.1e+06; #X obj -46 93 print bundle_depth; #X text 354 317 2012/02/14 Martin Peach; #X text 107 15 [unpackOSC] processes lists of floats (only integers on [0..255]) as though they were OSC packets.; #X text -76 134 <- usually the bytes pass over the network with [udpsend]/[udpreceive] \, or serial port using [comport] with [slipenc] and [slipdec]; #X text 48 49 timetag offset is in microseconds relative to sender's clock; #X text 83 201 second outlet is timetag offset in millieconds relative to receiver's clock; #X connect 1 0 3 0; #X connect 1 0 7 0; #X connect 1 1 2 0; #X connect 1 1 3 1; #X connect 3 0 14 0; #X connect 10 0 11 0; #X connect 10 0 1 0; #X connect 10 1 16 0; #X connect 12 0 10 0; #X connect 13 0 10 0; #X connect 15 0 10 0; mrpeach/osc/LICENSE.txt0000644000175000017500000000133211616504076015343 0ustar zmoelnigzmoelnig OpenSoundControl for Pure data Copyright (C) 2006-2011 Martin Peach This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . mrpeach/osc/pipelist.c0000644000175000017500000001241711034222475015515 0ustar zmoelnigzmoelnig/* pipelist.c 20070711 Martin Peach based on pipe from x_time.c */ /* 20080706 added anything method for meta-messages */ #include "m_pd.h" /* -------------------------- pipe -------------------------- */ static t_class *pipelist_class; typedef struct _hang { t_clock *h_clock; struct _hang *h_next; struct _pipelist *h_owner; int h_n; /* number of atoms in h_list */ t_atom *h_atoms; /* pointer to a list of h_n t_atoms */ } t_hang; typedef struct _pipelist { t_object x_obj; float x_deltime; t_outlet *x_pipelistout; t_hang *x_hang; } t_pipelist; static void *pipelist_new(t_symbol *s, int argc, t_atom *argv); static void pipelist_hang_free(t_hang *h); static void pipelist_hang_tick(t_hang *h); static void pipelist_any_hang_tick(t_hang *h); static void pipelist_list(t_pipelist *x, t_symbol *s, int ac, t_atom *av); static void pipelist_anything(t_pipelist *x, t_symbol *s, int ac, t_atom *av); static void pipelist_flush(t_pipelist *x); static void pipelist_clear(t_pipelist *x); void pipelist_setup(void); static void *pipelist_new(t_symbol *s, int argc, t_atom *argv) { t_pipelist *x = (t_pipelist *)pd_new(pipelist_class); float deltime; if (argc) { /* We accept one argument to set the delay time, ignore any further args */ if (argv[0].a_type != A_FLOAT) { char stupid[80]; atom_string(&argv[argc-1], stupid, 79); post("pipelist: %s: bad time delay value", stupid); deltime = 0; } else deltime = argv[argc-1].a_w.w_float; } else deltime = 0; x->x_pipelistout = outlet_new(&x->x_obj, &s_list); floatinlet_new(&x->x_obj, &x->x_deltime); x->x_hang = NULL; x->x_deltime = deltime; return (x); } static void pipelist_hang_free(t_hang *h) { freebytes(h->h_atoms, h->h_n*sizeof(t_atom)); clock_free(h->h_clock); freebytes(h, sizeof(t_hang)); } static void pipelist_hang_tick(t_hang *h) { t_pipelist *x = h->h_owner; t_hang *h2, *h3; /* excise h from the linked list of hangs */ if (x->x_hang == h) x->x_hang = h->h_next; else for (h2 = x->x_hang; ((h3 = h2->h_next)!=NULL); h2 = h3) { if (h3 == h) { h2->h_next = h3->h_next; break; } } /* output h's list */ outlet_list(x->x_pipelistout, &s_list, h->h_n, h->h_atoms); /* free h */ pipelist_hang_free(h); } static void pipelist_any_hang_tick(t_hang *h) { t_pipelist *x = h->h_owner; t_hang *h2, *h3; /* excise h from the linked list of hangs */ if (x->x_hang == h) x->x_hang = h->h_next; else for (h2 = x->x_hang; ((h3 = h2->h_next)!=NULL); h2 = h3) { if (h3 == h) { h2->h_next = h3->h_next; break; } } /* output h's atoms */ outlet_anything(x->x_pipelistout, h->h_atoms[0].a_w.w_symbol, h->h_n-1, &h->h_atoms[1]); /* free h */ pipelist_hang_free(h); } static void pipelist_list(t_pipelist *x, t_symbol *s, int ac, t_atom *av) { if (x->x_deltime > 0) { /* if delay is real, save the list for output in delay milliseconds */ t_hang *h; int i; h = (t_hang *)getbytes(sizeof(t_hang)); h->h_n = ac; h->h_atoms = (t_atom *)getbytes(h->h_n*sizeof(t_atom)); for (i = 0; i < h->h_n; ++i) h->h_atoms[i] = av[i]; h->h_next = x->x_hang; x->x_hang = h; h->h_owner = x; h->h_clock = clock_new(h, (t_method)pipelist_hang_tick); clock_delay(h->h_clock, (x->x_deltime >= 0 ? x->x_deltime : 0)); } /* otherwise just pass the list straight through */ else outlet_list(x->x_pipelistout, &s_list, ac, av); } static void pipelist_anything(t_pipelist *x, t_symbol *s, int ac, t_atom *av) { if (x->x_deltime > 0) { /* if delay is real, save the list for output in delay milliseconds */ t_hang *h; int i; h = (t_hang *)getbytes(sizeof(t_hang)); h->h_n = ac+1; h->h_atoms = (t_atom *)getbytes(h->h_n*sizeof(t_atom)); SETSYMBOL(&h->h_atoms[0], s); for (i = 1; i < h->h_n; ++i) h->h_atoms[i] = av[i-1]; h->h_next = x->x_hang; x->x_hang = h; h->h_owner = x; h->h_clock = clock_new(h, (t_method)pipelist_any_hang_tick); clock_delay(h->h_clock, (x->x_deltime >= 0 ? x->x_deltime : 0)); } /* otherwise just pass it straight through */ else outlet_anything(x->x_pipelistout, s, ac, av); } static void pipelist_flush(t_pipelist *x) { while (x->x_hang) pipelist_hang_tick(x->x_hang); } static void pipelist_clear(t_pipelist *x) { t_hang *hang; while ((hang = x->x_hang) != NULL) { x->x_hang = hang->h_next; pipelist_hang_free(hang); } } void pipelist_setup(void) { pipelist_class = class_new(gensym("pipelist"), (t_newmethod)pipelist_new, (t_method)pipelist_clear, sizeof(t_pipelist), 0, A_GIMME, 0); class_addlist(pipelist_class, pipelist_list); class_addanything(pipelist_class, pipelist_anything); class_addmethod(pipelist_class, (t_method)pipelist_flush, gensym("flush"), 0); class_addmethod(pipelist_class, (t_method)pipelist_clear, gensym("clear"), 0); } /* end of pipelist.c*/ mrpeach/osc/unpackOSCstream.pd0000644000175000017500000000046211522077656017117 0ustar zmoelnigzmoelnig#N canvas 693 326 361 208 10; #X obj 9 7 inlet; #X obj 9 135 unpackOSC; #X obj 9 158 outlet; #X obj 60 158 outlet; #X text 172 144 Author: Roman Haefeli; #X text 172 160 Version: 2011-02-01; #X obj 9 71 mrpeach/slipdec 65536; #X connect 0 0 6 0; #X connect 1 0 2 0; #X connect 1 1 3 0; #X connect 6 0 1 0; mrpeach/osc/unpackOSCstream-help.pd0000644000175000017500000000272611533764023020043 0ustar zmoelnigzmoelnig#N canvas 1 53 638 435 10; #X text 8 369 check also:; #X obj 240 386 tcpreceive; #X obj 183 386 tcpsend; #X obj 318 386 tcpserver; #X obj 389 386 tcpclient; #X text 472 374 Author: Roman Haefeli; #X text 472 390 Version: 2008-09-09; #X text 158 65 [unpackOSCstream] is meant to be a replacement for [unpackOSC] \, when receiving from a stream based protocol \, such as TCP.; #X obj 18 197 unpackOSCstream; #X obj 18 17 tcpreceive 9995; #X obj 18 222 print; #X floatatom 105 221 5 0 0 0 - - -; #X text 159 283 reference:; #X obj 10 386 packOSCstream; #X obj 110 386 unpackOSC; #X text 160 300 http://archive.cnmat.berkeley.edu/OpenSoundControl/OSC-spec.html : Section "OSC Packets"; #X text 141 221 milliseconds delay; #X text 158 119 [unpackOSCstream] will only be able to decode OSC packets or bundles created by [packOSCstream]. OSC packets that were generated by [packOSC] will cause errors or wrong output.; #N canvas 507 340 494 344 META 0; #X text 12 155 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; #X text 12 25 LICENSE GPL v2 or later; #X text 12 5 KEYWORDS control network abstraction; #X text 12 46 DESCRIPTION meant to be a replacement for [unpackOSC] \, when receiving from a stream based protocol \, such as TCP.; #X text 12 75 INLET_0 anything; #X text 12 95 OUTLET_0 anything; #X text 12 115 OUTLET_1 float; #X text 12 135 AUTHOR Roman Haefeli; #X restore 591 413 pd META; #X connect 8 0 10 0; #X connect 8 1 11 0; #X connect 9 0 8 0; mrpeach/osc/packOSC-help.pd0000644000175000017500000001024112741545524016260 0ustar zmoelnigzmoelnig#N canvas 201 81 1158 705 12; #X obj 301 434 cnv 15 100 40 empty empty empty 20 12 0 14 -4034 -66577 0; #X obj 330 548 udpsend; #X msg 323 521 disconnect; #X msg 301 499 connect 127.0.0.1 9997; #X obj 330 447 packOSC; #X obj 330 583 tgl 15 0 empty empty 1=connected 20 8 0 8 -4034 -257985 -1 1 1; #X msg -130 -33 send /test/one/two/three zz 88 T; #X msg -84 13 send /test 1 2 3; #X msg -107 -10 send /west 35; #X msg -38 59 send /*/left 22; #X msg -13 84 send /?est/ 1; #X text 293 13 packOSC is like sendOSC except that it outputs a list of floats instead of directly connecting to the network; #X text 103 -33 send a type-guessed message; #X obj 515 541 routeOSC; #X text 436 540 see also:; #X msg 318 415 typetags \$1; #X obj 318 397 tgl 15 0 empty empty empty 17 7 0 10 -257985 -258113 -1 0 1; #X text 414 414 typetags are on by default; #X text 578 107 Useable types are:; #X text 578 125 i: 32 bit integer; #X text 578 143 f: 32-bit float; #X text 578 161 s: string; #X text 359 107 send a type-forced message; #X msg 10 107 sendtyped /test/one/two/three sis zz 88 T; #X msg 33 130 sendtyped /left/right TTiTIFNfisf 1.1 2.1 3.1 4.1 5.1 ; #X text 578 179 T: true (no argument); #X text 578 197 F: false (no argument); #X text 578 215 I: infinitum (no argument); #X text 578 232 N: Nil (no argument); #X msg 277 374 bufsize 100; #X text 376 374 set buffer size (default is 64000 bytes); #X msg 79 176 prefix /test; #X text 186 175 set the OSC path prefix for subsequent messages; #X msg -61 36 /left one two; #X msg 56 153 /right 88; #X text 139 153 'send' prefix is not required; #X msg 55 209 [; #X msg 9 210 ]; #X text -97 211 close bundle; #X msg 157 254 timetagoffset 0; #X msg 180 277 timetagoffset -1; #X text 319 254 send current time as timetag; #X text 135 229 (timetags are sent in bundle messages only); #X obj 9 186 t b a b; #X msg -90 166 /test 5 6 7; #X text 323 277 immediate time tag (default); #X floatatom 376 476 5 0 0 0 - - -, f 5; #X text 426 476 bundle depth; #X obj 495 499 cnv 15 380 30 empty empty empty 20 12 0 14 -24198 -66577 0; #X text 589 540 and http://opensoundcontrol.org/cnmat; #X msg 203 300 timetagoffset 1e+06; #X text 499 506 <- First open routeOSC-help \, then connect; #X text 88 210 open a bundle (and generate time tag); #X obj 418 568 packOSCstream; #X text 383 567 see:; #X text 534 568 for a way to send OSC over TCP or serial connections. ; #X text 366 299 current time plus 1 second (delay is in microseconds) ; #X text 578 248 b: blob (a list of bytes \, or floats on [0..255]) ; #X text 722 341 send a blob; #X msg 253 334 sendtyped /left b 0 1 2 3 124 125 126 127 128 129 255 254 253 252 -14 -15 -16 17 18 19 20 21 22 23 24 25 26 27 28; #N canvas 496 61 548 344 META 0; #X text 12 185 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; #X text 12 25 LICENSE GPL v2 or later; #X text 12 165 AUTHOR Martin Peach; #X text 12 5 KEYWORDS control network; #X text 12 45 DESCRIPTION packOSC is like sendOSC except it outputs a list of floats instead of directly connecting to the network; #X text 12 85 INLET_0 anything send sendtyped prefix timetagoffset bufsize typetags; #X text 12 125 OUTLET_0 anything; #X text 12 145 OUTLET_1 float; #X restore 832 595 pd META; #X msg 150 65 sendtyped /a/midi/message mm 0 144 60 64 0 144 62 32 ; #X obj 175 530 print >>; #X text 578 263 m: MIDI (4 bytes per MIDI message:; #X text 601 278 Port \, Status \, Param1 \, Param2; #X text -75 570 2009-2016 Martin Peach; #X obj 175 506 spigot; #X obj 220 473 tgl 15 0 empty empty raw 17 7 0 12 -257985 -258113 -1 0 1; #X connect 1 0 5 0; #X connect 2 0 1 0; #X connect 3 0 1 0; #X connect 4 0 1 0; #X connect 4 0 66 0; #X connect 4 1 46 0; #X connect 6 0 4 0; #X connect 7 0 4 0; #X connect 8 0 4 0; #X connect 9 0 4 0; #X connect 10 0 4 0; #X connect 15 0 4 0; #X connect 16 0 15 0; #X connect 23 0 4 0; #X connect 24 0 4 0; #X connect 29 0 4 0; #X connect 31 0 4 0; #X connect 33 0 4 0; #X connect 34 0 4 0; #X connect 36 0 4 0; #X connect 37 0 4 0; #X connect 39 0 4 0; #X connect 40 0 4 0; #X connect 43 0 37 0; #X connect 43 1 4 0; #X connect 43 2 36 0; #X connect 44 0 43 0; #X connect 50 0 4 0; #X connect 59 0 4 0; #X connect 61 0 4 0; #X connect 66 0 62 0; #X connect 67 0 66 1; mrpeach/osc/packOSCstream-help.pd0000644000175000017500000000420011533764023017465 0ustar zmoelnigzmoelnig#N canvas 1 53 609 569 10; #X obj 69 119 packOSCstream; #X obj 69 451 tcpsend; #X text -24 496 check also:; #X obj -22 513 unpackOSCstream; #X obj 93 513 packOSC; #X msg 38 403 connect localhost 9995; #X obj 208 513 tcpreceive; #X obj 151 513 tcpsend; #X obj 286 513 tcpserver; #X obj 357 513 tcpclient; #X msg 58 423 disconnect; #X obj 69 473 tgl 15 0 empty empty empty 17 7 0 10 -4034 -257985 -1 0 1; #X obj 181 403 cnv 15 380 30 empty empty empty 20 12 0 14 -24198 -66577 0; #X text 196 408 <- First open unpackOSCstream-help \, then connect ; #X text 440 501 Author: Roman Haefeli; #X text 440 517 Version: 2008-09-09; #X text 74 254 [packOSCstream] uses the same methods as [packOSC]. Please consult packOSC-help.pd for the complete documentation.; #X text 75 189 [packOSstream] puts a frame length header (int32) in front of every OSC packet or bundle \, so that the receiving side knows \, how to split the incoming stream into OSC packets again.; #X msg -24 9 /first/message 1 \, /second/message 2; #X text 79 330 reference:; #X text 80 347 http://archive.cnmat.berkeley.edu/OpenSoundControl/OSC-spec.html : Section "OSC Packets"; #X msg -4 29 send /test/one/two/three zz 88 T; #X msg 16 49 sendtyped /test/one/two/three sis zz 88 T; #X msg 36 69 prefix /test; #X msg 56 89 [ \, /previous/page 666 \, /next/page 999 \, ]; #X text 72 142 [packOSCstream] is meant to be a replacement for [packOSC] \, when sending over a stream based protocol \, such as TCP.; #N canvas 499 120 494 344 META 0; #X text 12 135 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; #X text 12 25 LICENSE GPL v2 or later; #X text 12 115 AUTHOR Roman Haefeli; #X text 12 75 INLET_0 anything send sendtyped prefix connect disconnect ; #X text 12 45 DESCRIPTION meant to be a replacement for [packOSC] \, when sending over a stream based protocol \, such as TCP; #X text 12 95 OUTLET_0 float; #X text 12 5 KEYWORDS control network abstraction; #X restore 532 544 pd META; #X connect 0 0 1 0; #X connect 1 0 11 0; #X connect 5 0 1 0; #X connect 10 0 1 0; #X connect 18 0 0 0; #X connect 21 0 0 0; #X connect 22 0 0 0; #X connect 23 0 0 0; #X connect 24 0 0 0; mrpeach/osc/packOSCstream.pd0000644000175000017500000000045711522077656016560 0ustar zmoelnigzmoelnig#N canvas 642 471 204 215 10; #X obj 9 35 packOSC; #X obj 9 14 inlet; #X obj 9 139 outlet; #X text 36 157 Author: Roman Haefeli; #X obj 135 139 outlet; #X obj 9 80 mrpeach/slipenc 65536; #X text 36 173 version: 2011-02-01; #X connect 0 0 5 0; #X connect 0 1 4 0; #X connect 1 0 0 0; #X connect 5 0 2 0; mrpeach/osc/packingOSC.h0000644000175000017500000000157512453053113015652 0ustar zmoelnigzmoelnig/* packingOSC.h */ #ifndef _PACKINGOSC #include "m_pd.h" #include #include #include #ifdef _WIN32 #include #include #else #include #include #include #include #endif /* _WIN32 */ /* Declarations */ #ifdef WIN32 typedef unsigned __int64 osc_time_t; #else typedef unsigned long long osc_time_t; #endif #define MAX_MESG 65536 /* same as MAX_UDP_PACKET */ /* The maximum depth of bundles within bundles within bundles within... This is the size of a static array. If you exceed this limit you'll get an error message. */ #define MAX_BUNDLE_NESTING 32 typedef struct { uint32_t seconds; uint32_t fraction; } OSCTimeTag; typedef union { int i; float f; } intfloat32; #endif // _PACKINGOSC /* end of packingOSC.h */ mrpeach/osc/routeOSC-help.pd0000644000175000017500000000720212741545524016503 0ustar zmoelnigzmoelnig#N canvas 81 134 1070 758 12; #X obj 11 524 cnv 15 820 130 empty empty empty 20 12 0 14 -261207 -66577 0; #X obj -31 10 udpreceive 9997; #X floatatom 160 82 3 0 0 0 - - -, f 3; #X floatatom 191 82 3 0 0 0 - - -, f 3; #X floatatom 222 82 3 0 0 0 - - -, f 3; #X floatatom 253 82 3 0 0 0 - - -, f 3; #X text 120 81 from; #X obj -31 134 unpackOSC; #X text 369 78 see also:; #X obj 445 79 packOSC; #X floatatom 528 154 10 0 0 1 millisecond_delay - -, f 10; #X obj -31 161 pipelist; #X text 529 529 arguments are OSC addresses to be routed; #X text 88 677 see:; #X text 248 678 for a way to send OSC over TCP or serial connections. ; #X obj 123 678 unpackOSCstream; #X obj -65 188 print unpacked; #X obj 160 58 unpack 0 0 0 0 0; #X floatatom 285 82 8 0 0 0 - - -, f 8; #X obj 86 35 route received from; #X floatatom 86 103 5 0 0 0 - - -, f 5; #X text 129 103 bytes; #X text 98 9 Open [packOSC-help] to send packets to this patch.; #X text 39 156 If the OSC packet has a timetag \, [pipelist] will delay it until the time occurs; #X obj 317 623 print match_1; #X obj 393 601 print match_2; #X obj 546 557 print no_match; #N canvas 499 254 494 344 META 0; #X text 12 155 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; #X text 12 25 LICENSE GPL v2 or later; #X text 12 5 KEYWORDS control list_op; #X text 12 75 INLET_0 list verbosity paths set; #X text 12 95 OUTLET_N list; #X text 12 115 OUTLET_R list; #X text 12 135 AUTHOR Martin Peach; #X text 12 45 DESCRIPTION routes lists as OSC packets.; #X restore 833 655 pd META; #X text 657 627 2012/03/13 Martin Peach; #X text 44 119 [unpackOSC] parses lists of floats (only integers on [0..255]) as OSC packets.; #X obj 11 219 cnv 15 600 160 empty empty empty 20 12 0 14 -204786 -66577 0; #X obj 172 382 cnv 15 600 140 empty empty empty 20 12 0 14 -261234 -66577 0; #X msg 121 313 set /left; #X msg 98 290 set /left /right; #X text 226 311 (but new outlets can't be created); #X msg 72 264 paths; #X msg 49 241 verbosity \$1; #X obj 49 223 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1; #X text 67 219 set to 1 for debugging; #X text 295 335 routeOSC will match deep paths; #X text 232 289 [set( reassigns outputs from left to right; #X text 126 264 [paths( will print the current OSC addresses to Pd console; #X msg 190 382 /test any2 4 5; #X msg 302 494 1 2 3; #X msg 144 336 set /one/two/three; #X msg 167 359 set /*; #X text 220 358 this will match any OSC message; #X msg 257 449 /* zap!; #X msg 280 472 zorro trope; #X text 379 472 not a valid OSC message; #X text 350 493 not a valid OSC message; #X text 308 382 input is a message whose selector is an OSC path; #X text 411 404 or a list whose first element is an OSC path; #X obj 469 579 print match_3; #X obj 317 529 routeOSC /test /west /one/two; #X msg 234 426 /one/two/three yikes!; #X msg 212 404 list /west/rate any1 2 3; #X text 11 556 [routeOSC] routes Open Sound Control* messages \, or lists of anything beginning with a /path; #X text 13 599 *See http://opensoundcontrol.org/spec-1_0; #X connect 1 0 7 0; #X connect 1 1 19 0; #X connect 7 0 11 0; #X connect 7 0 16 0; #X connect 7 1 10 0; #X connect 7 1 11 1; #X connect 11 0 54 0; #X connect 17 0 2 0; #X connect 17 1 3 0; #X connect 17 2 4 0; #X connect 17 3 5 0; #X connect 17 4 18 0; #X connect 19 0 20 0; #X connect 19 1 17 0; #X connect 32 0 54 0; #X connect 33 0 54 0; #X connect 35 0 54 0; #X connect 36 0 54 0; #X connect 37 0 36 0; #X connect 42 0 54 0; #X connect 43 0 54 0; #X connect 44 0 54 0; #X connect 45 0 54 0; #X connect 47 0 54 0; #X connect 48 0 54 0; #X connect 54 0 24 0; #X connect 54 1 25 0; #X connect 54 2 53 0; #X connect 54 3 26 0; #X connect 55 0 54 0; #X connect 56 0 54 0; mrpeach/osc/pipelist-help.pd0000644000175000017500000000262511533764023016630 0ustar zmoelnigzmoelnig#N canvas 1 53 558 300 10; #X obj 112 129 pipelist 1000; #X msg 198 83 5000; #X floatatom 198 107 5 0 0 0 - - -; #X floatatom 222 42 5 0 0 0 - - -; #X floatatom 181 42 5 0 0 0 - - -; #X obj 112 62 pack s s 3 4 5; #X obj 112 0 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 -1; #X msg 135 -1 tik; #X msg 57 13 alpha; #X msg 50 41 beta; #X floatatom 63 90 5 0 0 0 - - -; #X obj 112 196 print; #X obj 130 107 symbol; #X msg 135 83 bb; #X text 195 1 pipelist delays lists.; #X text 237 106 Delay time is in milliseconds.; #X text 208 131 Argument sets initial delay time.; #X text 242 218 2007/07/11 Martin Peach; #X text 229 182 see also:; #X obj 305 183 pipe; #X obj 339 183 delay; #X obj 379 183 timer; #X obj 135 21 symbol; #N canvas 500 149 494 344 META 0; #X text 12 145 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; #X text 12 25 LICENSE GPL v2 or later; #X text 12 125 AUTHOR Roman Haefeli; #X text 12 5 KEYWORDS control list_op; #X text 12 45 DESCRIPTION delay lists; #X text 12 65 INLET_0 anything; #X text 12 85 INLET_1 float; #X text 12 105 OUTLET_0 list; #X restore 492 265 pd META; #X connect 0 0 11 0; #X connect 1 0 2 0; #X connect 2 0 0 1; #X connect 3 0 5 4; #X connect 4 0 5 3; #X connect 5 0 0 0; #X connect 6 0 5 0; #X connect 7 0 22 0; #X connect 8 0 5 0; #X connect 9 0 5 0; #X connect 10 0 0 0; #X connect 12 0 0 0; #X connect 13 0 12 0; #X connect 22 0 5 1; mrpeach/osc/unpackOSC.c0000644000175000017500000005547612741545524015537 0ustar zmoelnigzmoelnig/* unpackOSC is like dumpOSC but outputs a list consisting of a single symbol for the path */ /* and a list of floats and/or symbols for the data, and adds an outlet for a time delay. */ /* This allows for the separation of the protocol and its transport. */ /* Started by Martin Peach 20060420 */ /* dumpOSC.c header follows: */ /* Written by Matt Wright and Adrian Freed, The Center for New Music and Audio Technologies, University of California, Berkeley. Copyright (c) 1992,93,94,95,96,97,98,99,2000,01,02,03,04 The Regents of the University of California (Regents). Permission to use, copy, modify, distribute, and distribute modified versions of this software and its documentation without fee and without a signed licensing agreement, is hereby granted, provided that the above copyright notice, this paragraph and the following two paragraphs appear in all copies, modifications, and distributions. IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. The OSC webpage is http://cnmat.cnmat.berkeley.edu/OpenSoundControl */ /* dumpOSC.c server that displays OpenSoundControl messages sent to it for debugging client udp and UNIX protocol by Matt Wright, 6/3/97 modified from dumpSC.c, by Matt Wright and Adrian Freed version 0.2: Added "-silent" option a.k.a. "-quiet" version 0.3: Incorporated patches from Nicola Bernardini to make things Linux-friendly. Also added ntohl() in the right places to support little-endian architectures. to-do: More robustness in saying exactly what's wrong with ill-formed messages. (If they don't make sense, show exactly what was received.) Time-based features: print time-received for each packet Clean up to separate OSC parsing code from socket/select stuff pd: branched from http://www.cnmat.berkeley.edu/OpenSoundControl/src/dumpOSC/dumpOSC.c ------------- -- added pd functions -- socket is made differently than original via pd mechanisms -- tweaks for Win32 www.zeggz.com/raf 13-April-2002 -- the OSX changes from cnmat didnt make it here yet but this compiles on OSX anyway. */ //define DEBUG #include "packingOSC.h" static t_class *unpackOSC_class; typedef struct _unpackOSC { t_object x_obj; t_outlet *x_data_out; t_outlet *x_delay_out; int x_bundle_flag;/* non-zero if we are processing a bundle */ int x_recursion_level;/* number of times we reenter unpackOSC_list */ int x_abort_bundle;/* non-zero if unpackOSC_list is not well formed */ int x_reentry_count; } t_unpackOSC; void unpackOSC_setup(void); static void *unpackOSC_new(void); static void unpackOSC_free(t_unpackOSC *x); static void unpackOSC_list(t_unpackOSC *x, t_symbol *s, int argc, t_atom *argv); static int unpackOSC_path(t_atom *data_at, char *path); static void unpackOSC_Smessage(t_atom *data_at, int *data_atc, void *v, int n); static void unpackOSC_PrintTypeTaggedArgs(t_atom *data_at, int *data_atc, void *v, int n); static void unpackOSC_PrintHeuristicallyTypeGuessedArgs(t_atom *data_at, int *data_atc, void *v, int n, int skipComma); static char *unpackOSC_DataAfterAlignedString(char *string, char *boundary); static int unpackOSC_IsNiceString(char *string, char *boundary); static t_float unpackOSC_DeltaTime(OSCTimeTag tt); static void *unpackOSC_new(void) { t_unpackOSC *x; x = (t_unpackOSC *)pd_new(unpackOSC_class); x->x_data_out = outlet_new(&x->x_obj, &s_list); x->x_delay_out = outlet_new(&x->x_obj, &s_float); x->x_bundle_flag = 0; x->x_recursion_level = 0; x->x_abort_bundle = 0; return (x); } static void unpackOSC_free(t_unpackOSC *x) { } void unpackOSC_setup(void) { unpackOSC_class = class_new(gensym("unpackOSC"), (t_newmethod)unpackOSC_new, (t_method)unpackOSC_free, sizeof(t_unpackOSC), 0, 0); class_addlist(unpackOSC_class, (t_method)unpackOSC_list); } /* unpackOSC_list expects an OSC packet in the form of a list of floats on [0..255] */ static void unpackOSC_list(t_unpackOSC *x, t_symbol *s, int argc, t_atom *argv) { int size, messageLen, i, j; char *messageName, *args, *buf; OSCTimeTag tt; t_atom data_at[MAX_MESG] ={{0}};/* symbols making up the path + payload */ int data_atc = 0;/* number of symbols to be output */ char raw[MAX_MESG];/* bytes making up the entire OSC message */ int raw_c;/* number of bytes in OSC message */ #ifdef DEBUG printf(">>> unpackOSC_list: %d bytes, abort=%d, reentry_count %d recursion_level %d\n", argc, x->x_abort_bundle, x->x_reentry_count, x->x_recursion_level); #endif if(x->x_abort_bundle) return; /* if backing quietly out of the recursive stack */ x->x_reentry_count++; if ((argc%4) != 0) { post("unpackOSC: Packet size (%d) not a multiple of 4 bytes: dropping packet", argc); goto unpackOSC_list_out; } if(argc > MAX_MESG) { post("unpackOSC: Packet size (%d) greater than max (%d). Change MAX_MESG and recompile if you want more.", argc, MAX_MESG); goto unpackOSC_list_out; } /* copy the list to a byte buffer, checking for bytes only */ for (i = 0; i < argc; ++i) { if (argv[i].a_type == A_FLOAT) { j = (int)argv[i].a_w.w_float; /* if ((j == argv[i].a_w.w_float) && (j >= 0) && (j <= 255)) */ /* this can miss bytes between 128 and 255 because they are interpreted somewhere as negative */ /* , so change to this: */ if ((j == argv[i].a_w.w_float) && (j >= -128) && (j <= 255)) { raw[i] = (char)j; } else { post("unpackOSC: Data out of range (%d), dropping packet", argv[i].a_w.w_float); goto unpackOSC_list_out; } } else { post("unpackOSC: Data not float, dropping packet"); goto unpackOSC_list_out; } } raw_c = argc; buf = raw; if ((argc >= 8) && (strncmp(buf, "#bundle", 8) == 0)) { /* This is a bundle message. */ #ifdef DEBUG printf("unpackOSC: bundle msg:\n"); #endif if (argc < 16) { post("unpackOSC: Bundle message too small (%d bytes) for time tag", argc); goto unpackOSC_list_out; } x->x_bundle_flag = 1; /* Print the time tag */ #ifdef DEBUG printf("unpackOSC bundle timetag: [ %x.%0x\n", ntohl(*((uint32_t *)(buf+8))), ntohl(*((uint32_t *)(buf+12)))); #endif /* convert the timetag into a millisecond delay from now */ tt.seconds = ntohl(*((uint32_t *)(buf+8))); tt.fraction = ntohl(*((uint32_t *)(buf+12))); /* pd can use a delay in milliseconds */ outlet_float(x->x_delay_out, unpackOSC_DeltaTime(tt)); /* Note: if we wanted to actually use the time tag as a little-endian 64-bit int, we'd have to word-swap the two 32-bit halves of it */ i = 16; /* Skip "#group\0" and time tag */ while(i < argc) { size = ntohl(*((int *) (buf + i))); if ((size % 4) != 0) { post("unpackOSC: Bad size count %d in bundle (not a multiple of 4)", size); goto unpackOSC_list_out; } if ((size + i + 4) > argc) { post("unpackOSC: Bad size count %d in bundle (only %d bytes left in entire bundle)", size, argc-i-4); goto unpackOSC_list_out; } /* Recursively handle element of bundle */ x->x_recursion_level++; #ifdef DEBUG printf("unpackOSC: bundle depth %d\n", x->x_recursion_level); #endif if (x->x_recursion_level > MAX_BUNDLE_NESTING) { post("unpackOSC: bundle depth %d exceeded", MAX_BUNDLE_NESTING); x->x_abort_bundle = 1;/* we need to back out of the recursive stack*/ goto unpackOSC_list_out; } #ifdef DEBUG printf("unpackOSC: bundle calling unpackOSC_list(x=%p, s=%s, size=%d, argv[%d]=%p)\n", x, s->s_name, size, i+4, &argv[i+4]); #endif unpackOSC_list(x, s, size, &argv[i+4]); i += 4 + size; } if (i != argc) { post("unpackOSC: This can't happen"); } x->x_bundle_flag = 0; /* end of bundle */ #ifdef DEBUG printf("unpackOSC: bundle end ] depth is %d\n", x->x_recursion_level); #endif } else if ((argc == 24) && (strcmp(buf, "#time") == 0)) { post("unpackOSC: Time message: %s\n :).\n", buf); goto unpackOSC_list_out; } else { /* This is not a bundle message or a time message */ messageName = buf; #ifdef DEBUG printf("unpackOSC: message name string: %s length %d\n", messageName, raw_c); #endif args = unpackOSC_DataAfterAlignedString(messageName, buf+raw_c); if (args == 0) { post("unpackOSC: Bad message name string: Dropping entire message."); goto unpackOSC_list_out; } messageLen = args-messageName; /* put the OSC path into a single symbol */ data_atc = unpackOSC_path(data_at, messageName); /* returns 1 if path OK, else 0 */ if (data_atc == 1) { #ifdef DEBUG printf("unpackOSC_list calling unpackOSC_Smessage: message length %d\n", raw_c-messageLen); #endif unpackOSC_Smessage(data_at, &data_atc, (void *)args, raw_c-messageLen); if (0 == x->x_bundle_flag) outlet_float(x->x_delay_out, 0); /* no delay for message not in a bundle */ } } if (data_atc >= 1) outlet_anything(x->x_data_out, atom_getsymbol(data_at), data_atc-1, data_at+1); data_atc = 0; x->x_abort_bundle = 0; unpackOSC_list_out: x->x_recursion_level = 0; x->x_reentry_count--; } static int unpackOSC_path(t_atom *data_at, char *path) { int i; if (path[0] != '/') { for (i = 0; i < 16; ++i) if ('\0' == path[i]) break; path[i] = '\0'; post("unpackOSC: Path doesn't begin with \"/\", dropping message"); return 0; } for (i = 1; i < MAX_MESG; ++i) { if (path[i] == '\0') { /* the end of the path: turn path into a symbol */ SETSYMBOL(data_at, gensym(path)); return 1; } } post("unpackOSC: Path too long, dropping message"); return 0; } #define SMALLEST_POSITIVE_FLOAT 0.000001f static void unpackOSC_Smessage(t_atom *data_at, int *data_atc, void *v, int n) { char *chars = v; if (n != 0) { if (chars[0] == ',') { if (chars[1] != ',') { #ifdef DEBUG printf("unpackOSC_Smessage calling unpackOSC_PrintTypeTaggedArgs: message length %d\n", n); #endif /* This message begins with a type-tag string */ unpackOSC_PrintTypeTaggedArgs(data_at, data_atc, v, n); } else { #ifdef DEBUG printf("unpackOSC_Smessage calling unpackOSC_PrintHeuristicallyTypeGuessedArgs: message length %d, skipComma 1\n", n); #endif /* Double comma means an escaped real comma, not a type string */ unpackOSC_PrintHeuristicallyTypeGuessedArgs(data_at, data_atc, v, n, 1); } } else { #ifdef DEBUG printf("unpackOSC_Smessage calling unpackOSC_PrintHeuristicallyTypeGuessedArgs: message length %d, skipComma 0\n", n); #endif unpackOSC_PrintHeuristicallyTypeGuessedArgs(data_at, data_atc, v, n, 0); } } } static void unpackOSC_PrintTypeTaggedArgs(t_atom *data_at, int *data_atc, void *v, int n) { char *typeTags, *thisType, *p; int myargc = *data_atc; t_atom *mya = data_at; typeTags = v; if (!unpackOSC_IsNiceString(typeTags, typeTags+n)) { #ifdef DEBUG printf("unpackOSC_PrintTypeTaggedArgs not nice string\n"); #endif /* No null-termination, so maybe it wasn't a type tag string after all */ unpackOSC_PrintHeuristicallyTypeGuessedArgs(data_at, data_atc, v, n, 0); return; } #ifdef DEBUG printf("unpackOSC_PrintTypeTaggedArgs calling unpackOSC_DataAfterAlignedString %p to %p\n", typeTags, typeTags+n); #endif p = unpackOSC_DataAfterAlignedString(typeTags, typeTags+n); #ifdef DEBUG printf("unpackOSC_PrintTypeTaggedArgs p is %p: ", p); #endif if (p == NULL) return; /* malformed message */ for (thisType = typeTags + 1; *thisType != 0; ++thisType) { switch (*thisType) { case 'b': /* blob: an int32 size count followed by that many 8-bit bytes */ { int i, blob_bytes = ntohl(*((int *) p)); #ifdef DEBUG printf("blob: %u bytes\n", blob_bytes); #endif p += 4; for (i = 0; i < blob_bytes; ++i, ++p, ++myargc) SETFLOAT(mya+myargc,(*(unsigned char *)p)); while (i%4) { ++i; ++p; } break; } case 'm': /* MIDI message is the next four bytes*/ { int i; #ifdef DEBUG printf("MIDI: 0x%08X\n", ntohl(*((int *) p))); #endif for (i = 0; i < 4; ++i, ++p, ++myargc) SETFLOAT(mya+myargc, (*(unsigned char *)p)); break; } case 'i': case 'r': case 'c': #ifdef DEBUG printf("integer: %d\n", ntohl(*((int *) p))); #endif SETFLOAT(mya+myargc,(signed)ntohl(*((int *) p))); myargc++; p += 4; break; case 'f': { intfloat32 thisif; thisif.i = ntohl(*((int *) p)); #ifdef DEBUG printf("float: %f\n", thisif.f); #endif SETFLOAT(mya+myargc, thisif.f); myargc++; p += 4; break; } case 'h': case 't': #ifdef DEBUG printf("[A 64-bit int]\n"); #endif post("unpackOSC: PrintTypeTaggedArgs: [A 64-bit int] not implemented"); p += 8; break; case 'd': #ifdef DEBUG printf("[A 64-bit float]\n"); #endif post("unpackOSC: PrintTypeTaggedArgs: [A 64-bit float] not implemented"); p += 8; break; case 's': case 'S': if (!unpackOSC_IsNiceString(p, typeTags+n)) { post("unpackOSC: PrintTypeTaggedArgs: Type tag said this arg is a string but it's not!\n"); return; } else { #ifdef DEBUG printf("string: \"%s\"\n", p); #endif SETSYMBOL(mya+myargc,gensym(p)); myargc++; p = unpackOSC_DataAfterAlignedString(p, typeTags+n); } break; case 'T': #ifdef DEBUG printf("[True]\n"); #endif SETFLOAT(mya+myargc,1.); myargc++; break; case 'F': #ifdef DEBUG printf("[False]\n"); #endif SETFLOAT(mya+myargc,0.); myargc++; break; case 'N': #ifdef DEBUG printf("[Nil]\n"); #endif SETFLOAT(mya+myargc,0.); myargc++; break; case 'I': #ifdef DEBUG printf("[Infinitum]\n"); #endif SETSYMBOL(mya+myargc,gensym("INF")); myargc++; break; default: #ifdef DEBUG printf("unpackOSC_PrintTypeTaggedArgs unknown typetag %c (%0X)\n", *thisType, *thisType); #endif post("unpackOSC: PrintTypeTaggedArgs: [Unrecognized type tag %c]", *thisType); return; } } *data_atc = myargc; } static void unpackOSC_PrintHeuristicallyTypeGuessedArgs(t_atom *data_at, int *data_atc, void *v, int n, int skipComma) { int i; int *ints; intfloat32 thisif; char *chars, *string, *nextString; int myargc = *data_atc; t_atom* mya = data_at; /* Go through the arguments 32 bits at a time */ ints = v; chars = v; for (i = 0; i < n/4; ) { string = &chars[i*4]; thisif.i = ntohl(ints[i]); /* Reinterpret the (potentially byte-reversed) thisif as a float */ if (thisif.i >= -1000 && thisif.i <= 1000000) { #ifdef DEBUG printf("%d ", thisif.i); #endif SETFLOAT(mya+myargc,(t_float) (thisif.i)); myargc++; i++; } else if (thisif.f >= -1000.f && thisif.f <= 1000000.f && (thisif.f <=0.0f || thisif.f >= SMALLEST_POSITIVE_FLOAT)) { #ifdef DEBUG printf("%f ", thisif.f); #endif SETFLOAT(mya+myargc,thisif.f); myargc++; i++; } else if (unpackOSC_IsNiceString(string, chars+n)) { nextString = unpackOSC_DataAfterAlignedString(string, chars+n); #ifdef DEBUG printf("\"%s\" ", (i == 0 && skipComma) ? string +1 : string); #endif SETSYMBOL(mya+myargc,gensym(string)); myargc++; i += (nextString-string) / 4; } else { /* unhandled .. ;) */ post("unpackOSC: PrintHeuristicallyTypeGuessedArgs: indeterminate type: 0x%x xx", ints[i]); i++; } *data_atc = myargc; } } #define STRING_ALIGN_PAD 4 static char *unpackOSC_DataAfterAlignedString(char *string, char *boundary) { /* The argument is a block of data beginning with a string. The string has (presumably) been padded with extra null characters so that the overall length is a multiple of STRING_ALIGN_PAD bytes. Return a pointer to the next byte after the null byte(s). The boundary argument points to the character after the last valid character in the buffer---if the string hasn't ended by there, something's wrong. If the data looks wrong, return 0 */ int i; #ifdef DEBUG printf("unpackOSC_DataAfterAlignedString boundary - string = %ld\n", boundary-string); #endif if ((boundary - string) %4 != 0) { post("unpackOSC: DataAfterAlignedString: bad boundary"); return 0; } for (i = 0; string[i] != '\0'; i++) { #ifdef DEBUG printf("%0X(%c) ", string[i], string[i]); #endif if (string + i >= boundary) { post("unpackOSC: DataAfterAlignedString: Unreasonably long string"); return 0; } } /* Now string[i] is the first null character */ #ifdef DEBUG printf("\nunpackOSC_DataAfterAlignedString first null character at %p\n", &string[i]); #endif i++; for (; (i % STRING_ALIGN_PAD) != 0; i++) { if (string + i >= boundary) { post("unpackOSC: DataAfterAlignedString: Unreasonably long string"); return 0; } if (string[i] != '\0') { post("unpackOSC: DataAfterAlignedString: Incorrectly padded string"); return 0; } } #ifdef DEBUG printf("unpackOSC_DataAfterAlignedString first non-null character at %p\n", &string[i]); #endif return string+i; } static int unpackOSC_IsNiceString(char *string, char *boundary) { /* Arguments same as DataAfterAlignedString(). Is the given "string" really an OSC-string? I.e., is it "A sequence of non-null ASCII characters followed by a null, followed by 0-3 additional null characters to make the total number of bits a multiple of 32"? (OSC 1.0) Returns 1 if true, else 0. */ int i; if ((boundary - string) %4 != 0) { post("unpackOSC: IsNiceString: bad boundary\n"); return 0; } /* any non-zero byte will be accepted, so UTF-8 sequences will also be accepted -- not strictly OSC v1.0 */ for (i = 0; string[i] != '\0'; i++) /* if ((!isprint(string[i])) || (string + i >= boundary)) return 0; */ /* only ASCII printable chars */ /*if ((0==(string[i]&0xE0)) || (string + i >= boundary)) return 0;*/ /* onl;y ASCII space (0x20) and above */ if (string + i >= boundary) return 0; /* anything non-zero */ /* If we made it this far, it's a null-terminated sequence of characters within the given boundary. Now we just make sure it's null padded... */ /* Now string[i] is the first null character */ i++; for (; (i % STRING_ALIGN_PAD) != 0; i++) if (string[i] != '\0') return 0; return 1; } #define SECONDS_FROM_1900_to_1970 2208988800LL /* 17 leap years */ #define TWO_TO_THE_32_OVER_ONE_MILLION 4295LL #define ONE_MILLION_OVER_TWO_TO_THE_32 0.00023283064365386963 /* return the time difference in milliseconds between an OSC timetag and now */ static t_float unpackOSC_DeltaTime(OSCTimeTag tt) { static double onemillion = 1000000.0f; #ifdef _WIN32 static double onethousand = 1000.0f; #endif /* ifdef _WIN32 */ if (tt.fraction == 1 && tt.seconds == 0) return 0.0; /* immediate */ else { OSCTimeTag ttnow; double ttusec, nowusec, delta; #ifdef _WIN32 struct _timeb tb; _ftime(&tb); /* find now */ /* First get the seconds right */ ttnow.seconds = (unsigned) SECONDS_FROM_1900_to_1970 + (unsigned) tb.time; /* find usec in tt */ ttusec = tt.seconds*onemillion + ONE_MILLION_OVER_TWO_TO_THE_32*tt.fraction; nowusec = ttnow.seconds*onemillion + tb.millitm*onethousand; #else struct timeval tv; struct timezone tz; gettimeofday(&tv, &tz); /* find now */ /* First get the seconds right */ ttnow.seconds = (unsigned) SECONDS_FROM_1900_to_1970 + (unsigned) tv.tv_sec; /* find usec in tt */ ttusec = tt.seconds*onemillion + ONE_MILLION_OVER_TWO_TO_THE_32*tt.fraction; nowusec = ttnow.seconds*onemillion + tv.tv_usec; #endif /* ifdef _WIN32 */ /* subtract now from tt to get delta time */ /* if (ttusec < nowusec) return 0.0; */ /*negative delays are all right */ delta = ttusec - nowusec; return (float)(delta*0.001f); } } /* end of unpackOSC.c */ mrpeach/osc/routeOSC.c0000644000175000017500000005365512430231203015366 0ustar zmoelnigzmoelnig/* routeOSC.c 20060424 by Martin Peach, based on OSCroute and OSC-pattern-match.c. */ /* OSCroute.c header follows: */ /* Written by Adrian Freed, The Center for New Music and Audio Technologies, University of California, Berkeley. Copyright (c) 1992,93,94,95,96,97,98,99,2000,01,02,03,04 The Regents of the University of California (Regents). Permission to use, copy, modify, distribute, and distribute modified versions of this software and its documentation without fee and without a signed licensing agreement, is hereby granted, provided that the above copyright notice, this paragraph and the following two paragraphs appear in all copies, modifications, and distributions. IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. The OSC webpage is http://cnmat.cnmat.berkeley.edu/OpenSoundControl */ /* OSC-route.c Max object for OSC-style dispatching To-do: Match a pattern against a pattern? [Done: Only Slash-Star is allowed, see MyPatternMatch.] Declare outlet types / distinguish leaf nodes from other children More sophisticated (2-pass?) allmessages scheme set message? pd ------------- -- tweaks for Win32 www.zeggz.com/raf 13-April-2002 */ /* OSC-pattern-match.c header follows: */ /* Copyright © 1998. The Regents of the University of California (Regents). All Rights Reserved. Written by Matt Wright, The Center for New Music and Audio Technologies, University of California, Berkeley. Permission to use, copy, modify, distribute, and distribute modified versions of this software and its documentation without fee and without a signed licensing agreement, is hereby granted, provided that the above copyright notice, this paragraph and the following two paragraphs appear in all copies, modifications, and distributions. IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. The OpenSound Control WWW page is http://www.cnmat.berkeley.edu/OpenSoundControl */ /* OSC-pattern-match.c Matt Wright, 3/16/98 Adapted from oscpattern.c, by Matt Wright and Amar Chaudhury */ /* the required include files */ #include "m_pd.h" #define MAX_NUM 128 // maximum number of paths (prefixes) we can route typedef struct _routeOSC { t_object x_obj; /* required header */ int x_num; /* Number of prefixes we store */ int x_verbosity; /* level of debug output required */ char **x_prefixes; /* the OSC addresses to be matched */ int *x_prefix_depth; /* the number of slashes in each prefix */ void **x_outlets; /* one for each prefix plus one for everything else */ } t_routeOSC; /* prototypes */ void routeOSC_setup(void); static void routeOSC_free(t_routeOSC *x); static int MyPatternMatch (const char *pattern, const char *test); static void routeOSC_doanything(t_routeOSC *x, t_symbol *s, int argc, t_atom *argv); static void routeOSC_bang(t_routeOSC *x); static void routeOSC_float(t_routeOSC *x, t_floatarg f); static void routeOSC_symbol(t_routeOSC *x, t_symbol *s); static void routeOSC_list(t_routeOSC *x, t_symbol *s, int argc, t_atom *argv); static void *routeOSC_new(t_symbol *s, int argc, t_atom *argv); static void routeOSC_set(t_routeOSC *x, t_symbol *s, int argc, t_atom *argv); static void routeOSC_paths(t_routeOSC *x, t_symbol *s, int argc, t_atom *argv); static void routeOSC_verbosity(t_routeOSC *x, t_floatarg v); static int routeOSC_count_slashes(char *prefix); static char *NextSlashOrNull(char *p); static char *NthSlashOrNull(char *p, int n); static void StrCopyUntilSlash(char *target, const char *source); static void StrCopyUntilNthSlash(char *target, const char *source, int n); /* from OSC-pattern-match.c */ static const char *theWholePattern; /* Just for warning messages */ static int MatchBrackets (const char *pattern, const char *test); static int MatchList (const char *pattern, const char *test); static int PatternMatch (const char * pattern, const char * test); static t_class *routeOSC_class; t_symbol *ps_list, *ps_complain, *ps_emptySymbol; static int MyPatternMatch (const char *pattern, const char *test) { // This allows the special case of "routeOSC /* " to be an outlet that // matches anything; i.e., it always outputs the input with the first level // of the address stripped off. if (test[0] == '*' && test[1] == '\0') return 1; else return PatternMatch(pattern, test); } static void routeOSC_free(t_routeOSC *x) { freebytes(x->x_prefixes, x->x_num*sizeof(char *)); /* the OSC addresses to be matched */ freebytes(x->x_prefix_depth, x->x_num*sizeof(int)); /* the number of slashes in each prefix */ freebytes(x->x_outlets, (x->x_num+1)*sizeof(void *)); /* one for each prefix plus one for everything else */ } /* initialization routine */ void routeOSC_setup(void) { routeOSC_class = class_new(gensym("routeOSC"), (t_newmethod)routeOSC_new, (t_method)routeOSC_free, sizeof(t_routeOSC), 0, A_GIMME, 0); class_addanything(routeOSC_class, routeOSC_doanything); class_addbang(routeOSC_class, routeOSC_bang); class_addfloat(routeOSC_class, routeOSC_float); class_addsymbol(routeOSC_class, routeOSC_symbol); class_addlist(routeOSC_class, routeOSC_list); class_addmethod(routeOSC_class, (t_method)routeOSC_set, gensym("set"), A_GIMME, 0); class_addmethod(routeOSC_class, (t_method)routeOSC_paths, gensym("paths"), A_GIMME, 0); class_addmethod(routeOSC_class, (t_method)routeOSC_verbosity, gensym("verbosity"), A_DEFFLOAT, 0); ps_emptySymbol = gensym(""); // post("routeOSC object version 1.0 by Martin Peach, based on OSCroute by Matt Wright. pd: jdl Win32 raf."); // post("OSCroute Copyright © 1999 Regents of the Univ. of California. All Rights Reserved."); } /* instance creation routine */ static void *routeOSC_new(t_symbol *s, int argc, t_atom *argv) { t_routeOSC *x = (t_routeOSC *)pd_new(routeOSC_class); // get memory for a new object & initialize int i; if (argc > MAX_NUM) { error("* routeOSC: too many arguments: %d (max %d)", argc, MAX_NUM); return 0; } x->x_num = 0; /* first verify that all arguments are symbols whose first character is '/' */ for (i = 0; i < argc; ++i) { if (argv[i].a_type == A_SYMBOL) { if (argv[i].a_w.w_symbol->s_name[0] == '/') { /* Now that's a nice prefix */ ++(x->x_num); } else { error("routeOSC: argument %d does not begin with a slash(/).", i); return(0); } } else { error("routeOSC: argument %d is not a symbol.", i); return 0; } } /* now allocate the storage for each path */ x->x_prefixes = (char **)getzbytes(x->x_num*sizeof(char *)); /* the OSC addresses to be matched */ x->x_prefix_depth = (int *)getzbytes(x->x_num*sizeof(int)); /* the number of slashes in each prefix */ x->x_outlets = (void **)getzbytes((x->x_num+1)*sizeof(void *)); /* one for each prefix plus one for everything else */ /* put the pointer to the path in x_prefixes */ /* put the number of levels in x_prefix_depth */ for (i = 0; i < x->x_num; ++i) { x->x_prefixes[i] = argv[i].a_w.w_symbol->s_name; x->x_prefix_depth[i] = routeOSC_count_slashes(x->x_prefixes[i]); } /* Have to create the outlets in reverse order */ /* well, not in pd ? */ for (i = 0; i <= x->x_num; i++) { x->x_outlets[i] = outlet_new(&x->x_obj, &s_list); } x->x_verbosity = 0; /* quiet by default */ return (x); } static void routeOSC_set(t_routeOSC *x, t_symbol *s, int argc, t_atom *argv) { int i; if (argc > x->x_num) { pd_error (x, "routeOSC: too many paths"); return; } for (i = 0; i < argc; ++i) { if (argv[i].a_type != A_SYMBOL) { pd_error (x, "routeOSC: path %d not a symbol", i); return; } if (argv[i].a_w.w_symbol->s_name[0] != '/') { pd_error (x, "routeOSC: path %d doesn't start with /", i); return; } } for (i = 0; i < argc; ++i) { if (argv[i].a_w.w_symbol->s_name[0] == '/') { /* Now that's a nice prefix */ x->x_prefixes[i] = argv[i].a_w.w_symbol->s_name; x->x_prefix_depth[i] = routeOSC_count_slashes(x->x_prefixes[i]); } } } static void routeOSC_paths(t_routeOSC *x, t_symbol *s, int argc, t_atom *argv) { /* print out the paths we are matching */ int i; for (i = 0; i < x->x_num; ++i) post("path[%d]: %s (depth %d)", i, x->x_prefixes[i], x->x_prefix_depth[i]); } static void routeOSC_verbosity(t_routeOSC *x, t_floatarg v) { x->x_verbosity = (v == 0)? 0: 1; if (x->x_verbosity) post("routeOSC_verbosity(%p) is %d", x, x->x_verbosity); } static int routeOSC_count_slashes(char *prefix) { /* find the path depth of the prefix by counting the numberof slashes */ int i = 0; char *p = prefix; while (*p != '\0') if (*p++ == '/') i++; return i; } static void routeOSC_doanything(t_routeOSC *x, t_symbol *s, int argc, t_atom *argv) { char *pattern, *nextSlash; int i = 0, pattern_depth = 0, matchedAnything = 0; int noPath = 0; // nonzero if we are dealing with a simple list (as from a previous [routeOSC]) pattern = s->s_name; if (x->x_verbosity) post("routeOSC_doanything(%p): pattern is %s", x, pattern); if (pattern[0] != '/') { /* output unmatched data on rightmost outlet */ if (x->x_verbosity) post("routeOSC_doanything no OSC path(%p) , %d args", x, argc); outlet_anything(x->x_outlets[x->x_num], s, argc, argv); return; } pattern_depth = routeOSC_count_slashes(pattern); if (x->x_verbosity) post("routeOSC_doanything(%p): pattern_depth is %i", x, pattern_depth); nextSlash = NextSlashOrNull(pattern+1); if (*nextSlash == '\0') { /* pattern_depth == 1 */ /* last level of the address, so we'll output the argument list */ for (i = 0; i < x->x_num; ++i) { if ( (x->x_prefix_depth[i] <= pattern_depth) && (MyPatternMatch(pattern+1, x->x_prefixes[i]+1)) ) { ++matchedAnything; if (noPath) { // just a list starting with a symbol // The special symbol is s if (x->x_verbosity) post("routeOSC_doanything _1_(%p): (%d) noPath: s is \"%s\"", x, i, s->s_name); outlet_anything(x->x_outlets[i], s, argc, argv); } else // normal OSC path { // I hate stupid Max lists with a special first element if (argc == 0) { if (x->x_verbosity) post("routeOSC_doanything _2_(%p): (%d) no args", x, i); outlet_bang(x->x_outlets[i]); } else if (argv[0].a_type == A_SYMBOL) { // Promote the symbol that was argv[0] to the special symbol if (x->x_verbosity) post("routeOSC_doanything _3_(%p): (%d) symbol: is \"%s\"", x, i, argv[0].a_w.w_symbol->s_name); outlet_anything(x->x_outlets[i], argv[0].a_w.w_symbol, argc-1, argv+1); } else if (argc > 1) { // Multiple arguments starting with a number, so naturally we have // to use a special function to output this "list", since it's what // Max originally meant by "list". if (x->x_verbosity) post("routeOSC_doanything _4_(%p): (%d) list:", x, i); outlet_list(x->x_outlets[i], 0L, argc, argv); } else { // There was only one argument, and it was a number, so we output it // not as a list if (argv[0].a_type == A_FLOAT) { if (x->x_verbosity) post("routeOSC_doanything _5_(%p): (%d) a single float", x, i); outlet_float(x->x_outlets[i], argv[0].a_w.w_float); } else { pd_error(x, "* routeOSC: unrecognized atom type!"); } } } } } } else { /* There's more address after this part, so our output list will begin with the next slash. */ t_symbol *restOfPattern = 0; /* avoid the gensym unless we have to output */ char patternBegin[1000]; /* Get the incoming pattern to match against all our prefixes */ for (i = 0; i < x->x_num; ++i) { restOfPattern = 0; if (x->x_prefix_depth[i] <= pattern_depth) { StrCopyUntilNthSlash(patternBegin, pattern+1, x->x_prefix_depth[i]); if (x->x_verbosity) post("routeOSC_doanything _6_(%p): (%d) patternBegin is %s", x, i, patternBegin); if (MyPatternMatch(patternBegin, x->x_prefixes[i]+1)) { if (x->x_verbosity) post("routeOSC_doanything _7_(%p): (%d) matched %s depth %d", x, i, x->x_prefixes[i], x->x_prefix_depth[i]); ++matchedAnything; nextSlash = NthSlashOrNull(pattern+1, x->x_prefix_depth[i]); if (x->x_verbosity) post("routeOSC_doanything _8_(%p): (%d) nextSlash %s [%d]", x, i, nextSlash, nextSlash[0]); if (*nextSlash != '\0') { if (x->x_verbosity) post("routeOSC_doanything _9_(%p): (%d) more pattern", x, i); restOfPattern = gensym(nextSlash); outlet_anything(x->x_outlets[i], restOfPattern, argc, argv); } else if (argc == 0) { if (x->x_verbosity) post("routeOSC_doanything _10_(%p): (%d) no more pattern, no args", x, i); outlet_bang(x->x_outlets[i]); } else { if (x->x_verbosity) post("routeOSC_doanything _11_(%p): (%d) no more pattern, %d args", x, i, argc); if (argv[0].a_type == A_SYMBOL) // Promote the symbol that was argv[0] to the special symbol outlet_anything(x->x_outlets[i], argv[0].a_w.w_symbol, argc-1, argv+1); else outlet_anything(x->x_outlets[i], gensym("list"), argc, argv); } } } } } if (!matchedAnything) { // output unmatched data on rightmost outlet a la normal 'route' object, jdl 20020908 if (x->x_verbosity) post("routeOSC_doanything _13_(%p) unmatched %d, %d args", x, i, argc); outlet_anything(x->x_outlets[x->x_num], s, argc, argv); } } static void routeOSC_bang(t_routeOSC *x) { /* output non-OSC data on rightmost outlet */ if (x->x_verbosity) post("routeOSC_bang (%p)", x); outlet_bang(x->x_outlets[x->x_num]); } static void routeOSC_float(t_routeOSC *x, t_floatarg f) { /* output non-OSC data on rightmost outlet */ if (x->x_verbosity) post("routeOSC_float (%p) %f", x, f); outlet_float(x->x_outlets[x->x_num], f); } static void routeOSC_symbol(t_routeOSC *x, t_symbol *s) { /* output non-OSC data on rightmost outlet */ if (x->x_verbosity) post("routeOSC_symbol (%p) %s", x, s->s_name); outlet_symbol(x->x_outlets[x->x_num], s); } static void routeOSC_list(t_routeOSC *x, t_symbol *s, int argc, t_atom *argv) { /* output non-OSC data on rightmost outlet */ if (x->x_verbosity) post("routeOSC_list (%p) s=%s argc is %d", x, s->s_name, argc); if (0 == argc) post("routeOSC_list (%p) empty list", x);/* this should never happen but catch it just in case... */ else if (argv[0].a_type == A_SYMBOL) routeOSC_doanything(x, argv[0].a_w.w_symbol, argc-1, &argv[1]); else if (argv[0].a_type == A_FLOAT) { if (x->x_verbosity) post("routeOSC_list (%p) floats:", x); outlet_list(x->x_outlets[x->x_num], 0L, argc, argv); } } static char *NextSlashOrNull(char *p) { while (*p != '/' && *p != '\0') p++; return p; } static char *NthSlashOrNull(char *p, int n) { int i; for (i = 0; i < n; ++i) { while (*p != '/') { if (*p == '\0') return p; p++; } if (i < n-1) p++; /* skip the slash unless it's the nth slash */ } return p; } static void StrCopyUntilSlash(char *target, const char *source) { while (*source != '/' && *source != '\0') { *target = *source; ++target; ++source; } *target = 0; } static void StrCopyUntilNthSlash(char *target, const char *source, int n) { /* copy the path up but not including the nth slash */ int i = n; while (i > 0) { while (*source != '/') { *target = *source; if (*source == '\0') return; ++target; ++source; } i--; /* got a slash. If it's the nth, don't include it */ if (i == 0) { *target = 0; return; } *target = *source; ++source; ++target; } } /* from OSC-pattern-match.c Matt Wright, 3/16/98 Adapted from oscpattern.c, by Matt Wright and Amar Chaudhury */ static int PatternMatch (const char * pattern, const char * test) { theWholePattern = pattern; if (pattern == 0 || pattern[0] == 0) return test[0] == 0; if (test[0] == 0) { if (pattern[0] == '*') return PatternMatch (pattern+1, test); return 0; } switch (pattern[0]) { case 0: return test[0] == 0; case '?': return PatternMatch (pattern+1, test+1); case '*': if (PatternMatch (pattern+1, test)) return 1; return PatternMatch (pattern, test+1); case ']': case '}': error("routeOSC: Spurious %c in pattern \".../%s/...\"",pattern[0], theWholePattern); return 0; case '[': return MatchBrackets (pattern,test); case '{': return MatchList (pattern,test); case '\\': if (pattern[1] == 0) return test[0] == 0; if (pattern[1] == test[0]) return PatternMatch (pattern+2,test+1); return 0; default: if (pattern[0] == test[0]) return PatternMatch (pattern+1,test+1); return 0; } } /* we know that pattern[0] == '[' and test[0] != 0 */ static int MatchBrackets (const char *pattern, const char *test) { int result; int negated = 0; const char *p = pattern; if (pattern[1] == 0) { error("routeOSC: Unterminated [ in pattern \".../%s/...\"", theWholePattern); return 0; } if (pattern[1] == '!') { negated = 1; p++; } while (*p != ']') { if (*p == 0) { error("Unterminated [ in pattern \".../%s/...\"", theWholePattern); return 0; } if (p[1] == '-' && p[2] != 0) { if (test[0] >= p[0] && test[0] <= p[2]) { result = !negated; goto advance; } } if (p[0] == test[0]) { result = !negated; goto advance; } p++; } result = negated; advance: if (!result) return 0; while (*p != ']') { if (*p == 0) { error("Unterminated [ in pattern \".../%s/...\"", theWholePattern); return 0; } p++; } return PatternMatch (p+1,test+1); } static int MatchList (const char *pattern, const char *test) { const char *restOfPattern, *tp = test; for(restOfPattern = pattern; *restOfPattern != '}'; restOfPattern++) { if (*restOfPattern == 0) { error("Unterminated { in pattern \".../%s/...\"", theWholePattern); return 0; } } restOfPattern++; /* skip close curly brace */ pattern++; /* skip open curly brace */ while (1) { if (*pattern == ',') { if (PatternMatch (restOfPattern, tp)) return 1; tp = test; ++pattern; } else if (*pattern == '}') return PatternMatch (restOfPattern, tp); else if (*pattern == *tp) { ++pattern; ++tp; } else { tp = test; while (*pattern != ',' && *pattern != '}') pattern++; if (*pattern == ',') pattern++; } } } /* end of routeOSC.c */ mrpeach/osc/osc-meta.pd0000644000175000017500000000030412430431643015545 0ustar zmoelnigzmoelnig#N canvas 18 212 200 200 10; #N canvas 28 50 420 300 META 1; #X text 13 61 NAME OSC; #X text 13 85 VERSION 0.2; #X text 13 129 AUTHOR Martin Peach; #X text 19 189 NOTE:; #X restore 10 10 pd META; mrpeach/osc/Makefile0000644000175000017500000003234111616773462015173 0ustar zmoelnigzmoelnig## Pd library template version 1.0.9-zmoelnig # For instructions on how to use this template, see: # http://puredata.info/docs/developer/MakefileTemplate # # the name of this library # must not contain any spaces or weird characters (as it's used for # filenames,...) LIBRARY_NAME = osc # add your .c source files, one object per file, to the SOURCES # variable, help files will be included automatically, and for GUI # objects, the matching .tcl file too SOURCES = packOSC.c pipelist.c routeOSC.c unpackOSC.c # list all pd objects (i.e. myobject.pd) files here, and their helpfiles will # be included automatically PDOBJECTS = packOSCstream.pd unpackOSCstream.pd # example patches and related files, in the 'examples' subfolder EXAMPLES = # manuals and related files, in the 'manual' subfolder MANUAL = # if you want to include any other files in the source and binary tarballs, # list them here. This can be anything from header files, test patches, # documentation, etc. README.txt and LICENSE.txt are required and therefore # automatically included EXTRA_DIST = packingOSC.h HELPPATCHES = \ packOSC-help.pd \ packOSCstream-help.pd \ pipelist-help.pd routeOSC-help.pd \ unpackOSCstream-help.pd #------------------------------------------------------------------------------# # # things you might need to edit if you are using other C libraries # #------------------------------------------------------------------------------# # -I"$(PD_INCLUDE)" supports the header location for 0.43 ALL_CFLAGS = -I"$(PD_INCLUDE)" ALL_LDFLAGS = ALL_LIBS = #------------------------------------------------------------------------------# # # you shouldn't need to edit anything below here, if we did it right :) # #------------------------------------------------------------------------------# # these can be set from outside without (usually) breaking the build CFLAGS = -Wall -W -g LDFLAGS= LIBS= # get library version from meta file LIBRARY_VERSION = $(shell sed -n 's|^\#X text [0-9][0-9]* [0-9][0-9]* VERSION \(.*\);|\1|p' $(LIBRARY_NAME)-meta.pd) ALL_CFLAGS += -DPD -DVERSION='"$(LIBRARY_VERSION)"' PD_INCLUDE = $(PD_PATH)/include/pd # where to install the library, overridden below depending on platform prefix = /usr/local libdir = $(prefix)/lib pkglibdir = $(libdir)/pd-externals objectsdir = $(pkglibdir) INSTALL = install INSTALL_PROGRAM = $(INSTALL) -p -m 644 INSTALL_DATA = $(INSTALL) -p -m 644 INSTALL_DIR = $(INSTALL) -p -m 755 -d ALLSOURCES := $(SOURCES) $(SOURCES_android) $(SOURCES_cygwin) $(SOURCES_macosx) \ $(SOURCES_iphoneos) $(SOURCES_linux) $(SOURCES_windows) DISTDIR=$(LIBRARY_NAME)-$(LIBRARY_VERSION) ORIGDIR=pd-$(LIBRARY_NAME:~=)_$(LIBRARY_VERSION) UNAME := $(shell uname -s) ifeq ($(UNAME),Darwin) CPU := $(shell uname -p) ifeq ($(CPU),arm) # iPhone/iPod Touch SOURCES += $(SOURCES_iphoneos) EXTENSION = pd_darwin OS = iphoneos PD_PATH = /Applications/Pd-extended.app/Contents/Resources IPHONE_BASE=/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin CC=$(IPHONE_BASE)/gcc CPP=$(IPHONE_BASE)/cpp CXX=$(IPHONE_BASE)/g++ ISYSROOT = -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.0.sdk IPHONE_CFLAGS = -miphoneos-version-min=3.0 $(ISYSROOT) -arch armv6 OPT_CFLAGS = -fast -funroll-loops -fomit-frame-pointer ALL_CFLAGS := $(IPHONE_CFLAGS) $(ALL_CFLAGS) ALL_LDFLAGS += -arch armv6 -bundle -undefined dynamic_lookup $(ISYSROOT) ALL_LIBS += -lc STRIP = strip -x DISTBINDIR=$(DISTDIR)-$(OS) else # Mac OS X SOURCES += $(SOURCES_macosx) EXTENSION = pd_darwin OS = macosx PD_PATH = /Applications/Pd-extended.app/Contents/Resources OPT_CFLAGS = -ftree-vectorize -ftree-vectorizer-verbose=2 -fast # build universal 32-bit on 10.4 and 32/64 on newer ifeq ($(shell uname -r | sed 's|\([0-9][0-9]*\)\.[0-9][0-9]*\.[0-9][0-9]*|\1|'), 8) FAT_FLAGS = -arch ppc -arch i386 -mmacosx-version-min=10.4 else FAT_FLAGS = -arch ppc -arch i386 -arch x86_64 -mmacosx-version-min=10.4 SOURCES += $(SOURCES_iphoneos) endif ALL_CFLAGS += $(FAT_FLAGS) -fPIC -I/sw/include ALL_LDFLAGS += $(FAT_FLAGS) -bundle -undefined dynamic_lookup -L/sw/lib # if the 'pd' binary exists, check the linking against it to aid with stripping ALL_LDFLAGS += $(shell test -e $(PD_PATH)/bin/pd && echo -bundle_loader $(PD_PATH)/bin/pd) ALL_LIBS += -lc STRIP = strip -x DISTBINDIR=$(DISTDIR)-$(OS) # install into ~/Library/Pd on Mac OS X since /usr/local isn't used much pkglibdir=$(HOME)/Library/Pd endif endif # Tho Android uses Linux, we use this fake uname to provide an easy way to # setup all this things needed to cross-compile for Android using the NDK ifeq ($(UNAME),ANDROID) CPU := arm SOURCES += $(SOURCES_android) EXTENSION = pd_linux OS = android PD_PATH = /usr NDK_BASE := /usr/local/android-ndk NDK_PLATFORM_VERSION := 5 NDK_SYSROOT=$(NDK_BASE)/platforms/android-$(NDK_PLATFORM_VERSION)/arch-arm NDK_UNAME := $(shell uname -s | tr '[A-Z]' '[a-z]') NDK_TOOLCHAIN_BASE=$(NDK_BASE)/toolchains/arm-linux-androideabi-4.4.3/prebuilt/$(NDK_UNAME)-x86 CC := $(NDK_TOOLCHAIN_BASE)/bin/arm-linux-androideabi-gcc --sysroot=$(NDK_SYSROOT) OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer CFLAGS += LDFLAGS += -Wl,--export-dynamic -shared LIBS += -lc STRIP := $(NDK_TOOLCHAIN_BASE)/bin/arm-linux-androideabi-strip \ --strip-unneeded -R .note -R .comment DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m) endif ifeq ($(UNAME),Linux) CPU := $(shell uname -m) SOURCES += $(SOURCES_linux) EXTENSION = pd_linux OS = linux PD_PATH = /usr OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer ALL_CFLAGS += -fPIC ALL_LDFLAGS += -Wl,--export-dynamic -shared -fPIC ALL_LIBS += -lc STRIP = strip --strip-unneeded -R .note -R .comment DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m) endif ifeq ($(UNAME),GNU) # GNU/Hurd, should work like GNU/Linux for basically all externals CPU := $(shell uname -m) SOURCES += $(SOURCES_linux) EXTENSION = pd_linux OS = linux PD_PATH = /usr OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer ALL_CFLAGS += -fPIC ALL_LDFLAGS += -Wl,--export-dynamic -shared -fPIC ALL_LIBS += -lc STRIP = strip --strip-unneeded -R .note -R .comment DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m) endif ifeq ($(UNAME),GNU/kFreeBSD) # Debian GNU/kFreeBSD, should work like GNU/Linux for basically all externals CPU := $(shell uname -m) SOURCES += $(SOURCES_linux) EXTENSION = pd_linux OS = linux PD_PATH = /usr OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer ALL_CFLAGS += -fPIC ALL_LDFLAGS += -Wl,--export-dynamic -shared -fPIC ALL_LIBS += -lc STRIP = strip --strip-unneeded -R .note -R .comment DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m) endif ifeq (CYGWIN,$(findstring CYGWIN,$(UNAME))) CPU := $(shell uname -m) SOURCES += $(SOURCES_cygwin) EXTENSION = dll OS = cygwin PD_PATH = $(cygpath $(PROGRAMFILES))/pd OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer ALL_CFLAGS += ALL_LDFLAGS += -Wl,--export-dynamic -shared -L"$(PD_PATH)/src" -L"$(PD_PATH)/bin" ALL_LIBS += -lc -lpd STRIP = strip --strip-unneeded -R .note -R .comment DISTBINDIR=$(DISTDIR)-$(OS) endif ifeq (MINGW,$(findstring MINGW,$(UNAME))) CPU := $(shell uname -m) SOURCES += $(SOURCES_windows) EXTENSION = dll OS = windows PD_PATH = $(shell cd "$(PROGRAMFILES)"/pd && pwd) OPT_CFLAGS = -O3 -funroll-loops -fomit-frame-pointer ALL_CFLAGS += -mms-bitfields ALL_LDFLAGS += -s -shared -Wl,--enable-auto-import ALL_LIBS += -L"$(PD_PATH)/src" -L"$(PD_PATH)/bin" -L"$(PD_PATH)/obj" -lpd -lwsock32 -lkernel32 -luser32 -lgdi32 STRIP = strip --strip-unneeded -R .note -R .comment DISTBINDIR=$(DISTDIR)-$(OS) endif # in case somebody manually set the HELPPATCHES above HELPPATCHES ?= $(SOURCES:.c=-help.pd) $(PDOBJECTS:.pd=-help.pd) CFLAGS += $(OPT_CFLAGS) ALL_CFLAGS := $(ALL_CFLAGS) $(CFLAGS) ALL_LDFLAGS := $(LDFLAGS) $(ALL_LDFLAGS) ALL_LIBS := $(LIBS) $(ALL_LIBS) .PHONY = install libdir_install single_install install-doc install-exec install-examples install-manual clean dist etags $(LIBRARY_NAME) all: $(SOURCES:.c=.$(EXTENSION)) %.o: %.c $(CC) $(ALL_CFLAGS) -o "$*.o" -c "$*.c" %.$(EXTENSION): %.o $(CC) $(ALL_LDFLAGS) -o "$*.$(EXTENSION)" "$*.o" $(ALL_LIBS) chmod a-x "$*.$(EXTENSION)" # this links everything into a single binary file $(LIBRARY_NAME): $(SOURCES:.c=.o) $(LIBRARY_NAME).o $(CC) $(ALL_LDFLAGS) -o $(LIBRARY_NAME).$(EXTENSION) $(SOURCES:.c=.o) $(LIBRARY_NAME).o $(ALL_LIBS) chmod a-x $(LIBRARY_NAME).$(EXTENSION) install: libdir_install # The meta and help files are explicitly installed to make sure they are # actually there. Those files are not optional, then need to be there. libdir_install: $(SOURCES:.c=.$(EXTENSION)) install-doc install-examples install-manual $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) $(INSTALL_DATA) $(LIBRARY_NAME)-meta.pd \ $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) test -z "$(strip $(SOURCES))" || (\ $(INSTALL_PROGRAM) $(SOURCES:.c=.$(EXTENSION)) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) && \ $(STRIP) $(addprefix $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/,$(SOURCES:.c=.$(EXTENSION)))) test -z "$(strip $(shell ls $(SOURCES:.c=.tcl)))" || \ $(INSTALL_DATA) $(shell ls $(SOURCES:.c=.tcl)) \ $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) test -z "$(strip $(PDOBJECTS))" || \ $(INSTALL_DATA) $(PDOBJECTS) \ $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) # install library linked as single binary single_install: $(LIBRARY_NAME) install-doc install-exec $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) $(INSTALL_PROGRAM) $(LIBRARY_NAME).$(EXTENSION) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) $(STRIP) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/$(LIBRARY_NAME).$(EXTENSION) install-doc: $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) test -z "$(strip $(SOURCES) $(PDOBJECTS))" || \ $(INSTALL_DATA) $(HELPPATCHES) \ $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) $(INSTALL_DATA) README.txt $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/README.txt $(INSTALL_DATA) LICENSE.txt $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/LICENSE.txt install-examples: test -z "$(strip $(EXAMPLES))" || \ $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/examples && \ for file in $(EXAMPLES); do \ $(INSTALL_DATA) examples/$$file $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/examples; \ done install-manual: test -z "$(strip $(MANUAL))" || \ $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/manual && \ for file in $(MANUAL); do \ $(INSTALL_DATA) manual/$$file $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/manual; \ done clean: -rm -f -- $(SOURCES:.c=.o) $(SOURCES_LIB:.c=.o) -rm -f -- $(SOURCES:.c=.$(EXTENSION)) -rm -f -- $(LIBRARY_NAME).o -rm -f -- $(LIBRARY_NAME).$(EXTENSION) distclean: clean -rm -f -- $(DISTBINDIR).tar.gz -rm -rf -- $(DISTBINDIR) -rm -f -- $(DISTDIR).tar.gz -rm -rf -- $(DISTDIR) -rm -f -- $(ORIGDIR).tar.gz -rm -rf -- $(ORIGDIR) $(DISTBINDIR): $(INSTALL_DIR) $(DISTBINDIR) libdir: all $(DISTBINDIR) $(INSTALL_DATA) $(LIBRARY_NAME)-meta.pd $(DISTBINDIR) $(INSTALL_DATA) $(SOURCES) $(DISTBINDIR) $(INSTALL_DATA) $(HELPPATCHES) $(DISTBINDIR) test -z "$(strip $(EXTRA_DIST))" || \ $(INSTALL_DATA) $(EXTRA_DIST) $(DISTBINDIR) # tar --exclude-vcs -czpf $(DISTBINDIR).tar.gz $(DISTBINDIR) $(DISTDIR): $(INSTALL_DIR) $(DISTDIR) $(ORIGDIR): $(INSTALL_DIR) $(ORIGDIR) dist: $(DISTDIR) $(INSTALL_DATA) Makefile $(DISTDIR) $(INSTALL_DATA) README.txt $(DISTDIR) $(INSTALL_DATA) LICENSE.txt $(DISTDIR) $(INSTALL_DATA) $(LIBRARY_NAME)-meta.pd $(DISTDIR) test -z "$(strip $(ALLSOURCES))" || \ $(INSTALL_DATA) $(ALLSOURCES) $(DISTDIR) test -z "$(strip $(shell ls $(ALLSOURCES:.c=.tcl)))" || \ $(INSTALL_DATA) $(shell ls $(ALLSOURCES:.c=.tcl)) $(DISTDIR) test -z "$(strip $(PDOBJECTS))" || \ $(INSTALL_DATA) $(PDOBJECTS) $(DISTDIR) test -z "$(strip $(HELPPATCHES))" || \ $(INSTALL_DATA) $(HELPPATCHES) $(DISTDIR) test -z "$(strip $(EXTRA_DIST))" || \ $(INSTALL_DATA) $(EXTRA_DIST) $(DISTDIR) test -z "$(strip $(EXAMPLES))" || \ $(INSTALL_DIR) $(DISTDIR)/examples && \ for file in $(EXAMPLES); do \ $(INSTALL_DATA) examples/$$file $(DISTDIR)/examples; \ done test -z "$(strip $(MANUAL))" || \ $(INSTALL_DIR) $(DISTDIR)/manual && \ for file in $(MANUAL); do \ $(INSTALL_DATA) manual/$$file $(DISTDIR)/manual; \ done tar --exclude-vcs -czpf $(DISTDIR).tar.gz $(DISTDIR) # make a Debian source package dpkg-source: debclean make distclean dist mv $(DISTDIR) $(ORIGDIR) tar --exclude-vcs -czpf ../$(ORIGDIR).orig.tar.gz $(ORIGDIR) rm -f -- $(DISTDIR).tar.gz rm -rf -- $(DISTDIR) $(ORIGDIR) cd .. && dpkg-source -b $(LIBRARY_NAME) etags: etags *.h $(SOURCES) ../../pd/src/*.[ch] /usr/include/*.h /usr/include/*/*.h showsetup: @echo "CFLAGS: $(CFLAGS)" @echo "LDFLAGS: $(LDFLAGS)" @echo "LIBS: $(LIBS)" @echo "ALL_CFLAGS: $(ALL_CFLAGS)" @echo "ALL_LDFLAGS: $(ALL_LDFLAGS)" @echo "ALL_LIBS: $(ALL_LIBS)" @echo "PD_INCLUDE: $(PD_INCLUDE)" @echo "PD_PATH: $(PD_PATH)" @echo "objectsdir: $(objectsdir)" @echo "LIBRARY_NAME: $(LIBRARY_NAME)" @echo "LIBRARY_VERSION: $(LIBRARY_VERSION)" @echo "SOURCES: $(SOURCES)" @echo "PDOBJECTS: $(PDOBJECTS)" @echo "ALLSOURCES: $(ALLSOURCES)" @echo "UNAME: $(UNAME)" @echo "CPU: $(CPU)" @echo "pkglibdir: $(pkglibdir)" @echo "DISTDIR: $(DISTDIR)" @echo "ORIGDIR: $(ORIGDIR)" mrpeach/osc/packOSC.c0000644000175000017500000014230012741545524015153 0ustar zmoelnigzmoelnig/* packOSC is like sendOSC but outputs a list of floats which are the bytes making up the OSC packet. */ /* This allows for the separation of the protocol and its transport. */ /* Started by Martin Peach 20060403 */ /* 20060425 version independent of libOSC */ /* 20070620 added packOSC_path and packOSC_anything methods by zmoelnig */ /* 20160713 added 'm' typetag for MIDI messages */ /* packOSC.c makes extensive use of code from OSC-client.c and sendOSC.c */ /* as well as some from OSC-timetag.c. These files have the following header: */ /* Written by Matt Wright, The Center for New Music and Audio Technologies, University of California, Berkeley. Copyright (c) 1996,97,98,99,2000,01,02,03 The Regents of the University of California (Regents). Permission to use, copy, modify, distribute, and distribute modified versions of this software and its documentation without fee and without a signed licensing agreement, is hereby granted, provided that the above copyright notice, this paragraph and the following two paragraphs appear in all copies, modifications, and distributions. IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. The OSC webpage is http://cnmat.cnmat.berkeley.edu/OpenSoundControl */ //define DEBUG #define SC_BUFFER_SIZE 64000 #include "packingOSC.h" /* This is from OSC-client.h :*/ /* OSC-client.h: library for constructing OpenSoundControl messages. Derived from SynthControl.h Author: Matt Wright Version 0.1: 6/13/97 Version 0.2: 7/21/2000: Support for type-tagged messages General notes: This library abstracts away the data format for the OpenSoundControl protocol. Users of this library can construct OpenSoundControl packets with a function call interface instead of knowing how to lay out the bits. All issues of memory allocation are deferred to the user of this library. There are two data structures that the user must allocate. The first is the actual buffer that the message will be written into. This buffer can be any size, but if it's too small there's a possibility that it will become overfull. The other data structure is called an OSCbuf, and it holds all the state used by the library as it's constructing a buffer. All procedures that have the possibility of an error condition return int, with 0 indicating no error and nonzero indicating an error. The variable OSC_errorMessage will be set to point to a string containing an error message explaining what the problem is. */ /* OSC_timeTag.h: library for manipulating OSC time tags Matt Wright, 5/29/97 Time tags in OSC have the same format as in NTP: 64 bit fixed point, with the top 32 bits giving number of seconds sinve midnight 1/1/1900 and the bottom 32 bits giving fractional parts of a second. We represent this by an 8-byte unsigned long if possible, or else a struct. NB: On many architectures with 8-byte ints, it's illegal (like maybe a bus error) to dereference a pointer to an 8 byte int that's not 8-byte aligned. */ /* Return the time tag 0x0000000000000001, indicating to the receiving device that it should process the message immediately. */ static OSCTimeTag OSCTT_Immediately(void); static OSCTimeTag OSCTT_Infinite(void); static OSCTimeTag OSCTT_CurrentTimePlusOffset(uint32_t offset); /* Don't ever manipulate the data in the OSCbuf struct directly. (It's declared here in the header file only so your program will be able to declare variables of type OSCbuf and have the right amount of memory be allocated.) */ typedef struct OSCbuf_struct { char *buffer; /* The buffer to hold the OSC packet */ size_t size; /* Size of the buffer */ char *bufptr; /* Current position as we fill the buffer */ int state; /* State of partially-constructed message */ uint32_t *thisMsgSize; /* Pointer to count field before */ /* currently-being-written message */ uint32_t *prevCounts[MAX_BUNDLE_NESTING]; /* Pointers to count */ /* field before each currently open bundle */ int bundleDepth; /* How many sub-sub-bundles are we in now? */ char *typeStringPtr; /* This pointer advances through the type */ /* tag string as you add arguments. */ int gettingFirstUntypedArg; /* nonzero if this message doesn't have */ /* a type tag and we're waiting for the 1st arg */ } OSCbuf; typedef struct { enum {INT_osc, FLOAT_osc, STRING_osc, BLOB_osc, NOTYPE_osc} type; union { int i; float f; char *s; } datum; } typedArg; /* Here are the possible values of the state field: */ #define EMPTY 0 /* Nothing written to packet yet */ #define ONE_MSG_ARGS 1 /* Packet has a single message; gathering arguments */ #define NEED_COUNT 2 /* Just opened a bundle; must write message name or */ /* open another bundle */ #define GET_ARGS 3 /* Getting arguments to a message. If we see a message */ /* name or a bundle open/close then the current message */ /* will end. */ #define DONE 4 /* All open bundles have been closed, so can't write */ /* anything else */ static int OSC_strlen(char *s); static int OSC_padString(char *dest, char *str); static int OSC_padStringWithAnExtraStupidComma(char *dest, char *str); static int OSC_WriteStringPadding(char *dest, int i); static int OSC_WriteBlobPadding(char *dest, int i); static int CheckTypeTag(OSCbuf *buf, char expectedType); /* Initialize the given OSCbuf. The user of this module must pass in the block of memory that this OSCbuf will use for a buffer, and the number of bytes in that block. (It's the user's job to allocate the memory because you do it differently in different systems.) */ static void OSC_initBuffer(OSCbuf *buf, size_t size, char *byteArray); /* Reset the given OSCbuf. Do this after you send out the contents of the buffer and want to start writing new data into it. */ static void OSC_resetBuffer(OSCbuf *buf); /* Is the buffer empty? (I.e., would it be stupid to send the buffer contents to the synth?) */ static int OSC_isBufferEmpty(OSCbuf *buf); /* How much space is left in the buffer? */ static size_t OSC_freeSpaceInBuffer(OSCbuf *buf); /* Does the buffer contain a valid OSC packet? (Returns nonzero if yes.) */ static int OSC_isBufferDone(OSCbuf *buf); /* When you're ready to send out the buffer (i.e., when OSC_isBufferDone() returns true), call these two procedures to get the OSC packet that's been assembled and its size in bytes. (And then call OSC_resetBuffer() if you want to re-use this OSCbuf for the next packet.) */ static char *OSC_getPacket(OSCbuf *buf); static int OSC_packetSize(OSCbuf *buf); static int OSC_CheckOverflow(OSCbuf *buf, size_t bytesNeeded); /* Here's the basic model for building up OSC messages in an OSCbuf: - Make sure the OSCbuf has been initialized with OSC_initBuffer(). - To open a bundle, call OSC_openBundle(). You can then write messages or open new bundles within the bundle you opened. Call OSC_closeBundle() to close the bundle. Note that a packet does not have to have a bundle; it can instead consist of just a single message. - For each message you want to send: - Call OSC_writeAddress() with the name of your message. (In addition to writing your message name into the buffer, this procedure will also leave space for the size count of this message.) - Alternately, call OSC_writeAddressAndTypes() with the name of your message and with a type string listing the types of all the arguments you will be putting in this message. - Now write each of the arguments into the buffer, by calling one of: OSC_writeFloatArg() OSC_writeIntArg() OSC_writeStringArg() OSC_writeNullArg() - Now your message is complete; you can send out the buffer or you can add another message to it. */ static int OSC_openBundle(OSCbuf *buf, OSCTimeTag tt); static int OSC_closeBundle(OSCbuf *buf); static int OSC_writeAddress(OSCbuf *buf, char *name); static int OSC_writeAddressAndTypes(OSCbuf *buf, char *name, char *types); static int OSC_writeFloatArg(OSCbuf *buf, float arg); static int OSC_writeIntArg(OSCbuf *buf, uint32_t arg); static int OSC_writeBlobArg(OSCbuf *buf, typedArg *arg, size_t nArgs); static int OSC_writeStringArg(OSCbuf *buf, char *arg); static int OSC_writeNullArg(OSCbuf *buf, char type); /* How many bytes will be needed in the OSC format to hold the given string? The length of the string, plus the null char, plus any padding needed for 4-byte alignment. */ static int OSC_effectiveStringLength(char *string); static t_class *packOSC_class; typedef struct _packOSC { t_object x_obj; int x_typetags; /* typetag flag */ int x_timeTagOffset; int x_bundle; /* bundle open flag */ OSCbuf x_oscbuf[1]; /* OSCbuffer */ t_outlet *x_bdpthout; /* bundle-depth floatoutlet */ t_outlet *x_listout; /* OSC packet list ouput */ size_t x_buflength; /* number of elements in x_bufferForOSCbuf and x_bufferForOSClist */ char *x_bufferForOSCbuf; /*[SC_BUFFER_SIZE];*/ t_atom *x_bufferForOSClist; /*[SC_BUFFER_SIZE];*/ char *x_prefix; int x_reentry_count; } t_packOSC; static void *packOSC_new(void); static void packOSC_path(t_packOSC *x, t_symbol*s); static void packOSC_openbundle(t_packOSC *x); static void packOSC_closebundle(t_packOSC *x); static void packOSC_settypetags(t_packOSC *x, t_floatarg f); static void packOSC_setbufsize(t_packOSC *x, t_floatarg f); static void packOSC_setTimeTagOffset(t_packOSC *x, t_floatarg f); static void packOSC_sendtyped(t_packOSC *x, t_symbol *s, int argc, t_atom *argv); static void packOSC_send_type_forced(t_packOSC *x, t_symbol *s, int argc, t_atom *argv); static void packOSC_send(t_packOSC *x, t_symbol *s, int argc, t_atom *argv); static void packOSC_anything(t_packOSC *x, t_symbol *s, int argc, t_atom *argv); static void packOSC_free(t_packOSC *x); void packOSC_setup(void); static typedArg packOSC_parseatom(t_atom *a); static typedArg packOSC_packMIDI(t_atom *a); static typedArg packOSC_forceatom(t_atom *a, char ctype); static typedArg packOSC_blob(t_atom *a); static int packOSC_writetypedmessage(t_packOSC *x, OSCbuf *buf, char *messageName, int numArgs, typedArg *args, char *typeStr); static int packOSC_writemessage(t_packOSC *x, OSCbuf *buf, char *messageName, int numArgs, typedArg *args); static void packOSC_sendbuffer(t_packOSC *x); static void *packOSC_new(void) { t_packOSC *x = (t_packOSC *)pd_new(packOSC_class); x->x_typetags = 1; /* set typetags to 1 by default */ x->x_bundle = 0; /* bundle is closed */ x->x_buflength = SC_BUFFER_SIZE; x->x_bufferForOSCbuf = (char *)getbytes(sizeof(char)*x->x_buflength); if(x->x_bufferForOSCbuf == NULL) { pd_error(x, "packOSC: unable to allocate %lu bytes for x_bufferForOSCbuf", (long)(sizeof(char)*x->x_buflength)); goto fail; } x->x_bufferForOSClist = (t_atom *)getbytes(sizeof(t_atom)*x->x_buflength); if(x->x_bufferForOSClist == NULL) { pd_error(x, "packOSC: unable to allocate %lu bytes for x_bufferForOSClist", (long)(sizeof(t_atom)*x->x_buflength)); goto fail; } if (x->x_oscbuf != NULL) OSC_initBuffer(x->x_oscbuf, x->x_buflength, x->x_bufferForOSCbuf); x->x_listout = outlet_new(&x->x_obj, &s_list); x->x_bdpthout = outlet_new(&x->x_obj, &s_float); x->x_timeTagOffset = -1; /* immediately */ x->x_reentry_count = 0; return (x); fail: if(x->x_bufferForOSCbuf != NULL) freebytes(x->x_bufferForOSCbuf, (long)(sizeof(char)*x->x_buflength)); if(x->x_bufferForOSClist != NULL) freebytes(x->x_bufferForOSClist, (long)(sizeof(char)*x->x_buflength)); return NULL; } static void packOSC_path(t_packOSC *x, t_symbol*s) { /* Set a default prefix to the OSC path */ if(s == gensym("")) { x->x_prefix = 0; return; } if ((*s->s_name) != '/') { pd_error(x, "packOSC: bad path: '%s'", s->s_name); return; } x->x_prefix = s->s_name; } static void packOSC_openbundle(t_packOSC *x) { int result; t_float bundledepth=(t_float)x->x_oscbuf->bundleDepth; if (x->x_timeTagOffset == -1) result = OSC_openBundle(x->x_oscbuf, OSCTT_Immediately()); else result = OSC_openBundle(x->x_oscbuf, OSCTT_CurrentTimePlusOffset((uint32_t)x->x_timeTagOffset)); if (result != 0) { /* reset the buffer */ OSC_initBuffer(x->x_oscbuf, x->x_buflength, x->x_bufferForOSCbuf); x->x_bundle = 0; } else x->x_bundle = 1; outlet_float(x->x_bdpthout, bundledepth); } static void packOSC_closebundle(t_packOSC *x) { t_float bundledepth=(t_float)x->x_oscbuf->bundleDepth; if (OSC_closeBundle(x->x_oscbuf)) { pd_error(x, "packOSC: Problem closing bundle."); return; } outlet_float(x->x_bdpthout, bundledepth); /* in bundle mode we send when bundle is closed */ if(!OSC_isBufferEmpty(x->x_oscbuf) > 0 && OSC_isBufferDone(x->x_oscbuf)) { x->x_bundle = 0; /* call this before _sendbuffer() to be ready for recursive calls */ packOSC_sendbuffer(x); return; } } static void packOSC_settypetags(t_packOSC *x, t_floatarg f) { x->x_typetags = (f != 0)?1:0; post("packOSC: setting typetags %d", x->x_typetags); } static void packOSC_setbufsize(t_packOSC *x, t_floatarg f) { if (x->x_bufferForOSCbuf != NULL) freebytes((void *)x->x_bufferForOSCbuf, sizeof(char)*x->x_buflength); if (x->x_bufferForOSClist != NULL) freebytes((void *)x->x_bufferForOSClist, sizeof(t_atom)*x->x_buflength); post("packOSC: bufsize arg is %f (%lu)", f, (long)f); x->x_buflength = (long)f; x->x_bufferForOSCbuf = (char *)getbytes(sizeof(char)*x->x_buflength); if(x->x_bufferForOSCbuf == NULL) pd_error(x, "packOSC unable to allocate %lu bytes for x_bufferForOSCbuf", (long)(sizeof(char)*x->x_buflength)); x->x_bufferForOSClist = (t_atom *)getbytes(sizeof(t_atom)*x->x_buflength); if(x->x_bufferForOSClist == NULL) pd_error(x, "packOSC unable to allocate %lu bytes for x_bufferForOSClist", (long)(sizeof(t_atom)*x->x_buflength)); OSC_initBuffer(x->x_oscbuf, x->x_buflength, x->x_bufferForOSCbuf); post("packOSC: bufsize is now %d",x->x_buflength); } static void packOSC_setTimeTagOffset(t_packOSC *x, t_floatarg f) { x->x_timeTagOffset = (int)f; } /* this is the real and only sending routine now, for both typed and */ /* undtyped mode. */ static void packOSC_sendtyped(t_packOSC *x, t_symbol *s, int argc, t_atom *argv) { char messageName[MAXPDSTRING]; unsigned int nTypeTags = 0, typeStrTotalSize = 0; unsigned int argsSize = sizeof(typedArg)*argc; char* typeStr = NULL; /* might not be used */ typedArg* args = (typedArg*)getbytes(argsSize); unsigned int i, nTagsWithData, nArgs, blobCount; unsigned int m, tagIndex, typedArgIndex, argvIndex; char c; #ifdef DEBUG printf("*** packOSC_sendtyped bundle %d reentry %d\n", x->x_bundle, x->x_reentry_count); #endif x->x_reentry_count++; if (args == NULL) { pd_error(x, "packOSC: unable to allocate %lu bytes for args", (long)argsSize); return; } messageName[0] = '\0'; /* empty */ if(x->x_prefix) /* if there is a prefix, prefix it to the path */ { size_t len = strlen(x->x_prefix); if(len >= MAXPDSTRING) len = MAXPDSTRING-1; strncpy(messageName, x->x_prefix, MAXPDSTRING); atom_string(&argv[0], messageName+len, (unsigned)(MAXPDSTRING-len)); } else atom_string(&argv[0], messageName, MAXPDSTRING); /* the OSC address string */ if (x->x_typetags & 2) { /* second arg is typestring */ /* we need to find out how long the type string is before we copy it*/ nTypeTags = (unsigned int)strlen(atom_getsymbol(&argv[1])->s_name); typeStrTotalSize = nTypeTags + 2; typeStr = (char*)getzbytes(typeStrTotalSize); if (typeStr == NULL) { pd_error(x, "packOSC: unable to allocate %u bytes for typeStr", nTypeTags); return; } typeStr[0] = ','; atom_string(&argv[1], &typeStr[1], typeStrTotalSize); #ifdef DEBUG printf("packOSC_sendtyped typeStr: %s, nTypeTags %u\n", typeStr, nTypeTags); #endif nArgs = argc-2; for (m = nTagsWithData = blobCount = 0; m < nTypeTags; ++m) { #ifdef DEBUG printf("packOSC_sendtyped typeStr[%d] %c\n", m+1, typeStr[m+1]); #endif if ((c = typeStr[m+1]) == 0) break; if (!(c == 'T' || c == 'F' || c == 'N' || c == 'I')) { ++nTagsWithData; /* anything other than these tags have at least one data byte */ if (c == 'm') nTagsWithData += 3; // MIDI tag should have four data bytes /* OSC-blob An int32 size count, followed by that many 8-bit bytes of arbitrary binary data, followed by 0-3 additional zero bytes to make the total number of bits a multiple of 32. */ if (c == 'b') blobCount++; /* b probably has more than one byte, so set a flag */ } } if (((blobCount == 0)&&(nTagsWithData != nArgs)) || ((blobCount != 0)&&(nTagsWithData > nArgs))) { pd_error(x, "packOSC: Tags count %d doesn't match argument count %d", nTagsWithData, nArgs); goto cleanup; } if (blobCount > 1) { pd_error(x, "packOSC: Only one blob per packet at the moment..."); goto cleanup; } for (tagIndex = typedArgIndex = 0, argvIndex = 2; tagIndex < m; ++tagIndex) /* m is the number of tags */ { c = typeStr[tagIndex+1]; if (c == 'b') { /* A blob has to be the last item, until we get more elaborate. */ if (tagIndex != m-1) { pd_error(x, "packOSC: Since I don't know how big the blob is, Blob must be the last item in the list"); goto cleanup; } /* Pack all the remaining arguments as a blob */ for (; typedArgIndex < nArgs; ++typedArgIndex, ++argvIndex) { #ifdef DEBUG printf("packOSC_blob %d:\n", nArgs); #endif args[typedArgIndex] = packOSC_blob(&argv[argvIndex]); /* Make sure it was blobbable */ if (args[typedArgIndex].type != BLOB_osc) goto cleanup; } } else if (!(c == 'T' || c == 'F' || c == 'N' || c == 'I')) /* not no data */ { if (c == 'm') { // pack the next four arguments into one int args[typedArgIndex++] = packOSC_packMIDI(&argv[argvIndex]); argvIndex += 4; } else args[typedArgIndex++] = packOSC_forceatom(&argv[argvIndex++], c); } } //if(packOSC_writetypedmessage(x, x->x_oscbuf, messageName, nArgs, args, typeStr)) if(packOSC_writetypedmessage(x, x->x_oscbuf, messageName, typedArgIndex, args, typeStr)) { pd_error(x, "packOSC: usage error, packOSC_writetypedmessage failed."); goto cleanup; } } else { for (i = 0; i < (unsigned)(argc-1); i++) { args[i] = packOSC_parseatom(&argv[i+1]); #ifdef DEBUG switch (args[i].type) { case INT_osc: printf("packOSC: cell-cont: %d\n", args[i].datum.i); break; case FLOAT_osc: printf("packOSC: cell-cont: %f\n", args[i].datum.f); break; case STRING_osc: printf("packOSC: cell-cont: %s\n", args[i].datum.s); break; case BLOB_osc: printf("packOSC: blob\n"); break; case NOTYPE_osc: printf("packOSC: unknown type\n"); break; } printf("packOSC: type-id: %d\n", args[i].type); #endif } if(packOSC_writemessage(x, x->x_oscbuf, messageName, i, args)) { pd_error(x, "packOSC: usage error, packOSC_writemessage failed."); goto cleanup; } } if(!x->x_bundle) { packOSC_sendbuffer(x); } cleanup: if (typeStr != NULL) freebytes(typeStr, typeStrTotalSize); if (args != NULL) freebytes(args, argsSize); x->x_reentry_count--; } static void packOSC_send_type_forced(t_packOSC *x, t_symbol *s, int argc, t_atom *argv) { /* typetags are the argument following the OSC path */ x->x_typetags |= 2;/* tell packOSC_sendtyped to use the specified typetags... */ packOSC_sendtyped(x, s, argc, argv); x->x_typetags &= ~2;/* ...this time only */ } static void packOSC_send(t_packOSC *x, t_symbol *s, int argc, t_atom *argv) { if(!argc) { pd_error(x, "packOSC: not sending empty message."); return; } packOSC_sendtyped(x, s, argc, argv); } static void packOSC_anything(t_packOSC *x, t_symbol *s, int argc, t_atom *argv) { /* If the message starts with '/', assume it's an OSC path and send it */ t_atom*ap = 0; if ((*s->s_name)!='/') { pd_error(x, "packOSC: bad path: '%s'", s->s_name); return; } ap = (t_atom*)getbytes((argc+1)*sizeof(t_atom)); SETSYMBOL(ap, s); memcpy(ap+1, argv, argc * sizeof(t_atom)); packOSC_send(x, gensym("send"), argc+1, ap); freebytes(ap, (argc+1)*sizeof(t_atom)); } static void packOSC_free(t_packOSC *x) { if (x->x_bufferForOSCbuf != NULL) freebytes((void *)x->x_bufferForOSCbuf, sizeof(char)*x->x_buflength); if (x->x_bufferForOSClist != NULL) freebytes((void *)x->x_bufferForOSClist, sizeof(t_atom)*x->x_buflength); } void packOSC_setup(void) { packOSC_class = class_new(gensym("packOSC"), (t_newmethod)packOSC_new, (t_method)packOSC_free, sizeof(t_packOSC), 0, A_DEFFLOAT, 0); class_addmethod(packOSC_class, (t_method)packOSC_path, gensym("prefix"), A_DEFSYM, 0); class_addmethod(packOSC_class, (t_method)packOSC_settypetags, gensym("typetags"), A_DEFFLOAT, 0); class_addmethod(packOSC_class, (t_method)packOSC_setbufsize, gensym("bufsize"), A_DEFFLOAT, 0); class_addmethod(packOSC_class, (t_method)packOSC_setTimeTagOffset, gensym("timetagoffset"), A_DEFFLOAT, 0); class_addmethod(packOSC_class, (t_method)packOSC_send, gensym("send"), A_GIMME, 0); class_addmethod(packOSC_class, (t_method)packOSC_send, gensym("senduntyped"), A_GIMME, 0); class_addmethod(packOSC_class, (t_method)packOSC_send_type_forced, gensym("sendtyped"), A_GIMME, 0); class_addmethod(packOSC_class, (t_method)packOSC_openbundle, gensym("["), 0, 0); class_addmethod(packOSC_class, (t_method)packOSC_closebundle, gensym("]"), 0, 0); class_addanything(packOSC_class, (t_method)packOSC_anything); } static typedArg packOSC_parseatom(t_atom *a) { typedArg returnVal; t_float f; int i; t_symbol s; char buf[MAXPDSTRING]; atom_string(a, buf, MAXPDSTRING); #ifdef DEBUG printf("packOSC: atom type %d (%s)\n", a->a_type, buf); #endif /* It might be an int, a float, or a string */ switch (a->a_type) { case A_FLOAT: f = atom_getfloat(a); i = atom_getint(a); if (f == (t_float)i) { /* assume that if the int and float are the same, it's an int */ returnVal.type = INT_osc; returnVal.datum.i = i; } else { returnVal.type = FLOAT_osc; returnVal.datum.f = f; } return returnVal; case A_SYMBOL: s = *atom_getsymbol(a); returnVal.type = STRING_osc; returnVal.datum.s = s.s_name; return returnVal; default: atom_string(a, buf, MAXPDSTRING); error("packOSC: atom type %d not implemented (%s)", a->a_type, buf); returnVal.type = NOTYPE_osc; returnVal.datum.s = NULL; return returnVal; } } static typedArg packOSC_blob(t_atom *a) { /* ctype is one of i,f,s,T,F,N,I*/ typedArg returnVal; t_float f; int i; returnVal.type = NOTYPE_osc; returnVal.datum.s = NULL; /* the atoms must all be bytesl */ if(a->a_type != A_FLOAT) { error("packOSC_blob: all values must be floats"); return returnVal; } f = atom_getfloat(a); i = (int)f; if (i != f) { error("packOSC_blob: all values must be whole numbers"); return returnVal; } if ((i < -128) || (i > 255)) { error("packOSC_blob: all values must be bytes"); return returnVal; } returnVal.type = BLOB_osc; returnVal.datum.i = i; return returnVal; } static typedArg packOSC_packMIDI(t_atom *a) { /* pack four bytes at a into one int32 */ int i; typedArg returnVal; int m[4]; static char buf[MAXPDSTRING]; for (i = 0; i < 4; ++i, ++a) { #ifdef DEBUG atom_string(a, buf, MAXPDSTRING); printf("packOSC: atom type %d (%s)\n", a->a_type, buf); #endif if ((a->a_type != A_FLOAT)) { error("packOSC: MIDI parameters must be floats"); returnVal.type = NOTYPE_osc; returnVal.datum.s = NULL; return returnVal; } m[i] = atom_getint(a); #ifdef DEBUG printf("packOSC_packMIDI: float to integer %d\n", m[i]); #endif if ((i < 2) && (m[i] != (m[i] & 0x0FF))) { error("packOSC: MIDI parameters must be less than 256"); returnVal.type = NOTYPE_osc; returnVal.datum.s = NULL; return returnVal; } else if ((i > 1) && (m[i] != (m[i] & 0x07F))) { error("packOSC: MIDI parameters must be less than 128"); returnVal.type = NOTYPE_osc; returnVal.datum.s = NULL; return returnVal; } } returnVal.type = INT_osc; returnVal.datum.i = (m[0]<<24) + (m[1]<<16) + (m[2]<<8) + m[3]; return returnVal; } static typedArg packOSC_forceatom(t_atom *a, char ctype) { /* ctype is one of i,f,s,T,F,N,I*/ typedArg returnVal; t_float f; int i; t_symbol s; static char buf[MAXPDSTRING]; #ifdef DEBUG atom_string(a, buf, MAXPDSTRING); printf("packOSC: atom type %d (%s)\n", a->a_type, buf); #endif /* the atom might be a float, or a symbol */ switch (a->a_type) { case A_FLOAT: switch (ctype) { case 'i': returnVal.type = INT_osc; returnVal.datum.i = atom_getint(a); #ifdef DEBUG printf("packOSC_forceatom: float to integer %d\n", returnVal.datum.i); #endif break; case 'f': returnVal.type = FLOAT_osc; returnVal.datum.f = atom_getfloat(a); #ifdef DEBUG printf("packOSC_forceatom: float to float %f\n", returnVal.datum.f); #endif break; case 's': f = atom_getfloat(a); sprintf(buf, "%f", f); returnVal.type = STRING_osc; returnVal.datum.s = buf; #ifdef DEBUG printf("packOSC_forceatom: float to string %s\n", returnVal.datum.s); #endif break; default: post("packOSC: unknown OSC type %c", ctype); returnVal.type = NOTYPE_osc; returnVal.datum.s = NULL; break; } break; case A_SYMBOL: s = *atom_getsymbol(a); switch (ctype) { case 'i': i = atoi(s.s_name); returnVal.type = INT_osc; returnVal.datum.i = i; #ifdef DEBUG printf("packOSC_forceatom: symbol to integer %d\n", returnVal.datum.i); #endif break; case 'f': f = atof(s.s_name); returnVal.type = FLOAT_osc; returnVal.datum.f = f; #ifdef DEBUG printf("packOSC_forceatom: symbol to float %f\n", returnVal.datum.f); #endif break; case 's': returnVal.type = STRING_osc; returnVal.datum.s = s.s_name; #ifdef DEBUG printf("packOSC_forceatom: symbol to string %s\n", returnVal.datum.s); #endif break; default: post("packOSC: unknown OSC type %c", ctype); returnVal.type = NOTYPE_osc; returnVal.datum.s = NULL; break; } break; default: atom_string(a, buf, MAXPDSTRING); error("packOSC: atom type %d not implemented (%s)", a->a_type, buf); returnVal.type = NOTYPE_osc; returnVal.datum.s = NULL; break; } return returnVal; } static int packOSC_writetypedmessage (t_packOSC *x, OSCbuf *buf, char *messageName, int numArgs, typedArg *args, char *typeStr) { int i, j, returnVal; #ifdef DEBUG printf("packOSC_writetypedmessage: messageName %p (%s) typeStr %p (%s)\n", messageName, messageName, typeStr, typeStr); #endif returnVal = OSC_writeAddressAndTypes(buf, messageName, typeStr); if (returnVal) { error("packOSC: Problem writing address. (%d)", returnVal); return returnVal; } for (j = i = 0; (typeStr[i+1]!= 0) || (j < numArgs); j++, i++) { while (typeStr[i+1] == 'T' || typeStr[i+1] == 'F' || typeStr[i+1] == 'I' || typeStr[i+1] == 'N') { #ifdef DEBUG printf("packOSC_writetypedmessage: NULL [%c]\n", typeStr[i+1]); #endif returnVal = OSC_writeNullArg(buf, typeStr[i+1]); ++i; } if (j < numArgs) { switch (args[j].type) { case INT_osc: #ifdef DEBUG printf("packOSC_writetypedmessage: int [%d]\n", args[j].datum.i); #endif returnVal = OSC_writeIntArg(buf, args[j].datum.i); break; case FLOAT_osc: #ifdef DEBUG printf("packOSC_writetypedmessage: float [%f]\n", args[j].datum.f); #endif returnVal = OSC_writeFloatArg(buf, args[j].datum.f); break; case STRING_osc: #ifdef DEBUG printf("packOSC_writetypedmessage: string [%s]\n", args[j].datum.s); #endif returnVal = OSC_writeStringArg(buf, args[j].datum.s); break; case BLOB_osc: /* write all the blob elements at once */ #ifdef DEBUG printf("packOSC_writetypedmessage calling OSC_writeBlobArg\n"); #endif return OSC_writeBlobArg(buf, &args[j], numArgs-j); default: break; /* types with no data */ } } } return returnVal; } static int packOSC_writemessage(t_packOSC *x, OSCbuf *buf, char *messageName, int numArgs, typedArg *args) { int j, returnVal = 0, numTags; #ifdef DEBUG printf("packOSC_writemessage buf %p bufptr %p messageName %s %d args typetags %d\n", buf, buf->bufptr, messageName, numArgs, x->x_typetags); #endif if (!x->x_typetags) { #ifdef DEBUG printf("packOSC_writemessage calling OSC_writeAddress with x->x_typetags %d\n", x->x_typetags); #endif returnVal = OSC_writeAddress(buf, messageName); if (returnVal) { post("packOSC: Problem writing address."); } } else { char *typeTags; /* First figure out the type tags */ for (numTags = 0; numTags < numArgs; numTags++) { if (args[numTags].type == BLOB_osc) break; /* blob has one type tag and is the last element */ } typeTags=(char*)getbytes(sizeof(char)*(numTags+2)); /* number of args + ',' + '\0' */ typeTags[0] = ','; for (j = 0; j < numTags; ++j) { switch (args[j].type) { case INT_osc: typeTags[j+1] = 'i'; break; case FLOAT_osc: typeTags[j+1] = 'f'; break; case STRING_osc: typeTags[j+1] = 's'; break; case BLOB_osc: typeTags[j+1] = 'b'; break; default: error("packOSC: arg %d type is unrecognized(%d)", j, args[j].type); break; } } typeTags[j+1] = '\0'; #ifdef DEBUG printf("packOSC_writemessage calling OSC_writeAddressAndTypes with x->x_typetags %d typeTags %p (%s)\n", x->x_typetags, typeTags, typeTags); #endif returnVal = OSC_writeAddressAndTypes(buf, messageName, typeTags); if (returnVal) { error("packOSC: Problem writing address."); } freebytes(typeTags, sizeof(char)*(numTags+2)); } for (j = 0; j < numArgs; j++) { switch (args[j].type) { case INT_osc: returnVal = OSC_writeIntArg(buf, args[j].datum.i); break; case FLOAT_osc: returnVal = OSC_writeFloatArg(buf, args[j].datum.f); break; case STRING_osc: returnVal = OSC_writeStringArg(buf, args[j].datum.s); break; case BLOB_osc: #ifdef DEBUG printf("packOSC_writemessage calling OSC_writeBlobArg\n"); #endif return OSC_writeBlobArg(buf, &args[j], numArgs-j); /* All the remaining args are blob */ default: break; /* just skip bad types (which we won't get anyway unless this code is buggy) */ } } return returnVal; } static void packOSC_sendbuffer(t_packOSC *x) { int i; int length; unsigned char *buf; int reentry_count=x->x_reentry_count; /* must be on stack for recursion */ size_t bufsize=sizeof(t_atom)*x->x_buflength; /* must be on stack for recursion */ t_atom *atombuffer=x->x_bufferForOSClist; /* must be on stack in the case of recursion */ if(reentry_count>0) /* if we are recurse, let's move atombuffer to the stack */ atombuffer=(t_atom *)getbytes(bufsize); if(!atombuffer) { pd_error(x, "packOSC: unable to allocate %lu bytes for atombuffer", (long)bufsize); return; } #ifdef DEBUG printf("packOSC_sendbuffer: Sending buffer...\n"); #endif if (OSC_isBufferEmpty(x->x_oscbuf)) { post("packOSC_sendbuffer() called but buffer empty"); return; } if (!OSC_isBufferDone(x->x_oscbuf)) { post("packOSC_sendbuffer() called but buffer not ready!, not exiting"); return; } length = OSC_packetSize(x->x_oscbuf); buf = (unsigned char *)OSC_getPacket(x->x_oscbuf); #ifdef DEBUG printf("packOSC_sendbuffer: length: %u\n", length); #endif /* convert the bytes in the buffer to floats in a list */ for (i = 0; i < length; ++i) SETFLOAT(&atombuffer[i], buf[i]); /* cleanup the OSCbuffer structure (so we are ready for recursion) */ OSC_initBuffer(x->x_oscbuf, x->x_buflength, x->x_bufferForOSCbuf); /* send the list out the outlet */ outlet_list(x->x_listout, &s_list, length, atombuffer); /* cleanup our 'stack'-allocated atombuffer in the case of reentrancy */ if(reentry_count>0) freebytes(atombuffer, bufsize); } /* The next part is copied and morphed from OSC-client.c. */ /* Author: Matt Wright Version 2.2: Calls htonl in the right places 20000620 Version 2.3: Gets typed messages right. */ /* pd ------------- raf@interaccess.com: rev. for Win32 build (verified under Win-2ooo) 11-April-2002 -- changed licence part (20040820) jdl -- Version 2.4 changes not in here (20040820) jdl */ static void OSC_initBuffer(OSCbuf *buf, size_t size, char *byteArray) { buf->buffer = byteArray; buf->size = size; OSC_resetBuffer(buf); } static void OSC_resetBuffer(OSCbuf *buf) { buf->bufptr = buf->buffer; buf->state = EMPTY; buf->bundleDepth = 0; buf->prevCounts[0] = 0; buf->gettingFirstUntypedArg = 0; buf->typeStringPtr = 0; } static int OSC_isBufferEmpty(OSCbuf *buf) { return buf->bufptr == buf->buffer; } static size_t OSC_freeSpaceInBuffer(OSCbuf *buf) { return buf->size - (buf->bufptr - buf->buffer); } static int OSC_isBufferDone(OSCbuf *buf) { return (buf->state == DONE || buf->state == ONE_MSG_ARGS); } static char *OSC_getPacket(OSCbuf *buf) { return buf->buffer; } static int OSC_packetSize(OSCbuf *buf) { return (buf->bufptr - buf->buffer); } static int OSC_CheckOverflow(OSCbuf *buf, size_t bytesNeeded) { if ((bytesNeeded) > OSC_freeSpaceInBuffer(buf)) { error("packOSC: buffer overflow"); return 1; } return 0; } static void PatchMessageSize(OSCbuf *buf) { uint32_t size = buf->bufptr - ((char *) buf->thisMsgSize) - 4; *(buf->thisMsgSize) = htonl(size); } static int OSC_openBundle(OSCbuf *buf, OSCTimeTag tt) { if (buf->state == ONE_MSG_ARGS) { post("packOSC: Can't open a bundle in a one-message packet"); return 3; } if (buf->state == DONE) { post("packOSC: This packet is finished; can't open a new bundle"); return 4; } if (++(buf->bundleDepth) >= MAX_BUNDLE_NESTING) { post("packOSC: Bundles nested too deeply: maybe change MAX_BUNDLE_NESTING from %d and recompile", MAX_BUNDLE_NESTING); return 2; } if (CheckTypeTag(buf, '\0')) return 9; if (buf->state == GET_ARGS) { PatchMessageSize(buf); } if (buf->state == EMPTY) { /* Need 16 bytes for "#bundle" and time tag */ if(OSC_CheckOverflow(buf, 16)) return 1; } else { /* This bundle is inside another bundle, so we need to leave a blank size count for the size of this current bundle. */ if(OSC_CheckOverflow(buf, 20))return 1; *((uint32_t *)buf->bufptr) = 0xaaaaaaaa; buf->prevCounts[buf->bundleDepth] = (uint32_t *)buf->bufptr; buf->bufptr += 4; } buf->bufptr += OSC_padString(buf->bufptr, "#bundle"); *((OSCTimeTag *) buf->bufptr) = tt; if (htonl(1) != 1) { /* Byte swap the 8-byte integer time tag */ uint32_t *intp = (uint32_t *)buf->bufptr; intp[0] = htonl(intp[0]); intp[1] = htonl(intp[1]); /* tt is a struct of two 32-bit words, and even though each word was wrong-endian, they were in the right order in the struct.) */ } buf->bufptr += sizeof(OSCTimeTag); buf->state = NEED_COUNT; buf->gettingFirstUntypedArg = 0; buf->typeStringPtr = 0; return 0; } static int OSC_closeBundle(OSCbuf *buf) { if (buf->bundleDepth == 0) { /* This handles EMPTY, ONE_MSG, ARGS, and DONE */ post("packOSC: Can't close bundle: no bundle is open!"); return 5; } if (CheckTypeTag(buf, '\0')) return 9; if (buf->state == GET_ARGS) { PatchMessageSize(buf); } if (buf->bundleDepth == 1) { /* Closing the last bundle: No bundle size to patch */ buf->state = DONE; } else { /* Closing a sub-bundle: patch bundle size */ int size = buf->bufptr - ((char *) buf->prevCounts[buf->bundleDepth]) - 4; *(buf->prevCounts[buf->bundleDepth]) = htonl(size); buf->state = NEED_COUNT; } --buf->bundleDepth; buf->gettingFirstUntypedArg = 0; buf->typeStringPtr = 0; return 0; } static int OSC_writeAddress(OSCbuf *buf, char *name) { uint32_t paddedLength; #ifdef DEBUG printf("-->OSC_writeAddress buf %p bufptr %p name %s\n", buf, buf->bufptr, name); #endif if (buf->state == ONE_MSG_ARGS) { post("packOSC: This packet is not a bundle, so you can't write another address"); return 7; } if (buf->state == DONE) { post("packOSC: This packet is finished; can't write another address"); return 8; } if (CheckTypeTag(buf, '\0')) return 9; paddedLength = OSC_effectiveStringLength(name); #ifdef DEBUG printf("OSC_writeAddress paddedLength %d\n", paddedLength); #endif if (buf->state == EMPTY) { /* This will be a one-message packet, so no sizes to worry about */ if(OSC_CheckOverflow(buf, paddedLength))return 1; buf->state = ONE_MSG_ARGS; } else { /* GET_ARGS or NEED_COUNT */ if(OSC_CheckOverflow(buf, 4+paddedLength))return 1; if (buf->state == GET_ARGS) { /* Close the old message */ PatchMessageSize(buf); } buf->thisMsgSize = (uint32_t *)buf->bufptr; *(buf->thisMsgSize) = 0xbbbbbbbb; buf->bufptr += 4; buf->state = GET_ARGS; } /* Now write the name */ buf->bufptr += OSC_padString(buf->bufptr, name); buf->typeStringPtr = 0; buf->gettingFirstUntypedArg = 1; return 0; } static int OSC_writeAddressAndTypes(OSCbuf *buf, char *name, char *types) { int result; uint32_t paddedLength; #ifdef DEBUG printf("OSC_writeAddressAndTypes buf %p name %s types %s\n", buf, name, types); #endif if (buf == NULL) return 10; if (CheckTypeTag(buf, '\0')) return 9; result = OSC_writeAddress(buf, name); if (result) return result; paddedLength = OSC_effectiveStringLength(types); if(OSC_CheckOverflow(buf, paddedLength))return 1; buf->typeStringPtr = buf->bufptr + 1; /* skip comma */ buf->bufptr += OSC_padString(buf->bufptr, types); #ifdef DEBUG printf("OSC_writeAddressAndTypes buf->typeStringPtr now %p (%s) buf->bufptr now %p (%s)\n", buf->typeStringPtr, buf->typeStringPtr, buf->bufptr, buf->bufptr); #endif buf->gettingFirstUntypedArg = 0; buf->typeStringPtr = 0;// ready for a new type string return 0; } static int CheckTypeTag(OSCbuf *buf, char expectedType) { char c; if (buf->typeStringPtr) { #ifdef DEBUG printf("CheckTypeTag buf->typeStringPtr %p (%s)\n", buf->typeStringPtr, buf->typeStringPtr); #endif c = *(buf->typeStringPtr); #ifdef DEBUG printf("CheckTypeTag buf %p expectedType %c c is %c\n", buf, expectedType, c); #endif if (c != expectedType) { if (expectedType == '\0') { post("packOSC: According to the type tag (%c) I expected more arguments.", c); } else if (*(buf->typeStringPtr) == '\0') { post("packOSC: According to the type tag I didn't expect any more arguments."); } else { post("packOSC: According to the type tag I expected an argument of a different type."); post("* Expected %c, string now %s\n", expectedType, buf->typeStringPtr); } return 9; } ++(buf->typeStringPtr); } return 0; } static int OSC_writeFloatArg(OSCbuf *buf, float arg) { union intfloat32 { int i; float f; }; union intfloat32 if32; if(OSC_CheckOverflow(buf, 4))return 1; if (CheckTypeTag(buf, 'f')) return 9; /* Pretend arg is a long int so we can use htonl() */ if32.f = arg; *((uint32_t *) buf->bufptr) = htonl(if32.i); buf->bufptr += 4; buf->gettingFirstUntypedArg = 0; return 0; } static int OSC_writeIntArg(OSCbuf *buf, uint32_t arg) { if(OSC_CheckOverflow(buf, 4))return 1; if (CheckTypeTag(buf, 'i')) return 9; *((uint32_t *) buf->bufptr) = htonl(arg); buf->bufptr += 4; buf->gettingFirstUntypedArg = 0; return 0; } static int OSC_writeBlobArg(OSCbuf *buf, typedArg *arg, size_t nArgs) { size_t i; unsigned char b; /* pack all the args as single bytes following a 4-byte length */ if(OSC_CheckOverflow(buf, nArgs+4))return 1; if (CheckTypeTag(buf, 'b')) return 9; *((uint32_t *) buf->bufptr) = htonl(nArgs); #ifdef DEBUG printf("OSC_writeBlobArg length : %lu\n", nArgs); #endif buf->bufptr += 4; for (i = 0; i < nArgs; i++) { if (arg[i].type != BLOB_osc) { error("packOSC: blob element %lu not blob type", i); return 9; } b = (unsigned char)((arg[i].datum.i)&0x0FF);/* force int to 8-bit byte */ #ifdef DEBUG printf("OSC_writeBlobArg : %d, %d\n", arg[i].datum.i, b); #endif buf->bufptr[i] = b; } i = OSC_WriteBlobPadding(buf->bufptr, i); buf->bufptr += i; buf->gettingFirstUntypedArg = 0; return 0; } static int OSC_writeStringArg(OSCbuf *buf, char *arg) { int len; if (CheckTypeTag(buf, 's')) return 9; len = OSC_effectiveStringLength(arg); if (buf->gettingFirstUntypedArg && arg[0] == ',') { /* This un-type-tagged message starts with a string that starts with a comma, so we have to escape it (with a double comma) so it won't look like a type tag string. */ if(OSC_CheckOverflow(buf, len+4))return 1; /* Too conservative */ buf->bufptr += OSC_padStringWithAnExtraStupidComma(buf->bufptr, arg); } else { if(OSC_CheckOverflow(buf, len))return 1; buf->bufptr += OSC_padString(buf->bufptr, arg); } buf->gettingFirstUntypedArg = 0; return 0; } static int OSC_writeNullArg(OSCbuf *buf, char type) { /* Don't write any data, just check the type tag */ if(OSC_CheckOverflow(buf, 4))return 1; if (CheckTypeTag(buf, type)) return 9; buf->gettingFirstUntypedArg = 0; return 0; } /* String utilities */ static int OSC_strlen(char *s) { int i; for (i = 0; s[i] != '\0'; i++) /* Do nothing */ ; return i; } #define STRING_ALIGN_PAD 4 static int OSC_effectiveStringLength(char *string) { int len = OSC_strlen(string) + 1; /* We need space for the null char. */ /* Round up len to next multiple of STRING_ALIGN_PAD to account for alignment padding */ if ((len % STRING_ALIGN_PAD) != 0) { len += STRING_ALIGN_PAD - (len % STRING_ALIGN_PAD); } return len; } static int OSC_padString(char *dest, char *str) { int i; for (i = 0; str[i] != '\0'; i++) dest[i] = str[i]; return OSC_WriteStringPadding(dest, i); } static int OSC_padStringWithAnExtraStupidComma(char *dest, char *str) { int i; dest[0] = ','; for (i = 0; str[i] != '\0'; i++) dest[i+1] = str[i]; return OSC_WriteStringPadding(dest, i+1); } static int OSC_WriteStringPadding(char *dest, int i) { /* pad with at least one zero to fit 4-byte */ dest[i] = '\0'; i++; for (; (i % STRING_ALIGN_PAD) != 0; i++) dest[i] = '\0'; return i; } static int OSC_WriteBlobPadding(char *dest, int i) { /* pad if necessary to fit 4-byte */ for (; (i % STRING_ALIGN_PAD) != 0; i++) dest[i] = '\0'; return i; } /* The next bit is modified from OSC-timetag.c. */ /* OSC_timeTag.c: library for manipulating OSC time tags Matt Wright, 5/29/97 Version 0.2 (9/11/98): cleaned up so no explicit type names in the .c file. */ static OSCTimeTag OSCTT_Immediately(void) { OSCTimeTag tt; tt.fraction = 1; tt.seconds = 0; return tt; } static OSCTimeTag OSCTT_Infinite(void) { OSCTimeTag tt; tt.fraction = 0xffffffffL; tt.seconds = 0xffffffffL; return tt; } #define SECONDS_FROM_1900_to_1970 2208988800LL /* 17 leap years */ #define TWO_TO_THE_32_OVER_ONE_MILLION 4295LL static OSCTimeTag OSCTT_CurrentTimePlusOffset(uint32_t offset) { /* offset is in microseconds */ OSCTimeTag tt; static unsigned int onemillion = 1000000; #ifdef _WIN32 static unsigned int onethousand = 1000; struct _timeb tb; _ftime(&tb); /* First get the seconds right */ tt.seconds = (unsigned)SECONDS_FROM_1900_to_1970 + (unsigned)tb.time+ (unsigned)offset/onemillion; /* Now get the fractional part. */ tt.fraction = (unsigned)tb.millitm*onethousand + (unsigned)(offset%onemillion); /* in usec */ #else struct timeval tv; struct timezone tz; gettimeofday(&tv, &tz); /* First get the seconds right */ tt.seconds = (unsigned) SECONDS_FROM_1900_to_1970 + (unsigned) tv.tv_sec + (unsigned) offset/onemillion; /* Now get the fractional part. */ tt.fraction = (unsigned) tv.tv_usec + (unsigned)(offset%onemillion); /* in usec */ #endif if (tt.fraction > onemillion) { tt.fraction -= onemillion; tt.seconds++; } tt.fraction *= (unsigned) TWO_TO_THE_32_OVER_ONE_MILLION; /* convert usec to 32-bit fraction of 1 sec */ return tt; } /* end packOSC.c*/ mrpeach/osc/README.txt0000644000175000017500000000232311616510724015214 0ustar zmoelnigzmoelnigOpenSoundControl (OSC) for Pd ============================= a collection of Pd objectclasses for OSC-messages. these objects only convert between Pd-messages and OSC-messages (binary format), so you will need a separate set of objects that implement the transport (OSI-Layer 4), for instance [udpsend]/[udpreceive] for sending OSC over UDP. Author: Martin Peach objectclasses - [packOSC] convert a Pd-message to an OSC (binary) message (useful if you want to transmit OSC over UDP or other protocols that have the concept of variable length packets) - [unpackOSC] convert an OSC (binary) message to a Pd-message (useful if you want to transmit OSC over UDP or other protocols that have the concept of variable length packets) - [routeOSC] route OSC-like Pd-messages according to the first element in the path - [pipelist] delay lists (useful if you want to respect timestamps) - [packOSCstream] convert a Pd-message to an OSC (binary) message suitable for streaming transport (useful if you want to transmit OSC over TCP/IP or a serial line) - [unpackOSCstream] convert an OSC (binary) message suitable for streaming transport to a Pd-message (useful if you want to transmit OSC over TCP/IP or a serial line) mrpeach/mrpeach-meta.pd0000644000175000017500000000026012571126663015626 0ustar zmoelnigzmoelnig#N canvas 15 49 200 200 10; #N canvas 25 49 420 300 META 1; #X text 13 41 NAME mrpeach; #X text 10 25 AUTHOR Martin Peach; #X text 10 10 VERSION 0.1; #X restore 10 10 pd META; mrpeach/rcosc~/0000755000175000017500000000000013605444732014246 5ustar zmoelnigzmoelnigmrpeach/rcosc~/rcosc~.c0000644000175000017500000000733011361701054015712 0ustar zmoelnigzmoelnig/* rcosc~.c by Martin Peach 20100331 */ /* Pd external emulating a resistor-capacitor-controlled oscillator */ /* The first control parameter is a time constant in seconds (or resistance X capacitance) */ /* The second control parameter is a threshold above which the cap is set to discharge */ /* The third control parameter is a threshold below which the cap is set to charge */ #include "m_pd.h" static t_class *rcosc_tilde_class; typedef struct _rcosc_tilde { t_object rc_obj; t_float rc_f; t_float rc_upper_threshold; /* if rc_dir is 1, charge to here */ t_float rc_lower_threshold; /* if rc_dir is 0, discharge to here */ t_int rc_dir; double rc_node; double rc_one; double rc_zero; double rc_sp; double rc_slewmax; } t_rcosc_tilde; static t_int *rcosc_tilde_perform(t_int *w); static void rcosc_tilde_dsp(t_rcosc_tilde *x, t_signal **sp); static void *rcosc_tilde_new(t_floatarg f); static t_int *rcosc_tilde_perform(t_int *w) { t_rcosc_tilde *x = (t_rcosc_tilde *)(w[1]); t_sample *in = (t_sample *)(w[2]); t_sample *out = (t_sample *)(w[3]); int n = (int)(w[4]); double slewrate, delta, node, overshoot; int i, n_oversamples = 64; // if (x->rc_rc < x->rc_sp) slewrate = 1.0; // else slewrate = x->rc_sp/x->rc_rc; while (n--) { slewrate = x->rc_one/(n_oversamples*(x->rc_sp*(*in++))); if (slewrate < x->rc_zero) slewrate = x->rc_zero; else if (slewrate > x->rc_one) slewrate = x->rc_one; node = x->rc_node; for (i = 0; i < n_oversamples; ++i) { if (x->rc_dir) { delta = slewrate*(x->rc_one - x->rc_node); if (delta > x->rc_slewmax) delta = x->rc_slewmax; x->rc_node += delta; overshoot = x->rc_node - x->rc_upper_threshold; if (overshoot > 0) { x->rc_dir = 0; x->rc_node = x->rc_upper_threshold - overshoot; /* bounce */ } } else { delta = slewrate*(x->rc_zero - x->rc_node); if (delta < -x->rc_slewmax) delta = -x->rc_slewmax; x->rc_node += delta; overshoot = x->rc_lower_threshold - x->rc_node; if (overshoot > 0) { x->rc_dir = 1; x->rc_node = x->rc_lower_threshold + overshoot; /* bounce */ } } } *out++ = ((node + x->rc_node)*3)-3; } return (w+5); } static void rcosc_tilde_dsp(t_rcosc_tilde *x, t_signal **sp) { x->rc_sp = sys_getsr(); dsp_add(rcosc_tilde_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n); } static void *rcosc_tilde_new(t_floatarg f) { t_rcosc_tilde *x = (t_rcosc_tilde *)pd_new(rcosc_tilde_class); x->rc_f = f; x->rc_node = 0.0; x->rc_upper_threshold = 0.666; /* if rc_dir is 1, charge to here */ x->rc_lower_threshold = 0.333; /* if rc_dir is 0, discharge to here */ x->rc_slewmax = 0.003;/* arbitrary slew rate limit */ x->rc_dir = 1; /* start charging */ x->rc_one = 1; x->rc_zero = 0; outlet_new(&x->rc_obj, &s_signal); post("rcosc~ 20100331 Martin Peach"); return (void *)x; } void rcosc_tilde_setup(void) { rcosc_tilde_class = class_new(gensym("rcosc~"), (t_newmethod)rcosc_tilde_new, 0, sizeof(t_rcosc_tilde), CLASS_DEFAULT, A_DEFFLOAT, 0); class_addmethod(rcosc_tilde_class, (t_method)rcosc_tilde_dsp, gensym("dsp"), 0); CLASS_MAINSIGNALIN(rcosc_tilde_class, t_rcosc_tilde, rc_f); } /* fin rcosc~.c */ mrpeach/rcosc~/rcosc~-help.pd0000644000175000017500000000320511533764212017024 0ustar zmoelnigzmoelnig#N canvas 2 53 450 439 10; #X obj 52 277 *~; #X text 181 301 Author: Martin Peach; #X obj 53 316 dac~; #X obj 67 228 nbx 5 14 0 1000 0 1 empty empty level 60 8 0 10 -4034 -13381 -13381 8 256; #X obj 67 253 / 1000; #X obj 168 244 tabwrite~ \$0-rcoschelp; #X obj 168 267 table \$0-rcoschelp; #X obj 168 213 metro 100; #X obj 168 194 tgl 15 0 empty empty graph 17 7 0 10 -4034 -13381 -1 0 1; #X obj 52 169 rcosc~ 0.001; #X floatatom 52 28 5 0 0 0 - - -; #X obj 52 135 / 1; #X obj 52 70 t b f; #X msg 52 103 0.722057; #X text 155 68 7.22057e+07; #X text 223 68 70756; #X text 147 68 0; #X obj 52 5 r note_a; #X obj 52 49 mtof; #X floatatom 92 66 5 0 0 0 - - -; #X text 49 -57 rcosc~ emulates an oscillator implemented with a capacitor charging through a resistor. The creation argument can be overriden by the inlet \, and represents a charging time constant in seconds. ; #X text 180 320 2010/04/15; #N canvas 455 293 494 344 META 0; #X text 12 135 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; #X text 12 25 LICENSE GPL v2 or later; #X text 12 115 AUTHOR Martin Peach; #X text 12 46 DESCRIPTION emulates an oscillator implemented with a capacitor charging through a resistor; #X text 12 5 KEYWORDS signal; #X text 12 75 INLET_0 float; #X text 12 95 OUTLET_0 signal; #X restore 392 355 pd META; #X connect 0 0 2 0; #X connect 0 0 2 1; #X connect 3 0 4 0; #X connect 4 0 0 1; #X connect 7 0 5 0; #X connect 8 0 7 0; #X connect 9 0 5 0; #X connect 9 0 0 0; #X connect 10 0 18 0; #X connect 11 0 9 0; #X connect 12 0 13 0; #X connect 12 1 11 1; #X connect 13 0 11 0; #X connect 17 0 10 0; #X connect 18 0 12 0; #X connect 18 0 19 0; mrpeach/LICENSE.txt0000644000175000017500000000132512571126663014564 0ustar zmoelnigzmoelnig mrpeach - a bag of tricks Copyright (C) 2006-2015 Martin Peach This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . mrpeach/which/0000755000175000017500000000000013605444730014037 5ustar zmoelnigzmoelnigmrpeach/which/which.c0000644000175000017500000001312112760060035015274 0ustar zmoelnigzmoelnig/* which: an external for pure data */ /* Will output the path to the object named as its first argument */ /* Martin Peach 20090225 */ #include "m_pd.h" #include #include #include /* for strncpy strncat */ #ifdef _WIN32 #include #include #include #include #include #define close _close #else #include #endif static t_class *which_class; typedef struct _which { t_object x_obj; t_symbol *x_object_name; t_symbol *x_object_path; t_canvas *x_canvas; } t_which; /* We took this (sys_dllextent) from s_loader.c since it's not global */ /* Naming convention for externs. The names are kept distinct for those who wich to make "fat" externs compiled for many platforms. Less specific fallbacks are provided, primarily for back-compatibility; these suffice if you are building a package which will run with a single set of compiled objects. The specific name is the letter b, l, d, or m for BSD, linux, darwin, or microsoft, followed by a more specific string, either "fat" for a fat binary or an indication of the instruction set. */ #ifdef __FreeBSD__ static char sys_dllextent[] = ".b_i386", sys_dllextent2[] = ".pd_freebsd"; #endif #ifdef __linux__ #ifdef __x86_64__ static char sys_dllextent[] = ".l_ia64", sys_dllextent2[] = ".pd_linux"; #else static char sys_dllextent[] = ".l_i386", sys_dllextent2[] = ".pd_linux"; #endif #endif #ifdef __APPLE__ #ifndef MACOSX3 static char sys_dllextent[] = ".d_fat", sys_dllextent2[] = ".pd_darwin"; #else static char sys_dllextent[] = ".d_ppc", sys_dllextent2[] = ".pd_darwin"; #endif #endif #ifdef _WIN32 static char sys_dllextent[] = ".m_i386", sys_dllextent2[] = ".dll"; #endif static void which_any(t_which *x, t_symbol *s, int argc, t_atom *argv); static void which_bang(t_which *x); static void which_symbol(t_which *x, t_symbol *s); static void which_set(t_which *x, t_symbol *s); static void *which_new(t_symbol *s, int argc, t_atom *argv); void which_setup(void); static void which_set(t_which *x, t_symbol *s) { x->x_object_name = s; } static void which_symbol(t_which *x, t_symbol *s) { x->x_object_name = s; } static void which_any(t_which *x, t_symbol *s, int argc, t_atom *argv) { x->x_object_name = s; which_bang(x); } static void which_bang(t_which *x) { int fd = -1; char *nameptr = 0; char filename[MAXPDSTRING]; char dirbuf[MAXPDSTRING]; /* EXTERN int canvas_open(t_canvas *x, const char *name, const char *ext, char *dirresult, char **nameresult, unsigned int size, int bin); */ /* canvas_open is a utility function to read a file, looking first down the canvas's search path (set with "declare" objects in the patch and recursively in calling patches), then down the system one. The filename is the concatenation of "name" and "ext". "Name" may be absolute, or may be relative with slashes. If anything can be opened, the true directory is put in the buffer dirresult (provided by caller), which should be "size" bytes. The "nameresult" pointer will be set somewhere in the interior of "dirresult" and will give the file basename (with slashes trimmed). If "bin" is set a 'binary' open is attempted, otherwise ASCII (this only matters on Microsoft.) If "x" is zero, the file is sought in the directory "." or in the global path. */ /* try looking in the path for (objectname).(sys_dllextent) ... */ x->x_canvas = canvas_getcurrent(); //post("which_bang: canvas is %p", x->x_canvas); //post("which_bang: name is %s", x->x_object_name->s_name); //post("which_bang: ext is %s", sys_dllextent); //post("which_bang: ext2 is %s", sys_dllextent2); fd = canvas_open(x->x_canvas, x->x_object_name->s_name, sys_dllextent, dirbuf, &nameptr, MAXPDSTRING, 1); //post("which_bang 1: fd is %d", fd); // if (fd >= 0) post("1"); if (fd < 0) {/* same, with the more generic sys_dllextent2 */ fd = canvas_open(x->x_canvas, x->x_object_name->s_name, sys_dllextent2, dirbuf, &nameptr, MAXPDSTRING, 1); //post("which_bang 2: fd is %d", fd); // if (fd >= 0) post("2"); } if (fd < 0) { //post("which_bang: not found"); outlet_symbol(x->x_obj.te_outlet, gensym("not found")); return; } close(fd); //post("which_bang: dirbuf: %s", dirbuf); //post("which_bang: nameptr: %s", nameptr); /* rebuild the absolute pathname */ strncpy(filename, dirbuf, MAXPDSTRING); filename[MAXPDSTRING-2] = 0; strcat(filename, "/"); strncat(filename, nameptr, MAXPDSTRING-strlen(filename)); filename[MAXPDSTRING-1] = 0; //post("which_bang: filename: %s", filename); x->x_object_path = gensym(filename); outlet_symbol(x->x_obj.te_outlet, x->x_object_path); } static void *which_new(t_symbol *s, int argc, t_atom *argv) { t_which *x = (t_which *)pd_new(which_class); x->x_object_name = s; if ((argc >= 1)&&(argv[0].a_type == A_SYMBOL)) x->x_object_name = argv[0].a_w.w_symbol; outlet_new(&x->x_obj, &s_anything); /// x->x_canvas = canvas_getcurrent();/* canvas_getcurrent only seems to work in the _new function: why? */ /// post("which_new: canvas is %p", x->x_canvas); return (x); } void which_setup(void) { which_class = class_new(gensym("which"), (t_newmethod)which_new, 0, sizeof(t_which), 0, A_GIMME, 0); class_addbang(which_class, (t_method)which_bang); class_addsymbol(which_class, (t_method)which_symbol); class_addanything(which_class, (t_method)which_any); class_addmethod(which_class, (t_method)which_set, gensym("set"), A_DEFSYM, 0); } /* end which.c */ mrpeach/which/which-help.pd0000644000175000017500000000214612760060035016410 0ustar zmoelnigzmoelnig#N canvas 354 468 693 285 10; #X obj 129 170 which tcpclient; #X obj 9 35 bng 15 250 50 0 empty empty output_path_to_object 17 7 0 10 -4034 -257985 -1; #X text 9 7 [which] outputs the path to an object; #X obj 57 56 bng 15 250 50 0 empty empty set_object_name 17 7 0 10 -4034 -257985 -1; #X msg 78 102 set tabdump; #X symbolatom 129 193 64 0 0 0 - - -, f 64; #X obj 57 81 symbol Gem; #X msg 120 144 expr; #X msg 99 123 counter; #X text 165 101 set object name; #X text 155 122 set object name and output path; #X text 245 169 argument is object name; #N canvas 334 661 494 344 META 0; #X text 12 125 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; #X text 12 25 LICENSE GPL v2 or later; #X text 12 105 AUTHOR Martin Peach; #X text 12 5 KEYWORDS control; #X text 12 46 DESCRIPTION output the path to an object; #X text 12 65 INLET_0 anything set; #X text 12 85 OUTLET_0 symbol; #X restore 515 236 pd META; #X text 130 222 2016/08/26 Martin Peach; #X connect 0 0 5 0; #X connect 1 0 0 0; #X connect 3 0 6 0; #X connect 4 0 0 0; #X connect 6 0 0 0; #X connect 7 0 0 0; #X connect 8 0 0 0; mrpeach/runningmean/0000755000175000017500000000000013605444731015257 5ustar zmoelnigzmoelnigmrpeach/runningmean/runningmean.c0000644000175000017500000001016112430233607017734 0ustar zmoelnigzmoelnig/* runningmean.c MP 20080516 */ /* output the running mean of the input */ #include "m_pd.h" /* We implement a circular buffer x_data of length x_n */ /* With each incoming value we sum the x_n values, then divide by */ /* x_n to get the mean value, x_mean. */ #define RUNNINGMEAN_MAX 128 /* a default value when no valid argument is supplied */ typedef struct _runningmean { t_object x_obj; int x_in1; int x_in2; int x_in3; t_outlet *x_out; t_inlet *x_inlet2; int x_n; int x_originalsize; t_float *x_data; t_float x_mean; int x_pointer; } t_runningmean; static t_class *runningmean_class; void runningmean_setup(void); static void *runningmean_new(t_floatarg f); static void runningmean_free(t_runningmean *x); static void runningmean_bang(t_runningmean *x); static void runningmean_float(t_runningmean *x, t_float f); static void runningmean_length(t_runningmean *x, t_float f); static void runningmean_zero(t_runningmean *x, t_float f); static void runningmean_float(t_runningmean *x, t_float f) { float *p = x->x_data; float total = 0; int i; if (x->x_n > 0) { /* add a float at the current location, overwriting the oldest data */ x->x_data[x->x_pointer] = f; if (++x->x_pointer >= x->x_n) x->x_pointer = 0; /* wrap pointer */ for (i = 0; i < x->x_n; ++i) total += *p++; x->x_mean = total/x->x_n; outlet_float(x->x_out, x->x_mean); } return; } static void runningmean_bang(t_runningmean *x) { outlet_float(x->x_out, x->x_mean); return; } static void runningmean_length(t_runningmean *x, t_float f) { if ((f >= 1) && ((int)f == f) && (f <= x->x_originalsize)) { x->x_n = (int)f; runningmean_zero(x, x->x_mean); // set the entire new array to the old mean } else post("runningmean length must be an integer between 1 and %d.", x->x_originalsize); return; } static void runningmean_zero(t_runningmean *x, t_float f) { float *p = x->x_data; int i; /* set the entire array to f */ for (i = 0; i < x->x_n; ++i) *p++ = f; x->x_mean = f; x->x_pointer = 0; return; } static void runningmean_free(t_runningmean *x) { freebytes(x->x_data, x->x_originalsize); x->x_originalsize = x->x_n = 0; x->x_data = NULL; return; } static void *runningmean_new(t_floatarg f) { t_runningmean *x; x = (t_runningmean *)pd_new(runningmean_class); if (x == NULL) return (x); x->x_out = outlet_new((t_object *)x, &s_float); x->x_inlet2 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("length")); if (!((f >= 1) && ((int)f == f))) { post("runningmean length %0.2f must be an integer greater than 1, using %d", f, RUNNINGMEAN_MAX); f = RUNNINGMEAN_MAX; } { x->x_n = (int)f; x->x_data = (t_float *)getbytes(sizeof(float)*x->x_n); if (x->x_data == NULL) { post("runningmean unable to allocate %lu bytes of memory, using %d", sizeof(float)*x->x_n, RUNNINGMEAN_MAX); x->x_n = RUNNINGMEAN_MAX; //x->x_data = (t_float *)getbytes(x->x_n); if (x->x_data == NULL) { post("runningmean unable to allocate %lu bytes of memory, using 0", x->x_n); x->x_n = 0; } } x->x_originalsize = x->x_n; runningmean_zero(x, 0); } return (x); } void runningmean_setup(void) { runningmean_class = class_new ( gensym("runningmean"), (t_newmethod)runningmean_new, (t_method)runningmean_free, sizeof(t_runningmean), CLASS_DEFAULT, A_DEFFLOAT, 0 ); /* one argument for length */ class_addbang(runningmean_class, runningmean_bang); class_addfloat(runningmean_class, runningmean_float); class_addmethod(runningmean_class, (t_method)runningmean_length, gensym("length"), A_FLOAT, 0); class_addmethod(runningmean_class, (t_method)runningmean_zero, gensym("clear"), A_DEFFLOAT, 0); } /* end runningmean.c */ mrpeach/runningmean/runningmean-help.pd0000644000175000017500000000317512155715447021065 0ustar zmoelnigzmoelnig#N canvas 216 528 808 369 10; #X obj 191 231 runningmean 128; #X msg 121 144 clear; #X msg 165 189 length 10; #X msg 278 209 22; #X floatatom 191 262 5 0 0 0 - - -; #X obj 11 36 bng 15 250 50 0 empty empty empty 17 7 0 10 -257985 -1 -1; #X text 29 35 bang outputs current mean; #X msg 76 99 1; #X msg 98 121 2; #X text 155 261 mean:; #X text 63 69 Incoming floats are added to the array. The mean is recalculated for each incoming float; #X text 287 231 Argument sets initial length. Default (no argument) is 128; #X text 10 4 [runningmean] outputs the running mean of the last n floats to arrive on the left inlet.; #X text 249 251 Length can be changed to any positive value less than or equal to the length set by the creation argumwent; #X text 505 289 Martin Peach 2009/04/10; #N canvas 701 617 494 344 META 0; #X text 12 155 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; #X text 12 25 LICENSE GPL v2 or later; #X text 12 135 AUTHOR Martin Peach; #X text 12 5 KEYWORDS control analysis; #X text 12 46 DESCRIPTION output the running mean of the last n floats to arrive on the left inlet; #X text 12 75 INLET_0 float bang clear length; #X text 12 95 INLET_1 float; #X text 12 115 OUTLET_0 float; #X restore 621 319 pd META; #X msg 145 168 clear 10; #X text 231 189 set length (and sets the new array to the current mean) ; #X text 304 208 another way to set length; #X text 203 167 set the array to all 10s; #X text 159 144 clear the array to all zeroes; #X connect 0 0 4 0; #X connect 1 0 0 0; #X connect 2 0 0 0; #X connect 3 0 0 1; #X connect 5 0 0 0; #X connect 7 0 0 0; #X connect 8 0 0 0; #X connect 16 0 0 0; mrpeach/cmos/0000755000175000017500000000000013605444730013676 5ustar zmoelnigzmoelnigmrpeach/cmos/cd4075-help.pd0000644000175000017500000000105311026462102016042 0ustar zmoelnigzmoelnig#N canvas 670 174 478 232 12; #X obj 86 82 tgl 15 0 empty empty empty 17 7 0 10 -24198 -258699 -1 1 1; #X obj 147 82 tgl 15 0 empty empty empty 17 7 0 10 -24198 -258699 -1 1 1; #X obj 86 137 tgl 15 0 empty empty empty 17 7 0 10 -258699 -241291 -1 1 1; #X obj 209 82 tgl 15 0 empty empty empty 17 7 0 10 -24198 -258699 -1 1 1; #X text 210 170 20070312_Martin_Peach; #X text 18 47 cd4075 emulates 1/3 of the CMOS triple OR gate; #X obj 86 106 cd4075 triple or; #X connect 0 0 6 0; #X connect 1 0 6 1; #X connect 3 0 6 2; #X connect 6 0 2 0; mrpeach/cmos/cd4516-help.pd0000644000175000017500000000553611026462102016054 0ustar zmoelnigzmoelnig#N canvas 406 127 747 414 12; #X obj 75 -57 tgl 15 1 empty empty clock 17 7 0 10 -44926 -258699 -1 0 1; #X obj 96 -37 tgl 15 1 empty empty up_down 17 7 0 10 -44926 -258699 -1 1 1; #X obj 117 -88 tgl 15 1 empty empty reset 17 7 0 10 -44926 -258699 -1 0 1; #X obj 139 -111 tgl 15 1 empty empty preset_enable 17 7 0 10 -44926 -258699 -1 0 1; #X obj 177 -24 tgl 15 0 empty empty P1 17 7 0 10 -260818 -258699 -1 1 1; #X obj 211 -24 tgl 15 0 empty empty P2 17 7 0 10 -260818 -258699 -1 0 1; #X obj 243 -24 tgl 15 0 empty empty P3 17 7 0 10 -260818 -258699 -1 1 1; #X obj 283 -24 tgl 15 0 empty empty P4 17 7 0 10 -260818 -258699 -1 0 1; #X obj 75 47 tgl 15 0 empty empty Q1 17 7 0 10 -24198 -258699 -1 1 1; #X obj 117 47 tgl 15 0 empty empty Q2 17 7 0 10 -24198 -258699 -1 0 1; #X obj 160 47 tgl 15 0 empty empty Q3 17 7 0 10 -24198 -258699 -1 1 1; #X obj 203 47 tgl 15 0 empty empty Q4 17 7 0 10 -24198 -258699 -1 1 1; #X obj 246 47 tgl 15 0 empty empty carry_out 17 7 0 10 -62784 -258699 -1 1 1; #X text 197 -90 1 clears counter; #X text 285 204 20070314_MartinPeach; #X obj 9 -121 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 1 1; #X obj 9 -89 metro 100; #X obj 75 5 cd4516 up down counter; #X text 283 -115 1 loads data into counter; #X obj 160 -55 tgl 15 1 empty empty carry_in 17 7 0 10 -44926 -258699 -1 0 1; #X text 32 -155 cd4516 emulates the CMOS binary up/down counter; #X text 271 -1 0 to 1 transition on clock counts if reset = 0 and preset_enable = 0 and carry_in = 0; #X obj 208 82 tgl 15 0 empty empty P1 17 7 0 10 -260818 -258699 -1 0 1; #X obj 242 82 tgl 15 0 empty empty P2 17 7 0 10 -260818 -258699 -1 0 1; #X obj 274 82 tgl 15 0 empty empty P3 17 7 0 10 -260818 -258699 -1 1 1; #X obj 314 82 tgl 15 0 empty empty P4 17 7 0 10 -260818 -258699 -1 1 1; #X obj 143 163 tgl 15 0 empty empty Q1 17 7 0 10 -24198 -258699 -1 0 1; #X obj 185 163 tgl 15 0 empty empty Q2 17 7 0 10 -24198 -258699 -1 0 1; #X obj 228 163 tgl 15 0 empty empty Q3 17 7 0 10 -24198 -258699 -1 0 1; #X obj 271 163 tgl 15 0 empty empty Q4 17 7 0 10 -24198 -258699 -1 1 1; #X obj 314 163 tgl 15 0 empty empty carry_out 17 7 0 10 -62784 -258699 -1 1 1; #X obj 123 108 cd4516 up down counter; #X connect 0 0 17 0; #X connect 0 0 31 0; #X connect 1 0 17 1; #X connect 1 0 31 1; #X connect 2 0 17 2; #X connect 2 0 31 2; #X connect 3 0 17 3; #X connect 3 0 31 3; #X connect 4 0 17 5; #X connect 5 0 17 6; #X connect 6 0 17 7; #X connect 7 0 17 8; #X connect 15 0 16 0; #X connect 16 0 0 0; #X connect 17 0 8 0; #X connect 17 1 9 0; #X connect 17 2 10 0; #X connect 17 3 11 0; #X connect 17 4 12 0; #X connect 17 4 31 4; #X connect 19 0 17 4; #X connect 22 0 31 5; #X connect 23 0 31 6; #X connect 24 0 31 7; #X connect 25 0 31 8; #X connect 31 0 26 0; #X connect 31 1 27 0; #X connect 31 2 28 0; #X connect 31 3 29 0; #X connect 31 4 30 0; mrpeach/cmos/LICENSE.txt0000644000175000017500000000135612571126767015536 0ustar zmoelnigzmoelnig CMOS digital logic emulation objects for Pure Data Copyright (C) 2007-2014 Martin Peach This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . mrpeach/cmos/cd4516.c0000644000175000017500000001661212430236316014750 0ustar zmoelnigzmoelnig/* cd4516.c MP 20070312 */ /* Emulate a cd4516b */ #include "m_pd.h" typedef struct _cd4516 { t_object x_obj; t_outlet *x_Q1Out; t_outlet *x_Q2Out; t_outlet *x_Q3Out; t_outlet *x_Q4Out; t_outlet *x_CarryOut; int x_clock; int x_upDown; int x_preset_enable; int x_carry; int x_P1; int x_P2; int x_P3; int x_P4; int x_reset; int x_count; t_inlet *x_UpDownIn;/* All inlets take one or zero as acceptable inputs. */ t_inlet *x_ResetIn; t_inlet *x_PresetEnableIn; t_inlet *x_CarryIn; t_inlet *x_P1In; t_inlet *x_P2In; t_inlet *x_P3In; t_inlet *x_P4In; /* The main inlet (clock) should accept a bang or a one as valid clocks. */ /* If a one is received, it must be followed by a zero before the clock will work again. */ } t_cd4516; static t_class *cd4516_class; void cd4516_setup(void); static void *cd4516_new(t_symbol *s, int argc, t_atom *argv); static void cd4516_free(t_cd4516 *x); static void cd4516_bang(t_cd4516 *x); static void cd4516_float(t_cd4516 *x, t_float f); static void cd4516_reset(t_cd4516 *x, t_float f); static void cd4516_preset_enable(t_cd4516 *x, t_float f); static void cd4516_up_down(t_cd4516 *x, t_float f); static void cd4516_carry(t_cd4516 *x, t_float f); static void cd4516_P1(t_cd4516 *x, t_float f); static void cd4516_P2(t_cd4516 *x, t_float f); static void cd4516_P3(t_cd4516 *x, t_float f); static void cd4516_P4(t_cd4516 *x, t_float f); static void cd4516_update_outlets(t_cd4516 *x); static void cd4516_float(t_cd4516 *x, t_float f) { if (f == 1) { /* if clock is high and was low, count up. */ if ((x->x_clock == 0)&&(x->x_reset == 0)&&(x->x_preset_enable == 0)&&(x->x_carry == 0)) { x->x_clock = 1; if (x->x_upDown == 1) x->x_count = (x->x_count + 1)%16; else x->x_count = (x->x_count - 1)%16; cd4516_update_outlets(x); } } else if (f == 0) { x->x_clock = 0; } else post("cd4516 accepts bang, 1 or 0."); } static void cd4516_bang(t_cd4516 *x) { if ((x->x_reset == 0)&&(x->x_preset_enable == 0)&&(x->x_carry == 0)) { if (x->x_upDown == 1)x->x_count = (x->x_count + 1)%16; else x->x_count = (x->x_count - 1)%16; cd4516_update_outlets(x); } } static void cd4516_reset(t_cd4516 *x, t_float f) { if (f == 1) { if (x->x_reset == 0) { x->x_count = 0; cd4516_update_outlets(x); x->x_reset = 1; } } else if (f == 0) { x->x_reset = 0; if (x->x_preset_enable == 1) { /* the strange case of a low-going reset enabling an already high preset enable */ x->x_count = x->x_P1 + 2*x->x_P2 + 4*x->x_P3 + 8*x->x_P4; cd4516_update_outlets(x); } } else { post("cd4516 reset takes 1 or 0 only."); return; } } static void cd4516_preset_enable(t_cd4516 *x, t_float f) { if (f == 0) { x->x_preset_enable = 0; } else if (f == 1) { if (x->x_preset_enable == 0) { x->x_preset_enable = 1; if (x->x_reset == 0) { x->x_count = x->x_P1 + 2*x->x_P2 + 4*x->x_P3 + 8*x->x_P4; cd4516_update_outlets(x); } } } else { post("cd4516 x_preset_enable takes 1 or 0 only."); return; } } static void cd4516_up_down(t_cd4516 *x, t_float f) { if (f == 1) { x->x_upDown = 1; } else if (f == 0) { x->x_upDown = 0; } else post("cd4516 updown accepts bang, 1 or 0."); } static void cd4516_carry(t_cd4516 *x, t_float f) { if (f == 1) { x->x_carry = 1; } else if (f == 0) { x->x_carry = 0; } else post("cd4516 carry accepts bang, 1 or 0."); } static void cd4516_P1(t_cd4516 *x, t_float f) { if (f == 1) x->x_P1 = 1; else if (f == 0) x->x_P1 = 0; else { post("cd4516 P1 takes 1 or 0 only."); return; } } static void cd4516_P2(t_cd4516 *x, t_float f) { if (f == 1) x->x_P2 = 1; else if (f == 0) x->x_P2 = 0; else { post("cd4516 P2 takes 1 or 0 only."); return; } } static void cd4516_P3(t_cd4516 *x, t_float f) { if (f == 1) x->x_P3 = 1; else if (f == 0) x->x_P3 = 0; else { post("cd4516 P3 takes 1 or 0 only."); return; } } static void cd4516_P4(t_cd4516 *x, t_float f) { if (f == 1) x->x_P4 = 1; else if (f == 0) x->x_P4 = 0; else { post("cd4516 P4 takes 1 or 0 only."); return; } } static void cd4516_update_outlets(t_cd4516 *x) { if (x->x_upDown == 1) outlet_float(x->x_CarryOut, (x->x_count == 15)?0:1); else outlet_float(x->x_CarryOut, (x->x_count == 0)?0:1); outlet_float(x->x_Q4Out, ((x->x_count & 8) != 0)?1:0); outlet_float(x->x_Q3Out, ((x->x_count & 4) != 0)?1:0); outlet_float(x->x_Q2Out, ((x->x_count & 2) != 0)?1:0); outlet_float(x->x_Q1Out, ((x->x_count & 1) != 0)?1:0); } static void cd4516_free(t_cd4516 *x) { return; } static void *cd4516_new(t_symbol *s, int argc, t_atom *argv) { t_cd4516 *x; x = (t_cd4516 *)pd_new(cd4516_class); if (x == NULL) return (x); x->x_Q1Out = outlet_new((t_object *)x, &s_float); x->x_Q2Out = outlet_new((t_object *)x, &s_float); x->x_Q3Out = outlet_new((t_object *)x, &s_float); x->x_Q4Out = outlet_new((t_object *)x, &s_float); x->x_CarryOut = outlet_new((t_object *)x, &s_float); x->x_UpDownIn = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("updown")); x->x_ResetIn = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("reset")); x->x_PresetEnableIn = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("presetenable")); x->x_CarryIn = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("carry")); x->x_P1In = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("P1")); x->x_P2In = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("P2")); x->x_P3In = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("P3")); x->x_P4In = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("P4")); return (x); } void cd4516_setup(void) { cd4516_class = class_new(gensym("cd4516"), (t_newmethod)cd4516_new, (t_method)cd4516_free, sizeof(t_cd4516), 0, 0); /* no arguments */ class_addbang(cd4516_class, cd4516_bang); class_addfloat(cd4516_class, cd4516_float); class_addmethod(cd4516_class, (t_method)cd4516_up_down, gensym("updown"), A_FLOAT, 0); class_addmethod(cd4516_class, (t_method)cd4516_preset_enable, gensym("presetenable"), A_FLOAT, 0); class_addmethod(cd4516_class, (t_method)cd4516_reset, gensym("reset"), A_FLOAT, 0); class_addmethod(cd4516_class, (t_method)cd4516_carry, gensym("carry"), A_FLOAT, 0); class_addmethod(cd4516_class, (t_method)cd4516_P1, gensym("P1"), A_FLOAT, 0); class_addmethod(cd4516_class, (t_method)cd4516_P2, gensym("P2"), A_FLOAT, 0); class_addmethod(cd4516_class, (t_method)cd4516_P3, gensym("P3"), A_FLOAT, 0); class_addmethod(cd4516_class, (t_method)cd4516_P4, gensym("P4"), A_FLOAT, 0); } /* end cd4516.c */ mrpeach/cmos/cd4094.c0000644000175000017500000001321412430236316014744 0ustar zmoelnigzmoelnig/* cd4094.c MP 20070312 */ /* Emulate a cd4094b */ #include "m_pd.h" typedef struct _cd4094 { t_object x_obj; t_outlet *x_Q1Out; t_outlet *x_Q2Out; t_outlet *x_Q3Out; t_outlet *x_Q4Out; t_outlet *x_Q5Out; t_outlet *x_Q6Out; t_outlet *x_Q7Out; t_outlet *x_Q8Out; t_outlet *x_QSOut; t_outlet *x_QprimeSOut; int x_clock; int x_data; int x_data_in; int x_strobe; int x_output_enable; int x_qprime; t_inlet *x_StrobeIn;/* Strobe takes one or zero as acceptable inputs. */ t_inlet *x_DataIn;/* Data takes one or zero as acceptable inputs. */ t_inlet *x_OutputEnable;/* Output Enable takes one or zero as acceptable inputs. */ /* The main inlet (clock) should accept a bang or a one as valid clocks. */ /* If a one is received, it must be followed by a zero before the clock will work again. */ } t_cd4094; static t_class *cd4094_class; void cd4094_setup(void); static void *cd4094_new(t_symbol *s, int argc, t_atom *argv); static void cd4094_free(t_cd4094 *x); static void cd4094_bang(t_cd4094 *x); static void cd4094_float(t_cd4094 *x, t_float f); static void cd4094_strobe(t_cd4094 *x, t_float f); static void cd4094_data(t_cd4094 *x, t_float f); static void cd4094_output_enable(t_cd4094 *x, t_float f); static void cd4094_update_outlets(t_cd4094 *x); static void cd4094_float(t_cd4094 *x, t_float f) { if (f == 1) { /* if clock is high and was low, clock it. */ if ((x->x_clock == 0)&&(x->x_strobe == 1)) { x->x_data <<= 1; if (x->x_data_in != 0) x->x_data |= 1; cd4094_update_outlets(x); } x->x_clock = 1; } else if (f == 0) { if (x->x_clock == 1) /* if clock was high and is low, clock Q prime. */ { x->x_qprime = ((x->x_data & 256) != 0)?1:0; outlet_float(x->x_QprimeSOut, x->x_qprime); } x->x_clock = 0; } else post("cd4094 accepts bang, 1 or 0."); } static void cd4094_bang(t_cd4094 *x) { if (x->x_strobe == 1) { /* rising edge clock */ x->x_data <<= 1; if (x->x_data_in != 0) x->x_data |= 1; cd4094_update_outlets(x); /* Q'7 is clocked on a falling edge */ x->x_qprime = ((x->x_data & 256) != 0)?1:0; outlet_float(x->x_QprimeSOut, x->x_qprime); } } static void cd4094_strobe(t_cd4094 *x, t_float f) { if (f == 1) { x->x_strobe = 1; } else if (f == 0) { x->x_strobe = 0; } else { post("cd4094 strobe takes 1 or 0 only."); return; } } static void cd4094_output_enable(t_cd4094 *x, t_float f) { if (f == 1) { x->x_output_enable = 1; cd4094_update_outlets(x); } else if (f == 0) { x->x_output_enable = 0; } else { post("cd4094 output enable takes 1 or 0 only."); return; } } static void cd4094_data(t_cd4094 *x, t_float f) { if (f == 1) x->x_data_in = 1; else if (f == 0) x->x_data_in = 0; else { post("cd4094 data takes 1 or 0 only."); return; } } static void cd4094_update_outlets(t_cd4094 *x) { outlet_float(x->x_QprimeSOut, ((x->x_qprime) != 0)?1:0); outlet_float(x->x_QSOut, ((x->x_data & 256) != 0)?1:0); if (x->x_output_enable != 0) { outlet_float(x->x_QSOut, ((x->x_data & 256) != 0)?1:0); outlet_float(x->x_Q8Out, ((x->x_data & 128) != 0)?1:0); outlet_float(x->x_Q7Out, ((x->x_data & 64) != 0)?1:0); outlet_float(x->x_Q6Out, ((x->x_data & 32) != 0)?1:0); outlet_float(x->x_Q5Out, ((x->x_data & 16) != 0)?1:0); outlet_float(x->x_Q4Out, ((x->x_data & 8) != 0)?1:0); outlet_float(x->x_Q3Out, ((x->x_data & 4) != 0)?1:0); outlet_float(x->x_Q2Out, ((x->x_data & 2) != 0)?1:0); outlet_float(x->x_Q1Out, ((x->x_data & 1) != 0)?1:0); } } static void cd4094_free(t_cd4094 *x) { return; } static void *cd4094_new(t_symbol *s, int argc, t_atom *argv) { t_cd4094 *x; x = (t_cd4094 *)pd_new(cd4094_class); if (x == NULL) return (x); x->x_Q1Out = outlet_new((t_object *)x, &s_float); x->x_Q2Out = outlet_new((t_object *)x, &s_float); x->x_Q3Out = outlet_new((t_object *)x, &s_float); x->x_Q4Out = outlet_new((t_object *)x, &s_float); x->x_Q5Out = outlet_new((t_object *)x, &s_float); x->x_Q6Out = outlet_new((t_object *)x, &s_float); x->x_Q7Out = outlet_new((t_object *)x, &s_float); x->x_Q8Out = outlet_new((t_object *)x, &s_float); x->x_QSOut = outlet_new((t_object *)x, &s_float); x->x_QprimeSOut = outlet_new((t_object *)x, &s_float); x->x_StrobeIn = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("strobe")); x->x_DataIn = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("data")); x->x_OutputEnable = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("enableoutput")); return (x); } void cd4094_setup(void) { cd4094_class = class_new(gensym("cd4094"), (t_newmethod)cd4094_new, (t_method)cd4094_free, sizeof(t_cd4094), 0, 0); /* no arguments */ class_addbang(cd4094_class, cd4094_bang); class_addfloat(cd4094_class, cd4094_float); class_addmethod(cd4094_class, (t_method)cd4094_strobe, gensym("strobe"), A_FLOAT, 0); class_addmethod(cd4094_class, (t_method)cd4094_data, gensym("data"), A_FLOAT, 0); class_addmethod(cd4094_class, (t_method)cd4094_output_enable, gensym("enableoutput"), A_FLOAT, 0); } /* end cd4094.c */ mrpeach/cmos/cd4070-help.pd0000644000175000017500000000070311026462102016036 0ustar zmoelnigzmoelnig#N canvas 670 174 454 208 12; #X obj 86 107 cd4070; #X obj 86 82 tgl 15 0 empty empty empty 17 7 0 10 -24198 -258699 -1 0 1; #X obj 129 83 tgl 15 0 empty empty empty 17 7 0 10 -24198 -258699 -1 0 1; #X obj 86 137 tgl 15 0 empty empty empty 17 7 0 10 -258699 -241291 -1 0 1; #X text 18 47 cd4070 emulates 1/4 of the CMOS Exclusive Or gate; #X text 167 138 20070308_Martin_Peach; #X connect 0 0 3 0; #X connect 1 0 0 0; #X connect 2 0 0 1; mrpeach/cmos/cd4082.c0000644000175000017500000000630012430236316014737 0ustar zmoelnigzmoelnig/* cd4082.c MP 20070312 */ /* Emulate a cd4082b */ #include "m_pd.h" typedef struct _cd4082 { t_object x_obj; int x_in1; int x_in2; int x_in3; int x_in4; t_outlet *x_out; t_inlet *x_inlet2;/* Second inlet is 'live' like the first */ t_inlet *x_inlet3;/* Third inlet is 'live' like the first */ t_inlet *x_inlet4;/* Fourth inlet is 'live' like the first */ } t_cd4082; static t_class *cd4082_class; void cd4082_setup(void); static void *cd4082_new(t_symbol *s, int argc, t_atom *argv); static void cd4082_free(t_cd4082 *x); static void cd4082_bang(t_cd4082 *x); static void cd4082_float(t_cd4082 *x, t_float f); static void cd4082_inlet2(t_cd4082 *x, t_float f); static void cd4082_inlet3(t_cd4082 *x, t_float f); static void cd4082_inlet4(t_cd4082 *x, t_float f); static void cd4082_update_outlets(t_cd4082 *x); static void cd4082_float(t_cd4082 *x, t_float f) { if (f == 1) x->x_in1 = 1; else if (f == 0) x->x_in1 = 0; else { post("cd4082 inlet 2 accepts 1 or 0."); return; } cd4082_update_outlets(x); } static void cd4082_bang(t_cd4082 *x) { cd4082_update_outlets(x); } static void cd4082_inlet2(t_cd4082 *x, t_float f) { if (f == 1) x->x_in2 = 1; else if (f == 0) x->x_in2 = 0; else { post("cd4082 inlet 2 accepts 1 or 0."); return; } cd4082_update_outlets(x); } static void cd4082_inlet3(t_cd4082 *x, t_float f) { if (f == 1) x->x_in3 = 1; else if (f == 0) x->x_in3 = 0; else { post("cd4082 inlet 3 accepts 1 or 0."); return; } cd4082_update_outlets(x); } static void cd4082_inlet4(t_cd4082 *x, t_float f) { if (f == 1) x->x_in4 = 1; else if (f == 0) x->x_in4 = 0; else { post("cd4082 inlet 4 accepts 1 or 0."); return; } cd4082_update_outlets(x); } static void cd4082_update_outlets(t_cd4082 *x) { /* QUAD AND function */ outlet_float(x->x_out, ((x->x_in1 + x->x_in2 + x->x_in3 + x->x_in4) == 4)?1:0); } static void cd4082_free(t_cd4082 *x) { return; } static void *cd4082_new(t_symbol *s, int argc, t_atom *argv) { t_cd4082 *x; x = (t_cd4082 *)pd_new(cd4082_class); if (x == NULL) return (x); x->x_out = outlet_new((t_object *)x, &s_float); x->x_inlet2 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("inlet2")); x->x_inlet3 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("inlet3")); x->x_inlet4 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("inlet4")); return (x); } void cd4082_setup(void) { cd4082_class = class_new(gensym("cd4082"), (t_newmethod)cd4082_new, (t_method)cd4082_free, sizeof(t_cd4082), 0, 0); /* no arguments */ class_addbang(cd4082_class, cd4082_bang); class_addfloat(cd4082_class, cd4082_float); class_addmethod(cd4082_class, (t_method)cd4082_inlet2, gensym("inlet2"), A_FLOAT, 0); class_addmethod(cd4082_class, (t_method)cd4082_inlet3, gensym("inlet3"), A_FLOAT, 0); class_addmethod(cd4082_class, (t_method)cd4082_inlet4, gensym("inlet4"), A_FLOAT, 0); } /* end cd4082.c */ mrpeach/cmos/cd4013-help.pd0000644000175000017500000000255311026462102016040 0ustar zmoelnigzmoelnig#N canvas 581 224 651 219 12; #X obj 79 38 tgl 15 0 empty empty CLK 17 7 0 10 -24198 -62784 -1 0 1; #X obj 98 53 tgl 15 0 empty empty SET 17 7 0 10 -24198 -62784 -1 0 1; #X obj 118 68 tgl 15 0 empty empty RESET 17 7 0 10 -24198 -62784 -1 0 1; #X obj 138 83 tgl 15 0 empty empty D 17 7 0 10 -24198 -62784 -1 0 1 ; #X obj 138 172 tgl 15 0 empty empty /Q 17 7 0 10 -143491 -241291 -1 0 1; #X obj 79 172 tgl 15 0 empty empty Q 17 7 0 10 -143491 -241291 -1 1 1; #X obj 6 67 tgl 15 0 empty empty empty 17 7 0 10 -44926 -90881 -1 0 1; #X text 27 5 cd4013 emulates one half of the CMOS logic D flipflop. ; #X obj 79 146 cd4013 v; #X text 172 80 D is clocked to the output on rising edge of a clock. ; #X text 133 35 A 0-1 transition or a bang clocks D to the outlets. ; #X text 147 50 Sets Q=1. Overrides Reset and Clock.; #X text 183 65 Sets Q=0. Overrides Clock.; #X obj 170 145 spigot; #X obj 213 123 tgl 15 0 empty empty feedback 17 7 0 10 -44926 -1109 -1 1 1; #X obj 42 115 bng 15 250 50 0 empty empty empty 17 7 0 10 -24198 -241291 -1; #X obj 6 89 metro 500; #X text 272 172 20070308_Martin_Peach; #X connect 0 0 8 0; #X connect 1 0 8 1; #X connect 2 0 8 2; #X connect 3 0 8 3; #X connect 4 0 13 0; #X connect 6 0 16 0; #X connect 8 0 5 0; #X connect 8 1 4 0; #X connect 13 0 3 0; #X connect 14 0 13 1; #X connect 15 0 8 0; #X connect 16 0 15 0; mrpeach/cmos/cd4081-help.pd0000644000175000017500000000067211026462102016045 0ustar zmoelnigzmoelnig#N canvas 670 174 462 216 12; #X obj 86 82 tgl 15 0 empty empty empty 17 7 0 10 -24198 -258699 -1 1 1; #X obj 129 83 tgl 15 0 empty empty empty 17 7 0 10 -24198 -258699 -1 1 1; #X obj 86 137 tgl 15 0 empty empty empty 17 7 0 10 -258699 -241291 -1 1 1; #X text 167 138 20070308_Martin_Peach; #X obj 86 106 cd4081; #X text 18 47 cd4081 emulates 1/4 of the CMOS AND gate; #X connect 0 0 4 0; #X connect 1 0 4 1; #X connect 4 0 2 0; mrpeach/cmos/cd4001-help.pd0000644000175000017500000000071011026462102016026 0ustar zmoelnigzmoelnig#N canvas 670 174 486 240 12; #X obj 86 82 tgl 15 1 empty empty empty 17 7 0 10 -24198 -258699 -1 1 1; #X obj 161 82 tgl 15 1 empty empty empty 17 7 0 10 -24198 -258699 -1 1 1; #X obj 86 137 tgl 15 0 empty empty empty 17 7 0 10 -258699 -241291 -1 0 1; #X text 210 170 20070315_Martin_Peach; #X obj 86 106 cd4001 nor; #X text 16 29 cd4001 emulates 1/4 of the CMOS two-input NOR gate; #X connect 0 0 4 0; #X connect 1 0 4 1; #X connect 4 0 2 0; mrpeach/cmos/cd4027.c0000644000175000017500000001402512430236316014741 0ustar zmoelnigzmoelnig/* cd4027.c MP 20070306 */ /* Emulate a cd4027b */ #include "m_pd.h" typedef struct _cd4027 { t_object x_obj; int x_state;/* set = bit0, clock = bit1, reset = bit2 j = bit3 k = bit4 q = bit 5 */ t_outlet *x_Q; t_outlet *x_notQ; t_inlet *x_set;/* set takes one or zero as acceptable inputs. */ t_inlet *x_reset;/* reset takes one or zero as acceptable inputs. */ t_inlet *x_j;/* j takes one or zero as acceptable inputs. */ t_inlet *x_k;/* k takes one or zero as acceptable inputs. */ /* The main inlet (clock) should accept a bang or a one as valid clocks. */ /* If a one is received, it must be followed by a zero before the clock will work again. */ } t_cd4027; #define SET_4027 1 #define CLOCK_4027 2 #define RESET_4027 4 #define J_4027 8 #define K_4027 16 #define Q_4027 32 #define UPDATING_4027 64 #define CHANGED_4027 128 static t_class *cd4027_class; void cd4027_setup(void); static void *cd4027_new(t_symbol *s, int argc, t_atom *argv); static void cd4027_free(t_cd4027 *x); static void cd4027_bang(t_cd4027 *x); static void cd4027_float(t_cd4027 *x, t_float f); static void cd4027_set(t_cd4027 *x, t_float f); static void cd4027_reset(t_cd4027 *x, t_float f); static void cd4027_j(t_cd4027 *x, t_float f); static void cd4027_k(t_cd4027 *x, t_float f); static void cd4027_update_outlets(t_cd4027 *x); static void cd4027_printstate (t_cd4027 *x); static void cd4027_float(t_cd4027 *x, t_float f) { if (f == 1) { /* if clock is high and was low, clock it. */ if ((x->x_state & CLOCK_4027) == 0) cd4027_bang(x); x->x_state |= CLOCK_4027; } else if (f == 0) x->x_state &= ~CLOCK_4027; else post("cd4027 accepts bang, 1 or 0."); } static void cd4027_printstate (t_cd4027 *x) { post ("SET %d RESET %d J %d K %d Q %d", ((x->x_state & SET_4027) != 0)?1:0 , ((x->x_state & RESET_4027) != 0)?1:0 , ((x->x_state & J_4027) != 0)?1:0 , ((x->x_state & K_4027) != 0)?1:0 , ((x->x_state & Q_4027) != 0)?1:0); } static void cd4027_bang(t_cd4027 *x) { if ((x->x_state & (SET_4027 | RESET_4027)) == 0) { /* if set is low and reset is low, clock forward */ if ((x->x_state & Q_4027) != 0) { /* Q is high */ if ((x->x_state & K_4027)== 0) x->x_state |= Q_4027; else x->x_state &= ~Q_4027; } else { /* Q is low */ if ((x->x_state & J_4027) != 0) x->x_state |= Q_4027; else x->x_state &= ~Q_4027; } cd4027_update_outlets(x); } } static void cd4027_set(t_cd4027 *x, t_float f) { if (f == 1) { x->x_state |= SET_4027; /* set = 1 */ } else if (f == 0) { x->x_state &= ~SET_4027; /* set = 0 */ } else { post("cd4027 set takes 1 or 0 only."); return; } /* update outlets if not already doing that */ if ((x->x_state & UPDATING_4027) == 0) { cd4027_update_outlets(x); } else { x->x_state |= CHANGED_4027; } return; } static void cd4027_reset(t_cd4027 *x, t_float f) { if (f == 1) { x->x_state |= RESET_4027; /* reset = 1 */ } else if (f == 0) { x->x_state &= ~RESET_4027; /* reset = 0 */ } else { return; } /* update outlets if not already doing that */ if ((x->x_state & UPDATING_4027) == 0) { cd4027_update_outlets(x); } else { x->x_state |= CHANGED_4027; } return; } static void cd4027_j(t_cd4027 *x, t_float f) { if (f == 1) { x->x_state |= J_4027; /* j = 1 */ } else if (f == 0) { x->x_state &= ~J_4027; /* j = 0 */ } else post("cd4027 j takes 1 or 0 only."); return; } static void cd4027_k(t_cd4027 *x, t_float f) { if (f == 1) { x->x_state |= K_4027; /* k = 1 */ } else if (f == 0) { x->x_state &= ~K_4027; /* k = 0 */ } else post("cd4027 k takes 1 or 0 only."); return; } static void cd4027_update_outlets(t_cd4027 *x) { /* cd4027_printstate (x); */ x->x_state |= UPDATING_4027;/* updating outlets */ reset: if ((x->x_state & SET_4027) != 0) x->x_state |= Q_4027; else if ((x->x_state & RESET_4027) != 0) x->x_state &= ~Q_4027; x->x_state &= ~CHANGED_4027; /* prepare to flag any changes that occur during outlet_update */ outlet_float(x->x_notQ, ((x->x_state & Q_4027) == 0)?1:0); /* we might get set or reset as a result of feedback from one of these outlets. */ if ((x->x_state & CHANGED_4027) != 0) goto reset; outlet_float(x->x_Q, ((x->x_state & Q_4027) != 0)?1:0); if ((x->x_state & CHANGED_4027) != 0) goto reset; x->x_state &= ~UPDATING_4027;/* finished updating outlets */ } static void cd4027_free(t_cd4027 *x) { return; } static void *cd4027_new(t_symbol *s, int argc, t_atom *argv) { t_cd4027 *x; x = (t_cd4027 *)pd_new(cd4027_class); if (x == NULL) return (x); x->x_Q = outlet_new((t_object *)x, &s_float); x->x_notQ = outlet_new((t_object *)x, &s_float); x->x_set = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("set")); x->x_reset = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("reset")); x->x_j = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("j")); x->x_k = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("k")); return (x); } void cd4027_setup(void) { cd4027_class = class_new(gensym("cd4027"), (t_newmethod)cd4027_new, (t_method)cd4027_free, sizeof(t_cd4027), 0, 0); /* no arguments */ class_addbang(cd4027_class, cd4027_bang); class_addfloat(cd4027_class, cd4027_float); class_addmethod(cd4027_class, (t_method)cd4027_reset, gensym("reset"), A_FLOAT, 0); class_addmethod(cd4027_class, (t_method)cd4027_set, gensym("set"), A_FLOAT, 0); class_addmethod(cd4027_class, (t_method)cd4027_j, gensym("j"), A_FLOAT, 0); class_addmethod(cd4027_class, (t_method)cd4027_k, gensym("k"), A_FLOAT, 0); } /* end cd4027.c */ mrpeach/cmos/cd4017-help.pd0000644000175000017500000000614611026462102016046 0ustar zmoelnigzmoelnig#N canvas 0 0 684 247 10; #X obj 9 123 cd4017 vvvvvvvvvvvvvvvvvvvvvvv; #X obj 9 78 tgl 15 0 empty empty clock 17 7 0 10 -24198 -225271 -1 0 1; #X obj 111 88 tgl 15 0 empty empty clock_inhibit 17 7 0 10 -24198 -225271 -1 0 1; #X obj 214 103 tgl 15 0 empty empty reset 17 7 0 10 -24198 -225271 -1 0 1; #X obj 9 39 metro 100; #X obj 9 9 tgl 15 0 empty empty run 17 7 0 10 -24198 -225271 -1 1 1 ; #X obj 9 152 tgl 15 0 empty empty 0 3 23 0 10 -44926 -250685 -1 0 1 ; #X obj 29 152 tgl 15 0 empty empty 1 3 23 0 10 -44926 -250685 -1 0 1; #X obj 50 152 tgl 15 0 empty empty 2 3 23 0 10 -44926 -250685 -1 0 1; #X obj 70 152 tgl 15 0 empty empty 3 3 23 0 10 -44926 -250685 -1 0 1; #X obj 91 152 tgl 15 0 empty empty 4 3 23 0 10 -44926 -250685 -1 0 1; #X obj 111 152 tgl 15 0 empty empty 5 3 23 0 10 -44926 -250685 -1 0 1; #X obj 132 152 tgl 15 0 empty empty 6 3 23 0 10 -44926 -250685 -1 0 1; #X obj 152 152 tgl 15 0 empty empty 7 3 23 0 10 -44926 -250685 -1 0 1; #X obj 173 152 tgl 15 0 empty empty 8 3 23 0 10 -44926 -250685 -1 1 1; #X obj 193 152 tgl 15 0 empty empty 9 3 23 0 10 -44926 -250685 -1 0 1; #X obj 214 152 tgl 15 0 empty empty carry_out 3 23 0 10 -44926 -250685 -1 0 1; #X text 122 7 The CD4017 is a CMOS digital logic IC.; #X text 123 25 It counts up to ten and sets one of the numbered outlets high whenever it is clocked.; #X text 123 55 A clock can be a bang or a 1 following a 0; #X obj 332 142 cd4017 vvvvvvvvvvvvvvvvvvvvvvv; #X obj 332 97 tgl 15 0 empty empty clock 17 7 0 10 -24198 -225271 -1 0 1; #X obj 434 107 tgl 15 0 empty empty clock_inhibit 17 7 0 10 -24198 -225271 -1 0 1; #X obj 537 122 tgl 15 0 empty empty reset 17 7 0 10 -24198 -225271 -1 0 1; #X obj 332 171 tgl 15 0 empty empty 0 3 23 0 10 -44926 -250685 -1 0 1; #X obj 352 171 tgl 15 0 empty empty 1 3 23 0 10 -44926 -250685 -1 0 1; #X obj 373 171 tgl 15 0 empty empty 2 3 23 0 10 -44926 -250685 -1 1 1; #X obj 393 171 tgl 15 0 empty empty 3 3 23 0 10 -44926 -250685 -1 0 1; #X obj 414 171 tgl 15 0 empty empty 4 3 23 0 10 -44926 -250685 -1 0 1; #X obj 434 171 tgl 15 0 empty empty 5 3 23 0 10 -44926 -250685 -1 0 1; #X obj 455 171 tgl 15 0 empty empty 6 3 23 0 10 -44926 -250685 -1 0 1; #X obj 475 171 tgl 15 0 empty empty 7 3 23 0 10 -44926 -250685 -1 0 1; #X obj 496 171 tgl 15 0 empty empty 8 3 23 0 10 -44926 -250685 -1 0 1; #X obj 516 171 tgl 15 0 empty empty 9 3 23 0 10 -44926 -250685 -1 0 1; #X obj 537 171 tgl 15 0 empty empty carry_out 3 23 0 10 -44926 -250685 -1 1 1; #X text 452 229 2007MartinPeach; #X connect 0 0 6 0; #X connect 0 1 7 0; #X connect 0 2 8 0; #X connect 0 3 9 0; #X connect 0 4 10 0; #X connect 0 5 11 0; #X connect 0 6 12 0; #X connect 0 7 13 0; #X connect 0 8 14 0; #X connect 0 9 15 0; #X connect 0 10 16 0; #X connect 1 0 0 0; #X connect 2 0 0 1; #X connect 3 0 0 2; #X connect 4 0 1 0; #X connect 5 0 4 0; #X connect 16 0 21 0; #X connect 20 0 24 0; #X connect 20 1 25 0; #X connect 20 2 26 0; #X connect 20 3 27 0; #X connect 20 4 28 0; #X connect 20 5 29 0; #X connect 20 6 30 0; #X connect 20 7 31 0; #X connect 20 8 32 0; #X connect 20 9 33 0; #X connect 20 10 34 0; #X connect 21 0 20 0; #X connect 22 0 20 1; #X connect 23 0 20 2; #X connect 29 0 23 0; mrpeach/cmos/cd4002.c0000644000175000017500000000616112430236316014734 0ustar zmoelnigzmoelnig/* cd4002.c MP 20070315 */ /* Emulate a cd4002b */ #include "m_pd.h" typedef struct _cd4002 { t_object x_obj; int x_in1; int x_in2; int x_in3; int x_in4; t_outlet *x_out; t_inlet *x_inlet2;/* extra inlets are 'live' like the first */ t_inlet *x_inlet3; t_inlet *x_inlet4; } t_cd4002; static t_class *cd4002_class; void cd4002_setup(void); static void *cd4002_new(t_symbol *s, int argc, t_atom *argv); static void cd4002_free(t_cd4002 *x); static void cd4002_bang(t_cd4002 *x); static void cd4002_float(t_cd4002 *x, t_float f); static void cd4002_inlet2(t_cd4002 *x, t_float f); static void cd4002_inlet3(t_cd4002 *x, t_float f); static void cd4002_inlet4(t_cd4002 *x, t_float f); static void cd4002_update_outlets(t_cd4002 *x); static void cd4002_float(t_cd4002 *x, t_float f) { if (f == 1) x->x_in1 = 1; else if (f == 0) x->x_in1 = 0; else { post("cd4002 inlet 2 accepts 1 or 0."); return; } cd4002_update_outlets(x); } static void cd4002_bang(t_cd4002 *x) { cd4002_update_outlets(x); } static void cd4002_inlet2(t_cd4002 *x, t_float f) { if (f == 1) x->x_in2 = 1; else if (f == 0) x->x_in2 = 0; else { post("cd4002 inlet 2 accepts 1 or 0."); return; } cd4002_update_outlets(x); } static void cd4002_inlet3(t_cd4002 *x, t_float f) { if (f == 1) x->x_in3 = 1; else if (f == 0) x->x_in3 = 0; else { post("cd4002 inlet 3 accepts 1 or 0."); return; } cd4002_update_outlets(x); } static void cd4002_inlet4(t_cd4002 *x, t_float f) { if (f == 1) x->x_in4 = 1; else if (f == 0) x->x_in4 = 0; else { post("cd4002 inlet 4 accepts 1 or 0."); return; } cd4002_update_outlets(x); } static void cd4002_update_outlets(t_cd4002 *x) { /* Quadruple NOR function */ outlet_float(x->x_out, ((x->x_in1 + x->x_in2 + x->x_in3 + x->x_in4) != 0)?0:1); } static void cd4002_free(t_cd4002 *x) { return; } static void *cd4002_new(t_symbol *s, int argc, t_atom *argv) { t_cd4002 *x; x = (t_cd4002 *)pd_new(cd4002_class); if (x == NULL) return (x); x->x_out = outlet_new((t_object *)x, &s_float); x->x_inlet2 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("inlet2")); x->x_inlet3 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("inlet3")); x->x_inlet4 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("inlet4")); return (x); } void cd4002_setup(void) { cd4002_class = class_new(gensym("cd4002"), (t_newmethod)cd4002_new, (t_method)cd4002_free, sizeof(t_cd4002), 0, 0); /* no arguments */ class_addbang(cd4002_class, cd4002_bang); class_addfloat(cd4002_class, cd4002_float); class_addmethod(cd4002_class, (t_method)cd4002_inlet2, gensym("inlet2"), A_FLOAT, 0); class_addmethod(cd4002_class, (t_method)cd4002_inlet3, gensym("inlet3"), A_FLOAT, 0); class_addmethod(cd4002_class, (t_method)cd4002_inlet4, gensym("inlet4"), A_FLOAT, 0); } /* end cd4002.c */ mrpeach/cmos/cd4081.c0000644000175000017500000000410212430236316014734 0ustar zmoelnigzmoelnig/* cd4081.c MP 20070308 */ /* Emulate a cd4081b */ #include "m_pd.h" typedef struct _cd4081 { t_object x_obj; int x_in1; int x_in2; t_outlet *x_out; t_inlet *x_inlet2;/* Second inlet is 'live' like the first */ } t_cd4081; static t_class *cd4081_class; void cd4081_setup(void); static void *cd4081_new(t_symbol *s, int argc, t_atom *argv); static void cd4081_free(t_cd4081 *x); static void cd4081_bang(t_cd4081 *x); static void cd4081_float(t_cd4081 *x, t_float f); static void cd4081_inlet2(t_cd4081 *x, t_float f); static void cd4081_update_outlets(t_cd4081 *x); static void cd4081_float(t_cd4081 *x, t_float f) { if (f == 1) x->x_in1 = 1; else if (f == 0) x->x_in1 = 0; else { post("cd4081 inlet 2 accepts 1 or 0."); return; } cd4081_update_outlets(x); } static void cd4081_bang(t_cd4081 *x) { cd4081_update_outlets(x); } static void cd4081_inlet2(t_cd4081 *x, t_float f) { if (f == 1) x->x_in2 = 1; else if (f == 0) x->x_in2 = 0; else { post("cd4081 inlet 2 accepts 1 or 0."); return; } cd4081_update_outlets(x); } static void cd4081_update_outlets(t_cd4081 *x) { /* AND function */ outlet_float(x->x_out, ((x->x_in1 + x->x_in2) == 2)?1:0); } static void cd4081_free(t_cd4081 *x) { return; } static void *cd4081_new(t_symbol *s, int argc, t_atom *argv) { t_cd4081 *x; x = (t_cd4081 *)pd_new(cd4081_class); if (x == NULL) return (x); x->x_out = outlet_new((t_object *)x, &s_float); x->x_inlet2 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("inlet2")); return (x); } void cd4081_setup(void) { cd4081_class = class_new(gensym("cd4081"), (t_newmethod)cd4081_new, (t_method)cd4081_free, sizeof(t_cd4081), 0, 0); /* no arguments */ class_addbang(cd4081_class, cd4081_bang); class_addfloat(cd4081_class, cd4081_float); class_addmethod(cd4081_class, (t_method)cd4081_inlet2, gensym("inlet2"), A_FLOAT, 0); } /* end cd4081.c */ mrpeach/cmos/cd4011.c0000644000175000017500000000411212430236316014726 0ustar zmoelnigzmoelnig/* cd4011.c MP 20070315 */ /* Emulate a cd4011b */ #include "m_pd.h" typedef struct _cd4011 { t_object x_obj; int x_in1; int x_in2; t_outlet *x_out; t_inlet *x_inlet2;/* Second inlet is 'live' like the first */ } t_cd4011; static t_class *cd4011_class; void cd4011_setup(void); static void *cd4011_new(t_symbol *s, int argc, t_atom *argv); static void cd4011_free(t_cd4011 *x); static void cd4011_bang(t_cd4011 *x); static void cd4011_float(t_cd4011 *x, t_float f); static void cd4011_inlet2(t_cd4011 *x, t_float f); static void cd4011_update_outlets(t_cd4011 *x); static void cd4011_float(t_cd4011 *x, t_float f) { if (f == 1) x->x_in1 = 1; else if (f == 0) x->x_in1 = 0; else { post("cd4011 inlet 2 accepts 1 or 0."); return; } cd4011_update_outlets(x); } static void cd4011_bang(t_cd4011 *x) { cd4011_update_outlets(x); } static void cd4011_inlet2(t_cd4011 *x, t_float f) { if (f == 1) x->x_in2 = 1; else if (f == 0) x->x_in2 = 0; else { post("cd4011 inlet 2 accepts 1 or 0."); return; } cd4011_update_outlets(x); } static void cd4011_update_outlets(t_cd4011 *x) { /* Double NAND function */ outlet_float(x->x_out, ((x->x_in1 + x->x_in2) == 2)?0:1); } static void cd4011_free(t_cd4011 *x) { return; } static void *cd4011_new(t_symbol *s, int argc, t_atom *argv) { t_cd4011 *x; x = (t_cd4011 *)pd_new(cd4011_class); if (x == NULL) return (x); x->x_out = outlet_new((t_object *)x, &s_float); x->x_inlet2 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("inlet2")); return (x); } void cd4011_setup(void) { cd4011_class = class_new(gensym("cd4011"), (t_newmethod)cd4011_new, (t_method)cd4011_free, sizeof(t_cd4011), 0, 0); /* no arguments */ class_addbang(cd4011_class, cd4011_bang); class_addfloat(cd4011_class, cd4011_float); class_addmethod(cd4011_class, (t_method)cd4011_inlet2, gensym("inlet2"), A_FLOAT, 0); } /* end cd4011.c */ mrpeach/cmos/cmos-meta.pd0000644000175000017500000000025512571126767016122 0ustar zmoelnigzmoelnig#N canvas 15 49 200 200 10; #N canvas 25 49 420 300 META 1; #X text 13 41 NAME cmos; #X text 10 25 AUTHOR Martin Peach; #X text 10 10 VERSION 0.1; #X restore 10 10 pd META; mrpeach/cmos/cd4073-help.pd0000644000175000017500000000105511026462102016042 0ustar zmoelnigzmoelnig#N canvas 670 174 474 228 12; #X obj 86 82 tgl 15 0 empty empty empty 17 7 0 10 -24198 -258699 -1 1 1; #X obj 151 82 tgl 15 0 empty empty empty 17 7 0 10 -24198 -258699 -1 0 1; #X obj 86 137 tgl 15 0 empty empty empty 17 7 0 10 -258699 -241291 -1 0 1; #X obj 217 82 tgl 15 0 empty empty empty 17 7 0 10 -24198 -258699 -1 1 1; #X text 210 170 20070312_Martin_Peach; #X text 18 47 cd4073 emulates 1/3 of the CMOS triple AND gate; #X obj 86 106 cd4073 triple and; #X connect 0 0 6 0; #X connect 1 0 6 1; #X connect 3 0 6 2; #X connect 6 0 2 0; mrpeach/cmos/cd4014-help.pd0000644000175000017500000000313311026462102016034 0ustar zmoelnigzmoelnig#N canvas 633 293 527 277 12; #X obj 95 151 cd4014 shift register; #X obj 95 32 tgl 15 0 empty empty Clock 17 7 0 10 -44926 -258699 -1 0 1; #X obj 40 48 bng 15 250 50 0 empty empty empty 17 7 0 10 -44926 -258699 -1; #X obj 111 49 tgl 15 0 empty empty P1 17 7 0 10 -44926 -258699 -1 0 1; #X obj 127 65 tgl 15 0 empty empty P2 17 7 0 10 -44926 -258699 -1 0 1; #X obj 143 81 tgl 15 0 empty empty P3 17 7 0 10 -44926 -258699 -1 0 1; #X obj 160 98 tgl 15 0 empty empty P4 17 7 0 10 -44926 -258699 -1 0 1; #X obj 176 49 tgl 15 0 empty empty P5 17 7 0 10 -44926 -258699 -1 0 1; #X obj 192 65 tgl 15 0 empty empty P6 17 7 0 10 -44926 -258699 -1 0 1; #X obj 209 81 tgl 15 0 empty empty P7 17 7 0 10 -44926 -258699 -1 0 1; #X obj 225 98 tgl 15 0 empty empty P8 17 7 0 10 -44926 -258699 -1 0 1; #X obj 241 49 tgl 15 0 empty empty ParallelSerial 17 7 0 10 -44926 -258699 -1 0 1; #X obj 258 66 tgl 15 0 empty empty SerialIn 17 7 0 10 -44926 -258699 -1 0 1; #X obj 95 181 tgl 15 0 empty empty Q6 17 7 0 10 -258699 -241291 -1 0 1; #X obj 176 181 tgl 15 0 empty empty Q7 17 7 0 10 -258699 -241291 -1 0 1; #X obj 258 181 tgl 15 0 empty empty Q8 17 7 0 10 -258699 -241291 -1 0 1; #X text 18 0 cd4014 emulates the CMOS 8-stage static shift register ; #X text 147 226 20070315_MartinPeach; #X connect 0 0 13 0; #X connect 0 1 14 0; #X connect 0 2 15 0; #X connect 1 0 0 0; #X connect 2 0 0 0; #X connect 3 0 0 1; #X connect 4 0 0 2; #X connect 5 0 0 3; #X connect 6 0 0 4; #X connect 7 0 0 5; #X connect 8 0 0 6; #X connect 9 0 0 7; #X connect 10 0 0 8; #X connect 11 0 0 9; #X connect 12 0 0 10; mrpeach/cmos/cd4075.c0000644000175000017500000000520412430236316014743 0ustar zmoelnigzmoelnig/* cd4075.c MP 20070312 */ /* Emulate a cd4075b */ #include "m_pd.h" typedef struct _cd4075 { t_object x_obj; int x_in1; int x_in2; int x_in3; t_outlet *x_out; t_inlet *x_inlet2;/* Second inlet is 'live' like the first */ t_inlet *x_inlet3;/* Third inlet is 'live' like the first */ } t_cd4075; static t_class *cd4075_class; void cd4075_setup(void); static void *cd4075_new(t_symbol *s, int argc, t_atom *argv); static void cd4075_free(t_cd4075 *x); static void cd4075_bang(t_cd4075 *x); static void cd4075_float(t_cd4075 *x, t_float f); static void cd4075_inlet2(t_cd4075 *x, t_float f); static void cd4075_inlet3(t_cd4075 *x, t_float f); static void cd4075_update_outlets(t_cd4075 *x); static void cd4075_float(t_cd4075 *x, t_float f) { if (f == 1) x->x_in1 = 1; else if (f == 0) x->x_in1 = 0; else { post("cd4075 inlet 2 accepts 1 or 0."); return; } cd4075_update_outlets(x); } static void cd4075_bang(t_cd4075 *x) { cd4075_update_outlets(x); } static void cd4075_inlet2(t_cd4075 *x, t_float f) { if (f == 1) x->x_in2 = 1; else if (f == 0) x->x_in2 = 0; else { post("cd4075 inlet 2 accepts 1 or 0."); return; } cd4075_update_outlets(x); } static void cd4075_inlet3(t_cd4075 *x, t_float f) { if (f == 1) x->x_in3 = 1; else if (f == 0) x->x_in3 = 0; else { post("cd4075 inlet 3 accepts 1 or 0."); return; } cd4075_update_outlets(x); } static void cd4075_update_outlets(t_cd4075 *x) { /* Triple OR function */ outlet_float(x->x_out, ((x->x_in1 + x->x_in2 + x->x_in3) != 0)?1:0); } static void cd4075_free(t_cd4075 *x) { return; } static void *cd4075_new(t_symbol *s, int argc, t_atom *argv) { t_cd4075 *x; x = (t_cd4075 *)pd_new(cd4075_class); if (x == NULL) return (x); x->x_out = outlet_new((t_object *)x, &s_float); x->x_inlet2 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("inlet2")); x->x_inlet3 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("inlet3")); return (x); } void cd4075_setup(void) { cd4075_class = class_new(gensym("cd4075"), (t_newmethod)cd4075_new, (t_method)cd4075_free, sizeof(t_cd4075), 0, 0); /* no arguments */ class_addbang(cd4075_class, cd4075_bang); class_addfloat(cd4075_class, cd4075_float); class_addmethod(cd4075_class, (t_method)cd4075_inlet2, gensym("inlet2"), A_FLOAT, 0); class_addmethod(cd4075_class, (t_method)cd4075_inlet3, gensym("inlet3"), A_FLOAT, 0); } /* end cd4075.c */ mrpeach/cmos/cd4008-help.pd0000644000175000017500000000542511026462102016045 0ustar zmoelnigzmoelnig#N canvas 580 256 530 325 12; #X obj 8 136 cd4008 4 bit full adder; #X obj 8 33 tgl 15 0 empty empty Carry_In 17 7 0 10 -44926 -258699 -1 0 1; #X obj 30 64 tgl 15 0 empty empty A1 17 7 0 10 -44926 -258699 -1 1 1; #X obj 52 80 tgl 15 0 empty empty A2 17 7 0 10 -44926 -258699 -1 0 1; #X obj 75 96 tgl 15 0 empty empty A3 17 7 0 10 -44926 -258699 -1 1 1; #X obj 97 111 tgl 15 0 empty empty A4 17 7 0 10 -44926 -258699 -1 1 1; #X obj 119 63 tgl 15 0 empty empty B1 17 7 0 10 -44926 -258699 -1 0 1; #X obj 142 79 tgl 15 0 empty empty B2 17 7 0 10 -44926 -258699 -1 1 1; #X obj 164 95 tgl 15 0 empty empty B3 17 7 0 10 -44926 -258699 -1 0 1; #X obj 187 110 tgl 15 0 empty empty B4 17 7 0 10 -44926 -258699 -1 1 1; #X obj 8 174 tgl 15 0 empty empty S1 17 7 0 10 -258699 -241291 -1 1 1; #X obj 52 174 tgl 15 0 empty empty S2 17 7 0 10 -258699 -241291 -1 1 1; #X obj 97 174 tgl 15 0 empty empty S3 17 7 0 10 -258699 -241291 -1 1 1; #X obj 142 174 tgl 15 0 empty empty S4 17 7 0 10 -258699 -241291 -1 0 1; #X obj 187 190 tgl 15 0 empty empty Carry_Out 17 7 0 10 -258699 -241291 -1 1 1; #X obj 214 170 cd4008 4 bit full adder; #X obj 236 98 tgl 15 0 empty empty A1 17 7 0 10 -44926 -258699 -1 0 1; #X obj 258 114 tgl 15 0 empty empty A2 17 7 0 10 -44926 -258699 -1 1 1; #X obj 281 130 tgl 15 0 empty empty A3 17 7 0 10 -44926 -258699 -1 0 1; #X obj 303 145 tgl 15 0 empty empty A4 17 7 0 10 -44926 -258699 -1 0 1; #X obj 325 97 tgl 15 0 empty empty B1 17 7 0 10 -44926 -258699 -1 0 1; #X obj 348 113 tgl 15 0 empty empty B2 17 7 0 10 -44926 -258699 -1 1 1; #X obj 370 129 tgl 15 0 empty empty B3 17 7 0 10 -44926 -258699 -1 0 1; #X obj 393 144 tgl 15 0 empty empty B4 17 7 0 10 -44926 -258699 -1 1 1; #X obj 214 208 tgl 15 0 empty empty S1 17 7 0 10 -258699 -241291 -1 1 1; #X obj 258 208 tgl 15 0 empty empty S2 17 7 0 10 -258699 -241291 -1 0 1; #X obj 303 208 tgl 15 0 empty empty S3 17 7 0 10 -258699 -241291 -1 1 1; #X obj 348 208 tgl 15 0 empty empty S4 17 7 0 10 -258699 -241291 -1 1 1; #X obj 393 208 tgl 15 0 empty empty Carry_Out 17 7 0 10 -258699 -241291 -1 0 1; #X text 87 9 cd4008 emulates the CMOS 4-bit full adder.; #X text 194 279 20070315_MartinPeach; #X connect 0 0 10 0; #X connect 0 1 11 0; #X connect 0 2 12 0; #X connect 0 3 13 0; #X connect 0 4 14 0; #X connect 0 4 15 0; #X connect 1 0 0 0; #X connect 2 0 0 1; #X connect 3 0 0 2; #X connect 4 0 0 3; #X connect 5 0 0 4; #X connect 6 0 0 5; #X connect 7 0 0 6; #X connect 8 0 0 7; #X connect 9 0 0 8; #X connect 15 0 24 0; #X connect 15 1 25 0; #X connect 15 2 26 0; #X connect 15 3 27 0; #X connect 15 4 28 0; #X connect 16 0 15 1; #X connect 17 0 15 2; #X connect 18 0 15 3; #X connect 19 0 15 4; #X connect 20 0 15 5; #X connect 21 0 15 6; #X connect 22 0 15 7; #X connect 23 0 15 8; mrpeach/cmos/cd4071-help.pd0000644000175000017500000000067111026462102016043 0ustar zmoelnigzmoelnig#N canvas 670 174 458 212 12; #X obj 86 82 tgl 15 0 empty empty empty 17 7 0 10 -24198 -258699 -1 0 1; #X obj 129 83 tgl 15 0 empty empty empty 17 7 0 10 -24198 -258699 -1 0 1; #X obj 86 137 tgl 15 0 empty empty empty 17 7 0 10 -258699 -241291 -1 0 1; #X text 167 138 20070308_Martin_Peach; #X text 18 47 cd4071 emulates 1/4 of the CMOS OR gate; #X obj 86 107 cd4071; #X connect 0 0 5 0; #X connect 1 0 5 1; #X connect 5 0 2 0; mrpeach/cmos/cd4011-help.pd0000644000175000017500000000071211026462102016031 0ustar zmoelnigzmoelnig#N canvas 670 174 490 244 12; #X obj 86 82 tgl 15 1 empty empty empty 17 7 0 10 -24198 -258699 -1 1 1; #X obj 169 82 tgl 15 1 empty empty empty 17 7 0 10 -24198 -258699 -1 1 1; #X obj 86 137 tgl 15 0 empty empty empty 17 7 0 10 -258699 -241291 -1 0 1; #X text 210 170 20070315_Martin_Peach; #X text 16 29 cd4011 emulates 1/4 of the CMOS two-input NAND gate; #X obj 86 106 cd4011 nand; #X connect 0 0 5 0; #X connect 1 0 5 1; #X connect 5 0 2 0; mrpeach/cmos/cd4072-help.pd0000644000175000017500000000121011026462102016032 0ustar zmoelnigzmoelnig#N canvas 670 174 470 224 12; #X obj 86 82 tgl 15 0 empty empty empty 17 7 0 10 -24198 -258699 -1 0 1; #X obj 121 82 tgl 15 0 empty empty empty 17 7 0 10 -24198 -258699 -1 0 1; #X obj 86 137 tgl 15 0 empty empty empty 17 7 0 10 -258699 -241291 -1 0 1; #X obj 157 82 tgl 15 0 empty empty empty 17 7 0 10 -24198 -258699 -1 0 1; #X obj 193 82 tgl 15 0 empty empty empty 17 7 0 10 -24198 -258699 -1 0 1; #X text 210 170 20070312_Martin_Peach; #X text 18 47 cd4072 emulates 1/2 of the CMOS quad OR gate; #X obj 86 106 cd4072 quad or; #X connect 0 0 7 0; #X connect 1 0 7 1; #X connect 3 0 7 2; #X connect 4 0 7 3; #X connect 7 0 2 0; mrpeach/cmos/cd40193.c0000644000175000017500000001700012430236316015021 0ustar zmoelnigzmoelnig/* cd40193.c MP 20070312 */ /* Emulate a cd40193b */ #include "m_pd.h" typedef struct _cd40193 { t_object x_obj; t_outlet *x_QAOut; t_outlet *x_QBOut; t_outlet *x_QCOut; t_outlet *x_QDOut; t_outlet *x_CarryOut; t_outlet *x_BorrowOut; int x_countUp; int x_countDown; int x_dataA; int x_dataB; int x_dataC; int x_dataD; int x_load; int x_clear; int x_count; t_inlet *x_CountDownIn;/* All inlets take one or zero as acceptable inputs. */ t_inlet *x_ClearIn; t_inlet *x_LoadIn; t_inlet *x_DataAIn; t_inlet *x_DataBIn; t_inlet *x_DataCIn; t_inlet *x_DataDIn; /* The main inlet (clock) should accept a bang or a one as valid clocks. */ /* If a one is received, it must be followed by a zero before the clock will work again. */ } t_cd40193; static t_class *cd40193_class; void cd40193_setup(void); static void *cd40193_new(t_symbol *s, int argc, t_atom *argv); static void cd40193_free(t_cd40193 *x); static void cd40193_bang(t_cd40193 *x); static void cd40193_float(t_cd40193 *x, t_float f); static void cd40193_clear(t_cd40193 *x, t_float f); static void cd40193_load(t_cd40193 *x, t_float f); static void cd40193_count_down(t_cd40193 *x, t_float f); static void cd40193_data_A(t_cd40193 *x, t_float f); static void cd40193_data_B(t_cd40193 *x, t_float f); static void cd40193_data_C(t_cd40193 *x, t_float f); static void cd40193_data_D(t_cd40193 *x, t_float f); static void cd40193_update_outlets(t_cd40193 *x); static void cd40193_float(t_cd40193 *x, t_float f) { if (f == 1) { /* if clock is high and was low, count up. */ if ((x->x_countUp == 0)&&(x->x_countDown == 1)&&(x->x_clear == 0)&&(x->x_load == 1)) { x->x_countUp = 1; x->x_count = (x->x_count + 1)%16; cd40193_update_outlets(x); } } else if (f == 0) { if ((x->x_countUp == 1) && (x->x_count == 15)) outlet_float(x->x_CarryOut, 0); x->x_countUp = 0; } else post("cd40193 accepts bang, 1 or 0."); } static void cd40193_bang(t_cd40193 *x) { if ((x->x_countDown == 1)&&(x->x_clear == 0)&&(x->x_load == 1)) { x->x_countUp = 1; x->x_count = (x->x_count + 1)%16; cd40193_update_outlets(x); if (x->x_count == 15) outlet_float(x->x_CarryOut, 0); } } static void cd40193_clear(t_cd40193 *x, t_float f) { if (f == 1) { if (x->x_clear == 0) { x->x_count = 0; cd40193_update_outlets(x); x->x_clear = 1; } } else if (f == 0) { x->x_clear = 0; if (x->x_load == 0) { /* the strange case of a low-going clear enabling an already low load */ x->x_count = x->x_dataA + 2*x->x_dataB + 4*x->x_dataC + 8*x->x_dataD; cd40193_update_outlets(x); } } else { post("cd40193 clear takes 1 or 0 only."); return; } } static void cd40193_load(t_cd40193 *x, t_float f) { if (f == 1) { x->x_load = 1; } else if (f == 0) { if (x->x_load == 1) { x->x_load = 0; if (x->x_clear == 0) { x->x_count = x->x_dataA + 2*x->x_dataB + 4*x->x_dataC + 8*x->x_dataD; cd40193_update_outlets(x); } } } else { post("cd40193 load takes 1 or 0 only."); return; } } static void cd40193_count_down(t_cd40193 *x, t_float f) { if (f == 1) { /* if clock is high and was low, count down. */ if (x->x_countDown == 0) { x->x_countDown = 1; if((x->x_countUp == 1)&&(x->x_clear == 0)&&(x->x_load = 1)) { x->x_count = (x->x_count - 1)%16; cd40193_update_outlets(x); } } } else if (f == 0) { if ((x->x_countDown == 1) && (x->x_count == 0)) outlet_float(x->x_BorrowOut, 0); x->x_countDown = 0; } else post("cd40193 count down accepts bang, 1 or 0."); } static void cd40193_data_A(t_cd40193 *x, t_float f) { if (f == 1) x->x_dataA = 1; else if (f == 0) x->x_dataA = 0; else { post("cd40193 data A takes 1 or 0 only."); return; } } static void cd40193_data_B(t_cd40193 *x, t_float f) { if (f == 1) x->x_dataB = 1; else if (f == 0) x->x_dataB = 0; else { post("cd40193 data B takes 1 or 0 only."); return; } } static void cd40193_data_C(t_cd40193 *x, t_float f) { if (f == 1) x->x_dataC = 1; else if (f == 0) x->x_dataC = 0; else { post("cd40193 data C takes 1 or 0 only."); return; } } static void cd40193_data_D(t_cd40193 *x, t_float f) { if (f == 1) x->x_dataD = 1; else if (f == 0) x->x_dataD = 0; else { post("cd40193 data D takes 1 or 0 only."); return; } } static void cd40193_update_outlets(t_cd40193 *x) { outlet_float(x->x_BorrowOut, 1); outlet_float(x->x_CarryOut, 1); outlet_float(x->x_QDOut, ((x->x_count & 8) != 0)?1:0); outlet_float(x->x_QCOut, ((x->x_count & 4) != 0)?1:0); outlet_float(x->x_QBOut, ((x->x_count & 2) != 0)?1:0); outlet_float(x->x_QAOut, ((x->x_count & 1) != 0)?1:0); } static void cd40193_free(t_cd40193 *x) { return; } static void *cd40193_new(t_symbol *s, int argc, t_atom *argv) { t_cd40193 *x; x = (t_cd40193 *)pd_new(cd40193_class); if (x == NULL) return (x); x->x_QAOut = outlet_new((t_object *)x, &s_float); x->x_QBOut = outlet_new((t_object *)x, &s_float); x->x_QCOut = outlet_new((t_object *)x, &s_float); x->x_QDOut = outlet_new((t_object *)x, &s_float); x->x_CarryOut = outlet_new((t_object *)x, &s_float); x->x_BorrowOut = outlet_new((t_object *)x, &s_float); x->x_CountDownIn = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("countdown")); x->x_ClearIn = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("clear")); x->x_LoadIn = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("load")); x->x_DataAIn = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("dataA")); x->x_DataBIn = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("dataB")); x->x_DataCIn = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("dataC")); x->x_DataDIn = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("dataD")); return (x); } void cd40193_setup(void) { cd40193_class = class_new(gensym("cd40193"), (t_newmethod)cd40193_new, (t_method)cd40193_free, sizeof(t_cd40193), 0, 0); /* no arguments */ class_addbang(cd40193_class, cd40193_bang); class_addfloat(cd40193_class, cd40193_float); class_addmethod(cd40193_class, (t_method)cd40193_count_down, gensym("countdown"), A_FLOAT, 0); class_addmethod(cd40193_class, (t_method)cd40193_load, gensym("load"), A_FLOAT, 0); class_addmethod(cd40193_class, (t_method)cd40193_clear, gensym("clear"), A_FLOAT, 0); class_addmethod(cd40193_class, (t_method)cd40193_data_A, gensym("dataA"), A_FLOAT, 0); class_addmethod(cd40193_class, (t_method)cd40193_data_B, gensym("dataB"), A_FLOAT, 0); class_addmethod(cd40193_class, (t_method)cd40193_data_C, gensym("dataC"), A_FLOAT, 0); class_addmethod(cd40193_class, (t_method)cd40193_data_D, gensym("dataD"), A_FLOAT, 0); } /* end cd40193.c */ mrpeach/cmos/cd4013.c0000644000175000017500000001232512430236316014735 0ustar zmoelnigzmoelnig/* cd4013.c MP 20070306 */ /* Emulate a cd4013b */ #include "m_pd.h" typedef struct _cd4013 { t_object x_obj; int x_state;/* set = bit0, clock = bit1, reset = bit2 j = bit3 k = bit4 q = bit 5 */ t_outlet *x_Q; t_outlet *x_notQ; t_inlet *x_set;/* set takes one or zero as acceptable inputs. */ t_inlet *x_reset;/* reset takes one or zero as acceptable inputs. */ t_inlet *x_d;/* d takes one or zero as acceptable inputs. */ /* The main inlet (clock) should accept a bang or a one as valid clocks. */ /* If a one is received, it must be followed by a zero before the clock will work again. */ } t_cd4013; #define SET_4013 1 #define CLOCK_4013 2 #define RESET_4013 4 #define D_4013 8 #define Q_4013 16 #define UPDATING_4013 32 #define CHANGED_4013 64 static t_class *cd4013_class; void cd4013_setup(void); static void *cd4013_new(t_symbol *s, int argc, t_atom *argv); static void cd4013_free(t_cd4013 *x); static void cd4013_bang(t_cd4013 *x); static void cd4013_float(t_cd4013 *x, t_float f); static void cd4013_set(t_cd4013 *x, t_float f); static void cd4013_reset(t_cd4013 *x, t_float f); static void cd4013_d(t_cd4013 *x, t_float f); static void cd4013_update_outlets(t_cd4013 *x); static void cd4013_printstate (t_cd4013 *x); static void cd4013_float(t_cd4013 *x, t_float f) { if (f == 1) { /* if clock is high and was low, clock it. */ if ((x->x_state & CLOCK_4013) == 0) cd4013_bang(x); x->x_state |= CLOCK_4013; } else if (f == 0) x->x_state &= ~CLOCK_4013; else post("cd4013 accepts bang, 1 or 0."); } static void cd4013_printstate (t_cd4013 *x) { post ("SET %d RESET %d D %d Q %d", ((x->x_state & SET_4013) != 0)?1:0 , ((x->x_state & RESET_4013) != 0)?1:0 , ((x->x_state & D_4013) != 0)?1:0 , ((x->x_state & Q_4013) != 0)?1:0); } static void cd4013_bang(t_cd4013 *x) { if ((x->x_state & (SET_4013 | RESET_4013)) == 0) { /* if set is low and reset is low, clock forward */ if ((x->x_state & D_4013) != 0) x->x_state |= Q_4013; else x->x_state &= ~Q_4013; cd4013_update_outlets(x); } } static void cd4013_set(t_cd4013 *x, t_float f) { if (f == 1) { x->x_state |= SET_4013; /* set = 1 */ } else if (f == 0) { x->x_state &= ~SET_4013; /* set = 0 */ } else { post("cd4013 set takes 1 or 0 only."); return; } /* update outlets if not already doing that */ if ((x->x_state & UPDATING_4013) == 0) { cd4013_update_outlets(x); } else { x->x_state |= CHANGED_4013; } return; } static void cd4013_reset(t_cd4013 *x, t_float f) { if (f == 1) { x->x_state |= RESET_4013; /* reset = 1 */ } else if (f == 0) { x->x_state &= ~RESET_4013; /* reset = 0 */ } else { return; } /* update outlets if not already doing that */ if ((x->x_state & UPDATING_4013) == 0) { cd4013_update_outlets(x); } else { x->x_state |= CHANGED_4013; } return; } static void cd4013_d(t_cd4013 *x, t_float f) { if (f == 1) { x->x_state |= D_4013; /* d = 1 */ } else if (f == 0) { x->x_state &= ~D_4013; /* d = 0 */ } else post("cd4013 d takes 1 or 0 only."); return; } static void cd4013_update_outlets(t_cd4013 *x) { /* cd4013_printstate (x); */ x->x_state |= UPDATING_4013;/* updating outlets */ reset: if ((x->x_state & SET_4013) != 0) x->x_state |= Q_4013; else if ((x->x_state & RESET_4013) != 0) x->x_state &= ~Q_4013; x->x_state &= ~CHANGED_4013; /* prepare to flag any changes that occur during outlet_update */ outlet_float(x->x_notQ, ((x->x_state & Q_4013) == 0)?1:0); /* we might get set or reset as a result of feedback from one of these outlets. */ if ((x->x_state & CHANGED_4013) != 0) goto reset; outlet_float(x->x_Q, ((x->x_state & Q_4013) != 0)?1:0); if ((x->x_state & CHANGED_4013) != 0) goto reset; x->x_state &= ~UPDATING_4013;/* finished updating outlets */ } static void cd4013_free(t_cd4013 *x) { return; } static void *cd4013_new(t_symbol *s, int argc, t_atom *argv) { t_cd4013 *x; x = (t_cd4013 *)pd_new(cd4013_class); if (x == NULL) return (x); x->x_Q = outlet_new((t_object *)x, &s_float); x->x_notQ = outlet_new((t_object *)x, &s_float); x->x_set = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("set")); x->x_reset = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("reset")); x->x_d = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("d")); return (x); } void cd4013_setup(void) { cd4013_class = class_new(gensym("cd4013"), (t_newmethod)cd4013_new, (t_method)cd4013_free, sizeof(t_cd4013), 0, 0); /* no arguments */ class_addbang(cd4013_class, cd4013_bang); class_addfloat(cd4013_class, cd4013_float); class_addmethod(cd4013_class, (t_method)cd4013_reset, gensym("reset"), A_FLOAT, 0); class_addmethod(cd4013_class, (t_method)cd4013_set, gensym("set"), A_FLOAT, 0); class_addmethod(cd4013_class, (t_method)cd4013_d, gensym("d"), A_FLOAT, 0); } /* end cd4013.c */ mrpeach/cmos/cd4001.c0000644000175000017500000000411112430236316014724 0ustar zmoelnigzmoelnig/* cd4001.c MP 20070312 */ /* Emulate a cd4001b */ #include "m_pd.h" typedef struct _cd4001 { t_object x_obj; int x_in1; int x_in2; t_outlet *x_out; t_inlet *x_inlet2;/* Second inlet is 'live' like the first */ } t_cd4001; static t_class *cd4001_class; void cd4001_setup(void); static void *cd4001_new(t_symbol *s, int argc, t_atom *argv); static void cd4001_free(t_cd4001 *x); static void cd4001_bang(t_cd4001 *x); static void cd4001_float(t_cd4001 *x, t_float f); static void cd4001_inlet2(t_cd4001 *x, t_float f); static void cd4001_update_outlets(t_cd4001 *x); static void cd4001_float(t_cd4001 *x, t_float f) { if (f == 1) x->x_in1 = 1; else if (f == 0) x->x_in1 = 0; else { post("cd4001 inlet 2 accepts 1 or 0."); return; } cd4001_update_outlets(x); } static void cd4001_bang(t_cd4001 *x) { cd4001_update_outlets(x); } static void cd4001_inlet2(t_cd4001 *x, t_float f) { if (f == 1) x->x_in2 = 1; else if (f == 0) x->x_in2 = 0; else { post("cd4001 inlet 2 accepts 1 or 0."); return; } cd4001_update_outlets(x); } static void cd4001_update_outlets(t_cd4001 *x) { /* Double NOR function */ outlet_float(x->x_out, ((x->x_in1 + x->x_in2) != 0)?0:1); } static void cd4001_free(t_cd4001 *x) { return; } static void *cd4001_new(t_symbol *s, int argc, t_atom *argv) { t_cd4001 *x; x = (t_cd4001 *)pd_new(cd4001_class); if (x == NULL) return (x); x->x_out = outlet_new((t_object *)x, &s_float); x->x_inlet2 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("inlet2")); return (x); } void cd4001_setup(void) { cd4001_class = class_new(gensym("cd4001"), (t_newmethod)cd4001_new, (t_method)cd4001_free, sizeof(t_cd4001), 0, 0); /* no arguments */ class_addbang(cd4001_class, cd4001_bang); class_addfloat(cd4001_class, cd4001_float); class_addmethod(cd4001_class, (t_method)cd4001_inlet2, gensym("inlet2"), A_FLOAT, 0); } /* end cd4001.c */ mrpeach/cmos/cd4002-help.pd0000644000175000017500000000121311026462102016026 0ustar zmoelnigzmoelnig#N canvas 670 174 490 244 12; #X obj 86 82 tgl 15 1 empty empty empty 17 7 0 10 -24198 -258699 -1 0 1; #X obj 111 82 tgl 15 1 empty empty empty 17 7 0 10 -24198 -258699 -1 0 1; #X obj 86 137 tgl 15 0 empty empty empty 17 7 0 10 -258699 -241291 -1 1 1; #X text 210 170 20070315_Martin_Peach; #X obj 86 106 cd4002 nor; #X obj 136 82 tgl 15 1 empty empty empty 17 7 0 10 -24198 -258699 -1 0 1; #X obj 161 82 tgl 15 1 empty empty empty 17 7 0 10 -24198 -258699 -1 0 1; #X text 16 29 cd4002 emulates 1/2 of the CMOS four-input NOR gate; #X connect 0 0 4 0; #X connect 1 0 4 1; #X connect 4 0 2 0; #X connect 5 0 4 2; #X connect 6 0 4 3; mrpeach/cmos/cd40193-help.pd0000644000175000017500000000563211026462102016132 0ustar zmoelnigzmoelnig#N canvas 406 127 739 406 12; #X obj 75 5 cd40193 up down counter; #X obj 75 -53 tgl 15 1 empty empty up_clock 17 7 0 10 -44926 -258699 -1 1 1; #X obj 100 -37 tgl 15 1 empty empty down_clock 17 7 0 10 -44926 -258699 -1 1 1; #X obj 126 -88 tgl 15 1 empty empty clear 17 7 0 10 -44926 -258699 -1 0 1; #X obj 151 -111 tgl 15 1 empty empty load 17 7 0 10 -44926 -258699 -1 1 1; #X obj 177 -24 tgl 15 0 empty empty A 17 7 0 10 -260818 -258699 -1 0 1; #X obj 202 -24 tgl 15 0 empty empty B 17 7 0 10 -260818 -258699 -1 0 1; #X obj 228 -24 tgl 15 0 empty empty C 17 7 0 10 -260818 -258699 -1 0 1; #X obj 254 -24 tgl 15 0 empty empty D 17 7 0 10 -260818 -258699 -1 0 1; #X obj 75 47 tgl 15 0 empty empty QA 17 7 0 10 -24198 -258699 -1 1 1; #X obj 110 47 tgl 15 0 empty empty QB 17 7 0 10 -24198 -258699 -1 1 1; #X obj 146 47 tgl 15 0 empty empty QC 17 7 0 10 -24198 -258699 -1 1 1; #X obj 182 47 tgl 15 0 empty empty QD 17 7 0 10 -24198 -258699 -1 1 1; #X obj 218 29 tgl 15 0 empty empty Carry 17 7 0 10 -62784 -258699 -1 1 1; #X obj 254 47 tgl 15 0 empty empty Borrow 17 7 0 10 -62784 -258699 -1 1 1; #X obj 349 106 cd40193 up down counter; #X obj 451 77 tgl 15 0 empty empty A 17 7 0 10 -260818 -258699 -1 0 1; #X obj 476 77 tgl 15 0 empty empty B 17 7 0 10 -260818 -258699 -1 0 1; #X obj 502 77 tgl 15 0 empty empty C 17 7 0 10 -260818 -258699 -1 0 1; #X obj 528 77 tgl 15 0 empty empty D 17 7 0 10 -260818 -258699 -1 0 1; #X obj 349 148 tgl 15 0 empty empty QA 17 7 0 10 -24198 -258699 -1 1 1; #X obj 384 148 tgl 15 0 empty empty QB 17 7 0 10 -24198 -258699 -1 1 1; #X obj 420 148 tgl 15 0 empty empty QC 17 7 0 10 -24198 -258699 -1 1 1; #X obj 456 148 tgl 15 0 empty empty QD 17 7 0 10 -24198 -258699 -1 0 1; #X obj 492 130 tgl 15 0 empty empty Carry 17 7 0 10 -62784 -258699 -1 1 1; #X obj 528 148 tgl 15 0 empty empty Borrow 17 7 0 10 -62784 -258699 -1 1 1; #X text 32 -155 cd40193 emulates the CMOS synchronous up/down counter ; #X text 212 -113 0 loads data into counter; #X text 197 -90 1 clears counter; #X text 202 -65 0 to 1 transition on a clock counts only if the other clock = 1 and clear = 0 and load = 1; #X text 285 204 20070314_MartinPeach; #X obj 9 -121 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1; #X obj 9 -89 metro 100; #X connect 0 0 9 0; #X connect 0 1 10 0; #X connect 0 2 11 0; #X connect 0 3 12 0; #X connect 0 4 13 0; #X connect 0 4 15 0; #X connect 0 5 14 0; #X connect 0 5 15 1; #X connect 1 0 0 0; #X connect 2 0 0 1; #X connect 3 0 0 2; #X connect 3 0 15 2; #X connect 4 0 0 3; #X connect 4 0 15 3; #X connect 5 0 0 4; #X connect 6 0 0 5; #X connect 7 0 0 6; #X connect 8 0 0 7; #X connect 15 0 20 0; #X connect 15 1 21 0; #X connect 15 2 22 0; #X connect 15 3 23 0; #X connect 15 4 24 0; #X connect 15 5 25 0; #X connect 16 0 15 4; #X connect 17 0 15 5; #X connect 18 0 15 6; #X connect 19 0 15 7; #X connect 31 0 32 0; #X connect 32 0 1 0; mrpeach/cmos/cd4014.c0000644000175000017500000001573412430236316014745 0ustar zmoelnigzmoelnig/* cd4014.c MP 20070315 */ /* Emulate a cd4014b */ #include "m_pd.h" typedef struct _cd4014 { t_object x_obj; int x_P1; int x_P2; int x_P3; int x_P4; int x_P5; int x_P6; int x_P7; int x_P8; int x_SerialIn; int x_Clk; int x_Q; int x_ParallelSerial; t_outlet *x_outQ6; t_outlet *x_outQ7; t_outlet *x_outQ8; t_inlet *x_inP1;/* extra inlets are 'live' like the first */ t_inlet *x_inP2; t_inlet *x_inP3; t_inlet *x_inP4; t_inlet *x_inP5; t_inlet *x_inP6; t_inlet *x_inP7; t_inlet *x_inP8; t_inlet *x_inParallelSerial; t_inlet *x_inSerial; } t_cd4014; static t_class *cd4014_class; void cd4014_setup(void); static void *cd4014_new(t_symbol *s, int argc, t_atom *argv); static void cd4014_free(t_cd4014 *x); static void cd4014_float(t_cd4014 *x, t_float f); static void cd4014_bang(t_cd4014 *x); static void cd4014_inP1(t_cd4014 *x, t_float f); static void cd4014_inP2(t_cd4014 *x, t_float f); static void cd4014_inP3(t_cd4014 *x, t_float f); static void cd4014_inP4(t_cd4014 *x, t_float f); static void cd4014_inP5(t_cd4014 *x, t_float f); static void cd4014_inP6(t_cd4014 *x, t_float f); static void cd4014_inP7(t_cd4014 *x, t_float f); static void cd4014_inP8(t_cd4014 *x, t_float f); static void cd4014_inParallelSerial(t_cd4014 *x, t_float f); static void cd4014_inSerial(t_cd4014 *x, t_float f); static void cd4014_update_outlets(t_cd4014 *x); static void cd4014_float(t_cd4014 *x, t_float f) { if (f == 1) { if (x->x_Clk == 0) { x->x_Clk = 1; cd4014_bang(x); } } else if (f == 0) x->x_Clk = 0; else { post("cd4014 Clock inlet accepts 1 or 0."); return; } } static void cd4014_bang(t_cd4014 *x) { if (x->x_ParallelSerial == 0) { /* shift left by one */ x->x_Q <<= 1; x->x_Q |= x->x_SerialIn; } else { /* parallel load */ x->x_Q = 128*x->x_P8 + 64*x->x_P7 + 32*x->x_P6 + 16*x->x_P5 + 8*x->x_P4 + 4*x->x_P3 + 2*x->x_P2 + x->x_P1; } cd4014_update_outlets(x); } static void cd4014_inP1(t_cd4014 *x, t_float f) { if (f == 1) x->x_P1 = 1; else if (f == 0) x->x_P1 = 0; else { post("cd4014 inlet P1 accepts 1 or 0."); return; } } static void cd4014_inP2(t_cd4014 *x, t_float f) { if (f == 1) x->x_P2 = 2; else if (f == 0) x->x_P2 = 0; else { post("cd4014 inlet P2 accepts 1 or 0."); return; } } static void cd4014_inP3(t_cd4014 *x, t_float f) { if (f == 1) x->x_P3 = 1; else if (f == 0) x->x_P3 = 0; else { post("cd4014 inlet P3 accepts 1 or 0."); return; } } static void cd4014_inP4(t_cd4014 *x, t_float f) { if (f == 1) x->x_P4 = 1; else if (f == 0) x->x_P4 = 0; else { post("cd4014 inlet P4 accepts 1 or 0."); return; } } static void cd4014_inP5(t_cd4014 *x, t_float f) { if (f == 1) x->x_P5 = 1; else if (f == 0) x->x_P5 = 0; else { post("cd4014 inlet P5 accepts 1 or 0."); return; } } static void cd4014_inP6(t_cd4014 *x, t_float f) { if (f == 1) x->x_P6 = 1; else if (f == 0) x->x_P6 = 0; else { post("cd4014 inlet P6 accepts 1 or 0."); return; } } static void cd4014_inP7(t_cd4014 *x, t_float f) { if (f == 1) x->x_P7 = 1; else if (f == 0) x->x_P7 = 0; else { post("cd4014 inlet P7 accepts 1 or 0."); return; } } static void cd4014_inP8(t_cd4014 *x, t_float f) { if (f == 1) x->x_P8 = 1; else if (f == 0) x->x_P8 = 0; else { post("cd4014 inlet P8 accepts 1 or 0."); return; } } static void cd4014_inParallelSerial(t_cd4014 *x, t_float f) { if (f == 1) x->x_ParallelSerial = 1; else if (f == 0) x->x_ParallelSerial = 0; else { post("cd4014 inlet ParallelSerial accepts 1 or 0."); return; } } static void cd4014_inSerial(t_cd4014 *x, t_float f) { if (f == 1) x->x_SerialIn = 1; else if (f == 0) x->x_SerialIn = 0; else { post("cd4014 inlet Serial accepts 1 or 0."); return; } } static void cd4014_update_outlets(t_cd4014 *x) { /* Output Q8, Q7, Q6 */ outlet_float(x->x_outQ8, ((x->x_Q & 128) != 0)?1:0); outlet_float(x->x_outQ7, ((x->x_Q & 64) != 0)?1:0); outlet_float(x->x_outQ6, ((x->x_Q & 32) != 0)?1:0); } static void cd4014_free(t_cd4014 *x) { return; } static void *cd4014_new(t_symbol *s, int argc, t_atom *argv) { t_cd4014 *x; x = (t_cd4014 *)pd_new(cd4014_class); if (x == NULL) return (x); x->x_outQ6 = outlet_new((t_object *)x, &s_float); x->x_outQ7 = outlet_new((t_object *)x, &s_float); x->x_outQ8 = outlet_new((t_object *)x, &s_float); x->x_inP1 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("P1")); x->x_inP2 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("P2")); x->x_inP3 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("P3")); x->x_inP4 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("P4")); x->x_inP5 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("P5")); x->x_inP6 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("P6")); x->x_inP7 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("P7")); x->x_inP8 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("P8")); x->x_inParallelSerial = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ParallelSerial")); x->x_inSerial = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("Serial")); return (x); } void cd4014_setup(void) { cd4014_class = class_new(gensym("cd4014"), (t_newmethod)cd4014_new, (t_method)cd4014_free, sizeof(t_cd4014), 0, 0); /* no arguments */ class_addfloat(cd4014_class, cd4014_float); class_addbang(cd4014_class, cd4014_bang); class_addmethod(cd4014_class, (t_method)cd4014_inP1, gensym("P1"), A_FLOAT, 0); class_addmethod(cd4014_class, (t_method)cd4014_inP2, gensym("P2"), A_FLOAT, 0); class_addmethod(cd4014_class, (t_method)cd4014_inP3, gensym("P3"), A_FLOAT, 0); class_addmethod(cd4014_class, (t_method)cd4014_inP4, gensym("P4"), A_FLOAT, 0); class_addmethod(cd4014_class, (t_method)cd4014_inP5, gensym("P5"), A_FLOAT, 0); class_addmethod(cd4014_class, (t_method)cd4014_inP6, gensym("P6"), A_FLOAT, 0); class_addmethod(cd4014_class, (t_method)cd4014_inP7, gensym("P7"), A_FLOAT, 0); class_addmethod(cd4014_class, (t_method)cd4014_inP8, gensym("P8"), A_FLOAT, 0); class_addmethod(cd4014_class, (t_method)cd4014_inParallelSerial, gensym("ParallelSerial"), A_FLOAT, 0); class_addmethod(cd4014_class, (t_method)cd4014_inSerial, gensym("Serial"), A_FLOAT, 0); } /* end cd4014.c */ mrpeach/cmos/cd4015.c0000644000175000017500000000616412430236316014743 0ustar zmoelnigzmoelnig/* cd4015.c MP 20070315 */ /* Emulate a cd4015b */ #include "m_pd.h" typedef struct _cd4015 { t_object x_obj; int x_D; int x_R; int x_Clk; int x_Q; t_outlet *x_outQ1; t_outlet *x_outQ2; t_outlet *x_outQ3; t_outlet *x_outQ4; t_inlet *x_inD;/* extra inlets are 'live' like the first */ t_inlet *x_inR; } t_cd4015; static t_class *cd4015_class; void cd4015_setup(void); static void *cd4015_new(t_symbol *s, int argc, t_atom *argv); static void cd4015_free(t_cd4015 *x); static void cd4015_float(t_cd4015 *x, t_float f); static void cd4015_bang(t_cd4015 *x); static void cd4015_inD(t_cd4015 *x, t_float f); static void cd4015_inR(t_cd4015 *x, t_float f); static void cd4015_update_outlets(t_cd4015 *x); static void cd4015_float(t_cd4015 *x, t_float f) { if (f == 1) { if (x->x_Clk == 0) { x->x_Clk = 1; cd4015_bang(x); } } else if (f == 0) x->x_Clk = 0; else { post("cd4015 Clock inlet accepts 1 or 0."); return; } } static void cd4015_bang(t_cd4015 *x) { if (x->x_R == 0) { /* shift left by one */ x->x_Q <<= 1; x->x_Q |= x->x_D; cd4015_update_outlets(x); } } static void cd4015_inD(t_cd4015 *x, t_float f) { if (f == 1) x->x_D = 1; else if (f == 0) x->x_D = 0; else { post("cd4015 D inlet accepts 1 or 0."); return; } } static void cd4015_inR(t_cd4015 *x, t_float f) { if (f == 1) { x->x_R = 1; x->x_Q = 0; cd4015_update_outlets(x); } else if (f == 0) x->x_R = 0; else { post("cd4015 R inlet accepts 1 or 0."); return; } } static void cd4015_update_outlets(t_cd4015 *x) { outlet_float(x->x_outQ4, ((x->x_Q & 8) != 0)?1:0); outlet_float(x->x_outQ3, ((x->x_Q & 4) != 0)?1:0); outlet_float(x->x_outQ2, ((x->x_Q & 2) != 0)?1:0); outlet_float(x->x_outQ1, ((x->x_Q & 1) != 0)?1:0); } static void cd4015_free(t_cd4015 *x) { return; } static void *cd4015_new(t_symbol *s, int argc, t_atom *argv) { t_cd4015 *x; x = (t_cd4015 *)pd_new(cd4015_class); if (x == NULL) return (x); x->x_outQ1 = outlet_new((t_object *)x, &s_float); x->x_outQ2 = outlet_new((t_object *)x, &s_float); x->x_outQ3 = outlet_new((t_object *)x, &s_float); x->x_outQ4 = outlet_new((t_object *)x, &s_float); x->x_inD = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("D")); x->x_inR = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("R")); return (x); } void cd4015_setup(void) { cd4015_class = class_new(gensym("cd4015"), (t_newmethod)cd4015_new, (t_method)cd4015_free, sizeof(t_cd4015), 0, 0); /* no arguments */ class_addfloat(cd4015_class, cd4015_float); class_addbang(cd4015_class, cd4015_bang); class_addmethod(cd4015_class, (t_method)cd4015_inD, gensym("D"), A_FLOAT, 0); class_addmethod(cd4015_class, (t_method)cd4015_inR, gensym("R"), A_FLOAT, 0); } /* end cd4015.c */ mrpeach/cmos/cd4024.c0000644000175000017500000000740012430236316014735 0ustar zmoelnigzmoelnig/* cd4024.c MP 20070319 */ /* Emulate a cd4024b */ #include "m_pd.h" typedef struct _cd4024 { t_object x_obj; int x_reset; int x_clock; int x_count; int x_updating; t_outlet *x_Q1; t_outlet *x_Q2; t_outlet *x_Q3; t_outlet *x_Q4; t_outlet *x_Q5; t_outlet *x_Q6; t_outlet *x_Q7; t_inlet *x_resetIn;/* reset */ /* The main inlet (clcok) should accept a bang or a one as valid clocks. */ /* If a one is received, it must be followed by a zero before the clock will work again. */ } t_cd4024; static t_class *cd4024_class; void cd4024_setup(void); static void *cd4024_new(t_symbol *s, int argc, t_atom *argv); static void cd4024_free(t_cd4024 *x); static void cd4024_bang(t_cd4024 *x); static void cd4024_float(t_cd4024 *x, t_float f); static void cd4024_reset(t_cd4024 *x, t_float f); static void cd4024_update_outlets(t_cd4024 *x); static void cd4024_float(t_cd4024 *x, t_float f) { if (f == 0) { /* if clock is low and was high, clock it. */ if (x->x_clock == 1) { x->x_clock = 0; cd4024_bang(x); } } else if (f == 1) x->x_clock = 1; else post("cd4024 clock accepts bang, 1 or 0."); } static void cd4024_bang(t_cd4024 *x) { if (x->x_reset == 0) { /* if reset is low, clock forward */ x->x_count = (x->x_count + 1)%128; cd4024_update_outlets(x); } } static void cd4024_reset(t_cd4024 *x, t_float f) { if (f == 1) { x->x_count = 0; x->x_reset = 1; if (x->x_updating != 0) x->x_updating |= 2; else cd4024_update_outlets(x); } else if (f == 0) x->x_reset = 0; } static void cd4024_update_outlets(t_cd4024 *x) { reset: x->x_updating = 1;/* updating outlets */ outlet_float(x->x_Q7, ((x->x_count & 64) != 0)?1:0); /* we might get reset as a result of feedback from one of these outlets. */ if ((x->x_updating & 2) != 0) goto reset; outlet_float(x->x_Q6, ((x->x_count & 32) != 0)?1:0); if ((x->x_updating & 2) != 0) goto reset; outlet_float(x->x_Q5, ((x->x_count & 16) != 0)?1:0); if ((x->x_updating & 2) != 0) goto reset; outlet_float(x->x_Q4, ((x->x_count & 8) != 0)?1:0); if ((x->x_updating & 2) != 0) goto reset; outlet_float(x->x_Q3, ((x->x_count & 4) != 0)?1:0); if ((x->x_updating & 2) != 0) goto reset; outlet_float(x->x_Q2, ((x->x_count & 2) != 0)?1:0); if ((x->x_updating & 2) != 0) goto reset; outlet_float(x->x_Q1, ((x->x_count & 1) != 0)?1:0); if ((x->x_updating & 2) != 0) goto reset; x->x_updating = 0; /* finished updating outlets */ } static void cd4024_free(t_cd4024 *x) { return; } static void *cd4024_new(t_symbol *s, int argc, t_atom *argv) { t_cd4024 *x; x = (t_cd4024 *)pd_new(cd4024_class); if (x == NULL) return (x); x->x_Q1 = outlet_new((t_object *)x, &s_float); x->x_Q2 = outlet_new((t_object *)x, &s_float); x->x_Q3 = outlet_new((t_object *)x, &s_float); x->x_Q4 = outlet_new((t_object *)x, &s_float); x->x_Q5 = outlet_new((t_object *)x, &s_float); x->x_Q6 = outlet_new((t_object *)x, &s_float); x->x_Q7 = outlet_new((t_object *)x, &s_float); x->x_resetIn = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("reset")); return (x); } void cd4024_setup(void) { cd4024_class = class_new(gensym("cd4024"), (t_newmethod)cd4024_new, (t_method)cd4024_free, sizeof(t_cd4024), 0, 0); /* no arguments */ class_addbang(cd4024_class, cd4024_bang); class_addfloat(cd4024_class, cd4024_float); class_addmethod(cd4024_class, (t_method)cd4024_reset, gensym("reset"), A_FLOAT, 0); } /* end cd4024.c */ mrpeach/cmos/cd4071.c0000644000175000017500000000410112430236316014732 0ustar zmoelnigzmoelnig/* cd4071.c MP 20070308 */ /* Emulate a cd4071b */ #include "m_pd.h" typedef struct _cd4071 { t_object x_obj; int x_in1; int x_in2; t_outlet *x_out; t_inlet *x_inlet2;/* Second inlet is 'live' like the first */ } t_cd4071; static t_class *cd4071_class; void cd4071_setup(void); static void *cd4071_new(t_symbol *s, int argc, t_atom *argv); static void cd4071_free(t_cd4071 *x); static void cd4071_bang(t_cd4071 *x); static void cd4071_float(t_cd4071 *x, t_float f); static void cd4071_inlet2(t_cd4071 *x, t_float f); static void cd4071_update_outlets(t_cd4071 *x); static void cd4071_float(t_cd4071 *x, t_float f) { if (f == 1) x->x_in1 = 1; else if (f == 0) x->x_in1 = 0; else { post("cd4071 inlet 2 accepts 1 or 0."); return; } cd4071_update_outlets(x); } static void cd4071_bang(t_cd4071 *x) { cd4071_update_outlets(x); } static void cd4071_inlet2(t_cd4071 *x, t_float f) { if (f == 1) x->x_in2 = 1; else if (f == 0) x->x_in2 = 0; else { post("cd4071 inlet 2 accepts 1 or 0."); return; } cd4071_update_outlets(x); } static void cd4071_update_outlets(t_cd4071 *x) { /* OR function */ outlet_float(x->x_out, ((x->x_in1 + x->x_in2) != 0)?1:0); } static void cd4071_free(t_cd4071 *x) { return; } static void *cd4071_new(t_symbol *s, int argc, t_atom *argv) { t_cd4071 *x; x = (t_cd4071 *)pd_new(cd4071_class); if (x == NULL) return (x); x->x_out = outlet_new((t_object *)x, &s_float); x->x_inlet2 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("inlet2")); return (x); } void cd4071_setup(void) { cd4071_class = class_new(gensym("cd4071"), (t_newmethod)cd4071_new, (t_method)cd4071_free, sizeof(t_cd4071), 0, 0); /* no arguments */ class_addbang(cd4071_class, cd4071_bang); class_addfloat(cd4071_class, cd4071_float); class_addmethod(cd4071_class, (t_method)cd4071_inlet2, gensym("inlet2"), A_FLOAT, 0); } /* end cd4071.c */ mrpeach/cmos/cd4076.c0000644000175000017500000001764212430236316014755 0ustar zmoelnigzmoelnig/* cd4076.c MP 20070312 */ /* Emulate a cd4076b */ #include "m_pd.h" typedef struct _cd4076 { t_object x_obj; t_outlet *x_output_A; t_outlet *x_output_B; t_outlet *x_output_C; t_outlet *x_output_D; int x_clock; int x_QA; int x_QB; int x_QC; int x_QD; int x_inA; int x_inB; int x_inC; int x_inD; int x_InDis1; int x_InDis2; int x_OutDis1; int x_OutDis2; int x_Clear; t_inlet *x_clear;/* clear takes one or zero as acceptable inputs. */ t_inlet *x_input_disable_1;/* input_disable_1 takes one or zero as acceptable inputs. */ t_inlet *x_input_disable_2;/* input_disable_2 takes one or zero as acceptable inputs. */ t_inlet *x_output_disable_1;/* output_disable_1 takes one or zero as acceptable inputs. */ t_inlet *x_output_disable_2;/* output_disable_2 takes one or zero as acceptable inputs. */ t_inlet *x_input_A;/* input_A takes one or zero as acceptable inputs. */ t_inlet *x_input_B;/* input_B takes one or zero as acceptable inputs. */ t_inlet *x_input_C;/* input_C takes one or zero as acceptable inputs. */ t_inlet *x_input_D;/* input_D takes one or zero as acceptable inputs. */ /* The main inlet (clock) should accept a bang or a one as valid clocks. */ /* If a one is received, it must be followed by a zero before the clock will work again. */ } t_cd4076; static t_class *cd4076_class; void cd4076_setup(void); static void *cd4076_new(t_symbol *s, int argc, t_atom *argv); static void cd4076_free(t_cd4076 *x); static void cd4076_bang(t_cd4076 *x); static void cd4076_float(t_cd4076 *x, t_float f); static void cd4076_clear(t_cd4076 *x, t_float f); static void cd4076_input_disable_1(t_cd4076 *x, t_float f); static void cd4076_input_disable_2(t_cd4076 *x, t_float f); static void cd4076_output_disable_1(t_cd4076 *x, t_float f); static void cd4076_output_disable_2(t_cd4076 *x, t_float f); static void cd4076_input_a(t_cd4076 *x, t_float f); static void cd4076_input_b(t_cd4076 *x, t_float f); static void cd4076_input_c(t_cd4076 *x, t_float f); static void cd4076_input_d(t_cd4076 *x, t_float f); static void cd4076_update_outlets(t_cd4076 *x); static void cd4076_float(t_cd4076 *x, t_float f) { if (f == 1) { /* if clock is high and was low, clock it. */ if ((x->x_clock) == 0) cd4076_bang(x); x->x_clock = 1; } else if (f == 0) x->x_clock = 0; else post("cd4076 accepts bang, 1 or 0."); } static void cd4076_bang(t_cd4076 *x) { if ((x->x_InDis1 + x->x_InDis2 + x->x_Clear) == 0) { x->x_QA = x->x_inA; x->x_QB = x->x_inB; x->x_QC = x->x_inC; x->x_QD = x->x_inD; } cd4076_update_outlets(x); } static void cd4076_clear(t_cd4076 *x, t_float f) { if (f == 1) { x->x_Clear = 1; x->x_QA = 0; x->x_QB = 0; x->x_QC = 0; x->x_QD = 0; cd4076_update_outlets(x); } else if (f == 0) { x->x_Clear = 0; } else { post("cd4076 clear takes 1 or 0 only."); return; } } static void cd4076_input_disable_1(t_cd4076 *x, t_float f) { if (f == 1) x->x_InDis1 = 1; else if (f == 0) x->x_InDis1 = 0; else { post("cd4076 input disable 1 takes 1 or 0 only."); return; } } static void cd4076_input_disable_2(t_cd4076 *x, t_float f) { if (f == 1) x->x_InDis2 = 1; else if (f == 0) x->x_InDis2 = 0; else { post("cd4076 input disable 2 takes 1 or 0 only."); return; } } static void cd4076_output_disable_1(t_cd4076 *x, t_float f) { if (f == 1) x->x_OutDis1 = 1; else if (f == 0) { x->x_OutDis1 = 0; cd4076_update_outlets(x); } else { post("cd4076 output disable 1 takes 1 or 0 only."); return; } } static void cd4076_output_disable_2(t_cd4076 *x, t_float f) { if (f == 1) x->x_OutDis2 = 1; else if (f == 0) { x->x_OutDis2 = 0; cd4076_update_outlets(x); } else { post("cd4076 output disable 2 takes 1 or 0 only."); return; } } static void cd4076_input_a(t_cd4076 *x, t_float f) { if (f == 1) x->x_inA = 1; else if (f == 0) x->x_inA = 0; else { post("cd4076 input A takes 1 or 0 only."); return; } } static void cd4076_input_b(t_cd4076 *x, t_float f) { if (f == 1) x->x_inB = 1; else if (f == 0) x->x_inB = 0; else { post("cd4076 input B takes 1 or 0 only."); return; } } static void cd4076_input_c(t_cd4076 *x, t_float f) { if (f == 1) x->x_inC = 1; else if (f == 0) x->x_inC = 0; else { post("cd4076 input C takes 1 or 0 only."); return; } } static void cd4076_input_d(t_cd4076 *x, t_float f) { if (f == 1) x->x_inD = 1; else if (f == 0) x->x_inD = 0; else { post("cd4076 input D takes 1 or 0 only."); return; } } static void cd4076_update_outlets(t_cd4076 *x) { if (x->x_OutDis1 + x->x_OutDis2 == 0) { outlet_float(x->x_output_D, ((x->x_QD) == 1)?1:0); outlet_float(x->x_output_C, ((x->x_QC) == 1)?1:0); outlet_float(x->x_output_B, ((x->x_QB) == 1)?1:0); outlet_float(x->x_output_A, ((x->x_QA) == 1)?1:0); } } static void cd4076_free(t_cd4076 *x) { return; } static void *cd4076_new(t_symbol *s, int argc, t_atom *argv) { t_cd4076 *x; x = (t_cd4076 *)pd_new(cd4076_class); if (x == NULL) return (x); x->x_output_A = outlet_new((t_object *)x, &s_float); x->x_output_B = outlet_new((t_object *)x, &s_float); x->x_output_C = outlet_new((t_object *)x, &s_float); x->x_output_D = outlet_new((t_object *)x, &s_float); x->x_clear = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("clear")); x->x_input_disable_1 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("inputdisable1")); x->x_input_disable_2 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("inputdisable2")); x->x_output_disable_1 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("outputdisable1")); x->x_output_disable_2 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("outputdisable2")); x->x_input_A = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("inputA")); x->x_input_B = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("inputB")); x->x_input_C = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("inputC")); x->x_input_D = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("inputD")); return (x); } void cd4076_setup(void) { cd4076_class = class_new(gensym("cd4076"), (t_newmethod)cd4076_new, (t_method)cd4076_free, sizeof(t_cd4076), 0, 0); /* no arguments */ class_addbang(cd4076_class, cd4076_bang); class_addfloat(cd4076_class, cd4076_float); class_addmethod(cd4076_class, (t_method)cd4076_clear, gensym("clear"), A_FLOAT, 0); class_addmethod(cd4076_class, (t_method)cd4076_input_disable_1, gensym("inputdisable1"), A_FLOAT, 0); class_addmethod(cd4076_class, (t_method)cd4076_input_disable_2, gensym("inputdisable2"), A_FLOAT, 0); class_addmethod(cd4076_class, (t_method)cd4076_output_disable_1, gensym("outputdisable1"), A_FLOAT, 0); class_addmethod(cd4076_class, (t_method)cd4076_output_disable_2, gensym("outputdisable2"), A_FLOAT, 0); class_addmethod(cd4076_class, (t_method)cd4076_input_a, gensym("inputA"), A_FLOAT, 0); class_addmethod(cd4076_class, (t_method)cd4076_input_b, gensym("inputB"), A_FLOAT, 0); class_addmethod(cd4076_class, (t_method)cd4076_input_c, gensym("inputC"), A_FLOAT, 0); class_addmethod(cd4076_class, (t_method)cd4076_input_d, gensym("inputD"), A_FLOAT, 0); } /* end cd4076.c */ mrpeach/cmos/cd4024-help.pd0000644000175000017500000000202711026462102016036 0ustar zmoelnigzmoelnig#N canvas 627 296 564 304 12; #X obj 138 127 cd4024 7-stage counter; #X obj 138 103 tgl 15 0 empty empty Clk 17 7 0 10 -44926 -258699 -1 1 1; #X obj 309 103 tgl 15 0 empty empty Reset 17 7 0 10 -44926 -258699 -1 0 1; #X obj 138 174 tgl 15 0 empty empty Q1 17 7 0 10 -24198 -258699 -1 1 1; #X obj 170 174 tgl 15 0 empty empty Q2 17 7 0 10 -24198 -258699 -1 0 1; #X obj 202 174 tgl 15 0 empty empty Q3 17 7 0 10 -24198 -258699 -1 0 1; #X obj 234 174 tgl 15 0 empty empty Q4 17 7 0 10 -24198 -258699 -1 0 1; #X obj 267 174 tgl 15 0 empty empty Q5 17 7 0 10 -24198 -258699 -1 0 1; #X obj 300 174 tgl 15 0 empty empty Q6 17 7 0 10 -24198 -258699 -1 0 1; #X obj 334 174 tgl 15 0 empty empty Q7 17 7 0 10 -24198 -258699 -1 0 1; #X text 15 16 cd4024 emulates the CMOS 7-stage ripple carry binary counter; #X text 242 250 20070319_MartinPeach; #X connect 0 0 3 0; #X connect 0 1 4 0; #X connect 0 2 5 0; #X connect 0 3 6 0; #X connect 0 4 7 0; #X connect 0 5 8 0; #X connect 0 6 9 0; #X connect 1 0 0 0; #X connect 2 0 0 1; mrpeach/cmos/cd4023.c0000644000175000017500000000520612430236316014736 0ustar zmoelnigzmoelnig/* cd4023.c MP 20070312 */ /* Emulate a cd4023b */ #include "m_pd.h" typedef struct _cd4023 { t_object x_obj; int x_in1; int x_in2; int x_in3; t_outlet *x_out; t_inlet *x_inlet2;/* Second inlet is 'live' like the first */ t_inlet *x_inlet3;/* Third inlet is 'live' like the first */ } t_cd4023; static t_class *cd4023_class; void cd4023_setup(void); static void *cd4023_new(t_symbol *s, int argc, t_atom *argv); static void cd4023_free(t_cd4023 *x); static void cd4023_bang(t_cd4023 *x); static void cd4023_float(t_cd4023 *x, t_float f); static void cd4023_inlet2(t_cd4023 *x, t_float f); static void cd4023_inlet3(t_cd4023 *x, t_float f); static void cd4023_update_outlets(t_cd4023 *x); static void cd4023_float(t_cd4023 *x, t_float f) { if (f == 1) x->x_in1 = 1; else if (f == 0) x->x_in1 = 0; else { post("cd4023 inlet 2 accepts 1 or 0."); return; } cd4023_update_outlets(x); } static void cd4023_bang(t_cd4023 *x) { cd4023_update_outlets(x); } static void cd4023_inlet2(t_cd4023 *x, t_float f) { if (f == 1) x->x_in2 = 1; else if (f == 0) x->x_in2 = 0; else { post("cd4023 inlet 2 accepts 1 or 0."); return; } cd4023_update_outlets(x); } static void cd4023_inlet3(t_cd4023 *x, t_float f) { if (f == 1) x->x_in3 = 1; else if (f == 0) x->x_in3 = 0; else { post("cd4023 inlet 3 accepts 1 or 0."); return; } cd4023_update_outlets(x); } static void cd4023_update_outlets(t_cd4023 *x) { /* Triple NAND function */ outlet_float(x->x_out, ((x->x_in1 + x->x_in2 + x->x_in3) == 3)?0:1); } static void cd4023_free(t_cd4023 *x) { return; } static void *cd4023_new(t_symbol *s, int argc, t_atom *argv) { t_cd4023 *x; x = (t_cd4023 *)pd_new(cd4023_class); if (x == NULL) return (x); x->x_out = outlet_new((t_object *)x, &s_float); x->x_inlet2 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("inlet2")); x->x_inlet3 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("inlet3")); return (x); } void cd4023_setup(void) { cd4023_class = class_new(gensym("cd4023"), (t_newmethod)cd4023_new, (t_method)cd4023_free, sizeof(t_cd4023), 0, 0); /* no arguments */ class_addbang(cd4023_class, cd4023_bang); class_addfloat(cd4023_class, cd4023_float); class_addmethod(cd4023_class, (t_method)cd4023_inlet2, gensym("inlet2"), A_FLOAT, 0); class_addmethod(cd4023_class, (t_method)cd4023_inlet3, gensym("inlet3"), A_FLOAT, 0); } /* end cd4023.c */ mrpeach/cmos/cd4012.c0000644000175000017500000000616212430236316014736 0ustar zmoelnigzmoelnig/* cd4012.c MP 20070315 */ /* Emulate a cd4012b */ #include "m_pd.h" typedef struct _cd4012 { t_object x_obj; int x_in1; int x_in2; int x_in3; int x_in4; t_outlet *x_out; t_inlet *x_inlet2;/* extra inlets are 'live' like the first */ t_inlet *x_inlet3; t_inlet *x_inlet4; } t_cd4012; static t_class *cd4012_class; void cd4012_setup(void); static void *cd4012_new(t_symbol *s, int argc, t_atom *argv); static void cd4012_free(t_cd4012 *x); static void cd4012_bang(t_cd4012 *x); static void cd4012_float(t_cd4012 *x, t_float f); static void cd4012_inlet2(t_cd4012 *x, t_float f); static void cd4012_inlet3(t_cd4012 *x, t_float f); static void cd4012_inlet4(t_cd4012 *x, t_float f); static void cd4012_update_outlets(t_cd4012 *x); static void cd4012_float(t_cd4012 *x, t_float f) { if (f == 1) x->x_in1 = 1; else if (f == 0) x->x_in1 = 0; else { post("cd4012 inlet 2 accepts 1 or 0."); return; } cd4012_update_outlets(x); } static void cd4012_bang(t_cd4012 *x) { cd4012_update_outlets(x); } static void cd4012_inlet2(t_cd4012 *x, t_float f) { if (f == 1) x->x_in2 = 1; else if (f == 0) x->x_in2 = 0; else { post("cd4012 inlet 2 accepts 1 or 0."); return; } cd4012_update_outlets(x); } static void cd4012_inlet3(t_cd4012 *x, t_float f) { if (f == 1) x->x_in3 = 1; else if (f == 0) x->x_in3 = 0; else { post("cd4012 inlet 3 accepts 1 or 0."); return; } cd4012_update_outlets(x); } static void cd4012_inlet4(t_cd4012 *x, t_float f) { if (f == 1) x->x_in4 = 1; else if (f == 0) x->x_in4 = 0; else { post("cd4012 inlet 4 accepts 1 or 0."); return; } cd4012_update_outlets(x); } static void cd4012_update_outlets(t_cd4012 *x) { /* Quadruple NAND function */ outlet_float(x->x_out, ((x->x_in1 + x->x_in2 + x->x_in3 + x->x_in4) == 4)?0:1); } static void cd4012_free(t_cd4012 *x) { return; } static void *cd4012_new(t_symbol *s, int argc, t_atom *argv) { t_cd4012 *x; x = (t_cd4012 *)pd_new(cd4012_class); if (x == NULL) return (x); x->x_out = outlet_new((t_object *)x, &s_float); x->x_inlet2 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("inlet2")); x->x_inlet3 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("inlet3")); x->x_inlet4 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("inlet4")); return (x); } void cd4012_setup(void) { cd4012_class = class_new(gensym("cd4012"), (t_newmethod)cd4012_new, (t_method)cd4012_free, sizeof(t_cd4012), 0, 0); /* no arguments */ class_addbang(cd4012_class, cd4012_bang); class_addfloat(cd4012_class, cd4012_float); class_addmethod(cd4012_class, (t_method)cd4012_inlet2, gensym("inlet2"), A_FLOAT, 0); class_addmethod(cd4012_class, (t_method)cd4012_inlet3, gensym("inlet3"), A_FLOAT, 0); class_addmethod(cd4012_class, (t_method)cd4012_inlet4, gensym("inlet4"), A_FLOAT, 0); } /* end cd4012.c */ mrpeach/cmos/cd4000-help.pd0000644000175000017500000000113511026462102016027 0ustar zmoelnigzmoelnig#N canvas 670 174 482 236 12; #X obj 86 82 tgl 15 1 empty empty empty 17 7 0 10 -24198 -258699 -1 0 1; #X obj 151 82 tgl 15 1 empty empty empty 17 7 0 10 -24198 -258699 -1 0 1; #X obj 86 137 tgl 15 0 empty empty empty 17 7 0 10 -258699 -241291 -1 1 1; #X obj 217 82 tgl 15 1 empty empty empty 17 7 0 10 -24198 -258699 -1 0 1; #X obj 86 106 cd4000 triple nor; #X text 16 29 cd4000 emulates 1/2 of the CMOS three-input NOR gate ; #X text 210 170 20070315_Martin_Peach; #X text 170 48 (inverter not included); #X connect 0 0 4 0; #X connect 1 0 4 1; #X connect 3 0 4 2; #X connect 4 0 2 0; mrpeach/cmos/cd4025-help.pd0000644000175000017500000000105511026462102016037 0ustar zmoelnigzmoelnig#N canvas 670 174 478 232 12; #X obj 86 82 tgl 15 0 empty empty empty 17 7 0 10 -24198 -258699 -1 0 1; #X obj 151 82 tgl 15 0 empty empty empty 17 7 0 10 -24198 -258699 -1 0 1; #X obj 86 137 tgl 15 0 empty empty empty 17 7 0 10 -258699 -241291 -1 1 1; #X obj 217 82 tgl 15 0 empty empty empty 17 7 0 10 -24198 -258699 -1 0 1; #X text 210 170 20070319_Martin_Peach; #X text 18 47 cd4025 emulates 1/3 of the CMOS triple NOR gate; #X obj 86 106 cd4025 triple nor; #X connect 0 0 6 0; #X connect 1 0 6 1; #X connect 3 0 6 2; #X connect 6 0 2 0; mrpeach/cmos/cd4017.c0000644000175000017500000001234712430236316014745 0ustar zmoelnigzmoelnig/* cd4017.c MP 20070305 */ /* Emulate a cd4017b */ #include "m_pd.h" typedef struct _cd4017 { t_object x_obj; int x_state;/* clock_inhibit value in bit 0, clock level in bit 1, reset level in bit 2 */ int x_count; t_outlet *x_0; t_outlet *x_1; t_outlet *x_2; t_outlet *x_3; t_outlet *x_4; t_outlet *x_5; t_outlet *x_6; t_outlet *x_7; t_outlet *x_8; t_outlet *x_9; t_outlet *x_carry_out;/* Outputs 1 when any of outlets 0-3 is one */ t_inlet *x_clock_inhibit;/* clock_inhibit takes one or zero as acceptable inputs. 1 inhibits the clock. */ t_inlet *x_reset;/* reset */ /* The main inlet (clcok) should accept a bang or a one as valid clocks. */ /* If a one is received, it must be followed by a zero before the clock will work again. */ } t_cd4017; static t_class *cd4017_class; void cd4017_setup(void); static void *cd4017_new(t_symbol *s, int argc, t_atom *argv); static void cd4017_free(t_cd4017 *x); static void cd4017_bang(t_cd4017 *x); static void cd4017_float(t_cd4017 *x, t_float f); static void cd4017_clock_inhibit(t_cd4017 *x, t_float f); static void cd4017_reset(t_cd4017 *x, t_float f); static void cd4017_update_outlets(t_cd4017 *x); static void cd4017_float(t_cd4017 *x, t_float f) { if (f == 1) { /* if clock is high and was low, clock it. */ if ((x->x_state & 2) == 0) cd4017_bang(x); x->x_state |= 2; } else if (f == 0) x->x_state &= ~2; else post("cd4017 accepts bang, 1 or 0."); } static void cd4017_bang(t_cd4017 *x) { if ((x->x_state & 5) == 0) { /* if clock inhibit is low and reset is low, clock forward */ x->x_count = ((x->x_count + 1)%10); cd4017_update_outlets(x); } } static void cd4017_clock_inhibit(t_cd4017 *x, t_float f) { if (f == 1) x->x_state |= 1; /* clock inhibited */ else if (f == 0) x->x_state &= ~1; /* clock uninhibited */ else post("cd4017 clock inhibit takes 1 or 0 only."); return; } static void cd4017_reset(t_cd4017 *x, t_float f) { if (f == 1) { x->x_count = 0; x->x_state |= 4; /* reset */ if ((x->x_state & 8) == 0) /* don't reenter any update_oulets in progress */ { cd4017_update_outlets(x); } else x->x_state |= 16; /* reset during outlet_update */ } else if (f == 0) x->x_state &= ~4; /* no reset */ } static void cd4017_update_outlets(t_cd4017 *x) { x->x_state |= 8;/* updating outlets */ reset: x->x_state &= ~16; /* clear reset during outlet_update */ outlet_float(x->x_0, (x->x_count == 0)?1:0); /* we might get reset as a result of feedback from one of these outlets. */ if ((x->x_state & 16) != 0) goto reset; outlet_float(x->x_1, (x->x_count == 1)?1:0); if ((x->x_state & 16) != 0) goto reset; outlet_float(x->x_2, (x->x_count == 2)?1:0); if ((x->x_state & 16) != 0) goto reset; outlet_float(x->x_3, (x->x_count == 3)?1:0); if ((x->x_state & 16) != 0) goto reset; outlet_float(x->x_4, (x->x_count == 4)?1:0); if ((x->x_state & 16) != 0) goto reset; outlet_float(x->x_5, (x->x_count == 5)?1:0); if ((x->x_state & 16) != 0) goto reset; outlet_float(x->x_6, (x->x_count == 6)?1:0); if ((x->x_state & 16) != 0) goto reset; outlet_float(x->x_7, (x->x_count == 7)?1:0); if ((x->x_state & 16) != 0) goto reset; outlet_float(x->x_8, (x->x_count == 8)?1:0); if ((x->x_state & 16) != 0) goto reset; outlet_float(x->x_9, (x->x_count == 9)?1:0); if ((x->x_state & 16) != 0) goto reset; outlet_float(x->x_carry_out, (x->x_count < 5)?1:0); if ((x->x_state & 16) != 0) goto reset; x->x_state &= ~8;/* finished updating outlets */ } static void cd4017_free(t_cd4017 *x) { return; } static void *cd4017_new(t_symbol *s, int argc, t_atom *argv) { t_cd4017 *x; x = (t_cd4017 *)pd_new(cd4017_class); if (x == NULL) return (x); x->x_0 = outlet_new((t_object *)x, &s_float); x->x_1 = outlet_new((t_object *)x, &s_float); x->x_2 = outlet_new((t_object *)x, &s_float); x->x_3 = outlet_new((t_object *)x, &s_float); x->x_4 = outlet_new((t_object *)x, &s_float); x->x_5 = outlet_new((t_object *)x, &s_float); x->x_6 = outlet_new((t_object *)x, &s_float); x->x_7 = outlet_new((t_object *)x, &s_float); x->x_8 = outlet_new((t_object *)x, &s_float); x->x_9 = outlet_new((t_object *)x, &s_float); x->x_carry_out = outlet_new((t_object *)x, &s_float); x->x_clock_inhibit = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("clock_inhibit")); x->x_reset = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("reset")); return (x); } void cd4017_setup(void) { cd4017_class = class_new(gensym("cd4017"), (t_newmethod)cd4017_new, (t_method)cd4017_free, sizeof(t_cd4017), 0, 0); /* no arguments */ class_addbang(cd4017_class, cd4017_bang); class_addfloat(cd4017_class, cd4017_float); class_addmethod(cd4017_class, (t_method)cd4017_reset, gensym("reset"), A_FLOAT, 0); class_addmethod(cd4017_class, (t_method)cd4017_clock_inhibit, gensym("clock_inhibit"), A_FLOAT, 0); } /* end cd4017.c */ mrpeach/cmos/Makefile0000644000175000017500000004147712571126767015363 0ustar zmoelnigzmoelnig## Pd library template version 1.0.14 # For instructions on how to use this template, see: # http://puredata.info/docs/developer/MakefileTemplate LIBRARY_NAME = cmos # add your .c source files, one object per file, to the SOURCES # variable, help files will be included automatically, and for GUI # objects, the matching .tcl file too SOURCES = \ cd4000.c cd4008.c cd4013.c cd4017.c cd4024.c cd4070.c cd4073.c \ cd4081.c cd4516.c cd4001.c cd4011.c cd4014.c cd40193.c cd4025.c \ cd4071.c cd4075.c cd4082.c cd4002.c cd4012.c cd4015.c cd4023.c \ cd4027.c cd4072.c cd4076.c cd4094.c # list all pd objects (i.e. myobject.pd) files here, and their helpfiles will # be included automatically PDOBJECTS = # example patches and related files, in the 'examples' subfolder EXAMPLES = # manuals and related files, in the 'manual' subfolder MANUAL = # if you want to include any other files in the source and binary tarballs, # list them here. This can be anything from header files, test patches, # documentation, etc. README.txt and LICENSE.txt are required and therefore # automatically included EXTRA_DIST = # unit tests and related files here, in the 'unittests' subfolder UNITTESTS = #------------------------------------------------------------------------------# # # things you might need to edit if you are using other C libraries # #------------------------------------------------------------------------------# ALL_CFLAGS = -I"$(PD_INCLUDE)" ALL_LDFLAGS = SHARED_LDFLAGS = ALL_LIBS = #------------------------------------------------------------------------------# # # you shouldn't need to edit anything below here, if we did it right :) # #------------------------------------------------------------------------------# # these can be set from outside without (usually) breaking the build CFLAGS = -Wall -W -g LDFLAGS = LIBS = # get library version from meta file LIBRARY_VERSION = $(shell sed -n 's|^\#X text [0-9][0-9]* [0-9][0-9]* VERSION \(.*\);|\1|p' $(LIBRARY_NAME)-meta.pd) ALL_CFLAGS += -DPD -DVERSION='"$(LIBRARY_VERSION)"' PD_INCLUDE = $(PD_PATH)/include/pd # where to install the library, overridden below depending on platform prefix = /usr/local libdir = $(prefix)/lib pkglibdir = $(libdir)/pd-externals objectsdir = $(pkglibdir) INSTALL = install INSTALL_PROGRAM = $(INSTALL) -p -m 644 INSTALL_DATA = $(INSTALL) -p -m 644 INSTALL_DIR = $(INSTALL) -p -m 755 -d ALLSOURCES := $(SOURCES) $(SOURCES_android) $(SOURCES_cygwin) $(SOURCES_macosx) \ $(SOURCES_iphoneos) $(SOURCES_linux) $(SOURCES_windows) DISTDIR=$(LIBRARY_NAME)-$(LIBRARY_VERSION) ORIGDIR=pd-$(LIBRARY_NAME:~=)_$(LIBRARY_VERSION) UNAME := $(shell uname -s) ifeq ($(UNAME),Darwin) CPU := $(shell uname -p) ifeq ($(CPU),arm) # iPhone/iPod Touch SOURCES += $(SOURCES_iphoneos) EXTENSION = pd_darwin SHARED_EXTENSION = dylib OS = iphoneos PD_PATH = /Applications/Pd-extended.app/Contents/Resources IPHONE_BASE=/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin CC=$(IPHONE_BASE)/gcc CPP=$(IPHONE_BASE)/cpp CXX=$(IPHONE_BASE)/g++ ISYSROOT = -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.0.sdk IPHONE_CFLAGS = -miphoneos-version-min=3.0 $(ISYSROOT) -arch armv6 OPT_CFLAGS = -fast -funroll-loops -fomit-frame-pointer ALL_CFLAGS := $(IPHONE_CFLAGS) $(ALL_CFLAGS) ALL_LDFLAGS += -arch armv6 -bundle -undefined dynamic_lookup $(ISYSROOT) SHARED_LDFLAGS += -arch armv6 -dynamiclib -undefined dynamic_lookup $(ISYSROOT) ALL_LIBS += -lc $(LIBS_iphoneos) STRIP = strip -x DISTBINDIR=$(DISTDIR)-$(OS) else # Mac OS X SOURCES += $(SOURCES_macosx) EXTENSION = pd_darwin SHARED_EXTENSION = dylib OS = macosx PD_PATH = /Applications/Pd-extended.app/Contents/Resources OPT_CFLAGS = -ftree-vectorize -ftree-vectorizer-verbose=2 -fast # build universal 32-bit on 10.4 and 32/64 on newer ifeq ($(shell uname -r | sed 's|\([0-9][0-9]*\)\.[0-9][0-9]*\.[0-9][0-9]*|\1|'), 8) FAT_FLAGS = -arch ppc -arch i386 -mmacosx-version-min=10.4 else SOURCES += $(SOURCES_iphoneos) # Starting with Xcode 4.0, the PowerPC compiler is not installed by default ifeq ($(wildcard /usr/llvm-gcc-4.2/libexec/gcc/powerpc*), ) FAT_FLAGS = -arch i386 -arch x86_64 -mmacosx-version-min=10.5 else FAT_FLAGS = -arch ppc -arch i386 -arch x86_64 -mmacosx-version-min=10.4 endif endif ALL_CFLAGS += $(FAT_FLAGS) -fPIC -I/sw/include # if the 'pd' binary exists, check the linking against it to aid with stripping BUNDLE_LOADER = $(shell test ! -e $(PD_PATH)/bin/pd || echo -bundle_loader $(PD_PATH)/bin/pd) ALL_LDFLAGS += $(FAT_FLAGS) -headerpad_max_install_names -bundle $(BUNDLE_LOADER) \ -undefined dynamic_lookup -L/sw/lib SHARED_LDFLAGS += $(FAT_FLAGS) -dynamiclib -undefined dynamic_lookup \ -install_name @loader_path/$(SHARED_LIB) -compatibility_version 1 -current_version 1.0 ALL_LIBS += -lc $(LIBS_macosx) STRIP = strip -x DISTBINDIR=$(DISTDIR)-$(OS) # install into ~/Library/Pd on Mac OS X since /usr/local isn't used much pkglibdir=$(HOME)/Library/Pd endif endif # Tho Android uses Linux, we use this fake uname to provide an easy way to # setup all this things needed to cross-compile for Android using the NDK ifeq ($(UNAME),ANDROID) CPU := arm SOURCES += $(SOURCES_android) EXTENSION = so SHARED_EXTENSION = so OS = android PD_PATH = /usr NDK_BASE := /opt/android-ndk NDK_PLATFORM_LEVEL ?= 5 NDK_ABI=arm NDK_COMPILER_VERSION = 4.6 NDK_SYSROOT=$(NDK_BASE)/platforms/android-$(NDK_PLATFORM_LEVEL)/arch-$(NDK_ABI) NDK_UNAME:=$(shell uname -s | tr '[A-Z]' '[a-z]') ifeq ($(NDK_ABI),x86) HOST = i686-linux-android NDK_TOOLCHAIN = $(NDK_ABI)-$(NDK_COMPILER_VERSION) else HOST = $(NDK_ABI)-linux-androideabi NDK_TOOLCHAIN = $(HOST)-$(NDK_COMPILER_VERSION) endif NDK_TOOLCHAIN_BASE=$(NDK_BASE)/toolchains/$(NDK_TOOLCHAIN)/prebuilt/$(NDK_UNAME)-$(NDK_PROCESSOR) CC := $(NDK_TOOLCHAIN_BASE)/bin/$(HOST)-gcc --sysroot=$(NDK_SYSROOT) LD := $(NDK_TOOLCHAIN_BASE)/bin/$(HOST)-ld OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer CFLAGS += LDFLAGS += -rdynamic -shared SHARED_LDFLAGS += -Wl,-soname,$(SHARED_LIB) -shared LIBS += -lc $(LIBS_android) STRIP := $(NDK_TOOLCHAIN_BASE)/bin/$(HOST)-strip) \ --strip-unneeded -R .note -R .comment DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m) endif ifeq ($(UNAME),Linux) CPU := $(shell uname -m) SOURCES += $(SOURCES_linux) EXTENSION = pd_linux SHARED_EXTENSION = so OS = linux PD_PATH = /usr OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer ALL_CFLAGS += -fPIC ALL_LDFLAGS += -rdynamic -shared -fPIC -Wl,-rpath,"\$$ORIGIN",--enable-new-dtags SHARED_LDFLAGS += -Wl,-soname,$(SHARED_LIB) -shared ALL_LIBS += -lc $(LIBS_linux) STRIP = strip --strip-unneeded -R .note -R .comment DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m) endif ifeq ($(UNAME),GNU) # GNU/Hurd, should work like GNU/Linux for basically all externals CPU := $(shell uname -m) SOURCES += $(SOURCES_linux) EXTENSION = pd_linux SHARED_EXTENSION = so OS = linux PD_PATH = /usr OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer ALL_CFLAGS += -fPIC ALL_LDFLAGS += -rdynamic -shared -fPIC -Wl,-rpath,"\$$ORIGIN",--enable-new-dtags SHARED_LDFLAGS += -shared -Wl,-soname,$(SHARED_LIB) ALL_LIBS += -lc $(LIBS_linux) STRIP = strip --strip-unneeded -R .note -R .comment DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m) endif ifeq ($(UNAME),GNU/kFreeBSD) # Debian GNU/kFreeBSD, should work like GNU/Linux for basically all externals CPU := $(shell uname -m) SOURCES += $(SOURCES_linux) EXTENSION = pd_linux SHARED_EXTENSION = so OS = linux PD_PATH = /usr OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer ALL_CFLAGS += -fPIC ALL_LDFLAGS += -rdynamic -shared -fPIC -Wl,-rpath,"\$$ORIGIN",--enable-new-dtags SHARED_LDFLAGS += -shared -Wl,-soname,$(SHARED_LIB) ALL_LIBS += -lc $(LIBS_linux) STRIP = strip --strip-unneeded -R .note -R .comment DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m) endif ifeq (CYGWIN,$(findstring CYGWIN,$(UNAME))) CPU := $(shell uname -m) SOURCES += $(SOURCES_cygwin) EXTENSION = dll SHARED_EXTENSION = dll OS = cygwin PD_PATH = $(shell cygpath $$PROGRAMFILES)/pd OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer ALL_CFLAGS += ALL_LDFLAGS += -rdynamic -shared -L"$(PD_PATH)/src" -L"$(PD_PATH)/bin" SHARED_LDFLAGS += -shared -Wl,-soname,$(SHARED_LIB) ALL_LIBS += -lc -lpd $(LIBS_cygwin) STRIP = strip --strip-unneeded -R .note -R .comment DISTBINDIR=$(DISTDIR)-$(OS) endif ifeq (MINGW,$(findstring MINGW,$(UNAME))) CPU := $(shell uname -m) SOURCES += $(SOURCES_windows) EXTENSION = dll SHARED_EXTENSION = dll OS = windows PD_PATH = $(shell cd "$$PROGRAMFILES/pd" && pwd) # MinGW doesn't seem to include cc so force gcc CC=gcc OPT_CFLAGS = -O3 -funroll-loops -fomit-frame-pointer ALL_CFLAGS += -mms-bitfields ALL_LDFLAGS += -s -shared -Wl,--enable-auto-import SHARED_LDFLAGS += -shared ALL_LIBS += -L"$(PD_PATH)/src" -L"$(PD_PATH)/bin" -L"$(PD_PATH)/obj" \ -lpd -lwsock32 -lkernel32 -luser32 -lgdi32 -liberty $(LIBS_windows) STRIP = strip --strip-unneeded -R .note -R .comment DISTBINDIR=$(DISTDIR)-$(OS) endif # in case somebody manually set the HELPPATCHES above HELPPATCHES ?= $(SOURCES:.c=-help.pd) $(PDOBJECTS:.pd=-help.pd) ALL_CFLAGS := $(ALL_CFLAGS) $(CFLAGS) $(OPT_CFLAGS) ALL_LDFLAGS := $(LDFLAGS) $(ALL_LDFLAGS) ALL_LIBS := $(LIBS) $(ALL_LIBS) SHARED_SOURCE ?= $(wildcard lib$(LIBRARY_NAME).c) SHARED_HEADER ?= $(shell test ! -e $(LIBRARY_NAME).h || echo $(LIBRARY_NAME).h) SHARED_LIB ?= $(SHARED_SOURCE:.c=.$(SHARED_EXTENSION)) SHARED_TCL_LIB = $(wildcard lib$(LIBRARY_NAME).tcl) .PHONY = install libdir_install single_install install-doc install-examples install-manual install-unittests clean distclean dist etags $(LIBRARY_NAME) all: $(SOURCES:.c=.$(EXTENSION)) $(SHARED_LIB) %.o: %.c $(CC) $(ALL_CFLAGS) -o "$*.o" -c "$*.c" %.$(EXTENSION): %.o $(SHARED_LIB) $(CC) $(ALL_LDFLAGS) -o "$*.$(EXTENSION)" "$*.o" $(ALL_LIBS) $(SHARED_LIB) chmod a-x "$*.$(EXTENSION)" # this links everything into a single binary file $(LIBRARY_NAME): $(SOURCES:.c=.o) $(LIBRARY_NAME).o lib$(LIBRARY_NAME).o $(CC) $(ALL_LDFLAGS) -o $(LIBRARY_NAME).$(EXTENSION) $(SOURCES:.c=.o) \ $(LIBRARY_NAME).o lib$(LIBRARY_NAME).o $(ALL_LIBS) chmod a-x $(LIBRARY_NAME).$(EXTENSION) $(SHARED_LIB): $(SHARED_SOURCE:.c=.o) $(CC) $(SHARED_LDFLAGS) -o $(SHARED_LIB) $(SHARED_SOURCE:.c=.o) $(ALL_LIBS) install: libdir_install # The meta and help files are explicitly installed to make sure they are # actually there. Those files are not optional, then need to be there. libdir_install: $(SOURCES:.c=.$(EXTENSION)) $(SHARED_LIB) install-doc install-examples install-manual install-unittests $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) $(INSTALL_DATA) $(LIBRARY_NAME)-meta.pd \ $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) test -z "$(strip $(SOURCES))" || (\ $(INSTALL_PROGRAM) $(SOURCES:.c=.$(EXTENSION)) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) && \ $(STRIP) $(addprefix $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/,$(SOURCES:.c=.$(EXTENSION)))) test -z "$(strip $(SHARED_LIB))" || \ $(INSTALL_DATA) $(SHARED_LIB) \ $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) test -z "$(strip $(wildcard $(SOURCES:.c=.tcl)))" || \ $(INSTALL_DATA) $(wildcard $(SOURCES:.c=.tcl)) \ $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) test -z "$(strip $(PDOBJECTS))" || \ $(INSTALL_DATA) $(PDOBJECTS) \ $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) test -z "$(strip $(SHARED_TCL_LIB))" || \ $(INSTALL_DATA) $(SHARED_TCL_LIB) \ $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) # install library linked as single binary single_install: $(LIBRARY_NAME) install-doc install-examples install-manual install-unittests $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) $(INSTALL_PROGRAM) $(LIBRARY_NAME).$(EXTENSION) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) $(STRIP) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/$(LIBRARY_NAME).$(EXTENSION) install-doc: $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) test -z "$(strip $(SOURCES) $(PDOBJECTS))" || \ $(INSTALL_DATA) $(HELPPATCHES) \ $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) $(INSTALL_DATA) README.txt $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/README.txt $(INSTALL_DATA) LICENSE.txt $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/LICENSE.txt install-examples: test -z "$(strip $(EXAMPLES))" || \ $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/examples && \ for file in $(EXAMPLES); do \ $(INSTALL_DATA) examples/$$file $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/examples; \ done install-manual: test -z "$(strip $(MANUAL))" || \ $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/manual && \ for file in $(MANUAL); do \ $(INSTALL_DATA) manual/$$file $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/manual; \ done install-unittests: test -z "$(strip $(UNITTESTS))" || \ $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/unittests && \ for file in $(UNITTESTS); do \ $(INSTALL_DATA) unittests/$$file $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/unittests; \ done clean: -rm -f -- $(SOURCES:.c=.o) $(SOURCES_LIB:.c=.o) $(SHARED_SOURCE:.c=.o) -rm -f -- $(SOURCES:.c=.$(EXTENSION)) -rm -f -- $(LIBRARY_NAME).o -rm -f -- $(LIBRARY_NAME).$(EXTENSION) -rm -f -- $(SHARED_LIB) distclean: clean -rm -f -- $(DISTBINDIR).tar.gz -rm -rf -- $(DISTBINDIR) -rm -f -- $(DISTDIR).tar.gz -rm -rf -- $(DISTDIR) -rm -f -- $(ORIGDIR).tar.gz -rm -rf -- $(ORIGDIR) $(DISTBINDIR): $(INSTALL_DIR) $(DISTBINDIR) libdir: all $(DISTBINDIR) $(INSTALL_DATA) $(LIBRARY_NAME)-meta.pd $(DISTBINDIR) $(INSTALL_DATA) $(SOURCES) $(SHARED_SOURCE) $(SHARED_HEADER) $(DISTBINDIR) $(INSTALL_DATA) $(HELPPATCHES) $(DISTBINDIR) test -z "$(strip $(EXTRA_DIST))" || \ $(INSTALL_DATA) $(EXTRA_DIST) $(DISTBINDIR) # tar --exclude-vcs -czpf $(DISTBINDIR).tar.gz $(DISTBINDIR) $(DISTDIR): $(INSTALL_DIR) $(DISTDIR) $(ORIGDIR): $(INSTALL_DIR) $(ORIGDIR) dist: $(DISTDIR) $(INSTALL_DATA) Makefile $(DISTDIR) $(INSTALL_DATA) README.txt $(DISTDIR) $(INSTALL_DATA) LICENSE.txt $(DISTDIR) $(INSTALL_DATA) $(LIBRARY_NAME)-meta.pd $(DISTDIR) test -z "$(strip $(ALLSOURCES))" || \ $(INSTALL_DATA) $(ALLSOURCES) $(DISTDIR) test -z "$(strip $(wildcard $(ALLSOURCES:.c=.tcl)))" || \ $(INSTALL_DATA) $(wildcard $(ALLSOURCES:.c=.tcl)) $(DISTDIR) test -z "$(strip $(wildcard $(LIBRARY_NAME).c))" || \ $(INSTALL_DATA) $(LIBRARY_NAME).c $(DISTDIR) test -z "$(strip $(SHARED_HEADER))" || \ $(INSTALL_DATA) $(SHARED_HEADER) $(DISTDIR) test -z "$(strip $(SHARED_SOURCE))" || \ $(INSTALL_DATA) $(SHARED_SOURCE) $(DISTDIR) test -z "$(strip $(SHARED_TCL_LIB))" || \ $(INSTALL_DATA) $(SHARED_TCL_LIB) $(DISTDIR) test -z "$(strip $(PDOBJECTS))" || \ $(INSTALL_DATA) $(PDOBJECTS) $(DISTDIR) test -z "$(strip $(HELPPATCHES))" || \ $(INSTALL_DATA) $(HELPPATCHES) $(DISTDIR) test -z "$(strip $(EXTRA_DIST))" || \ $(INSTALL_DATA) $(EXTRA_DIST) $(DISTDIR) test -z "$(strip $(EXAMPLES))" || \ $(INSTALL_DIR) $(DISTDIR)/examples && \ for file in $(EXAMPLES); do \ $(INSTALL_DATA) examples/$$file $(DISTDIR)/examples; \ done test -z "$(strip $(MANUAL))" || \ $(INSTALL_DIR) $(DISTDIR)/manual && \ for file in $(MANUAL); do \ $(INSTALL_DATA) manual/$$file $(DISTDIR)/manual; \ done test -z "$(strip $(UNITTESTS))" || \ $(INSTALL_DIR) $(DISTDIR)/unittests && \ for file in $(UNITTESTS); do \ $(INSTALL_DATA) unittests/$$file $(DISTDIR)/unittests; \ done tar --exclude-vcs -czpf $(DISTDIR).tar.gz $(DISTDIR) # make a Debian source package dpkg-source: debclean make distclean dist mv $(DISTDIR) $(ORIGDIR) tar --exclude-vcs -czpf ../$(ORIGDIR).orig.tar.gz $(ORIGDIR) rm -f -- $(DISTDIR).tar.gz rm -rf -- $(DISTDIR) $(ORIGDIR) cd .. && dpkg-source -b $(LIBRARY_NAME) etags: TAGS TAGS: $(wildcard $(PD_INCLUDE)/*.h) $(SOURCES) $(SHARED_SOURCE) $(SHARED_HEADER) etags $(wildcard $(PD_INCLUDE)/*.h) etags -a *.h $(SOURCES) $(SHARED_SOURCE) $(SHARED_HEADER) etags -a --language=none --regex="/proc[ \t]+\([^ \t]+\)/\1/" *.tcl showsetup: @echo "CC: $(CC)" @echo "CFLAGS: $(CFLAGS)" @echo "LDFLAGS: $(LDFLAGS)" @echo "LIBS: $(LIBS)" @echo "ALL_CFLAGS: $(ALL_CFLAGS)" @echo "ALL_LDFLAGS: $(ALL_LDFLAGS)" @echo "ALL_LIBS: $(ALL_LIBS)" @echo "PD_INCLUDE: $(PD_INCLUDE)" @echo "PD_PATH: $(PD_PATH)" @echo "objectsdir: $(objectsdir)" @echo "LIBRARY_NAME: $(LIBRARY_NAME)" @echo "LIBRARY_VERSION: $(LIBRARY_VERSION)" @echo "SOURCES: $(SOURCES)" @echo "SHARED_HEADER: $(SHARED_HEADER)" @echo "SHARED_SOURCE: $(SHARED_SOURCE)" @echo "SHARED_LIB: $(SHARED_LIB)" @echo "SHARED_TCL_LIB: $(SHARED_TCL_LIB)" @echo "PDOBJECTS: $(PDOBJECTS)" @echo "ALLSOURCES: $(ALLSOURCES)" @echo "ALLSOURCES TCL: $(wildcard $(ALLSOURCES:.c=.tcl))" @echo "UNAME: $(UNAME)" @echo "CPU: $(CPU)" @echo "pkglibdir: $(pkglibdir)" @echo "DISTDIR: $(DISTDIR)" @echo "ORIGDIR: $(ORIGDIR)" @echo "NDK_TOOLCHAIN: $(NDK_TOOLCHAIN)" @echo "NDK_BASE: $(NDK_BASE)" @echo "NDK_SYSROOT: $(NDK_SYSROOT)" mrpeach/cmos/cd4027-help.pd0000644000175000017500000000235511026462102016045 0ustar zmoelnigzmoelnig#N canvas 581 224 647 312 12; #X obj 79 38 tgl 15 0 empty empty CLK 17 7 0 10 -24198 -62784 -1 1 1; #X obj 93 53 tgl 15 0 empty empty SET 17 7 0 10 -24198 -62784 -1 0 1; #X obj 108 68 tgl 15 0 empty empty RESET 17 7 0 10 -24198 -62784 -1 0 1; #X obj 123 83 tgl 15 0 empty empty J 17 7 0 10 -24198 -62784 -1 1 1 ; #X obj 138 98 tgl 15 0 empty empty K 17 7 0 10 -24198 -62784 -1 1 1 ; #X obj 79 146 cd4027 v; #X obj 138 172 tgl 15 0 empty empty /Q 17 7 0 10 -143491 -241291 -1 0 1; #X obj 79 172 tgl 15 0 empty empty Q 17 7 0 10 -143491 -241291 -1 1 1; #X text 173 65 Sets Q=0. Overrides Clock; #X text 133 35 A 0-1 transition or a bang clocks the flipflop.; #X text 142 50 Sets Q=1. Overrides Reset and Clock; #X text 237 264 20070307MartinPeach; #X text 27 5 cd4027 emulates one half of the CMOS logic J/K flipflop. ; #X text 157 80 When Q=0 and J=1 \, Q will change on next clock.; #X text 168 96 When Q=1 and K=1 \, Q will change on next clock.; #X obj 6 89 metro 100; #X obj 6 67 tgl 15 0 empty empty empty 17 7 0 10 -44926 -90881 -1 0 1; #X connect 0 0 5 0; #X connect 1 0 5 1; #X connect 2 0 5 2; #X connect 3 0 5 3; #X connect 4 0 5 4; #X connect 5 0 7 0; #X connect 5 1 6 0; #X connect 15 0 5 0; #X connect 16 0 15 0; mrpeach/cmos/cd4073.c0000644000175000017500000000520512430236316014742 0ustar zmoelnigzmoelnig/* cd4073.c MP 20070312 */ /* Emulate a cd4073b */ #include "m_pd.h" typedef struct _cd4073 { t_object x_obj; int x_in1; int x_in2; int x_in3; t_outlet *x_out; t_inlet *x_inlet2;/* Second inlet is 'live' like the first */ t_inlet *x_inlet3;/* Third inlet is 'live' like the first */ } t_cd4073; static t_class *cd4073_class; void cd4073_setup(void); static void *cd4073_new(t_symbol *s, int argc, t_atom *argv); static void cd4073_free(t_cd4073 *x); static void cd4073_bang(t_cd4073 *x); static void cd4073_float(t_cd4073 *x, t_float f); static void cd4073_inlet2(t_cd4073 *x, t_float f); static void cd4073_inlet3(t_cd4073 *x, t_float f); static void cd4073_update_outlets(t_cd4073 *x); static void cd4073_float(t_cd4073 *x, t_float f) { if (f == 1) x->x_in1 = 1; else if (f == 0) x->x_in1 = 0; else { post("cd4073 inlet 2 accepts 1 or 0."); return; } cd4073_update_outlets(x); } static void cd4073_bang(t_cd4073 *x) { cd4073_update_outlets(x); } static void cd4073_inlet2(t_cd4073 *x, t_float f) { if (f == 1) x->x_in2 = 1; else if (f == 0) x->x_in2 = 0; else { post("cd4073 inlet 2 accepts 1 or 0."); return; } cd4073_update_outlets(x); } static void cd4073_inlet3(t_cd4073 *x, t_float f) { if (f == 1) x->x_in3 = 1; else if (f == 0) x->x_in3 = 0; else { post("cd4073 inlet 3 accepts 1 or 0."); return; } cd4073_update_outlets(x); } static void cd4073_update_outlets(t_cd4073 *x) { /* Triple AND function */ outlet_float(x->x_out, ((x->x_in1 + x->x_in2 + x->x_in3) == 3)?1:0); } static void cd4073_free(t_cd4073 *x) { return; } static void *cd4073_new(t_symbol *s, int argc, t_atom *argv) { t_cd4073 *x; x = (t_cd4073 *)pd_new(cd4073_class); if (x == NULL) return (x); x->x_out = outlet_new((t_object *)x, &s_float); x->x_inlet2 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("inlet2")); x->x_inlet3 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("inlet3")); return (x); } void cd4073_setup(void) { cd4073_class = class_new(gensym("cd4073"), (t_newmethod)cd4073_new, (t_method)cd4073_free, sizeof(t_cd4073), 0, 0); /* no arguments */ class_addbang(cd4073_class, cd4073_bang); class_addfloat(cd4073_class, cd4073_float); class_addmethod(cd4073_class, (t_method)cd4073_inlet2, gensym("inlet2"), A_FLOAT, 0); class_addmethod(cd4073_class, (t_method)cd4073_inlet3, gensym("inlet3"), A_FLOAT, 0); } /* end cd4073.c */ mrpeach/cmos/cd4000.c0000644000175000017500000000520512430236171014727 0ustar zmoelnigzmoelnig/* cd4000.c MP 20070312 */ /* Emulate a cd4000b */ #include "m_pd.h" typedef struct _cd4000 { t_object x_obj; int x_in1; int x_in2; int x_in3; t_outlet *x_out; t_inlet *x_inlet2;/* Second inlet is 'live' like the first */ t_inlet *x_inlet3;/* Third inlet is 'live' like the first */ } t_cd4000; static t_class *cd4000_class; void cd4000_setup(void); static void *cd4000_new(t_symbol *s, int argc, t_atom *argv); static void cd4000_free(t_cd4000 *x); static void cd4000_bang(t_cd4000 *x); static void cd4000_float(t_cd4000 *x, t_float f); static void cd4000_inlet2(t_cd4000 *x, t_float f); static void cd4000_inlet3(t_cd4000 *x, t_float f); static void cd4000_update_outlets(t_cd4000 *x); static void cd4000_float(t_cd4000 *x, t_float f) { if (f == 1) x->x_in1 = 1; else if (f == 0) x->x_in1 = 0; else { post("cd4000 inlet 2 accepts 1 or 0."); return; } cd4000_update_outlets(x); } static void cd4000_bang(t_cd4000 *x) { cd4000_update_outlets(x); } static void cd4000_inlet2(t_cd4000 *x, t_float f) { if (f == 1) x->x_in2 = 1; else if (f == 0) x->x_in2 = 0; else { post("cd4000 inlet 2 accepts 1 or 0."); return; } cd4000_update_outlets(x); } static void cd4000_inlet3(t_cd4000 *x, t_float f) { if (f == 1) x->x_in3 = 1; else if (f == 0) x->x_in3 = 0; else { post("cd4000 inlet 3 accepts 1 or 0."); return; } cd4000_update_outlets(x); } static void cd4000_update_outlets(t_cd4000 *x) { /* Triple NOR function */ outlet_float(x->x_out, ((x->x_in1 + x->x_in2 + x->x_in3) != 0)?0:1); } static void cd4000_free(t_cd4000 *x) { return; } static void *cd4000_new(t_symbol *s, int argc, t_atom *argv) { t_cd4000 *x; x = (t_cd4000 *)pd_new(cd4000_class); if (x == NULL) return (x); x->x_out = outlet_new((t_object *)x, &s_float); x->x_inlet2 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("inlet2")); x->x_inlet3 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("inlet3")); return (x); } void cd4000_setup(void) { cd4000_class = class_new(gensym("cd4000"), (t_newmethod)cd4000_new, (t_method)cd4000_free, sizeof(t_cd4000), 0, 0); /* no arguments */ class_addbang(cd4000_class, cd4000_bang); class_addfloat(cd4000_class, cd4000_float); class_addmethod(cd4000_class, (t_method)cd4000_inlet2, gensym("inlet2"), A_FLOAT, 0); class_addmethod(cd4000_class, (t_method)cd4000_inlet3, gensym("inlet3"), A_FLOAT, 0); } /* end cd4000.c */ mrpeach/cmos/cd4072.c0000644000175000017500000000627712430236316014753 0ustar zmoelnigzmoelnig/* cd4072.c MP 20070312 */ /* Emulate a cd4072b */ #include "m_pd.h" typedef struct _cd4072 { t_object x_obj; int x_in1; int x_in2; int x_in3; int x_in4; t_outlet *x_out; t_inlet *x_inlet2;/* Second inlet is 'live' like the first */ t_inlet *x_inlet3;/* Third inlet is 'live' like the first */ t_inlet *x_inlet4;/* Fourth inlet is 'live' like the first */ } t_cd4072; static t_class *cd4072_class; void cd4072_setup(void); static void *cd4072_new(t_symbol *s, int argc, t_atom *argv); static void cd4072_free(t_cd4072 *x); static void cd4072_bang(t_cd4072 *x); static void cd4072_float(t_cd4072 *x, t_float f); static void cd4072_inlet2(t_cd4072 *x, t_float f); static void cd4072_inlet3(t_cd4072 *x, t_float f); static void cd4072_inlet4(t_cd4072 *x, t_float f); static void cd4072_update_outlets(t_cd4072 *x); static void cd4072_float(t_cd4072 *x, t_float f) { if (f == 1) x->x_in1 = 1; else if (f == 0) x->x_in1 = 0; else { post("cd4072 inlet 2 accepts 1 or 0."); return; } cd4072_update_outlets(x); } static void cd4072_bang(t_cd4072 *x) { cd4072_update_outlets(x); } static void cd4072_inlet2(t_cd4072 *x, t_float f) { if (f == 1) x->x_in2 = 1; else if (f == 0) x->x_in2 = 0; else { post("cd4072 inlet 2 accepts 1 or 0."); return; } cd4072_update_outlets(x); } static void cd4072_inlet3(t_cd4072 *x, t_float f) { if (f == 1) x->x_in3 = 1; else if (f == 0) x->x_in3 = 0; else { post("cd4072 inlet 3 accepts 1 or 0."); return; } cd4072_update_outlets(x); } static void cd4072_inlet4(t_cd4072 *x, t_float f) { if (f == 1) x->x_in4 = 1; else if (f == 0) x->x_in4 = 0; else { post("cd4072 inlet 4 accepts 1 or 0."); return; } cd4072_update_outlets(x); } static void cd4072_update_outlets(t_cd4072 *x) { /* QUAD OR function */ outlet_float(x->x_out, ((x->x_in1 + x->x_in2 + x->x_in3 + x->x_in4) != 0)?1:0); } static void cd4072_free(t_cd4072 *x) { return; } static void *cd4072_new(t_symbol *s, int argc, t_atom *argv) { t_cd4072 *x; x = (t_cd4072 *)pd_new(cd4072_class); if (x == NULL) return (x); x->x_out = outlet_new((t_object *)x, &s_float); x->x_inlet2 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("inlet2")); x->x_inlet3 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("inlet3")); x->x_inlet4 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("inlet4")); return (x); } void cd4072_setup(void) { cd4072_class = class_new(gensym("cd4072"), (t_newmethod)cd4072_new, (t_method)cd4072_free, sizeof(t_cd4072), 0, 0); /* no arguments */ class_addbang(cd4072_class, cd4072_bang); class_addfloat(cd4072_class, cd4072_float); class_addmethod(cd4072_class, (t_method)cd4072_inlet2, gensym("inlet2"), A_FLOAT, 0); class_addmethod(cd4072_class, (t_method)cd4072_inlet3, gensym("inlet3"), A_FLOAT, 0); class_addmethod(cd4072_class, (t_method)cd4072_inlet4, gensym("inlet4"), A_FLOAT, 0); } /* end cd4072.c */ mrpeach/cmos/cd4070.c0000644000175000017500000000405112430236316014735 0ustar zmoelnigzmoelnig/* cd4070.c MP 20070305 */ /* Emulate a cd4070b */ #include "m_pd.h" typedef struct _cd4070 { t_object x_obj; int x_in1; int x_in2; t_outlet *x_out; t_inlet *x_inlet2;/* Second inlet is 'live' like the first */ } t_cd4070; static t_class *cd4070_class; void cd4070_setup(void); static void *cd4070_new(t_symbol *s, int argc, t_atom *argv); static void cd4070_free(t_cd4070 *x); static void cd4070_bang(t_cd4070 *x); static void cd4070_float(t_cd4070 *x, t_float f); static void cd4070_inlet2(t_cd4070 *x, t_float f); static void cd4070_update_outlets(t_cd4070 *x); static void cd4070_float(t_cd4070 *x, t_float f) { if (f == 1) x->x_in1 = 1; else if (f == 0) x->x_in1 = 0; else { post("cd4070 inlet 2 accepts 1 or 0."); return; } cd4070_update_outlets(x); } static void cd4070_bang(t_cd4070 *x) { cd4070_update_outlets(x); } static void cd4070_inlet2(t_cd4070 *x, t_float f) { if (f == 1) x->x_in2 = 1; else if (f == 0) x->x_in2 = 0; else { post("cd4070 inlet 2 accepts 1 or 0."); return; } cd4070_update_outlets(x); } static void cd4070_update_outlets(t_cd4070 *x) { outlet_float(x->x_out, (x->x_in1 != x->x_in2)?1:0); } static void cd4070_free(t_cd4070 *x) { return; } static void *cd4070_new(t_symbol *s, int argc, t_atom *argv) { t_cd4070 *x; x = (t_cd4070 *)pd_new(cd4070_class); if (x == NULL) return (x); x->x_out = outlet_new((t_object *)x, &s_float); x->x_inlet2 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("inlet2")); return (x); } void cd4070_setup(void) { cd4070_class = class_new(gensym("cd4070"), (t_newmethod)cd4070_new, (t_method)cd4070_free, sizeof(t_cd4070), 0, 0); /* no arguments */ class_addbang(cd4070_class, cd4070_bang); class_addfloat(cd4070_class, cd4070_float); class_addmethod(cd4070_class, (t_method)cd4070_inlet2, gensym("inlet2"), A_FLOAT, 0); } /* end cd4070.c */ mrpeach/cmos/cd4015-help.pd0000644000175000017500000000150611026462102016037 0ustar zmoelnigzmoelnig#N canvas 693 303 454 304 12; #X obj 125 135 cd4015 4bit shift register; #X obj 125 84 tgl 15 0 empty empty Clk 17 7 0 10 -44926 -258699 -1 0 1; #X obj 226 84 tgl 15 0 empty empty D 17 7 0 10 -44926 -258699 -1 0 1; #X obj 328 84 tgl 15 0 empty empty R 17 7 0 10 -44926 -258699 -1 0 1; #X obj 125 183 tgl 15 0 empty empty Q1 17 7 0 10 -24198 -258699 -1 0 1; #X obj 192 183 tgl 15 0 empty empty Q2 17 7 0 10 -24198 -258699 -1 0 1; #X obj 260 183 tgl 15 0 empty empty Q3 17 7 0 10 -24198 -258699 -1 0 1; #X obj 328 183 tgl 15 0 empty empty Q4 17 7 0 10 -24198 -258699 -1 0 1; #X text 32 22 cd4016 emulates 1/2 of the CMOS shift register; #X text 165 239 20070319_MartinPeach; #X connect 0 0 4 0; #X connect 0 1 5 0; #X connect 0 2 6 0; #X connect 0 3 7 0; #X connect 1 0 0 0; #X connect 2 0 0 1; #X connect 3 0 0 2; mrpeach/cmos/cd4008.c0000644000175000017500000001375612430236316014752 0ustar zmoelnigzmoelnig/* cd4008.c MP 20070315 */ /* Emulate a cd4008b */ #include "m_pd.h" typedef struct _cd4008 { t_object x_obj; int x_A1; int x_A2; int x_A3; int x_A4; int x_B1; int x_B2; int x_B3; int x_B4; int x_CarryIn; t_outlet *x_outS1; t_outlet *x_outS2; t_outlet *x_outS3; t_outlet *x_outS4; t_outlet *x_outC; t_inlet *x_inA1;/* extra inlets are 'live' like the first */ t_inlet *x_inA2; t_inlet *x_inA3; t_inlet *x_inA4; t_inlet *x_inB1; t_inlet *x_inB2; t_inlet *x_inB3; t_inlet *x_inB4; } t_cd4008; static t_class *cd4008_class; void cd4008_setup(void); static void *cd4008_new(t_symbol *s, int argc, t_atom *argv); static void cd4008_free(t_cd4008 *x); static void cd4008_float(t_cd4008 *x, t_float f); static void cd4008_inA1(t_cd4008 *x, t_float f); static void cd4008_inA2(t_cd4008 *x, t_float f); static void cd4008_inA3(t_cd4008 *x, t_float f); static void cd4008_inA4(t_cd4008 *x, t_float f); static void cd4008_inB1(t_cd4008 *x, t_float f); static void cd4008_inB2(t_cd4008 *x, t_float f); static void cd4008_inB3(t_cd4008 *x, t_float f); static void cd4008_inB4(t_cd4008 *x, t_float f); static void cd4008_update_outlets(t_cd4008 *x); static void cd4008_float(t_cd4008 *x, t_float f) { if (f == 1) x->x_CarryIn = 1; else if (f == 0) x->x_CarryIn = 0; else { post("cd4008 Carry inlet accepts 1 or 0."); return; } cd4008_update_outlets(x); } static void cd4008_inA1(t_cd4008 *x, t_float f) { if (f == 1) x->x_A1 = 1; else if (f == 0) x->x_A1 = 0; else { post("cd4008 inlet A1 accepts 1 or 0."); return; } cd4008_update_outlets(x); } static void cd4008_inA2(t_cd4008 *x, t_float f) { if (f == 1) x->x_A2 = 1; else if (f == 0) x->x_A2 = 0; else { post("cd4008 inlet A2 accepts 1 or 0."); return; } cd4008_update_outlets(x); } static void cd4008_inA3(t_cd4008 *x, t_float f) { if (f == 1) x->x_A3 = 1; else if (f == 0) x->x_A3 = 0; else { post("cd4008 inlet A3 accepts 1 or 0."); return; } cd4008_update_outlets(x); } static void cd4008_inA4(t_cd4008 *x, t_float f) { if (f == 1) x->x_A4 = 1; else if (f == 0) x->x_A4 = 0; else { post("cd4008 inlet A4 accepts 1 or 0."); return; } cd4008_update_outlets(x); } static void cd4008_inB1(t_cd4008 *x, t_float f) { if (f == 1) x->x_B1 = 1; else if (f == 0) x->x_B1 = 0; else { post("cd4008 inlet B1 accepts 1 or 0."); return; } cd4008_update_outlets(x); } static void cd4008_inB2(t_cd4008 *x, t_float f) { if (f == 1) x->x_B2 = 1; else if (f == 0) x->x_B2 = 0; else { post("cd4008 inlet B2 accepts 1 or 0."); return; } cd4008_update_outlets(x); } static void cd4008_inB3(t_cd4008 *x, t_float f) { if (f == 1) x->x_B3 = 1; else if (f == 0) x->x_B3 = 0; else { post("cd4008 inlet B3 accepts 1 or 0."); return; } cd4008_update_outlets(x); } static void cd4008_inB4(t_cd4008 *x, t_float f) { if (f == 1) x->x_B4 = 1; else if (f == 0) x->x_B4 = 0; else { post("cd4008 inlet B4 accepts 1 or 0."); return; } cd4008_update_outlets(x); } static void cd4008_update_outlets(t_cd4008 *x) { /* Quadruple add function */ t_int sum; sum = x->x_CarryIn + x->x_A1 + x->x_B1 + 2*(x->x_A2 + x->x_B2) + 4*(x->x_A3 + x->x_B3) + 8*(x->x_A4 + x->x_B4); outlet_float(x->x_outC, ((sum & 16) != 0)?1:0); outlet_float(x->x_outS4, ((sum & 8) != 0)?1:0); outlet_float(x->x_outS3, ((sum & 4) != 0)?1:0); outlet_float(x->x_outS2, ((sum & 2) != 0)?1:0); outlet_float(x->x_outS1, ((sum & 1) != 0)?1:0); } static void cd4008_free(t_cd4008 *x) { return; } static void *cd4008_new(t_symbol *s, int argc, t_atom *argv) { t_cd4008 *x; x = (t_cd4008 *)pd_new(cd4008_class); if (x == NULL) return (x); x->x_outS1 = outlet_new((t_object *)x, &s_float); x->x_outS2 = outlet_new((t_object *)x, &s_float); x->x_outS3 = outlet_new((t_object *)x, &s_float); x->x_outS4 = outlet_new((t_object *)x, &s_float); x->x_outC = outlet_new((t_object *)x, &s_float); x->x_inA1 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("A1")); x->x_inA2 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("A2")); x->x_inA3 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("A3")); x->x_inA4 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("A4")); x->x_inB1 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("B1")); x->x_inB2 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("B2")); x->x_inB3 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("B3")); x->x_inB4 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("B4")); return (x); } void cd4008_setup(void) { cd4008_class = class_new(gensym("cd4008"), (t_newmethod)cd4008_new, (t_method)cd4008_free, sizeof(t_cd4008), 0, 0); /* no arguments */ class_addfloat(cd4008_class, cd4008_float); class_addmethod(cd4008_class, (t_method)cd4008_inA1, gensym("A1"), A_FLOAT, 0); class_addmethod(cd4008_class, (t_method)cd4008_inA2, gensym("A2"), A_FLOAT, 0); class_addmethod(cd4008_class, (t_method)cd4008_inA3, gensym("A3"), A_FLOAT, 0); class_addmethod(cd4008_class, (t_method)cd4008_inA4, gensym("A4"), A_FLOAT, 0); class_addmethod(cd4008_class, (t_method)cd4008_inB1, gensym("B1"), A_FLOAT, 0); class_addmethod(cd4008_class, (t_method)cd4008_inB2, gensym("B2"), A_FLOAT, 0); class_addmethod(cd4008_class, (t_method)cd4008_inB3, gensym("B3"), A_FLOAT, 0); class_addmethod(cd4008_class, (t_method)cd4008_inB4, gensym("B4"), A_FLOAT, 0); } /* end cd4008.c */ mrpeach/cmos/cd4023-help.pd0000644000175000017500000000105711026462102016037 0ustar zmoelnigzmoelnig#N canvas 670 174 478 232 12; #X obj 86 82 tgl 15 0 empty empty empty 17 7 0 10 -24198 -258699 -1 0 1; #X obj 155 82 tgl 15 0 empty empty empty 17 7 0 10 -24198 -258699 -1 0 1; #X obj 86 137 tgl 15 0 empty empty empty 17 7 0 10 -258699 -241291 -1 1 1; #X obj 225 82 tgl 15 0 empty empty empty 17 7 0 10 -24198 -258699 -1 1 1; #X obj 86 106 cd4023 triple nand; #X text 18 47 cd4023 emulates 1/3 of the CMOS triple NAND gate; #X text 210 170 20070319_Martin_Peach; #X connect 0 0 4 0; #X connect 1 0 4 1; #X connect 3 0 4 2; #X connect 4 0 2 0; mrpeach/cmos/cd4082-help.pd0000644000175000017500000000121211026462102016035 0ustar zmoelnigzmoelnig#N canvas 670 174 466 220 12; #X obj 86 82 tgl 15 0 empty empty empty 17 7 0 10 -24198 -258699 -1 1 1; #X obj 124 82 tgl 15 0 empty empty empty 17 7 0 10 -24198 -258699 -1 1 1; #X obj 86 137 tgl 15 0 empty empty empty 17 7 0 10 -258699 -241291 -1 1 1; #X obj 162 82 tgl 15 0 empty empty empty 17 7 0 10 -24198 -258699 -1 1 1; #X obj 201 82 tgl 15 0 empty empty empty 17 7 0 10 -24198 -258699 -1 1 1; #X obj 86 106 cd4082 quad and; #X text 18 47 cd4082 emulates 1/2 of the CMOS quad AND gate; #X text 210 170 20070312_Martin_Peach; #X connect 0 0 5 0; #X connect 1 0 5 1; #X connect 3 0 5 2; #X connect 4 0 5 3; #X connect 5 0 2 0; mrpeach/cmos/cd4012-help.pd0000644000175000017500000000121711026462102016033 0ustar zmoelnigzmoelnig#N canvas 670 174 494 248 12; #X obj 86 82 tgl 15 1 empty empty empty 17 7 0 10 -24198 -258699 -1 0 1; #X obj 113 82 tgl 15 1 empty empty empty 17 7 0 10 -24198 -258699 -1 0 1; #X obj 86 137 tgl 15 0 empty empty empty 17 7 0 10 -258699 -241291 -1 1 1; #X text 210 170 20070315_Martin_Peach; #X obj 141 82 tgl 15 1 empty empty empty 17 7 0 10 -24198 -258699 -1 0 1; #X obj 169 82 tgl 15 1 empty empty empty 17 7 0 10 -24198 -258699 -1 0 1; #X text 18 31 cd4012 emulates 1/2 of the CMOS four-input NAND gate ; #X obj 86 106 cd4012 nand; #X connect 0 0 7 0; #X connect 1 0 7 1; #X connect 4 0 7 2; #X connect 5 0 7 3; #X connect 7 0 2 0; mrpeach/cmos/cd4094-help.pd0000644000175000017500000000316011026462102016044 0ustar zmoelnigzmoelnig#N canvas 657 97 532 308 12; #X obj 130 135 cd4094 shift register; #X obj 130 173 tgl 15 0 empty empty Q1 17 7 0 10 -24198 -123526 -1 0 1; #X obj 148 189 tgl 15 0 empty empty Q2 17 7 0 10 -24198 -123526 -1 0 1; #X obj 166 173 tgl 15 0 empty empty Q3 17 7 0 10 -24198 -123526 -1 0 1; #X obj 184 189 tgl 15 0 empty empty Q4 17 7 0 10 -24198 -123526 -1 0 1; #X obj 202 173 tgl 15 0 empty empty Q5 17 7 0 10 -24198 -123526 -1 0 1; #X obj 220 189 tgl 15 0 empty empty Q6 17 7 0 10 -24198 -123526 -1 0 1; #X obj 238 173 tgl 15 0 empty empty Q7 17 7 0 10 -24198 -123526 -1 0 1; #X obj 256 189 tgl 15 0 empty empty Q8 17 7 0 10 -24198 -123526 -1 0 1; #X obj 274 173 tgl 15 0 empty empty QS 17 7 0 10 -24198 -123526 -1 0 1; #X obj 292 189 tgl 15 0 empty empty Q'S 17 7 0 10 -24198 -123526 -1 0 1; #X obj 130 51 tgl 15 0 empty empty CLOCK 17 7 0 10 -258699 -42246 -1 1 1; #X obj 184 73 tgl 15 0 empty empty STROBE 17 7 0 10 -24198 -143491 -1 1 1; #X obj 238 93 tgl 15 0 empty empty DATA 17 7 0 10 -24198 -143491 -1 0 1; #X obj 293 110 tgl 15 0 empty empty OUTPUT_ENABLE 17 7 0 10 -24198 -143491 -1 1 1; #X text 52 10 cd4094 emulates the CMOS shift register; #X text 166 239 20030313_MartinPeach; #X text 200 48 0 to 1 transition clocks data...; #X text 255 70 ...only if strobe is 1; #X text 316 121 enables outputs Q1-Q8.; #X connect 0 0 1 0; #X connect 0 1 2 0; #X connect 0 2 3 0; #X connect 0 3 4 0; #X connect 0 4 5 0; #X connect 0 5 6 0; #X connect 0 6 7 0; #X connect 0 7 8 0; #X connect 0 8 9 0; #X connect 0 9 10 0; #X connect 11 0 0 0; #X connect 12 0 0 1; #X connect 13 0 0 2; #X connect 14 0 0 3; mrpeach/cmos/README.txt0000644000175000017500000000024012571126767015400 0ustar zmoelnigzmoelnigCMOS digital logic emulation objects === This is a collection of small objects that emulate logic CMOS components. The emulation assumes idealized components. mrpeach/cmos/cd4076-help.pd0000644000175000017500000000401211026462102016041 0ustar zmoelnigzmoelnig#N canvas 581 224 661 399 12; #X obj 49 39 tgl 15 0 empty empty CP 17 7 0 10 -24198 -62784 -1 0 1 ; #X obj 68 54 tgl 15 0 empty empty CLEAR 17 7 0 10 -24198 -62784 -1 0 1; #X obj 87 70 tgl 15 0 empty empty Input_Disable_1 17 7 0 10 -24198 -62784 -1 0 1; #X obj 106 88 tgl 15 0 empty empty Input_Disable_2 17 7 0 10 -24198 -62784 -1 0 1; #X obj 106 304 tgl 15 0 empty empty B 17 7 0 10 -143491 -241291 -1 0 1; #X obj 49 304 tgl 15 0 empty empty A 17 7 0 10 -143491 -241291 -1 0 1; #X obj 26 157 tgl 15 0 empty empty empty 17 7 0 10 -44926 -90881 -1 0 1; #X text 89 36 A 0-1 transition or a bang clocks D to the outlets.; #X obj 26 221 bng 15 250 50 0 empty empty empty 17 7 0 10 -24198 -241291 -1; #X obj 26 187 metro 500; #X text 27 5 cd4076 emulates the CMOS quad D flipflop.; #X obj 220 304 tgl 15 0 empty empty D 17 7 0 10 -143491 -241291 -1 0 1; #X obj 163 304 tgl 15 0 empty empty C 17 7 0 10 -143491 -241291 -1 0 1; #X text 131 50 Sets outputs to 0 Overrides CP.; #X text 250 74 Prevents input from being clocked to output.; #X obj 125 106 tgl 15 0 empty empty Output_Disable_1 17 7 0 10 -24198 -62784 -1 0 1; #X obj 144 124 tgl 15 0 empty empty Output_Disable_1 17 7 0 10 -24198 -62784 -1 0 1; #X text 291 107 Inhibits output.; #X text 74 341 20070312_Martin_Peach; #X obj 163 141 tgl 15 0 empty empty InA 17 7 0 10 -260818 -143491 -1 0 1; #X obj 182 158 tgl 15 0 empty empty InB 17 7 0 10 -260818 -143491 -1 0 1; #X obj 201 177 tgl 15 0 empty empty InC 17 7 0 10 -260818 -143491 -1 0 1; #X obj 220 194 tgl 15 0 empty empty InD 17 7 0 10 -260818 -143491 -1 0 1; #X text 236 142 Data inputs; #X obj 49 263 cd4076 quad d flipflop; #X connect 0 0 24 0; #X connect 1 0 24 1; #X connect 2 0 24 2; #X connect 3 0 24 3; #X connect 6 0 9 0; #X connect 8 0 24 0; #X connect 9 0 8 0; #X connect 15 0 24 4; #X connect 16 0 24 5; #X connect 19 0 24 6; #X connect 20 0 24 7; #X connect 21 0 24 8; #X connect 22 0 24 9; #X connect 24 0 5 0; #X connect 24 1 4 0; #X connect 24 2 12 0; #X connect 24 3 11 0; mrpeach/cmos/cd4025.c0000644000175000017500000000520512430236316014737 0ustar zmoelnigzmoelnig/* cd4025.c MP 20070312 */ /* Emulate a cd4025b */ #include "m_pd.h" typedef struct _cd4025 { t_object x_obj; int x_in1; int x_in2; int x_in3; t_outlet *x_out; t_inlet *x_inlet2;/* Second inlet is 'live' like the first */ t_inlet *x_inlet3;/* Third inlet is 'live' like the first */ } t_cd4025; static t_class *cd4025_class; void cd4025_setup(void); static void *cd4025_new(t_symbol *s, int argc, t_atom *argv); static void cd4025_free(t_cd4025 *x); static void cd4025_bang(t_cd4025 *x); static void cd4025_float(t_cd4025 *x, t_float f); static void cd4025_inlet2(t_cd4025 *x, t_float f); static void cd4025_inlet3(t_cd4025 *x, t_float f); static void cd4025_update_outlets(t_cd4025 *x); static void cd4025_float(t_cd4025 *x, t_float f) { if (f == 1) x->x_in1 = 1; else if (f == 0) x->x_in1 = 0; else { post("cd4025 inlet 2 accepts 1 or 0."); return; } cd4025_update_outlets(x); } static void cd4025_bang(t_cd4025 *x) { cd4025_update_outlets(x); } static void cd4025_inlet2(t_cd4025 *x, t_float f) { if (f == 1) x->x_in2 = 1; else if (f == 0) x->x_in2 = 0; else { post("cd4025 inlet 2 accepts 1 or 0."); return; } cd4025_update_outlets(x); } static void cd4025_inlet3(t_cd4025 *x, t_float f) { if (f == 1) x->x_in3 = 1; else if (f == 0) x->x_in3 = 0; else { post("cd4025 inlet 3 accepts 1 or 0."); return; } cd4025_update_outlets(x); } static void cd4025_update_outlets(t_cd4025 *x) { /* Triple NOR function */ outlet_float(x->x_out, ((x->x_in1 + x->x_in2 + x->x_in3) != 0)?0:1); } static void cd4025_free(t_cd4025 *x) { return; } static void *cd4025_new(t_symbol *s, int argc, t_atom *argv) { t_cd4025 *x; x = (t_cd4025 *)pd_new(cd4025_class); if (x == NULL) return (x); x->x_out = outlet_new((t_object *)x, &s_float); x->x_inlet2 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("inlet2")); x->x_inlet3 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("inlet3")); return (x); } void cd4025_setup(void) { cd4025_class = class_new(gensym("cd4025"), (t_newmethod)cd4025_new, (t_method)cd4025_free, sizeof(t_cd4025), 0, 0); /* no arguments */ class_addbang(cd4025_class, cd4025_bang); class_addfloat(cd4025_class, cd4025_float); class_addmethod(cd4025_class, (t_method)cd4025_inlet2, gensym("inlet2"), A_FLOAT, 0); class_addmethod(cd4025_class, (t_method)cd4025_inlet3, gensym("inlet3"), A_FLOAT, 0); } /* end cd4025.c */ mrpeach/midifile/0000755000175000017500000000000013605444730014517 5ustar zmoelnigzmoelnigmrpeach/midifile/I_Wanna_Be_Sedated.mid0000644000175000017500000013561013153266454020576 0ustar zmoelnigzmoelnigMThdxMTrkBXYQt%Sequenced by sargpepp67@earthlink.net/MTrk !Drums @][@c$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$(((((!$((($*((,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$y$$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$$4$$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(J$4$B(,(M$$#$y$%(+(I$4,4$/MTrk!Cymbals/Percussionc4|5;54.r;..o;..;..;..;..;..{;..|;..r;..;..;..;..o;..;..;.4;4.;..u;..|;..;..o;..};..|;..;..;..i;..o;..;..;..;..;.4;4.c;..};..;..;..;..;..o;..;..Y;..o;..Y;..;..;..|;..;.4f;4.;..;..;..;..;..;..;..;..{;..;..c;..;..;..u;..;.4;4.;..;..;..u;..;..;..;..u;..u;..i;..Y;..;..{;..;..;.4|;4.u;..;..;..;..o;..;..c;..;..;..;..;..;..;..;..o;.4;43;33;33l;33;33;33;33o;34;43M;33Y;33x;33|;33V;33o;33o;34|;43i;33{;33;33];33u;33Y;33i;34c;43o;33];33;33i;33x;33x;33i;34;43|;33;33c;33V;33u;33;33;34;43;33;33;33;33;33u;33;34x;43o;33{;33u;33u;33;33;33c;34{;43`;33{;33{;33u;33};33l;33];3..'.E.'..#.M.(..#.[.+.c.'.V.-.o. .f..T..V.".Y"..r....u..V ..Y!..}#..u!....!.. ..`..Q..x. ."..r.. .. ..|..o .4*4L...l..i..|. .}..H.!.!... .o..u ..x ....i..|. ...... .. .`. .i. .Y..|. .. .r....`.."..~....$.4%4S...T.".{ ..=..i.".i.%.].#.`.#.`.".o.#.T.#.V.&.].(.c."4|#4S.V.&.r.#.|.".o.#..#..!4"4.u.(.O.$.o.".c.".|. ..!.O."4}"4.l.#.Q.#.x.".l.".]..o. .l.4{$4.i.&..".}..Q.".Q.".`..i.4"4.].).].#.|.!.Q.!.`. .|.#..4i 4.O.'.Q.$.u.".~.!.l.%.Q."..4!4.].&.u..~.".o. .u.$..%..4c!4.u.)..!.{..u. .Q.".}. ..%6H* 6**H6Q 6 *#'*}66' **T6c6*"*Q6]6* *6c 6*$*l'Y6'*6'x6o*Y6'**6Q6**| 6M 6*#*'~6'6**]6H6*"*Y6@6*6E*l6 * 6*'|'*66T'c*x6'*!6x*~6*6`*x6 *!6'{*6*'6O*c6*6o*x6*6H*6* '*{6'* 6*'x6x6'* *c6[6**}6H6*$'*6'6**H6J6*$6B*~6**u6Q6*"'*{6'*6*'6H6'**o6O6**|6Y6*%*'6'6**|6f6**|6f6**i6J6*"6'V*{'*66x'*`6'*6x*o6*6=* 6 * 6*''6*6E*6*!6o*6 *6Y*|6 *6'*'6*6*o'6 '*6r*o6*6M*6* '*6'*6*l6V6**6Q6**6T6*'*r6'* 6*'x6T'6**6x*6*6=6*!'*u6'*6*6=6* *6Q6**O6B6*#*'6'*6*{'~6u6 '*11'.E.'..#.M.(..#.[.+.c.'.V.-.o. .f..T..V.".Y"..r....u..V ..Y!..}#..u!....!.. ..`..Q..x. ."..r.. .. ..|..o .4*4L...l..i..|. .}..H.!.!... .o..u ..x ....i..|. ...... .. .`. .i. .Y..|. .. .r....`.."..~....$.4%4S...T.".{ ..=..i.".i.%.].#.`.#.`.".o.#.T.#.V.&.].(.c."4|#4S.V.&.r.#.|.".o.#..#..!4"4.u.(.O.$.o.".c.".|. ..!.O."4}"4.l.#.Q.#.x.".l.".]..o. .l.4{$4.i.&..".}..Q.".Q.".`..i.4"4.].).].#.|.!.Q.!.`. .|.#..4i 4.O.'.Q.$.u.".~.!.l.%.Q."..4!4.].&.u..~.".o. .u.$..%..4c!4.u.)..!.{..u. .Q.".}. ..!..'.E.'..#.M.(..#.[.+.c.'.V.-.o. .f..T..V.".Y"..r....u..V ..Y!..}#..u!....!.. ..`..Q..x. ."..r.. .. ..|..o .4*4L...l..i..|. .}..H.!.!... .o..u ..x ....i..|. ...... .. .`. .i. .Y..|. .. .r....`.."..~....$.4%4S...T.".{ ..=..i.".i.%.].#.`.#.`.".o.#.T.#.V.&.].(.c."4|#4S.V.&.r.#.|.".o.#..#..!4"4.u.(.O.$.o.".c.".|. ..!.O."4}"4.l.#.Q.#.x.".l.".]..o. .l.4{$4.i.&..".}..Q.".Q.".`..i.4"4.].).].#.|.!.Q.!.`. .|.#..4i 4.O.'.Q.$.u.".~.!.l.%.Q."..4!4.].&.u..~.".o. .u.$..%..4c!4.u.)..!.{..u. .Q.".}. ..%6H* 6**H6Q 6 *#'*}66' **T6c6*"*Q6]6* *6c 6*$*l'Y6'*6'x6o*Y6'**6Q6**| 6M 6*#*'~6'6**]6H6*"*Y6@6*6E*l6 * 6*'|'*66T'c*x6'*!6x*~6*6`*x6 *!6'{*6*'6O*c6*6o*x6*6H*6* '*{6'* 6*'x6x6'* *c6[6**}6H6*$'*6'6**H6J6*$6B*~6**u6Q6*"'*{6'*6*'6H6'*$6H* 6**H6Q 6 *#'*}66' **T6c6*"*Q6]6* *6c 6*$*l'Y6'*6'x6o*Y6'**6Q6**| 6M 6*#*'~6'6**]6H6*"*Y6@6*6E*l6 * 6*'|'*66T'c*x6'*!6x*~6*6`*x6 *!6'{*6*'6O*c6*6o*x6*6H*6* '*{6'* 6*'x6x6'* *c6[6**}6H6*$'*6'6**H6J6*$6B*~6**u6Q6*"'*{6'*6*'6H6'*$6H* 6**H6Q 6 *#'*}66' **T6c6*"*Q6]6* *6c 6*$*l'Y6'*6'x6o*Y6'**6Q6**| 6M 6*#*'~6'6**]6H6*"*Y6@6*6E*l6 * 6*'|'*66T'c*x6'*!6x*~6*6`*x6 *!6'{*6*'6O*c6*6o*x6*6H*6* '*{6'* 6*'x6x6'* *c6[6**}6H6*$'*6'6**H6J6*$6B*~6**u6Q6*"'*{6'*6*'6H6'*$6H* 6**H6Q 6 *#'*}66' **T6c6*"*Q6]6* *6c 6*$*l'Y6'*6'x6o*Y6'**6Q6**| 6M 6*#*'~6'6**]6H6*"*Y6@6*6E*l6 * 6*'|'*66T'c*x6'*!6x*~6*6`*x6 *!6'{*6*'6O*c6*6o*x6*6H*6* '*{6'* 6*'x6x6'*/MTrk!Bass"d @][`r;c;V@4Q;J;H;T;J;B;B;T;H;J;J;J;B%@`;f5@M;Q;`;`;`;Y;H;E;O;T;M;O;];T;@o;:;@J;O;H;T;E;@;J;J;E;Y;T;O;J;O.@ !|'@!=!T;!!M;!!O;!!J;!!T;!!Y"@!f @H;J;J;H;O;M;=;x @2O@4Y;O;T;J;O;O;T;O;@;H;E;M;Y;f8@!o*@!!O;!!O;!!M;!!T;!!J;!!O;!!V&@!l@"M;O;J;Y;T;H;V)@#Y@##B;##B;##T;##H;##E;##E;##E-@#f!@V;f;O;E;T;r;`,@#`@!##T;##O;##Y;##`;##Y;##Q;##f@&#l@-`;V;E;Y;B;H;O.@ #f!@##M;##Y;##Q;##O;##Y;##O;##M,@#M@M;Y;Y;H;T;f;T0@ !o@#!!T;!!O;!!J;!!Q;!!H;!!T;!!](@!#o@##`;##T;##T;##Y;##Y;##r;##'@#@T`"TJM`!E"cQOE#ETr T@f"@ O!f$`#l"T[YTE T]TOT ]&@!|@!!Y! !c!"!f!"!f!!!Y!$!Y!#!c!!@@f"Y Yu Y!i l]T!O!@ TJTV YO ff@Y@Y`!u%@!!@!!Q!!Y!"!T!$!Y!%!T!#!f!'!T&!@~0 3@"{"T [ T!]x @#r@##Y#"#O###M#%#H#"#Y#&#`#$#M@#@`r] roi" @#`@##T# #`# #T#"#f# #Y#!#M##f@#~@V ff!f f ~"#@#`@##Y##V#%#T#%#O#%#H#%#f##O@#| @`f"Mi"Q{"["@!{@!#!Y!!!V!!!`! !l!!!Y!!!c!"!f%!@#|@##O##Y##Y#"#J##`# #V ##u #@f@:TY@ `@ `T!x$@!J@! !T!!H!"!Y@!!u @!!f!!!`!!!H@!#x@##E#"#J#"#Y@ #@#`##J# #T!##]@#` @TO"T$@Y @Y"OO  @u@B!H'O!@x@T M J@!`@!!O!"!O!!!H@!!!M@! !B!"!E! !O@!#`@##E#"#`#"#O#@ #Y @##O#"#T#"#T@ #]@JY O@o@Mc(f @!@T`"TJM`!E"cQOE#ETr T@f"@ O!f$`#l"T[YTE T]TOT ]&@#|@##Y# #c#"#f#"#f#!#Y#$#Y###c!#@@f"Y Yu Y!i l]T!O!@ TJTV YO ff@Y@Y`!u%@#!@##Q##Y#"#T#$#Y#%#T###f#'#T&#@~0 3@"{"T [ T!]x @%r@%%Y%"%O%#%M%%%H%"%Y%&%`%$%M@%@`r] roi" @%`@%%T% %`% %T%"%f% %Y%!%M%%f@%~@V ff!f f ~"#@%`@%%Y%%V%%%T%%%O%%%H%%%f%%O@%| @`f"Mi"Q{"["@#{@###Y#!#V#!#`# #l#!#Y#!#c#"#f%#@%|@%%O%%Y%%Y%"%J%%`% %V %%u %@@T`"TJM`!E"cQOE#ETr T@f"@ O!f$`#l"T[YTE T]TOT ]&@#|@##Y# #c#"#f#"#f#!#Y#$#Y###c!#@@f"Y Yu Y!i l]T!O!@ TJTV YO ff@Y@Y`!u%@#!@##Q##Y#"#T#$#Y#%#T###f#'#T&#@~0 3@"{"T [ T!]x @%r@%%Y%"%O%#%M%%%H%"%Y%&%`%$%M@%@`r] roi" @%`@%%T% %`% %T%"%f% %Y%!%M%%f@%~@V ff!f f ~"#@%`@%%Y%%V%%%T%%%O%%%H%%%f%%O@%| @`f"Mi"Q{"["@#{@###Y#!#V#!#`# #l#!#Y#!#c#"#f%#@%|@%%O%%Y%%Y%"%J%%`% %V %%u %@O@H"H"7#OB!B!E'@#H@##:#!#@#"#0#%#E##:##@##7@#%J@ %%E% %= %%=%%E%%@%%B% %B@ %T@ B T @JH T!O@J@ @TM$O TO `@#T@##@# #=#"#@#"#H#!#B#"#H##H@#%M@%%:%%E%%:%%@% %E%%J%%M!@%E@ E"E@MO OJ@f @@"B EO O O H@#H@##B#!#B ##:##$#:#$#@# #@#@%B@%%B% %B%%B% %J%%B%%B% %T %@V@M@#M#H @!E$BHHT!M O#JO!J#@#B@# #@#!#H#"#O#!#O##@#%#@#"#H@#%Y @%%J%#%B% %O%!%H%"%B%$%H% %V!% @E/MTrk,!Guitarj (][(c3:?::0&?3: ;J@H4@%@;44E;J@M"44E;@ 44H;J@Q44B;@44V;T@O44O;@44M ;Y@T44Y;@44c;O@] 44c@ ; 44c;Y@c44Y;@44c;c@c44B ;@43Y?T:c;:?3@H;H4E+@4;4`;O@Y44@;@4'4c@c;]44O@;4$4T;c@c4@;4B4#4c;c@]4@;4]4#4c;c@Y4;@4H4!4J;c@]4@ 4M;44O;T@T44M;@4"4c@Y;]4;@4T4;Q4c@T"4;@4O4;Y@V4Q#4;@4E4;Q@M4Q#4@;4Y44Y@Y;c 4;@4J44T@Y;Y"4 @;4J$44J;c@T&4@; 4Y!44V;c@`44M;@44J-c9Ta99V@44 9-4'9J-3-4940-39:4-94M-@9@-494@-:9794- @4M;`@M4@;@47;:@E4;@4E;=@J4@;4@;3@E@;44H;B@H@4;4B;:@J@;4"4B;J@M@;44B;0@@4@;@4c;`@` 4;@ 4B44T;J@O#4;@4@44c@c;c$4@;4J44M@T;O&4;@4B 44B@`;]%4@;4E"44Y@Y;Y"4@;4B44E;T@]4;@4E#44O;c@Y44@4;@ 4c-c9cR9 -4@479E-E349-94O-M9O49-9E4:-7-49!9@47-79-49E4E-3 -94@@Y;T4`%@447@;44M;T@J@!44B@@;44O;J@H$4@; 4E$4;T@V4Y!44@@; 4@/B;]6Y0@/ ;/:6/ ;H67/B6/;/H/;Y6B/@"/6;/: ;+6/;6 /J;c6O;/6/O;M6E6; / @ @`4c;J;4@@;7@H44@; ;B4B@@@;447;:@=@;4;J4=@B@;4;34=@B@;4";E43@H@;4#;H4B@M@4; @/T;V6E@/;6/O;J63;/6/H;:63;/6 6:/T;:;6/6B;7/7;6/6@;7/@; 6/ ;O6@/O;6/6H;T/B;6/@@M;Q4H@;@4;J@H4H@;4!;=4B@H@;443;:@H@;4 ;E40@H@;4";J4E@J@;4 ;O4@@T@;4!47;J@H;4@@/J6M;O@;/6/=;B63;/6/T;E6:;6/!6:/:;B;6/ ;E67/O;6/;H6@/O;6/;:67/T;6/!;H/Y636;/ @;O@Y4E@;4@;E47@H@;4;B4=@H@;4 ;=4@@7@;4";J4:@B@4;$;347@E@;4#;J4:@T@;4;B4B@:@;@4 4O9Y-B@94--:9H4=9-4-O9H4=9-4-B9H43-94-J9B4:9-4 9E47-@9-4"4@9@-@9-4!9E43-E94-@;]6H/H@;/660;@/:;/6;=6B/O;/6;B67/O;6/;E6@/T;6/;763/H;6/;E67/J;6/#/B;@6'6/;@;Y@Y4Y 4 ;@;B4@@H@4;'4Q;T@Y&44=;@4;V@Y4Y$440 ;@4"4Y;Y@Y'4@;4@4#4T;Y@Y$4;@4E 4;Y@Y4Y"4@;4B4;Y4Y@T&44J;@4;Y4Y@Y%44O;@4@T;Y4Y&4;@4B"4;T4Y@V(44E;@$4;Y@Y4Y'4@;47%4;Y@Y4Y#4@;4:"4 4Y;Y@Y44J;@%4;Y@Y4O(44B @;!4;Y@Y4O%44B @;"4 @Y;Y4J44Y;@"4-Y9Y4QC@-94-@4H9O%9-4M9O4J-E9-4-B9T43-94 9J-E47-94-B9B409-4@@V4Y;Q4 @4O@; @44Y@];Y'443 ;@4#4Y;]@V"4@;4:4!;Y4Y@Q!4;@4:4#4Y;M@T @4;@474@ ;Q4Y@O&4@;@4B 44Y@M;O@$4; 43@@44T@M;J@ 4@ 4B;@ 44T;Y@J44B;@@4@Y;Y4Y'4@;4J@@4@V;Y4Y'4@;4B%4@V;J4:4@;4Y#49Y4Y-J1@ 49--J9T4B+- 9499Y-H4E-94-B974H-94-:9@4@-94-: 9E439-4 @@T;`4H44@@; 4"@Y;Y4Y#44J @;4 ;Y4Y@Y 4;4J@44Y;Y@Y 4;@4E4!/O;M6M/@;6/T;76:;/6/E;@63/;6/B;@67/;6/O ;:63/;6/O ;J6+ / ;6/O;B67/;6/H;T6+ 6/;@@T;J4O@;4@;:@J47;@4 4B;O@B;@4;@47@3@;4!;B4@@E;@447;E@H;@4"4@;O@J;4@!;B43@H4;@@;]6J/:;6/@/@;763;/6/B ;O67/;6/B ;B60 /;6/J;H6E/ ;6/B;O6:/;6/Y;H67/;6/Y;E606;@/;f@O4O@@;4;@4=@E@;4";O4B@T;@4 ;E4:@0@;4"4@;B@M;@44E;B@B@;4 @;T4B@O4;@@;B4:@B4;@@/E;Y6=6; / /#;H67@ ;6//J;O63/;6/H ;:6/;6/J ;M63/;6/: ;@6+/;6/T ;Y6@/;6/`;H676/;@@V;H4Y@;4@;B4@@B@;4!;T4B@M@;4;@4B@E@;4";Y4M@O;@4#;M4E@M@4;$@M;B4:;4@@@;E4+;@@4-O4=9T@-94-B974'-94-H 9@43-94-@ 9@4+-94-O 9B43-94-B974:9-4-J9H479-4!9O47-@49-@;`6H/H@6;/;B/O6:6;/ /O/ /=/%/=/%/7/s@;|4x@V'4 ;@4=4@Y;Q4T(4;@4"44l;u@i'4;@ 4H"4@o4Y;] 4; @4T!44|-O9`'-49-T"--V4B9V)-49-E--E9]4O%-49-E- -H9f4o(-49-:-&/r;i6Y"//T6; /#/u;O6E#//O 6;//f;J6T"//c6;/ /;V6E#/6/Q; / @`;M4V$4;@4#44Y;Q@Y'44:@;44Y;`@i"4@;4H!44]@f;T!4@4:;4;O@E4V44E@;44|;f@`!4@;4H44c@T;` 4;@4E4@c4o;`4;@4Y$4-c49i!-94-T--`9c4Y%--E49 -"-f9u4T!- 49 -E-$-Q9]4` --@94 -"/u;`6O/6;/T/#/r;M6J/6;/`/!/i;x6T /;6/Q/ /u;o6O /6;/B/";f4J@c&443 @;4;f4O@]%4@;474#4u;u@Q%4;4E@#4;|4f@i'44:@;"4;Y@Y4Y 4 @;;B4@@H@4;"@Y4Q;T(4;4= @4;V@Y4Y$4@;404!4Y;Y@Y'4@;4@44T;Y@Y&4@;4E 4;Y@Y4Y"4@;4B4;Y4Y@T&4;@4J4 ;Y4Y@Y%44O@;4BT=Y6Y&6=B6B"6=T6YBV(66EB=%6=YBY6Y'6B=67%6=YBY6Y#6B6:=66Y=YBY!6B=6J(6=YBY6O(6B=6B+6=YBY6O%6B=6B,6BY=Y6J6=B6Y(6/Y;Y6QB@6/; /@6H;O%;6/M;O6J/E/;6!/B;T63;6/ ;J/E676/;!/B;B60;6/@BV6Y=Q 6@=B6O@ 66YB]=Y(663=B66Y=]BV"6B=6:6"=Y6YBQ"6B=6:6#6Y=MBT@6B=676@=Q6YBO&6@B=6B 66YBM=O@$6=B63@ 66TBM=J@6=B6B!@66T=YBJ!6 =B6B!@6BY=Y6Y'6@B=6J"@6BV=Y6Y'6=B6B%6BV=J6:6#B=6Y#6;Y6Y/J4@6/;"/J;T6B,/;6@;Y/H6E/;6/B;76H/;6/:;@6@/;6/:;E63;6/@=`BT6H6B=6@6 BY=Y6Y#6 =B6J6 =Y6YBY!6 =B6J!66Y=YBY 6 =B6E61O=M8M1=@81T=78:=811E=@83=811B=@871=8 1O=:83=181O=J8+8=1"1O=B871=81H=T8+ 8 =1@BT=J6O@6=B=:BJ67B6=%6B=OBBB=6=@67B3B6=$=B6@BEB=6 67=EBHB=6"6@=OBJ=B6!=B63BH6=B@=]8J1:=81@1@=783=811B=O87=181B=B80=18"1J=H8E=811B=O8:18= 1Y=H8781= 1Y=E808=@1=fBO6O@B=6=@6=BEB=6!=O6BBTB=6 =E6:B0B=6#6@=BBMB=6 6E=BBBB=6 @=T6BBO6=B@=B6:BB6=B@ 1E=Y8=8= 11#=H87@ =8 11J=O831=81H=:8=81 1J=M831=81:=@8+8=11T=Y8@18= 1`=H878=1@BV=H6Y@6=B=B6@BBB=6"=T6BBMB=6=@6BBEB=6#=Y6MBO=B6"=M6EBMB6=$BM=B6:=6BB@=E6+=B@6/O6=;T;@/6/B;76';6//H;@63;/6/@;@6+;/6/O;B63;6//B;76:;6/"/J;H67;/6";O67/@6;/@=`8H1H18@==B1O8:8=1!1O11=1"1=1$171x@=YBY6Y 6 B==B6@BHB6=#6Q=TBY(6B=6=%6=VBY6Y$6B=606!6Y=YBY'6B=6@66T=YBY&6B=6E 6=YBY6Y"6B=6B6=Y6YBT&6=B6J6 =Y6YBY%6B=6O"6BT=Y6Y&6=B6B"6=T6YBV(66EB=%6=YBY6Y'6B=67%6=YBY6Y#6B=6:"66Y=YBY!6B=6J(6=YBY6O(6B=6B+6=YBY6O%6B=6B,6BY=Y6J6)=B6Y(6/Y;Y6QB@6/; /@6H;O%;6/M;O6J/E/;6!/B;T63;6/ ;J/E676/;!/B;B60;6/@BV6Y=Q 6@=B6O@ 66YB]=Y(6=B6366Y=]BV"6B=6:6"=Y6YBQ"6 B=6:6#6Y=MBT@6B=676@=Q6YBO&6B=@6B 66YBM=O@$6B=63@ 66TBM=J@6=B6B!@66T=YBJ!6B=6B!@6BY=Y6Y'6@B=6J"@6BV=Y6Y'6=B6B%6BV=J6:6#B=6Y#6;Y6Y/J4@6/;"/J;T6B,/;6@;Y/H6E/;6/B;76H/;6/:;@6@/;6/:;E63;6/@BT=`6H6=B6@6 BY=Y6Y#6=B6J6 =Y6YBY!6 B=6J!66Y=YBY 6 B=6E61O=M8M1=@81T=78:=811E=@83=811B=@871=8 1O=:83=181O=J8+8=1"1O=B871=81H=T8+ 8 =1@BT=J6O@6=B=:BJ67B6=%6B=OBBB=6=@67B3B6=$=B6@BEB=6 67=EBHB=6"6@=OBJ=B6!=B63BH6=B@=]8J1:=81@1@=783=811B=O87=181B=B80=18"1J=H8E=811B=O8:18= 1Y=H8781= 1Y=E808=@1=fBO6O@B=6=@6=BEB=6!=O6BBTB=6 =E6:B0B=6#6@=BBMB=6 6E=BBBB=6 @=T6BBO6=B@=B6:BB6=B@ 1E=Y8=8= 11#=H87@ =8 11J=O831=81H=:8=81 1J=M831=81:=@8+8=11T=Y8@18= 1`=H878=1@BV=H6Y@6=B=B6@BBB=6"=T6BBMB=6=@6BBEB=6#=Y6MBO=B6"=M6EBMB6=$BM=B6:=6BB@=E6+=B@6/O6=;T;@/6/B;76';6//H;@63;/6/@;@6+;/6/O;B63;6//B;76:;6/"/J;H67;/6";O67/@6;/@=`8H1H18@==B1O8:8=1!1O11=1"1=1$171x@Z6=6BY=Q6T(6=B6"66l=uBi'6=B 6H"6Bo6Y=] 6= B6T!66|/O;`'/6;/T"//V6B;V)/6;/E//E;]6O%/6;/E/ /H;f6o(/6;/:/&1r=i8Y"11T8= 1#1u=O8E#11O 8=11f=J8T"11c8=1 1=V8E#181Q= 1 B`=M6V$6=B6#66Y=QBY'66:B=66Y=`Bi"6B=6H!66]Bf=T!6B6:=6=OBE6V66EB=66|=fB`!6B=6H66cBT=` 6=B6E6Bc6o=`6=B6Y$6/c6;i!/;6/T//`;c6Y%//E6; /"/f;u6T!/ 6; /E/$/Q;]6` //@;6 /"1u=`8O18=1T1#1r=M8J18=1`1!1i=x8T 1=81Q1 1u=o8O 18=1B1"=f6JBc&663 B=6=f6OB]%6B=676#6u=uBQ%6=6EB#6=|6fBi'66:B="66d=dBd66=B=6BY=Q6T(6=B6"66l=uBi'6=B 6H"6Bo6Y=] 6= B6T!66|/O;`'/6;/T"//V6B;V)/6;/E//E;]6O%/6;/E/ /H;f6o(/6;/:/&1r=i8Y"11T8= 1#1u=O8E#11O 8=11f=J8T"11c8=1 1=V8E#181Q= 1 B`=M6V$6=B6#66Y=QBY'66:B=66Y=`Bi"6B=6H!66]Bf=T!6B6:=6=OBE6V66EB=66|=fB`!6B=6H66cBT=` 6=B6E6Bc6o=`6=B6Y$6/c6;i!/;6/T//`;c6Y%//E6; /"/f;u6T!/ 6; /E/$/Q;]6` //@;6 /"1u=`8O18=1T1#1r=M8J18=1`1!1i=x8T 1=81Q1 1u=o8O 18=1B1"=f6JBc 1]*V6$=B:1 */MTrk9!GuitarU P[@]@_@O @@@O@!@+@%@7@'@:@&@=@#@J@@B@@@M@ @@O@$@H@$@=@%@@@%@H@%@H@"@H@@@M@@@O@#@@@#@J@$@@@#@B@'@H@$@M@@ @J@ @@@@"@B@'@0@*@J@%@0@(@J@'@:@@#@O@@ @E@!@J@&@0@)@B@)@:@)@@@'@B@@"@H@@"@@@'@@@%@:@'@H@#@:@!@@@#@J@@#@H@@ @B@%@B@&@@@&@E@$@J@'@=@%@E@ @#@H @ @"@:@$@B@#@H@(@=@&@B@!@:@ @B+@@L@@M"@@:@$@:@&@@@(@@@&@3@$@M@ @M@@#@O @@ @B@%@E@(@@@'@@@(@H@(@7@'@B@ @@J@@"@:@&@@@&@H@&@H@%@:@&@B@"@J@@%@J@@#@@@(@E@'@B@%@@@&@=@$@J@(@B@@#@M@ @"@:@%@B@%@@@(@J@&@B@(@H@#@J @ @"@O @@#@H@)@E@&@7@(@H@#@3@&@7@'@H@@#@H@@'@7@,@H@%@7@&@:@%@B@#@E@ @J@@!@J@ @!@:@"@7@$@3@#@=@ @H@%@E@!@O@@"@lu@@u@@lu@@u@@u@@u@@u@@u@@u@@u@@u@@ru@@u@@u@@u@@u@@u@@~u@@fu@@u@@xu@@u@@fu@@u@@xu@@u@@{u@@xu@@xu@@u@@u@@u@BluBBuBBluBBuBBuBBuBBuBBuBBuBBuBBuBBruBBuBBuBBuBBuBBuBB~uBBfuBBuBBxuBBuBBfuBBuBBxuBBuBB{uBBxuB BT}B/MTrk1!Guitarj P][(]'T3E.B<.(T/04@3'$/(4(Y4M/:@/(4 (J4E/0#/(4@(O4O/B&(/4(Y4B/@@(/4(@4O/3%/4((B/74T @/(4(@/74B%4/((:/E4M@"4(/(J/+4@&/4( @(Y4J/:%(/4(`4B/3@(/4(Q4f/B$(/4(T/:4O"/(4(T/@4f@ /(4'T3Y.T&.3' (B/34B /(4(O4`/J'/@(4(Y4T/@&/(4(J/34B@/4((O/@4Y&/(4(E/@4f(/4(@(Y/=4`&4/((B/34E'4/@( (T/=4B%(4/(@4T/7&(/4 @ (T/E4O&4(/(B/:4M&/4(/=(T4`@ /4(4Y/=(]&(4/(M4J/: @(4/(B4T/3$(/4@(Y4Y/:%4/(/34O(H@ 4(/(@4T/3%4(/(M4J/3&4/(@(E47/7&4/(4:/7(B$4/(@/@4H(B"4/((:/+4E&(4/(T/:4V@ 4(/4Y/J(B%/4((J4Y/J@4/((@4:/:%4/(/=4O(B@ 4/(4`/:(V'(/4(B4E/@#/4(4x-o@=-4!4J-@(-4Q4T-B4-4E-E-4-34T4--H4T4-@(@4H/@$/(4(H4@/:!@4(/(B4T/3%(4/(H/:4E@$4(/(V4T/E&4/( @(H/@4V%(/4(J/74O&(4/@4B/E(B&/(4/H(Y4O&4/(4H/:(T@/(4(E4H/3&4(//:4B(O@$(4//B(T4M'4(/@4E/=(O&(4/(B4H/7&4/(/@4T(H@#/(44@/:(H&/(44B(M/@@#/4((@/74=&/4(4O/T(E@#4(//@(T4H&(4/@(J/E4V&/4((J/M4O&4(/(O/@47@ /4(4]-T@@-4%4T-J,-4C4H-B&-44O-:&-44M-H'4-4B-H@-44J/H'/4(`4`/T@ /(4(Y4T/E'4(/(T@/=4T&(4/(T/H4H'(4/4Y(O/@@'/(4(T4H/@(/4(4H/7(J@ /4(/:6}$@6//=6T'6/6B/='/66:/@'/66J/O&/66J/@&6//T6o'6/6O/7 @6//B(V4V@/(4(]/:4B'4(/(V/:4H&4(/(O/:4=&/4((o/:4T&4(/(Y4B/:&4/((Q4M/7&/(4(`4H/3@ 4/(6M/H@/66O/:&/66M/7&/6/76E&66M/@!//6/76H&6//J6f'6/6J/:@ /64Y/3(J@ (/4(O/74@$(/4(O/:4@%(/4(Y/74M$4/(/E(O4=%/(4(T4B/H&/(4(B4O/@%(4/(`4J/:@/(46M/J&/6@6H/3&/6/E6T&6//B6J&6//H6O&6//76O&6//E6o&6/6E/:&6/@(H/H&/(@(M/3%(/(`/J%(/(`/@@/((J/H%(/@(O/J$(/(J/@$(/(M/:@(/4J-J&4-4:-: @-4-74O(4-@4H-B&-44B-E@ 4-4T-E$4-4M-H%4-4H-E@4-6T/E'/66J/O@6//:6B'6/6O/J@/6/O6T'6/6O/E@&/6/O6H'6/6J/T @/6/E4T(J'(4/(O/:4H'4/( @ (O/:4@%(4/ @(M/04=&(4/(:/=4@$(4/@(H/B4O%(/4(J/B4H$(4/@ (B/B4B$(4/(T/=4Y%(/4(H/H4T @(4/(O/@4M%(/4(`4T/:@(/4/B4c8/4(c(@(H'(4/'(B'(/@4(M4Q/B&4/(/E(J4: @4/((B/=4@&(4/4H/J(O@#(/4(H4J/J'/4(@(J/B4J'4/((7/E4M'4/(@/@4H(M'(4//@4M(V'(4/ @ /@(J4M'4(/(O/O4E'4/(@/@4T(J'(4//H(T4T'4(/@(E/@4M'4/((B/E4B'4/((:/:4M @4/(4O-YL-4@-H4Y24-B4J-7'-44E-:'-44Y-J'-44E-J&@-4(O4T/J'/(4(=4Q/@@$(/4(M/H4O/4@(/74O(J/4(/E4H(B%/(4(:/E4T@/(4(T/J4O"4(/('/:4J @(4/(H/E4T$4(/(H4T/J@&/4((T4T/O$4/((M/O4] @4/((O4`/B&(/4(E/H4O@4(/(B/O4V%(4/(H/M4Y@(4//M(J4B'4(/(Y/T4J@4/((O/H4T'4/(/M(Y4H@4(//J4J(J'(4/(Y/T4M@$4/((O/J4M'4/((@/M4T@(4/4T-TF@4-4T-E%-4K4T-='-4-=4H%-4-@4O'4--:4H#@4-(E/O4O&/(4(O/:4E @(4/(Y4Y/B#(/4(:/:4H@(4/(:/E4Y&(4/ @ (O/Y4Y%(4/(O4B/B'/4((@/J4M@(4/6c/O'/@66E/:%6/6M/E'/66E/:'/66J/B'/6/:6O'6/6J/@'/6/E6J%@6/(O/T4Y&(4/@(J/74O'4/((T/34H'4/((T4M/H'/4((J4B/:'/4((O/:4J'4/(4@/:(B'(/44H/:(@'(/4@/O6V'6//H6H @6//B6T'6//:6J'6//J6H'6//B6O'6//E6B'6//H6H!@6/(O/H4`%(4/ @(H/@4H%(4/(O/@4B&(4/(:4O/:'/4((B/B4O'4/((H/:4='4/((J4B/E'/4((B4O/B"@/4(6f/T'/6/B6H@$6/6B/:)/66=/7)/6/@6B&/6/:6J&/66H/H&6/6J/7&6/ @ /E(B4H&4/((Y/:4T@/4((Q/@4T%4(/(O4E/7&/(4(E/:4@&/4((O/@4J%/4(/E(H4B&4(/(B/=4E#@/4(4J-Y-4@-H4B4-#-Y4T-4-M4B4-#-H4E-44@-:-44M-B-44@-:-4@6f/O@/6/06B6/!/O6B6/ /@6E/66Y/O/66H/E/66T/M/6 6J/J/6@(`/J@(//E(T(/(Y/J(/(J/:(/(O/B(/(O/B(/(T/B(/(H/E /(@4V-]@4 --J4H-44J-E4-4O-@4-4@-@4-4O-B-4%4O-H-4!-=4J@4-6o/f@ /6/J6Y6/ /J6H6//B6E6/ /H6:/6/@6@/6!/B6J6/ 6M/J6/@/Y(l@ /((T/@/( (=/M(/"/E(@/(%/B(@(/!/@(B(/#/:(@/($/H(O/(@ /`(Q/(@/O(O/((Y/f/( /M(T(/!/T(Y/(/B(T/(/@(M/(/J(O/(@4]-o@ 4-4E-J4-4O-B4-4J-E-4 -J4M4-4T-@-4!4f-J-44M-@@4-6`/]@/ 6/O6T/6/T6T6/!6O/H6/!/O6T/6$6c/Y/6#/O6O6/6f/Y/6@/T(O@ /((T/B/((O/T(/(J/@(/(T/Y(/(Y/B(/(f/T/((J/J(/@[(O/:4H'4/( @ (O/:4@%(4/ @(M/04=&(4/(:/=4@$(4/@(H/B4O%(/4(J/B4H$(4/@ (B/B4B$(4/(T/=4Y%(/4(H/H4T @(4/(O/@4M%(/4(`4T/:@(/4/B4c8/4(c(@(H'(4/'(B'(/@4*M6Q1B&61*1E*J6: @61**B1=6@&*616H1J*O@#*16*H6J1J'16*@*J1B6J'61**71E6M'61*@1@6H*M'*611@6M*V'*61 @ 1@*J6M'6*1*O1O6E'61*@1@6T*J'*611H*T6T'6*1@*E1@6M'61**B1E6B'61**:1:6M @61*6O/YL/6@/H6Y26/B6J/7'/66E/:'/66Y/J'/66E/J&@/6*O6T1J'1*6*=6Q1@@$*16*M1H6O16@*176O*J16*1E6H*B%1*6*:1E6T@1*6*T1J6O"6*1*'1:6J @*61*H1E6T$6*1*H6T1J@&16**T6T1O$61**M1O6] @61**O6`1B&*16*E1H6O@6*1*B1O6V%*61*H1M6Y@*611M*J6B'6*1*Y1T6J@61**O1H6T'61*1M*Y6H@6*11J6J*J'*61*Y1T6M@$61**O1J6M'61**@1M6T@*616T/TF@6/6T/E%/6K6T/='/6/=6H%/6/@6O'6//:6H#@6/*E1O6O&1*6*O1:6E @*61*Y6Y1B#*16*:1:6H@*61*:1E6Y&*61 @ *O1Y6Y%*61*O6B1B'16**@1J6M@*618c1O'1@88E1:%818M1E'188E1:'188J1B'181:8O'818J1@'181E8J%@81*O1T6Y&*61@*J176O'61**T136H'61**T6M1H'16**J6B1:'16**O1:6J'61*6@1:*B'*166H1:*@'*16@1O8V'811H8H @811B8T'811:8J'811J8H'811B8O'811E8B'811H8H!@81*O1H6`%*61 @*H1@6H%*61*O1@6B&*61*:6O1:'16**B1B6O'61**H1:6='61**J6B1E'16**B6O1B"@16*8f1T'181B8H@$818B1:)188=17)181@8B&181:8J&188H1H&818J17&81 @ 1E*B6H&61**Y1:6T@16**Q1@6T%6*1*O6E17&1*6*E1:6@&16**O1@6J%16*1E*H6B&6*1*B1=6E#@16*6J/Y/6@/H6B6/#/Y6T/6/M6B6/#/H6E/66@/:/66M/B/66@/:/6@8f1O@18108B81!1O8B81 1@8E188Y1O188H1E188T1M18 8J1J18@*` **O1:6H'61* @ *O1:6@%*61 @*M106=&*61*:1=6@$*61@*H1B6O%*16*J1B6H$*61@ *B1B6B$*61*T1=6Y%*16*H1H6T @*61*O1@6M%*16*`6T1:@*161B6c816*c*@*H'*61'*B'*1@6*M6Q1B&61*1E*J6: @61**B1=6@&*616H1J*O@#*16*H6J1J'16*@*J1B6J'61**71E6M'61*@1@6H*M'*611@6M*V'*61 @ 1@*J6M'6*1*O1O6E'61*@1@6T*J'*611H*T6T'6*1@*E1@6M'61**B1E6B'61**:1:6M @61*6O/YL/6@/H6Y26/B6J/7'/66E/:'/66Y/J'/66E/J&@/6*O6T1J'1*6*=6Q1@@$*16*M1H6O16@*176O*J16*1E6H*B%1*6*:1E6T@1*6*T1J6O"6*1*'1:6J @*61*H1E6T$6*1*H6T1J@&16**T6T1O$61**M1O6] @61**O6`1B&*16*E1H6O@6*1*B1O6V%*61*H1M6Y@*611M*J6B'6*1*Y1T6J@61**O1H6T'61*1M*Y6H@6*11J6J*J'*61*Y1T6M@$61**O1J6M'61**@1M6T@*616T/TF@6/6T/E%/6K6T/='/6/=6H%/6/@6O'6//:6H#@6/*E1O6O&1*6*O1:6E @*61*Y6Y1B#*16*:1:6H@*61*:1E6Y&*61 @ *O1Y6Y%*61*O6B1B'16**@1J6M@*618c1O'1@88E1:%818M1E'188E1:'188J1B'181:8O'818J1@'181E8J%@81*O1T6Y&*61@*J176O'61**T136H'61**T6M1H'16**J6B1:'16**O1:6J'61*6@1:*B'*166H1:*@'*16@1O8V'811H8H @811B8T'811:8J'811J8H'811B8O'811E8B'811H8H!@81*O1H6`%*61 @*H1@6H%*61*O1@6B&*61*:6O1:'16**B1B6O'61**H1:6='61**J6B1E'16**B6O1B"@16*8f1T'181B8H@$818B1:)188=17)181@8B&181:8J&188H1H&818J17&81 @ 1E*B6H&61**Y1:6T@16**Q1@6T%6*1*O6E17&1*6*E1:6@&16**O1@6J%16*1E*H6B&6*1*B1=6E#@16*6J/Y/6@/H6B6/#/Y6T/6/M6B6/#/H6E/66@/:/66M/B/66@/:/6@8f1O@18108B81!1O8B81 1@8E188Y1O188H1E188T1M18 8J1J18@*`1J@*11E*T*1*Y1J*1*J1:*1*O1B*1*O1B*1*T1B*1*H1E 1*@6V/]@6 //J6H/66J/E6/6O/@6/6@/@6/6O/B/6%6O/H/6!/=6J@6/8o1f@ 181J8Y81 1J8H811B8E81 1H8:181@8@18!1B8J81 8M1J81@1Y*l@ 1**T1@1* *=1M*1"1E*@1*%1B*@*1!1@*B*1#1:*@1*$1H*O1*@ 1`*Q1*@1O*O1**Y1f1* 1M*T*1!1T*Y1*1B*T1*1@*M1*1J*O1*@6]/o@ 6/6E/J6/6O/B6/6J/E/6 /J6M6/6T/@/6!6f/J/66M/@@6/8`1]@1 81O8T181T8T81!8O1H81!1O8T18$8c1Y18#1O8O818f1Y18@1T*O@ 1**T1B1**O1T*1*J1@*1*T1Y*1*Y1B*1*f1T1**J1J*1@"1J@!11E*T*1*Y1J*1*J1:*1*O1B*1*O1B*1*T1B*1*H1E 1*@6V/]@6 //J6H/66J/E6/6O/@6/6@/@6/6O/B/6%6O/H/6!/=6J@6/8o1f@ 181J8Y81 1J8H811B8E81 1H8:181@8@18!1B8J81 8M1J81@1Y*l@ 1**T1@1* *=1M*1"1E*@1*%1B*@*1!1@*B*1#1:*@1*$1H*O1*@ 1`*Q1*@1O*O1**Y1f1* 1M*T*1!1T*Y1*1B*T1*1@*M1*1J*O1*@6]/o@ 6/6E/J6/6O/B6/6J/E/6 /J6M6/6T/@/6!6f/J/66M/@@6/8`1]@1 81O8T181T8T81!8O1H81!1O8T18$8c1Y18#1O8O818f1Y18@1T*OBT=O6J1*,B=6/MTrk L!Voice @][("GZGGGG| GGGGp GGGG GG| GG|"GG2G ID2GRG&G|GG|GGGGG GG"GGGBG6GGGGGG G9GIc;IGG1GG GG"GpG$GG#GG"GG#GSG%GG"GG"G|G$G&GI&IGmG1GG!G|GGpG"GG$GG%GG!GOG*GG!GpG&GG%GG I"IGsG@`@EVE"DaD@l@ I^IGRGG\GGG!G|G GG!GG!G|G#GG"GG%GG GGI)IGkG E;EDmwD=E!EDZDBiB@,@BRB&DADcDDDD$DD%D|MD+DKD-DaDB)BDm.DE.EDGGGG!GG$GpG#GG%GG%GSG%GG%G|G"GyG$G$GIc!IGyG;GG!G|G"GG#GpG!GG"GG!GmJG.GG$GG$GG#G1G I4IGlG @Q@'EsEDcD@cyI@MIGGeITI#IIIIII"II"IKAKI$II"II!IIIIK:KInI GD4DHLQV[`ejptx|B    !#%D&()+,-/01345789:<@/MTrk !Piano d (][(adOXH@XdXOdMdXXMdOXd#XEdHdX"XJd@dX XEdBdX$XBdBd XXEdBdX$XJdHdX XHdBdX XHd@dX!XEd:dXXMdBdX dEXBXd$XJdJdX X=d@dX$XMdBdX XEd=dX%XMdBdX X@d:dX XJdJdXX=d7dX#XMdYdXd:X7Xd#XHdHXd!XEd@dX#XJdHdX"X@d=dX#XHdBXd!XJdBdXXJdJdXXHdTX@ddTX`Xd@ XOdMdXXOdJdX XHdBdX!dOXJXdXJdBdX!XVd`dXXTdJdX XTdOdX dOXOXd"dOXOXdXOdMdX#XHdMdX!XTdJdX$dMXMXd!XTdYdX"dYXVXd"dOXOXd#X]d`dX!XHdJdX"dTXOXd XHdOdX"dYXYXd!dJXHXd!dOXYXdXOdOXd#XTdOXd#dJXMXdXOdcXd dOXJXd$d]X]Xd$XTdMXd$XYdOXd"XJdOXd"dYX`Xd"XOdTdX"dTXM!XddMXMXd#XidQXddTXTXd"XYd]dXXTdTdX$XTdMdXXOdOXd!dMXTXd#dOXVXd"XTdQXddOXHXd dYXTXd dOXHXd#X`dOdX"XHdOXd"XTdO"XddMXTXd$XQdYXd dJXOXd"dYXQXdXOdTXd"dMXYXd dTXTXddYXYXddQXQXddYXTXdX]du@XdP@dYXYXdXOdOdX"XTdTdX#XOdMdX"XJdMdX$X:dHdX%XOdQXd!XTdHdX#XQdYdX XEdOXd#dYXfXdXOdQdX#XJdTXd XMdMXd$d]XfXdXHdJdX X]d`XdXOdOXd dYXoXd XTdfXd d`XTXddHXOXd"XTdMdX dOX@Xd dOXMXd!d`XTXd!XOd`XddJXOXd!dOX`Xd!dOXTXd"d`XYXd XMdMXd#dYXYXdXTdMdX!XYdOdX XJdMXdX]dTXd!XOdMdX#X`dfXdXHdMXddTXYXddOXJXd!XYdodXXOdHdXXTdOdX XJd`Xd"XOdVXdXOdOdX!dOXTXd!XHdMdX%dOXHXd!dTXOXd"dQXMXd#dTXTXd$X]dVXd"XOdTdX#dTXVXd#dTXTXd!XTdYXd#XTdVdX!dOXVXdX`dMdX XYdY dXX]du Xd@ foZ`Zf#ZVfVZfZxf|ZfZOfTZf!foZuZfZOffZf%Z|f]Zf ZYfuZf$fZ]Zf fQZTZf#Z]fYZf Z]fQfZ#Z|f~ZfZ`fMZf'ZffZ Z~f|Zf!Z|f~Zf#Z|fZf"Z~fYfZ!ZffVfZ%ZcffZ!Z]foZf%ZcfQfZZYfMZf%Zuf]Zf"ZlfVZf%Z]fQZfZof]ZfZTfuZf!ZYf`Zf&Z~fxZfZ]fTZf#ZlfQZf$Z|frZf%ZfoZf#Zcf|Zf Z`f~ZfZofxZf%ZfZfZ`fTZf#ZVflZfZQf]Zf Zff[ZfZYfYZfZofuZfZofofZ!ZufZfZOfQZf"ZYf`ZfZ`foZf!foZ]Zf ZffoZf"Zff`ZfZof`Zf%Z`flZf!ZTfoZf!ZcfVZf"Zof|Zf$ZTfiZfZOfJZf$Z]f~fZ!Z`foZf$ZTf`Zf"ZofOZf"Z`fVfZ#Z]fofZ#ZYflZf ZYffZf$ZYfxZf!ZifoZf$ZffuZf#ZcfZf#ZofZf$Z`ffZf&Z`fcZf!Z]f{Zf%Zuf|fZ%ZYfcZf$f[ZTZf#fYZiZf Z`fTZf!ffZ]Zf$Z]fTfZ$ZlfoZff|ZTZf#ZQfTfZ'Z]frZf%foZ]Zf"Z|foZf@@/MTrk!GuitarU ][(!*O1T1*!*f1@1**`1T*1*O1B1**c1E1**`1T1* 1H*`*11@*~1*6Q/O/6!6H/:/6 /H6O 6/6f/@6/ 6T/E6/6M/H/66O/=/6 6O/T/6!8i1J1 88Y1H18"1B8Y811O8Y81$1O8`81 8M1E18"8T1O18$1J8Y81*Q1f*1*Y1@1* *V1`1*1Y*Q1*1M*Y1**T1Y1*"*`1`1* *T1Y1**o1`1* *T1V1*"1`*Y1**T1J1* *Q1Y1*1`*f1*1T*Q1*1]*Q1*6Y/O/66T/B/6$6u/O6/6`/T6//Y6Q6/6O/T/66~/Q/6 6x/Y/681f188V1T18$8l1V18!1O8c81"1J8{81#8o1f81#8c1O188f1E81*x1o*1*`1]1*!*Y1Y*1!*Y1E1*#*Y1f*1 *O1]*1"*u1l1**T1O/:/ 1*!*Y1l*1*H1]*1"*u1o1**T1V1*1Y*Y*1*o1Y1*!1Y*Y*1 *T1T*16T/V6/ 6Y/H/6!6l/O/66O/E/6%/M6f6/"6Y/E/6&6|/J/6!6o/Y/6$1Y8c18#8u1B18&1Y8|81!1H8f81&8f1J18"8T1B18'8u1B18 1Y8M81*O1V*1*Y1T*1 *O1V*1*T1B*1!1|*Y*1*J1Y1*"*f1M*1*B1T*1!*V1Q*1*J1`*1#*c1o*1"*M1`1*"1`*V1*1V*`1* 1Y*Q*1#1B*V1*6o/H/6!6T/J6/%6f/J/6$/O6i6/$6i/O/6!6V/B/66Y/T/66M/:/6"8u1M1 88T1Y188}1O181f8E81$1Q8Y18#8o1r1881o18 8o1o18/MTrk! Muted Guitar^ P[@]@\@lu@@u@@lu@@u@@u@@u@@u@@u@@u@@u@@u@@ru@@u@@u@@u@@u@@u@@~u@@fu@@u@@xu@@u@@fu@@u@@xu@@u@@{u@@xu@@xu@@u@@u@@u@BluBBuBBluBBuBBuBBuBBuBBuBBuBBuBBuBBruBBuBBuBBuBBuBBuBB~uBBfuBBuBBxuBBuBBfuBBuBBxuBBuBB{uBBxuB/MTrk!I Wanna Be Sedated/MTrk!By The Ramones/MTrk! Sequenced by/MTrk$!sargepp67@earthlink.net/mrpeach/midifile/midifile.c0000644000175000017500000025145213242610310016440 0ustar zmoelnigzmoelnig/** \mainpage midifile.c An external for Pure Data that reads and writes MIDI files * * Copyright (C) 2005-2018 Martin Peach * \section license * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * Latest version of this file can be found at: * http://pure-data.svn.sourceforge.net/viewvc/pure-data/trunk/externals/mrpeach/midifile/ * */ #include "m_pd.h" #include #include #include // for uint32_t #include /* support older Pd versions without sys_open(), sys_fopen(), sys_fclose() */ #if PD_MAJOR_VERSION == 0 && PD_MINOR_VERSION < 44 #define sys_open open #define sys_fopen fopen #define sys_fclose fclose #endif #define NO_MORE_ELEMENTS 0xFFFFFFFF static t_class *midifile_class; #define PATH_BUF_SIZE 1024 #define MAX_TRACKS 128 /* track data is allocated as needed but we need to preallocate space for the pointers */ #define ALL_TRACKS MAX_TRACKS /** [midifile] can be in one of three states: - mfReset: set by midifile_new() and midifile_clode() - mfReading: set by midifile_new() and midifile_read() if a file has been opened - mfWriting: set by midifile_write() if a file has been opened */ typedef enum {mfReset, mfReading, mfWriting} mfstate; typedef struct mf_header_chunk { char chunk_type[4]; /* each chunk begins with a 4-character ASCII type.*/ uint32_t chunk_length ; /* followed by a 32-bit length */ int chunk_format; int chunk_ntrks; int chunk_division; } mf_header_chunk; typedef struct mf_track_chunk { char chunk_type[4]; /* each chunk begins with a 4-character ASCII type. */ uint32_t chunk_length; /* followed by a 32-bit length */ uint32_t delta_time; /* current delta_time of latest track_data element */ uint32_t total_time; /* sum of delta_times so far */ uint32_t track_index; /* current byte offset to next track_data element */ int track_ended; /* non-zero if track has finished */ unsigned char running_status; unsigned char *track_data; } mf_track_chunk; typedef struct t_midifile { t_object x_obj; /** current time for this MIDI file in delta_time units */ uint32_t total_time; /** one MIDI packet as a list */ t_atom midi_data[3]; t_outlet *midi_list_outlet; t_outlet *status_outlet; t_outlet *total_time_outlet; /** a file for reading or writing */ FILE *fP; /** potentially lots of tracks may be written */ FILE *tmpFP[MAX_TRACKS]; /** current directory for relative file paths */ t_symbol *our_directory; /** absolute path to file at fP */ char fPath[PATH_BUF_SIZE]; /** character offset into the file fP */ uint32_t offset; /** play this track, or all tracks if negative. Write to this track */ int track; /** nonzero for text output to console */ int verbosity; /** nonzero if all tracks have finished */ int ended; /** mfReset, mfReading, or mfWriting */ mfstate state; /** First chunk in the midi file */ mf_header_chunk header_chunk; /** Subsequent track chunks. Other kinds of chunk are ignored. */ mf_track_chunk track_chunk[MAX_TRACKS]; } t_midifile; static void midifile_skip_next_track_chunk_data(t_midifile *x, int mfTrack); static void midifile_get_next_track_chunk_data(t_midifile *x, int mfTrack); static uint32_t midifile_get_next_track_chunk_delta_time(t_midifile *x, int mfTrack); static void midifile_output_long_list (t_outlet *outlet, unsigned char *cP, uint32_t len, unsigned char first_byte); static void midifile_dump_track_chunk_data(t_midifile *x, int mfTrack); static unsigned char *midifile_read_var_len (unsigned char *cP, uint32_t *delta); static int midifile_write_variable_length_value (FILE *fP, uint32_t value); static unsigned short midifile_combine_bytes(unsigned char data1, unsigned char data2); static unsigned short midifile_get_multibyte_2(unsigned char*n); static unsigned long midifile_get_multibyte_3(unsigned char*n); static unsigned long midifile_get_multibyte_4(unsigned char*n); static int midifile_read_track_chunk(t_midifile *x, int mfTrack); static int midifile_read_header_chunk(t_midifile *x); static void midifile_rewind (t_midifile *x); static void midifile_rewind_tracks(t_midifile *x); static int midifile_read_chunks(t_midifile *x); static void midifile_close(t_midifile *x); static void midifile_free_file(t_midifile *x); static void midifile_free(t_midifile *x); static int midifile_open_path(t_midifile *x, char *path, char *mode); static void midifile_flush(t_midifile *x); static uint32_t midifile_write_header(t_midifile *x, int nTracks); static void midifile_read(t_midifile *x, t_symbol *path); static void midifile_write(t_midifile *x, t_symbol *s, int argc, t_atom *argv); static int midifile_write_delta_time(t_midifile *x); static void midifile_meta(t_midifile *x, t_symbol *s, int argc, t_atom *argv); static void midifile_bang(t_midifile *x); static FILE *midifile_open_track_file(t_midifile *x, int trackNr); static int midifile_delete_track_file(t_midifile *x, int trackNr); static uint32_t midifile_write_end_of_track(t_midifile *x, uint32_t end_time, int trackNr); static void midifile_float(t_midifile *x, t_float ticks); static void midifile_list(t_midifile *x, t_symbol *s, int argc, t_atom *argv); static void *midifile_new(t_symbol *s, int argc, t_atom *argv); static void midifile_verbosity(t_midifile *x, t_floatarg verbosity); static void midifile_set_track(t_midifile *x, t_floatarg track); static void midifile_dump(t_midifile *x, t_floatarg track); static t_symbol *midifile_key_name(int sf, int mi); void midifile_setup(void); /** midifile_setup instantiates an instance of [midifile] - calls class_new() to register midifile_new() as the constructor and midifile_free() as the destructor * Registers methods: - midifile_bang() - midifile_float() - midifile_list() - midifile_read() - midifile_flush() - midifile_write() - midifile_dump() - midifile_set_track() - midifile_rewind() - midifile_verbosity() */ void midifile_setup(void) { const char aStr[] = "midifile v0.3 20171026 by Martin Peach"; midifile_class = class_new (gensym("midifile"), (t_newmethod) midifile_new, (t_method)midifile_free, sizeof(t_midifile), CLASS_DEFAULT, A_GIMME, 0); class_addbang(midifile_class, midifile_bang); class_addfloat(midifile_class, midifile_float); class_addlist(midifile_class, midifile_list); class_addmethod(midifile_class, (t_method)midifile_read, gensym("read"), A_DEFSYMBOL, 0); class_addmethod(midifile_class, (t_method)midifile_flush, gensym("flush"), 0); class_addmethod(midifile_class, (t_method)midifile_write, gensym("write"), A_GIMME, 0); class_addmethod(midifile_class, (t_method)midifile_meta, gensym("meta"), A_GIMME, 0); class_addmethod(midifile_class, (t_method)midifile_dump, gensym("dump"), A_DEFFLOAT, 0); class_addmethod(midifile_class, (t_method)midifile_set_track, gensym("track"), A_DEFFLOAT, 0); class_addmethod(midifile_class, (t_method)midifile_rewind, gensym("rewind"), 0); class_addmethod(midifile_class, (t_method)midifile_verbosity, gensym("verbose"), A_DEFFLOAT, 0); class_sethelpsymbol(midifile_class, gensym("midifile-help")); post("Hello?"); #if PD_MAJOR_VERSION==0 && PD_MINOR_VERSION<43 post(aStr); #else logpost(NULL, 3, "%s", aStr); #endif } /** midifile_new is called from Pd when a new [midifile] is being instantiated. * - Initializes the state of this [midifile]. - An optional argument is a file name that will be opened here. - Adds outlets for midi_list, total_time, and status. */ static void *midifile_new(t_symbol *s, int argc, t_atom *argv) { t_midifile *x = (t_midifile *)pd_new(midifile_class); t_symbol *pathSymbol; int i; if (x == NULL) { error("midifile: Could not create..."); return x; } x->fP = NULL; x->fPath[0] = '\0'; x->our_directory = canvas_getcurrentdir();/* get the current directory to use as the base for relative file paths */ x->track = ALL_TRACKS; /* startup playing anything */ x->midi_data[0].a_type = x->midi_data[1].a_type = x->midi_data[2].a_type = A_FLOAT; x->state = mfReset; x->verbosity = 1; /* default to posting all */ for (i = 0; i < MAX_TRACKS; ++i) { x->track_chunk[i].track_data = NULL; x->track_chunk[i].track_ended = 0; } /* find the first string in the arg list and interpret it as a path to a midi file */ for (i = 0; i < argc; ++i) { if (argv[i].a_type == A_SYMBOL) { pathSymbol = atom_getsymbol(&argv[i]); if (pathSymbol != NULL) { if (midifile_open_path(x, pathSymbol->s_name, "rb")) { if (x->verbosity) post("midifile: opened %s", x->fPath); x->state = mfReading; if (midifile_read_chunks(x) == 0) midifile_free_file(x); } else error("midifile: unable to open %s", pathSymbol->s_name); break; } } } x->midi_list_outlet = outlet_new(&x->x_obj, &s_list); x->total_time_outlet = outlet_new(&x->x_obj, &s_float); /* current total_time */ x->status_outlet = outlet_new(&x->x_obj, &s_anything);/* last outlet for everything else */ return (void *)x; } /** midifile_close closes the file and its associated temp files. - calls sys_fclose, midifile_delete_track_file, and sets x->fP and all x->tmpFp[]s to NULL - clears x->fPath[0] - sets x->state to mfReset - resets x->totalTime and x->offset - outputs new totalTime from x->total_time_outlet */ static void midifile_close(t_midifile *x) { int i; if (x->fP != NULL) { sys_fclose (x->fP); x->fP = NULL; } for (i = 0; i < MAX_TRACKS; ++i) { if (x->tmpFP[i] != NULL) { sys_fclose(x->tmpFP[i]); midifile_delete_track_file(x, i); x->tmpFP[i] = NULL; } } x->fPath[0] = '\0'; x->state = mfReset; x->total_time = 0L; x->offset = 0L; outlet_float(x->total_time_outlet, x->total_time); } /** midifile_free_file closes the file and its associated tracks. - calls midifile_close() and frees all track data */ static void midifile_free_file(t_midifile *x) { int i; midifile_close(x); for (i = 0; i < MAX_TRACKS; ++i) { if (x->track_chunk[i].track_data != NULL) freebytes(x->track_chunk[i].track_data, x->track_chunk[i].chunk_length); x->track_chunk[i].track_data = NULL; x->track_chunk[i].track_ended = 0; } } /** midifile_free closes all files and frees all allocated memory. - calls midifile_free_file(). */ static void midifile_free(t_midifile *x) { midifile_free_file(x); } /** midifile_open_path attempts to open a file. - path is a string. - Up to PATH_BUF_SIZE-1 characters will be copied into x->fPath. - mode should be "rb" or "wb". - x->fPath will be used as a file name to open. - Returns 1 if successful, else 0. */ static int midifile_open_path(t_midifile *x, char *path, char *mode) { FILE *fP = NULL; char tryPath[PATH_BUF_SIZE]; char slash[] = "/"; /* If the first character of the path is a slash then the path is absolute */ /* On MSW if the second character of the path is a colon then the path is absolute */ if ((path[0] == '/') || (path[0] == '\\') || (path[1] == ':')) { strncpy(tryPath, path, PATH_BUF_SIZE-1); /* copy path into a length-limited buffer */ /* ...if it doesn't work we won't mess up x->fPath */ tryPath[PATH_BUF_SIZE-1] = '\0'; /* just make sure there is a null termination */ if (x->verbosity > 1)post("midifile_open_path (absolute): %s\n", tryPath); fP = sys_fopen(tryPath, mode); } if (fP == NULL) { /* Then try to open the path from the current directory */ strncpy(tryPath, x->our_directory->s_name, PATH_BUF_SIZE - 1); /* copy path into a length-limited buffer */ strncat(tryPath, slash, PATH_BUF_SIZE-1); /* copy path into a length-limited buffer */ strncat(tryPath, path, PATH_BUF_SIZE - 1); /* copy path into a length-limited buffer */ /* ...if it doesn't work we won't mess up x->fPath */ tryPath[PATH_BUF_SIZE-1] = '\0'; /* just make sure there is a null termination */ if (x->verbosity > 1)post("midifile_open_path (relative): %s\n", tryPath); fP = sys_fopen(tryPath, mode); } if (fP == NULL) return 0; x->fP = fP; strncpy(x->fPath, tryPath, PATH_BUF_SIZE); return 1; } /** midifile_flush writes the header to x->fP, copies the contents of x->tmpFP[] into it, and closes both files. - flush ends the track. - returns immediately unless x->state is mfWriting. - sends a bang to status_outlet so tick count can be captured. - calls midifile_write_header() - calls midifile_write_end_of_track() for each active track. - calls midifile_close(). */ static void midifile_flush(t_midifile *x) { uint32_t written = 0L; uint32_t end_time = x->total_time; uint32_t len; int c, i, k, nTracks = 0; if(x->state != mfWriting) return; /* only if we're writing */ outlet_bang(x->status_outlet); /* bang so tick count can be saved externally */ /* First count the active tracks*/ for (i = 0; i < MAX_TRACKS; ++i) if (x->tmpFP[i] != NULL) ++nTracks; /* Next write the header for the entire file */ written += midifile_write_header(x, nTracks); for (i = 0; i < MAX_TRACKS; ++i) { if (x->tmpFP[i] != NULL) { ++nTracks; if (0 == x->track_chunk[i].track_ended) written += midifile_write_end_of_track(x, end_time, i); /* now copy the MIDI data from tmpFP[i] to fP */ rewind (x->tmpFP[i]); /* write track chunk header followed by the track data */ fprintf (x->fP, "MTrk"); len = x->track_chunk[i].chunk_length; /* length of MIDI data */ for (k = 0; k < 4; ++k) { /* msb first */ c = (char)((len & 0xFF000000)>>24); putc(c, x->fP); len <<= 8; } while ((c = fgetc(x->tmpFP[i])) != EOF) { putc(c, x->fP); ++written; } } } if (x->verbosity) post ("midifile: wrote %lu to %s", written, x->fPath); midifile_close(x); } /** midifile_write_header writes the MThd and MTrk headers to x->fP. - returns the number of bytes written to x->fP. */ static uint32_t midifile_write_header(t_midifile *x, int nTracks) { uint32_t j, written = 0L; int i; char c; rewind (x->fP); fprintf (x->fP, "MThd"); j = 6; /* length of header data */ for (i = 0; i < 4; ++i) { /* msb first */ c = (char)((j & 0xFF000000)>>24); putc(c, x->fP); j <<= 8; } j = (nTracks > 1)?1:0; /* type of file */ /* msb first */ c = (char)((j & 0xFF00)>>8); putc(c, x->fP); c = (char)(j & 0x0FF); putc(c, x->fP); j = nTracks; /* number of tracks */ /* msb first */ c = (char)((j & 0xFF00)>>8); putc(c, x->fP); c = (char)(j & 0x0FF); putc(c, x->fP); j = x->header_chunk.chunk_division; /* ticks per quarter note */ /* msb first */ c = (char)((j & 0xFF00)>>8); putc(c, x->fP); c = (char)(j & 0x0FF); putc(c, x->fP); written = 18L;//22L; return written; } /** midifile_open_track_file opens a temporary file for one track's data * - opens a file for reading and writing in the same directory as the main file. - filename is built from the main filename, trackNr and ".trk" */ static FILE *midifile_open_track_file(t_midifile *x, int trackNr) { int i; char trackPath[PATH_BUF_SIZE]; FILE *fP; strncpy(trackPath, x->fPath, PATH_BUF_SIZE); if (x->verbosity > 2) post("midifile_open_track_file: main file path is %s", trackPath); i = strlen(trackPath); sprintf(&trackPath[i], "%d.trk", trackNr); if (x->verbosity > 2) post("midifile_open_track_file: track path is %s", trackPath); fP = sys_fopen(trackPath, "w+b"); if (NULL == fP) pd_error(x, "Unable to open track file"); return fP; } /** midifile_delete_track_file erases the temporary file for one track's data * - filename is built from the main filename, trackNr and ".trk" */ static int midifile_delete_track_file(t_midifile *x, int trackNr) { int i; char trackPath[PATH_BUF_SIZE]; int result; strncpy(trackPath, x->fPath, PATH_BUF_SIZE); if (x->verbosity > 2) post("midifile_delete_track_file: main file path is %s", trackPath); i = strlen(trackPath); sprintf(&trackPath[i], "%d.trk", trackNr); if (x->verbosity > 2) post("midifile_delete_track_file: \"%s\"", trackPath); result = remove(trackPath); if (0 != result) { result = errno; pd_error(x, "Unable to delete track file \"%s\": %s", trackPath, strerror(result)); } return result; } /** midifile_write implements the write message. * - opens the file for writing and writes the header. - first element of list must be a pathname symbol - optional second argument: ticks_per_frame or frames_per_second - optional third argument: ticks_per_frame - calls midifile_free_file() to clear any previous file data - calls midifile_open_path() - calls midifile_rewind_tracks() */ static void midifile_write(t_midifile *x, t_symbol *s, int argc, t_atom *argv) { char *path = NULL; int frames_per_second = 0;/* default */ int ticks_per_frame = 90; /* default*/ if ((argc >= 1) && (argv[0].a_type == A_SYMBOL)) path = argv[0].a_w.w_symbol->s_name; else pd_error(x, "midifile_write: No valid path name"); if (argc == 2) { if (argv[1].a_type == A_FLOAT) ticks_per_frame = (int)argv[1].a_w.w_float; else pd_error (x, "midifile_write: second argument is not a float"); } else if (argc >= 3) /* ignore extra arguments */ { if (argv[2].a_type == A_FLOAT) ticks_per_frame = (int)argv[2].a_w.w_float; else pd_error (x, "midifile_write: third argument is not a float"); if (argv[1].a_type == A_FLOAT) frames_per_second = (int)argv[1].a_w.w_float; else pd_error (x, "midifile_write: second argument is not a float"); } post("midifile_write: path = %s, fps = %d, tpf = %d", path, frames_per_second, ticks_per_frame); midifile_free_file(x); if (midifile_open_path(x, path, "wb")) { if (x->verbosity) post("midifile: opened %s", x->fPath); x->state = mfWriting; x->track = 0; /* write to first track */ x->tmpFP[x->track] = midifile_open_track_file(x, x->track);//tmpfile(); /* a temporary file for the MIDI data while we don't know how long it is */ x->header_chunk.chunk_type[0] = 'M'; x->header_chunk.chunk_type[1] = 'T'; x->header_chunk.chunk_type[2] = 'h'; x->header_chunk.chunk_type[3] = 'd'; x->header_chunk.chunk_length = 6L; /* 3 ints to follow */ x->header_chunk.chunk_format = 0; /* single-track file so far */ x->header_chunk.chunk_ntrks = 1; /* one track for type 0 file */ x->header_chunk.chunk_division = (((-frames_per_second)<<8)|ticks_per_frame); x->track_chunk[0].chunk_type[0] = 'M'; x->track_chunk[0].chunk_type[0] = 'T'; x->track_chunk[0].chunk_type[0] = 'r'; x->track_chunk[0].chunk_type[0] = 'k'; x->track_chunk[0].chunk_length = 0L; /* for now */ midifile_rewind_tracks(x); } else pd_error(x, "midifile_write: Unable to open %s", path); } /** midifile_write_delta_time writes the current delta time to the current track * - returns number of bytes written - calls midifile_write_variable_length_value() */ static int midifile_write_delta_time(t_midifile *x) { /* deltatime */ x->track_chunk[x->track].delta_time = x->total_time - x->track_chunk[x->track].total_time; x->track_chunk[x->track].total_time = x->total_time; return midifile_write_variable_length_value(x->tmpFP[x->track], x->track_chunk[x->track].delta_time); } /** midifile_meta attempts to add the arguments as a meta event to the current track of the open file. * - First argument is the event ID - Subsequent args are parameters for the specific meta avent - calls midifile_write_delta_time */ static void midifile_meta(t_midifile *x, t_symbol *s, int argc, t_atom *argv) { int i, j, metaType; long jj; uint32_t nbWritten = 0L; int paramBuf[5]; char *sPtr; char c; uint32_t len; if ((x->state != mfWriting) || (x->tmpFP[x->track] == NULL)) { /* list only works for writing */ pd_error (x, "midifile_meta: no file is open for writing"); return; } if (0 != x->track_chunk[x->track].track_ended) { /* list only works for writing */ pd_error (x, "midifile_meta: track %d is ended", x->track); return; } if (A_FLOAT != argv[0].a_type) { pd_error (x, "midifile_meta: first argument not an integer on [0..255]"); return; } metaType = atom_getint(&argv[0]); if (x->verbosity > 1) post ("midifile_meta: metaType %d", metaType); switch (metaType) { case 0: /* Sequence Number must be at start of track*/ /* 16-bit sequence number stored bigendian */ /* len is always 02*/ if (x->verbosity > 1) post ("midifile_meta: Sequence Number"); if (argc < 2) { post ("midifile_meta: not enough parameters"); return; } if (A_FLOAT != argv[1].a_type) { post ("midifile_meta: parameter not a number"); return; } j = atom_getint(&argv[1]); if (x->verbosity > 1) post ("midifile_meta: Sequence Number %d", j); nbWritten = midifile_write_delta_time(x); putc (0xFF, x->tmpFP[x->track]); // Meta Status putc (0, x->tmpFP[x->track]); // Sequence Number Meta putc (2, x->tmpFP[x->track]); // len putc (j>>8, x->tmpFP[x->track]); // Sequence Number high byte putc (j%256, x->tmpFP[x->track]); // Sequence Number low byte nbWritten += 5; break; case 1: case 2: case 3: case 4: case 5: case 6: case 7: if (x->verbosity > 1) { if (1 == metaType) post ("midifile_meta: Text Event"); else if (2 == metaType) post ("midifile_meta: Copyright Notice"); else if (3 == metaType) post ("midifile_meta: Sequence/Track Name"); else if (4 == metaType) post ("midifile_meta: Instrument Name"); else if (5 == metaType) post ("midifile_meta: Lyric"); else if (6 == metaType) post ("midifile_meta: Marker"); else if (7 == metaType) post ("midifile_meta: Cue Point"); } /* variable-length len followed by string (spaces must be replaced by underscores to prevent Pd from chopping up into symbols) */ if (argc < 2) { post ("midifile_meta: not enough parameters"); return; } if (argv[1].a_type != A_SYMBOL) { post ("midifile_meta: parameter not a symbol"); return; } sPtr = argv[1].a_w.w_symbol->s_name; nbWritten = midifile_write_delta_time(x); putc (0xFF, x->tmpFP[x->track]); // Meta Status putc (metaType, x->tmpFP[x->track]); // a textual Event Meta nbWritten += 2; len = strlen(sPtr); nbWritten += midifile_write_variable_length_value(x->tmpFP[x->track], len); for (jj = 0; jj < len; ++jj) { c = *sPtr++; if (c == '_') c = ' '; // replace underscore with space putc (c, x->tmpFP[x->track]); // text } nbWritten += len; break; case 32: if (x->verbosity > 1) post ("midifile_meta: MIDI Channel Prefix"); /* one-byte channel [0-15] */ /* len is always 01 */ if (argc < 2) { post ("midifile_meta: not enough parameters"); return; } if (A_FLOAT != argv[1].a_type) { post ("midifile_meta: parameter not a number"); return; } j = atom_getint(&argv[1]); if (j <0 || j >15) { post ("midifile_meta: channel number out of range [0-15]"); return; } nbWritten = midifile_write_delta_time(x); putc (0xFF, x->tmpFP[x->track]); // Meta Status putc (32, x->tmpFP[x->track]);; // MIDI Channel Prefix Meta putc (1, x->tmpFP[x->track]); // len putc (j, x->tmpFP[x->track]); // channel byte nbWritten += 4; break; case 47: if (x->verbosity > 1) post ("midifile_meta: End of Track"); /* must be the last event */ /* len is always 00 */ nbWritten = midifile_write_delta_time(x); putc (0xFF, x->tmpFP[x->track]); // Meta Status putc (47, x->tmpFP[x->track]);; // End of Track Meta putc (0, x->tmpFP[x->track]); // len nbWritten += 3; x->track_chunk[x->track].track_ended = 1; // can't write any more data to this track break; case 81: if (x->verbosity > 1) post ("midifile_meta: Set Tempo"); /* 24-bit microseconds per qurter-note stored bigendian */ /* len is always 3 */ if (argc < 2) { post ("midifile_meta: not enough parameters"); return; } if (A_FLOAT != argv[1].a_type) { post ("midifile_meta: parameter not a number"); return; } jj = atom_getint(&argv[1]); if ((jj < 0) || (jj > 0xFFFFFF)) { post ("midifile_meta: Tempo out of range [0-16777215]"); return; } if (x->verbosity > 1) post ("midifile_meta: Set Tempo %ld", jj); nbWritten = midifile_write_delta_time(x); putc (0xFF, x->tmpFP[x->track]); // Meta Status putc (81, x->tmpFP[x->track]);; // Set Tempo Meta putc (3, x->tmpFP[x->track]); // len putc ((jj>>16)&0xFF, x->tmpFP[x->track]); // Set Tempo high byte putc ((jj>>8)&0xFF, x->tmpFP[x->track]); // Set Tempo mid byte putc (jj%256, x->tmpFP[x->track]); // Set Tempo low byte nbWritten += 6; break; case 84: if (x->verbosity > 1) post ("midifile_meta: SMPTE Offset"); /* Should be at time 0 */ /* len is always 5: hr mn se fr ff */ if (argc < 6) { post ("midifile_meta: not enough parameters"); return; } for (i = 1; i < 6; ++i) { if (A_FLOAT != argv[i].a_type) { post ("midifile_meta: parameter %d not a number", i); return; } j = atom_getint(&argv[i]); if ((j < 0) || (j > 127)) { post ("midifile_meta: SMPTE value out of range [0-127]"); // this won't catch all range errors return; } paramBuf[i-1] = j; } nbWritten = midifile_write_delta_time(x); putc (0xFF, x->tmpFP[x->track]); // Meta Status putc (84, x->tmpFP[x->track]);; // Set SMPTE Offset Meta putc (5, x->tmpFP[x->track]); // len for (i = 0; i < 5; ++i) { putc (paramBuf[i], x->tmpFP[x->track]); // timecode } nbWritten += 8; break; case 88: if (x->verbosity > 1) post ("midifile_meta: Time Signature"); /* len is always 4: nn dd cc bb */ /* nn=numerator; dd=denominator (as negative power of two: 2=quarter-note */ /* cc=clocks per metronome click; bb=32nd-notes per MIDI quarter-note(24 cloccks) */ if (argc < 5) { post ("midifile_meta: not enough parameters"); return; } for (i = 1; i < 5; ++i) { if (A_FLOAT != argv[i].a_type) { post ("midifile_meta: parameter %d not a number", i); return; } j = atom_getint(&argv[i]); if ((j < 0) || (j > 127)) { post ("midifile_meta: Time Signature value out of range [0-127]"); // this won't catch all range errors return; } paramBuf[i-1] = j; } putc (0xFF, x->tmpFP[x->track]); // Meta Status nbWritten = midifile_write_delta_time(x); putc (88, x->tmpFP[x->track]);; // Time Signatre Meta putc (4, x->tmpFP[x->track]); // len for (i = 0; i < 4; ++i) { putc (paramBuf[i], x->tmpFP[x->track]); // time signature } nbWritten += 7; break; case 89: if (x->verbosity > 1) post ("midifile_meta: Key Signature"); /* len is always 2: sf mi */ /* sf = number of sharps (or flats if negative) */ /* mi = 0(major) or 1(minor) */ if (argc < 3) { post ("midifile_meta: not enough parameters"); return; } for (i = 1; i < 3; ++i) { if (A_FLOAT != argv[i].a_type) { post ("midifile_meta: parameter %d not a number", i); return; } j = atom_getint(&argv[i]); if ((i == 1) && ((j < -7) || (j > 7))) { post ("midifile_meta: Key Signature value out of range [-7-+7]"); return; } if ((i == 2) && ((j < 0) || (j > 1))) { post ("midifile_meta: Key Signature value out of range [0-1]"); return; } paramBuf[i-1] = j; } nbWritten = midifile_write_delta_time(x); putc (0xFF, x->tmpFP[x->track]); // Meta Status putc (89, x->tmpFP[x->track]);; // Key Signatre Meta putc (2, x->tmpFP[x->track]); // len for (i = 0; i < 2; ++i) { putc (paramBuf[i], x->tmpFP[x->track]); // key signature } nbWritten += 5; break; case 127: if (x->verbosity > 1) post ("midifile_meta: Sequencer-Specific Meta-Event"); /* variable-len followed by stuff */ if (argc < 2) { post ("midifile_meta: not enough parameters"); return; } post ("Sequencer-Specific Meta-Event not implemented yet."); break; default: post("Unknown Meta tag %d", metaType); return; } /* for (i = 1; i < argc; ++i) { if (A_FLOAT == argv[i].a_type) { j = atom_getint(&argv[i]); if (x->verbosity > 1) post ("midifile_meta: %d", j); } else if (A_SYMBOL == argv[i].a_type) { ts = atom_getsymbol(&argv[i]); len += strlen(ts->s_name); */ if (0 != nbWritten) { if (x->verbosity > 1) post("Wrote %lu to track %d", nbWritten, x->track); x->track_chunk[x->track].chunk_length += nbWritten; } } /** midifile_read attempts to open a MIDI file at path. * - calls midifile_open_path() - calls midifile_read_chunks() */ static void midifile_read(t_midifile *x, t_symbol *path) { midifile_free_file(x); if (midifile_open_path(x, path->s_name, "rb")) { if (x->verbosity) post("midifile: opened %s", x->fPath); x->state = mfReading; if (midifile_read_chunks(x) == 0) midifile_free_file(x); // } else error("midifile: Unable to open %s", path->s_name); } /** midifile_bang steps forward one tick and processes all tracks for that tick. * - calls midifile_get_next_track_chunk_delta_time() - calls midifile_get_next_track_chunk_data() - calls midifile_skip_next_track_chunk_data() */ static void midifile_bang(t_midifile *x) { int j, result = 1, ended = 0; uint32_t total_time; switch (x->state) { case mfReading: if (x->verbosity > 3) post("midifile_bang: total_time %lu", x->total_time); for (j = 0; ((j < x->header_chunk.chunk_ntrks)&&(result != 0)); ++j) { if (x->track_chunk[j].total_time != NO_MORE_ELEMENTS) { while ( ( total_time = midifile_get_next_track_chunk_delta_time(x, j) + x->track_chunk[j].total_time ) == x->total_time ) { if ((x->track == j) ||(x->track == ALL_TRACKS)) midifile_get_next_track_chunk_data(x, j); else midifile_skip_next_track_chunk_data(x, j); } x->ended = 0; } if (x->track_chunk[j].delta_time == NO_MORE_ELEMENTS) ++ended; } if ((ended == x->header_chunk.chunk_ntrks)&&(x->ended == 0)) { /* set ended flag, only bang once */ if (x->verbosity > 1) post ("ended = %d x->header_chunk.chunk_ntrks = %d", ended, x->header_chunk.chunk_ntrks); outlet_bang(x->status_outlet); ++x->ended; } /* fall through into mfWriting */ case mfWriting: ++x->total_time; outlet_float(x->total_time_outlet, x->total_time); break; default: break;/* don't change time when no files are open */ } } /* The arguments of the ``list''-method * a pointer to the class-dataspace * a pointer to the selector-symbol (always &s_list) * the number of atoms and a pointer to the list of atoms: */ /** midifile_list adds a list containing time and midi packet to the temporary file in MIDI file format. * - current track is used to select the temp file. * - calls midifile_write_delta_time() */ static void midifile_list(t_midifile *x, t_symbol *s, int argc, t_atom *argv) { int i, j, k, m = 0, dt_written = 0; uint32_t len, written = 0L; static int warnings = 0; if (x->state != mfWriting) return;/* list only works for writing */ if (x->tmpFP[x->track] == NULL) { if (0 == warnings++) error ("midifile: no file is open for writing"); return; } if (0 != x->track_chunk[x->track].track_ended) { if (0 == warnings++) error ("midifile: track %d is ended", x->track); return; } for (i = 0; i < argc; ++i) { if (A_FLOAT == argv[i].a_type) { j = atom_getint(&argv[i]); if (x->verbosity > 2) post ("midifile_list. j[%d] = 0x%lX", i, j); if (j < 0x100) { if (!dt_written) { /* deltatime */ written = midifile_write_delta_time(x); // x->track_chunk[x->track].delta_time = x->total_time - x->track_chunk[x->track].total_time; // x->track_chunk[x->track].total_time = x->total_time; // written = midifile_write_variable_length_value(x->tmpFP[x->track], x->track_chunk[x->track].delta_time); dt_written = 1; } //if (j == x->track_chunk[0].running_status) continue;/* don't save redundant status byte */ if (j >= 0x80 && j <= 0xEF)x->track_chunk[x->track].running_status = j;/* new running status */ else if (j >= 0xF0 && j <= 0xF7) { x->track_chunk[x->track].running_status = 0;/* clear running status */ if (j == 0xF0) { /* system exclusive: */ /* find length */ for (k = i+1, len = 0L; k < argc; ++k, ++len) { if (argv[k].a_type != A_FLOAT) { error ("midifile: sysex list must be all floats"); x->track_chunk[x->track].chunk_length += written; return; } m = atom_getint(&argv[k]); if (m & 0x80) break;/* take any non-data as end of exclusive */ } if (m != 0xF7) { error ("midifile: sysex list terminator is 0x%X", m); x->track_chunk[x->track].chunk_length += written; return; } ++len; if (x->verbosity) post ("midifile: sysex length %lu. j = 0x%X", len, j); putc (j, x->tmpFP[x->track]); ++written; /* write length as variable length */ written += midifile_write_variable_length_value (x->tmpFP[x->track], len); /* write the rest of the sysex message */ for (k = i+1; j != 0xF7; ++k) { j = atom_getint(&argv[k]); putc (j, x->tmpFP[x->track]); ++written; } x->track_chunk[x->track].chunk_length += written; return; } } if (x->verbosity > 1) post ("midifile: j = 0x%X", j); putc (j, x->tmpFP[x->track]); ++written; } } } x->track_chunk[x->track].chunk_length += written; } /** midifile_write_end_of_track writes an End of Track event to x->tmpFP[trackNr]. - calls midifile_write_variable_length_value() - adds number of bytes written to x->track_chunk[trackNr].chunk_length. - returns number of bytes written. */ static uint32_t midifile_write_end_of_track(t_midifile *x, uint32_t end_time, int trackNr) { uint32_t written = 0; x->track_chunk[trackNr].delta_time = end_time - x->track_chunk[trackNr].total_time; x->track_chunk[trackNr].total_time = x->total_time; written = midifile_write_variable_length_value (x->tmpFP[trackNr], x->track_chunk[trackNr].delta_time); putc (0xFF, x->tmpFP[trackNr]); putc (0x2F, x->tmpFP[trackNr]); putc (0x00, x->tmpFP[trackNr]); written += 3L; x->track_chunk[trackNr].chunk_length += written; return written; } /** midifile_float: Go to a total time of ticks. * if state is mfReading - calls midifile_rewind_tracks() - calls midifile_get_next_track_chunk_delta_time - calls midifile_skip_next_track_chunk_data() if state is mfWriting - sets total_time to ticks If mfReading or mfWriting, outputs new total_time */ static void midifile_float(t_midifile *x, t_float ticks) { uint32_t cTime = (uint32_t)ticks; uint32_t total_time; int j, result = 1, ended = 0; switch (x->state) { case mfReading: /* cue to ticks */ midifile_rewind_tracks(x); for (j = 0; ((j < x->header_chunk.chunk_ntrks)&&(result != 0)); ++j) { if (x->track_chunk[j].total_time != NO_MORE_ELEMENTS) { while ( ( total_time = midifile_get_next_track_chunk_delta_time(x, j) + x->track_chunk[j].total_time ) < cTime ) midifile_skip_next_track_chunk_data(x, j); } if (x->track_chunk[j].delta_time == NO_MORE_ELEMENTS) ++ended; } x->total_time = cTime; outlet_float(x->total_time_outlet, x->total_time); if (ended == x->header_chunk.chunk_ntrks) { if (x->verbosity) post ("midifile: ended = %d x->header_chunk.chunk_ntrks = %d", ended, x->header_chunk.chunk_ntrks); outlet_bang(x->status_outlet); } break; case mfWriting: /* add ticks to current time */ x->total_time += cTime; outlet_float(x->total_time_outlet, x->total_time); break; case mfReset: /* do nothing */ break; } } /** midifile_read_chunks reads in the MIDI file chunks. * - calls midifile_read_header_chunk() and then - calls midifile_read_track_chunk() for each track */ static int midifile_read_chunks(t_midifile *x) { int j, result; result = midifile_read_header_chunk(x); midifile_rewind_tracks(x); for (j = 0; ((j < x->header_chunk.chunk_ntrks)&&(result != 0)); ++j) midifile_read_track_chunk(x, j); return result; } /** midifile_read_header_chunk reads the header chunk from an open MIDI file into x->header_chunk. * - calls midifile_get_multibyte_2() - calls midifile_get_multibyte_4() - outputs various file info on the status outlet - Returns 1 on success, else 0 */ static int midifile_read_header_chunk(t_midifile *x) { unsigned char *cP = (unsigned char *)x->header_chunk.chunk_type; char *sP; char buf[4]; uint32_t n; int div, smpte, ticks; t_atom output_atom; if (x->fP == NULL) { error("midifile: no open file"); return 0;/* no open file */ } rewind(x->fP); x->offset = 0L; n = fread(cP, 1L, 4L, x->fP); x->offset += n; if (n != 4L) { error("midifile: read %d instead of 4", n); return 0; } if (x->verbosity) post("midifile: Header chunk type: %c%c%c%c", cP[0], cP[1], cP[2], cP[3]); if (!(cP[0] == 'M' && cP[1] == 'T' && cP[2] == 'h' && cP[3] == 'd')) { error ("midifile: bad file format: bad header chunk type"); return 0; } cP = (unsigned char *)buf; n = fread(cP, 1L, 4L, x->fP); x->offset += n; if (n != 4L) { error("midifile: read %d instead of 4", n); return 0; } x->header_chunk.chunk_length = midifile_get_multibyte_4(cP); if (x->verbosity) post("midifile: Header chunk length: %lu", x->header_chunk.chunk_length); if (x->header_chunk.chunk_length != 6L) { error ("midifile: bad file format: bad header chunk length"); return 0; } n = fread(cP, 1L, 2L, x->fP); x->offset += n; if (n != 2L) { error("midifile: read %d instead of 2", n); return 0; } x->header_chunk.chunk_format = midifile_get_multibyte_2(cP); switch (x->header_chunk.chunk_format) { case 0: sP = "Single multichannel track"; break; case 1: sP = "One or more simultaneous tracks"; break; case 2: sP = "One or more sequentially independent single tracks"; break; default: sP = "Unknown format"; } if (x->verbosity) post("midifile: Header chunk format: %d (%s)", x->header_chunk.chunk_format, sP); SETFLOAT(&output_atom, x->header_chunk.chunk_format); outlet_anything( x->status_outlet, gensym("format"), 1, &output_atom); n = fread(cP, 1L, 2L, x->fP); x->offset += n; if (n != 2L) { error("midifile: read %d instead of 2", n); return 0; } x->header_chunk.chunk_ntrks = midifile_get_multibyte_2(cP); if (x->verbosity) post("midifile: Header chunk ntrks: %d", x->header_chunk.chunk_ntrks); SETFLOAT(&output_atom, x->header_chunk.chunk_ntrks); outlet_anything( x->status_outlet, gensym("tracks"), 1, &output_atom); if (x->header_chunk.chunk_ntrks > MAX_TRACKS) { error ("midifile: Header chunk ntrks (%d) exceeds midifile MAX_TRACKS, set to %d", x->header_chunk.chunk_ntrks, MAX_TRACKS); x->header_chunk.chunk_ntrks = MAX_TRACKS; } n = fread(cP, 1L, 2L, x->fP); x->offset += n; if (n != 2L) { error("midifile: read %d instead of 2", n); return 0; } x->header_chunk.chunk_division = midifile_get_multibyte_2(cP); div = x->header_chunk.chunk_division; if(div & 0x8000) { smpte = (-(div>>8)) & 0x0FF; ticks = div & 0x0FF; if (x->verbosity) post("midifile: Header chunk division: 0x%X: %d frames per second, %d ticks per frame", div, smpte, ticks); SETFLOAT(&output_atom, smpte); outlet_anything( x->status_outlet, gensym("frames_per_sec"), 1, &output_atom); SETFLOAT(&output_atom, ticks); outlet_anything( x->status_outlet, gensym("ticks_per_frame"), 1, &output_atom); } else { if (x->verbosity) post("midifile: Header chunk division: 0x%X: %d ticks per quarter note", div, div); SETFLOAT(&output_atom, div); outlet_anything( x->status_outlet, gensym("ticks_per_quarternote"), 1, &output_atom); } return 1; } /** midifile_read_track_chunk reads the data part of a track chunk into x->track_chunk[mfTrack].track_data * after allocating the space for it. * - calls midifile_get_multibyte_4() - returns 1 on success, else 0 */ static int midifile_read_track_chunk(t_midifile *x, int mfTrack) { unsigned char *cP = (unsigned char *)x->track_chunk[mfTrack].chunk_type; char buf[4]; char type[5]; uint32_t n, len; if (x->fP == NULL) { error("midifile: no open file"); return 0;/* no open file */ } n = fread(cP, 1L, 4L, x->fP); x->offset += n; if (n != 4L) { error("midifile: read %d instead of 4", n); return 0; } if (!(cP[0] == 'M' && cP[1] == 'T' && cP[2] == 'r' && cP[3] == 'k')) { error ("midifile: bad file format: bad track chunk type"); return 0; } type[0] = cP[0]; type[1] = cP[1]; type[2] = cP[2]; type[3] = cP[3]; type[4] = '\0'; cP = (unsigned char *)buf; n = fread(cP, 1L, 4L, x->fP); x->offset += n; if (n != 4L) { error("midifile: read %d instead of 4", n); return 0; } len = midifile_get_multibyte_4(cP); x->track_chunk[mfTrack].chunk_length = len; if (x->verbosity) post("midifile: Track chunk %d type: %s, length %d", mfTrack, type, len); if ((cP = getbytes(len)) == NULL) { error ("midifile: Unable to allocate %d bytes for track data", len); return 0; } x->track_chunk[mfTrack].track_data = (unsigned char*)cP; n = fread(cP, 1L, len, x->fP); return 1; } static unsigned short midifile_combine_bytes(unsigned char data1, unsigned char data2) /** make a short from two 7bit MIDI data bytes */ { /* unsigned short value = (unsigned short)data2; value <<= 7; value |= (unsigned short)data1; return value; */ return ((((unsigned short)data2)<< 7) | ((unsigned short)data1)); } static unsigned long midifile_get_multibyte_4(unsigned char*n) /** make a long from 4 consecutive bytes in big-endian format */ { unsigned long a, b, c, d, e; a = (*(unsigned long *)(&n[0])) & 0x0FF; b = (*(unsigned long *)(&n[1])) & 0x0FF; c = (*(unsigned long *)(&n[2])) & 0x0FF; d = (*(unsigned long *)(&n[3])) &0x0FF; e = (a<<24) + (b<<16) + (c<<8) + d; return e; } static unsigned long midifile_get_multibyte_3(unsigned char*n) /** make a long from 3 consecutive bytes in big-endian format */ { unsigned long a, b, c, d; a = (*(unsigned long *)(&n[0])) & 0x0FF; b = (*(unsigned long *)(&n[1])) & 0x0FF; c = (*(unsigned long *)(&n[2])) & 0x0FF; d = (a<<16) + (b<<8) + c; return d; } static unsigned short midifile_get_multibyte_2(unsigned char*n) /** make a short from 2 consecutive bytes in big-endian format */ { unsigned short a, b, c; a = (*(unsigned long *)(&n[0])) & 0x0FF; b = (*(unsigned long *)(&n[1])) & 0x0FF; c = (a<<8) + b; return c; } /** midifile_write_variable_length_value writes an integer to the file in variable-length format - returns number of characters written to fP */ static int midifile_write_variable_length_value (FILE *fP, uint32_t value) { uint32_t buffer; int i; char c; buffer = value & 0x07F; while ((value >>= 7) > 0) { buffer <<= 8; buffer |= 0x80; buffer += (value & 0x07F); } i = 0; while (1) { c = (char)(buffer & (0x0FF)); putc(c, fP); ++i; if (buffer & 0x80) buffer >>= 8; else break; } return i; } /** midifile_read_var_len reads a variable-length value from cP into delta. - enter with cP pointing to deltatime. - sets delta to deltatime. - returns pointer to following data. */ static unsigned char *midifile_read_var_len (unsigned char *cP, uint32_t *delta) { unsigned long value; char c; if (((value = *(cP++))) & 0x80) { value &= 0x7f; do { value = (value << 7) + ((c = *(cP++)) & 0x7f); } while (c & 0x80); } *delta = value; return cP; } /** midifile_verbosity sets the verbosity level of console output. - verbosity can be 0 to 4 - default is 1 */ static void midifile_verbosity(t_midifile *x, t_floatarg verbosity) { x->verbosity = (int)verbosity; post ("midifile verbosity is %d", x->verbosity); } /** midifile_set_track implements the track message. * - sets x->track. * - When reading, play only this track or all tracks if out of range. - When writing, select the track to write to and open a temp file for it unless one is already open. */ static void midifile_set_track(t_midifile *x, t_floatarg track) { if(x->state == mfReading) { /* only if we're reading */ /* anything out of range will be interpreted as all tracks */ if ((track < 0) || (track >= x->header_chunk.chunk_ntrks)) { x->track = ALL_TRACKS; if (x->verbosity>1) post("midifile: playing %d track%s", x->header_chunk.chunk_ntrks, (x->header_chunk.chunk_ntrks>1)?"s":""); } else { x->track = track; if (x->verbosity>1) post("midifile: playing track %d", x->track); } } else if(x->state == mfWriting) { /* only if we're writing */ /* anything out of range will be rejected */ if ((track < 0) || (track >= MAX_TRACKS)) { post ("midifile track not between 0 and %d; using %d.", MAX_TRACKS, x->track); return; } else { x->track = track; // possibly update x->header_chunk.chunk_ntrks if (x->track_chunk[x->track].track_data == NULL) { /* this track is being used for the first time */ post("this track (%d) is being used for the first time", x->track); x->tmpFP[x->track] = midifile_open_track_file(x, x->track);//tmpfile(); /* a temporary file for the MIDI data while we don't know how long it is */ strncpy (x->track_chunk[x->track].chunk_type, "MTrk", 4L); x->track_chunk[x->track].chunk_length = 0L; /* for now */ x->track_chunk[x->track].track_ended = 0; } } } } /** midifile_dump implements the dump message. * - dumps track to console - if track is out of range, dumps all tracks. - calls midifile_dump_track_chunk_data() */ static void midifile_dump(t_midifile *x, t_floatarg track) { int mfTrack = (int)track; if(x->state != mfReading) return; /* only if we're reading */ if ((mfTrack < x->header_chunk.chunk_ntrks) && (mfTrack >= 0)) midifile_dump_track_chunk_data(x, mfTrack); else /* anything out of range will be interpreted as all tracks */ for (mfTrack = 0; mfTrack < x->header_chunk.chunk_ntrks; ++mfTrack) midifile_dump_track_chunk_data(x, mfTrack); } /** midifile_rewind implements the rewind message. * - calls midifile_rewind_tracks() */ static void midifile_rewind (t_midifile *x) { if(x->state != mfReading) return; /* only if we're reading */ midifile_rewind_tracks(x); } /** For all tracks, point to start of track_data */ static void midifile_rewind_tracks(t_midifile *x) { int i; for (i = 0; i < MAX_TRACKS; ++i) { x->track_chunk[i].delta_time = 0L; x->track_chunk[i].track_index = 0L; x->track_chunk[i].total_time = 0L; x->track_chunk[i].running_status = 0; } x->total_time = 0L; x->ended = 0L; outlet_float(x->total_time_outlet, x->total_time); } static uint32_t midifile_get_next_track_chunk_delta_time(t_midifile *x, int mfTrack) /** return the delta_time of the next event in track[mfTrack] */ { unsigned char *cP, *last_cP; uint32_t delta_time; cP = x->track_chunk[mfTrack].track_data + x->track_chunk[mfTrack].track_index; last_cP = x->track_chunk[mfTrack].track_data + x->track_chunk[mfTrack].chunk_length; delta_time = NO_MORE_ELEMENTS; if ((cP != NULL) && (cP < last_cP) && (x->track_chunk[mfTrack].delta_time != NO_MORE_ELEMENTS)) cP = midifile_read_var_len(cP, &delta_time); return delta_time; } /** output a long MIDI message as a list of floats * first_byte is followed by len bytes at cP */ static void midifile_output_long_list (t_outlet *outlet, unsigned char *cP, uint32_t len, unsigned char first_byte) { uint32_t slen; unsigned int si; t_atom *slist; slen = (len+1L)*sizeof(t_atom); slist = getbytes (slen); if (slist == NULL) { error ("midifile: no memory for long list"); return; } slist[0].a_type = A_FLOAT; slist[0].a_w.w_float = first_byte;//0xF0; for (si = 0; si < len; ++si) { slist[si+1].a_type = A_FLOAT; slist[si+1].a_w.w_float = cP[si]; } outlet_list(outlet, &s_list, len+1L, slist); freebytes(slist, slen); } /** parse entire track chunk and output it to the main window */ static void midifile_dump_track_chunk_data(t_midifile *x, int mfTrack) { unsigned char *cP, *last_cP, *str; uint32_t total_time, delta_time, len; unsigned long time_sig; unsigned char status, running_status = 0, c, d, nn, dd, cc, bb, mi, mcp, ch, hr, mn, se, fr, ff; char sf; unsigned short sn; unsigned char tt[3]; char *msgPtr; char msg[256]; cP = x->track_chunk[mfTrack].track_data; last_cP = x->track_chunk[mfTrack].track_data + x->track_chunk[mfTrack].chunk_length; total_time = 0L; post("midifile: Parsing track[%d]...", mfTrack); while ((cP != NULL) && (cP < last_cP) && (x->track_chunk[mfTrack].delta_time != NO_MORE_ELEMENTS)) { msgPtr = msg; cP = midifile_read_var_len(cP, &delta_time); status = *cP++; total_time += delta_time; msgPtr += sprintf (msgPtr, "tick %d delta %d status %02X ", total_time, delta_time, status); if ((status & 0xF0) == 0xF0) { switch (status) { case 0xF0: case 0xF7: cP = midifile_read_var_len(cP, &len);/* not a time but the same variable length format */ msgPtr += sprintf(msgPtr, "Sysex: %02X length %d ", status, len); cP += len; break; case 0xF3: /* song select */ c = *cP++; msgPtr += sprintf(msgPtr, "Song Select: %d ", c); break; case 0xF2: /* song position */ c = *cP++; d = *cP++; msgPtr += sprintf(msgPtr, "Song Position %d ", midifile_combine_bytes(c, d)); break; case 0xF1: /* quarter frame */ msgPtr += sprintf(msgPtr, "MIDI Quarter Frame"); break; case 0xF6: /* tune request */ msgPtr += sprintf(msgPtr, "MIDI Tune Request"); break; case 0xF8: /* MIDI clock */ msgPtr += sprintf(msgPtr, "MIDI Clock"); break; case 0xF9: /* MIDI tick */ msgPtr += sprintf(msgPtr, "MIDI Tick"); break; case 0xFA: /* MIDI start */ msgPtr += sprintf(msgPtr, "MIDI Start"); break; case 0xFB: /* MIDI continue */ msgPtr += sprintf(msgPtr, "MIDI Continue"); break; case 0xFC: /* MIDI stop */ msgPtr += sprintf(msgPtr, "MIDI Stop"); break; case 0xFE: /* active sense */ msgPtr += sprintf(msgPtr, "MIDI Active Sense"); break; case 0xFF: c = *cP++; cP = midifile_read_var_len(cP, &len);/* not a time but the same variable length format */ msgPtr += sprintf(msgPtr, "Meta 0x%02X length %d \n", c, len); switch (c) { case 0x58: nn = *cP++; dd = *cP++; dd = 1<<(dd); cc = *cP++; bb = *cP++; msgPtr += sprintf( msgPtr, "Time Signature: %d/%d %d clocks per tick, %d 32nd notes per quarter note", nn, dd, cc, bb); break; case 0x59: sf = *(signed char*)cP++; mi = *cP++; msgPtr += sprintf( msgPtr, "Key Signature: %d %s, %s", (sf < 0)?-sf:sf, (sf<0)?"flats":"sharps", (mi)?"minor":"major"); break; case 0x54: hr = *cP++; mn = *cP++; se = *cP++; fr = *cP++; ff = *cP++; msgPtr += sprintf( msgPtr, "SMPTE Offset: %02d:%02d:%02d:%02d.%02d", hr&0x1F, mn, se, fr, ff); break; case 0x51: tt[0] = *cP++; tt[1] = *cP++; tt[2] = *cP++; time_sig = midifile_get_multibyte_3(tt); msgPtr += sprintf(msgPtr, "%lu microseconds per MIDI quarter-note", time_sig); break; case 0x2F: msgPtr += sprintf(msgPtr, "========End of Track %d==========", mfTrack); cP += len; break; case 0x21: tt[0] = *cP++; msgPtr += sprintf(msgPtr, "MIDI port or cable number (unofficial): %d", tt[0]); break; case 0x20: mcp = *cP++; msgPtr += sprintf(msgPtr, "MIDI Channel Prefix: %d", mcp); break; case 0x07: str = cP; c = cP[len]; cP[len] = '\0'; /* null terminate temporarily */ msgPtr += sprintf(msgPtr, "Cue Point: %s", str); cP[len] = c; cP += len; break; case 0x06: str = cP; c = cP[len]; cP[len] = '\0'; /* null terminate temporarily */ msgPtr += sprintf(msgPtr, "Marker: %s", str); cP[len] = c; cP += len; break; case 0x05: str = cP; c = cP[len]; cP[len] = '\0'; /* null terminate temporarily */ msgPtr += sprintf(msgPtr, "Lyric: %s", str); cP[len] = c; cP += len; break; case 0x04: str = cP; c = cP[len]; cP[len] = '\0'; /* null terminate temporarily */ msgPtr += sprintf(msgPtr, "Instrument Name: %s", str); cP[len] = c; cP += len; break; case 0x03: str = cP; c = cP[len]; cP[len] = '\0'; /* null terminate temporarily */ msgPtr += sprintf(msgPtr, "Sequence/Track Name: %s", str); cP[len] = c; cP += len; break; case 0x02: str = cP; c = cP[len]; cP[len] = '\0'; /* null terminate temporarily */ msgPtr += sprintf(msgPtr, "Copyright Notice: %s", str); cP[len] = c; cP += len; break; case 0x01: str = cP; c = cP[len]; cP[len] = '\0'; /* null terminate temporarily */ msgPtr += sprintf(msgPtr, "Text: %s", str); cP[len] = c; cP += len; break; case 0x00: tt[0] = *cP++; tt[1] = *cP++; sn = midifile_get_multibyte_2(tt); msgPtr += sprintf(msgPtr, "Sequence Number: %d", sn); break; default: msgPtr += sprintf(msgPtr, "Unknown: 0x%02X", c); cP += len; break; } break; default: /* 0xF4, 0xF5, 0xF9, 0xFD are not defined */ msgPtr += sprintf(msgPtr, "Undefined: 0x%02X", status); break; } } else { if (status & 0x80) { running_status = status; c = *cP++; } else { c = status; status = running_status; } ch = (status & 0x0F) + 1; /* MIDI channel number */ switch (status & 0xF0) { case 0x80: d = *cP++; /* 2 data bytes */ msgPtr += sprintf(msgPtr, "MIDI 0x%02X %02X %02X : channel %d Note %d Off velocity %d", status, c, d, ch, c, d); break; case 0x90: d = *cP++; /* 2 data bytes */ if (d == 0) msgPtr += sprintf(msgPtr,"MIDI 0x%02X %02X %02X : channel %d Note %d Off", status, c, d, ch, c); else msgPtr += sprintf(msgPtr, "MIDI 0x%02X %02X %02X : channel %d Note %d On velocity %d", status, c, d, ch, c, d); break; case 0xA0: d = *cP++; /* 2 data bytes */ msgPtr += sprintf(msgPtr, "MIDI: 0x%02X %02X %02X : channel %d Note %d Aftertouch %d", status, c, d, ch, c, d); break; case 0xB0: d = *cP++; /* 2 data bytes */ msgPtr += sprintf(msgPtr, "MIDI: 0x%02X %02X %02X : channel %d Controller %d: %d", status, c, d, ch, c, d); break; case 0xC0: /* 1 data byte */ msgPtr += sprintf(msgPtr,"MIDI: 0x%02X %02X: channel %d Program Change: %d", status, c, ch, c); break; case 0xD0: /* 1 data byte */ msgPtr += sprintf(msgPtr,"MIDI: 0x%02X %02X: channel %d Channel Pressure: %d", status, c, ch, c); break; case 0xE0: /* 2 data bytes */ d = *cP++; /* 2 data bytes */ msgPtr += sprintf(msgPtr, "MIDI: 0x%02X %02X %02X : channel %d Pitch Wheel %d", status, c, d, ch, midifile_combine_bytes(c, d)); break; } } post("midifile: %s", msg); } } static void midifile_get_next_track_chunk_data(t_midifile *x, int mfTrack) /** parse the next track chunk data element and output via the appropriate outlet or post to main window * Sets the delta_time of the element or NO_MORE_ELEMENTS if no more elements */ { unsigned char *cP, *last_cP, *str; uint32_t delta_time, time_sig, len; unsigned char status, c, d=0, nn, dd, cc, bb, mi, mcp, n=0; char sf; char fps, hour, min, sec, frame, subframe; unsigned short sn; unsigned char tt[3]; t_atom output_atom[6]; cP = x->track_chunk[mfTrack].track_data + x->track_chunk[mfTrack].track_index; last_cP = x->track_chunk[mfTrack].track_data + x->track_chunk[mfTrack].chunk_length; delta_time = NO_MORE_ELEMENTS; if ((cP != NULL) && (cP < last_cP) && (x->track_chunk[mfTrack].delta_time != NO_MORE_ELEMENTS)) { cP = midifile_read_var_len(cP, &delta_time); status = *cP++; if ((status & 0xF0) == 0xF0) { switch (status) { /* system message */ case 0xF0: case 0xF7: cP = midifile_read_var_len(cP, &len); /* packet length */ if (x->verbosity) post("midifile: Sysex: %02X length %d", status, len); midifile_output_long_list(x->midi_list_outlet, cP, len, 0xF0); cP += len; x->track_chunk[mfTrack].running_status = 0; break; case 0xF1: /* quarter frame */ x->midi_data[0].a_w.w_float = status; outlet_list(x->midi_list_outlet, &s_list, 1, x->midi_data); x->track_chunk[mfTrack].running_status = 0; break; case 0xF3: /* song select */ c = *cP++; x->midi_data[0].a_w.w_float = status; x->midi_data[1].a_w.w_float = c; outlet_list(x->midi_list_outlet, &s_list, 2, x->midi_data); x->track_chunk[mfTrack].running_status = 0; break; case 0xF2: /* song position */ c = *cP++; x->midi_data[0].a_w.w_float = status; x->midi_data[1].a_w.w_float = c; c = *cP++; x->midi_data[2].a_w.w_float = c; outlet_list(x->midi_list_outlet, &s_list, 3, x->midi_data); x->track_chunk[mfTrack].running_status = 0; break; case 0xF6: /* tune request */ x->midi_data[0].a_w.w_float = status; outlet_list(x->midi_list_outlet, &s_list, 1, x->midi_data); x->track_chunk[mfTrack].running_status = 0; break; case 0xF8: /* MIDI clock */ case 0xF9: /* MIDI tick */ case 0xFA: /* MIDI start */ case 0xFB: /* MIDI continue */ case 0xFC: /* MIDI stop */ case 0xFE: /* active sense */ x->midi_data[0].a_w.w_float = status; outlet_list(x->midi_list_outlet, &s_list, 1, x->midi_data); break; case 0xFF: /* meta event */ c = *cP++; cP = midifile_read_var_len(cP, &len);/* meta length */ if (x->verbosity) post("midifile: Track %d Meta: %02X length %d", mfTrack, c, len); switch (c) { case 0x59: /* key signature */ sf = *(signed char *)cP++; mi = *cP++; if (x->verbosity) post ("midifile: Key Signature: %d %s, %s", sf, (sf<0)?"flats":"sharps", (mi)?"minor":"major"); SETFLOAT(&output_atom[0], sf); SETFLOAT(&output_atom[1], mi); SETSYMBOL(&output_atom[2], midifile_key_name(sf, mi)); outlet_anything( x->status_outlet, gensym("key_sig"), 3, output_atom); break; case 0x58: /* time signature */ nn = *cP++; dd = *cP++; dd = 1<<(dd); cc = *cP++; bb = *cP++; if (x->verbosity) post ("midifile: Time Signature: %d/%d %d clocks per tick, %d 32nd notes per quarternote", nn, dd, cc, bb); SETFLOAT(&output_atom[0], nn); SETFLOAT(&output_atom[1], dd); SETFLOAT(&output_atom[2], cc); SETFLOAT(&output_atom[3], bb); outlet_anything( x->status_outlet, gensym("time_sig"), 4, output_atom); break; case 0x54: /* smpte offset */ hour = *cP++; /* hour is mixed with fps as 0ffhhhhhh */ switch (hour>>6) { case 0: fps = 24; break; case 1: fps = 25; break; case 2: fps = 29;/* 30 fps dropframe */ break; case 3: fps = 30; default: fps = 0; /* error */ } hour = hour & 0x3F; min = *cP++; sec = *cP++; frame = *cP++; subframe = *cP++; if (x->verbosity) post ("midifile: SMPTE offset: %d:%d:%d:%d:%d, %d fps", hour, min, sec, frame, subframe, fps); SETFLOAT(&output_atom[0], hour); SETFLOAT(&output_atom[1], min); SETFLOAT(&output_atom[2], sec); SETFLOAT(&output_atom[3], frame); SETFLOAT(&output_atom[4], subframe); SETFLOAT(&output_atom[5], fps); outlet_anything( x->status_outlet, gensym("smpte"), 6, output_atom); break; case 0x51: /* set tempo */ tt[0] = *cP++; tt[1] = *cP++; tt[2] = *cP++; time_sig = midifile_get_multibyte_3(tt); if (x->verbosity) post ("midifile: %lu microseconds per MIDI quarter-note", time_sig); SETFLOAT(&output_atom[0], time_sig); outlet_anything( x->status_outlet, gensym("microsec_per_quarternote"), 1, output_atom); break; case 0x2F: /* end of track */ if (x->verbosity) post ("midifile: End of Track %d", mfTrack); delta_time = NO_MORE_ELEMENTS; SETFLOAT(&output_atom[0], mfTrack); SETFLOAT(&output_atom[1], x->total_time); outlet_anything( x->status_outlet, gensym("end"), 2, output_atom); cP += len; break; case 0x21: tt[0] = *cP++; if (x->verbosity) post ("midifile: MIDI port or cable number (unofficial): %d", tt[0]); break; case 0x20: /* MIDI channel prefix */ mcp = *cP++; if (x->verbosity) post ("midifile: MIDI Channel Prefix: %d", mcp); SETFLOAT(&output_atom[0], mfTrack); SETFLOAT(&output_atom[1], mcp); outlet_anything( x->status_outlet, gensym("channel"), 2, output_atom); break; case 0x07: /* cue point */ str = cP; c = cP[len]; cP[len] = '\0'; /* null terminate temporarily */ if (x->verbosity) post ("midifile: Cue Point: %s", str); SETSYMBOL(&output_atom[0], gensym((char *)str)); outlet_anything( x->status_outlet, gensym("cue"), 1, output_atom); cP[len] = c; cP += len; break; case 0x06: /* marker */ str = cP; c = cP[len]; cP[len] = '\0'; /* null terminate temporarily */ if (x->verbosity) post ("midifile: Marker: %s", str); SETSYMBOL(&output_atom[0], gensym((char *)str)); outlet_anything( x->status_outlet, gensym("marker"), 1, output_atom); cP[len] = c; cP += len; break; case 0x05: /* lyrics */ str = cP; c = cP[len]; cP[len] = '\0'; /* null terminate temporarily */ if (x->verbosity) post ("midifile: Lyric: %s", str); SETSYMBOL(&output_atom[0], gensym((char *)str)); outlet_anything( x->status_outlet, gensym("lyrics"), 1, output_atom); cP[len] = c; cP += len; break; case 0x04: /* instrument name */ str = cP; c = cP[len]; cP[len] = '\0'; /* null terminate temporarily */ if (x->verbosity) post ("midifile: Instrument Name: %s", str); SETSYMBOL(&output_atom[0], gensym((char *)str)); outlet_anything( x->status_outlet, gensym("instr_name"), 1, output_atom); cP[len] = c; cP += len; break; case 0x03: /* sequence/track name */ str = cP; c = cP[len]; cP[len] = '\0'; /* null terminate temporarily */ if (x->verbosity) post ("midifile: Sequence/Track Name: %s", str); SETFLOAT(&output_atom[0], mfTrack); SETSYMBOL(&output_atom[1], gensym((char *)str)); outlet_anything( x->status_outlet, gensym("name"), 2, output_atom); cP[len] = c; cP += len; break; case 0x02:/* copyright notice */ str = cP; c = cP[len]; cP[len] = '\0'; /* null terminate temporarily */ if (x->verbosity) post ("midifile: Copyright Notice: %s", str); SETSYMBOL(&output_atom[0], gensym((char *)str)); outlet_anything( x->status_outlet, gensym("copyright"), 1, output_atom); cP[len] = c; cP += len; break; case 0x01: /* text event */ str = cP; c = cP[len]; cP[len] = '\0'; /* null terminate temporarily */ if (x->verbosity) post ("midifile: Text Event: %s", str); SETSYMBOL(&output_atom[0], gensym((char *)str)); outlet_anything( x->status_outlet, gensym("text"), 1, output_atom); cP[len] = c; cP += len; break; case 0x00: /* sequence number */ tt[0] = *cP++; tt[1] = *cP++; sn = midifile_get_multibyte_2(tt); if (x->verbosity) post ("midifile: Sequence Number %d", sn); SETFLOAT(&output_atom[0], sn); outlet_anything( x->status_outlet, gensym("seq_num"), 1, output_atom); break; default: if (x->verbosity) post ("midifile: Unknown: %02X", c); cP += len; break; } break; default: /* 0xF4, 0xF5, 0xF9, 0xFD are not defined */ break; } } else { if (status & 0x80) { x->track_chunk[mfTrack].running_status = status;/* status is true status */ c = *cP++; } else { c = status; /* status is actually 1st data byte */ status = x->track_chunk[mfTrack].running_status; /* current status */ } switch (status & 0xF0) { case 0x80: case 0x90: case 0xA0: case 0xB0: case 0xE0: n = 3; d = *cP++; /* 2 data bytes */ break; case 0xC0: /* 1 data byte */ case 0xD0: n = 2; break; } x->midi_data[0].a_w.w_float = status; x->midi_data[1].a_w.w_float = c; x->midi_data[2].a_w.w_float = (n == 3)?d:0; if (x->midi_data[0].a_w.w_float != 0) outlet_list(x->midi_list_outlet, &s_list, n, x->midi_data); if (x->track_chunk[mfTrack].running_status == 0) error ("midifile: No running status on track %d at %d", mfTrack, x->track_chunk[mfTrack].total_time + delta_time); } } x->track_chunk[mfTrack].track_index = (char *)cP - (char *)x->track_chunk[mfTrack].track_data; x->track_chunk[mfTrack].delta_time = delta_time; if (delta_time == NO_MORE_ELEMENTS) x->track_chunk[mfTrack].total_time = delta_time; else x->track_chunk[mfTrack].total_time += delta_time; } /** parse the next track chunk data element and skip it without any output * Sets the delta_time of the element or NO_MORE_ELEMENTS if no more elements */ static void midifile_skip_next_track_chunk_data(t_midifile *x, int mfTrack) { unsigned char *cP, *last_cP; uint32_t delta_time, len; unsigned char status, c, n; cP = x->track_chunk[mfTrack].track_data + x->track_chunk[mfTrack].track_index; last_cP = x->track_chunk[mfTrack].track_data + x->track_chunk[mfTrack].chunk_length; delta_time = NO_MORE_ELEMENTS; if ((cP != NULL) && (cP < last_cP) && (x->track_chunk[mfTrack].delta_time != NO_MORE_ELEMENTS)) { cP = midifile_read_var_len(cP, &delta_time); status = *cP++; if ((status & 0xF0) == 0xF0) { switch (status) { /* system message */ case 0xF0: case 0xF7: cP = midifile_read_var_len(cP, &len); /* packet length */ cP += len; break; case 0xF1: /* quarter frame */ break; case 0xF3: /* song select */ cP += 1; break; case 0xF2: /* song position */ cP += 2; break; case 0xF6: /* tune request */ case 0xF8: /* MIDI clock */ case 0xF9: /* MIDI tick */ case 0xFA: /* MIDI start */ case 0xFB: /* MIDI continue */ case 0xFC: /* MIDI stop */ case 0xFE: /* active sense */ break; case 0xFF: c = *cP++; cP = midifile_read_var_len(cP, &len);/* meta length */ switch (c) { case 0x2F: if (x->verbosity) post ("midifile: End of Track %d", mfTrack); delta_time = NO_MORE_ELEMENTS; /* fall through to default....*/ default: cP += len; break; } break; default: /* 0xF4, 0xF5, 0xF9, 0xFD are not defined */ break; } } else { if (status & 0x80) { x->track_chunk[mfTrack].running_status = status; n = 1; } else { n = 0; /* no status in this message */ status = x->track_chunk[mfTrack].running_status; } switch (status & 0xF0) { case 0x80: case 0x90: case 0xA0: case 0xB0: case 0xE0: n += 1; /* data bytes */ break; case 0xC0: case 0xD0: /* only one data byte */ break; } cP += n; } } x->track_chunk[mfTrack].track_index = (char *)cP - (char *)x->track_chunk[mfTrack].track_data; x->track_chunk[mfTrack].delta_time = delta_time; if (delta_time == NO_MORE_ELEMENTS) x->track_chunk[mfTrack].total_time = delta_time; else x->track_chunk[mfTrack].total_time += delta_time; } /** set a symbol to the key name based on * sf= number of sharps if positive, else flats * mi = 0=major 1= minor */ static t_symbol *midifile_key_name(int sf, int mi) { char *maj_key[15]={"B", "Gb", "Db", "Ab", "Eb", "Bb", "F", "C", "G", "D", "A", "E", "B", "F#", "Db"}; char *min_key[15]={"G#", "Eb", "Bb", "F", "C", "G", "D", "A", "E", "B", "F#", "C#", "G#", "D#", "Bb"}; char buf[8] = {"no_key."}; int i; if ((sf >= -7)&&(sf <= 7)) { if (mi == 1) { i = sprintf(buf, "%s", min_key[sf+7]); sprintf(buf+i, "%s", "Minor"); } else if (mi == 0) { i = sprintf(buf, "%s", maj_key[sf+7]); sprintf(buf+i, "%s", "Major"); } } return gensym(buf); } /* fin midifile.c */ mrpeach/midifile/midifile-help.pd0000644000175000017500000003236613240656554017572 0ustar zmoelnigzmoelnig#N canvas 583 98 399 237 12; #N canvas 24 112 1136 834 midifile_write 0; #X obj 324 -2 bng 45 250 50 0 empty empty choose 5 23 0 8 -62784 -260818 -258699; #X obj 67 65 tgl 45 0 empty empty record 2 23 0 8 -258699 -241291 -24198 0 1; #X floatatom 553 780 15 0 0 0 tick - -, f 15; #X obj 67 150 metro 2; #X floatatom 120 125 15 0 0 0 - - -, f 15; #X msg 120 99 2.005; #X msg 506 590 verbose \$1; #X text 525 544 verbosity defaults to 1; #X obj 324 54 savepanel; #X msg 409 493 240 1 2 3 4 247; #X text 536 492 a sysex message; #X obj 553 750 float; #X floatatom 506 564 5 0 0 0 - - -, f 5; #X msg 324 408 write \$1 \$2 \$3; #X msg 350 199 29; #X msg 388 199 30; #X msg 235 199 0; #X floatatom 405 275 5 0 0 0 ticks_per_frame - -, f 5; #X text 80 301 (ticks per quarter note if frames per second is zero) ; #X msg 312 199 25; #X msg 272 199 24; #X text 79 322 25 20 will give accurate timing with metro ticks at 2ms; #X obj 324 375 pack s 25 20; #X obj 559 663 midifile; #X text 7 199 time code frames per second:; #X text 509 432 default is 90 ticks per quarter note; #X msg 349 433 write filename.mid; #X msg 374 458 write filename.mid 77; #X text 555 457 77 ticks per quarter note; #X msg 442 526 flush; #X obj 268 146 cnv 15 200 20 empty empty empty 20 12 0 14 -257985 -66577 0; #X floatatom 514 145 5 0 0 0 note - -, f 5; #X floatatom 514 175 5 0 0 0 velocity - -, f 5; #X obj 558 333 pack 144 0 0; #X obj 577 179 sel 0; #X obj 558 206 t b f; #X obj 558 307 f; #X text 553 565 set to 3 to debug input; #X obj 558 125 notein; #X obj 102 8 cnv 15 220 20 empty empty empty 20 12 0 14 -257985 -66577 0; #X text 104 10 1: open a file for writing:; #X obj 116 64 cnv 15 150 20 empty empty empty 20 12 0 14 -257985 -66577 0; #X text 118 67 2: start recording; #X obj 142 524 cnv 15 300 20 empty empty empty 20 12 0 14 -257985 -66577 0; #X text 150 526 4: stop recording and save the file:; #X floatatom 512 230 5 0 0 0 channel - -, f 5; #X obj 609 287 +; #X msg 577 235 127; #X msg 609 207 143; #X floatatom 919 103 5 0 0 0 value - -, f 5; #X floatatom 919 134 5 0 0 0 controller - -, f 5; #X floatatom 917 183 5 0 0 0 channel - -, f 5; #X obj 965 83 ctlin; #X obj 965 237 pack 176 0 0; #X obj 965 269 print ctl>; #X obj 579 374 print note>; #X obj 965 119 t b f; #X obj 965 183 f; #X obj 1020 126 + 175; #X text 285 143 3: input MIDI as lists; #X msg 778 551 track \$1; #X msg 971 519 144 60 0; #X msg 882 518 144 60 64; #X msg 863 549 144 67 64; #X msg 953 549 144 67 0; #X obj 778 500 hradio 15 1 0 8 empty empty empty 0 -8 0 10 -262144 -1 -1 0; #X obj 708 633 r midiwrite; #N canvas 141 452 1100 497 meta_messages 0; #X text 71 6 FF 51 3 tttttt Set Tempo (in microseconds per MIDI quarter-note) ; #X obj 539 526 s midiwrite; #X text 407 196 Instrument Name; #X text 399 220 Lyric; #X text 385 126 Text Event (should be at start of track); #X text 224 102 Sequence Number (must be at start of track); #X text 419 150 Copyright Notice; #X text 398 173 Sequence/Track Name; #X msg 372 339 meta 81 500000; #X text 495 338 Set Tempo (microseconds per MIDI quarter-note); #X msg 136 103 meta 0 678; #X text 439 244 Marker; #X text 463 268 Cue Point; #X msg 326 293 meta 32 5; #X text 405 292 MIDI Channel Prefix; #X msg 349 316 meta 47; #X text 414 315 End of Track; #X text 6 42 raw mode; #X text 44 104 meta method; #X msg 74 41 255 81 3 500000; #X text 544 361 SMPTE Offset (hr mi se fr ff); #X msg 395 362 meta 84 0 1 30 4 5; #X text 555 384 Time Signature; #X msg 418 385 meta 88 6 3 36 8; #X msg 441 408 meta 89 0 0; #X text 538 407 Key Signature (number of sharps(+) / flats(-) 0 or 1 for major or minor; #X msg 481 448 meta 127 0 1 22 33 44 55; #X text 683 449 Sequencer-Specific Meta-Event; #X msg 509 476 meta 52; #X text 574 475 unknown; #X msg 230 197 meta 4 twisted_guitar; #X msg 278 245 meta 6 another_part; #X msg 302 269 meta 7 "drops_ball"; #X msg 160 127 meta 1 Some_text_goes_here.; #X msg 184 151 meta 2 (C)2018_Nobody_At_All; #X msg 207 174 meta 3 amazing_sequence; #X msg 254 221 meta 5 "what_the"; #X text 575 143 Underscore will be replaced by space in text metas ; #X connect 8 0 1 0; #X connect 10 0 1 0; #X connect 13 0 1 0; #X connect 15 0 1 0; #X connect 19 0 1 0; #X connect 21 0 1 0; #X connect 23 0 1 0; #X connect 24 0 1 0; #X connect 26 0 1 0; #X connect 28 0 1 0; #X connect 30 0 1 0; #X connect 31 0 1 0; #X connect 32 0 1 0; #X connect 33 0 1 0; #X connect 34 0 1 0; #X connect 35 0 1 0; #X connect 36 0 1 0; #X restore 561 87 pd meta_messages; #X obj 506 532 hradio 15 1 0 5 empty empty verbosity 0 -6 0 12 -62784 -241291 -1 4; #X obj 174 86 cnv 15 380 20 empty empty empty 20 12 0 14 -257985 -66577 0; #X text 180 86 Maybe add some meta messages before we start:; #X text 780 478 choose track to write; #X text 753 744 Martin Peach \, 2010 - 2018; #X connect 0 0 8 0; #X connect 1 0 3 0; #X connect 3 0 23 0; #X connect 4 0 3 1; #X connect 5 0 4 0; #X connect 6 0 23 0; #X connect 8 0 22 0; #X connect 9 0 23 0; #X connect 11 0 2 0; #X connect 12 0 6 0; #X connect 13 0 23 0; #X connect 14 0 22 1; #X connect 15 0 22 1; #X connect 16 0 22 1; #X connect 17 0 22 2; #X connect 19 0 22 1; #X connect 20 0 22 1; #X connect 22 0 13 0; #X connect 23 1 11 1; #X connect 23 2 11 0; #X connect 26 0 23 0; #X connect 27 0 23 0; #X connect 29 0 23 0; #X connect 33 0 23 0; #X connect 33 0 55 0; #X connect 34 0 47 0; #X connect 34 1 48 0; #X connect 35 0 36 0; #X connect 35 1 33 1; #X connect 36 0 33 0; #X connect 38 0 31 0; #X connect 38 0 35 0; #X connect 38 1 32 0; #X connect 38 1 34 0; #X connect 38 1 33 2; #X connect 38 2 45 0; #X connect 38 2 46 1; #X connect 46 0 36 1; #X connect 47 0 46 0; #X connect 48 0 46 0; #X connect 52 0 49 0; #X connect 52 0 56 0; #X connect 52 1 50 0; #X connect 52 1 53 1; #X connect 52 2 51 0; #X connect 52 2 58 0; #X connect 53 0 54 0; #X connect 53 0 23 0; #X connect 56 0 57 0; #X connect 56 1 53 2; #X connect 57 0 53 0; #X connect 58 0 57 1; #X connect 60 0 23 0; #X connect 61 0 23 0; #X connect 62 0 23 0; #X connect 63 0 23 0; #X connect 64 0 23 0; #X connect 65 0 60 0; #X connect 66 0 23 0; #X connect 68 0 12 0; #X restore 76 116 pd midifile_write; #N canvas 73 183 1087 702 midifile_read 0; #X obj 544 149 bng 15 250 50 0 empty empty step_one_tick 18 7 0 12 -4160 -257985 -1; #X obj 12 69 openpanel; #X obj 12 16 bng 45 250 50 0 empty empty choose 3 23 0 12 -62784 -260818 -258699; #X obj 116 151 tgl 45 0 empty empty play -45 23 0 12 -24198 -1 -258699 0 1; #X msg 391 478 rewind; #X text 235 477 go to start of file; #X floatatom 501 581 15 0 0 0 current_tick - -, f 15; #X obj 235 301 hradio 15 1 0 16 empty empty dump_track_number 0 -6 0 12 -62784 -241291 -1 0; #X msg 235 322 dump \$1; #X msg 354 441 68050; #X msg 179 266 track \$1; #X obj 179 226 hradio 15 1 0 16 empty empty play_track_number 0 -6 0 12 -62784 -241291 -1 4; #X obj 116 203 metro 2; #X text 158 542 creation arguments: midi_file_name; #X text 298 321 parse this track to main window; #X floatatom 591 652 15 0 0 0 last_tick - -, f 15; #X msg 311 398 verbose \$1; #X text 123 398 verbosity defaults to 1; #X text 63 11 1: choose a MIDI file to play; #X text 169 145 2: start playing it; #X obj 435 424 spigot; #X obj 480 390 tgl 25 0 empty empty loop -45 12 0 12 -4160 -257985 -258113 0 1; #X msg 12 99 read \$1; #X floatatom 311 374 5 0 0 0 - - -, f 5; #X obj 311 355 hradio 15 1 0 5 empty empty verbosity 0 -6 0 12 -62784 -241291 -1 4; #X obj 179 243 - 1; #X obj 435 542 midifile wowo.mid; #X obj 65 505 ctlout 123; #X msg 65 475 123; #X msg 39 126 read I_Wanna_Be_Sedated.mid; #X obj 65 447 bng 15 250 50 0 empty empty all_notes_off 17 7 0 10 -258113 -257985 -1; #X obj 754 610 t b b; #X floatatom 134 263 5 0 0 0 - - -, f 5; #X obj 791 637 bng 15 250 50 0 empty empty end 17 7 0 10 -258113 -257985 -1; #X floatatom 632 433 9 0 0 0 loop_start_tick: - -, f 9; #X text 214 243 -1 = play all tracks; #X obj 591 630 f; #X obj 435 450 f 0; #N canvas 15 196 1058 571 route_events 0; #X obj 20 29 inlet; #X floatatom 172 125 5 0 0 0 note - -, f 5; #X floatatom 249 125 5 0 0 1 velocity - -, f 5; #X obj 172 50 route 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159; #X obj 172 103 unpack 0 0; #X obj 178 182 route 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143; #X obj 18 86 print note_on; #X obj 18 218 print note_off; #X obj 705 283 noteout 1; #X obj 786 283 noteout 2; #X obj 865 283 noteout 3; #X obj 945 283 noteout 4; #X obj 178 289 route 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192; #X floatatom 178 363 5 0 0 0 controller - -, f 5; #X floatatom 252 363 5 0 0 1 value - -, f 5; #X obj 178 339 unpack 0 0; #X obj 17 325 print controller; #X obj 706 359 ctlout 1; #X text 172 30 route note-on events by channel:; #X text 235 162 route note off events by channel:; #X text 225 265 route controller events by channel:; #X text 699 249 send events to MIDI devices:; #X obj 473 438 route 240; #X obj 572 501 print sysex; #X connect 0 0 3 0; #X connect 3 0 4 0; #X connect 3 0 6 0; #X connect 3 0 8 0; #X connect 3 1 9 0; #X connect 3 2 10 0; #X connect 3 3 11 0; #X connect 3 16 5 0; #X connect 4 0 1 0; #X connect 4 1 2 0; #X connect 5 0 7 0; #X connect 5 0 8 0; #X connect 5 1 9 0; #X connect 5 2 10 0; #X connect 5 3 11 0; #X connect 5 16 12 0; #X connect 12 0 15 0; #X connect 12 0 16 0; #X connect 12 0 17 0; #X connect 12 17 22 0; #X connect 15 0 13 0; #X connect 15 1 14 0; #X connect 22 0 23 0; #X restore 435 604 pd route_events; #N canvas 114 197 1088 523 route_info 0; #X obj 34 13 inlet; #X floatatom 34 73 3 0 0 1 format - -, f 3; #X floatatom 142 73 5 0 0 1 tracks - -, f 5; #X floatatom 252 73 5 0 0 1 ticks_per_quarternote - -, f 5; #X floatatom 360 140 5 0 0 1 tracks - -, f 5; #X symbolatom 546 190 40 0 0 0 - - -, f 40; #X obj 538 224 unpack 0 0; #X floatatom 615 278 15 0 0 0 last_tick - -, f 15; #X floatatom 538 250 5 0 0 1 track - -, f 5; #X floatatom 449 190 5 0 0 1 track - -, f 5; #X obj 449 164 unpack 0 s; #X obj 627 316 unpack 0 0 0 0; #X floatatom 627 352 3 0 0 1 / - -, f 3; #X floatatom 663 353 3 0 0 1 - - -, f 3; #X floatatom 699 353 5 0 0 1 clocks_per_click - -, f 5; #X floatatom 736 379 5 0 0 1 32nds_per_quarternote - -, f 5; #X floatatom 716 136 15 0 0 0 microsec_per_quarternote - -, f 15; #X obj 229 354 /; #X floatatom 442 374 15 0 0 0 microsec_per_tick - -, f 15; #X obj 229 395 / 1000; #X floatatom 229 426 15 0 0 0 millisec_per_tick - -, f 15; #X obj 906 190 print other_meta; #X obj 360 103 route seq_num name end time_sig microsec_per_quarternote ; #X obj 805 161 route key_sig; #X obj 805 218 unpack 0 0 s; #X symbolatom 898 323 10 0 0 0 key - -, f 10; #X floatatom 805 247 5 0 0 1 +sharps/-flats - -, f 5; #X obj 851 276 tgl 15 0 empty empty minor 17 7 0 10 -262144 -1 -1 0 1; #X obj 546 164 list prepend; #X obj 898 297 list prepend; #X obj 34 43 route format tracks ticks_per_quarternote; #X obj 228 477 s msec_per_tick; #X obj 405 211 print name:; #X text 503 352 time signature:; #X connect 0 0 30 0; #X connect 6 0 8 0; #X connect 6 1 7 0; #X connect 10 0 9 0; #X connect 10 1 28 0; #X connect 11 0 12 0; #X connect 11 1 13 0; #X connect 11 2 14 0; #X connect 11 3 15 0; #X connect 17 0 18 0; #X connect 17 0 19 0; #X connect 19 0 20 0; #X connect 19 0 31 0; #X connect 22 0 4 0; #X connect 22 1 10 0; #X connect 22 1 32 0; #X connect 22 2 6 0; #X connect 22 3 11 0; #X connect 22 4 16 0; #X connect 22 4 17 0; #X connect 22 5 23 0; #X connect 23 0 24 0; #X connect 23 1 21 0; #X connect 24 0 26 0; #X connect 24 1 27 0; #X connect 24 2 29 0; #X connect 28 0 5 0; #X connect 29 0 25 0; #X connect 30 0 1 0; #X connect 30 1 2 0; #X connect 30 2 3 0; #X connect 30 2 17 1; #X connect 30 3 22 0; #X restore 831 599 pd route_info; #X obj 754 562 route bang; #X text 222 441 goto tick 68050:; #X obj 386 147 r msec_per_tick; #X floatatom 386 186 9 0 0 0 - - -, f 9; #X text 584 541 metadata are output on third outlet; #X text 31 604 MIDI messages are output on first outlet as lists:; #X text 590 562 bang at end of file:; #X text 386 108 milliseconds per tick is calculated from metadata at start of file. Step one tick to get the initial value.; #X text 793 665 Martin Peach \, 2011-2018; #X connect 0 0 26 0; #X connect 1 0 22 0; #X connect 2 0 1 0; #X connect 3 0 12 0; #X connect 4 0 26 0; #X connect 7 0 8 0; #X connect 8 0 26 0; #X connect 9 0 26 0; #X connect 10 0 26 0; #X connect 11 0 25 0; #X connect 12 0 26 0; #X connect 16 0 26 0; #X connect 20 0 37 0; #X connect 21 0 20 1; #X connect 22 0 26 0; #X connect 23 0 16 0; #X connect 24 0 23 0; #X connect 25 0 10 0; #X connect 25 0 32 0; #X connect 26 0 38 0; #X connect 26 1 6 0; #X connect 26 1 36 1; #X connect 26 2 40 0; #X connect 28 0 27 0; #X connect 29 0 26 0; #X connect 30 0 28 0; #X connect 31 0 20 0; #X connect 31 1 36 0; #X connect 31 1 33 0; #X connect 34 0 37 1; #X connect 36 0 15 0; #X connect 37 0 26 0; #X connect 40 0 31 0; #X connect 40 1 39 0; #X connect 42 0 43 0; #X connect 43 0 12 1; #X restore 76 83 pd midifile_read; #X text 15 10 midifile reads and writes MIDI files.; #N canvas 403 187 587 265 META 0; #X text 12 185 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; #X text 12 25 LICENSE GPL v2 or later; #X text 12 165 AUTHOR Martin Peach; #X text 12 5 KEYWORDS control MIDI; #X text 12 45 DESCRIPTION read and write MIDI files; #X text 12 105 OUTLET_0 list; #X text 12 125 OUTLET_1 float; #X text 12 145 OUTLET_2 bang; #X text 12 65 INLET_0 bang float list rewind read track dump verbose write meta flush; #X restore 335 202 pd META; #X text 148 203 2018/02/13 Martin Peach; mrpeach/op~/0000755000175000017500000000000013605444732013553 5ustar zmoelnigzmoelnigmrpeach/op~/op~-help.pd0000644000175000017500000000501411533624307015636 0ustar zmoelnigzmoelnig#N canvas 1 53 749 629 10; #X obj 152 267 dac~; #X obj 168 205 line~; #X obj 171 162 hsl 128 15 0 1 0 0 empty empty level -2 -8 0 10 -4034 -13381 -1 0 1; #X msg 168 182 \$1 100; #X obj 153 230 *~; #X obj 154 99 op~ <; #X obj 180 -25 osc~ 120; #X obj 153 -46 osc~ 0.01; #X obj 154 125 lop~ 10000; #X obj -197 216 env~; #X floatatom -197 238 5 0 0 0 - - -; #X floatatom -196 148 5 0 0 0 - - -; #X floatatom -163 170 5 0 0 0 - - -; #X obj -196 194 op~ !=; #X text -197 94 op~ compares two inlet signals or floats according to the operator specified in the creation argument.; #X text -186 330 Author: Martin Peach \, 2010/03/23. Based on zexy [<~] etc.; #X msg 113 41 help; #X obj 361 133 op~ >=; #X obj 360 68 noise~; #X floatatom 394 102 5 0 0 0 - - -; #X obj 360 305 dac~; #X obj 376 243 line~; #X obj 379 200 hsl 128 15 0 1 0 0 empty empty level -2 -8 0 10 -4034 -13381 -1 0 1; #X msg 376 220 \$1 100; #X obj 361 268 *~; #X obj 362 164 lop~ 100; #X msg 22 -50 op <; #X msg 42 -30 op >; #X msg 62 -10 op ==; #X msg 82 10 op !=; #X msg 2 -70 op <=; #X msg -20 -92 op >=; #X msg -105 -177 op ge; #X msg -125 -197 op le; #X msg -145 -217 op lt; #X msg -82 -154 op gt; #X msg -61 -133 op eq; #X msg -41 -113 op ne; #X msg -166 -238 op nop; #X text -98 40 Print a list of allowed operators:; #X text -148 -92 set operator to >=:; #N canvas 529 140 494 344 META 0; #X text 12 155 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; #X text 12 25 LICENSE GPL v2 or later; #X text 12 135 AUTHOR Martin Peach; #X text 12 45 DESCRIPTION compare two inlet signals or floats according to the operator specified in the creation argument; #X text 12 75 INLET_0 signal op; #X text 12 95 INLET_1 signal; #X text 12 115 OUTLET_0 signal; #X text 12 5 KEYWORDS signal; #X restore 499 364 pd META; #X connect 1 0 4 1; #X connect 2 0 3 0; #X connect 3 0 1 0; #X connect 4 0 0 0; #X connect 4 0 0 1; #X connect 5 0 8 0; #X connect 6 0 5 1; #X connect 7 0 5 0; #X connect 8 0 4 0; #X connect 9 0 10 0; #X connect 11 0 13 0; #X connect 12 0 13 1; #X connect 13 0 9 0; #X connect 16 0 5 0; #X connect 17 0 25 0; #X connect 18 0 17 0; #X connect 19 0 17 1; #X connect 21 0 24 1; #X connect 22 0 23 0; #X connect 23 0 21 0; #X connect 24 0 20 0; #X connect 24 0 20 1; #X connect 25 0 24 0; #X connect 26 0 5 0; #X connect 27 0 5 0; #X connect 28 0 5 0; #X connect 29 0 5 0; #X connect 30 0 5 0; #X connect 31 0 5 0; #X connect 32 0 5 0; #X connect 33 0 5 0; #X connect 34 0 5 0; #X connect 35 0 5 0; #X connect 36 0 5 0; #X connect 37 0 5 0; #X connect 38 0 5 0; mrpeach/op~/op~.c0000644000175000017500000001423311352227200014520 0ustar zmoelnigzmoelnig/* op~ by Martin Peach 201003123, based on the zexy binop externals: */ /****************************************************** * * zexy - implementation file * * copyleft (c) IOhannes m zmlnig * * 1999:forum::fr::umlute:2004 * * institute of electronic music and acoustics (iem) * ****************************************************** * * license: GNU General Public License v.2 * ******************************************************/ /* ----------------------------- op_tilde ----------------------------- */ #include "m_pd.h" static t_class *op_tilde_class; static char *operator_names[] = {"<=", ">=", "!=", "==", "<", ">", "le", "ge", "ne", "eq", "lt", "gt", "nop"}; static int n_opnames = 13; typedef enum { le = 0, ge, ne, eq, lt, gt, nop, none } op_op; typedef struct _op_tilde { t_object x_obj; t_float x_f; t_float x_g; /* inlet value */ op_op x_operator; } t_op_tilde; static void *op_tilde_new(t_symbol *s, int argc, t_atom *argv); static t_int *op_tilde_perform(t_int *w); static void op_tilde_help(t_op_tilde *x); static void op_tilde_op(t_op_tilde *x, t_symbol *op); static void op_tilde_dsp(t_op_tilde *x, t_signal **sp); void op_tilde_setup(void); static void *op_tilde_new(t_symbol *s, int argc, t_atom *argv) { t_symbol *argsym; if (argc > 1) post("op~: extra arguments ignored"); if (argc == 0) post("op~: need to specify operator"); argsym = atom_getsymbolarg(0, argc, argv); // post ("op~: %s", argsym->s_name); t_op_tilde *x = (t_op_tilde *)pd_new(op_tilde_class); x->x_operator = none; switch (argsym->s_name[0]) { case '<': if (argsym->s_name[1] == 0) x->x_operator = lt; else if (argsym->s_name[1] == '=') x->x_operator = le; break; case '>': if (argsym->s_name[1] == 0) x->x_operator = gt; else if (argsym->s_name[1] == '=') x->x_operator = ge; break; case '=': if (argsym->s_name[1] == '=') x->x_operator = eq; break; case '!': if (argsym->s_name[1] == '=') x->x_operator = ne; break; case 'n': if ( (argsym->s_name[1] == 'o') && (argsym->s_name[2] == 'p') && (argsym->s_name[3] == '\0') ) x->x_operator = nop; break; } if (x->x_operator == none) { post("op~: unknown operator"); x->x_operator = nop; } inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); outlet_new(&x->x_obj, &s_signal); x->x_f = 0; x->x_g = 0; return (x); } static t_int *op_tilde_perform(t_int *w) { t_op_tilde *x = (t_op_tilde *)(w[1]); t_sample *in1 = (t_sample *)(w[2]); t_sample *in2 = (t_sample *)(w[3]); t_sample *out = (t_sample *)(w[4]); int n = (int)(w[5]); switch (x->x_operator) { case le: while (n--) *out++ = *in1++ <= *in2++; break; case ge: while (n--) *out++ = *in1++ >= *in2++; break; case ne: while (n--) *out++ = *in1++ != *in2++; break; case eq: while (n--) *out++ = *in1++ == *in2++; break; case lt: while (n--) *out++ = *in1++ < *in2++; break; case gt: while (n--) *out++ = *in1++ > *in2++; break; case nop: default: while (n--) *out++ = 0; break; } return (w+6); } static void op_tilde_help(t_op_tilde *x) { int i; post("op~: available operators:"); for (i = 0; i < n_opnames; ++i) { post ("%s", operator_names[i]); } } static void op_tilde_op(t_op_tilde *x, t_symbol *op) { int i, j = 0; while ((op->s_name[j] != '\0') && (j < 3)) ++j; if ((j < 1) || (j > 3)) { post("op~: %s is not a valid operator (length %d)", op->s_name, j); return; } for (i = 0; i < n_opnames; ++i) { if (operator_names[i][0] != op->s_name[0]) continue; if ((j == 2) && (operator_names[i][1] != op->s_name[1])) continue; if ((j == 3) && (operator_names[i][2] != op->s_name[2])) continue; if ((j == 1) && (operator_names[i][1] != '\0')) continue; break; } if (i == n_opnames) { post("op~: %s is not a valid operator (match)", op->s_name); return; } switch(i) { /*"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"*/ /*"<=", ">=", "!=", "==", "<", ">", "le", "ge", "ne", "eq", "lt", "gt", "nop"*/ case 0: case 6: /* "<=" "le" */ x->x_operator = 0; break; case 1: case 7: /* ">=" "ge" */ x->x_operator = 1; break; case 2: case 8: /* "!=" "ne" */ x->x_operator = 2; break; case 3: case 9: /* "==" "eq" */ x->x_operator = 3; break; case 4: case 10: /* "<" "lt" */ x->x_operator = 4; break; case 5: case 11: /* ">" "gt" */ x->x_operator = 5; break; default: /* "nop" */ x->x_operator = 6; break; } // post("op~: operator %s", operator_names[i]); } static void op_tilde_dsp(t_op_tilde *x, t_signal **sp) { t_sample *in1 = sp[0]->s_vec; t_sample *in2 = sp[1]->s_vec; t_sample *out = sp[2]->s_vec; int n = sp[0]->s_n; dsp_add(op_tilde_perform, 5, x, in1, in2, out, n); } void op_tilde_setup(void) { op_tilde_class = class_new(gensym("op~"), (t_newmethod)op_tilde_new, 0, sizeof(t_op_tilde), 0, A_GIMME, 0); class_addmethod(op_tilde_class, (t_method)op_tilde_dsp, gensym("dsp"), 0); class_addmethod(op_tilde_class, (t_method)op_tilde_help, gensym("help"), 0); class_addmethod(op_tilde_class, (t_method)op_tilde_op, gensym("op"), A_DEFSYMBOL, 0); CLASS_MAINSIGNALIN(op_tilde_class, t_op_tilde, x_f); } /* fin op~.c */ mrpeach/str/0000755000175000017500000000000013605444731013546 5ustar zmoelnigzmoelnigmrpeach/str/str-help.pd0000644000175000017500000002101711026462102015615 0ustar zmoelnigzmoelnig#N canvas 93 115 450 300 10; #N canvas 32 72 706 515 string 0; #X obj 88 454 print; #X obj 143 328 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 -1; #X floatatom 37 53 5 0 0 0 - - -; #X obj 88 387 str hello 32 there 10 no more; #X obj 16 7 str nono 32 pitek; #X obj 16 -15 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 -1; #X obj 88 429 str to_list; #X obj 67 123 symbol tikka; #X obj 67 100 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 -1; #X msg 117 218 str 2; #X text 174 430 str to_list outputs the string as a list of floats. ; #X text 299 378 str string (the default) converts nearly anything to a string.; #X msg 100 190 set one 2; #X msg 82 155 list 1 2 3 alpha; #X text 80 51 Whole numbers from -127 through 255 are converted to single bytes. All others are formatted as floats using ASCII characters. ; #X text 173 190 Set the string quietly; #X floatatom 130 29 5 0 0 0 - - -; #X text 165 0 The basic [str] or [str string] outputs a string on its left outlet and the length of the string at the reight outlet.; #X floatatom 286 410 5 0 0 0 - - -; #X msg 127 260 file_read test.txt; #X text 159 124 Symbols are interpreted as text strings.; #X text 210 156 List elements are converted to numbers or strings. ; #X text 167 215 Messages other than [list ...( or [set ...( are transcribed directly.; #X msg 136 282 file_write test.txt; #X text 265 261 String data can be stored in and retrieved from files. ; #X text 163 327 [Bang] generates output.; #X connect 1 0 3 0; #X connect 2 0 3 0; #X connect 3 0 6 0; #X connect 3 1 18 0; #X connect 4 0 3 0; #X connect 4 1 16 0; #X connect 5 0 4 0; #X connect 6 0 0 0; #X connect 7 0 3 0; #X connect 8 0 7 0; #X connect 9 0 3 0; #X connect 12 0 3 0; #X connect 13 0 3 0; #X connect 19 0 3 0; #X connect 23 0 3 0; #X restore 3 31 pd string; #N canvas 259 148 678 300 split 0; #X obj 67 101 str to_list; #X obj 174 100 str to_list; #X obj 67 126 print left; #X obj 174 125 print right; #X obj 95 55 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 -1; #X obj 95 79 str nsplit 6; #X floatatom 174 55 5 0 0 0 - - -; #X text 192 79 [str nsplit] splits a string in two at the nth character. ; #X msg 42 31 set microscope; #X obj 75 244 str to_list; #X obj 156 244 str to_list; #X obj 75 269 print left; #X obj 156 269 print right; #X obj 142 193 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 -1; #X obj 142 218 str csplit 32; #X msg 65 170 what 32 are 32 you 10 13; #X msg 176 193 set t 32; #X text 251 193 Set the target character(s); #X text 244 217 [str csplit] splits incoming strings in two at the first occurrence of any of the characters in its string. The second string begins with the first remaining non-target character.; #X text 153 31 Quietly set the string to be split; #X text 219 54 Split position: positive from start \, negative from end; #X text 252 11 Split this string; #X msg 6 10 10 11 12 13 14 15 16 17 18 19 20; #X connect 0 0 2 0; #X connect 1 0 3 0; #X connect 4 0 5 0; #X connect 5 0 0 0; #X connect 5 1 1 0; #X connect 6 0 5 1; #X connect 8 0 5 0; #X connect 9 0 11 0; #X connect 10 0 12 0; #X connect 13 0 14 0; #X connect 14 0 9 0; #X connect 14 1 10 0; #X connect 15 0 14 0; #X connect 16 0 14 0; #X connect 22 0 5 0; #X restore 3 66 pd split; #N canvas 273 114 640 400 join 0; #X obj 48 60 str join pig; #X obj 48 108 str to_list; #X obj 206 -4 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 -1; #X obj 13 -32 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 -1; #X obj 198 15 str 32 the 32 end; #X obj 13 -13 str This 32 is; #X msg 10 31 set That 32 was; #X floatatom 198 -27 5 0 0 0 - - -; #X obj 48 130 print joined; #X obj 10 51 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 -1; #X text 175 60 [str join]: Set the string to be appended either with a [set( message to the first inlet or by sending a string to the second inlet.; #X msg 43 -34 elephant; #X floatatom 106 7 5 0 0 0 - - -; #X floatatom 312 36 5 0 0 0 - - -; #X floatatom 127 82 5 0 0 0 - - -; #X obj 43 259 str add abc; #X floatatom 43 217 5 0 0 0 - - -; #X obj 17 233 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 -1; #X obj 43 303 str to_list; #X obj 115 200 str; #X floatatom 88 159 5 0 0 0 - - -; #X msg 115 176 whoa; #X msg 55 236 set; #X text 84 237 [set( message without arguments clears the string.; #X text 133 259 [str add] adds input to the end of the string until banged.; #X floatatom 129 221 5 0 0 0 - - -; #X floatatom 115 282 5 0 0 0 - - -; #X text 158 282 string length; #X obj 43 324 print added; #X connect 0 0 1 0; #X connect 0 1 14 0; #X connect 1 0 8 0; #X connect 2 0 4 0; #X connect 3 0 5 0; #X connect 4 0 0 1; #X connect 4 1 13 0; #X connect 5 0 0 0; #X connect 5 1 12 0; #X connect 6 0 0 0; #X connect 7 0 4 0; #X connect 9 0 0 0; #X connect 11 0 0 0; #X connect 15 0 18 0; #X connect 15 1 26 0; #X connect 16 0 15 0; #X connect 17 0 15 0; #X connect 18 0 28 0; #X connect 19 0 15 1; #X connect 19 1 25 0; #X connect 20 0 19 0; #X connect 21 0 19 0; #X connect 22 0 15 0; #X restore 3 99 pd join; #X text 61 98 join and add; #N canvas 0 0 771 248 compare 0; #X obj 16 130 str compare This 32 is 32 the 32 end; #X floatatom 16 153 5 0 0 0 - - -; #X text 276 131 [str compare]: Set the reference string either with a [set( message to the first inlet or by sending a string to the second inlet.; #X msg 67 102 set This 32 is That 32 was; #X obj 263 62 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 -1; #X obj 263 81 str 32 the 32 end; #X floatatom 377 102 5 0 0 0 - - -; #X text 19 179 Output is 1 only if the input string and the reference string are identical.; #X obj 30 37 str This 32 is 32 the 32 end; #X obj 30 15 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 -1; #X msg 37 64 32 the 32 end; #X obj 45 103 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 -1; #X connect 0 0 1 0; #X connect 3 0 0 0; #X connect 4 0 5 0; #X connect 5 0 0 1; #X connect 5 1 6 0; #X connect 8 0 0 0; #X connect 9 0 8 0; #X connect 10 0 0 0; #X connect 11 0 0 0; #X restore 4 135 pd compare; #X text 84 134 compare two strings; #N canvas -4 -4 399 531 conversion 0; #X obj 19 16 bng 15 250 50 0 empty empty empty 17 7 0 10 -24198 -250685 -1; #X obj 19 80 print; #X obj 19 52 str to_symbol whichever 32 was it; #X floatatom 47 16 5 0 0 0 - - -; #X obj 22 152 str to_float 189.999; #X floatatom 22 181 15 0 0 0 - - -; #X obj 22 118 bng 15 250 50 0 empty empty empty 17 7 0 10 -24198 -250685 -1; #X floatatom 48 118 5 0 0 0 - - -; #X msg 90 16 whatever I thought32 at 32 the 10 32 time; #X msg 97 121 192.168.0.1; #X msg 110 89 all32were wolves; #X text 167 152 [str to_float] converts as much as possible of a string to a single float.; #X text 257 53 [str to_symbol] converts a string to a symbol as best it can.; #X obj 24 261 print; #X obj 24 236 str to_list; #X msg 24 212 tell 32 me 32 everything 10 13; #X text 112 235 [str to_list] outputs the string as a list of floats. ; #X msg 30 299 One 32 at 32 a 32 time 10 13; #X obj 30 347 print; #X obj 30 323 str drip trip 10 13; #X obj -13 269 bng 15 250 50 0 empty empty empty 17 7 0 10 -24198 -250685 -1; #X floatatom 80 259 5 0 0 0 - - -; #X floatatom 83 349 5 0 0 0 - - -; #X obj 158 345 bng 15 250 50 0 empty empty empty 17 7 0 10 -24198 -250685 -1; #X obj 180 345 tgl 15 0 empty empty empty 17 7 0 10 -24198 -250685 -1 0 1; #X floatatom 118 432 5 0 0 0 - - -; #X msg 29 377 The nth character of this string will be output as a float 10 13; #X obj 60 450 str nth 5; #X obj 22 422 bng 15 250 50 0 empty empty empty 17 7 0 10 -24198 -250685 -1; #X msg 98 410 set one; #X text 160 411 [set( quietly sets the string to be analyzed.; #X floatatom 118 490 5 0 0 0 - - -; #X text 161 489 string length; #X floatatom 60 491 5 0 0 0 - - -; #X text 128 451 [str nth] emits the nth character if it exists \, otherwise a bang will be emitted.; #X text 162 431 set n; #X text 202 322 [str drip] outputs the entire string one float at a time. Outlet 2 bangs when end is reached.; #X obj -12 289 until; #X connect 0 0 2 0; #X connect 2 0 1 0; #X connect 3 0 2 0; #X connect 4 0 5 0; #X connect 6 0 4 0; #X connect 7 0 4 0; #X connect 8 0 2 0; #X connect 9 0 4 0; #X connect 10 0 4 0; #X connect 14 0 13 0; #X connect 14 0 21 0; #X connect 15 0 14 0; #X connect 17 0 19 0; #X connect 19 0 18 0; #X connect 19 0 22 0; #X connect 19 1 23 0; #X connect 19 1 37 1; #X connect 20 0 37 0; #X connect 23 0 24 0; #X connect 25 0 27 1; #X connect 26 0 27 0; #X connect 27 0 33 0; #X connect 27 1 31 0; #X connect 28 0 27 0; #X connect 29 0 27 0; #X connect 37 0 19 0; #X restore 4 172 pd conversion; #X text 105 171 convert strings to other pd types; #X text 75 30 the basic string; #X text 69 65 split strings by character or position; mrpeach/str/str.c0000644000175000017500000006341212111234732014515 0ustar zmoelnigzmoelnig/* str.c MP 20061227 */ /* version 20070101 no more resizing memory */ #include #include #include #include #include "m_pd.h" /* support older Pd versions without sys_open(), sys_fopen(), sys_fclose() */ #if PD_MAJOR_VERSION == 0 && PD_MINOR_VERSION < 44 #define sys_open open #define sys_fopen fopen #define sys_fclose fclose #endif #ifndef PD_BLOBS /* PD_BLOBS is not defined in m_pd.h: No PD blob support: Make a dummy str object */ typedef struct _str { t_object x_obj; } t_str; static t_class *str_class; void str_setup(void); static void *str_new(t_symbol *s, int argc, t_atom *argv); static void *str_new(t_symbol *s, int argc, t_atom *argv) { t_str *x; x = (t_str *)pd_new(str_class); if (x == NULL) return (x); post("This str is a dummy str."); return (x); } void str_setup(void) { str_class = class_new(gensym("str"), (t_newmethod)str_new, 0, sizeof(t_str), 0, 0); } #else //ifndef PD_BLOBS /* Make a _real_ str object: */ typedef enum { string, nsplit, csplit, join, compare, add, nth, drip, to_list, to_symbol, to_float, n_functions } str_function; char *str_function_names[] = {"string", "nsplit", "csplit", "join", "compare", "add", "nth", "drip", "to_list", "to_symbol", "to_float"}; typedef struct _str { t_object x_obj; t_float x_nsplit; str_function x_function; t_blob x_buf; t_blob x_string_in1; t_blob x_string_in2; t_blob x_string_out1; t_blob x_string_out2; t_atom *x_atom_list; size_t x_atom_list_end; size_t x_buf_end; size_t x_string_in1_end;/* the current end of the string. Must be less than x_string_in1.s_length */ size_t x_string_in2_end; size_t x_string_out1_end; size_t x_string_out2_end; t_outlet *x_outlet_1; t_outlet *x_outlet_2; t_inlet *x_inlet_2; size_t x_atom_list_length; } t_str; //typedef struct _blob /* pointer to a blob */ //{ // unsigned long s_length; /* length of blob in bytes */ // unsigned char *s_data; /* pointer to 1st byte of blob */ //} t_blob; static t_class *str_class; void str_setup(void); static void *str_new(t_symbol *s, int argc, t_atom *argv); static void str_free(t_str *x); static void str_do_out1(t_str *x); static void str_do_out2(t_str *x); static void str_do_out3(t_str *x); static void str_do_string(t_str *x); static void str_bang(t_str *x); static void str_float(t_str *x, t_float f); static void str_symbol(t_str *x, t_symbol *s); static void str_list(t_str *x, t_symbol *s, int argc, t_atom *argv); static void str_anything(t_str *x, t_symbol *s, int argc, t_atom *argv); static void str_string(t_str *x, t_blob *st); static void str_set_string(t_blob *dest, t_blob *src, size_t *len); static void str_buf_to_string(t_str *x, t_blob *dest); static void str_float_to_buf(t_str *x, t_float f); static void str_str_to_buf (t_str *x, t_atom *a); static void str_symbol_to_buf(t_str *x, t_atom *a); static void str_list_to_buf(t_str *x, t_atom *a, int n); static void str_set(t_str *x, t_symbol *s, int argc, t_atom *argv); static void str_fread(t_str *x, t_symbol *s, int argc, t_atom *argv); static void str_fwrite(t_str *x, t_symbol *s, int argc, t_atom *argv); static void str_set_second(t_str *x, t_blob *st); static int str_equal(t_str *x); static void str_join(t_str *x); static void str_add(t_str *x); static void str_drip(t_str *x); static void str_nsplit(t_str *x); static void str_csplit(t_str *x); static t_symbol *str_to_symbol(t_str *x); static t_float str_to_float(t_str *x); static t_float str_to_float(t_str *x) {/* return a float from an ASCII representation of a float at the start of the string, or the first character. */ size_t limit; t_float f = 0.0; limit = (x->x_string_in1.s_length-1 >= x->x_string_in1_end)? x->x_string_in1_end: x->x_string_in1.s_length-1; if (limit == f) return f; x->x_string_in1.s_data[limit] = '\0'; if (sscanf((char *)x->x_string_in1.s_data, "%f", &f)) return f; return (f = x->x_string_in1.s_data[0]); } static t_symbol *str_to_symbol(t_str *x) { size_t limit; limit = (x->x_string_in1.s_length-1 >= x->x_string_in1_end)? x->x_string_in1_end: x->x_string_in1.s_length-1; x->x_string_in1.s_data[limit] = '\0'; return gensym((char *)x->x_string_in1.s_data); } static void str_csplit(t_str *x) /* split input string 1 into output strings 1 and 2 at first occurrence of any character in input string 2 */ { size_t i, j; /*post("str_csplit: x->x_string_in2_end is %lu", x->x_string_in2_end);*/ for (i = 0; i < x->x_string_in1_end; ++i) { for (j = 0; j < x->x_string_in2_end; ++j ) { if (x->x_string_in1.s_data[i] == x->x_string_in2.s_data[j]) { /* found the first character, see if there are more */ x->x_string_out1_end = x->x_buf_end = i; for (++i; i < x->x_string_in1_end; ++i) { for (j = 0; j < x->x_string_in2_end; ++j ) { if (x->x_string_in1.s_data[i] == x->x_string_in2.s_data[j]) break; } if(j == x->x_string_in2_end) goto found; /* 1st non-target character */ } } } x->x_buf.s_data[i] = x->x_string_in1.s_data[i]; /* this string goes to the left outlet*/ } found: str_buf_to_string(x, &x->x_string_out1); j = i; for (i = 0; j < x->x_string_in1_end; ++i, ++j) { x->x_buf.s_data[i] = x->x_string_in1.s_data[j]; /* this string goes to the right outlet */ } x->x_string_out2_end = x->x_buf_end = i; str_buf_to_string(x, &x->x_string_out2); return; } static void str_nsplit(t_str *x) /* split input string 1 into output strings 1 and 2 at index x_nsplit */ { size_t len, i, j; if (x->x_nsplit >= 0) { /* split from start of data, no more than size of largest possible string */ len = (unsigned long)x->x_nsplit; if (len > x->x_string_in1_end) len = x->x_string_in1_end; if (len > x->x_string_in1.s_length) len = x->x_string_in1.s_length; } else { /* split from the end */ len = (unsigned long)-x->x_nsplit; if (len > x->x_string_in1_end) len = 0L; else len = x->x_string_in1_end - len; } for (i = 0; i < len; ++i) x->x_buf.s_data[i] = x->x_string_in1.s_data[i]; x->x_string_out1_end = x->x_buf_end = len; str_buf_to_string(x, &x->x_string_out1); j = i; len = (len < x->x_string_in1_end)? x->x_string_in1_end - len: 0L; for (i = 0; i < len; ++i, ++j) x->x_buf.s_data[i] = x->x_string_in1.s_data[j]; x->x_string_out2_end = x->x_buf_end = len; str_buf_to_string(x, &x->x_string_out2); x->x_buf_end = 0L;/* finished with x_buf */ return; } static int str_equal(t_str *x) /* If input string 1 is exactly equal to input string 2, return 1, else 0 */ { size_t len, i, j; if ((len = x->x_string_in1_end) != x->x_string_in2_end) return 0; /* not the same length */ for (i = 0; i < len; ++i) if (x->x_string_in1.s_data[i] != x->x_string_in2.s_data[i]) return 0; return 1; } static void str_drip(t_str *x) /* Send next character of input string 1 out outlet 1, bang outlet 2 if end of string */ { size_t limit, i; unsigned char c; limit = (x->x_string_in1_end > x->x_string_in1.s_length)? x->x_string_in1.s_length: x->x_string_in1_end; if (x->x_nsplit >= limit) x->x_nsplit = 0L; if (limit != 0) {/* x->x_nsplit points to the current output character */ c = x->x_string_in1.s_data[(size_t)x->x_nsplit++]; outlet_float(x->x_outlet_1, (float)c); } if (x->x_nsplit >= limit) { /* bang at end of string */ x->x_nsplit = 0L; outlet_bang(x->x_outlet_2); } } static void str_add(t_str *x) /* Append input string 1 to input string 2, result to input_string 2. Clear input string 1 */ { size_t len, i, j; len = x->x_string_in1_end + x->x_string_in2_end; if (len > x->x_string_in2.s_length) len = x->x_string_in2.s_length; for (i = 0, j = x->x_string_in2_end; ((i < x->x_string_in1_end) && (j < len)); ++i, ++j) x->x_string_in2.s_data[j] = x->x_string_in1.s_data[i]; x->x_string_in2_end = j; x->x_string_in1_end = 0L; return; } static void str_join(t_str *x) /* Append input string 1 to input string 2 in output string 1 */ { size_t len, i, j; len = x->x_string_in1_end + x->x_string_in2_end; if (len > x->x_string_out1.s_length) len = x->x_string_out1.s_length; for (i = 0; i < x->x_string_in1_end; ++i) x->x_string_out1.s_data[i] = x->x_string_in1.s_data[i]; j = i; for (i = 0; i < x->x_string_in2_end; ++i, ++j) x->x_string_out1.s_data[j] = x->x_string_in2.s_data[i]; x->x_string_out1_end = len; return; } static void str_list_to_buf(t_str *x, t_atom *a, int n) /* Convert list of atoms to string in x->x_buf.s_data at offset x->x_buf_end, * increment x->x_buf_end by the number of chars added to x->x_buf.s_data*/ { int j; for (j = 0; j < n; ++j) { /* concatenate all arguments into a single string */ if (a[j].a_type == A_BLOB) { /* already a string */ str_str_to_buf(x, &a[j]); } else if (a[j].a_type == A_SYMBOL) { str_symbol_to_buf(x, &a[j]); } else if (a[j].a_type == A_FLOAT) { /* integers on [0..255] are taken directly, otherwise converted to strings */ str_float_to_buf(x, atom_getfloat(&a[j])); } } } static void str_str_to_buf (t_str *x, t_atom *a) /* Copy string to string in x->x_buf.s_data at offset x->x_buf_end, * increment x->x_buf_end by the number of chars added to x->x_buf.s_data*/ { size_t len, limit, i, j; char *cP = (char *)x->x_buf.s_data + x->x_buf_end; t_blob *str = atom_getblob(a); if (str == NULL) { post ("str_str_to_buf: null blob. Need a blob to point to...."); return; } limit = x->x_buf.s_length - x->x_buf_end; len = (str->s_length > limit)? limit: str->s_length; for (i = 0, j = x->x_buf_end; ((i < len)&&(j < x->x_buf.s_length)); ++i, ++j) x->x_buf.s_data[j] = str->s_data[i]; x->x_buf_end = j; } static void str_symbol_to_buf(t_str *x, t_atom *a) /* Convert symbol to string in x->x_buf.s_data at offset x->x_buf_end, * increment x->x_buf_end by the number of chars added to x->x_buf.s_data*/ { char *cP = (char *)x->x_buf.s_data + x->x_buf_end; atom_string(a, cP, x->x_buf.s_length-x->x_buf_end); x->x_buf_end += strlen(cP); } static void str_float_to_buf(t_str *x, t_float f) /* Convert float to characters in x->x_buf.s_data at offset x->x_buf_end, * increment x->x_buf_end by the number of chars added to x->x_buf.s_data. */ { long i; char j; if (x->x_buf_end > x->x_buf.s_length-20) /* what's the longest float? */ { error("str_float_to_buf: string too long."); return; } /* A float is either an ascii character number or a floating-point string */ i = (long)f; j = i & 0x0FF; if ((f == i)&&(i < 256)&&(i > -129)) /* is f an integer on [-128..255] */ x->x_buf.s_data[x->x_buf_end++] = j; else x->x_buf_end += sprintf((char *)&x->x_buf.s_data[x->x_buf_end], "%f", f); } static void str_buf_to_string(t_str *x, t_blob *dest) /* copy x->x_buf_end bytes of x->x_buf.s_data into dest */ { size_t i, limit; limit = (dest->s_length < x->x_buf.s_length)? dest->s_length: x->x_buf.s_length; if (limit > x->x_buf_end) limit = x->x_buf_end;/* normally the case */ // post("str_buf_to_string: limit %lu", limit); for (i = 0; i < limit; ++i) { dest->s_data[i] = x->x_buf.s_data[i]; } // post("str_buf_to_string: new length %lu", dest->s_length); return; } static void str_set_string(t_blob *dest, t_blob *src, size_t *len) /* Copy src into dest up to the shorter of dest->s_length and src->s_length * and set len to number of bytes copied */ { size_t i, limit; *len = (dest->s_length < src->s_length)? dest->s_length: src->s_length; for (i = 0; i < *len; ++i) dest->s_data[i] = src->s_data[i]; } static void str_fread(t_str *x, t_symbol *s, int argc, t_atom *argv) { /* a [file_read( message can have any type */ FILE *fp = NULL; size_t limit = 0L; int err = 0; x->x_buf_end = limit; post("str_fread: argc %d", argc); str_list_to_buf(x, argv, argc); limit = (x->x_buf_end >= x->x_buf.s_length)? x->x_buf.s_length-1: x->x_buf_end; x->x_buf.s_data[limit] = '\0'; /* make buf a c string */ if (0 == limit) { post ("str file_read: no path."); return; } errno = 0; fp = sys_fopen((char *)x->x_buf.s_data, "rb"); if(NULL == fp) { post ("str file_read: error opening file \"%s\": %d", x->x_buf.s_data, errno); return; } limit = x->x_string_in1.s_length; limit = fread(x->x_string_in1.s_data, 1L, limit, fp); if (0 != (err = ferror(fp))) { post ("str file_read: error reading file \"%s\": %d", x->x_buf.s_data, errno); x->x_string_in1_end = 0L; } else { x->x_string_in1_end = limit; post ("str file_read: read %lu bytes", limit); } sys_fclose(fp); return; } static void str_fwrite(t_str *x, t_symbol *s, int argc, t_atom *argv) { /* a [file_write( message can have any type */ FILE *fp = NULL; size_t limit = 0L; int err = 0; if (0 == x->x_string_in1_end) { post ("str file_write: nothing to write"); return; } x->x_buf_end = limit; post("str_fwrite: argc %d", argc); str_list_to_buf(x, argv, argc); limit = (x->x_buf_end >= x->x_buf.s_length)? x->x_buf.s_length: x->x_buf_end; if (0 == limit) { post ("str file_write: no path."); return; } errno = 0; fp = sys_fopen((char *)x->x_buf.s_data, "wb"); if(NULL == fp) { post ("str file_write: error opening file \"%s\": %d", x->x_buf.s_data, errno); return; } rewind(fp); limit = x->x_string_in1_end; limit = fwrite(x->x_string_in1.s_data, 1L, limit, fp); if (0 != (err = ferror(fp))) post ("str file_write: error writing file \"%s\": %d", x->x_buf.s_data, errno); else post ("str file_write: wrote %lu bytes to \"%s\"", limit, x->x_buf.s_data); sys_fclose(fp); return; } static void str_set(t_str *x, t_symbol *s, int argc, t_atom *argv) { /* a [set( message can have any type */ x->x_buf_end = 0L; /*post("str_set: argc %d", argc);*/ str_list_to_buf(x, argv, argc); if ((x->x_function == csplit) || (x->x_function == compare) || (x->x_function == join) || (x->x_function == add)) { x->x_string_in2_end = x->x_buf_end; str_buf_to_string(x, &x->x_string_in2); } else { x->x_string_in1_end = x->x_buf_end; str_buf_to_string(x, &x->x_string_in1); } if ((x->x_function == add)||(x->x_function == join)) outlet_float(x->x_outlet_2, x->x_string_in2_end); else if ((x->x_function == nth) || (x->x_function == string)) outlet_float(x->x_outlet_2, x->x_string_in1_end); } static void str_set_second(t_str *x, t_blob *st) { /* Inlet 2 accepts blobs only: Set string_in2 */ /*post("x=%p str_set_second(%p): %s %p %lu", x, &str_set_second, str_function_names[x->x_function], st, st->s_length);*/ str_set_string(&x->x_string_in2, st, &x->x_string_in2_end); if ((x->x_function == add)||(x->x_function == join)) outlet_float(x->x_outlet_2, x->x_string_in2_end); } static void str_string(t_str *x, t_blob *st) { /*post("x=%p str_string (%p) blob %p %lu", x, &str_string, st, st->s_length);*/ str_set_string(&x->x_string_in1, st, &x->x_string_in1_end); if (x->x_function == drip) x->x_nsplit = 0L; str_do_string(x); } static void str_anything(t_str *x, t_symbol *s, int argc, t_atom *argv) { // post("str_anything"); x->x_buf_end = sprintf((char *)x->x_buf.s_data, "%s", s->s_name); /* the selector is just another word... */ str_list_to_buf(x, argv, argc); x->x_string_in1_end = x->x_buf_end; str_buf_to_string(x, &x->x_string_in1); if (x->x_function == drip) x->x_nsplit = 0L; str_do_string(x); } static void str_list(t_str *x, t_symbol *s, int argc, t_atom *argv) { // post("str_list"); x->x_buf_end = 0L; str_list_to_buf(x, argv, argc); x->x_string_in1_end = x->x_buf_end; str_buf_to_string(x, &x->x_string_in1); if (x->x_function == drip) x->x_nsplit = 0L; str_do_string(x); } static void str_symbol(t_str *x, t_symbol *s) { // post("str_symbol"); x->x_buf_end = sprintf((char *)x->x_buf.s_data, "%s", s->s_name); x->x_string_in1_end = x->x_buf_end; str_buf_to_string(x, &x->x_string_in1); if (x->x_function == drip) x->x_nsplit = 0L; str_do_string(x); } static void str_float(t_str *x, t_float f) { x->x_buf_end = 0L; // post("str_float"); str_float_to_buf(x, f); x->x_string_in1_end = x->x_buf_end; str_buf_to_string(x, &x->x_string_in1); if (x->x_function == drip) x->x_nsplit = 0L; str_do_string(x); } static void str_bang(t_str *x) { // post("str_bang"); if((x->x_function == add) && (x->x_string_in2_end != 0))str_do_out3(x); else str_do_string(x); } /* Send string_in1 through outlet_1 */ static void str_do_out0(t_str *x) { /* The receiver needs to know the length of the actual data, not the size of our buffer */ /* so we temporarily replace s_length with string end. */ size_t true_length = x->x_string_in1.s_length; x->x_string_in1.s_length = x->x_string_in1_end; // post("str_do_out0: x->x_string_in1.s_data[0] = %d", x->x_string_in1.s_data[0]); outlet_blob(x->x_outlet_1, &x->x_string_in1); x->x_string_in1.s_length = true_length; } /* send string_out_1 through outlet_1 */ static void str_do_out1(t_str *x) { size_t true_length = x->x_string_out1.s_length; x->x_string_out1.s_length = x->x_string_out1_end; // post("str_do_out1: x->x_string_out1.s_data[0] = %d", x->x_string_out1.s_data[0]); outlet_blob(x->x_outlet_1, &x->x_string_out1); x->x_string_out1.s_length = true_length; } /* send string_out_2 through outlet_2 */ static void str_do_out2(t_str *x) { size_t true_length = x->x_string_out2.s_length; x->x_string_out2.s_length = x->x_string_out2_end; // post("str_do_out2: x->x_string_out2.s_data[0] = %d", x->x_string_out2.s_data[0]); outlet_blob(x->x_outlet_2, &x->x_string_out2); x->x_string_out2.s_length = true_length; } /* Send string_in2 through outlet_1 */ static void str_do_out3(t_str *x) { /* The receiver needs to know the length of the actual data, not the size of the buffer */ /* so we temporarily replace s_length with string end. */ size_t true_length = x->x_string_in2.s_length; x->x_string_in2.s_length = x->x_string_in2_end; outlet_blob(x->x_outlet_1, &x->x_string_in2); x->x_string_in2.s_length = true_length; } /* Perform the string function and emit the result */ static void str_do_string(t_str *x) { size_t i; float f; unsigned char c; switch (x->x_function) { case string: outlet_float(x->x_outlet_2, x->x_string_in1_end); if(x->x_string_in1_end != 0) str_do_out0(x); break; case join: str_join(x); outlet_float(x->x_outlet_2, x->x_string_out1_end); if(x->x_string_out1_end != 0) str_do_out1(x); break; case add: str_add(x);/* no output until banged */ outlet_float(x->x_outlet_2, x->x_string_in2_end); break; case drip: if (x->x_string_in1_end != 0) str_drip(x); break; case nth: outlet_float(x->x_outlet_2, x->x_string_in1_end); i = x->x_nsplit; /* output the nth character as a float, or bang if none. */ if ((x->x_string_in1_end != 0) && (i < x->x_string_in1_end)) outlet_float(x->x_outlet_1, x->x_string_in1.s_data[i]); else outlet_bang(x->x_outlet_1); break; case compare: outlet_float(x->x_outlet_1, str_equal(x)); break; case nsplit: str_nsplit(x); if(x->x_string_out2_end != 0) str_do_out2(x); if(x->x_string_out1_end != 0) str_do_out1(x); break; case csplit: str_csplit(x); if(x->x_string_out2_end != 0) str_do_out2(x); if(x->x_string_out1_end != 0) str_do_out1(x); break; case to_float: if (x->x_string_in1_end != 0) outlet_float(x->x_outlet_1, str_to_float(x)); break; case to_symbol: if (x->x_string_in1_end != 0) outlet_symbol(x->x_outlet_1, str_to_symbol(x)); break; case to_list: x->x_atom_list_end = (sizeof(t_atom))*(x->x_string_in1.s_length); if (x->x_atom_list_end > x->x_atom_list_length) x->x_atom_list_end = x->x_atom_list_length; for (i = 0; i < x->x_string_in1_end; ++i) { c = x->x_string_in1.s_data[i]; f = (float)c; SETFLOAT(&x->x_atom_list[i], f); } if (x->x_string_in1_end != 0) outlet_list(x->x_outlet_1, &s_list, x->x_string_in1_end, x->x_atom_list); break; } } static void str_free(t_str *x) { // post("str_free"); freebytes(x->x_string_out1.s_data, x->x_string_out1.s_length); freebytes(x->x_string_out2.s_data, x->x_string_out2.s_length); freebytes(x->x_string_in1.s_data, x->x_string_in1.s_length); freebytes(x->x_string_in2.s_data, x->x_string_in2.s_length); freebytes(x->x_buf.s_data, x->x_buf.s_length); freebytes(x->x_atom_list, x->x_atom_list_length); } static void *str_new(t_symbol *s, int argc, t_atom *argv) { t_str *x; unsigned long i, next; size_t cLen = MAXPDSTRING; unsigned int u; t_float f; x = (t_str *)pd_new(str_class); if (x == NULL) return (x); x->x_outlet_1 = outlet_new((t_object *)x, &s_anything); /* This is the only place we allocate string storage */ x->x_buf.s_data = getbytes(cLen); x->x_buf.s_length = cLen; x->x_buf_end = 0L; x->x_string_in1.s_data = getbytes(cLen); x->x_string_in1.s_length = cLen; x->x_string_in1_end = 0L;/* the current end of the string. Must be less than x_string_in1.s_length */ x->x_string_in2.s_data = getbytes(cLen); x->x_string_in2.s_length = cLen; x->x_string_in2_end = 0L; x->x_string_out1.s_data = getbytes(cLen); x->x_string_out1.s_length = cLen; x->x_string_out1_end = 0L; x->x_string_out2.s_data = getbytes(cLen); x->x_string_out2.s_length = cLen; x->x_string_out2_end = 0L; x->x_atom_list = getbytes(cLen); x->x_atom_list_length = cLen; x->x_atom_list_end = 0L; x->x_function = 0; /* default = string */ x->x_nsplit = 0L; next = 0; /* index of next argument */ if (argv[0].a_type == A_SYMBOL) { /* the first argument may be a selector */ atom_string(&argv[0], (char *)x->x_buf.s_data, MAXPDSTRING); for (i = 0; i < n_functions; ++i) { if (strcmp((char *)x->x_buf.s_data, str_function_names[i]) == 0) { x->x_function = i; // post("str_new: x_function is %s", str_function_names[x->x_function]); next = 1; if ((x->x_function == nsplit) || (x->x_function == csplit)) x->x_outlet_2 = outlet_new((t_object *)x, &s_anything); break; } } } if ((x->x_function == string)||(x->x_function == nth)||(x->x_function == add)||(x->x_function == join) || (x->x_function == drip)) x->x_outlet_2 = outlet_new((t_object *)x, &s_anything); /* an outlet for the string length or bang */ if ((x->x_function == nsplit)||(x->x_function == nth)) { /* single argument must be a float, add a float inlet */ x->x_nsplit = atom_getfloat(&argv[next]); x->x_inlet_2 = floatinlet_new((t_object *)x, &x->x_nsplit); } else if (x->x_function == csplit) { /* argument goes to string_in2 */ str_list_to_buf(x, &argv[next], argc-next); x->x_string_in2_end = x->x_buf_end; str_buf_to_string(x, &x->x_string_in2); } else if ((x->x_function == join)||(x->x_function == compare)||(x->x_function == add)) { /* argument goes to string_in2, add a string inlet */ x->x_inlet_2 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_blob, gensym("")); /* gensym("blob") */ str_list_to_buf(x, &argv[next], argc-next); x->x_string_in2_end = x->x_buf_end; str_buf_to_string(x, &x->x_string_in2); } else { /* argument goes to string_in1 */ str_list_to_buf(x, &argv[next], argc-next); x->x_string_in1_end = x->x_buf_end; str_buf_to_string(x, &x->x_string_in1); } return (x); } void str_setup(void) { str_class = class_new(gensym("str"), (t_newmethod)str_new, (t_method)str_free, sizeof(t_str), 0, A_GIMME, 0); class_addbang(str_class, str_bang); class_addfloat(str_class, str_float); class_addsymbol(str_class, str_symbol); class_addlist(str_class, str_list); class_addanything(str_class, str_anything); class_addblob(str_class, str_string); class_addmethod(str_class, (t_method)str_set, gensym("set"), A_GIMME, 0); class_addmethod(str_class, (t_method)str_fread, gensym("file_read"), A_GIMME, 0); class_addmethod(str_class, (t_method)str_fwrite, gensym("file_write"), A_GIMME, 0); class_addmethod(str_class, (t_method)str_set_second, gensym(""), A_BLOB, 0); } #endif // ifndef PD_BLOBS /* end str.c */ mrpeach/str/str-to-comport.pd0000644000175000017500000000204611026462102016771 0ustar zmoelnigzmoelnig#N canvas 574 0 450 300 10; #X obj 98 81 comport 0 9600; #X msg 98 30 Tell 32 me 32 again 10 13; #X obj 94 124 print a; #X obj 184 127 print b; #X msg 107 8 info; #X obj 30 111 float; #X obj 32 147 + 1; #X floatatom 6 132 5 0 0 0 - - -; #X obj 47 84 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 -1; #X msg 16 73 0; #X obj 96 54 str drip what????; #X obj 210 80 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 -1; #X obj 210 105 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1; #X obj 24 7 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1 ; #X obj 24 30 metro 10; #X obj 56 8 until; #X obj 55 -14 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 -1; #X connect 0 0 2 0; #X connect 0 1 3 0; #X connect 1 0 10 0; #X connect 4 0 0 0; #X connect 5 0 6 0; #X connect 5 0 7 0; #X connect 6 0 5 1; #X connect 8 0 5 0; #X connect 9 0 5 1; #X connect 10 0 0 0; #X connect 10 0 8 0; #X connect 10 1 11 0; #X connect 10 1 15 1; #X connect 11 0 12 0; #X connect 13 0 14 0; #X connect 14 0 10 0; #X connect 15 0 10 0; #X connect 16 0 15 0; mrpeach/slipenc/0000755000175000017500000000000013605444731014373 5ustar zmoelnigzmoelnigmrpeach/slipenc/slipenc-help.pd0000644000175000017500000000631011533764476017314 0ustar zmoelnigzmoelnig#N canvas 1 53 855 568 10; #X obj -98 77 packOSC; #X msg -98 52 /test 1 2 3 192 218 219 220 221 222; #X floatatom -72 99 5 0 0 0 - - -; #X text -99 3 [slipenc]: Encode a list of bytes using Serial Line Internet Protocol (SLIP); #X obj -71 246 print encoded; #X obj -71 163 print original; #X obj 8 381 print decoded; #X obj -98 141 t a a; #X obj -98 224 t a a; #X msg 124 60 /test/pi 3.14159; #X msg 233 60 /test/pi \$1; #X obj 233 40 expr 4*atan(1); #X obj 233 22 bng 15 250 50 0 empty empty empty 17 7 0 10 -4034 -86277 -1; #X obj -98 448 unpackOSC; #X obj -98 364 t a a; #X obj -98 469 routeOSC /test; #X obj -92 492 print test; #X obj -17 492 print other; #X obj -98 515 routeOSC /pi; #X floatatom -98 537 12 0 0 0 - - -; #X text -16 190 Encodes a list of bytes for transmission through a serial link using SLIP (RFC 1055). Useful for sending OSC through [comport]. ; #X msg -52 124 192 192 192 192 192; #X obj -104 322 cnv 15 60 30 empty empty empty 20 12 0 14 -4034 -66577 0; #X obj -103 186 cnv 15 60 30 empty empty empty 20 12 0 14 -4034 -66577 0; #X msg 27 174 1 2 3 4; #X text 340 77 The motivation behind SLIP is the need to determine the boundaries of a packet when it is received one byte at a time \, as with a serial channel. Bytes are integers between 0 and 255; #X msg 79 124 1 2 3 4 5 6; #X msg 160 124 1.1 2.22 3 4 5 6; #X text -37 98 single floats will pass through as single packets; #X msg -76 290 verbosity \$1; #X obj -76 271 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1; #X text 340 134 SLIP (RFC 1055) is a simple encoding that prefixes each packet with 192 \, and replaces 192s inside the packet with 219 followed by 220 Any 219 will be replaced with 219 and 221 The packet ends with 192; #X obj -71 383 list split 1; #X obj -71 404 == 47; #X obj -98 425 spigot; #X text -35 403 select OSC messages based on the leading '/'; #X obj -59 358 print valid; #X text 56 234 Note that the SLIP specification limits the maximum packet size to 1006...; #X obj -98 191 slipenc; #X obj -98 329 slipdec; #X text 31 530 Author: Martin Peach \, 2010/10/01; #X text 57 262 ...but a float argument to slipenc will set another maximum packet size; #N canvas 529 327 494 344 META 0; #X text 12 135 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; #X text 12 25 LICENSE GPL v2 or later; #X text 12 115 AUTHOR Martin Peach; #X text 12 5 KEYWORDS control conversion; #X text 12 95 OUTLET_0 anything; #X text 12 46 DESCRIPTION encode a list of bytes using Serial Line Internet Protocol (SLIP); #X text 12 75 INLET_0 float list; #X restore 693 530 pd META; #X connect 0 0 7 0; #X connect 1 0 0 0; #X connect 2 0 7 0; #X connect 7 0 38 0; #X connect 7 1 5 0; #X connect 8 0 39 0; #X connect 8 1 4 0; #X connect 9 0 0 0; #X connect 10 0 0 0; #X connect 11 0 10 0; #X connect 12 0 11 0; #X connect 13 0 15 0; #X connect 14 0 34 0; #X connect 14 1 6 0; #X connect 14 1 32 0; #X connect 15 0 16 0; #X connect 15 0 18 0; #X connect 15 1 17 0; #X connect 18 0 19 0; #X connect 21 0 7 0; #X connect 24 0 38 0; #X connect 26 0 7 0; #X connect 27 0 7 0; #X connect 29 0 39 0; #X connect 30 0 29 0; #X connect 32 0 33 0; #X connect 33 0 34 1; #X connect 34 0 13 0; #X connect 38 0 8 0; #X connect 39 0 14 0; #X connect 39 1 36 0; mrpeach/slipenc/slipenc.c0000644000175000017500000001472212430233214016165 0ustar zmoelnigzmoelnig/* slipenc.c 20100513 Martin Peach */ /* encode a list of bytes as SLIP */ /* * From RFC 1055: * PROTOCOL * * The SLIP protocol defines two special characters: SLIP_END and SLIP_ESC. SLIP_END is * octal 300 (decimal 192) and SLIP_ESC is octal 333 (decimal 219) not to be * confused with the ASCII ESCape character; for the purposes of this * discussion, SLIP_ESC will indicate the SLIP SLIP_ESC character. To send a * packet, a SLIP host simply starts sending the data in the packet. If * a data byte is the same code as SLIP_END character, a two byte sequence of * SLIP_ESC and octal 334 (decimal 220) is sent instead. If it the same as * an SLIP_ESC character, an two byte sequence of SLIP_ESC and octal 335 (decimal * 221) is sent instead. When the last byte in the packet has been * sent, an SLIP_END character is then transmitted. * * Phil Karn suggests a simple change to the algorithm, which is to * begin as well as end packets with an SLIP_END character. This will flush * any erroneous bytes which have been caused by line noise. In the * normal case, the receiver will simply see two back-to-back SLIP_END * characters, which will generate a bad IP packet. If the SLIP * implementation does not throw away the zero-length IP packet, the IP * implementation certainly will. If there was line noise, the data * received due to it will be discarded without affecting the following * packet. * * Because there is no 'standard' SLIP specification, there is no real * defined maximum packet size for SLIP. It is probably best to accept * the maximum packet size used by the Berkeley UNIX SLIP drivers: 1006 * bytes including the IP and transport protocol headers (not including * the framing characters). Therefore any new SLIP implementations * should be prepared to accept 1006 byte datagrams and should not send * more than 1006 bytes in a datagram. */ #include "m_pd.h" /* -------------------------- slipenc -------------------------- */ #ifndef _SLIPCODES /* SLIP special character codes */ #define SLIP_END 0300 /* indicates end of packet */ #define SLIP_ESC 0333 /* indicates byte stuffing */ #define SLIP_ESC_END 0334 /* SLIP_ESC SLIP_ESC_END means SLIP_END data byte */ #define SLIP_ESC_ESC 0335 /* SLIP_ESC SLIP_ESC_ESC means SLIP_ESC data byte */ #define MAX_SLIP 1006 /* maximum SLIP packet size */ #define _SLIPCODES #endif // _SLIPCODES static t_class *slipenc_class; typedef struct _slipenc { t_object x_obj; t_outlet *x_slipenc_out; t_atom *x_slip_buf; int x_slip_length; int x_slip_max_length; } t_slipenc; static void *slipenc_new(t_symbol *s, int argc, t_atom *argv); static void slipenc_list(t_slipenc *x, t_symbol *s, int ac, t_atom *av); static void slipenc_free(t_slipenc *x); void slipenc_setup(void); static void *slipenc_new(t_symbol *s, int argc, t_atom *argv) { int i, max_len; t_slipenc *x = (t_slipenc *)pd_new(slipenc_class); if (x == NULL) return x; x->x_slip_max_length = MAX_SLIP; // default unless float argument given for (i = 0; i < argc; ++i) { if (argv[i].a_type == A_FLOAT) { max_len = atom_getfloat(&argv[i]); if (max_len > 3) { x->x_slip_max_length = max_len; post("slipenc: maximum packet length is %d", x->x_slip_max_length); } else post("slipenc: maximum packet length must be greater than 3, using %d", x->x_slip_max_length); break; } } x->x_slip_buf = (t_atom *)getbytes(sizeof(t_atom)*x->x_slip_max_length); if(x->x_slip_buf == NULL) { error("slipenc: unable to allocate %lu bytes for x_slip_buf", (long)sizeof(t_atom)*x->x_slip_max_length); return NULL; } /* Initialize all the slip buf atoms to float type */ for (i = 0; i < x->x_slip_max_length; ++i) x->x_slip_buf[i].a_type = A_FLOAT; x->x_slipenc_out = outlet_new(&x->x_obj, &s_list); return (x); } static void slipenc_list(t_slipenc *x, t_symbol *s, int ac, t_atom *av) { /* SLIP encode a list of bytes */ float f; int i, c; i = 0; /* for each byte in the packet, send the appropriate character sequence */ while (i < ac) { x->x_slip_length = 0; /* send an initial SLIP_END character to flush out any data that may */ /* have accumulated in the receiver due to line noise */ x->x_slip_buf[x->x_slip_length++].a_w.w_float = SLIP_END; while((i < ac)&&(x->x_slip_length < (x->x_slip_max_length-2))) { /* check each atom for byteness */ f = atom_getfloat(&av[i++]); c = (((int)f) & 0x0FF); if (c != f) { /* abort, bad input character */ pd_error (x, "slipenc: input %f out of range [0..255]", f); return; } if(SLIP_END == c) { /* If it's the same code as a SLIP_END character, replace it with a */ /* special two-character code so as not to make the receiver think we sent SLIP_END */ x->x_slip_buf[x->x_slip_length++].a_w.w_float = SLIP_ESC; x->x_slip_buf[x->x_slip_length++].a_w.w_float = SLIP_ESC_END; } else if (SLIP_ESC == c) { /* If it's the same code as a SLIP_ESC character, replace it with a special two-character code */ /* so as not to make the receiver think we sent SLIP_ESC */ x->x_slip_buf[x->x_slip_length++].a_w.w_float = SLIP_ESC; x->x_slip_buf[x->x_slip_length++].a_w.w_float = SLIP_ESC_ESC; } else { /* Otherwise, pass the character */ x->x_slip_buf[x->x_slip_length++].a_w.w_float = c; } } /* Add the SLIP_END code to tell the receiver that the packet is complete */ x->x_slip_buf[x->x_slip_length++].a_w.w_float = SLIP_END; outlet_list(x->x_slipenc_out, &s_list, x->x_slip_length, x->x_slip_buf); } } static void slipenc_free(t_slipenc *x) { if (x->x_slip_buf != NULL) freebytes((void *)x->x_slip_buf, sizeof(t_atom)*x->x_slip_max_length); } void slipenc_setup(void) { slipenc_class = class_new(gensym("slipenc"), (t_newmethod)slipenc_new, (t_method)slipenc_free, sizeof(t_slipenc), 0, A_GIMME, 0); class_addlist(slipenc_class, slipenc_list); } /* fin slipenc.c*/ mrpeach/net/0000755000175000017500000000000013605444730013523 5ustar zmoelnigzmoelnigmrpeach/net/tcpreceive-help.pd0000644000175000017500000000212211533624223017117 0ustar zmoelnigzmoelnig#N canvas 1 53 478 294 12; #X floatatom 206 144 3 0 0 0 - - -; #X floatatom 233 144 3 0 0 0 - - -; #X floatatom 260 144 3 0 0 0 - - -; #X floatatom 287 144 3 0 0 0 - - -; #X text 163 143 from; #X obj 155 185 print message; #X obj 155 57 tcpreceive 9997; #X floatatom 257 96 5 0 0 0 - - -; #X text 303 94 connections; #X text 32 16 tcpreceive receives bytes over a tcp connection.; #X floatatom 315 144 5 0 0 0 - - -; #X obj 206 117 unpack 0 0 0 0 0; #X text 265 235 Martin Peach 2008/11/05; #N canvas 529 268 494 344 META 0; #X text 12 145 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; #X text 12 125 AUTHOR Martin Peach; #X text 12 25 LICENSE GPL v2 or later; #X text 12 5 KEYWORDS control network; #X text 12 45 DESCRIPTION tcpreceive receives bytes over a tcp connection ; #X text 12 65 OUTLET_0 anything; #X text 12 85 OUTLET_1 list; #X text 12 105 OUTLET_2 float; #X restore 421 264 pd META; #X connect 6 0 5 0; #X connect 6 1 11 0; #X connect 6 2 7 0; #X connect 11 0 0 0; #X connect 11 1 1 0; #X connect 11 2 2 0; #X connect 11 3 3 0; #X connect 11 4 10 0; mrpeach/net/udpsend.c0000644000175000017500000005104413230146704015327 0ustar zmoelnigzmoelnig/* udpsend.c 20060424. Martin Peach did it based on x_net.c. x_net.c header follows: */ /* Copyright (c) 1997-1999 Miller Puckette. * For information on usage and redistribution, and for a DISCLAIMER OF ALL * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ /* network */ #include "m_pd.h" #include #include #ifdef _WIN32 #include #include #include // for interface addresses #else #include #include #include #include #include #include // for SIOCGIFCONF #include // for SIOCGIFCONF #include #include #include #endif // _WIN32 #ifdef __APPLE__ #include // for getifaddrs #endif // __APPLE__ /* support older Pd versions without sys_open(), sys_fopen(), sys_fclose() */ #if PD_MAJOR_VERSION == 0 && PD_MINOR_VERSION < 44 #define sys_open open #define sys_fopen fopen #define sys_fclose fclose #endif static t_class *udpsend_class; typedef struct _udpsend { t_object x_obj; int x_fd; /* the socket */ unsigned int x_multicast_loop_state; unsigned int x_multicast_ttl; /* time to live for multicast */ t_outlet *x_connectout; t_outlet *x_statusout; } t_udpsend; void udpsend_setup(void); static void udpsend_free(t_udpsend *x); static void udpsend_send(t_udpsend *x, t_symbol *s, int argc, t_atom *argv); static void udpsend_disconnect(t_udpsend *x); static void udpsend_connect(t_udpsend *x, t_symbol *hostname, t_floatarg fportno); static void udpsend_set_multicast_loopback(t_udpsend *x, t_floatarg loop_state); static void udpsend_set_multicast_ttl(t_udpsend *x, t_floatarg ttl_hops); static void udpsend_set_multicast_interface (t_udpsend *x, t_symbol *s, int argc, t_atom *argv); static void udpsend_sock_err(t_udpsend *x, char *err_string); static void *udpsend_new(void); static void *udpsend_new(void) { t_udpsend *x = (t_udpsend *)pd_new(udpsend_class); x->x_connectout = outlet_new(&x->x_obj, &s_float); /* connection state */ x->x_statusout = outlet_new(&x->x_obj, &s_anything);/* last outlet for everything else */ x->x_fd = -1; return (x); } static void udpsend_connect(t_udpsend *x, t_symbol *hostname, t_floatarg fportno) { struct sockaddr_in server, addr; socklen_t addrlen = sizeof (addr); struct hostent *hp; int sockfd; int portno = fportno; int broadcast = 1;/* nonzero is true */ unsigned char multicast_loop_state; unsigned char multicast_ttl; unsigned int size; uint32_t ourAddr; // address of our interface int ourPort; // port nunber of our interface t_atom output_atom[5]; if (x->x_fd >= 0) { pd_error(x, "udpsend: already connected"); return; } /* create a socket */ sockfd = socket(AF_INET, SOCK_DGRAM, 0); #ifdef DEBUG fprintf(stderr, "udpsend_connect: send socket %d\n", sockfd); #endif if (sockfd < 0) { udpsend_sock_err(x, "udpsend socket"); return; } /* Based on zmoelnig's patch 2221504: Enable sending of broadcast messages (if hostname is a broadcast address)*/ #ifdef SO_BROADCAST if( 0 != setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, (const void *)&broadcast, sizeof(broadcast))) { udpsend_sock_err(x, "couldn't switch to broadcast mode"); } #endif /* SO_BROADCAST */ /* connect socket using hostname provided in command line */ server.sin_family = AF_INET; hp = gethostbyname(hostname->s_name); if (hp == 0) { post("udpsend: bad host?\n"); return; } memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length); if (0xE0000000 == (ntohl(server.sin_addr.s_addr) & 0xF0000000)) post ("udpsend: connecting to a multicast address"); size = sizeof(multicast_loop_state); getsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_LOOP, &multicast_loop_state, &size); size = sizeof(multicast_ttl); getsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL, &multicast_ttl, &size); x->x_multicast_loop_state = multicast_loop_state; x->x_multicast_ttl = multicast_ttl; /* assign client port number */ server.sin_port = htons((u_short)portno); post("udpsend: connecting to port %d", portno); /* try to connect. */ if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0) { udpsend_sock_err(x, "udpsend connect"); #ifdef _WIN32 closesocket(sockfd); #else close(sockfd); #endif return; } x->x_fd = sockfd; /* Find our address */ if (getsockname(sockfd, (struct sockaddr *)&addr, (socklen_t *)&addrlen)) udpsend_sock_err(x, "problem getting our socket address and port"); else { /* output the address this socket is bound to */ //printf("addrlen %u\n", addrlen); //printf("port %u\n", addr.sin_port); //printf("IP address %s\n", inet_ntoa(addr.sin_addr)); ourAddr = ntohl(addr.sin_addr.s_addr); ourPort = ntohs(addr.sin_port); SETFLOAT(&output_atom[0], (ourAddr & 0xFF000000)>>24); // address of our interface in bytes SETFLOAT(&output_atom[1], (ourAddr & 0x0FF0000)>>16); SETFLOAT(&output_atom[2], (ourAddr & 0x0FF00)>>8); SETFLOAT(&output_atom[3], (ourAddr & 0x0FF)); SETFLOAT(&output_atom[4], ourPort); // port nunber of our interface outlet_anything( x->x_statusout, gensym("ourIP"), 5, output_atom); } outlet_float(x->x_connectout, 1); } static void udpsend_set_multicast_loopback(t_udpsend *x, t_floatarg loop_state) { int sockfd = x->x_fd; unsigned char multicast_loop_state = loop_state; unsigned int size; if (x->x_fd < 0) { pd_error(x, "udpsend_set_multicast_loopback: not connected"); return; } if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_LOOP, &multicast_loop_state, sizeof(multicast_loop_state)) < 0) udpsend_sock_err(x, "udpsend setsockopt IP_MULTICAST_LOOP"); getsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_LOOP, &multicast_loop_state, &size); x->x_multicast_loop_state = multicast_loop_state; } static void udpsend_set_multicast_ttl(t_udpsend *x, t_floatarg ttl_hops) { int sockfd = x->x_fd; unsigned char multicast_ttl = ttl_hops; unsigned int size; if (x->x_fd < 0) { pd_error(x, "udpsend_set_multicast_ttl: not connected"); return; } if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL, &multicast_ttl, sizeof(multicast_ttl)) < 0) udpsend_sock_err(x, "udpsend setsockopt IP_MULTICAST_TTL"); getsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL, &multicast_ttl, &size); x->x_multicast_ttl = multicast_ttl; } static void udpsend_set_multicast_interface (t_udpsend *x, t_symbol *s, int argc, t_atom *argv) { #ifdef _WIN32 int i, n_ifaces = 32; PMIB_IPADDRTABLE pIPAddrTable; DWORD dwSize; IN_ADDR IPAddr; int if_index = -1; int found = 0; t_symbol *interfacename = gensym("none"); struct hostent *hp = 0; struct sockaddr_in server; if (x->x_fd < 0) { pd_error(x, "udpsend_set_multicast_interface: not connected"); return; } switch (argv[0].a_type) { case A_FLOAT: if_index = (int)atom_getfloat(&argv[0]); break; case A_SYMBOL: interfacename = atom_getsymbol(&argv[0]); break; default: pd_error(x, "udpsend_set_multicast_interface: argument not float or symbol"); return; } if (if_index == -1) { hp = gethostbyname(interfacename->s_name); // if interface is a dotted or named IP address (192.168.0.88) } if (hp != 0) memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length); else // maybe interface is its index (1) (names aren't available in _WIN32) { /* get the list of interfaces, IPv4 only */ dwSize = sizeof(MIB_IPADDRTABLE)*n_ifaces; if ((pIPAddrTable = (MIB_IPADDRTABLE *) getbytes(dwSize)) == NULL) { post("udpsend: unable to allocate %lu bytes for GetIpAddrTable", dwSize); return; } if (GetIpAddrTable(pIPAddrTable, &dwSize, 0)) { udpsend_sock_err(x, "udpsend_set_multicast_interface: GetIpAddrTable"); return; } n_ifaces = pIPAddrTable->dwNumEntries; post("udpsend: %d interface%s available:", n_ifaces, (n_ifaces == 1)?"":"s"); for (i = 0; i < n_ifaces; i++) { IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwAddr; post("[%d]: %s", pIPAddrTable->table[i].dwIndex, inet_ntoa(IPAddr)); if (pIPAddrTable->table[i].dwIndex == if_index) { server.sin_addr = IPAddr; found = 1; } } if (pIPAddrTable) { freebytes(pIPAddrTable, dwSize); pIPAddrTable = NULL; } if (! found) { post("udpsend_set_multicast_interface: bad host name? (%s)\n", interfacename->s_name); return; } } if (setsockopt(x->x_fd, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&server.sin_addr, sizeof(struct in_addr)) == SOCKET_ERROR) udpsend_sock_err(x, "udpsend setsockopt IP_MULTICAST_IF"); else post("udpsend multicast interface is %s", inet_ntoa(server.sin_addr)); #elif defined __APPLE__ int if_index = -1; int found = 0; t_symbol *interfacename = gensym("none"); struct ifaddrs *ifap; int i = 0; int n_ifaces = 0; struct hostent *hp = 0; struct sockaddr_in server; struct sockaddr *sa; char ifname[IFNAMSIZ]; /* longest possible interface name */ if (x->x_fd < 0) { pd_error(x, "udpsend_set_multicast_interface: not connected"); return; } switch (argv[0].a_type) { case A_FLOAT: if_index = (int)atom_getfloat(&argv[0]); break; case A_SYMBOL: interfacename = atom_getsymbol(&argv[0]); break; default: pd_error(x, "udpsend_set_multicast_interface: argument not float or symbol"); return; } if (if_index == -1) { hp = gethostbyname(interfacename->s_name); // if interface is a dotted or named IP address (192.168.0.88) } if (hp != 0) memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length); else // maybe interface is its name (eth0) or index (1) { // scan all the interfaces to get the IP address of interface if (getifaddrs(&ifap)) udpsend_sock_err(x, "udpsend getifaddrs"); i = found = n_ifaces = 0; while (NULL != ifap) { sa = ifap->ifa_addr; if (AF_INET == sa->sa_family) { ++n_ifaces; strncpy (ifname, ifap->ifa_name, IFNAMSIZ); post("[%d]: %s: %s", i, ifname, inet_ntoa(((struct sockaddr_in *)sa)->sin_addr)); if((i == if_index) || ((if_index == -1) && (!strncmp(interfacename->s_name, ifname, IFNAMSIZ)))) { // either the index or the name match server.sin_addr = ((struct sockaddr_in *)sa)->sin_addr; found = 1; } } i++; ifap = ifap->ifa_next; // next record or NULL } freeifaddrs(ifap); post ("udpsend: %d interfaces", n_ifaces); if (!found) return; } if (setsockopt(x->x_fd, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&server.sin_addr, sizeof(struct in_addr))) udpsend_sock_err(x, "udpsend setsockopt IP_MULTICAST_IF"); else post("udpsend multicast interface is %s", inet_ntoa(server.sin_addr)); return; #else // __linux__ struct sockaddr_in server; struct sockaddr *sa; struct hostent *hp = 0; struct ifconf ifc; int n_ifaces = 32, i, origbuflen, found = 0; char ifname[IFNAMSIZ]; /* longest possible interface name */ t_symbol *interface = gensym("none"); int if_index = -1; if (x->x_fd < 0) { pd_error(x, "udpsend_set_multicast_interface: not connected"); return; } switch (argv[0].a_type) { case A_FLOAT: if_index = (int)atom_getfloat(&argv[0]); break; case A_SYMBOL: interface = atom_getsymbol(&argv[0]); break; default: pd_error(x, "udpsend_set_multicast_interface: argument not float or symbol"); return; } if (if_index == -1) { hp = gethostbyname(interface->s_name); // if interface is a dotted or named IP address (192.168.0.88) } if (hp != 0) memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length); else // maybe interface is its name (eth0) or index (1) { // scan all the interfaces to get the IP address of interface // find the number of interfaces origbuflen = n_ifaces * sizeof (struct ifreq);// save maximum length for free() ifc.ifc_len = origbuflen; // SIOCGIFCONF changes it to valid length ifc.ifc_buf = (char*)getzbytes(origbuflen); if (ifc.ifc_buf != NULL) { // if (ioctl(x->x_fd, SIOCGIFCONF, &ifc) < 0) // get list of interfaces udpsend_sock_err(x, "udpsend_set_multicast_interface: getting list of interfaces"); else { n_ifaces = ifc.ifc_len/sizeof(struct ifreq); post("udpsend: %d interface%s available:", n_ifaces, (n_ifaces == 1)?"":"s"); for(i = 0; i < n_ifaces; i++) { sa = (struct sockaddr *)&(ifc.ifc_req[i].ifr_addr); strncpy (ifname, ifc.ifc_req[i].ifr_name, IFNAMSIZ); post("[%d]: %s: %s", i, ifname, inet_ntoa(((struct sockaddr_in *)sa)->sin_addr)); if ( (i == if_index) || ((if_index == -1) && (!strncmp(interface->s_name, ifname, IFNAMSIZ))) ) { server.sin_addr = ((struct sockaddr_in *)sa)->sin_addr; found = 1; } } } } freebytes(ifc.ifc_buf, origbuflen); if (! found) { post("udpsend_set_multicast_interface: bad host name? (%s)\n", interface->s_name); return; } } if (setsockopt(x->x_fd, IPPROTO_IP, IP_MULTICAST_IF, &server.sin_addr, sizeof(struct in_addr)) < 0) udpsend_sock_err(x, "udpsend_set_multicast_interface: setsockopt"); else post("udpsend multicast interface is %s", inet_ntoa(server.sin_addr)); #endif // _WIN32 } static void udpsend_sock_err(t_udpsend *x, char *err_string) { /* prints the last error from errno or WSAGetLastError() */ #ifdef _WIN32 void *lpMsgBuf; unsigned long errornumber = WSAGetLastError(); int len = 0, i; char *cp; if (len = FormatMessageA((FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS) , NULL, errornumber, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&lpMsgBuf, 0, NULL)) { cp = (char *)lpMsgBuf; for(i = 0; i < len; ++i) { if (cp[i] < 0x20) { /* end string at first weird character */ cp[i] = 0; break; } } pd_error(x, "%s: %s (%d)", err_string, lpMsgBuf, errornumber); LocalFree(lpMsgBuf); } #else pd_error(x, "%s: %s (%d)", err_string, strerror(errno), errno); #endif } static void udpsend_disconnect(t_udpsend *x) { if (x->x_fd >= 0) { #ifdef _WIN32 closesocket(x->x_fd); #else close(x->x_fd); #endif x->x_fd = -1; outlet_float(x->x_connectout, 0); } } static void udpsend_send(t_udpsend *x, t_symbol *s, int argc, t_atom *argv) { #define BYTE_BUF_LEN 65536 // arbitrary maximum similar to max IP packet size static char byte_buf[BYTE_BUF_LEN]; int d; int i, j; unsigned char c; float f, e; char *bp; int length, sent; int result; static double lastwarntime; static double pleasewarn; double timebefore; double timeafter; int late; char fpath[FILENAME_MAX]; FILE *fptr; #ifdef DEBUG post("s: %s", s->s_name); post("argc: %d", argc); #endif for (i = j = 0; i < argc; ++i) { if (argv[i].a_type == A_FLOAT) { f = argv[i].a_w.w_float; d = (int)f; e = f - d; if (e != 0) { pd_error(x, "udpsend_send: item %d (%f) is not an integer", i, f); return; } c = (unsigned char)d; if (c != d) { pd_error(x, "udpsend_send: item %d (%f) is not between 0 and 255", i, f); return; } #ifdef DEBUG post("udpsend_send: argv[%d]: %d", i, c); #endif byte_buf[j++] = c; } else if (argv[i].a_type == A_SYMBOL) { atom_string(&argv[i], fpath, FILENAME_MAX); #ifdef DEBUG post ("udpsend fname: %s", fpath); #endif fptr = sys_fopen(fpath, "rb"); if (fptr == NULL) { post("udpsend: unable to open \"%s\"", fpath); return; } rewind(fptr); #ifdef DEBUG post("udpsend: d is %d", d); #endif while ((d = fgetc(fptr)) != EOF) { byte_buf[j++] = (char)(d & 0x0FF); #ifdef DEBUG post("udpsend: byte_buf[%d] = %d", j-1, byte_buf[j-1]); #endif if (j >= BYTE_BUF_LEN) { post ("udpsend: file too long, truncating at %lu", BYTE_BUF_LEN); break; } } sys_fclose(fptr); fptr = NULL; post("udpsend: read \"%s\" length %d byte%s", fpath, j, ((d==1)?"":"s")); } else { pd_error(x, "udpsend_send: item %d is not a float or a file name", i); return; } } length = j; if ((x->x_fd >= 0) && (length > 0)) { for (bp = byte_buf, sent = 0; sent < length;) { timebefore = sys_getrealtime(); result = send(x->x_fd, byte_buf, length-sent, 0); timeafter = sys_getrealtime(); late = (timeafter - timebefore > 0.005); if (late || pleasewarn) { if (timeafter > lastwarntime + 2) { post("udpsend blocked %d msec", (int)(1000 * ((timeafter - timebefore) + pleasewarn))); pleasewarn = 0; lastwarntime = timeafter; } else if (late) pleasewarn += timeafter - timebefore; } if (result <= 0) { udpsend_sock_err(x, "udpsend send"); udpsend_disconnect(x); break; } else { sent += result; bp += result; } } } else pd_error(x, "udpsend: not connected"); } static void udpsend_free(t_udpsend *x) { udpsend_disconnect(x); } void udpsend_setup(void) { udpsend_class = class_new(gensym("udpsend"), (t_newmethod)udpsend_new, (t_method)udpsend_free, sizeof(t_udpsend), 0, 0); class_addmethod(udpsend_class, (t_method)udpsend_connect, gensym("connect"), A_SYMBOL, A_FLOAT, 0); class_addmethod(udpsend_class, (t_method)udpsend_set_multicast_ttl, gensym("multicast_ttl"), A_DEFFLOAT, 0); class_addmethod(udpsend_class, (t_method)udpsend_set_multicast_loopback, gensym("multicast_loopback"), A_DEFFLOAT, 0); class_addmethod(udpsend_class, (t_method)udpsend_set_multicast_interface, gensym("multicast_interface"), A_GIMME, 0); class_addmethod(udpsend_class, (t_method)udpsend_disconnect, gensym("disconnect"), 0); class_addmethod(udpsend_class, (t_method)udpsend_send, gensym("send"), A_GIMME, 0); class_addlist(udpsend_class, (t_method)udpsend_send); } /* end udpsend.c*/ mrpeach/net/LICENSE.txt0000644000175000017500000010437411650353267015361 0ustar zmoelnigzmoelnig GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . mrpeach/net/udpsndrcv.c0000644000175000017500000002763412303446646015715 0ustar zmoelnigzmoelnig/* udpsndrcv.c 20140221. Dennis Engdahl did it based on: 20060424. Martin Peach did it based on x_net.c. x_net.c header follows: */ /* Copyright (c) 1997-1999 Miller Puckette. * For information on usage and redistribution, and for a DISCLAIMER OF ALL * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ /* network */ #include "m_pd.h" #include "s_stuff.h" #include #include #ifdef _WIN32 #include #include #else #include #include #include #include #include #include // for SIOCGIFCONF #include // for SIOCGIFCONF #include #include #include #endif // _WIN32 /* support older Pd versions without sys_open(), sys_fopen(), sys_fclose() */ #if PD_MAJOR_VERSION == 0 && PD_MINOR_VERSION < 44 #define sys_open open #define sys_fopen fopen #define sys_fclose fclose #endif static t_class *udpsndrcv_class; #define MAX_UDP_RECEIVE 65536L // longer than data in maximum UDP packet typedef struct _udpsndrcv { t_object x_obj; int x_fd; /* the socket */ t_outlet *x_msgout; t_outlet *x_addrout; long x_total_received; t_atom x_addrbytes[5]; t_atom x_msgoutbuf[MAX_UDP_RECEIVE]; char x_msginbuf[MAX_UDP_RECEIVE]; char x_addr_name[256]; // a multicast address or 0 } t_udpsndrcv; void udpsndrcv_setup(void); static void udpsndrcv_free(t_udpsndrcv *x); static void udpsndrcv_send(t_udpsndrcv *x, t_symbol *s, int argc, t_atom *argv); static void udpsndrcv_disconnect(t_udpsndrcv *x); static void udpsndrcv_connect(t_udpsndrcv *x, t_symbol *hostname, t_floatarg fportno, t_floatarg ffromport); static void udpsndrcv_sock_err(t_udpsndrcv *x, char *err_string); static void *udpsndrcv_new(void); static void udpsndrcv_sock_err(t_udpsndrcv *x, char *err_string); static void udpsndrcv_status(t_udpsndrcv *x); static void udpsndrcv_read(t_udpsndrcv *x, int sockfd); static void *udpsndrcv_new(void) { t_udpsndrcv *x; int i; x = (t_udpsndrcv *)pd_new(udpsndrcv_class); /* if something fails we return 0 instead of x. Is this OK? */ if (NULL == x) return x; x->x_addr_name[0] = '\0'; /* convert the bytes in the buffer to floats in a list */ for (i = 0; i < MAX_UDP_RECEIVE; ++i) { x->x_msgoutbuf[i].a_type = A_FLOAT; x->x_msgoutbuf[i].a_w.w_float = 0; } for (i = 0; i < 5; ++i) { x->x_addrbytes[i].a_type = A_FLOAT; x->x_addrbytes[i].a_w.w_float = 0; } outlet_new(&x->x_obj, &s_float); x->x_msgout = outlet_new(&x->x_obj, &s_anything); x->x_addrout = outlet_new(&x->x_obj, &s_anything); x->x_fd = -1; return (x); } static void udpsndrcv_read(t_udpsndrcv *x, int sockfd) { int i, read = 0; struct sockaddr_in from; socklen_t fromlen = sizeof(from); t_atom output_atom; long addr; unsigned short port; read = recvfrom(sockfd, x->x_msginbuf, MAX_UDP_RECEIVE, 0, (struct sockaddr *)&from, &fromlen); #ifdef DEBUG post("udpsndrcv_read: read %lu x->x_fd = %d", read, x->x_fd); #endif /* get the sender's ip */ addr = ntohl(from.sin_addr.s_addr); port = ntohs(from.sin_port); x->x_addrbytes[0].a_w.w_float = (addr & 0xFF000000)>>24; x->x_addrbytes[1].a_w.w_float = (addr & 0x0FF0000)>>16; x->x_addrbytes[2].a_w.w_float = (addr & 0x0FF00)>>8; x->x_addrbytes[3].a_w.w_float = (addr & 0x0FF); x->x_addrbytes[4].a_w.w_float = port; outlet_anything(x->x_addrout, gensym("from"), 5L, x->x_addrbytes); if (read < 0) { udpsndrcv_sock_err(x, "udpsndrcv_read"); sys_closesocket(x->x_fd); return; } if (read > 0) { for (i = 0; i < read; ++i) { /* convert the bytes in the buffer to floats in a list */ x->x_msgoutbuf[i].a_w.w_float = (float)(unsigned char)x->x_msginbuf[i]; } x->x_total_received += read; SETFLOAT(&output_atom, read); outlet_anything(x->x_addrout, gensym("received"), 1, &output_atom); /* send the list out the outlet */ if (read > 1) outlet_list(x->x_msgout, &s_list, read, x->x_msgoutbuf); else outlet_float(x->x_msgout, x->x_msgoutbuf[0].a_w.w_float); } } static void udpsndrcv_connect(t_udpsndrcv *x, t_symbol *hostname, t_floatarg fportno, t_floatarg ffromport) { struct sockaddr_in server; struct hostent *hp; int sockfd; int portno = fportno; int fromport = ffromport; if (x->x_fd >= 0) { pd_error(x, "udpsndrcv: already connected"); return; } /* create a socket */ sockfd = socket(AF_INET, SOCK_DGRAM, 0); #ifdef DEBUG post("udpsndrcv_connect: socket %d port %d fromport %d", sockfd, portno, fromport); #endif if (sockfd < 0) { udpsndrcv_sock_err(x, "udpsndrcv socket"); return; } /* assign client port number */ if (fromport == 0) fromport = portno; server.sin_family = AF_INET; server.sin_port = htons((u_short)fromport); /* bind the socket to INADDR_ANY and port as specified */ server.sin_addr.s_addr = INADDR_ANY; if (bind(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0) { udpsndrcv_sock_err(x, "udpsndrcv: bind"); sys_closesocket(sockfd); return; } /* connect socket using hostname provided in command line */ hp = gethostbyname(hostname->s_name); if (hp == 0) { post("udpsndrcv: bad host?\n"); return; } memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length); server.sin_port = htons((u_short)portno); post("udpsndrcv: connecting to port %d from %d", portno, fromport); /* try to connect. */ if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0) { udpsndrcv_sock_err(x, "udpsndrcv connect"); #ifdef _WIN32 closesocket(sockfd); #else close(sockfd); #endif return; } x->x_fd = sockfd; x->x_total_received = 0L; sys_addpollfn(x->x_fd, (t_fdpollfn)udpsndrcv_read, x); outlet_float(x->x_obj.ob_outlet, 1); return; } static void udpsndrcv_sock_err(t_udpsndrcv *x, char *err_string) { /* prints the last error from errno or WSAGetLastError() */ #ifdef _WIN32 void *lpMsgBuf; unsigned long errornumber = WSAGetLastError(); int len = 0, i; char *cp; if ((len = FormatMessageA((FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS), NULL, errornumber, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&lpMsgBuf, 0, NULL))) { cp = (char *)lpMsgBuf; for(i = 0; i < len; ++i) { if (cp[i] < 0x20) { /* end string at first weird character */ cp[i] = 0; break; } } pd_error(x, "%s: %s (%ld)", err_string, (char *)lpMsgBuf, errornumber); LocalFree(lpMsgBuf); } #else pd_error(x, "%s: %s (%d)", err_string, strerror(errno), errno); #endif } static void udpsndrcv_status(t_udpsndrcv *x) { t_atom output_atom; SETFLOAT(&output_atom, x->x_total_received); outlet_anything(x->x_addrout, gensym("total"), 1, &output_atom); } static void udpsndrcv_disconnect(t_udpsndrcv *x) { if (x->x_fd >= 0) { post("udpsndrcv: disconnecting."); #ifdef _WIN32 closesocket(x->x_fd); #else close(x->x_fd); #endif sys_rmpollfn(x->x_fd); x->x_fd = -1; outlet_float(x->x_obj.ob_outlet, 0); } } static void udpsndrcv_send(t_udpsndrcv *x, t_symbol *s, int argc, t_atom *argv) { #define BYTE_BUF_LEN 65536 // arbitrary maximum similar to max IP packet size static char byte_buf[BYTE_BUF_LEN]; int d; int i, j; unsigned char c; float f, e; char *bp; int length, sent; int result; static double lastwarntime; static double pleasewarn; double timebefore; double timeafter; int late; char fpath[FILENAME_MAX]; FILE *fptr; #ifdef DEBUG post("s: %s", s->s_name); post("argc: %d", argc); #endif for (i = j = 0; i < argc; ++i) { if (argv[i].a_type == A_FLOAT) { f = argv[i].a_w.w_float; d = (int)f; e = f - d; if (e != 0) { pd_error(x, "udpsndrcv_send: item %d (%f) is not an integer", i, f); return; } c = (unsigned char)d; if (c != d) { pd_error(x, "udpsndrcv_send: item %d (%f) is not between 0 and 255", i, f); return; } #ifdef DEBUG post("udpsndrcv_send: argv[%d]: %d", i, c); #endif byte_buf[j++] = c; } else if (argv[i].a_type == A_SYMBOL) { atom_string(&argv[i], fpath, FILENAME_MAX); #ifdef DEBUG post ("udpsndrcv fname: %s", fpath); #endif fptr = sys_fopen(fpath, "rb"); if (fptr == NULL) { post("udpsndrcv: unable to open \"%s\"", fpath); return; } rewind(fptr); while ((d = fgetc(fptr)) != EOF) { #ifdef DEBUG post("udpsndrcv: d is %d", d); #endif byte_buf[j++] = (char)(d & 0x0FF); #ifdef DEBUG post("udpsndrcv: byte_buf[%d] = %d", j-1, byte_buf[j-1]); #endif if (j >= BYTE_BUF_LEN) { post ("udpsndrcv: file too long, truncating at %lu", BYTE_BUF_LEN); break; } } fclose(fptr); fptr = NULL; post("udpsndrcv: read \"%s\" length %d byte%s", fpath, j, ((d==1)?"":"s")); } else { pd_error(x, "udpsndrcv_send: item %d is not a float or a file name", i); return; } } length = j; if ((x->x_fd >= 0) && (length > 0)) { for (bp = byte_buf, sent = 0; sent < length;) { timebefore = sys_getrealtime(); result = send(x->x_fd, byte_buf, length-sent, 0); timeafter = sys_getrealtime(); late = (timeafter - timebefore > 0.005); if (late || pleasewarn) { if (timeafter > lastwarntime + 2) { post("udpsndrcv blocked %d msec", (int)(1000 * ((timeafter - timebefore) + pleasewarn))); pleasewarn = 0; lastwarntime = timeafter; } else if (late) pleasewarn += timeafter - timebefore; } if (result <= 0) { udpsndrcv_sock_err(x, "udpsndrcv send"); udpsndrcv_disconnect(x); break; } else { sent += result; bp += result; } } } else pd_error(x, "udpsndrcv: not connected"); } static void udpsndrcv_free(t_udpsndrcv *x) { udpsndrcv_disconnect(x); } void udpsndrcv_setup(void) { udpsndrcv_class = class_new(gensym("udpsndrcv"), (t_newmethod)udpsndrcv_new, (t_method)udpsndrcv_free, sizeof(t_udpsndrcv), 0, 0); class_addmethod(udpsndrcv_class, (t_method)udpsndrcv_connect, gensym("connect"), A_SYMBOL, A_FLOAT, A_FLOAT, 0); class_addmethod(udpsndrcv_class, (t_method)udpsndrcv_disconnect, gensym("disconnect"), 0); class_addmethod(udpsndrcv_class, (t_method)udpsndrcv_send, gensym("send"), A_GIMME, 0); class_addmethod(udpsndrcv_class, (t_method)udpsndrcv_status, gensym("status"), 0); class_addlist(udpsndrcv_class, (t_method)udpsndrcv_send); } /* end udpsndrcv.c*/ mrpeach/net/udpsend~-help.pd0000644000175000017500000001672512417550101016637 0ustar zmoelnigzmoelnig#N canvas 1 53 785 621 10; #X obj -178 225 osc~ 440; #X msg -398 60 disconnect; #X msg -353 105 format float; #X msg -332 126 format 16bit; #X msg -311 147 format 8bit; #X msg -440 18 connect localhost 8008; #X text -244 103 float is the most expensive with the best resolution (32bit) \, default is float; #X msg -419 39 connect 255.255.255.255 8008; #X obj 52 687 print udpreceive~; #X obj 224 369 print udpsend~; #X obj -178 320 tgl 15 0 empty empty empty 17 7 0 10 -4034 -1 -1 0 1; #X symbolatom -97 435 10 0 0 0 - - -; #X floatatom -44 369 5 0 0 0 - - -; #X floatatom 10 391 9 0 0 0 - - -; #X floatatom 63 411 9 0 0 0 - - -; #X symbolatom 117 390 10 0 0 0 - - -; #X obj -97 411 prepend set; #X obj 117 367 prepend set; #X text -102 368 channels:; #X text -144 442 format:; #X text 13 411 bitrate:; #X text -51 391 framesize:; #X text 98 389 to:; #X msg -216 242 info; #X symbolatom -293 774 10 0 0 0 - - -; #X floatatom -259 708 5 0 0 0 - - -; #X floatatom -224 687 7 0 0 0 - - -; #X floatatom -190 752 9 0 0 0 - - -; #X obj -293 733 prepend set; #X text -323 707 channels:; #X text -339 773 format:; #X text -239 751 bitrate:; #X text -288 686 framesize:; #X floatatom -155 709 9 0 0 0 - - -; #X floatatom -121 687 9 0 0 0 - - -; #X floatatom -86 730 5 0 0 0 - - -; #X floatatom -52 709 5 0 0 0 - - -; #X text -212 708 overflow:; #X text -181 686 underflow:; #X text -147 729 queuesize:; #X text -100 708 average:; #X msg -435 478 info; #X text -237 34 broadcast to everybody on your local subnet listening on the specified port; #X msg -455 458 reset; #X text -402 477 status info to rightmost outlet; #X text -415 241 status info to rightmost outlet; #X text -417 457 reset underflow & overflow counters; #X floatatom -260 589 3 0 0 0 - - -; #X floatatom -237 589 3 0 0 0 - - -; #X floatatom -214 589 3 0 0 0 - - -; #X floatatom -191 589 3 0 0 0 - - -; #X floatatom -167 589 5 0 0 0 - - -; #X obj -260 563 unpack 0 0 0 0 0; #X text -297 588 from:; #X obj -179 268 *~; #X floatatom -124 150 5 0 0 0 - - -; #X text -66 148 Framesize = (blocksize) X (number of channels) X (bytes per sample); #X obj -97 339 route format channels framesize bitrate ipaddr vecsize ; #X floatatom 170 430 9 0 0 0 - - -; #X text 70 430 dsp vector size:; #X msg -258 200 channels \$1; #X obj -412 185 hradio 15 1 0 4 empty empty empty 0 -8 0 10 -4034 -1 -1 0; #X obj -178 297 udpsend~ 2 512; #X text -88 296 sends 2 dsp-channels using 512-sample blocks; #X obj -388 572 dac~ 1 2; #X text 68 448 (blocksize must be a multiple of this); #X text -160 318 1 = transmitting; #X obj -97 246 noise~; #X obj -98 268 *~; #X obj -124 170 / 100; #X text -455 343 Based on: [netreceive~] and [netsend~]by Olaf Matthes ; #X floatatom -17 752 9 0 0 0 - - -; #X text -69 751 packets:; #X text -50 177 Default blocksize is 2048 The number of samples per block must be an integer multiple of the number of samples in one signal vector.; #X text -28 225 Arguments: (1st required \, 2nd optional) 1:number of channels to send. 2:blocksize = number of samples per channel per frame. (Blocksize of sender and receiver must be the same.); #X text -122 562 To communicate \, a [udpreceive~] and [udpsend~] pair must have the same number of channels and the same blocksize. Also [udpsend~] must [connect( to the port on which [udpreceive~] is listening. ; #X text -329 59 stop transmitting; #X text -355 76 format defines the resolution of the sent signal and may be changed on-the-fly; #X text -450 200 number of channels to transmit; #X msg -414 499 buffer 2; #X text -352 498 set number of frames to buffer before playback; #X text -458 368 [udpsend~] transmits dsp vectors ("audio") via UDP. UDP is a connectionless protocol \, so [udpsend~] will transmit even if nothing is receiving.; #X text -299 18 connect to and begin transmitting ; #X text -456 313 [udpreceive~] and [udpsend~]; #X text -249 540 receives 2 channels on port 8008 Same blocksize as udpsend~; #X floatatom -412 216 5 0 0 0 - - -; #X obj -288 172 tgl 15 0 empty empty toggle_connection 17 7 0 10 -4034 -1 -1 0 1; #X obj -293 650 route format channels framesize bitrate overflow underflow queuesize average packets tag_errors; #X floatatom 17 730 9 0 0 0 - - -; #X text -49 729 tag errors:; #X obj -326 601 env~; #X floatatom -326 624 9 0 0 0 - - -; #X text -266 613 The rightmost signal outlet outputs 1 if the stream is valid \, else 0; #N canvas 27 271 657 334 multicast 0; #X msg 91 87 multicast_interface 192.168.0.88; #X msg 66 62 multicast_interface eth1; #X text 229 13 send to a multicast address; #X text 201 38 specify an interface to use with multicast; #X msg 43 39 multicast_interface 1; #X text 251 61 by index \, name or address; #X floatatom 183 112 5 0 256 0 - - -; #X obj 165 135 f 1; #X obj 165 115 bng 15 250 50 0 empty empty empty 17 7 0 10 -4034 -1 -1; #X text 17 136 set multicast ttl:; #X msg 165 161 multicast_ttl \$1; #X msg 215 211 multicast_loopback \$1; #X obj 215 189 tgl 15 0 empty empty empty 20 7 0 8 -24198 -241291 -1 0 1; #X text 26 187 enable multicast loopback:; #X obj 244 257 outlet; #X msg 18 14 connect 239.200.200.200 8008; #X text 262 278 [udpreceive~ 8008 2 512 239.200.200.200]; #X text -70 278 Will be received by any udpreceive~ declared like this: ; #X text 347 295 (2 and 512 may be changed); #X connect 0 0 14 0; #X connect 1 0 14 0; #X connect 4 0 14 0; #X connect 6 0 7 1; #X connect 7 0 10 0; #X connect 8 0 7 0; #X connect 10 0 14 0; #X connect 11 0 14 0; #X connect 12 0 11 0; #X connect 15 0 14 0; #X restore -347 280 pd multicast; #X obj -389 541 udpreceive~ 8008 2 512; #X text -50 497 Arguments: port \, channels \, blocksize \, multicast_address. Blocksize should match [udpsend~]. multicast_address is optional. Arguments must be in that order.; #X text -455 328 Author: Martin Peach 2010/10/28; #N canvas 529 111 494 344 META 0; #X text 12 175 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; #X text 12 25 LICENSE GPL v2 or later; #X text 12 155 AUTHOR Martin Peach; #X text 12 5 KEYWORDS control network; #X text 12 45 DESCRIPTION transmit dsp vectors ("audio") via UDP; #X text 12 65 INLET_0 signal connect disconnect format channels info multicast_interface multicast_ttl multicast_loopback; #X text 12 95 INLET_1 signal; #X text 12 115 OUTLET_0 float; #X text 12 135 OUTLET_1 format channels framesize bitrate ipaddr vecsize ; #X restore 248 760 pd META; #X connect 0 0 54 0; #X connect 1 0 62 0; #X connect 2 0 62 0; #X connect 3 0 62 0; #X connect 4 0 62 0; #X connect 5 0 62 0; #X connect 7 0 62 0; #X connect 16 0 11 0; #X connect 17 0 15 0; #X connect 23 0 62 0; #X connect 28 0 24 0; #X connect 41 0 94 0; #X connect 43 0 94 0; #X connect 52 0 47 0; #X connect 52 1 48 0; #X connect 52 2 49 0; #X connect 52 3 50 0; #X connect 52 4 51 0; #X connect 54 0 62 0; #X connect 55 0 69 0; #X connect 57 0 16 0; #X connect 57 1 12 0; #X connect 57 2 13 0; #X connect 57 3 14 0; #X connect 57 4 17 0; #X connect 57 5 58 0; #X connect 57 6 9 0; #X connect 60 0 62 0; #X connect 61 0 60 0; #X connect 61 0 85 0; #X connect 62 0 10 0; #X connect 62 1 57 0; #X connect 67 0 68 0; #X connect 68 0 62 1; #X connect 69 0 54 1; #X connect 69 0 68 1; #X connect 79 0 94 0; #X connect 86 0 62 0; #X connect 87 0 28 0; #X connect 87 1 25 0; #X connect 87 2 26 0; #X connect 87 3 27 0; #X connect 87 4 33 0; #X connect 87 5 34 0; #X connect 87 6 35 0; #X connect 87 7 36 0; #X connect 87 8 71 0; #X connect 87 9 88 0; #X connect 87 10 8 0; #X connect 90 0 91 0; #X connect 93 0 62 0; #X connect 94 0 64 0; #X connect 94 1 64 1; #X connect 94 2 90 0; #X connect 94 3 87 0; #X connect 94 4 52 0; mrpeach/net/udpreceive.c0000644000175000017500000002413511462347060016024 0ustar zmoelnigzmoelnig/* x_net_udpreceive.c 20060424. Martin Peach did it based on x_net.c. x_net.c header follows: */ /* Copyright (c) 1997-1999 Miller Puckette. * For information on usage and redistribution, and for a DISCLAIMER OF ALL * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ #include "m_pd.h" #include "s_stuff.h" #include #ifdef _WIN32 #include #include #else #include #include #include #include #include #include #include #endif /* ----------------------------- udpreceive ------------------------- */ static t_class *udpreceive_class; #define MAX_UDP_RECEIVE 65536L // longer than data in maximum UDP packet typedef struct _udpreceive { t_object x_obj; t_outlet *x_msgout; t_outlet *x_addrout; int x_connectsocket; int x_multicast_joined; long x_total_received; t_atom x_addrbytes[5]; t_atom x_msgoutbuf[MAX_UDP_RECEIVE]; char x_msginbuf[MAX_UDP_RECEIVE]; char x_addr_name[256]; // a multicast address or 0 } t_udpreceive; void udpreceive_setup(void); static void udpreceive_free(t_udpreceive *x); static void *udpreceive_new(t_symbol *s, int argc, t_atom *argv); static int udpreceive_new_socket(t_udpreceive *x, char *address, int port); static void udpreceive_sock_err(t_udpreceive *x, char *err_string); static void udpreceive_status(t_udpreceive *x); static void udpreceive_read(t_udpreceive *x, int sockfd); static void udpreceive_port(t_udpreceive *x, t_float portno); static void udpreceive_read(t_udpreceive *x, int sockfd) { int i, read = 0; struct sockaddr_in from; socklen_t fromlen = sizeof(from); t_atom output_atom; long addr; unsigned short port; read = recvfrom(sockfd, x->x_msginbuf, MAX_UDP_RECEIVE, 0, (struct sockaddr *)&from, &fromlen); #ifdef DEBUG post("udpreceive_read: read %lu x->x_connectsocket = %d", read, x->x_connectsocket); #endif /* get the sender's ip */ addr = ntohl(from.sin_addr.s_addr); port = ntohs(from.sin_port); x->x_addrbytes[0].a_w.w_float = (addr & 0xFF000000)>>24; x->x_addrbytes[1].a_w.w_float = (addr & 0x0FF0000)>>16; x->x_addrbytes[2].a_w.w_float = (addr & 0x0FF00)>>8; x->x_addrbytes[3].a_w.w_float = (addr & 0x0FF); x->x_addrbytes[4].a_w.w_float = port; outlet_anything(x->x_addrout, gensym("from"), 5L, x->x_addrbytes); if (read < 0) { udpreceive_sock_err(x, "udpreceive_read"); sys_closesocket(x->x_connectsocket); return; } if (read > 0) { for (i = 0; i < read; ++i) { /* convert the bytes in the buffer to floats in a list */ x->x_msgoutbuf[i].a_w.w_float = (float)(unsigned char)x->x_msginbuf[i]; } x->x_total_received += read; SETFLOAT(&output_atom, read); outlet_anything(x->x_addrout, gensym("received"), 1, &output_atom); /* send the list out the outlet */ if (read > 1) outlet_list(x->x_msgout, &s_list, read, x->x_msgoutbuf); else outlet_float(x->x_msgout, x->x_msgoutbuf[0].a_w.w_float); } } static void *udpreceive_new(t_symbol *s, int argc, t_atom *argv) { t_udpreceive *x; int result = 0, portno = 0; int i; x = (t_udpreceive *)pd_new(udpreceive_class); /* if something fails we return 0 instead of x. Is this OK? */ if (NULL == x) return x; x->x_addr_name[0] = '\0'; /* convert the bytes in the buffer to floats in a list */ for (i = 0; i < MAX_UDP_RECEIVE; ++i) { x->x_msgoutbuf[i].a_type = A_FLOAT; x->x_msgoutbuf[i].a_w.w_float = 0; } for (i = 0; i < 5; ++i) { x->x_addrbytes[i].a_type = A_FLOAT; x->x_addrbytes[i].a_w.w_float = 0; } #ifdef DEBUG post("udpreceive_new:argc is %d s is %s", argc, s->s_name); #endif for (i = 0; i < argc ;++i) { if (argv[i].a_type == A_FLOAT) { // float is taken to be a port number #ifdef DEBUG post ("argv[%d] is a float: %f", i, argv[i].a_w.w_float); #endif portno = (int)argv[i].a_w.w_float; } else if (argv[i].a_type == A_SYMBOL) { // symbol is taken to be an ip address (for multicast) #ifdef DEBUG post ("argv[%d] is a symbol: %s", i, argv[i].a_w.w_symbol->s_name); #endif atom_string(&argv[i], x->x_addr_name, 256); } } #ifdef DEBUG post("Setting port %d, address %s", portno, x->addr); #endif x->x_msgout = outlet_new(&x->x_obj, &s_anything); x->x_addrout = outlet_new(&x->x_obj, &s_anything); x->x_connectsocket = -1; // no socket result = udpreceive_new_socket(x, x->x_addr_name, portno); return (x); } static int udpreceive_new_socket(t_udpreceive *x, char *address, int port) { // return nonzero if successful in creating and binding a socket int sockfd; int intarg; int multicast_joined = 0; struct sockaddr_in server; struct hostent *hp; #if defined __APPLE__ || defined _WIN32 struct ip_mreq mreq; #else struct ip_mreqn mreq; #endif if (x->x_connectsocket >= 0) { // close the existing socket first sys_rmpollfn(x->x_connectsocket); sys_closesocket(x->x_connectsocket); } /* create a socket */ sockfd = socket(AF_INET, SOCK_DGRAM, 0); #ifdef DEBUG post("udpreceive_new: socket %d port %d", sockfd, portno); #endif if (sockfd < 0) { udpreceive_sock_err(x, "udpreceive: socket"); return 0; } server.sin_family = AF_INET; if (address[0] == 0) server.sin_addr.s_addr = INADDR_ANY; else { hp = gethostbyname(address); if (hp == 0) { pd_error(x, "udpreceive: bad host?\n"); return 0; } memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length); } /* enable delivery of all multicast or broadcast (but not unicast) * UDP datagrams to all sockets bound to the same port */ intarg = 1; if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&intarg, sizeof(intarg)) < 0) udpreceive_sock_err(x, "udpreceive: setsockopt (SO_REUSEADDR) failed"); /* assign server port number */ server.sin_port = htons((u_short)port); /* if a multicast address was specified, join the multicast group */ /* hop count defaults to 1 so we won't leave the subnet*/ if (0xE0000000 == (ntohl(server.sin_addr.s_addr) & 0xF0000000)) { server.sin_addr.s_addr = INADDR_ANY; /* first bind the socket to INADDR_ANY */ if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0) { udpreceive_sock_err(x, "udpreceive: bind"); sys_closesocket(sockfd); return 0; } /* second join the multicast group */ memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length); #if defined __APPLE__ || defined _WIN32 mreq.imr_multiaddr.s_addr = server.sin_addr.s_addr; mreq.imr_interface.s_addr = INADDR_ANY;/* can put a specific local IP address here if host is multihomed */ #else mreq.imr_multiaddr.s_addr = server.sin_addr.s_addr; mreq.imr_address.s_addr = INADDR_ANY; mreq.imr_ifindex = 0; #endif //__APPLE__ || _WIN32 if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq)) < 0) udpreceive_sock_err(x, "udpreceive: setsockopt IP_ADD_MEMBERSHIP"); else { multicast_joined = 1; post ("udpreceive: added to multicast group"); } } else { /* name the socket */ if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0) { udpreceive_sock_err(x, "udpreceive: bind"); sys_closesocket(sockfd); return 0; } } x->x_multicast_joined = multicast_joined; x->x_connectsocket = sockfd; x->x_total_received = 0L; sys_addpollfn(x->x_connectsocket, (t_fdpollfn)udpreceive_read, x); return 1; } static void udpreceive_sock_err(t_udpreceive *x, char *err_string) { /* prints the last error from errno or WSAGetLastError() */ #ifdef _WIN32 LPVOID lpMsgBuf; DWORD dwRetVal = WSAGetLastError(); int len = 0, i; char *cp; if (len = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS , NULL, dwRetVal, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&lpMsgBuf, 0, NULL)) { cp = (char *)lpMsgBuf; for(i = 0; i < len; ++i) { if (cp[i] < 0x20) { /* end string at first weird character */ cp[i] = 0; break; } } pd_error(x, "%s: %s (%d)", err_string, lpMsgBuf, dwRetVal); LocalFree(lpMsgBuf); } #else pd_error(x, "%s: %s (%d)", err_string, strerror(errno), errno); #endif } static void udpreceive_status(t_udpreceive *x) { t_atom output_atom; SETFLOAT(&output_atom, x->x_multicast_joined); outlet_anything( x->x_addrout, gensym("multicast"), 1, &output_atom); SETFLOAT(&output_atom, x->x_total_received); outlet_anything( x->x_addrout, gensym("total"), 1, &output_atom); } static void udpreceive_port(t_udpreceive *x, t_float portno) { int result = udpreceive_new_socket(x, x->x_addr_name, (int)portno); } static void udpreceive_free(t_udpreceive *x) { if (x->x_connectsocket >= 0) { sys_rmpollfn(x->x_connectsocket); sys_closesocket(x->x_connectsocket); } } void udpreceive_setup(void) { udpreceive_class = class_new(gensym("udpreceive"), (t_newmethod)udpreceive_new, (t_method)udpreceive_free, sizeof(t_udpreceive), CLASS_DEFAULT, A_GIMME, 0); class_addmethod(udpreceive_class, (t_method)udpreceive_status, gensym("status"), 0); class_addmethod(udpreceive_class, (t_method)udpreceive_port, gensym("port"), A_DEFFLOAT, 0); } /* end udpreceive.c */ mrpeach/net/examples/0000755000175000017500000000000013605444727015347 5ustar zmoelnigzmoelnigmrpeach/net/examples/test.txt0000644000175000017500000000002711650366670017064 0ustar zmoelnigzmoelnigtesting one two three mrpeach/net/net-meta.pd0000644000175000017500000000030711650352075015560 0ustar zmoelnigzmoelnig#N canvas 17 107 200 200 10; #N canvas 486 145 761 300 META 1; #X text 10 5 VERSION 0.1; #X text 11 25 NAME net; #X text 9 45 AUTHOR Martin Peach martin.peach@sympatico.ca; #X restore 10 10 pd META; mrpeach/net/tcpclient.c0000644000175000017500000006117413221012047015647 0ustar zmoelnigzmoelnig/* tcpclient.c Martin Peach 20060508, working version 20060512 */ /* linux version 20060515 */ /* tcpclient.c is based on netclient: */ /* -------------------------- netclient ------------------------------------- */ /* */ /* Extended 'netsend', connects to 'netserver'. */ /* Uses child thread to connect to server. Thus needs pd0.35-test17 or later. */ /* Written by Olaf Matthes (olaf.matthes@gmx.de) */ /* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ /* */ /* This program is free software; you can redistribute it and/or */ /* modify it under the terms of the GNU General Public License */ /* as published by the Free Software Foundation; either version 2 */ /* of the License, or (at your option) any later version. */ /* */ /* This program is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with this program; if not, write to the Free Software */ /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* */ /* Based on PureData by Miller Puckette and others. */ /* */ /* ---------------------------------------------------------------------------- */ //#define DEBUG #include "m_pd.h" #include "s_stuff.h" #include #include #include #include #ifndef _WIN32 #include #include #include #include #include #include #include #include #define SOCKET_ERROR -1 #else #include #include /* for socklen_t */ #endif /* support older Pd versions without sys_open(), sys_fopen(), sys_fclose() */ #if PD_MAJOR_VERSION == 0 && PD_MINOR_VERSION < 44 #define sys_open open #define sys_fopen fopen #define sys_fclose fclose #endif #ifdef _MSC_VER #define snprintf sprintf_s #endif #define DEFPOLLTIME 20 /* check for input every 20 ms */ static t_class *tcpclient_class; static char objName[] = "tcpclient"; #define MAX_TCPCLIENT_SEND_BUF 65536L // longer than data in maximum UDP packet /* each send is handled by a new thread with a new parameter struct: */ /* these are stored under x->x_tsp[0..MAX_TCPCLIENT_THREADS-1] */ /* The buffer is preallocated for speed. */ typedef struct _tcpclient_sender_params { char x_sendbuf[MAX_TCPCLIENT_SEND_BUF]; /* possibly allocate this dynamically for space over speed */ size_t x_buf_len; int x_sendresult; pthread_t sendthreadid; int threadisvalid; /* non-zero if sendthreadid is an active thread */ struct _tcpclient *x_x; } t_tcpclient_sender_params; #define MAX_TCPCLIENT_THREADS 32 /* MAX_TCPCLIENT_THREADS is small to avoid wasting space. This is the maximum number of concurrent threads. */ typedef struct _tcpclient { t_object x_obj; t_clock *x_clock; t_clock *x_poll; t_clock *x_sendclock; t_outlet *x_msgout; t_outlet *x_addrout; t_outlet *x_connectout; t_outlet *x_statusout; int x_dump; // 1 = hexdump received bytes int x_verbosity; // 1 = post connection state changes to main window int x_fd; // the socket int x_fdbuf; // the socket's buffer size char *x_hostname; // address we want to connect to as text int x_connectstate; // 0 = not connected, 1 = connected int x_port; // port we're connected to uint32_t x_addr; // address we're connected to as 32bit int uint32_t x_ourAddr; // address of our interface int x_ourPort; // port nunber of our interface t_atom x_addrbytes[5]; // address we're connected to as 4 bytes and one int t_atom x_msgoutbuf[MAX_TCPCLIENT_SEND_BUF]; // received data as float atoms unsigned char x_msginbuf[MAX_TCPCLIENT_SEND_BUF]; // received data as bytes char *x_sendbuf; // pointer to data to send int x_sendbuf_len; // number of bytes in sendbuf int x_sendresult; int x_blocked; /* multithread stuff */ pthread_t x_threadid; /* id of connector child thread */ pthread_attr_t x_threadattr; /* attributes of connector child thread */ pthread_attr_t x_sendthreadattr; /* attributes of all sender child thread for sending */ int x_nextthread; /* next unused x_tsp */ t_tcpclient_sender_params x_tsp[MAX_TCPCLIENT_THREADS]; /* Thread params are used round-robin to avoid overwriting buffers when doing multiple sends */ } t_tcpclient; static void tcpclient_verbosity(t_tcpclient *x, t_float verbosity); static void tcpclient_dump(t_tcpclient *x, t_float dump); static void tcp_client_hexdump(t_tcpclient *x, long len); static void tcpclient_tick(t_tcpclient *x); static void *tcpclient_child_connect(void *w); static void tcpclient_connect(t_tcpclient *x, t_symbol *hostname, t_floatarg fportno); static void tcpclient_disconnect(t_tcpclient *x); static void tcpclient_send(t_tcpclient *x, t_symbol *s, int argc, t_atom *argv); static int tcpclient_send_buf(t_tcpclient *x, char *buf, int buf_len); static void *tcpclient_child_send(void *w); static void tcpclient_sent(t_tcpclient *x); static int tcpclient_get_socket_send_buf_size(t_tcpclient *x); static int tcpclient_set_socket_send_buf_size(t_tcpclient *x, int size); static void tcpclient_buf_size(t_tcpclient *x, t_symbol *s, int argc, t_atom *argv); static void tcpclient_rcv(t_tcpclient *x); static void tcpclient_poll(t_tcpclient *x); static void tcpclient_unblock(t_tcpclient *x); static void *tcpclient_new(void); static void tcpclient_free(t_tcpclient *x); void tcpclient_setup(void); static void tcpclient_dump(t_tcpclient *x, t_float dump) { x->x_dump = (dump == 0)?0:1; } static void tcpclient_verbosity(t_tcpclient *x, t_float verbosity) { x->x_verbosity = (verbosity == 0)?0:1; /* only two states so far */ } static void tcp_client_hexdump(t_tcpclient *x, long len) { #define BYTES_PER_LINE 16 char hexStr[(3*BYTES_PER_LINE)+1]; char ascStr[BYTES_PER_LINE+1]; long i, j, k = 0L; unsigned char *buf = x->x_msginbuf; if (x->x_verbosity) post("%s_hexdump %d:", objName, len); while (k < len) { for (i = j = 0; i < BYTES_PER_LINE; ++i, ++k, j+=3) { if (k < len) { snprintf(&hexStr[j], 4, "%02X ", buf[k]); snprintf(&ascStr[i], 2, "%c", ((buf[k] >= 32) && (buf[k] <= 126))? buf[k]: '.'); } else { // the last line snprintf(&hexStr[j], 4, " "); snprintf(&ascStr[i], 2, " "); } } post ("%s%s", hexStr, ascStr); } } static void tcpclient_tick(t_tcpclient *x) { t_atom output_atom[5]; SETFLOAT(&output_atom[0], (x->x_ourAddr & 0xFF000000)>>24); // address of our interface in bytes SETFLOAT(&output_atom[1], (x->x_ourAddr & 0x0FF0000)>>16); SETFLOAT(&output_atom[2], (x->x_ourAddr & 0x0FF00)>>8); SETFLOAT(&output_atom[3], (x->x_ourAddr & 0x0FF)); SETFLOAT(&output_atom[4], x->x_ourPort); // port nunber of our interface outlet_anything( x->x_statusout, gensym("ourIP"), 5, output_atom); outlet_float(x->x_connectout, 1); } static void *tcpclient_child_connect(void *w) { t_tcpclient *x = (t_tcpclient*) w; struct sockaddr_in server, addr; struct hostent *hp; int sockfd; socklen_t addrlen = sizeof (addr); if (x->x_fd >= 0) { error("%s_child_connect: already connected", objName); return (x); } /* create a socket */ sockfd = socket(AF_INET, SOCK_STREAM, 0); #ifdef DEBUG post("%s: send socket %d\n", objName, sockfd); #endif if (sockfd < 0) { sys_sockerror("tcpclient: socket"); return (x); } /* connect socket using hostname provided in command line */ server.sin_family = AF_INET; hp = gethostbyname(x->x_hostname); if (hp == 0) { sys_sockerror("tcpclient: bad host?\n"); return (x); } memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length); /* assign client port number */ server.sin_port = htons((u_short)x->x_port); if (x->x_verbosity) post("%s: connecting socket %d to port %d", objName, sockfd, x->x_port); /* try to connect */ if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0) { sys_sockerror("tcpclient: connecting stream socket"); sys_closesocket(sockfd); return (x); } x->x_fd = sockfd; x->x_addr = ntohl(*(uint32_t *)hp->h_addr); /* outlet_float is not threadsafe ! */ // outlet_float(x->x_obj.ob_outlet, 1); x->x_connectstate = 1; x->x_blocked = 0; /* Find our address */ if (getsockname(sockfd, (struct sockaddr *)&addr, (socklen_t *)&addrlen)) sys_sockerror("tcpclient: getting socket name"); else { /* output the address this socket is bound to */ //printf("addrlen %u\n", addrlen); //printf("port %u\n", addr.sin_port); //printf("IP address %s\n", inet_ntoa(addr.sin_addr)); x->x_ourAddr = ntohl(addr.sin_addr.s_addr); x->x_ourPort = ntohs(addr.sin_port); } /* use callback instead to set outlet */ clock_delay(x->x_clock, 0); return (x); } static void tcpclient_connect(t_tcpclient *x, t_symbol *hostname, t_floatarg fportno) { /* if we are not already connected, as Ivica Ico Bukvic 5/5/10 noted */ if (0 != x->x_connectstate) { error("%s_connect: already connected to %s:%d on socket %d", objName, x->x_hostname, x->x_port, x->x_fd); return; } /* we get hostname and port and pass them on to the child thread that establishes the connection */ x->x_hostname = hostname->s_name; x->x_port = fportno; /* start child thread */ if(pthread_create(&x->x_threadid, &x->x_threadattr, tcpclient_child_connect, x) < 0) post("%s: could not create new thread", objName); } static void tcpclient_disconnect(t_tcpclient *x) { int i; if (x->x_fd >= 0) { for (i = 0; i < MAX_TCPCLIENT_THREADS;++i) { /* wait for any sender threads to finish */ while (x->x_tsp[i].threadisvalid != 0); } sys_closesocket(x->x_fd); x->x_fd = -1; x->x_connectstate = 0; x->x_ourAddr = 0L; x->x_ourPort = 0; outlet_float(x->x_connectout, 0); if (x->x_verbosity) post("%s: disconnected", objName); } else post("%s: not connected", objName); } static void tcpclient_send(t_tcpclient *x, t_symbol *s, int argc, t_atom *argv) { #define BYTE_BUF_LEN 65536 // arbitrary maximum similar to max IP packet size static char byte_buf[BYTE_BUF_LEN]; int i, j, d; unsigned char c; float f, e; size_t sent = 0; char fpath[FILENAME_MAX]; FILE *fptr; #ifdef DEBUG post("s: %s", s->s_name); post("argc: %d", argc); #endif for (i = j = 0; i < argc; ++i) { if (argv[i].a_type == A_FLOAT) { f = argv[i].a_w.w_float; d = (int)f; e = f - d; if (e != 0) { pd_error(x, "%s_send: item %d (%f) is not an integer", objName, i, f); return; } if ((d < 0) || (d > 255)) { pd_error(x, "%s: item %d (%f) is not between 0 and 255", objName, i, f); return; } c = (unsigned char)d; byte_buf[j++] = c; if (j >= BYTE_BUF_LEN) { sent += tcpclient_send_buf(x, byte_buf, j); j = 0; } } else if (argv[i].a_type == A_SYMBOL) { atom_string(&argv[i], fpath, FILENAME_MAX); fptr = sys_fopen(fpath, "rb"); if (fptr == NULL) { post("%s_send: unable to open \"%s\"", objName, fpath); return; } rewind(fptr); while ((d = fgetc(fptr)) != EOF) { c = (char)(d & 0x0FF); byte_buf[j++] = c; if (j >= BYTE_BUF_LEN) { sent += tcpclient_send_buf(x, byte_buf, j); j = 0; } } sys_fclose(fptr); fptr = NULL; if (x->x_verbosity) post("%s_send: read \"%s\" length %d byte%s", objName, fpath, j, ((d==1)?"":"s")); } else { pd_error(x, "%s_send: item %d is not a float or a file name", objName, i); return; } } if (j > 0) sent += tcpclient_send_buf(x, byte_buf, j); } static int tcpclient_send_buf(t_tcpclient *x, char *buf, int buf_len) { t_tcpclient_sender_params *tsp = &x->x_tsp[x->x_nextthread]; int i, max; if (x->x_blocked) return 0; if (x->x_fd < 0) { pd_error(x, "%s: not connected", objName); x->x_blocked++; return 0; } max = (buf_len > MAX_TCPCLIENT_SEND_BUF)? MAX_TCPCLIENT_SEND_BUF: buf_len; while(0 != tsp->threadisvalid); /* wait for thread to clear */ for (i = 0; i < max; ++i) { tsp->x_sendbuf[i] = buf[i]; } tsp->x_buf_len = i; x->x_sendbuf_len += i; tsp->x_x = x; tsp->threadisvalid = 1; if((tsp->x_sendresult = pthread_create(&tsp->sendthreadid, &x->x_sendthreadattr, tcpclient_child_send, tsp)) < 0) { tsp->threadisvalid = 0; post("%s_send_buf: could not create new thread (%d)", objName); clock_delay(x->x_sendclock, 0); // calls tcpclient_sent return 0; } x->x_nextthread++; if (x->x_nextthread >= MAX_TCPCLIENT_THREADS) x->x_nextthread = 0; return max; } /* tcpclient_child_send runs in sendthread */ static void *tcpclient_child_send(void *w) { t_tcpclient_sender_params *tsp = (t_tcpclient_sender_params*) w; if (tsp->x_x->x_fd >= 0) { tsp->x_sendresult = send(tsp->x_x->x_fd, tsp->x_sendbuf, tsp->x_buf_len, 0); clock_delay(tsp->x_x->x_sendclock, 0); // calls tcpclient_sent when it's safe to do so } tsp->threadisvalid = 0; /* this thread is over */ return(tsp); } static void tcpclient_sent(t_tcpclient *x) { t_atom output_atom; if (x->x_sendresult < 0) { sys_sockerror("tcpclient: send"); post("%s_sent: could not send data ", objName); x->x_blocked++; SETFLOAT(&output_atom, x->x_sendresult); outlet_anything( x->x_statusout, gensym("blocked"), 1, &output_atom); } else if (x->x_sendresult == 0) { /* assume the message is queued and will be sent real soon now */ SETFLOAT(&output_atom, x->x_sendbuf_len); outlet_anything( x->x_statusout, gensym("sent"), 1, &output_atom); x->x_sendbuf_len = 0; /* we might be called only once for multiple calls to tcpclient_send_buf */ } else { SETFLOAT(&output_atom, x->x_sendresult); outlet_anything( x->x_statusout, gensym("sent"), 1, &output_atom); } } /* Return the send buffer size of socket, also output it on status outlet */ static int tcpclient_get_socket_send_buf_size(t_tcpclient *x) { int optVal = 0; socklen_t optLen = sizeof(int); t_atom output_atom; #ifdef _WIN32 if (getsockopt(x->x_fd, SOL_SOCKET, SO_SNDBUF, (char*)&optVal, &optLen) == SOCKET_ERROR) post("%_get_socket_send_buf_size: getsockopt returned %d\n", objName, WSAGetLastError()); #else if (getsockopt(x->x_fd, SOL_SOCKET, SO_SNDBUF, (char*)&optVal, &optLen) == -1) post("%_get_socket_send_buf_size: getsockopt returned %d\n", objName, errno); #endif SETFLOAT(&output_atom, optVal); outlet_anything( x->x_statusout, gensym("buf"), 1, &output_atom); return optVal; } /* Set the send buffer size of socket, returns actual size */ static int tcpclient_set_socket_send_buf_size(t_tcpclient *x, int size) { int optVal = size; int optLen = sizeof(int); #ifdef _WIN32 if (setsockopt(x->x_fd, SOL_SOCKET, SO_SNDBUF, (char*)&optVal, optLen) == SOCKET_ERROR) { post("%s_set_socket_send_buf_size: setsockopt returned %d\n", objName, WSAGetLastError()); #else if (setsockopt(x->x_fd, SOL_SOCKET, SO_SNDBUF, (char*)&optVal, optLen) == -1) { post("%s_set_socket_send_buf_size: setsockopt returned %d\n", objName, errno); #endif return 0; } else return (tcpclient_get_socket_send_buf_size(x)); } /* Get/set the send buffer size of client socket */ static void tcpclient_buf_size(t_tcpclient *x, t_symbol *s, int argc, t_atom *argv) { float buf_size = 0; if(x->x_connectstate == 0) { post("%s_buf_size: no clients connected", objName); return; } /* get size of buffer (first element in list) */ if (argc > 0) { if (argv[0].a_type != A_FLOAT) { post("%s_buf_size: specify buffer size with a float", objName); return; } buf_size = atom_getfloatarg(0, argc, argv); x->x_fdbuf = tcpclient_set_socket_send_buf_size(x, (int)buf_size); if (x->x_verbosity) post("%s_buf_size: set to %d", objName, x->x_fdbuf); return; } x->x_fdbuf = tcpclient_get_socket_send_buf_size(x); return; } static void tcpclient_rcv(t_tcpclient *x) { int sockfd = x->x_fd; int ret; int i; fd_set readset; fd_set exceptset; struct timeval ztout; if(x->x_connectstate) { /* check if we can read/write from/to the socket */ FD_ZERO(&readset); FD_ZERO(&exceptset); FD_SET(x->x_fd, &readset ); FD_SET(x->x_fd, &exceptset ); ztout.tv_sec = 0; ztout.tv_usec = 0; ret = select(sockfd+1, &readset, NULL, &exceptset, &ztout); if(ret < 0) { pd_error(x, "%s: unable to read from socket", objName); sys_closesocket(sockfd); return; } if(FD_ISSET(sockfd, &readset) || FD_ISSET(sockfd, &exceptset)) { /* read from server */ ret = recv(sockfd, x->x_msginbuf, MAX_TCPCLIENT_SEND_BUF, 0); if(ret > 0) { #ifdef DEBUG x->x_msginbuf[ret] = 0; post("%s: received %d bytes ", objName, ret); #endif if (x->x_dump)tcp_client_hexdump(x, ret); for (i = 0; i < ret; ++i) { /* convert the bytes in the buffer to floats in a list */ x->x_msgoutbuf[i].a_w.w_float = (float)x->x_msginbuf[i]; } /* find sender's ip address and output it */ x->x_addrbytes[0].a_w.w_float = (x->x_addr & 0xFF000000)>>24; x->x_addrbytes[1].a_w.w_float = (x->x_addr & 0x0FF0000)>>16; x->x_addrbytes[2].a_w.w_float = (x->x_addr & 0x0FF00)>>8; x->x_addrbytes[3].a_w.w_float = (x->x_addr & 0x0FF); x->x_addrbytes[4].a_w.w_float = (x->x_port); outlet_list(x->x_addrout, &s_list, 5L, x->x_addrbytes); /* send the list out the outlet */ if (ret > 1) outlet_list(x->x_msgout, &s_list, ret, x->x_msgoutbuf); else outlet_float(x->x_msgout, x->x_msgoutbuf[0].a_w.w_float); } else { if (ret < 0) { sys_sockerror("tcpclient: recv"); tcpclient_disconnect(x); } else { if (x->x_verbosity) post("%s: connection closed for socket %d\n", objName, sockfd); tcpclient_disconnect(x); } } } } else post("%s: not connected", objName); } static void tcpclient_poll(t_tcpclient *x) { if(x->x_connectstate) tcpclient_rcv(x); /* try to read in case we're connected */ clock_delay(x->x_poll, DEFPOLLTIME); /* see you later */ } static void tcpclient_unblock(t_tcpclient *x) { x->x_blocked = 0; } static void *tcpclient_new(void) { int i; t_tcpclient *x = (t_tcpclient *)pd_new(tcpclient_class); x->x_msgout = outlet_new(&x->x_obj, &s_anything); /* received data */ x->x_addrout = outlet_new(&x->x_obj, &s_list); x->x_connectout = outlet_new(&x->x_obj, &s_float); /* connection state */ x->x_statusout = outlet_new(&x->x_obj, &s_anything);/* last outlet for everything else */ x->x_sendclock = clock_new(x, (t_method)tcpclient_sent); x->x_clock = clock_new(x, (t_method)tcpclient_tick); x->x_poll = clock_new(x, (t_method)tcpclient_poll); x->x_verbosity = 1; /* default post status changes to main window */ x->x_fd = -1; /* convert the bytes in the buffer to floats in a list */ for (i = 0; i < MAX_TCPCLIENT_SEND_BUF; ++i) { x->x_msgoutbuf[i].a_type = A_FLOAT; x->x_msgoutbuf[i].a_w.w_float = 0; } for (i = 0; i < 5; ++i) { x->x_addrbytes[i].a_type = A_FLOAT; x->x_addrbytes[i].a_w.w_float = 0; } x->x_addr = 0L; x->x_blocked = 1; x->x_ourAddr = 0L; x->x_ourPort = 0; x->x_connectstate = 0; x->x_nextthread = 0; /* prepare child threads */ if(pthread_attr_init(&x->x_threadattr) < 0) post("%s: warning: could not prepare child thread", objName); if(pthread_attr_setdetachstate(&x->x_threadattr, PTHREAD_CREATE_DETACHED) < 0) post("%s: warning: could not prepare child thread", objName); if(pthread_attr_init(&x->x_sendthreadattr) < 0) post("%s: warning: could not prepare child thread", objName); if(pthread_attr_setdetachstate(&x->x_sendthreadattr, PTHREAD_CREATE_DETACHED) < 0) post("%s: warning: could not prepare child thread", objName); clock_delay(x->x_poll, 0); /* start polling the input */ return (x); } static void tcpclient_free(t_tcpclient *x) { if (x->x_verbosity) post("tcpclient_free..."); tcpclient_disconnect(x); clock_free(x->x_poll); clock_free(x->x_clock); if (x->x_verbosity) post("...tcpclient_free"); } #ifndef BUILD_DATE # define BUILD_DATE __DATE__ " " __TIME__ #endif void tcpclient_setup(void) { char aboutStr[MAXPDSTRING]; snprintf(aboutStr, MAXPDSTRING, "%s: (GPL) 20111103 Martin Peach, compiled for pd-%d.%d on %s", objName, PD_MAJOR_VERSION, PD_MINOR_VERSION, BUILD_DATE ); #if PD_MAJOR_VERSION==0 && PD_MINOR_VERSION<43 post(aboutStr); #else logpost(NULL, 3, "%s", aboutStr); #endif tcpclient_class = class_new(gensym(objName), (t_newmethod)tcpclient_new, (t_method)tcpclient_free, sizeof(t_tcpclient), 0, 0); class_addmethod(tcpclient_class, (t_method)tcpclient_connect, gensym("connect") , A_SYMBOL, A_FLOAT, 0); class_addmethod(tcpclient_class, (t_method)tcpclient_disconnect, gensym("disconnect"), 0); class_addmethod(tcpclient_class, (t_method)tcpclient_send, gensym("send"), A_GIMME, 0); class_addmethod(tcpclient_class, (t_method)tcpclient_buf_size, gensym("buf"), A_GIMME, 0); class_addmethod(tcpclient_class, (t_method)tcpclient_unblock, gensym("unblock"), 0); class_addmethod(tcpclient_class, (t_method)tcpclient_verbosity, gensym("verbosity"), A_FLOAT, 0); class_addmethod(tcpclient_class, (t_method)tcpclient_dump, gensym("dump"), A_FLOAT, 0); class_addlist(tcpclient_class, (t_method)tcpclient_send); } /* end of tcpclient.c */ mrpeach/net/udpreceive~.c0000644000175000017500000007353111650353765016236 0ustar zmoelnigzmoelnig/* udpreceive~ started 20100110 by Martin Peach based on netreceive~: */ /* ------------------------ netreceive~ --------------------------------------- */ /* */ /* Tilde object to receive uncompressed audio data from netsend~. */ /* Written by Olaf Matthes . */ /* Based on streamin~ by Guenter Geiger. */ /* Get source at http://www.akustische-kunst.org/ */ /* */ /* This program is free software; you can redistribute it and/or */ /* modify it under the terms of the GNU General Public License */ /* as published by the Free Software Foundation; either version 2 */ /* of the License, or (at your option) any later version. */ /* */ /* See file LICENSE for further informations on licensing terms. */ /* */ /* This program is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with this program; if not, write to the Free Software */ /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* */ /* Based on PureData by Miller Puckette and others. */ /* */ /* This project was commissioned by the Society for Arts and Technology [SAT], */ /* Montreal, Quebec, Canada, http://www.sat.qc.ca/. */ /* */ /* ---------------------------------------------------------------------------- */ #include "m_pd.h" #include "s_stuff.h" #include "udpsend~.h" #include #include #include #ifndef _WIN32 #include #include #include #include #include #include #include #include #include #include #define SOCKET_ERROR -1 #endif #ifdef _WIN32 #include #include /* for socklen_t */ #endif #ifdef _MSC_VER #define snprintf sprintf_s #endif #ifndef SOL_IP #define SOL_IP IPPROTO_IP #endif #define DEFAULT_AUDIO_BUFFER_FRAMES 16 /* a small circ. buffer for 16 frames */ #define DEFAULT_AVERAGE_NUMBER 10 /* number of values we store for average history */ #define DEFAULT_NETWORK_POLLTIME 1 /* interval in ms for polling for input data (Max/MSP only) */ #define DEFAULT_QUEUE_LENGTH 3 /* min. number of buffers that can be used reliably on your hardware */ #ifndef _WIN32 #define CLOSESOCKET(fd) close(fd) #endif #ifdef _WIN32 #define CLOSESOCKET(fd) closesocket(fd) #endif /* ------------------------ udpreceive~ ----------------------------- */ typedef struct _udpreceive_tilde { t_object x_obj; t_outlet *x_outlet1; t_outlet *x_outlet2; t_outlet *x_addrout; t_clock *x_clock; t_atom x_addrbytes[5]; int x_socket; int x_connectsocket; int x_multicast_joined; int x_nconnections; long x_addr; unsigned short x_port; t_symbol *x_hostname; int x_error; int x_buffering; #define XMSG_SIZE 256 char x_msg[XMSG_SIZE]; char x_addr_name[256]; // a multicast address or 0 /* buffering */ int x_framein;// index of next empty frame in x_frames[] int x_frameout;// index of next frame to play back from x_frames[] t_frame x_frames[DEFAULT_AUDIO_BUFFER_FRAMES]; int x_maxframes; long x_tag_errors; int x_sync;// zero if we didn't receive a tag when we expected one int x_blocksize; int x_blocksperrecv; int x_blockssincerecv; int x_nbytes; int x_counter;// count of received frames int x_average[DEFAULT_AVERAGE_NUMBER]; int x_averagecur; int x_underflow; int x_overflow; int x_valid; long x_samplerate; int x_noutlets; int x_vecsize; t_int **x_myvec; /* vector we pass on to the DSP routine */ } t_udpreceive_tilde; /* function prototypes */ static void udpreceive_tilde_reset(t_udpreceive_tilde* x, t_floatarg buffer); static void udpreceive_tilde_datapoll(t_udpreceive_tilde *x); static int udpreceive_tilde_createsocket(t_udpreceive_tilde* x, char *address, int portno); static t_int *udpreceive_tilde_perform(t_int *w); static void udpreceive_tilde_dsp(t_udpreceive_tilde *x, t_signal **sp); static void udpreceive_tilde_info(t_udpreceive_tilde *x); static void udpreceive_tilde_tick(t_udpreceive_tilde *x); static void *udpreceive_tilde_new(t_symbol *s, int argc, t_atom *argv); static void udpreceive_tilde_free(t_udpreceive_tilde *x); void udpreceive_tilde_setup(void); static void udpreceive_tilde_sock_err(t_udpreceive_tilde *x, char *err_string); static int udpreceive_tilde_sockerror(char *s); static int udpreceive_tilde_setsocketoptions(int sockfd); static t_class *udpreceive_tilde_class; static t_symbol *ps_format, *ps_channels, *ps_framesize, *ps_overflow, *ps_underflow, *ps_packets, *ps_queuesize, *ps_average, *ps_sf_float, *ps_sf_16bit, *ps_sf_8bit, *ps_sf_mp3, *ps_sf_aac, *ps_sf_unknown, *ps_bitrate, *ps_hostname, *ps_nothing, *ps_tag_errors; static void udpreceive_tilde_reset(t_udpreceive_tilde* x, t_floatarg buffer) { int i; x->x_counter = 0; x->x_nbytes = 0; x->x_framein = 0; x->x_frameout = 0; x->x_blockssincerecv = 0; x->x_blocksperrecv = x->x_blocksize / x->x_vecsize; x->x_tag_errors = 0; for (i = 0; i < DEFAULT_AVERAGE_NUMBER; i++) x->x_average[i] = x->x_maxframes; x->x_averagecur = 0; i = (int)buffer; if ((i > 0)&&(i < DEFAULT_AUDIO_BUFFER_FRAMES)) { x->x_maxframes = i; post("udpreceive~: set buffer to %d frames)", x->x_maxframes); } else if (i != 0) /* special case of 0 leaves buffer size unchanged */ { post("udpreceive~: buffer must be between 1 and %d frames)", DEFAULT_AUDIO_BUFFER_FRAMES-1); } x->x_underflow = 0; x->x_overflow = 0; x->x_buffering = 1; } static void udpreceive_tilde_datapoll(t_udpreceive_tilde *x) { int ret; int n; long addr; unsigned short port; struct sockaddr_in from; socklen_t fromlen = sizeof(from); t_tag *tag_ptr; n = x->x_nbytes; if (x->x_nbytes == 0) /* we ate all the samples and need a new header tag */ { tag_ptr = &x->x_frames[x->x_framein].tag; /* receive header tag */ ret = recvfrom(x->x_socket, (char*)tag_ptr, sizeof(t_tag), 0, (struct sockaddr *)&from, &fromlen); /* get the sender's ip */ addr = ntohl(from.sin_addr.s_addr); port = ntohs(from.sin_port); /* output addr/port only if changed */ if (!((addr == x->x_addr)&&(port == x->x_port))) { x->x_addr = addr; x->x_port = port; x->x_addrbytes[0].a_w.w_float = (x->x_addr & 0xFF000000)>>24; x->x_addrbytes[1].a_w.w_float = (x->x_addr & 0x0FF0000)>>16; x->x_addrbytes[2].a_w.w_float = (x->x_addr & 0x0FF00)>>8; x->x_addrbytes[3].a_w.w_float = (x->x_addr & 0x0FF); x->x_addrbytes[4].a_w.w_float = x->x_port; outlet_list(x->x_addrout, &s_list, 5L, x->x_addrbytes); } if (ret <= 0) /* error */ { if (0 == udpreceive_tilde_sockerror("recv tag")) return; udpreceive_tilde_reset(x, 0); return; } else if (ret != sizeof(t_tag)) { /* incomplete header tag: return and try again later */ /* in the hope that more data will be available */ error("udpreceive~: got incomplete header tag"); return; } /* make sure this is really a tag */ if (!((tag_ptr->tag[0] == 'T')&&(tag_ptr->tag[1] == 'A')&&(tag_ptr->tag[2] == 'G')&&(tag_ptr->tag[3] == '!'))) { ++x->x_tag_errors; if (x->x_sync) error("udpreceive~: bad header tag (%d)", x->x_tag_errors); x->x_sync = 0; /* tag length is 16 bytes, a multiple of the data frame size, so eventually we should resync on a tag */ return; } /* adjust byte order if necessary */ tag_ptr->count = ntohl(tag_ptr->count); tag_ptr->framesize = ntohl(tag_ptr->framesize); /* get info from header tag */ if (tag_ptr->channels > (x->x_noutlets-1)) { error("udpreceive~: incoming stream has too many channels (%d)", tag_ptr->channels); x->x_counter = 0; return; } x->x_nbytes = n = tag_ptr->framesize; x->x_sync = 1; } else /* we already have header tag or some data and need more */ { ret = recvfrom(x->x_socket, (char*)x->x_frames[x->x_framein].data + x->x_frames[x->x_framein].tag.framesize - n, n, 0, (struct sockaddr *)&from, &fromlen); if (ret > 0) { n -= ret; } else if (ret < 0) /* error */ { if ( 0 == (ret = udpreceive_tilde_sockerror("recv data"))) return; #ifdef _WIN32 if ( ret == WSAEFAULT) #else if ( ret == EFAULT) #endif { post ("udpreceive~: EFAULT: %p %lu %d", x->x_frames[x->x_framein].data, x->x_frames[x->x_framein].tag.framesize, n); return; } udpreceive_tilde_reset(x, 0); return; } x->x_nbytes = n; if (n == 0) /* a complete packet is received */ { if (x->x_frames[x->x_framein].tag.format == SF_AAC) { error("udpreceive~: don't know how to decode AAC format"); return; } x->x_counter++; x->x_framein++; x->x_framein %= DEFAULT_AUDIO_BUFFER_FRAMES; /* check for buffer overflow */ if (x->x_framein == x->x_frameout) { x->x_overflow++; } } } } static int udpreceive_tilde_createsocket(t_udpreceive_tilde* x, char *address, int portno) { struct sockaddr_in server; struct hostent *hp; int sockfd; int intarg; int multicast_joined = 0; #if defined __APPLE__ || defined _WIN32 struct ip_mreq mreq; #else struct ip_mreqn mreq; #endif if (x->x_socket >= 0) { // close the existing socket first sys_rmpollfn(x->x_socket); sys_closesocket(x->x_socket); } /* create a socket */ sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (sockfd < 0) { udpreceive_tilde_sock_err(x, "udpreceive~: socket"); return 0; } server.sin_family = AF_INET; if (address[0] == 0) server.sin_addr.s_addr = INADDR_ANY; else { hp = gethostbyname(address); if (hp == 0) { pd_error(x, "udpreceive~: bad host?\n"); return 0; } memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length); } /* enable delivery of all multicast or broadcast (but not unicast) * UDP datagrams to all sockets bound to the same port */ intarg = 1; if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&intarg, sizeof(intarg)) < 0) udpreceive_tilde_sock_err(x, "udpreceive~: setsockopt (SO_REUSEADDR) failed"); /* assign server port number */ server.sin_port = htons((u_short)portno); post("udpreceive~: listening to port number %d", portno); udpreceive_tilde_setsocketoptions(sockfd); /* if a multicast address was specified, join the multicast group */ /* hop count defaults to 1 so we won't leave the subnet*/ if (0xE0000000 == (ntohl(server.sin_addr.s_addr) & 0xF0000000)) { server.sin_addr.s_addr = INADDR_ANY; /* first bind the socket to INADDR_ANY */ if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0) { udpreceive_tilde_sock_err(x, "udpreceive~: bind"); sys_closesocket(sockfd); return 0; } /* second join the multicast group */ memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length); #if defined __APPLE__ || defined _WIN32 mreq.imr_multiaddr.s_addr = server.sin_addr.s_addr; mreq.imr_interface.s_addr = INADDR_ANY;/* can put a specific local IP address here if host is multihomed */ #else mreq.imr_multiaddr.s_addr = server.sin_addr.s_addr; mreq.imr_address.s_addr = INADDR_ANY; mreq.imr_ifindex = 0; #endif //__APPLE__ || _WIN32 if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq)) < 0) udpreceive_tilde_sock_err(x, "udpreceive~: setsockopt IP_ADD_MEMBERSHIP"); else { multicast_joined = 1; post ("udpreceive~: added to multicast group"); } } else { /* name the socket */ if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0) { udpreceive_tilde_sock_err(x, "udpreceive~: bind"); CLOSESOCKET(sockfd); return 0; } } x->x_multicast_joined = multicast_joined; x->x_socket = sockfd; x->x_nbytes = 0; sys_addpollfn(x->x_socket, (t_fdpollfn)udpreceive_tilde_datapoll, x); return 1; } /* Queue is 1 to 16 frames long */ #define QUEUESIZE (int)((x->x_framein + DEFAULT_AUDIO_BUFFER_FRAMES - x->x_frameout) % DEFAULT_AUDIO_BUFFER_FRAMES) /* Block is a set of sample vectors inside a frame, one vector per channel */ #define BLOCKOFFSET (x->x_blockssincerecv * x->x_vecsize * x->x_frames[x->x_frameout].tag.channels) static t_int *udpreceive_tilde_perform(t_int *w) { t_udpreceive_tilde *x = (t_udpreceive_tilde*) (w[1]); int n = (int)(w[2]); t_float *out[DEFAULT_AUDIO_CHANNELS]; const int offset = 3; const int channels = x->x_frames[x->x_frameout].tag.channels; int i = 0; x->x_valid = 0; for (i = 0; i < x->x_noutlets; i++) { out[i] = (t_float *)(w[offset + i]); } /* set our vector size to the local vector size */ if (n != x->x_vecsize) { x->x_vecsize = n; x->x_blocksperrecv = x->x_blocksize / x->x_vecsize; x->x_blockssincerecv = 0; } /* check whether there is enough data in buffer */ if (x->x_buffering && (x->x_counter < x->x_maxframes)) { goto bail; } x->x_buffering = 0; /* check for buffer underflow */ if (x->x_framein == x->x_frameout) { x->x_underflow++; goto bail; } x->x_valid = 1; /* queue balancing */ x->x_average[x->x_averagecur] = QUEUESIZE; if (++x->x_averagecur >= DEFAULT_AVERAGE_NUMBER) x->x_averagecur = 0; switch (x->x_frames[x->x_frameout].tag.format) { case SF_FLOAT: { int32_t* buf = (int32_t *)x->x_frames[x->x_frameout].data + BLOCKOFFSET; flint fl; /* swap bytes if necessary */ while (n--) { for (i = 0; i < channels; i++) { fl.i32 = ntohl(*buf++); *out[i]++ = fl.f32; } for (i = channels; i < (x->x_noutlets-1); i++) { *out[i]++ = 0.; } *out[i]++ = x->x_valid; } x->x_error = 0; break; } case SF_16BIT: { short* buf = (short *)x->x_frames[x->x_frameout].data + BLOCKOFFSET; /* swap bytes if necessary */ while (n--) { for (i = 0; i < channels; i++) { *out[i]++ = (t_float)((short)(ntohs(*buf++)) * 3.051850e-05); } for (i = channels; i < (x->x_noutlets-1); i++) { *out[i]++ = 0.; } *out[i]++ = x->x_valid; } x->x_error = 0; break; } case SF_8BIT: { unsigned char* buf = (unsigned char *)x->x_frames[x->x_frameout].data + BLOCKOFFSET; while (n--) { for (i = 0; i < channels; i++) { *out[i]++ = (t_float)((0.0078125 * (*buf++)) - 1.0); } for (i = channels; i < (x->x_noutlets-1); i++) { *out[i]++ = 0.; } *out[i]++ = x->x_valid; } x->x_error = 0; break; } case SF_MP3: { if (x->x_error != 1) { x->x_error = 1; snprintf(x->x_msg, XMSG_SIZE, "udpreceive~: mp3 format not supported"); clock_delay(x->x_clock, 0); } break; } case SF_AAC: { if (x->x_error != 2) { x->x_error = 2; snprintf(x->x_msg, XMSG_SIZE, "udpreceive~: aac format not supported"); clock_delay(x->x_clock, 0); } break; } default: if (x->x_error != 3) { x->x_error = 3; snprintf(x->x_msg, XMSG_SIZE, "udpreceive~: unknown format (%d)",x->x_frames[x->x_frameout].tag.format); clock_delay(x->x_clock, 0); } break; } if (!(x->x_blockssincerecv < x->x_blocksperrecv - 1)) { x->x_blockssincerecv = 0; x->x_frameout++; x->x_frameout %= DEFAULT_AUDIO_BUFFER_FRAMES; } else x->x_blockssincerecv++; return (w + offset + x->x_noutlets); bail: /* set output to zero */ while (n--) for (i = 0; i < x->x_noutlets; i++) *(out[i]++) = 0.; return (w + offset + x->x_noutlets); } static void udpreceive_tilde_dsp(t_udpreceive_tilde *x, t_signal **sp) { int i; x->x_myvec[0] = (t_int*)x; x->x_myvec[1] = (t_int*)sp[0]->s_n; x->x_samplerate = (long)sp[0]->s_sr; if (x->x_blocksize % sp[0]->s_n) { error("udpreceive~: signal vector size too large (needs to be even divisor of %d)", x->x_blocksize); } else { for (i = 0; i < x->x_noutlets; i++) { x->x_myvec[2 + i] = (t_int*)sp[i + 1]->s_vec; } dsp_addv(udpreceive_tilde_perform, x->x_noutlets + 2, (t_int*)x->x_myvec); } } /* send stream info */ static void udpreceive_tilde_info(t_udpreceive_tilde *x) { t_atom list[2]; t_symbol *sf_format; t_float bitrate; int i, avg = 0; for (i = 0; i < DEFAULT_AVERAGE_NUMBER; i++) avg += x->x_average[i]; bitrate = (t_float)((SF_SIZEOF(x->x_frames[x->x_frameout].tag.format) * x->x_samplerate * 8 * x->x_frames[x->x_frameout].tag.channels) / 1000.); switch (x->x_frames[x->x_frameout].tag.format) { case SF_FLOAT: { sf_format = ps_sf_float; break; } case SF_16BIT: { sf_format = ps_sf_16bit; break; } case SF_8BIT: { sf_format = ps_sf_8bit; break; } case SF_MP3: { sf_format = ps_sf_mp3; break; } case SF_AAC: { sf_format = ps_sf_aac; break; } default: { sf_format = ps_sf_unknown; break; } } /* --- stream information (t_tag) --- */ /* audio format */ SETSYMBOL(list, (t_symbol *)sf_format); outlet_anything(x->x_outlet2, ps_format, 1, list); /* channels */ SETFLOAT(list, (t_float)x->x_frames[x->x_frameout].tag.channels); outlet_anything(x->x_outlet2, ps_channels, 1, list); /* framesize */ SETFLOAT(list, (t_float)x->x_frames[x->x_frameout].tag.framesize); outlet_anything(x->x_outlet2, ps_framesize, 1, list); /* bitrate */ SETFLOAT(list, (t_float)bitrate); outlet_anything(x->x_outlet2, ps_bitrate, 1, list); /* --- internal info (buffer and network) --- */ /* overflow */ SETFLOAT(list, (t_float)x->x_overflow); outlet_anything(x->x_outlet2, ps_overflow, 1, list); /* underflow */ SETFLOAT(list, (t_float)x->x_underflow); outlet_anything(x->x_outlet2, ps_underflow, 1, list); /* queuesize */ SETFLOAT(list, (t_float)QUEUESIZE); outlet_anything(x->x_outlet2, ps_queuesize, 1, list); /* average queuesize */ SETFLOAT(list, (t_float)((t_float)avg / (t_float)DEFAULT_AVERAGE_NUMBER)); outlet_anything(x->x_outlet2, ps_average, 1, list); /* total packets */ SETFLOAT(list, (t_float)x->x_counter); outlet_anything(x->x_outlet2, ps_packets, 1, list); /* total tag errors */ SETFLOAT(list, (t_float)x->x_tag_errors); outlet_anything(x->x_outlet2, ps_tag_errors, 1, list); outlet_list(x->x_addrout, &s_list, 5L, x->x_addrbytes); } static void udpreceive_tilde_tick(t_udpreceive_tilde *x) { /* post a message once, outside of perform routine */ post("%s", x->x_msg); } static void *udpreceive_tilde_new(t_symbol *s, int argc, t_atom *argv) { t_udpreceive_tilde *x; int i, j = 0, portno = 0, outlets = 0, blocksize = 0; x = (t_udpreceive_tilde *)pd_new(udpreceive_tilde_class); if (NULL == x) return NULL; for (i = sizeof(t_object); i < (int)sizeof(t_udpreceive_tilde); i++) ((char *)x)[i] = 0; /* do we need to do this?*/ #ifdef DEBUG post("udpreceive_tilde_new:argc is %d s is %s", argc, s->s_name); #endif for (i = 0; i < argc ;++i) { if (argv[i].a_type == A_FLOAT) { // float is taken to be a port number, a channel count, then a buffer size in that order #ifdef DEBUG post ("argv[%d] is a float: %f", i, argv[i].a_w.w_float); #endif if (j == 0) portno = (int)argv[i].a_w.w_float; else if (j == 1) outlets = (int)argv[i].a_w.w_float; else if (j == 2) blocksize = (int)argv[i].a_w.w_float; ++j; } else if (argv[i].a_type == A_SYMBOL) { // symbol is taken to be an ip address (for multicast) #ifdef DEBUG post ("argv[%d] is a symbol: %s", i, argv[i].a_w.w_symbol->s_name); #endif atom_string(&argv[i], x->x_addr_name, 256); } } #ifdef DEBUG post("Setting port %d, address %s", portno, x->addr); #endif if (outlets < 1 || outlets > DEFAULT_AUDIO_CHANNELS) { error("udpreceive~: Number of channels must be between 1 and %d", DEFAULT_AUDIO_CHANNELS); return NULL; } x->x_noutlets = outlets + 1; // extra outlet for valid flag for (i = 0; i < x->x_noutlets; i++) outlet_new(&x->x_obj, &s_signal); x->x_outlet2 = outlet_new(&x->x_obj, &s_anything); x->x_addrout = outlet_new(&x->x_obj, &s_list); for (i = 0; i < 5; ++i) { x->x_addrbytes[i].a_type = A_FLOAT; x->x_addrbytes[i].a_w.w_float = 0; } x->x_addr = 0; x->x_port = 0; x->x_myvec = (t_int **)t_getbytes(sizeof(t_int *) * (x->x_noutlets + 3)); if (!x->x_myvec) { error("udpreceive~: out of memory"); return NULL; } x->x_connectsocket = x->x_socket = -1; x->x_nconnections = x->x_underflow = x->x_overflow = 0; x->x_hostname = ps_nothing; /* allocate space for 16 frames of 1024 X numchannels floats*/ for (i = 0; i < DEFAULT_AUDIO_BUFFER_FRAMES; i++) { x->x_frames[i].data = (char *)t_getbytes(DEFAULT_AUDIO_BUFFER_SIZE * (x->x_noutlets-1) * sizeof(t_float)); } x->x_clock = clock_new(&x->x_obj.ob_pd, (t_method)udpreceive_tilde_tick); x->x_sync = 1; x->x_tag_errors = x->x_framein = x->x_frameout = x->x_valid = 0; x->x_maxframes = DEFAULT_QUEUE_LENGTH; x->x_vecsize = 64; /* we'll update this later */ if (blocksize == 0) x->x_blocksize = DEFAULT_AUDIO_BUFFER_SIZE; else if (DEFAULT_AUDIO_BUFFER_SIZE%(int)blocksize) { error("udpreceive~: blocksize must fit snugly in %d", DEFAULT_AUDIO_BUFFER_SIZE); return NULL; } else x->x_blocksize = blocksize; //DEFAULT_AUDIO_BUFFER_SIZE; /* <-- the only place blocksize is set */ x->x_blockssincerecv = 0; x->x_blocksperrecv = x->x_blocksize / x->x_vecsize; x->x_buffering = 1; if (!udpreceive_tilde_createsocket(x, x->x_addr_name, portno)) { error("udpreceive~: failed to create listening socket"); return NULL; } return (x); } static void udpreceive_tilde_free(t_udpreceive_tilde *x) { int i; if (x->x_connectsocket != -1) { sys_rmpollfn(x->x_connectsocket); CLOSESOCKET(x->x_connectsocket); } if (x->x_socket != -1) { sys_rmpollfn(x->x_socket); CLOSESOCKET(x->x_socket); } /* free memory */ t_freebytes(x->x_myvec, sizeof(t_int *) * (x->x_noutlets + 3)); for (i = 0; i < DEFAULT_AUDIO_BUFFER_FRAMES; i++) { t_freebytes(x->x_frames[i].data, DEFAULT_AUDIO_BUFFER_SIZE * (x->x_noutlets-1) * sizeof(t_float)); } clock_free(x->x_clock); } void udpreceive_tilde_setup(void) { udpreceive_tilde_class = class_new(gensym("udpreceive~"), (t_newmethod) udpreceive_tilde_new, (t_method) udpreceive_tilde_free, sizeof(t_udpreceive_tilde), CLASS_DEFAULT, A_GIMME, 0); class_addmethod(udpreceive_tilde_class, nullfn, gensym("signal"), 0); class_addmethod(udpreceive_tilde_class, (t_method)udpreceive_tilde_info, gensym("info"), 0); class_addmethod(udpreceive_tilde_class, (t_method)udpreceive_tilde_dsp, gensym("dsp"), 0); class_addmethod(udpreceive_tilde_class, (t_method)udpreceive_tilde_reset, gensym("reset"), A_DEFFLOAT, 0); class_addmethod(udpreceive_tilde_class, (t_method)udpreceive_tilde_reset, gensym("buffer"), A_DEFFLOAT, 0); post("udpreceive~ v%s, (c) 2004 Olaf Matthes, 2010 Martin Peach", VERSION); ps_format = gensym("format"); ps_tag_errors = gensym("tag_errors"); ps_channels = gensym("channels"); ps_framesize = gensym("framesize"); ps_bitrate = gensym("bitrate"); ps_overflow = gensym("overflow"); ps_underflow = gensym("underflow"); ps_queuesize = gensym("queuesize"); ps_average = gensym("average"); ps_packets = gensym("packets"); ps_hostname = gensym("ipaddr"); ps_sf_float = gensym("_float_"); ps_sf_16bit = gensym("_16bit_"); ps_sf_8bit = gensym("_8bit_"); ps_sf_mp3 = gensym("_mp3_"); ps_sf_aac = gensym("_aac_"); ps_sf_unknown = gensym("_unknown_"); ps_nothing = gensym(""); } /* error handlers */ static void udpreceive_tilde_sock_err(t_udpreceive_tilde *x, char *err_string) { /* prints the last error from errno or WSAGetLastError() */ #ifdef _WIN32 LPVOID lpMsgBuf; DWORD dwRetVal = WSAGetLastError(); int len = 0, i; char *cp; if (len = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS , NULL, dwRetVal, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&lpMsgBuf, 0, NULL)) { cp = (char *)lpMsgBuf; for(i = 0; i < len; ++i) { if (cp[i] < 0x20) { /* end string at first weird character */ cp[i] = 0; break; } } pd_error(x, "%s: %s (%d)", err_string, lpMsgBuf, dwRetVal); LocalFree(lpMsgBuf); } #else pd_error(x, "%s: %s (%d)", err_string, strerror(errno), errno); #endif } static int udpreceive_tilde_sockerror(char *s) { #ifdef _WIN32 int err = WSAGetLastError(); if (err == 10054) return 1; else if (err == 10040) post("udpreceive~: %s: message too long (%d)", s, err); else if (err == 10053) post("udpreceive~: %s: software caused connection abort (%d)", s, err); else if (err == 10055) post("udpreceive~: %s: no buffer space available (%d)", s, err); else if (err == 10060) post("udpreceive~: %s: connection timed out (%d)", s, err); else if (err == 10061) post("udpreceive~: %s: connection refused (%d)", s, err); else post("udpreceive~: %s: %s (%d)", s, strerror(err), err); #else int err = errno; post("udpreceive~: %s: %s (%d)", s, strerror(err), err); #endif #ifdef _WIN32 if (err == WSAEWOULDBLOCK) #endif #ifndef _WIN32 if (err == EAGAIN) #endif { return 0; /* recoverable error */ } return err; /* indicate non-recoverable error */ } static int udpreceive_tilde_setsocketoptions(int sockfd) { int sockopt = 1; if (setsockopt(sockfd, SOL_IP, TCP_NODELAY, (const char*)&sockopt, sizeof(int)) < 0) post("udpreceive~: setsockopt NODELAY failed"); sockopt = 1; if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&sockopt, sizeof(int)) < 0) post("udpreceive~: setsockopt REUSEADDR failed"); return 0; } /* fin udpreceive~.c */ mrpeach/net/udpreceive-help.pd0000644000175000017500000000400613230146704017123 0ustar zmoelnigzmoelnig#N canvas 12 66 742 431 12; #X floatatom 477 304 3 0 0 0 - - -, f 3; #X floatatom 508 304 3 0 0 0 - - -, f 3; #X floatatom 539 304 3 0 0 0 - - -, f 3; #X floatatom 570 304 3 0 0 0 - - -, f 3; #X obj 222 160 udpreceive 9997; #X floatatom 602 305 5 0 0 0 - - -, f 5; #X obj 477 278 unpack 0 0 0 0 0; #X msg 222 90 status; #X floatatom 339 225 9 0 0 0 - - -, f 9; #X obj 546 227 tgl 15 0 empty empty multicast 18 7 0 12 -4034 -258113 -13381 1 1; #X floatatom 408 251 9 0 0 0 - - -, f 9; #X text 2 90 get status on right outlet:; #X text 215 224 bytes received:; #X text 236 250 total bytes received:; #X text 434 303 from:; #X text 324 78 Specify a multicast address (from 224.0.0.0 to 239.255.255.255) to use multicasting; #X text 48 38 Creation arguments: port number to listen on (required) ; #X obj 222 294 spigot; #X obj 267 274 tgl 15 0 empty empty enable_print: -90 8 0 12 -4034 -258113 -13381 0 1; #X obj 222 319 print received; #X obj 339 192 route received total from multicast; #X text 187 56 IP address to listen on (optional); #X msg 233 129 port 9998; #X text 310 127 change port to listen on; #X text 498 360 Martin Peach 2010/10/15; #X text 0 3 [udpreceive] receives datagrams over a udp connection and outputs them as raw bytes.; #N canvas 529 53 494 344 META 0; #X text 12 155 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; #X text 12 25 LICENSE GPL v2 or later; #X text 12 135 AUTHOR Martin Peach; #X text 12 5 KEYWORDS control network; #X text 12 45 DESCRIPTION receive datagrams over a udp connection and outputs them as raw bytes; #X text 12 75 INLET_0 status port; #X text 12 95 OUTLET_0 anything; #X text 12 115 OUTLET_1 received total from multicast; #X restore 669 396 pd META; #X connect 4 0 17 0; #X connect 4 1 20 0; #X connect 6 0 0 0; #X connect 6 1 1 0; #X connect 6 2 2 0; #X connect 6 3 3 0; #X connect 6 4 5 0; #X connect 7 0 4 0; #X connect 17 0 19 0; #X connect 18 0 17 1; #X connect 20 0 8 0; #X connect 20 1 10 0; #X connect 20 2 6 0; #X connect 20 3 9 0; #X connect 22 0 4 0; mrpeach/net/tcpsend-help.pd0000644000175000017500000000247111650366670016446 0ustar zmoelnigzmoelnig#N canvas 1 53 559 320 12; #X msg 85 175 disconnect; #X msg 13 59 connect 127.0.0.1 9997; #X obj 60 253 tgl 15 0 empty empty connected 20 7 0 8 -24198 -241291 -1 0 1; #X obj 60 230 tcpsend; #X text 217 60 <--first; #X msg 32 83 send 0 1 2 3; #X text 8 7 tcpsend sends bytes over a tcp connection.; #X text 8 30 Used in conjunction with packOSC will send OSC over tcp ; #X msg 50 106 send examples/test.txt; #X obj 385 144 openpanel; #X msg 385 168 send \$1; #X obj 385 125 bng 15 250 50 0 empty empty empty 17 7 0 10 -24198 -241291 -1; #X text 344 105 send a file; #X text 407 124 ...any file; #X text 148 84 send raw data; #X text 137 134 'send' prefix is optional; #X msg 61 133 99 98 97; #X text 291 260 Martin Peach 2007/06/20; #N canvas 507 340 494 344 META 0; #X text 12 125 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; #X text 12 25 LICENSE GPL v2 or later; #X text 12 105 AUTHOR Martin Peach; #X text 12 45 DESCRIPTION send bytes over a tcp connection; #X text 12 65 INLET_0 connect send list disconnect; #X text 12 85 OUTLET_0 float; #X text 12 5 KEYWORDS control network; #X restore 490 290 pd META; #X connect 0 0 3 0; #X connect 1 0 3 0; #X connect 3 0 2 0; #X connect 5 0 3 0; #X connect 8 0 3 0; #X connect 9 0 10 0; #X connect 10 0 3 0; #X connect 11 0 9 0; #X connect 16 0 3 0; mrpeach/net/tcpsocket.OSC-help.pd0000644000175000017500000000022511650367742017424 0ustar zmoelnigzmoelnig#N canvas 171 298 450 300 10; #X obj 178 123 tcpsocket.OSC; #X text 79 81 This is a support object for; #X obj 252 81 pddp/helplink tcpsocketserver; mrpeach/net/tcpsocket.FUDI.pd0000644000175000017500000001052411522100264016562 0ustar zmoelnigzmoelnig#N canvas 585 75 446 533 10; #X obj 50 49 == \$2; #X obj 7 28 route in socket; #X obj 7 76 spigot; #N canvas 622 183 512 335 reset 0; #X obj 23 41 route \$2; #X obj 23 63 route reset; #X obj 23 83 t b b; #X msg 55 170 done; #X obj 23 113 outlet; #X text 161 33 this is used to:; #X text 87 114 a) reset the sockethandler on a new connection; #X text 88 129 (for instance \, if the previous connection was quitted in the middle of a packet).; #X text 55 213 b) check for the socketserver \, if a sockethandler on specified socket already exists.; #X obj 55 191 s \$1.TCPSOCKET; #X obj 23 19 r \$1.TCPSOCKET; #X connect 0 0 1 0; #X connect 1 0 2 0; #X connect 2 0 4 0; #X connect 2 1 3 0; #X connect 3 0 9 0; #X connect 10 0 0 0; #X restore 46 102 pd reset; #X obj 105 279 route socket ip; #X obj 41 367 list append; #X obj 58 323 list append; #X obj 7 299 t a b b b; #X obj 7 414 list prepend out; #X obj 41 391 list prepend socket.out; #X obj 58 345 list prepend ip.out; #X obj 7 442 list trim; #X text 16 220 the lower part makes [tcpsocketserver] behave like [tcpserver] ; #X obj -2 136 cnv 15 450 70 empty empty empty 20 12 0 14 -204786 -66577 0; #N canvas 385 67 606 479 FUDI 0; #X obj 23 6 inlet; #X obj 23 400 outlet; #N canvas 389 242 191 341 serialize 0; #X obj 5 100 t a a; #X obj 37 122 list prepend 0; #X obj 37 143 s \$0.inbuffer; #X obj 5 174 list length; #X obj 5 218 until; #X obj 5 195 t a b; #X obj 5 241 f; #X obj 50 244 + 1; #X msg 49 218 0; #X obj 5 267 tabread \$0.inbuffer; #X obj 5 50 inlet; #X obj 5 289 outlet; #X obj 5 12 table \$0.inbuffer 8192; #N canvas 294 258 396 232 list_serialize_raw 0; #X obj 13 73 until; #X obj 13 97 list append; #X obj 13 47 t b a; #X obj 13 23 inlet; #X obj 13 169 outlet; #X obj 13 121 list split 8192; #X obj 141 106 b; #X text 12 190 cut incoming list into pieces of a maximum of the buffersize. ; #X connect 0 0 1 0; #X connect 1 0 5 0; #X connect 2 0 0 0; #X connect 2 1 1 1; #X connect 3 0 2 0; #X connect 5 0 4 0; #X connect 5 1 1 1; #X connect 5 2 6 0; #X connect 5 2 4 0; #X connect 6 0 0 1; #X restore 5 74 pd list_serialize_raw; #X connect 0 0 3 0; #X connect 0 1 1 0; #X connect 1 0 2 0; #X connect 3 0 5 0; #X connect 4 0 6 0; #X connect 5 0 4 0; #X connect 5 1 8 0; #X connect 6 0 7 0; #X connect 6 0 9 0; #X connect 7 0 6 1; #X connect 8 0 6 1; #X connect 9 0 11 0; #X connect 10 0 13 0; #X connect 13 0 0 0; #X restore 23 30 pd serialize; #X obj 23 109 t a a; #X obj 97 297 list prepend; #X obj 195 296 t a; #X obj 23 327 list append; #X obj 23 350 t a b; #X obj 160 56 inlet; #X text 210 56 reset; #X obj 23 53 sel 10 13; #X msg 23 76 32; #X obj 23 219 sel 59; #X obj 178 264 b; #X obj 23 373 list append 10; #X obj 23 149 sel 92; #X msg 23 171 -1; #X obj 62 171 t a a; #X msg 62 193 59; #X text 119 182 <-; #X text 144 176 separate by 59 (semicolon) \, but ignore semicolons prepended by 92 (backslash); #X connect 0 0 2 0; #X connect 2 0 10 0; #X connect 3 0 15 0; #X connect 3 1 4 0; #X connect 4 0 5 0; #X connect 4 0 6 1; #X connect 5 0 4 1; #X connect 6 0 7 0; #X connect 7 0 14 0; #X connect 7 1 6 1; #X connect 7 1 4 1; #X connect 8 0 13 0; #X connect 10 0 11 0; #X connect 10 1 11 0; #X connect 10 2 3 0; #X connect 11 0 3 0; #X connect 12 0 6 0; #X connect 13 0 4 1; #X connect 13 0 6 1; #X connect 14 0 1 0; #X connect 15 0 16 0; #X connect 15 1 17 0; #X connect 16 0 12 1; #X connect 17 0 18 0; #X connect 17 1 12 0; #X connect 18 0 12 1; #X restore 7 161 pd FUDI; #X text 70 162 <- PUT HERE THE PROTOCOL SPECIFIC DELIMITER CODE; #X text 15 197 -------------------------------------------------------- ; #X text 12 129 -------------------------------------------------------- ; #X obj 7 6 r \$1.TCPSOCKET; #X obj 7 465 s \$1.TCPSOCKET; #X obj 105 255 r \$1.TCPSOCKET; #X text 200 454 Author: Roman Haefeli; #X text 50 74 <- only pass stream of own socket; #X text 201 474 Version: 2009-02-02; #X connect 0 0 2 1; #X connect 1 0 2 0; #X connect 1 1 0 0; #X connect 2 0 14 0; #X connect 3 0 14 1; #X connect 4 0 5 1; #X connect 4 1 6 1; #X connect 5 0 9 0; #X connect 6 0 10 0; #X connect 7 0 8 0; #X connect 7 2 5 0; #X connect 7 3 6 0; #X connect 8 0 11 0; #X connect 9 0 11 0; #X connect 10 0 11 0; #X connect 11 0 19 0; #X connect 14 0 7 0; #X connect 18 0 1 0; #X connect 20 0 4 0; mrpeach/net/udpreceive~-help.pd0000644000175000017500000000554011650367251017333 0ustar zmoelnigzmoelnig#N canvas 221 129 767 415 10; #N canvas 874 257 494 344 META 0; #X text 12 155 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; #X text 12 25 LICENSE GPL v2 or later; #X text 12 135 AUTHOR Martin Peach; #X text 12 5 KEYWORDS control network; #X text 12 45 DESCRIPTION receive datagrams over a udp connection and outputs them as a signal; #X restore 695 379 pd META; #X obj 522 267 print udpreceive~; #X symbolatom 177 354 10 0 0 0 - - -; #X floatatom 211 288 5 0 0 0 - - -; #X floatatom 246 267 7 0 0 0 - - -; #X floatatom 280 332 9 0 0 0 - - -; #X obj 177 313 prepend set; #X text 147 287 channels:; #X text 131 353 format:; #X text 231 331 bitrate:; #X text 182 266 framesize:; #X floatatom 315 289 9 0 0 0 - - -; #X floatatom 349 267 9 0 0 0 - - -; #X floatatom 384 310 5 0 0 0 - - -; #X floatatom 418 289 5 0 0 0 - - -; #X text 258 288 overflow:; #X text 289 266 underflow:; #X text 323 309 queuesize:; #X text 370 288 average:; #X msg 35 58 info; #X msg 15 38 reset; #X text 68 57 status info to rightmost outlet; #X text 53 37 reset underflow & overflow counters; #X floatatom 210 169 3 0 0 0 - - -; #X floatatom 233 169 3 0 0 0 - - -; #X floatatom 256 169 3 0 0 0 - - -; #X floatatom 279 169 3 0 0 0 - - -; #X floatatom 303 169 5 0 0 0 - - -; #X obj 210 143 unpack 0 0 0 0 0; #X text 173 168 from:; #X obj 82 152 dac~ 1 2; #X floatatom 453 332 9 0 0 0 - - -; #X text 401 331 packets:; #X text 348 142 To communicate \, a [udpreceive~] and [udpsend~] pair must have the same number of channels and the same blocksize. Also [udpsend~] must [connect( to the port on which [udpreceive~] is listening. ; #X msg 56 79 buffer 2; #X text 118 78 set number of frames to buffer before playback; #X obj 177 230 route format channels framesize bitrate overflow underflow queuesize average packets tag_errors; #X floatatom 487 310 9 0 0 0 - - -; #X text 421 309 tag errors:; #X obj 144 181 env~; #X floatatom 144 204 9 0 0 0 - - -; #X text 204 193 The rightmost signal outlet outputs 1 if the stream is valid \, else 0; #X text 420 77 Arguments: port \, channels \, blocksize \, multicast_address. Blocksize should match [udpsend~]. multicast_address is optional. Arguments must be in that order.; #X obj 81 121 udpreceive~ 9999 2 512; #X text 221 120 receives 2 channels on port 9999 Same blocksize as udpsend~; #X connect 6 0 2 0; #X connect 19 0 43 0; #X connect 20 0 43 0; #X connect 28 0 23 0; #X connect 28 1 24 0; #X connect 28 2 25 0; #X connect 28 3 26 0; #X connect 28 4 27 0; #X connect 34 0 43 0; #X connect 36 0 6 0; #X connect 36 1 3 0; #X connect 36 2 4 0; #X connect 36 3 5 0; #X connect 36 4 11 0; #X connect 36 5 12 0; #X connect 36 6 13 0; #X connect 36 7 14 0; #X connect 36 8 31 0; #X connect 36 9 37 0; #X connect 36 10 1 0; #X connect 39 0 40 0; #X connect 43 0 30 0; #X connect 43 1 30 1; #X connect 43 2 39 0; #X connect 43 3 36 0; #X connect 43 4 28 0; mrpeach/net/tcpserver.c0000644000175000017500000015373212520743523015714 0ustar zmoelnigzmoelnig/* tcpserver.c Martin Peach 20100508 */ /* with contributions from Ivica Ico Bukvic */ /* and IOhannes Zmoelnig zmoelnig@iem.at */ /* tcpserver.c is based on netserver by Olaf Matthes : */ /* -------------------------- netserver ------------------------------------- */ /* */ /* A server for bidirectional communication from within Pd. */ /* Allows to send back data to specific clients connected to the server. */ /* Written by Olaf Matthes */ /* Get source at http://www.akustische-kunst.org/puredata/maxlib */ /* */ /* This program is free software; you can redistribute it and/or */ /* modify it under the terms of the GNU General Public License */ /* as published by the Free Software Foundation; either version 2 */ /* of the License, or (at your option) any later version. */ /* */ /* This program is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with this program; if not, write to the Free Software */ /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* */ /* Based on PureData by Miller Puckette and others. */ /* */ /* ---------------------------------------------------------------------------- */ //define DEBUG #include "m_pd.h" #include "m_imp.h" #include "s_stuff.h" #include #include #include #ifndef _WIN32 #include #include #include #include #include #include #include #include #include #include #include /* linux has the SIOCOUTQ ioctl */ #define SOCKET_ERROR -1 #else #include #include /* for socklen_t */ #endif /* support older Pd versions without sys_open(), sys_fopen(), sys_fclose() */ #if PD_MAJOR_VERSION == 0 && PD_MINOR_VERSION < 44 #define sys_open open #define sys_fopen fopen #define sys_fclose fclose #endif #ifdef _MSC_VER #define snprintf sprintf_s #endif #define MAX_CONNECT 1024 /* maximum number of connections to reserve space for */ #define INBUFSIZE 65536L /* was 4096: size of receiving data buffer */ #define MAX_UDP_RECEIVE 65536L /* longer than data in maximum UDP packet */ /* ----------------------------- tcpserver ------------------------- */ static t_class *tcpserver_class; static char objName[] = "tcpserver"; typedef void (*t_tcpserver_socketnotifier)(void *x); typedef void (*t_tcpserver_socketreceivefn)(void *x, t_binbuf *b); typedef struct _tcpserver_socketreceiver { t_symbol *sr_host; int sr_fd; int sr_fdbuf; u_long sr_addr; unsigned char *sr_inbuf; int sr_inhead; int sr_intail; void *sr_owner; t_tcpserver_socketnotifier sr_notifier; t_tcpserver_socketreceivefn sr_socketreceivefn; } t_tcpserver_socketreceiver; typedef struct _tcpserver_send_params { int client; int sockfd; char *byte_buf; size_t length; int verbosity; } t_tcpserver_send_params; typedef struct _tcpserver { t_object x_obj; t_outlet *x_msgout; t_outlet *x_connectout; t_outlet *x_sockout; t_outlet *x_addrout; t_outlet *x_status_outlet; int x_dump; // 1 = hexdump received bytes t_tcpserver_socketreceiver *x_sr[MAX_CONNECT]; t_atom x_addrbytes[4]; int x_sock_fd; int x_connectsocket; int x_port; int x_nconnections; int x_blocked; int x_verbosity; t_atom x_msgoutbuf[MAX_UDP_RECEIVE]; char x_msginbuf[MAX_UDP_RECEIVE]; } t_tcpserver; typedef struct _tcpserver_broadcast_params { t_tcpserver *x; int argc; t_atom argv[MAX_UDP_RECEIVE]; } t_tcpserver_broadcast_params; static t_tcpserver_socketreceiver *tcpserver_socketreceiver_new(void *owner, t_tcpserver_socketnotifier notifier, t_tcpserver_socketreceivefn socketreceivefn); static int tcpserver_socketreceiver_doread(t_tcpserver_socketreceiver *x); static void tcpserver_socketreceiver_read(t_tcpserver_socketreceiver *x, int fd); static void tcpserver_socketreceiver_free(t_tcpserver_socketreceiver *x); static void tcpserver_send(t_tcpserver *x, t_symbol *s, int argc, t_atom *argv); static void tcpserver_send_bytes(int sockfd, t_tcpserver *x, int argc, t_atom *argv); #ifdef SIOCOUTQ static int tcpserver_send_buffer_avaliable_for_client(t_tcpserver *x, int client); #endif static void *tcpserver_send_buf_thread(void *arg); static void *tcpserver_broadcast_thread(void *arg); static void tcpserver_client_send(t_tcpserver *x, t_symbol *s, int argc, t_atom *argv); static void tcpserver_output_client_state(t_tcpserver *x, int client); static int tcpserver_get_socket_send_buf_size(int sockfd); static int tcpserver_set_socket_send_buf_size(int sockfd, int size); static void tcpserver_buf_size(t_tcpserver *x, t_symbol *s, int argc, t_atom *argv); static void tcpserver_disconnect(t_tcpserver *x); static void tcpserver_client_disconnect(t_tcpserver *x, t_floatarg fclient); static void tcpserver_socket_disconnect(t_tcpserver *x, t_floatarg fsocket); static void tcpserver_verbosity(t_tcpserver *x, t_floatarg verbosity_level); static void tcpserver_broadcast(t_tcpserver *x, t_symbol *s, int argc, t_atom *argv); static void tcpserver_notify(t_tcpserver *x); static void tcpserver_connectpoll(t_tcpserver *x); static void tcpserver_print(t_tcpserver *x); static void tcpserver_unblock(t_tcpserver *x); static void *tcpserver_new(t_floatarg fportno); static void tcpserver_port(t_tcpserver *x, t_floatarg fportno); static void tcpserver_free(t_tcpserver *x); void tcpserver_setup(void); static void tcpserver_dump(t_tcpserver *x, t_float dump); static void tcpserver_hexdump(unsigned char *buf, long len, int verbosity); static void tcpserver_verbosity(t_tcpserver *x, t_floatarg verbosity_level) { x->x_verbosity = verbosity_level; if (x->x_verbosity > 0) post("tcpserver_verbosity now %d", x->x_verbosity); } static void tcpserver_dump(t_tcpserver *x, t_float dump) { x->x_dump = (dump == 0)?0:1; } static void tcpserver_hexdump(unsigned char *buf, long len, int verbosity) { #define BYTES_PER_LINE 16 char hexStr[(3*BYTES_PER_LINE)+1]; char ascStr[BYTES_PER_LINE+1]; long i, j, k = 0L; if (verbosity > 0) post("tcpserver_hexdump of %d bytes", len); while (k < len) { for (i = j = 0; i < BYTES_PER_LINE; ++i, ++k, j+=3) { if (k < len) { snprintf(&hexStr[j], 4, "%02X ", buf[k]); snprintf(&ascStr[i], 2, "%c", ((buf[k] >= 32) && (buf[k] <= 126))? buf[k]: '.'); } else { // the last line snprintf(&hexStr[j], 4, " "); snprintf(&ascStr[i], 2, " "); } } post ("%s%s", hexStr, ascStr); } } static t_tcpserver_socketreceiver *tcpserver_socketreceiver_new(void *owner, t_tcpserver_socketnotifier notifier, t_tcpserver_socketreceivefn socketreceivefn) { t_tcpserver_socketreceiver *x = (t_tcpserver_socketreceiver *)getbytes(sizeof(*x)); if (!x) { error("%s_socketreceiver: unable to allocate %zu bytes", objName, sizeof(*x)); } else { x->sr_inhead = x->sr_intail = 0; x->sr_owner = owner; x->sr_notifier = notifier; x->sr_socketreceivefn = socketreceivefn; if (!(x->sr_inbuf = malloc(INBUFSIZE))) { freebytes(x, sizeof(*x)); x = NULL; error("%s_socketreceiver: unable to allocate %ld bytes", objName, INBUFSIZE); } } return (x); } /* this is in a separately called subroutine so that the buffer isn't sitting on the stack while the messages are getting passed. */ static int tcpserver_socketreceiver_doread(t_tcpserver_socketreceiver *x) { char messbuf[INBUFSIZE]; char *bp = messbuf; int indx, i; int inhead = x->sr_inhead; int intail = x->sr_intail; unsigned char c; t_tcpserver *y = x->sr_owner; unsigned char *inbuf = x->sr_inbuf; if (intail == inhead) return (0); if (y->x_verbosity > 1) post ("%s_socketreceiver_doread: intail=%d inhead=%d", objName, intail, inhead); for (indx = intail, i = 0; indx != inhead; indx = (indx+1)&(INBUFSIZE-1), ++i) { c = *bp++ = inbuf[indx]; y->x_msgoutbuf[i].a_w.w_float = (float)c; } if (y->x_dump)tcpserver_hexdump(&inbuf[intail], i, y->x_verbosity); if (i > 1) outlet_list(y->x_msgout, &s_list, i, y->x_msgoutbuf); else outlet_float(y->x_msgout, y->x_msgoutbuf[0].a_w.w_float); // intail = (indx+1)&(INBUFSIZE-1); x->sr_inhead = inhead; x->sr_intail = indx;//intail; return (1); } static void tcpserver_socketreceiver_read(t_tcpserver_socketreceiver *x, int fd) { int readto = (x->sr_inhead >= x->sr_intail ? INBUFSIZE : x->sr_intail-1); int ret, i; t_tcpserver *y = x->sr_owner; y->x_sock_fd = fd; /* the input buffer might be full. If so, drop the whole thing */ if (readto == x->sr_inhead) { if (y->x_verbosity > 0) post("%s: dropped message", objName); x->sr_inhead = x->sr_intail = 0; readto = INBUFSIZE; } else { ret = recv(fd, x->sr_inbuf + x->sr_inhead, readto - x->sr_inhead, 0); if (ret < 0) { sys_sockerror("tcpserver: recv"); if (x->sr_notifier) (*x->sr_notifier)(x->sr_owner); sys_rmpollfn(fd); sys_closesocket(fd); } else if (ret == 0) { if (y->x_verbosity > 0) post("%s: connection closed on socket %d", objName, fd); if (x->sr_notifier) (*x->sr_notifier)(x->sr_owner); sys_rmpollfn(fd); sys_closesocket(fd); } else { if (y->x_verbosity > 1) post ("%s_socketreceiver_read: received %d byte%s", objName, ret, (ret==1)?"":"s"); x->sr_inhead += ret; if (x->sr_inhead >= INBUFSIZE) x->sr_inhead = 0; /* output client's IP and socket no. */ for(i = 0; i < y->x_nconnections; i++) /* search for corresponding IP */ { if(y->x_sr[i]->sr_fd == y->x_sock_fd) { /* find sender's ip address and output it */ y->x_addrbytes[0].a_w.w_float = (y->x_sr[i]->sr_addr & 0xFF000000)>>24; y->x_addrbytes[1].a_w.w_float = (y->x_sr[i]->sr_addr & 0x0FF0000)>>16; y->x_addrbytes[2].a_w.w_float = (y->x_sr[i]->sr_addr & 0x0FF00)>>8; y->x_addrbytes[3].a_w.w_float = (y->x_sr[i]->sr_addr & 0x0FF); outlet_list(y->x_addrout, &s_list, 4L, y->x_addrbytes); break; } } outlet_float(y->x_sockout, y->x_sock_fd); /* the socket number */ tcpserver_socketreceiver_doread(x); } } } static void tcpserver_socketreceiver_free(t_tcpserver_socketreceiver *x) { t_tcpserver *y = x->sr_owner; if (y->x_verbosity > 1) post("tcpserver_socketreceiver_free x=%p", x); if (x != NULL) { if (NULL != x->sr_inbuf) { if (y->x_verbosity > 1) post("tcpserver_socketreceiver_free freeing x->sr_inbuf %p", x->sr_inbuf); free(x->sr_inbuf); x->sr_inbuf = NULL; } freebytes(x, sizeof(*x)); } } /* ---------------- main tcpserver (send) stuff --------------------- */ static void tcpserver_send_bytes(int client, t_tcpserver *x, int argc, t_atom *argv) { static char byte_buf[MAX_UDP_RECEIVE];// arbitrary maximum similar to max IP packet size int i, j, d; unsigned char c; float f, e; int length; size_t flen = 0; int sockfd = x->x_sr[client]->sr_fd; char fpath[FILENAME_MAX]; FILE *fptr; t_atom output_atom[3]; t_tcpserver_send_params *ttsp; pthread_t sender_thread; pthread_attr_t sender_attr = {{0}}; int sender_thread_result; /* process & send data */ if(sockfd >= 0) { if (x->x_blocked > 0) goto failed; /* sender thread should start out detached so its resouces will be freed when it is done */ if (0!= (sender_thread_result = pthread_attr_init(&sender_attr))) { error("%s: pthread_attr_init failed: %d", objName, sender_thread_result); goto failed; } if(0!= (sender_thread_result = pthread_attr_setdetachstate(&sender_attr, PTHREAD_CREATE_DETACHED))) { error("%s: pthread_attr_setdetachstate failed: %d", objName, sender_thread_result); goto failed; } for (i = j = 0; i < argc; ++i) { if (argv[i].a_type == A_FLOAT) { /* load floats into buffer as long as they are integers on [0..255]*/ f = argv[i].a_w.w_float; d = (int)f; e = f - d; if (x->x_verbosity > 2) post("%s: argv[%d]: float:%f int:%d delta:%f", objName, i, f, d, e); if (e != 0) { error("%s: item %d (%f) is not an integer", objName, i, f); goto failed; } if ((d < 0) || (d > 255)) { error("%s: item %d (%f) is not between 0 and 255", objName, i, f); goto failed; } c = (unsigned char)d; /* make sure it doesn't become negative; this only matters for post() */ if (x->x_verbosity > 2) post("%s: argv[%d]: %d", objName, i, c); byte_buf[j++] = c; if (j >= MAX_UDP_RECEIVE) { /* if the argument list is longer than our buffer, send the buffer whenever it's full */ #ifdef SIOCOUTQ if (tcpserver_send_buffer_avaliable_for_client(x, client) < j) { error("%s: buffer too small for client(%d)", objName, client); goto failed; } #endif // SIOCOUTQ ttsp = (t_tcpserver_send_params *)getbytes(sizeof(t_tcpserver_send_params)); if (ttsp == NULL) { error("%s: unable to allocate %zu bytes for t_tcpserver_send_params", objName, sizeof(t_tcpserver_send_params)); goto failed; } ttsp->client = client; ttsp->sockfd = sockfd; ttsp->byte_buf = byte_buf; ttsp->length = j; ttsp->verbosity = x->x_verbosity; if (0 != (sender_thread_result = pthread_create(&sender_thread, &sender_attr, tcpserver_send_buf_thread, (void *)ttsp))) { ++x->x_blocked; error("%s: couldn't create sender thread (%d)", objName, sender_thread_result); if (NULL != ttsp) { freebytes (ttsp, sizeof (t_tcpserver_send_params)); ttsp = NULL; } goto failed; } flen += j; j = 0; } } else if (argv[i].a_type == A_SYMBOL) { /* symbols are interpreted to be file names; attempt to load the file and send it */ atom_string(&argv[i], fpath, FILENAME_MAX); if (x->x_verbosity > 2) post ("%s: fname: %s", objName, fpath); fptr = sys_fopen(fpath, "rb"); if (fptr == NULL) { error("%s: unable to open \"%s\"", objName, fpath); goto failed; } rewind(fptr); while ((d = fgetc(fptr)) != EOF) { if (x->x_verbosity > 2) post("%s: d is %d", objName, d); byte_buf[j++] = (char)(d & 0x0FF); if (x->x_verbosity > 2) post("%s: byte_buf[%d] = %d", objName, j-1, byte_buf[j-1]); if (j >= MAX_UDP_RECEIVE) { /* if the file is longer than our buffer, send the buffer whenever it's full */ /* this might be better than allocating huge amounts of memory */ #ifdef SIOCOUTQ if (tcpserver_send_buffer_avaliable_for_client(x, client) < j) { error("%s: buffer too small for client(%d)", objName, client); goto failed; } #endif // SIOCOUTQ ttsp = (t_tcpserver_send_params *)getbytes(sizeof(t_tcpserver_send_params)); if (ttsp == NULL) { error("%s: unable to allocate %zu bytes for t_tcpserver_send_params", objName, sizeof(t_tcpserver_send_params)); goto failed; } ttsp->client = client; ttsp->sockfd = sockfd; ttsp->byte_buf = byte_buf; ttsp->length = j; ttsp->verbosity = x->x_verbosity; if ( 0!= (sender_thread_result = pthread_create(&sender_thread, &sender_attr, tcpserver_send_buf_thread, (void *)ttsp))) { ++x->x_blocked; error("%s: couldn't create sender thread (%d)", objName, sender_thread_result); if (NULL != ttsp) { freebytes (ttsp, sizeof (t_tcpserver_send_params)); ttsp = NULL; } goto failed; } flen += j; j = 0; } } flen += j; sys_fclose(fptr); fptr = NULL; if (x->x_verbosity > 0) post("%s: read \"%s\" length %d byte%s", objName, fpath, flen, ((d==1)?"":"s")); } else { /* arg was neither a float nor a valid file name */ error("%s: item %d is not a float or a file name", objName, i); goto failed; } } length = j; if (length > 0) { /* send whatever remains in our buffer */ #ifdef SIOCOUTQ if (tcpserver_send_buffer_avaliable_for_client(x, client) < length) { error("%s: buffer too small for client(%d)", objName, client); goto failed; } #endif // SIOCOUTQ ttsp = (t_tcpserver_send_params *)getbytes(sizeof(t_tcpserver_send_params)); if (ttsp == NULL) { error("%s: unable to allocate %zu bytes for t_tcpserver_send_params", objName, sizeof(t_tcpserver_send_params)); goto failed; } ttsp->client = client; ttsp->sockfd = sockfd; ttsp->byte_buf = byte_buf; ttsp->length = length; ttsp->verbosity = x->x_verbosity; if ( 0!= (sender_thread_result = pthread_create(&sender_thread, &sender_attr, tcpserver_send_buf_thread, (void *)ttsp))) { ++x->x_blocked; error("%s: couldn't create sender thread (%d)", objName, sender_thread_result); if (NULL != ttsp) { freebytes (ttsp, sizeof (t_tcpserver_send_params)); ttsp = NULL; } goto failed; } flen += length; } } else post("%s: not a valid socket number (%d)", objName, sockfd); failed: if (0!= (sender_thread_result = pthread_attr_destroy(&sender_attr))) { error("%s_broadcast: pthread_attr_destroy failed: %d", objName, sender_thread_result); } SETFLOAT(&output_atom[0], client+1); SETFLOAT(&output_atom[1], flen); SETFLOAT(&output_atom[2], sockfd); if(x->x_blocked) outlet_anything( x->x_status_outlet, gensym("blocked"), 3, output_atom); else outlet_anything( x->x_status_outlet, gensym("sent"), 3, output_atom); } #ifdef SIOCOUTQ /* SIOCOUTQ exists only(?) on linux, returns remaining space in the socket's output buffer */ static int tcpserver_send_buffer_avaliable_for_client(t_tcpserver *x, int client) { int sockfd = x->x_sr[client].sr_fd; int result = 0L; ioctl(sockfd, SIOCOUTQ, &result); return result; } #endif // SIOCOUTQ // send a buffer in its own thread static void *tcpserver_send_buf_thread(void *arg) { t_tcpserver_send_params *ttsp = (t_tcpserver_send_params *)arg; int result; result = send(ttsp->sockfd, ttsp->byte_buf, ttsp->length, 0); if (result <= 0) { sys_sockerror("tcpserver: send"); if (ttsp->verbosity > 0) post("%s_send_buf: could not send data to client %d", objName, ttsp->client+1); } if (NULL != arg) freebytes (arg, sizeof (t_tcpserver_send_params)); return NULL; } /* send message to client using socket number */ static void tcpserver_send(t_tcpserver *x, t_symbol *s, int argc, t_atom *argv) { int i, sockfd; int client = -1; if(x->x_nconnections <= 0) { if (x->x_verbosity > 0) post("%s_send: no clients connected", objName); return; } if(argc == 0) /* no socket specified: output state of all sockets */ { tcpserver_output_client_state(x, client); return; } /* get socket number of connection (first element in list) */ if(argv[0].a_type == A_FLOAT) { sockfd = atom_getfloatarg(0, argc, argv); for(i = 0; i < x->x_nconnections; i++) /* check if connection exists */ { if(x->x_sr[i]->sr_fd == sockfd) { client = i; /* the client we're sending to */ break; } } if(client == -1) { if (x->x_verbosity > 0) post("%s_send: no connection on socket %d", objName, sockfd); return; } } else { if (x->x_verbosity > 0) post("%s_send: no socket specified", objName); return; } if (argc < 2) /* nothing to send: output state of this socket */ { tcpserver_output_client_state(x, client+1); return; } tcpserver_send_bytes(client, x, argc-1, &argv[1]); } /* disconnect the client at x_sock_fd */ static void tcpserver_disconnect(t_tcpserver *x) { int i, fd; t_tcpserver_socketreceiver *y; if (x->x_sock_fd >= 0) { /* find the socketreceiver for this socket */ for(i = 0; i < x->x_nconnections; i++) { if(x->x_sr[i]->sr_fd == x->x_sock_fd) { y = x->x_sr[i]; fd = y->sr_fd; if (y->sr_notifier) (*y->sr_notifier)(x); sys_rmpollfn(fd); sys_closesocket(fd); x->x_sock_fd = -1; return; } } } if (x->x_verbosity > 0) post("%s__disconnect: no connection on socket %d", objName, x->x_sock_fd); } /* disconnect a client by socket */ static void tcpserver_socket_disconnect(t_tcpserver *x, t_floatarg fsocket) { int sock = (int)fsocket; if(x->x_nconnections <= 0) { if (x->x_verbosity > 0) post("%s_socket_disconnect: no clients connected", objName); return; } x->x_sock_fd = sock; tcpserver_disconnect(x); } /* disconnect a client by number */ static void tcpserver_client_disconnect(t_tcpserver *x, t_floatarg fclient) { int client = (int)fclient; if(x->x_nconnections <= 0) { if (x->x_verbosity > 0) post("%s_client_disconnect: no clients connected", objName); return; } if (!((client > 0) && (client < MAX_CONNECT))) { if (x->x_verbosity > 0) post("%s: client %d out of range [1..%d]", objName, client, MAX_CONNECT); return; } --client;/* zero based index*/ x->x_sock_fd = x->x_sr[client]->sr_fd; tcpserver_disconnect(x); } /* send message to client using client number note that the client numbers might change in case a client disconnects! */ /* clients start at 1 but our index starts at 0 */ static void tcpserver_client_send(t_tcpserver *x, t_symbol *s, int argc, t_atom *argv) { int client = -1; if(x->x_nconnections <= 0) { if (x->x_verbosity > 0) post("%s_client_send: no clients connected", objName); return; } if(argc > 0) { /* get number of client (first element in list) */ if(argv[0].a_type == A_FLOAT) client = atom_getfloatarg(0, argc, argv); else { if (x->x_verbosity > 0) post("%s_client_send: specify client by number", objName); return; } if (!((client > 0) && (client < MAX_CONNECT))) { if (x->x_verbosity > 0) post("%s_client_send: client %d out of range [1..%d]", objName, client, MAX_CONNECT); return; } } if (argc > 1) { --client;/* zero based index*/ tcpserver_send_bytes(client, x, argc-1, &argv[1]); return; } tcpserver_output_client_state(x, client); } static void tcpserver_output_client_state(t_tcpserver *x, int client) { t_atom output_atom[4]; if (client == -1) { /* output parameters of all connections via status outlet */ for(client = 0; client < x->x_nconnections; client++) { x->x_sr[client]->sr_fdbuf = tcpserver_get_socket_send_buf_size(x->x_sr[client]->sr_fd); SETFLOAT(&output_atom[0], client+1); SETFLOAT(&output_atom[1], x->x_sr[client]->sr_fd); output_atom[2].a_type = A_SYMBOL; output_atom[2].a_w.w_symbol = x->x_sr[client]->sr_host; SETFLOAT(&output_atom[3], x->x_sr[client]->sr_fdbuf); outlet_anything( x->x_status_outlet, gensym("client"), 4, output_atom); } } else { client -= 1;/* zero-based client index conflicts with 1-based user index !!! */ if (client < x->x_nconnections) { // only if there is such a client /* output client parameters via status outlet */ x->x_sr[client]->sr_fdbuf = tcpserver_get_socket_send_buf_size(x->x_sr[client]->sr_fd); SETFLOAT(&output_atom[0], client+1);/* user sees client 0 as 1 */ SETFLOAT(&output_atom[1], x->x_sr[client]->sr_fd); output_atom[2].a_type = A_SYMBOL; output_atom[2].a_w.w_symbol = x->x_sr[client]->sr_host; SETFLOAT(&output_atom[3], x->x_sr[client]->sr_fdbuf); outlet_anything( x->x_status_outlet, gensym("client"), 4, output_atom); } else if (x->x_verbosity > 0) post("%s: no such client (%d)", objName, client+1); } } /* Return the send buffer size of socket */ static int tcpserver_get_socket_send_buf_size(int sockfd) { int optVal = 0; unsigned int optLen = sizeof(int); #ifdef _WIN32 if (getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char*)&optVal, &optLen) == SOCKET_ERROR) post("%_get_socket_send_buf_size: getsockopt returned %d\n", objName, WSAGetLastError()); #else if (getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char*)&optVal, &optLen) == -1) post("%_get_socket_send_buf_size: getsockopt returned %d\n", objName, errno); #endif return optVal; } /* Set the send buffer size of socket, returns actual size */ static int tcpserver_set_socket_send_buf_size(int sockfd, int size) { int optVal = size; int optLen = sizeof(int); #ifdef _WIN32 if (setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char*)&optVal, optLen) == SOCKET_ERROR) { post("%s_set_socket_send_buf_size: setsockopt returned %d\n", objName, WSAGetLastError()); #else if (setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char*)&optVal, optLen) == -1) { post("%s_set_socket_send_buf_size: setsockopt returned %d\n", objName, errno); #endif return 0; } else return (tcpserver_get_socket_send_buf_size(sockfd)); } /* Get/set the send buffer of client socket */ static void tcpserver_buf_size(t_tcpserver *x, t_symbol *s, int argc, t_atom *argv) { int client = -1; float buf_size = 0; // t_atom output_atom[3]; if(x->x_nconnections <= 0) { if (x->x_verbosity > 0) post("%s_buf_size: no clients connected", objName); return; } /* get number of client (first element in list) */ if (argc > 0) { if (argv[0].a_type == A_FLOAT) client = atom_getfloatarg(0, argc, argv); else { if (x->x_verbosity > 0) post("%s_buf_size: specify client by number", objName); return; } if (!((client > 0) && (client < MAX_CONNECT))) { if (x->x_verbosity > 0) post("%s__buf_size: client %d out of range [1..%d]", objName, client, MAX_CONNECT); return; } } if (argc > 1) { if (argv[1].a_type != A_FLOAT) { if (x->x_verbosity > 0) post("%s_buf_size: specify buffer size with a float", objName); return; } buf_size = atom_getfloatarg(1, argc, argv); --client;/* zero based index*/ x->x_sr[client]->sr_fdbuf = tcpserver_set_socket_send_buf_size(x->x_sr[client]->sr_fd, (int)buf_size); if (x->x_verbosity > 0) post("%s_buf_size: client %d set to %d", objName, client+1, x->x_sr[client]->sr_fdbuf); return; } if (x->x_verbosity > 0) post("%s_buf_size: specify client and buffer size", objName); return; } /* broadcasts messages to all clients */ /* Ivica Ico Bukvic 5/6/10 rewrote broadcast to be xrun-free */ static void *tcpserver_broadcast_thread(void *arg) { t_tcpserver_broadcast_params *ttbp = (t_tcpserver_broadcast_params *)arg; int client; static char byte_buf[MAX_UDP_RECEIVE];// arbitrary maximum similar to max IP packet size int i, j, d; unsigned char c; float f, e; int length; size_t flen = 0; int sockfd = 0; char fpath[FILENAME_MAX]; FILE *fptr; // t_atom output_atom[3]; // t_tcpserver_send_params *ttsp; // pthread_t sender_thread; // pthread_attr_t sender_attr; // int sender_thread_result; int result; for (i = j = 0; i < ttbp->argc; ++i) { if (ttbp->argv[i].a_type == A_FLOAT) { /* load floats into buffer as long as they are integers on [0..255]*/ f = ttbp->argv[i].a_w.w_float; d = (int)f; e = f - d; if (ttbp->x->x_verbosity > 1) post("%s: argv[%d]: float:%f int:%d delta:%f", objName, i, f, d, e); if (e != 0) { error("%s_broadcast_thread: item %d (%f) is not an integer", objName, i, f); if (NULL != arg) freebytes (arg, sizeof (t_tcpserver_broadcast_params)); return NULL; } if ((d < 0) || (d > 255)) { error("%s_broadcast_thread: item %d (%f) is not between 0 and 255", objName, i, f); if (NULL != arg) freebytes (arg, sizeof (t_tcpserver_broadcast_params)); return NULL; } c = (unsigned char)d; /* make sure it doesn't become negative; this only matters for post() */ if (ttbp->x->x_verbosity > 1) post("%s_broadcast_thread: argv[%d]: %d", objName, i, c); byte_buf[j++] = c; if (j >= MAX_UDP_RECEIVE) { /* if the argument list is longer than our buffer, send the buffer whenever it's full */ //LOOP /* enumerate through the clients and send each the message */ for(client = 0; client < ttbp->x->x_nconnections; client++) /* check if connection exists */ { #ifdef SIOCOUTQ if (tcpserver_send_buffer_avaliable_for_client(ttbp->x, client) < j) { error("%s_broadcast_thread: buffer too small for client(%d)", objName, client); if (NULL != arg) freebytes (arg, sizeof (t_tcpserver_broadcast_params)); return NULL; } #endif // SIOCOUTQ if(ttbp->x->x_sr[client]->sr_fd >= 0) { /* socket exists for this client */ sockfd = ttbp->x->x_sr[client]->sr_fd; result = send(sockfd, byte_buf, j, 0); if (result <= 0) { sys_sockerror("tcpserver_broadcast_thread: send"); if (ttbp->x->x_verbosity > 0) post("%s_broadcast_thread: could not send data to client %d", objName, client+1); if (NULL != arg) freebytes (arg, sizeof (t_tcpserver_broadcast_params)); return NULL; } } } flen += j; j = 0; } } else if (ttbp->argv[i].a_type == A_SYMBOL) { /* symbols are interpreted to be file names; attempt to load the file and send it */ atom_string(&ttbp->argv[i], fpath, FILENAME_MAX); if (ttbp->x->x_verbosity > 1) post ("%s_broadcast_thread: fname: %s", objName, fpath); fptr = sys_fopen(fpath, "rb"); if (fptr == NULL) { error("%s_broadcast_thread: unable to open \"%s\"", objName, fpath); if (NULL != arg) freebytes (arg, sizeof (t_tcpserver_broadcast_params)); return NULL; } rewind(fptr); while ((d = fgetc(fptr)) != EOF) { if (ttbp->x->x_verbosity > 1) post("%s_broadcast_thread: d is %d", objName, d); byte_buf[j++] = (char)(d & 0x0FF); if (ttbp->x->x_verbosity > 1) post("%s_broadcast_thread: byte_buf[%d] = %d", objName, j-1, byte_buf[j-1]); if (j >= MAX_UDP_RECEIVE) { /* if the file is longer than our buffer, send the buffer whenever it's full */ //LOOP /* enumerate through the clients and send each the message */ for(client = 0; client < ttbp->x->x_nconnections; client++) /* check if connection exists */ { /* this might be better than allocating huge amounts of memory */ #ifdef SIOCOUTQ if (tcpserver_send_buffer_avaliable_for_client(x, client) < j) { error("%s_broadcast_thread: buffer too small for client(%d)", objName, client); if (NULL != arg) freebytes (arg, sizeof (t_tcpserver_broadcast_params)); return NULL; } #endif // SIOCOUTQ if(ttbp->x->x_sr[client]->sr_fd >= 0) { /* socket exists for this client */ sockfd = ttbp->x->x_sr[client]->sr_fd; result = send(sockfd, byte_buf, j, 0); if (result <= 0) { sys_sockerror("tcpserver_broadcast_thread: send"); if (ttbp->x->x_verbosity > 1) post("%s_broadcast_thread: could not send data to client %d", objName, client+1); if (NULL != arg) freebytes (arg, sizeof (t_tcpserver_broadcast_params)); return NULL; } } } flen += j; j = 0; } } flen += j; sys_fclose(fptr); fptr = NULL; if (ttbp->x->x_verbosity > 1) post("%s_broadcast_thread: read \"%s\" length %d byte%s", objName, fpath, flen, ((d==1)?"":"s")); } else { /* arg was neither a float nor a valid file name */ error("%s_broadcast_thread: item %d is not a float or a file name", objName, i); if (NULL != arg) freebytes (arg, sizeof (t_tcpserver_broadcast_params)); return NULL; } } length = j; if (length > 0) { /* send whatever remains in our buffer */ /* enumerate through the clients and send each the message */ for(client = 0; client < ttbp->x->x_nconnections; client++) /* check if connection exists */ { #ifdef SIOCOUTQ if (tcpserver_send_buffer_avaliable_for_client(x, client) < length) { error("%s_broadcast_thread: buffer too small for client(%d)", objName, client); if (NULL != arg) freebytes (arg, sizeof (t_tcpserver_broadcast_params)); return NULL; } #endif // SIOCOUTQ if(ttbp->x->x_sr[client]->sr_fd >= 0) { /* socket exists for this client */ sockfd = ttbp->x->x_sr[client]->sr_fd; result = send(sockfd, byte_buf, length, 0); if (result <= 0) { sys_sockerror("tcpserver_broadcast_thread: send"); if (ttbp->x->x_verbosity > 0) post("%s_broadcast_thread: could not send data to client %d", objName, client+1); if (NULL != arg) freebytes (arg, sizeof (t_tcpserver_broadcast_params)); return NULL; } } } flen += length; } else if (ttbp->x->x_verbosity > 0) post("%s_broadcast_thread: not a valid socket number (%d)", objName, sockfd); if (NULL != arg) freebytes (arg, sizeof (t_tcpserver_broadcast_params)); return NULL; } static void tcpserver_broadcast(t_tcpserver *x, t_symbol *s, int argc, t_atom *argv) /* initializes separate thread that broadcasts to all clients */ /* Ivica Ico Bukvic 5/6/10 rewrote broadcast to be xrun-free */ { int i; t_tcpserver_broadcast_params *ttbp; pthread_t broadcast_thread; pthread_attr_t broadcast_attr = {{0}}; int broadcast_thread_result; if (x->x_nconnections != 0) { /* sender thread should start out detached so its resouces will be freed when it is done */ if (0!= (broadcast_thread_result = pthread_attr_init(&broadcast_attr))) { error("%s_broadcast: pthread_attr_init failed: %d", objName, broadcast_thread_result); } else { if(0 != (broadcast_thread_result = pthread_attr_setdetachstate(&broadcast_attr, PTHREAD_CREATE_DETACHED))) { error("%s_broadcast: pthread_attr_setdetachstate failed: %d", objName, broadcast_thread_result); } else { ttbp = (t_tcpserver_broadcast_params *)getbytes(sizeof(t_tcpserver_broadcast_params)); if (ttbp == NULL) { error("%s_broadcast: unable to allocate %zu bytes for t_tcpserver_broadcast_params", objName, sizeof(t_tcpserver_broadcast_params)); } else { ttbp->x = x; ttbp->argc = argc; for (i = 0; i < argc; i++) ttbp->argv[i] = argv[i]; if (0 != (broadcast_thread_result = pthread_create(&broadcast_thread, &broadcast_attr, tcpserver_broadcast_thread, (void *)ttbp))) { error("%s_broadcast: couldn't create broadcast thread (%d)", objName, broadcast_thread_result); if (NULL != ttbp) { freebytes (ttbp, sizeof (t_tcpserver_broadcast_params)); ttbp = NULL; } } } } if (0!= (broadcast_thread_result = pthread_attr_destroy(&broadcast_attr))) { error("%s_broadcast: pthread_attr_destroy failed: %d", objName, broadcast_thread_result); } } } } /* ---------------- main tcpserver (receive) stuff --------------------- */ /* tcpserver_notify is called when socket has closed */ static void tcpserver_notify(t_tcpserver *x) { int i, k; /* remove connection from list */ for(i = 0; i < x->x_nconnections; i++) { if(x->x_sr[i]->sr_fd == x->x_sock_fd) { x->x_nconnections--; /* Ivica Ico Bukvic :*/ x->x_addrbytes[0].a_w.w_float = (x->x_sr[i]->sr_addr & 0xFF000000)>>24; x->x_addrbytes[1].a_w.w_float = (x->x_sr[i]->sr_addr & 0x0FF0000)>>16; x->x_addrbytes[2].a_w.w_float = (x->x_sr[i]->sr_addr & 0x0FF00)>>8; x->x_addrbytes[3].a_w.w_float = (x->x_sr[i]->sr_addr & 0x0FF); outlet_list(x->x_addrout, &s_list, 4L, x->x_addrbytes); outlet_float(x->x_sockout, x->x_sr[i]->sr_fd); /* the socket number */ outlet_float(x->x_connectout, x->x_nconnections); /* /Ivica Ico Bukvic */ if (x->x_verbosity > 0) post("%s: \"%s\" removed from list of clients", objName, x->x_sr[i]->sr_host->s_name); tcpserver_socketreceiver_free(x->x_sr[i]); x->x_sr[i] = NULL; /* rearrange list now: move entries to close the gap */ for(k = i; k < x->x_nconnections; k++) { x->x_sr[k] = x->x_sr[k + 1]; } } } // ico outlet_float(x->x_connectout, x->x_nconnections); } static void tcpserver_connectpoll(t_tcpserver *x) { struct sockaddr_in incomer_address; unsigned int sockaddrl = sizeof( struct sockaddr ); int fd; int i; int optVal; unsigned int optLen = sizeof(int); if (MAX_CONNECT <= x->x_nconnections) { /* no more free space for t_tcpserver_socketreceiver pointers, maybe increase MAX_CONNECT? */ if (x->x_verbosity > 0) post("%s: too many connections (MAX_CONNECT is %d)", objName, x->x_nconnections); return; } fd = accept(x->x_connectsocket, (struct sockaddr*)&incomer_address, &sockaddrl); if ((fd < 0)&&(x->x_verbosity > 1)) post("%s: accept failed", objName); else { t_tcpserver_socketreceiver *y = tcpserver_socketreceiver_new((void *)x, (t_tcpserver_socketnotifier)tcpserver_notify, NULL);/* MP tcpserver_doit isn't used I think...*/ if (!y) { #ifdef _WIN32 closesocket(fd); #else close(fd); #endif return; } sys_addpollfn(fd, (t_fdpollfn)tcpserver_socketreceiver_read, y); x->x_nconnections++; i = x->x_nconnections - 1; x->x_sr[i] = y; x->x_sr[i]->sr_host = gensym(inet_ntoa(incomer_address.sin_addr)); x->x_sr[i]->sr_fd = fd; if (x->x_verbosity > 0) post("%s: accepted connection from %s on socket %d (client %d)", objName, x->x_sr[i]->sr_host->s_name, x->x_sr[i]->sr_fd, i+1); /* see how big the send buffer is on this socket */ x->x_sr[i]->sr_fdbuf = 0; #ifdef _WIN32 if (getsockopt(x->x_sr[i]->sr_fd, SOL_SOCKET, SO_SNDBUF, (char*)&optVal, &optLen) != SOCKET_ERROR) { /* post("%s_connectpoll: send buffer is %ld\n", objName, optVal); */ x->x_sr[i]->sr_fdbuf = optVal; } else if (x->x_verbosity > 1) post("%s_connectpoll: getsockopt returned %d\n", objName, WSAGetLastError()); #else if (getsockopt(x->x_sr[i]->sr_fd, SOL_SOCKET, SO_SNDBUF, (char*)&optVal, &optLen) == 0) { /* post("%s_connectpoll: send buffer is %ld\n", objName, optVal); */ x->x_sr[i]->sr_fdbuf = optVal; } else if (x->x_verbosity > 1) post("%s_connectpoll: getsockopt returned %d\n", objName, errno); #endif x->x_sr[i]->sr_addr = ntohl(incomer_address.sin_addr.s_addr); x->x_addrbytes[0].a_w.w_float = (x->x_sr[i]->sr_addr & 0xFF000000)>>24; x->x_addrbytes[1].a_w.w_float = (x->x_sr[i]->sr_addr & 0x0FF0000)>>16; x->x_addrbytes[2].a_w.w_float = (x->x_sr[i]->sr_addr & 0x0FF00)>>8; x->x_addrbytes[3].a_w.w_float = (x->x_sr[i]->sr_addr & 0x0FF); outlet_list(x->x_addrout, &s_list, 4L, x->x_addrbytes); outlet_float(x->x_sockout, x->x_sr[i]->sr_fd); /* the socket number */ outlet_float(x->x_connectout, x->x_nconnections); } } static void tcpserver_print(t_tcpserver *x) { int i; if(x->x_nconnections > 0) { post("%s: %d open connections:", objName, x->x_nconnections); for(i = 0; i < x->x_nconnections; i++) { post(" \"%s\" on socket %d", x->x_sr[i]->sr_host->s_name, x->x_sr[i]->sr_fd); } } else post("%s: no open connections", objName); } static void tcpserver_unblock(t_tcpserver *x) { x->x_blocked = 0; } static void tcpserver_port(t_tcpserver*x, t_floatarg fportno) { t_atom output_atom; int portno = fportno; struct sockaddr_in server; socklen_t serversize = sizeof(server); int sockfd = x->x_connectsocket; int optVal = 1; int optLen = sizeof(int); if(x->x_port == portno) return; if(x->x_nconnections > 0) { if (x->x_verbosity > 0) post ("%s: can't change port (connection count is %d)", objName, x->x_nconnections); return; } SETFLOAT(&output_atom, -1); /* shut down the old socket */ if (sockfd >= 0) { sys_rmpollfn(sockfd); sys_closesocket(sockfd); x->x_connectsocket = -1; x->x_port = -1; } /* create a whole new socket */ sockfd = socket(AF_INET, SOCK_STREAM, 0); if (x->x_verbosity > 1) post("%s: receive socket %d", objName, sockfd); if (sockfd < 0) { sys_sockerror("tcpserver: socket"); return; } server.sin_family = AF_INET; server.sin_addr.s_addr = INADDR_ANY; /* enable reuse of local address */ #ifdef _WIN32 if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char*)&optVal, optLen) == SOCKET_ERROR) #else if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char*)&optVal, optLen) == -1) #endif sys_sockerror("tcpserver: setsockopt SO_REUSEADDR"); /* assign server port number */ server.sin_port = htons((u_short)portno); /* name the socket */ if (bind(sockfd, (struct sockaddr *)&server, serversize) < 0) { sys_sockerror("tcpserver: bind"); sys_closesocket(sockfd); outlet_anything(x->x_status_outlet, gensym("port"), 1, &output_atom); return; } /* streaming protocol */ if (listen(sockfd, 5) < 0) { sys_sockerror("tcpserver: listen"); sys_closesocket(sockfd); sockfd = -1; outlet_anything(x->x_status_outlet, gensym("port"), 1, &output_atom); return; } else { sys_addpollfn(sockfd, (t_fdpollfn)tcpserver_connectpoll, x); // wait for new connections } x->x_connectsocket = sockfd; x->x_nconnections = 0; x->x_blocked = 0; // find out which port is actually used (useful when assigning "0") if(!getsockname(sockfd, (struct sockaddr *)&server, &serversize)) { x->x_port=ntohs(server.sin_port); } SETFLOAT(&output_atom, x->x_port); outlet_anything(x->x_status_outlet, gensym("port"), 1, &output_atom); } static void *tcpserver_new(t_floatarg fportno) { t_tcpserver *x; int i; struct sockaddr_in server; int sockfd, portno = fportno; int optVal = 1; int optLen = sizeof(int); /* create a socket */ sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { sys_sockerror("tcpserver: socket"); return (0); } server.sin_family = AF_INET; server.sin_addr.s_addr = INADDR_ANY; /* enable reuse of local address */ #ifdef _WIN32 if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char*)&optVal, optLen) == SOCKET_ERROR) #else if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char*)&optVal, optLen) == -1) #endif sys_sockerror("tcpserver: setsockopt SO_REUSEADDR"); /* assign server port number */ server.sin_port = htons((u_short)portno); /* name the socket */ if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0) { sys_sockerror("tcpserver: bind"); sys_closesocket(sockfd); return (0); } x = (t_tcpserver *)pd_new(tcpserver_class); x->x_msgout = outlet_new(&x->x_obj, &s_anything); /* 1st outlet for received data */ /* streaming protocol */ if (listen(sockfd, 5) < 0) { sys_sockerror("tcpserver: listen"); sys_closesocket(sockfd); sockfd = -1; } else { sys_addpollfn(sockfd, (t_fdpollfn)tcpserver_connectpoll, x); x->x_connectout = outlet_new(&x->x_obj, &s_float); /* 2nd outlet for number of connected clients */ x->x_sockout = outlet_new(&x->x_obj, &s_float); /* 3rd outlet for socket number of current client */ x->x_addrout = outlet_new(&x->x_obj, &s_list); /* 4th outlet for ip address of current client */ x->x_status_outlet = outlet_new(&x->x_obj, &s_anything);/* 5th outlet for everything else */ } x->x_connectsocket = sockfd; x->x_nconnections = 0; x->x_blocked = 0; for(i = 0; i < MAX_CONNECT; i++) { x->x_sr[i] = NULL; } /* prepare to convert the bytes in the buffer to floats in a list */ for (i = 0; i < MAX_UDP_RECEIVE; ++i) { x->x_msgoutbuf[i].a_type = A_FLOAT; x->x_msgoutbuf[i].a_w.w_float = 0; } for (i = 0; i < 4; ++i) { x->x_addrbytes[i].a_type = A_FLOAT; x->x_addrbytes[i].a_w.w_float = 0; } x->x_port = portno; post ("tcpserver listening on port %d, socket %d", x->x_port, sockfd); x->x_verbosity = 0; // stop talking to console unless we're asked return (x); } static void tcpserver_free(t_tcpserver *x) { int i; if (x->x_verbosity > 1) post("tcp_server_free..."); for(i = 0; i < MAX_CONNECT; i++) { if (x->x_sr[i] != NULL) { if (x->x_verbosity > 1) post("tcp_server_free...freeing client %d", i+1); if (x->x_sr[i]->sr_fd >= 0) { if (x->x_verbosity > 1) post("tcp_server_free...freeing fd %d", x->x_sr[i]->sr_fd); sys_rmpollfn(x->x_sr[i]->sr_fd); // sometimes is not found as poll function was already removed sys_closesocket(x->x_sr[i]->sr_fd); } tcpserver_socketreceiver_free(x->x_sr[i]); x->x_sr[i] = NULL; } } if (x->x_connectsocket >= 0) { if (x->x_verbosity > 1) post("tcp_server_free...freeing connectsocket %d", x->x_connectsocket); sys_rmpollfn(x->x_connectsocket); sys_closesocket(x->x_connectsocket); } if (x->x_verbosity > 1) post("tcp_server_free end"); } void tcpserver_setup(void) { tcpserver_class = class_new(gensym(objName),(t_newmethod)tcpserver_new, (t_method)tcpserver_free, sizeof(t_tcpserver), 0, A_DEFFLOAT, 0); class_addmethod(tcpserver_class, (t_method)tcpserver_print, gensym("print"), 0); class_addmethod(tcpserver_class, (t_method)tcpserver_send, gensym("send"), A_GIMME, 0); class_addmethod(tcpserver_class, (t_method)tcpserver_client_send, gensym("client"), A_GIMME, 0); class_addmethod(tcpserver_class, (t_method)tcpserver_buf_size, gensym("clientbuf"), A_GIMME, 0); class_addmethod(tcpserver_class, (t_method)tcpserver_client_disconnect, gensym("disconnectclient"), A_DEFFLOAT, 0); class_addmethod(tcpserver_class, (t_method)tcpserver_socket_disconnect, gensym("disconnectsocket"), A_DEFFLOAT, 0); class_addmethod(tcpserver_class, (t_method)tcpserver_dump, gensym("dump"), A_FLOAT, 0); class_addmethod(tcpserver_class, (t_method)tcpserver_unblock, gensym("unblock"), 0); class_addmethod(tcpserver_class, (t_method)tcpserver_broadcast, gensym("broadcast"), A_GIMME, 0); class_addmethod(tcpserver_class, (t_method)tcpserver_port, gensym("port"), A_FLOAT, 0); class_addmethod(tcpserver_class, (t_method)tcpserver_verbosity, gensym("verbosity"), A_DEFFLOAT, 0); class_addlist(tcpserver_class, (t_method)tcpserver_send); } /* end of tcpserver.c */ mrpeach/net/tcpserver-help.pd0000644000175000017500000001543412277240173017021 0ustar zmoelnigzmoelnig#N canvas 4 103 1272 816 12; #X msg 39 -10 print; #X floatatom 404 376 5 0 0 0 - - -; #X floatatom 428 426 5 0 0 0 - - -; #X obj 452 377 unpack 0 0 0 0; #X floatatom 452 400 3 0 0 0 - - -; #X floatatom 483 400 3 0 0 0 - - -; #X floatatom 515 400 3 0 0 0 - - -; #X floatatom 549 400 3 0 0 0 - - -; #X text 409 399 from; #X text 320 376 connections; #X obj 381 501 print received; #X msg 135 86 client 1 1 2 3; #X msg 63 14 broadcast 1 2 3; #X text 91 -9 list of connections; #X text 186 14 send to all clients; #X text 358 426 on socket; #X msg -11 -60 send 504 1 2 3; #X text 100 -65 send to client on socket 504; #X msg 647 -209 client 1 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19; #X msg 647 -186 client 1 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39; #X msg 647 -148 client 1 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59; #X msg 647 -110 client 1 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79; #X msg 647 -72 client 1 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99; #X msg 647 -34 client 1 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119; #X msg 647 4 client 1 120 121 122 123 124 125 126 127 138 139 140 141 142 143 144 145 146 147 148 149; #X msg 647 42 client 1 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169; #X msg 647 80 client 1 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189; #X msg 647 118 client 1 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209; #X msg 647 156 client 1 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229; #X msg 647 194 client 1 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249; #X msg 647 232 client 1 250 251 252 253 254 255; #X obj 40 -177 openpanel; #X obj 40 -196 bng 15 250 50 0 empty empty choose_a_file 17 7 0 10 -24198 -241291 -1; #X text 24 -157 ...any file; #X msg -108 -157 client 1 \$1; #X msg 14 -35 10 1 2 43; #X text 98 -48 'send' prefix is optional; #X text 88 -31 (the first number is socket number); #X msg -41 -90 disconnectsocket \$1; #X msg -84 -133 disconnectclient \$1; #X obj 647 257 s toserver; #X obj 376 327 r toserver; #X floatatom 143 -172 5 0 0 0 - - -; #X obj 121 -153 f; #X obj 121 -172 bng 15 250 50 0 empty empty empty 17 7 0 10 -258699 -241291 -1; #X floatatom 185 -129 5 0 0 0 - - -; #X obj 163 -110 f; #X obj 163 -129 bng 15 250 50 0 empty empty empty 17 7 0 10 -258699 -241291 -1; #X text -109 -110 disconnect by socket or client number; #X text 488 351 argument is port number; #X text 52 353 Received messages are output as lists of bytes; #X text -9 457 ***WARNING*** Attempting to print long messages can hang pd!; #X obj 381 479 spigot; #X obj 420 459 tgl 15 0 empty empty enable_print 17 7 0 10 -24198 -258699 -45076 0 1; #X msg 159 110 dump \$1; #X obj -17 95 tgl 15 0 empty empty enable_dump 17 7 0 10 -4034 -257985 -1 0 1; #X text -85 45 dump received; #X text -85 61 characters to main; #X text -85 76 window in hexdump; #X text -85 92 format:; #X obj 381 352 tcpserver 9997; #X msg -132 -181 client 1 test.txt; #X text 647 -234 [tcpserver] sends and receives bytes on [0...255] ; #X text 158 -217 [tcpserver] waits for clients to connect to its port. ; #X text -137 -202 send a file to client 1; #X msg 183 134 client 1 72 101 108 108 111 13 10; #X floatatom 638 437 9 0 0 0 - - -; #X obj 770 396 print status; #X floatatom 598 460 5 0 0 0 - - -; #X text 528 459 to_client; #X msg 111 62 client; #X msg 88 39 client 1; #X text 156 38 get state of client 1; #X text 249 86 send (binary) 1 2 3 to client 1; #X floatatom 772 529 5 0 0 0 - - -; #X symbolatom 804 502 20 0 0 0 - - -; #X floatatom 741 502 5 0 0 0 - - -; #X text 705 436 bytes; #X text 598 436 sent; #X msg 209 160 clientbuf 1 65536; #X obj 741 478 unpack 0 0 s 0; #X floatatom 836 550 7 0 0 0 - - -; #X text 681 550 length of send buffer:; #X text 721 528 socket:; #X text 690 501 client:; #X text 781 501 ip:; #X text 339 159 set send-buffer size for client 1; #X text 163 62 get state of all clients (list on right outlet); #X obj 598 411 unpack 0 0 0; #X floatatom 679 478 5 0 0 0 - - -; #X text 609 477 on_socket; #X msg 233 184 send; #X msg 258 209 1156; #X text 276 183 output 'client' message for all sockets; #X text 298 209 output 'client' message for socket 1156; #X msg 283 234 unblock; #X obj 598 372 route sent client blocked; #X text -143 233 If sending too many messages blocks the system \, tcpserver will stop sending until it receives an unblock message; #X obj 712 419 print blocked; #N canvas 530 81 494 344 META 0; #X text 12 225 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; #X text 12 205 AUTHOR Martin Peach; #X text 12 25 LICENSE GPL v2 or later; #X text 12 5 KEYWORDS control network; #X text 12 45 DESCRIPTION wait for clients to connect to its port; #X text 12 65 INLET_0 float list client disconnectclient disconnectsocket send print broadcast dump clientbuf unblock; #X text 12 105 OUTLET_0 anything; #X text 12 125 OUTLET_1 float; #X text 12 145 OUTLET_2 float; #X text 12 165 OUTLET_3 list; #X text 12 185 OUTLET_4 sent client blocked; #X restore 899 458 pd META; #X msg 354 305 port 12345; #X text 436 304 change listening port (only if no connections are active) ; #X msg 332 283 verbosity \$1; #X obj 332 263 hradio 15 1 0 4 empty empty empty 0 -8 0 10 -1 -4034 -1 0; #X text 425 281 set verbosity level; #X text -9 536 2014/02/13 Martin Peach; #X connect 0 0 60 0; #X connect 3 0 4 0; #X connect 3 1 5 0; #X connect 3 2 6 0; #X connect 3 3 7 0; #X connect 11 0 60 0; #X connect 12 0 60 0; #X connect 16 0 60 0; #X connect 18 0 40 0; #X connect 19 0 40 0; #X connect 20 0 40 0; #X connect 21 0 40 0; #X connect 22 0 40 0; #X connect 23 0 40 0; #X connect 24 0 40 0; #X connect 25 0 40 0; #X connect 26 0 40 0; #X connect 27 0 40 0; #X connect 28 0 40 0; #X connect 29 0 40 0; #X connect 30 0 40 0; #X connect 31 0 34 0; #X connect 32 0 31 0; #X connect 34 0 60 0; #X connect 35 0 60 0; #X connect 38 0 60 0; #X connect 39 0 60 0; #X connect 41 0 60 0; #X connect 42 0 43 1; #X connect 43 0 39 0; #X connect 44 0 43 0; #X connect 45 0 46 1; #X connect 46 0 38 0; #X connect 47 0 46 0; #X connect 52 0 10 0; #X connect 53 0 52 1; #X connect 54 0 60 0; #X connect 55 0 54 0; #X connect 60 0 52 0; #X connect 60 1 1 0; #X connect 60 2 2 0; #X connect 60 3 3 0; #X connect 60 4 96 0; #X connect 61 0 60 0; #X connect 65 0 60 0; #X connect 70 0 60 0; #X connect 71 0 60 0; #X connect 79 0 60 0; #X connect 80 0 76 0; #X connect 80 1 74 0; #X connect 80 2 75 0; #X connect 80 3 81 0; #X connect 88 0 68 0; #X connect 88 1 66 0; #X connect 88 2 89 0; #X connect 91 0 60 0; #X connect 92 0 60 0; #X connect 95 0 60 0; #X connect 96 0 88 0; #X connect 96 1 80 0; #X connect 96 2 98 0; #X connect 96 3 67 0; #X connect 100 0 60 0; #X connect 102 0 60 0; #X connect 103 0 102 0; mrpeach/net/udpsend~.c0000644000175000017500000011023711650353765015540 0ustar zmoelnigzmoelnig/* udpsend~ started by Martin Peach on 20100110, based on netsend~ */ /* udpsend~ sends audio via udp only.*/ /* It is a PD external, all Max stuff has been removed from the source */ /* ------------------------ netsend~ ------------------------------------------ */ /* */ /* Tilde object to send uncompressed audio data to netreceive~. */ /* Written by Olaf Matthes . */ /* Based on streamout~ by Guenter Geiger. */ /* Get source at http://www.akustische-kunst.org/ */ /* */ /* This program is free software; you can redistribute it and/or */ /* modify it under the terms of the GNU General Public License */ /* as published by the Free Software Foundation; either version 2 */ /* of the License, or (at your option) any later version. */ /* */ /* See file LICENSE for further informations on licensing terms. */ /* */ /* This program is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with this program; if not, write to the Free Software */ /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* */ /* Based on PureData by Miller Puckette and others. */ /* */ /* This project was commissioned by the Society for Arts and Technology [SAT], */ /* Montreal, Quebec, Canada, http://www.sat.qc.ca/. */ /* */ /* ---------------------------------------------------------------------------- */ #include "m_pd.h" #include "udpsend~.h" #include #include #include #include #ifndef _WIN32 #include #include #include #include #include // for SIOCGIFCONF #include // for SIOCGIFCONF #include #include #include #include #include #include #include #include #define SOCKET_ERROR -1 #endif #ifdef __APPLE__ #include #endif #ifdef _WIN32 #include #include #include // for interface addresses #include "pthread.h" #endif #ifdef MSG_NOSIGNAL #define SEND_FLAGS /*MSG_DONTWAIT|*/MSG_NOSIGNAL #else #define SEND_FLAGS 0 #endif #ifndef SOL_IP #define SOL_IP IPPROTO_IP #endif /* ------------------------ udpsend~ ----------------------------- */ static t_class *udpsend_tilde_class; static t_symbol *ps_nothing, *ps_localhost, *ps_vecsize; static t_symbol *ps_format, *ps_channels, *ps_framesize; static t_symbol *ps_sf_float, *ps_sf_16bit, *ps_sf_8bit; static t_symbol *ps_sf_unknown, *ps_bitrate, *ps_hostname; typedef struct _udpsend_tilde { t_object x_obj; t_outlet *x_outlet; t_outlet *x_outlet2; t_clock *x_clock; int x_fd; unsigned int x_multicast_loop_state; unsigned int x_multicast_ttl; /* time to live for multicast */ t_tag x_tag; t_symbol* x_hostname; int x_portno; int x_connectstate; char *x_cbuf; int x_cbufsize; int x_blocksize; /* set to DEFAULT_AUDIO_BUFFER_SIZE or user-supplied argument 3 in udpsend_tilde_new() */ int x_blockspersend; /* set to x->x_blocksize / x->x_vecsize in udpsend_tilde_perform() */ int x_blockssincesend; long x_samplerate; /* samplerate we're running at */ int x_vecsize; /* current DSP signal vector size */ int x_ninlets; /* number of inlets */ int x_channels; /* number of channels we want to stream */ int x_format; /* format of streamed audio data */ int x_count; /* total number of audio frames */ t_int **x_myvec; /* vector we pass on in the DSP routine */ pthread_mutex_t x_mutex; pthread_t x_childthread; /* a thread to initiate a connection to the remote port */ pthread_attr_t x_childthread_attr; /* child thread should have detached attribute so it can be cleaned up after it exits. */ int x_childthread_result; /* result from pthread_create. Zero if x_childthread represents a valid thread. */ } t_udpsend_tilde; #define NO_CHILDTHREAD 1 /* not zero */ /* function prototypes */ static int udpsend_tilde_sockerror(char *s); static void udpsend_tilde_sock_err(t_udpsend_tilde *x, char *err_string); static void udpsend_tilde_closesocket(int fd); static void udpsend_tilde_notify(t_udpsend_tilde *x); static void udpsend_tilde_disconnect(t_udpsend_tilde *x); static void *udpsend_tilde_doconnect(void *zz); static void udpsend_tilde_connect(t_udpsend_tilde *x, t_symbol *host, t_floatarg fportno); static void udpsend_tilde_set_multicast_loopback(t_udpsend_tilde *x, t_floatarg loop_state); static void udpsend_tilde_set_multicast_ttl(t_udpsend_tilde *x, t_floatarg ttl_hops); static void udpsend_tilde_set_multicast_interface (t_udpsend_tilde *x, t_symbol *s, int argc, t_atom *argv); static t_int *udpsend_tilde_perform(t_int *w); static void udpsend_tilde_dsp(t_udpsend_tilde *x, t_signal **sp); static void udpsend_tilde_channels(t_udpsend_tilde *x, t_floatarg channels); static void udpsend_tilde_format(t_udpsend_tilde *x, t_symbol* form, t_floatarg bitrate); static void udpsend_tilde_float(t_udpsend_tilde* x, t_floatarg arg); static void udpsend_tilde_info(t_udpsend_tilde *x); static void *udpsend_tilde_new(t_floatarg inlets, t_floatarg blocksize); static void udpsend_tilde_free(t_udpsend_tilde* x); void udpsend_tilde_setup(void); /* functions */ static void udpsend_tilde_notify(t_udpsend_tilde *x) { pthread_mutex_lock(&x->x_mutex); x->x_childthread_result = NO_CHILDTHREAD; /* connection thread has ended */ outlet_float(x->x_outlet, x->x_connectstate); /* we should be connected */ pthread_mutex_unlock(&x->x_mutex); } static void udpsend_tilde_disconnect(t_udpsend_tilde *x) { pthread_mutex_lock(&x->x_mutex); if (x->x_fd != -1) { udpsend_tilde_closesocket(x->x_fd); x->x_fd = -1; x->x_connectstate = 0; outlet_float(x->x_outlet, 0); } pthread_mutex_unlock(&x->x_mutex); } /* udpsend_tilde_doconnect runs in the child thread, which terminates as soon as a connection is */ static void *udpsend_tilde_doconnect(void *zz) { t_udpsend_tilde *x = (t_udpsend_tilde *)zz; struct sockaddr_in server; struct hostent *hp; int intarg = 1; int sockfd; int portno; int broadcast = 1;/* nonzero is true */ unsigned char multicast_loop_state; unsigned char multicast_ttl; t_symbol *hostname; unsigned int size; pthread_mutex_lock(&x->x_mutex); hostname = x->x_hostname; portno = x->x_portno; pthread_mutex_unlock(&x->x_mutex); /* create a socket */ sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (sockfd < 0) { post("udpsend~: connection to %s on port %d failed", hostname->s_name,portno); udpsend_tilde_sock_err(x, "udpsend~ socket"); x->x_childthread_result = NO_CHILDTHREAD; return (0); } #ifdef SO_BROADCAST if( 0 != setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, (const void *)&broadcast, sizeof(broadcast))) { udpsend_tilde_sockerror("setting SO_BROADCAST"); } #endif /* SO_BROADCAST */ /* connect socket using hostname provided in command line */ server.sin_family = AF_INET; hp = gethostbyname(x->x_hostname->s_name); if (hp == 0) { post("udpsend~: bad host?"); x->x_childthread_result = NO_CHILDTHREAD; return (0); } #ifdef SO_PRIORITY /* set high priority, LINUX only */ intarg = 6; /* select a priority between 0 and 7 */ if (setsockopt(sockfd, SOL_SOCKET, SO_PRIORITY, (const char*)&intarg, sizeof(int)) < 0) { udpsend_tilde_sockerror("setting SO_PRIORITY"); } #endif memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length); if (0xE0000000 == (ntohl(server.sin_addr.s_addr) & 0xF0000000)) post ("udpsend~: connecting to a multicast address"); size = sizeof(multicast_loop_state); getsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_LOOP, &multicast_loop_state, &size); size = sizeof(multicast_ttl); getsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL, &multicast_ttl, &size); x->x_multicast_loop_state = multicast_loop_state; x->x_multicast_ttl = multicast_ttl; /* assign client port number */ server.sin_port = htons((unsigned short)portno); /* try to connect */ if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0) { udpsend_tilde_sock_err(x, "udpsend~ connect"); udpsend_tilde_closesocket(sockfd); x->x_childthread_result = NO_CHILDTHREAD; return (0); } post("udpsend~: connected host %s on port %d", hostname->s_name, portno); pthread_mutex_lock(&x->x_mutex); x->x_fd = sockfd; x->x_connectstate = 1; clock_delay(x->x_clock, 0);/* udpsend_tilde_notify is called in next clock tick */ pthread_mutex_unlock(&x->x_mutex); return (0); } static void udpsend_tilde_connect(t_udpsend_tilde *x, t_symbol *host, t_floatarg fportno) { pthread_mutex_lock(&x->x_mutex); if (x->x_childthread_result == 0) { pthread_mutex_unlock(&x->x_mutex); post("udpsend~: already trying to connect"); return; } if (x->x_fd != -1) { pthread_mutex_unlock(&x->x_mutex); post("udpsend~: already connected"); return; } if (host != ps_nothing) x->x_hostname = host; else x->x_hostname = ps_localhost; /* default host */ if (!fportno) x->x_portno = DEFAULT_PORT; else x->x_portno = (int)fportno; x->x_count = 0; /* start child thread to connect */ /* sender thread should start out detached so its resouces will be freed when it is done */ if (0!= (x->x_childthread_result = pthread_attr_init(&x->x_childthread_attr))) { pthread_mutex_unlock(&x->x_mutex); post("udpsend~: pthread_attr_init failed: %d", x->x_childthread_result); return; } if(0!= (x->x_childthread_result = pthread_attr_setdetachstate(&x->x_childthread_attr, PTHREAD_CREATE_DETACHED))) { pthread_mutex_unlock(&x->x_mutex); post("udpsend~: pthread_attr_setdetachstate failed: %d", x->x_childthread_result); return; } if (0 != (x->x_childthread_result = pthread_create(&x->x_childthread, &x->x_childthread_attr, udpsend_tilde_doconnect, x))) { pthread_mutex_unlock(&x->x_mutex); post("udpsend~: couldn't create sender thread (%d)", x->x_childthread_result); return; } pthread_mutex_unlock(&x->x_mutex); } static void udpsend_tilde_set_multicast_loopback(t_udpsend_tilde *x, t_floatarg loop_state) { int sockfd = x->x_fd; unsigned char multicast_loop_state = loop_state; unsigned int size; if (x->x_fd < 0) { pd_error(x, "udpsend_tilde_set_multicast_loopback: not connected"); return; } if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_LOOP, &multicast_loop_state, sizeof(multicast_loop_state)) < 0) udpsend_tilde_sock_err(x, "udpsend_tilde setsockopt IP_MULTICAST_LOOP"); getsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_LOOP, &multicast_loop_state, &size); x->x_multicast_loop_state = multicast_loop_state; } static void udpsend_tilde_set_multicast_ttl(t_udpsend_tilde *x, t_floatarg ttl_hops) { int sockfd = x->x_fd; unsigned char multicast_ttl = ttl_hops; unsigned int size; if (x->x_fd < 0) { pd_error(x, "udpsend_tilde_set_multicast_ttl: not connected"); return; } if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL, &multicast_ttl, sizeof(multicast_ttl)) < 0) udpsend_tilde_sock_err(x, "udpsend_tilde setsockopt IP_MULTICAST_TTL"); getsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL, &multicast_ttl, &size); x->x_multicast_ttl = multicast_ttl; } static void udpsend_tilde_set_multicast_interface (t_udpsend_tilde *x, t_symbol *s, int argc, t_atom *argv) { #ifdef _WIN32 int i, n_ifaces = 32; PMIB_IPADDRTABLE pIPAddrTable; DWORD dwSize; IN_ADDR IPAddr; int if_index = -1; int found = 0; t_symbol *interfacename = gensym("none"); struct hostent *hp = 0; struct sockaddr_in server; if (x->x_fd < 0) { pd_error(x, "udpsend_tilde_set_multicast_interface: not connected"); return; } switch (argv[0].a_type) { case A_FLOAT: if_index = (int)atom_getfloat(&argv[0]); break; case A_SYMBOL: interfacename = atom_getsymbol(&argv[0]); break; default: pd_error(x, "udpsend_tilde_set_multicast_interface: argument not float or symbol"); return; } if (if_index == -1) { hp = gethostbyname(interfacename->s_name); // if interface is a dotted or named IP address (192.168.0.88) } if (hp != 0) memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length); else // maybe interface is its index (1) (names aren't available in _WIN32) { /* get the list of interfaces, IPv4 only */ dwSize = sizeof(MIB_IPADDRTABLE)*n_ifaces; if ((pIPAddrTable = (MIB_IPADDRTABLE *) getbytes(dwSize)) == NULL) { post("udpsend_tilde: unable to allocate %lu bytes for GetIpAddrTable", dwSize); return; } if (GetIpAddrTable(pIPAddrTable, &dwSize, 0)) { udpsend_tilde_sock_err(x, "udpsend_tilde_set_multicast_interface: GetIpAddrTable"); return; } n_ifaces = pIPAddrTable->dwNumEntries; post("udpsend_tilde: %d interface%s available:", n_ifaces, (n_ifaces == 1)?"":"s"); for (i = 0; i < n_ifaces; i++) { IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwAddr; post("[%d]: %s", pIPAddrTable->table[i].dwIndex, inet_ntoa(IPAddr)); if (pIPAddrTable->table[i].dwIndex == if_index) { server.sin_addr = IPAddr; found = 1; } } if (pIPAddrTable) { freebytes(pIPAddrTable, dwSize); pIPAddrTable = NULL; } if (! found) { post("udpsend_tilde_set_multicast_interface: bad host name? (%s)\n", interfacename->s_name); return; } } if (setsockopt(x->x_fd, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&server.sin_addr, sizeof(struct in_addr)) == SOCKET_ERROR) udpsend_tilde_sock_err(x, "udpsend_tilde setsockopt IP_MULTICAST_IF"); else post("udpsend_tilde multicast interface is %s", inet_ntoa(server.sin_addr)); #elif defined __APPLE__ int if_index = -1; int found = 0; t_symbol *interfacename = gensym("none"); struct ifaddrs *ifap; int i = 0; int n_ifaces = 0; struct hostent *hp = 0; struct sockaddr_in server; struct sockaddr *sa; char ifname[IFNAMSIZ]; /* longest possible interface name */ if (x->x_fd < 0) { pd_error(x, "udpsend_tilde_set_multicast_interface: not connected"); return; } switch (argv[0].a_type) { case A_FLOAT: if_index = (int)atom_getfloat(&argv[0]); break; case A_SYMBOL: interfacename = atom_getsymbol(&argv[0]); break; default: pd_error(x, "udpsend_tilde_set_multicast_interface: argument not float or symbol"); return; } if (if_index == -1) { hp = gethostbyname(interfacename->s_name); // if interface is a dotted or named IP address (192.168.0.88) } if (hp != 0) memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length); else // maybe interface is its name (eth0) or index (1) { // scan all the interfaces to get the IP address of interface if (getifaddrs(&ifap)) udpsend_tilde_sock_err(x, "udpsend_tilde getifaddrs"); i = found = n_ifaces = 0; while (NULL != ifap) { sa = ifap->ifa_addr; if (AF_INET == sa->sa_family) { ++n_ifaces; strncpy (ifname, ifap->ifa_name, IFNAMSIZ); post("[%d]: %s: %s", i, ifname, inet_ntoa(((struct sockaddr_in *)sa)->sin_addr)); if((i == if_index) || ((if_index == -1) && (!strncmp(interfacename->s_name, ifname, IFNAMSIZ)))) { // either the index or the name match server.sin_addr = ((struct sockaddr_in *)sa)->sin_addr; found = 1; } } i++; ifap = ifap->ifa_next; // next record or NULL } freeifaddrs(ifap); post ("udpsend_tilde: %d interfaces", n_ifaces); if (!found) return; } if (setsockopt(x->x_fd, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&server.sin_addr, sizeof(struct in_addr))) udpsend_tilde_sock_err(x, "udpsend_tilde setsockopt IP_MULTICAST_IF"); else post("udpsend_tilde multicast interface is %s", inet_ntoa(server.sin_addr)); return; #else // __linux__ struct sockaddr_in server; struct sockaddr *sa; struct hostent *hp = 0; struct ifconf ifc; int n_ifaces = 32, i, origbuflen, found = 0; char ifname[IFNAMSIZ]; /* longest possible interface name */ t_symbol *interface = gensym("none"); int if_index = -1; if (x->x_fd < 0) { pd_error(x, "udpsend_tilde_set_multicast_interface: not connected"); return; } switch (argv[0].a_type) { case A_FLOAT: if_index = (int)atom_getfloat(&argv[0]); break; case A_SYMBOL: interface = atom_getsymbol(&argv[0]); break; default: pd_error(x, "udpsend_tilde_set_multicast_interface: argument not float or symbol"); return; } if (if_index == -1) { hp = gethostbyname(interface->s_name); // if interface is a dotted or named IP address (192.168.0.88) } if (hp != 0) memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length); else // maybe interface is its name (eth0) or index (1) { // scan all the interfaces to get the IP address of interface // find the number of interfaces origbuflen = n_ifaces * sizeof (struct ifreq);// save maximum length for free() ifc.ifc_len = origbuflen; // SIOCGIFCONF changes it to valid length ifc.ifc_buf = (char*)getzbytes(origbuflen); if (ifc.ifc_buf != NULL) { // if (ioctl(x->x_fd, SIOCGIFCONF, &ifc) < 0) // get list of interfaces udpsend_tilde_sock_err(x, "udpsend_tilde_set_multicast_interface: getting list of interfaces"); else { n_ifaces = ifc.ifc_len/sizeof(struct ifreq); post("udpsend_tilde: %d interface%s available:", n_ifaces, (n_ifaces == 1)?"":"s"); for(i = 0; i < n_ifaces; i++) { sa = (struct sockaddr *)&(ifc.ifc_req[i].ifr_addr); strncpy (ifname, ifc.ifc_req[i].ifr_name, IFNAMSIZ); post("[%d]: %s: %s", i, ifname, inet_ntoa(((struct sockaddr_in *)sa)->sin_addr)); if ( (i == if_index) || ((if_index == -1) && (!strncmp(interface->s_name, ifname, IFNAMSIZ))) ) { server.sin_addr = ((struct sockaddr_in *)sa)->sin_addr; found = 1; } } } } freebytes(ifc.ifc_buf, origbuflen); if (! found) { post("udpsend_tilde_set_multicast_interface: bad host name? (%s)\n", interface->s_name); return; } } if (setsockopt(x->x_fd, IPPROTO_IP, IP_MULTICAST_IF, &server.sin_addr, sizeof(struct in_addr)) < 0) udpsend_tilde_sock_err(x, "udpsend_tilde_set_multicast_interface: setsockopt"); else post("udpsend_tilde multicast interface is %s", inet_ntoa(server.sin_addr)); #endif // _WIN32 } static t_int *udpsend_tilde_perform(t_int *w) { t_udpsend_tilde* x = (t_udpsend_tilde*) (w[1]); int n = (int)(w[2]); t_float *in[DEFAULT_AUDIO_CHANNELS]; const int offset = 3; char* bp = NULL; int i, length = x->x_blocksize * SF_SIZEOF(x->x_tag.format) * x->x_tag.channels; int sent = 0; pthread_mutex_lock(&x->x_mutex); for (i = 0; i < x->x_ninlets; i++) in[i] = (t_float *)(w[offset + i]); if (n != x->x_vecsize) /* resize buffer */ { x->x_vecsize = n; x->x_blockspersend = x->x_blocksize / x->x_vecsize; x->x_blockssincesend = 0; length = x->x_blocksize * SF_SIZEOF(x->x_tag.format) * x->x_tag.channels; } /* format the buffer */ switch (x->x_tag.format) { case SF_FLOAT: { int32_t* fbuf = (int32_t *)x->x_cbuf + (x->x_blockssincesend * x->x_vecsize * x->x_tag.channels); flint fl; while (n--) for (i = 0; i < x->x_tag.channels; i++) { fl.f32 = *(in[i]++); *fbuf++ = htonl(fl.i32); } break; } case SF_16BIT: { short* cibuf = (short *)x->x_cbuf + (x->x_blockssincesend * x->x_vecsize * x->x_tag.channels); while (n--) for (i = 0; i < x->x_tag.channels; i++) *cibuf++ = htons((short)floor(32767.5 * *(in[i]++)));/* signed binary */ break; } case SF_8BIT: { unsigned char* cbuf = (unsigned char*)x->x_cbuf + (x->x_blockssincesend * x->x_vecsize * x->x_tag.channels); while (n--) for (i = 0; i < x->x_tag.channels; i++) *cbuf++ = (unsigned char)floor(128. * (1.0 + *(in[i]++))); /* offset binary */ break; } default: break; } if (!(x->x_blockssincesend < x->x_blockspersend - 1)) /* time to send the buffer */ { x->x_blockssincesend = 0; x->x_count++; /* count data packet we're going to send */ if (x->x_fd != -1) { bp = (char *)x->x_cbuf; /* fill in the header tag */ x->x_tag.tag[0] = 'T'; x->x_tag.tag[1] = 'A'; x->x_tag.tag[2] = 'G'; x->x_tag.tag[3] = '!'; x->x_tag.framesize = htonl(length); x->x_tag.count = htonl(x->x_count); /* send the format tag */ if (send(x->x_fd, (char*)&x->x_tag, sizeof(t_tag), SEND_FLAGS) < 0) { udpsend_tilde_sockerror("send tag"); pthread_mutex_unlock(&x->x_mutex); udpsend_tilde_disconnect(x); return (w + offset + x->x_ninlets); } if (length != 0) /* UDP: max. packet size is 64k (incl. headers) so we have to split */ { #ifdef __APPLE__ /* WARNING: due to a 'bug' (maybe Apple would call it a feature?) in OS X send calls with data packets larger than 16k fail with error number 40! Thus we have to split the data packets into several packets that are 16k in size. The other side will reassemble them again. */ int size = DEFAULT_UDP_PACKT_SIZE; if (length < size) /* maybe data fits into one packet? */ size = length; /* send the buffer */ for (sent = 0; sent < length;) { int ret = 0; ret = send(x->x_fd, bp, size, SEND_FLAGS); if (ret <= 0) { udpsend_tilde_sockerror("send data"); pthread_mutex_unlock(&x->x_mutex); udpsend_tilde_disconnect(x); return (w + offset + x->x_ninlets); } else { bp += ret; sent += ret; if ((length - sent) < size) size = length - sent; } } #else /* If there is any data, send the buffer, the OS might segment it into smaller packets */ int ret = send(x->x_fd, bp, length, SEND_FLAGS); if (ret <= 0) { post ("udpsend~: sending length %ld", length); udpsend_tilde_sockerror("send data"); pthread_mutex_unlock(&x->x_mutex); udpsend_tilde_disconnect(x); return (w + offset + x->x_ninlets); } #endif } } /* check whether user has updated any parameters */ if (x->x_tag.channels != x->x_channels) { x->x_tag.channels = x->x_channels; } if (x->x_tag.format != x->x_format) { x->x_tag.format = x->x_format; } } else { x->x_blockssincesend++; } pthread_mutex_unlock(&x->x_mutex); return (w + offset + x->x_ninlets); } static void udpsend_tilde_dsp(t_udpsend_tilde *x, t_signal **sp) { int i; pthread_mutex_lock(&x->x_mutex); x->x_myvec[0] = (t_int*)x; x->x_myvec[1] = (t_int*)sp[0]->s_n; x->x_samplerate = sp[0]->s_sr; for (i = 0; i < x->x_ninlets; i++) { x->x_myvec[2 + i] = (t_int*)sp[i]->s_vec; } pthread_mutex_unlock(&x->x_mutex); if (DEFAULT_AUDIO_BUFFER_SIZE % sp[0]->s_n) { error("udpsend~: signal vector size too large (needs to be even divisor of %d)", DEFAULT_AUDIO_BUFFER_SIZE); } else { dsp_addv(udpsend_tilde_perform, x->x_ninlets + 2, (t_int*)x->x_myvec); } } static void udpsend_tilde_channels(t_udpsend_tilde *x, t_floatarg channels) { pthread_mutex_lock(&x->x_mutex); if (channels >= 0 && channels <= x->x_ninlets) { x->x_channels = (int)channels; post("udpsend~: channels set to %d", (int)channels); } else post ("udpsend~ number of channels must be between 0 and %d", x->x_ninlets); pthread_mutex_unlock(&x->x_mutex); } static void udpsend_tilde_format(t_udpsend_tilde *x, t_symbol* form, t_floatarg bitrate) { pthread_mutex_lock(&x->x_mutex); if (!strncmp(form->s_name,"float", 5) && x->x_tag.format != SF_FLOAT) { x->x_format = (int)SF_FLOAT; } else if (!strncmp(form->s_name,"16bit", 5) && x->x_tag.format != SF_16BIT) { x->x_format = (int)SF_16BIT; } else if (!strncmp(form->s_name,"8bit", 4) && x->x_tag.format != SF_8BIT) { x->x_format = (int)SF_8BIT; } post("udpsend~: format set to %s", form->s_name); pthread_mutex_unlock(&x->x_mutex); } static void udpsend_tilde_float(t_udpsend_tilde* x, t_floatarg arg) { if (arg == 0.0) udpsend_tilde_disconnect(x); else udpsend_tilde_connect(x,x->x_hostname,(float) x->x_portno); } /* send stream info */ static void udpsend_tilde_info(t_udpsend_tilde *x) { t_atom list[2]; t_symbol *sf_format; t_float bitrate; bitrate = (t_float)((SF_SIZEOF(x->x_tag.format) * x->x_samplerate * 8 * x->x_tag.channels) / 1000.); switch (x->x_tag.format) { case SF_FLOAT: { sf_format = ps_sf_float; break; } case SF_16BIT: { sf_format = ps_sf_16bit; break; } case SF_8BIT: { sf_format = ps_sf_8bit; break; } default: { sf_format = ps_sf_unknown; break; } } /* --- stream information (t_tag) --- */ /* audio format */ SETSYMBOL(list, (t_symbol *)sf_format); outlet_anything(x->x_outlet2, ps_format, 1, list); /* channels */ SETFLOAT(list, (t_float)x->x_tag.channels); outlet_anything(x->x_outlet2, ps_channels, 1, list); /* current signal vector size */ SETFLOAT(list, (t_float)x->x_vecsize); outlet_anything(x->x_outlet2, ps_vecsize, 1, list); /* framesize */ SETFLOAT(list, (t_float)(ntohl(x->x_tag.framesize))); outlet_anything(x->x_outlet2, ps_framesize, 1, list); /* bitrate */ SETFLOAT(list, (t_float)bitrate); outlet_anything(x->x_outlet2, ps_bitrate, 1, list); /* IP address */ SETSYMBOL(list, (t_symbol *)x->x_hostname); outlet_anything(x->x_outlet2, ps_hostname, 1, list); } static void *udpsend_tilde_new(t_floatarg inlets, t_floatarg blocksize) { int i; t_udpsend_tilde *x = (t_udpsend_tilde *)pd_new(udpsend_tilde_class); if (x) { for (i = sizeof(t_object); i < (int)sizeof(t_udpsend_tilde); i++) ((char *)x)[i] = 0; if ((int)inlets < 1 || (int)inlets > DEFAULT_AUDIO_CHANNELS) { error("udpsend~: Number of channels must be between 1 and %d", DEFAULT_AUDIO_CHANNELS); return NULL; } x->x_ninlets = (int)inlets; for (i = 1; i < x->x_ninlets; i++) inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); x->x_outlet = outlet_new(&x->x_obj, &s_float); x->x_outlet2 = outlet_new(&x->x_obj, &s_list); x->x_clock = clock_new(x, (t_method)udpsend_tilde_notify); x->x_myvec = (t_int **)t_getbytes(sizeof(t_int *) * (x->x_ninlets + 3)); if (!x->x_myvec) { error("udpsend~: out of memory"); return NULL; } pthread_mutex_init(&x->x_mutex, 0); x->x_hostname = ps_localhost; x->x_portno = DEFAULT_PORT; x->x_connectstate = 0; x->x_childthread_result = NO_CHILDTHREAD; x->x_fd = -1; x->x_tag.format = x->x_format = SF_FLOAT; x->x_tag.channels = x->x_channels = x->x_ninlets; x->x_vecsize = 64; /* this is updated in the perform routine udpsend_tilde_perform */ x->x_cbuf = NULL; if (blocksize == 0) x->x_blocksize = DEFAULT_AUDIO_BUFFER_SIZE; else if (DEFAULT_AUDIO_BUFFER_SIZE%(int)blocksize) { error("udpsend~: blocksize must fit snugly in %d", DEFAULT_AUDIO_BUFFER_SIZE); return NULL; } else x->x_blocksize = (int)blocksize; //DEFAULT_AUDIO_BUFFER_SIZE; /* <-- the only place blocksize is set */ x->x_blockspersend = x->x_blocksize / x->x_vecsize; /* 1024/64 = 16 blocks */ x->x_blockssincesend = 0; x->x_cbufsize = x->x_blocksize * sizeof(t_float) * x->x_ninlets; x->x_cbuf = (char *)t_getbytes(x->x_cbufsize); #ifndef _WIN32 /* we don't want to get signaled in case send() fails */ signal(SIGPIPE, SIG_IGN); #endif } return (x); } static void udpsend_tilde_free(t_udpsend_tilde* x) { udpsend_tilde_disconnect(x); /* free the memory */ if (x->x_cbuf)t_freebytes(x->x_cbuf, x->x_cbufsize); if (x->x_myvec)t_freebytes(x->x_myvec, sizeof(t_int) * (x->x_ninlets + 3)); clock_free(x->x_clock); pthread_mutex_destroy(&x->x_mutex); } void udpsend_tilde_setup(void) { udpsend_tilde_class = class_new(gensym("udpsend~"), (t_newmethod)udpsend_tilde_new, (t_method)udpsend_tilde_free, sizeof(t_udpsend_tilde), 0, A_DEFFLOAT, A_DEFFLOAT, A_NULL); class_addmethod(udpsend_tilde_class, nullfn, gensym("signal"), 0); class_addmethod(udpsend_tilde_class, (t_method)udpsend_tilde_dsp, gensym("dsp"), 0); class_addfloat(udpsend_tilde_class, udpsend_tilde_float); class_addmethod(udpsend_tilde_class, (t_method)udpsend_tilde_info, gensym("info"), 0); class_addmethod(udpsend_tilde_class, (t_method)udpsend_tilde_connect, gensym("connect"), A_DEFSYM, A_DEFFLOAT, 0); class_addmethod(udpsend_tilde_class, (t_method)udpsend_tilde_set_multicast_ttl, gensym("multicast_ttl"), A_DEFFLOAT, 0); class_addmethod(udpsend_tilde_class, (t_method)udpsend_tilde_set_multicast_loopback, gensym("multicast_loopback"), A_DEFFLOAT, 0); class_addmethod(udpsend_tilde_class, (t_method)udpsend_tilde_set_multicast_interface, gensym("multicast_interface"), A_GIMME, 0); class_addmethod(udpsend_tilde_class, (t_method)udpsend_tilde_disconnect, gensym("disconnect"), 0); class_addmethod(udpsend_tilde_class, (t_method)udpsend_tilde_channels, gensym("channels"), A_FLOAT, 0); class_addmethod(udpsend_tilde_class, (t_method)udpsend_tilde_format, gensym("format"), A_SYMBOL, A_DEFFLOAT, 0); class_sethelpsymbol(udpsend_tilde_class, gensym("udpsend~")); post("udpsend~ v%s, (c) 2004-2005 Olaf Matthes, 2010 Martin Peach", VERSION); post("udpsend~ Default blocksize is %d", DEFAULT_AUDIO_BUFFER_SIZE); ps_nothing = gensym(""); ps_localhost = gensym("localhost"); ps_hostname = gensym("ipaddr"); ps_format = gensym("format"); ps_channels = gensym("channels"); ps_vecsize = gensym("vecsize"); ps_framesize = gensym("framesize"); ps_bitrate = gensym("bitrate"); ps_sf_float = gensym("_float_"); ps_sf_16bit = gensym("_16bit_"); ps_sf_8bit = gensym("_8bit_"); ps_sf_unknown = gensym("_unknown_"); } /* Utility functions */ static void udpsend_tilde_sock_err(t_udpsend_tilde *x, char *err_string) { /* prints the last error from errno or WSAGetLastError() */ #ifdef _WIN32 void *lpMsgBuf; unsigned long errornumber = WSAGetLastError(); int len = 0, i; char *cp; if (len = FormatMessageA((FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS) , NULL, errornumber, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&lpMsgBuf, 0, NULL)) { cp = (char *)lpMsgBuf; for(i = 0; i < len; ++i) { if (cp[i] < 0x20) { /* end string at first weird character */ cp[i] = 0; break; } } pd_error(x, "%s: %s (%d)", err_string, lpMsgBuf, errornumber); LocalFree(lpMsgBuf); } #else pd_error(x, "%s: %s (%d)", err_string, strerror(errno), errno); #endif } static int udpsend_tilde_sockerror(char *s) { #ifdef _WIN32 int err = WSAGetLastError(); if (err == 10054) return 1; else if (err == 10053) post("udpsend~: %s: software caused connection abort (%d)", s, err); else if (err == 10055) post("udpsend~: %s: no buffer space available (%d)", s, err); else if (err == 10060) post("udpsend~: %s: connection timed out (%d)", s, err); else if (err == 10061) post("udpsend~: %s: connection refused (%d)", s, err); else post("udpsend~: %s: %s (%d)", s, strerror(err), err); #else int err = errno; post("udpsend~: %s: %s (%d)", s, strerror(err), err); #endif #ifdef _WIN32 if (err == WSAEWOULDBLOCK) #endif #ifndef _WIN32 if (err == EAGAIN) #endif { return 1; /* recoverable error */ } return 0; /* indicate non-recoverable error */ } static void udpsend_tilde_closesocket(int fd) { #ifndef _WIN32 close(fd); #endif #ifdef _WIN32 closesocket(fd); #endif } /* fin udpsend~.c */ mrpeach/net/httpreq-help.pd0000644000175000017500000000644011513665537016477 0ustar zmoelnigzmoelnig#N canvas 525 51 712 894 10; #X obj 119 146 httpreq; #X obj 44 56 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 -1; #X msg 84 94 GET http://132.205.142.12/index.php; #X obj 136 309 unpack 0 0 0 0; #X floatatom 136 332 3 0 0 0 - - -; #X floatatom 163 332 3 0 0 0 - - -; #X floatatom 190 332 3 0 0 0 - - -; #X floatatom 217 332 3 0 0 0 - - -; #X text 81 350 from; #X obj 119 257 tcpclient; #X obj 153 283 tgl 15 0 empty empty connected 18 7 0 8 -24198 -13381 -1 0 1; #X text 190 256 tcpclient opens a tcp socket to send and receive bytes on; #X floatatom 270 342 9 0 0 0 - - -; #X floatatom 313 320 9 0 0 0 - - -; #X text 382 319 Size of the send buffer; #X obj 270 274 route sent buf blocked; #X text 340 341 Number of bytes sent; #X obj 356 298 print sender_blocked!; #X msg 85 206 connect 132.205.142.12 80; #X obj 119 450 httpreceive; #X floatatom 182 483 5 0 0 0 - - -; #X symbolatom 150 642 10 0 0 0 - - -; #X obj 150 620 prepend set; #X symbolatom 216 600 50 0 0 0 - - -; #X obj 216 578 prepend set; #X obj 150 526 route reason Date Content-Length Content-Type; #X symbolatom 350 568 50 0 0 0 - - -; #X obj 350 546 prepend set; #X floatatom 283 558 5 0 0 0 - - -; #X msg 64 74 GET http://132.205.142.12/nothing; #X msg 44 165 dump \$1; #X obj 44 139 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1; #X obj 37 328 tgl 15 0 empty empty empty 17 7 0 10 -4034 -257985 -1 0 1; #X msg 37 351 verbosity \$1; #X obj 457 543 print more_status; #X obj 76 392 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 -1; #X text 515 726 Author: Martin Peach; #X text 515 743 Date: 2011/01/13; #X text 224 481 The right outlet is the status code.; #X text 166 693 The left outlet is the message body as a list of bytes ; #X text 154 505 The middle outlet is the status header as name/value pairs; #X obj 119 693 spigot; #X obj 119 723 print message_body; #X obj 152 671 tgl 15 0 empty empty printing_long_messages_can_hang_Pd 17 7 0 10 -4034 -257985 -1 0 1; #X text 175 147 [httpreq] sends an HTTP/1.1 request as a list of bytes (actually float atoms) \, suitable for [tcpclient]; #X text 195 444 [htpreceive] expects an HTTP/1.1 response as one or more lists of bytes.; #X text 187 557 message length:; #X obj 27 14 tgl 15 0 empty empty empty 17 7 0 10 -4034 -257985 -1 1 1; #X msg 27 37 verbosity \$1; #X msg 105 115 HEAD http://132.205.142.12/index.php; #X text 175 185 So far only GET and HEAD requests are supported; #X text 274 73 should return 404 not found; #X text 306 93 should return a web page; #X text 332 114 should return only the metainformation; #X connect 0 0 9 0; #X connect 1 0 0 0; #X connect 2 0 0 0; #X connect 3 0 4 0; #X connect 3 1 5 0; #X connect 3 2 6 0; #X connect 3 3 7 0; #X connect 9 0 19 0; #X connect 9 1 3 0; #X connect 9 2 10 0; #X connect 9 3 15 0; #X connect 15 0 12 0; #X connect 15 1 13 0; #X connect 15 2 17 0; #X connect 18 0 9 0; #X connect 19 0 41 0; #X connect 19 1 25 0; #X connect 19 2 20 0; #X connect 22 0 21 0; #X connect 24 0 23 0; #X connect 25 0 22 0; #X connect 25 1 24 0; #X connect 25 2 28 0; #X connect 25 3 27 0; #X connect 25 4 34 0; #X connect 27 0 26 0; #X connect 29 0 0 0; #X connect 30 0 9 0; #X connect 31 0 30 0; #X connect 32 0 33 0; #X connect 33 0 19 0; #X connect 35 0 19 0; #X connect 41 0 42 0; #X connect 43 0 41 1; #X connect 47 0 48 0; #X connect 48 0 0 0; #X connect 49 0 0 0; mrpeach/net/tcpsocketserver.pd0000644000175000017500000000565111741742673017313 0ustar zmoelnigzmoelnig#N canvas 332 53 333 552 10; #X obj 13 9 inlet; #X obj 13 464 outlet; #X obj 71 463 outlet; #X obj 129 463 outlet; #X obj 187 462 outlet; #X obj 30 207 list trim; #X obj 47 165 list trim; #X obj 47 144 list prepend socket; #X obj 30 186 list prepend num_of_clients; #X obj 64 123 list trim; #X obj 64 102 list prepend ip; #N canvas 816 227 247 348 \$0.TCPSOCKETCONTAINER 0; #X restore 14 372 pd \$0.TCPSOCKETCONTAINER; #N canvas 491 218 502 504 socketmanager 0; #X msg 24 196 \$1 reset; #X obj 25 259 route done; #X obj 5 175 t a a b; #X msg 25 280 0; #X msg 44 280 1; #X obj 5 303 spigot; #X obj 44 344 f; #X obj 76 344 + 20; #X obj 5 323 t a b b; #X obj 24 365 list append \$1; #X obj 24 388 list append; #X obj 5 412 list append; #X obj 5 476 s pd-\$0.TCPSOCKETCONTAINER; #X obj 5 432 list append \$0; #X obj 5 24 route socket num_of_clients; #X obj 84 46 t a a; #X obj 69 73 -; #X obj 69 94 == 1; #X obj 5 122 spigot; #X obj 5 3 r \$0.TCPSOCKET; #X obj 24 217 s \$0.TCPSOCKET; #X obj 25 238 r \$0.TCPSOCKET; #X msg 5 454 obj 10 \$3 tcpsocket.\$2 \$4 \$1 \, loadbang; #X obj 5 148 t a b; #X msg 65 132 0; #X text 116 78 when a new client connects (num_of_clients: +1); #X text 119 197 send a 'reset' to the according socket handler; #X text 114 266 and if it doesn't respond (which means \, there is no socket handler on specified socket) \,; #X text 119 368 create one (into pd-\$0.TCPSOCKETCONTAINER).; #X connect 0 0 20 0; #X connect 1 0 3 0; #X connect 2 0 5 0; #X connect 2 1 0 0; #X connect 2 2 4 0; #X connect 3 0 5 1; #X connect 4 0 5 1; #X connect 5 0 8 0; #X connect 6 0 7 0; #X connect 6 0 10 1; #X connect 7 0 6 1; #X connect 8 0 11 0; #X connect 8 1 9 0; #X connect 8 2 6 0; #X connect 9 0 10 0; #X connect 10 0 11 1; #X connect 11 0 13 0; #X connect 13 0 22 0; #X connect 14 0 18 0; #X connect 14 1 15 0; #X connect 15 0 16 1; #X connect 15 1 16 0; #X connect 16 0 17 0; #X connect 17 0 18 1; #X connect 18 0 23 0; #X connect 19 0 14 0; #X connect 21 0 1 0; #X connect 22 0 12 0; #X connect 23 0 2 0; #X connect 23 1 24 0; #X connect 24 0 18 1; #X restore 14 349 pd socketmanager; #X obj 13 30 tcpserver \$2; #X obj 13 417 r \$0.TCPSOCKET; #X obj 13 228 list prepend in; #X obj 13 250 list trim; #X obj 82 316 s \$0.TCPSOCKET; #X text 23 501 Author: Roman Haefeli; #X text 94 292 [tcpsocketserver ]; #X obj 82 78 list trim; #X obj 82 57 list prepend status; #X obj 13 440 route out num_of_clients socket.out ip.out status; #X text 24 518 Version: 2012-04-13; #X obj 245 461 outlet; #X connect 0 0 13 0; #X connect 5 0 17 0; #X connect 6 0 17 0; #X connect 7 0 6 0; #X connect 8 0 5 0; #X connect 9 0 17 0; #X connect 10 0 9 0; #X connect 13 0 15 0; #X connect 13 1 8 0; #X connect 13 2 7 0; #X connect 13 3 10 0; #X connect 13 4 21 0; #X connect 14 0 22 0; #X connect 15 0 16 0; #X connect 16 0 17 0; #X connect 20 0 17 0; #X connect 21 0 20 0; #X connect 22 0 1 0; #X connect 22 1 2 0; #X connect 22 2 3 0; #X connect 22 3 4 0; #X connect 22 4 24 0; mrpeach/net/httpreq.c0000644000175000017500000001240711513665537015370 0ustar zmoelnigzmoelnig/* httptreq.c Started by Martin Peach 20110111 */ /* httpreq will generate http 1.1 requests as lists of bytes suitable for input to tcpclient */ /* See http://www.w3.org/Protocols/rfc2616/rfc2616.html */ #include "m_pd.h" #include #include static t_class *httpreq_class; typedef struct _httpreq { t_object x_obj; t_outlet *x_reqout; int x_verbosity; } t_httpreq; #define MAX_GETSTRING 256 static void httpreq_bang(t_httpreq *x); static void httpreq_get(t_httpreq *x, t_symbol *s); static void httpreq_head(t_httpreq *x, t_symbol *s); static void httpreq_verbosity(t_httpreq *x, t_floatarg verbosity); static void *httpreq_new (void); void httpreq_setup(void); static void httpreq_bang(t_httpreq *x) { post("httpreq_bang %p", x); } static void httpreq_get(t_httpreq *x, t_symbol *s) { unsigned int i, j, len; char buf[MAX_GETSTRING]; char request_line[1024]; t_atom request_atoms[1024]; len = strlen (s->s_name); if (len > MAX_GETSTRING) { pd_error(x, "httpreq_get: string too long (%d), should be less than %d", len, MAX_GETSTRING); return; } for (i = 0; i < strlen(s->s_name); ++i) buf[i] = s->s_name[i]; buf[i] = 0; if (0 != strncmp("http://", buf, 7)) { pd_error(x, "httpreq_get: url doesn't begin with 'http://' (%d)", len); return; } /* 5.1 Request-Line The Request-Line begins with a method token, followed by the Request-URI and the protocol version, and ending with CRLF. The elements are separated by SP characters. No CR or LF is allowed except in the final CRLF sequence. Request-Line = Method SP Request-URI SP HTTP-Version CRLF */ j = sprintf(request_line, "GET "); for (i = 7; i < len; ++i) { /* skip "http://" and the host name */ if ('/' == buf[i]) break; } for (; i < len; ++i, ++j) { if (buf[i] <= 0x20) break; request_line[j] = buf[i]; } j += sprintf(&request_line[j], " HTTP/1.1"); request_line[j++] = 0xD; // request_line[j++] = 0xA; // j += sprintf(&request_line[j], "Host: "); for (i = 7; i < len; ++i, ++j) { /* copy the host name */ if ('/' == buf[i]) break; request_line[j] = buf[i]; } request_line[j++] = 0xD; // request_line[j++] = 0xA; // request_line[j++] = 0xD; // request_line[j++] = 0xA; // request_line[j] = 0; // terminate string /* output the request line as a list of floats */ for (i = 0; i < j; ++i) { SETFLOAT(&request_atoms[i], request_line[i]); } if (x->x_verbosity) post("httpreq_get: %s", request_line); outlet_list(x->x_reqout, &s_list, j, &request_atoms[0]); } static void httpreq_head(t_httpreq *x, t_symbol *s) { /* this is the same as get except for the method */ unsigned int i, j, len; char buf[MAX_GETSTRING]; char request_line[1024]; t_atom request_atoms[1024]; len = strlen (s->s_name); if (len > MAX_GETSTRING) { pd_error(x, "httpreq_head: string too long (%d), should be less than %d", len, MAX_GETSTRING); return; } for (i = 0; i < strlen(s->s_name); ++i) buf[i] = s->s_name[i]; buf[i] = 0; if (0 != strncmp("http://", buf, 7)) { pd_error(x, "httpreq_head: url doesn't begin with 'http://' (%d)", len); return; } j = sprintf(request_line, "HEAD "); for (i = 7; i < len; ++i) { /* skip "http://" and the host name */ if ('/' == buf[i]) break; } for (; i < len; ++i, ++j) { if (buf[i] <= 0x20) break; request_line[j] = buf[i]; } j += sprintf(&request_line[j], " HTTP/1.1"); request_line[j++] = 0xD; // request_line[j++] = 0xA; // j += sprintf(&request_line[j], "Host: "); for (i = 7; i < len; ++i, ++j) { /* copy the host name */ if ('/' == buf[i]) break; request_line[j] = buf[i]; } request_line[j++] = 0xD; // request_line[j++] = 0xA; // request_line[j++] = 0xD; // request_line[j++] = 0xA; // request_line[j] = 0; // terminate string /* output the request line as a list of floats */ for (i = 0; i < j; ++i) { SETFLOAT(&request_atoms[i], request_line[i]); } if (x->x_verbosity) post("httpreq_head: %s", request_line); outlet_list(x->x_reqout, &s_list, j, &request_atoms[0]); } static void httpreq_verbosity(t_httpreq *x, t_float verbosity) { x->x_verbosity = verbosity; if (x->x_verbosity != 0) post ("httpreq_verbosity %d", x->x_verbosity); } static void *httpreq_new (void) { t_httpreq *x = (t_httpreq *)pd_new(httpreq_class); if (NULL != x) { x->x_reqout = outlet_new(&x->x_obj, &s_anything); } return (void *)x; } void httpreq_setup(void) { httpreq_class = class_new(gensym("httpreq"), (t_newmethod)httpreq_new, 0, sizeof(t_httpreq), CLASS_DEFAULT, 0); class_addbang(httpreq_class, httpreq_bang); class_addmethod (httpreq_class, (t_method)httpreq_get, gensym ("GET"), A_DEFSYM, 0); class_addmethod (httpreq_class, (t_method)httpreq_head, gensym ("HEAD"), A_DEFSYM, 0); class_addmethod(httpreq_class, (t_method)httpreq_verbosity, gensym("verbosity"), A_FLOAT, 0); } /* fin httpreq.c */ mrpeach/net/tcpsend.c0000644000175000017500000001620112111234434015314 0ustar zmoelnigzmoelnig/* tcpsend.c 20060424 Martin Peach did it based on x_net.c. x_net.c header follows: */ /* Copyright (c) 1997-1999 Miller Puckette. * For information on usage and redistribution, and for a DISCLAIMER OF ALL * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ /* network */ #include "m_pd.h" #include "s_stuff.h" #include #include #ifdef _WIN32 #include #else #include #include #include #include #include #endif /* support older Pd versions without sys_open(), sys_fopen(), sys_fclose() */ #if PD_MAJOR_VERSION == 0 && PD_MINOR_VERSION < 44 #define sys_open open #define sys_fopen fopen #define sys_fclose fclose #endif static t_class *tcpsend_class; typedef struct _tcpsend { t_object x_obj; int x_fd; } t_tcpsend; void tcpsend_setup(void); static void tcpsend_free(t_tcpsend *x); static void tcpsend_send(t_tcpsend *x, t_symbol *s, int argc, t_atom *argv); static void tcpsend_disconnect(t_tcpsend *x); static void tcpsend_connect(t_tcpsend *x, t_symbol *hostname, t_floatarg fportno); static void *tcpsend_new(void); static void *tcpsend_new(void) { t_tcpsend *x = (t_tcpsend *)pd_new(tcpsend_class); outlet_new(&x->x_obj, &s_float); x->x_fd = -1; return (x); } static void tcpsend_connect(t_tcpsend *x, t_symbol *hostname, t_floatarg fportno) { struct sockaddr_in server; struct hostent *hp; int sockfd; int portno = fportno; int intarg; if (x->x_fd >= 0) { error("tcpsend: already connected"); return; } /* create a socket */ sockfd = socket(AF_INET, SOCK_STREAM, 0); #ifdef DEBUG fprintf(stderr, "tcpsend_connect: send socket %d\n", sockfd); #endif if (sockfd < 0) { sys_sockerror("tcpsend: socket"); return; } /* connect socket using hostname provided in command line */ server.sin_family = AF_INET; hp = gethostbyname(hostname->s_name); if (hp == 0) { post("tcpsend: bad host?\n"); return; } /* for stream (TCP) sockets, specify "nodelay" */ intarg = 1; if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char *)&intarg, sizeof(intarg)) < 0) post("tcpsend: setsockopt (TCP_NODELAY) failed\n"); memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length); /* assign client port number */ server.sin_port = htons((u_short)portno); post("tcpsend: connecting to port %d", portno); /* try to connect. */ if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0) { sys_sockerror("tcpsend: connecting stream socket"); sys_closesocket(sockfd); return; } x->x_fd = sockfd; outlet_float(x->x_obj.ob_outlet, 1); } static void tcpsend_disconnect(t_tcpsend *x) { if (x->x_fd >= 0) { sys_closesocket(x->x_fd); x->x_fd = -1; outlet_float(x->x_obj.ob_outlet, 0); post("tcpsend: disconnected"); } } static void tcpsend_send(t_tcpsend *x, t_symbol *s, int argc, t_atom *argv) { #define BYTE_BUF_LEN 65536 // arbitrary maximum similar to max IP packet size static char byte_buf[BYTE_BUF_LEN]; int i, j; unsigned int d; unsigned char c; float f, e; char *bp; int length, sent; int result; static double lastwarntime; static double pleasewarn; double timebefore; double timeafter; int late; char fpath[FILENAME_MAX]; FILE *fptr; #ifdef DEBUG post("s: %s", s->s_name); post("argc: %d", argc); #endif for (i = j = 0; i < argc; ++i) { if (argv[i].a_type == A_FLOAT) { f = argv[i].a_w.w_float; d = (unsigned int)f; e = f - d; if (e != 0) { pd_error(x, "tcpsend_send: item %d (%f) is not an integer", i, f); return; } c = (unsigned char)d; if (c != d) { pd_error(x, "tcpsend_send: item %d (%f) is not between 0 and 255", i, f); return; } #ifdef DEBUG post("tcpsend_send: argv[%d]: %d", i, c); #endif byte_buf[j++] = c; } else if (argv[i].a_type == A_SYMBOL) { atom_string(&argv[i], fpath, FILENAME_MAX); #ifdef DEBUG post ("tcpsend fname: %s", fpath); #endif fptr = sys_fopen(fpath, "rb"); if (fptr == NULL) { post("tcpsend: unable to open \"%s\"", fpath); return; } rewind(fptr); #ifdef DEBUG post("tcpsend: d is %d", d); #endif while ((d = fgetc(fptr)) != EOF) { byte_buf[j++] = (char)(d & 0x0FF); #ifdef DEBUG post("tcpsend: byte_buf[%d] = %d", j-1, byte_buf[j-1]); #endif if (j >= BYTE_BUF_LEN) { post ("tcpsend: file too long, truncating at %lu", BYTE_BUF_LEN); break; } } sys_fclose(fptr); fptr = NULL; post("tcpsend: read \"%s\" length %d byte%s", fpath, j, ((d==1)?"":"s")); } else { pd_error(x, "tcpsend_send: item %d is not a float or a file name", i); return; } } length = j; if ((x->x_fd >= 0) && (length > 0)) { for (bp = byte_buf, sent = 0; sent < length;) { timebefore = sys_getrealtime(); result = send(x->x_fd, byte_buf, length-sent, 0); timeafter = sys_getrealtime(); late = (timeafter - timebefore > 0.005); if (late || pleasewarn) { if (timeafter > lastwarntime + 2) { post("tcpsend blocked %d msec", (int)(1000 * ((timeafter - timebefore) + pleasewarn))); pleasewarn = 0; lastwarntime = timeafter; } else if (late) pleasewarn += timeafter - timebefore; } if (result <= 0) { sys_sockerror("tcpsend"); tcpsend_disconnect(x); break; } else { sent += result; bp += result; } } } else pd_error(x, "tcpsend: not connected"); } static void tcpsend_free(t_tcpsend *x) { tcpsend_disconnect(x); } void tcpsend_setup(void) { tcpsend_class = class_new(gensym("tcpsend"), (t_newmethod)tcpsend_new, (t_method)tcpsend_free, sizeof(t_tcpsend), 0, 0); class_addmethod(tcpsend_class, (t_method)tcpsend_connect, gensym("connect"), A_SYMBOL, A_FLOAT, 0); class_addmethod(tcpsend_class, (t_method)tcpsend_disconnect, gensym("disconnect"), 0); class_addmethod(tcpsend_class, (t_method)tcpsend_send, gensym("send"), A_GIMME, 0); class_addlist(tcpsend_class, (t_method)tcpsend_send); } /* end tcpsend.c */ mrpeach/net/tcpclient-help.pd0000644000175000017500000001072613221012047016753 0ustar zmoelnigzmoelnig#N canvas 31 152 1205 761 12; #X msg 148 156 disconnect; #X floatatom 482 635 3 0 0 0 - - -, f 3; #X floatatom 516 635 3 0 0 0 - - -, f 3; #X floatatom 552 635 3 0 0 0 - - -, f 3; #X floatatom 588 635 3 0 0 0 - - -, f 3; #X text 442 634 from; #X obj 459 487 tcpclient; #X obj 505 513 tgl 15 0 empty empty connected 18 7 0 8 -24198 -13381 -1 1 1; #X msg 172 180 dump \$1; #X obj 120 165 tgl 15 0 empty empty empty 0 -6 0 8 -4034 -13381 -1 0 1; #X text 224 42 connect with an IP address and port number; #X msg 60 68 connect www.concordia.ca 80; #X text 243 179 print received messages to main window in hexdump format ; #X text 543 486 tcpclient opens a tcp socket to send and receive bytes on; #X text 43 405 See also:; #X obj 48 429 netclient; #X msg 35 43 connect 127.0.0.1 9997; #X obj 48 452 tcpreceive; #X text 46 474 can receive messages from tcpclient; #X text 124 428 is what tcpclient is based on; #X text 524 683 Received messages are output as a list of bytes; #X msg 343 351 send 49 127 128 51 59; #X obj 176 452 tcpserver; #X text 142 451 and; #X text 607 45 tcpclient can connect to a server and send and receive messages as lists of bytes. Any integer value between 0 and 255 can be transmitted or received.; #X msg 197 205 send examples/test.txt; #X obj 245 229 openpanel; #X msg 245 253 send \$1; #X obj 159 214 bng 15 250 50 0 empty empty empty 17 7 0 10 -4034 -13381 -1; #X text 382 205 send a file; #X text 322 228 ...any file; #X msg 382 374 71 69 84 32 104 116 116 112 58 47 47 47 105 110 100 101 120 46 104 116 109 108 13 10; #X text 865 381 'send' prefix is optional; #X obj 459 684 spigot; #X obj 504 661 tgl 15 0 empty empty enable_print 18 7 0 8 -24198 -13381 -1 0 1; #X obj 459 713 print >>>; #X text 612 124 GET http:///index.phpCRLF; #X floatatom 634 583 9 0 0 0 - - -, f 9; #X text 467 414 set send-buffer size; #X floatatom 689 557 9 0 0 0 - - -, f 9; #X text 768 556 Size of the send buffer; #X msg 430 438 buf; #X text 471 437 get send-buffer size; #X msg 406 414 buf 10; #X msg 454 462 verbosity \$1; #X obj 399 447 tgl 15 1 empty empty empty 0 -6 0 8 -4034 -13381 -1 1 1; #X text 566 463 print connection status messages to main window (default) ; #X msg 124 116 send 71 69 84 32 104 116 116 112 58 47 47 47 105 110 100 101 120 46 112 104 112 13 10 13 10; #X text 545 712 Attempting to print long messages can hang Pd!; #X msg 271 279 unblock; #X msg 85 93 connect 132.205.142.11 9997; #X msg 226 307 hello \;; #X obj 319 327 str to_list; #X text 418 325 semicolon-terminated strings for netserver or netreceive ; #X text 353 275 if the tcpclient sender blocks for any reason \, it must be unblocked manually; #X text 704 582 Number of bytes sent; #X obj 744 533 print sender_blocked!; #N canvas 527 268 494 344 META 0; #X text 12 215 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; #X text 12 195 AUTHOR Martin Peach; #X text 12 45 DESCRIPTION connect to a server and send and receive messages as lists of bytes; #X text 12 25 LICENSE GPL v2 or later; #X text 12 85 INLET_0 list buf verbosity connect send disconnect dump unblock; #X text 12 115 OUTLET_0 list; #X text 12 5 KEYWORDS control network; #X text 12 135 OUTLET_1 list; #X text 12 155 OUTLET_2 float; #X text 12 175 OUTLET_3 sent buf blocked ourIP; #X restore 993 691 pd META; #X obj 634 507 route sent buf blocked ourIP; #X text 32 716 2017/12/27 Martin Peach; #X floatatom 799 635 3 0 0 0 - - -, f 3; #X floatatom 833 635 3 0 0 0 - - -, f 3; #X floatatom 869 635 3 0 0 0 - - -, f 3; #X floatatom 905 635 3 0 0 0 - - -, f 3; #X text 739 634 our IP; #X obj 799 607 unpack 0 0 0 0 0; #X floatatom 945 635 6 0 0 0 - - -, f 6; #X floatatom 625 635 5 0 0 0 - - -, f 5; #X obj 482 607 unpack 0 0 0 0 0; #X connect 0 0 6 0; #X connect 6 0 33 0; #X connect 6 1 68 0; #X connect 6 2 7 0; #X connect 6 3 58 0; #X connect 8 0 6 0; #X connect 9 0 8 0; #X connect 11 0 6 0; #X connect 16 0 6 0; #X connect 21 0 6 0; #X connect 25 0 6 0; #X connect 26 0 27 0; #X connect 27 0 6 0; #X connect 28 0 26 0; #X connect 31 0 6 0; #X connect 33 0 35 0; #X connect 34 0 33 1; #X connect 41 0 6 0; #X connect 43 0 6 0; #X connect 44 0 6 0; #X connect 45 0 44 0; #X connect 47 0 6 0; #X connect 49 0 6 0; #X connect 50 0 6 0; #X connect 51 0 52 0; #X connect 58 0 37 0; #X connect 58 1 39 0; #X connect 58 2 56 0; #X connect 58 3 65 0; #X connect 65 0 60 0; #X connect 65 1 61 0; #X connect 65 2 62 0; #X connect 65 3 63 0; #X connect 65 4 66 0; #X connect 68 0 1 0; #X connect 68 1 2 0; #X connect 68 2 3 0; #X connect 68 3 4 0; #X connect 68 4 67 0; mrpeach/net/httpreceive-help.pd0000644000175000017500000000644011513665537017332 0ustar zmoelnigzmoelnig#N canvas 525 51 712 894 10; #X obj 119 146 httpreq; #X obj 44 56 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 -1; #X msg 84 94 GET http://132.205.142.12/index.php; #X obj 136 309 unpack 0 0 0 0; #X floatatom 136 332 3 0 0 0 - - -; #X floatatom 163 332 3 0 0 0 - - -; #X floatatom 190 332 3 0 0 0 - - -; #X floatatom 217 332 3 0 0 0 - - -; #X text 81 350 from; #X obj 119 257 tcpclient; #X obj 153 283 tgl 15 0 empty empty connected 18 7 0 8 -24198 -13381 -1 0 1; #X text 190 256 tcpclient opens a tcp socket to send and receive bytes on; #X floatatom 270 342 9 0 0 0 - - -; #X floatatom 313 320 9 0 0 0 - - -; #X text 382 319 Size of the send buffer; #X obj 270 274 route sent buf blocked; #X text 340 341 Number of bytes sent; #X obj 356 298 print sender_blocked!; #X msg 85 206 connect 132.205.142.12 80; #X obj 119 450 httpreceive; #X floatatom 182 483 5 0 0 0 - - -; #X symbolatom 150 642 10 0 0 0 - - -; #X obj 150 620 prepend set; #X symbolatom 216 600 50 0 0 0 - - -; #X obj 216 578 prepend set; #X obj 150 526 route reason Date Content-Length Content-Type; #X symbolatom 350 568 50 0 0 0 - - -; #X obj 350 546 prepend set; #X floatatom 283 558 5 0 0 0 - - -; #X msg 64 74 GET http://132.205.142.12/nothing; #X msg 44 165 dump \$1; #X obj 44 139 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1; #X obj 37 328 tgl 15 0 empty empty empty 17 7 0 10 -4034 -257985 -1 0 1; #X msg 37 351 verbosity \$1; #X obj 457 543 print more_status; #X obj 76 392 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 -1; #X text 515 726 Author: Martin Peach; #X text 515 743 Date: 2011/01/13; #X text 224 481 The right outlet is the status code.; #X text 166 693 The left outlet is the message body as a list of bytes ; #X text 154 505 The middle outlet is the status header as name/value pairs; #X obj 119 693 spigot; #X obj 119 723 print message_body; #X obj 152 671 tgl 15 0 empty empty printing_long_messages_can_hang_Pd 17 7 0 10 -4034 -257985 -1 0 1; #X text 175 147 [httpreq] sends an HTTP/1.1 request as a list of bytes (actually float atoms) \, suitable for [tcpclient]; #X text 195 444 [htpreceive] expects an HTTP/1.1 response as one or more lists of bytes.; #X text 187 557 message length:; #X obj 27 14 tgl 15 0 empty empty empty 17 7 0 10 -4034 -257985 -1 1 1; #X msg 27 37 verbosity \$1; #X msg 105 115 HEAD http://132.205.142.12/index.php; #X text 175 185 So far only GET and HEAD requests are supported; #X text 274 73 should return 404 not found; #X text 306 93 should return a web page; #X text 332 114 should return only the metainformation; #X connect 0 0 9 0; #X connect 1 0 0 0; #X connect 2 0 0 0; #X connect 3 0 4 0; #X connect 3 1 5 0; #X connect 3 2 6 0; #X connect 3 3 7 0; #X connect 9 0 19 0; #X connect 9 1 3 0; #X connect 9 2 10 0; #X connect 9 3 15 0; #X connect 15 0 12 0; #X connect 15 1 13 0; #X connect 15 2 17 0; #X connect 18 0 9 0; #X connect 19 0 41 0; #X connect 19 1 25 0; #X connect 19 2 20 0; #X connect 22 0 21 0; #X connect 24 0 23 0; #X connect 25 0 22 0; #X connect 25 1 24 0; #X connect 25 2 28 0; #X connect 25 3 27 0; #X connect 25 4 34 0; #X connect 27 0 26 0; #X connect 29 0 0 0; #X connect 30 0 9 0; #X connect 31 0 30 0; #X connect 32 0 33 0; #X connect 33 0 19 0; #X connect 35 0 19 0; #X connect 41 0 42 0; #X connect 43 0 41 1; #X connect 47 0 48 0; #X connect 48 0 0 0; #X connect 49 0 0 0; mrpeach/net/tcpsocket.FUDI-help.pd0000644000175000017500000000022611650367742017530 0ustar zmoelnigzmoelnig#N canvas 171 298 450 300 10; #X text 79 81 This is a support object for; #X obj 252 81 pddp/helplink tcpsocketserver; #X obj 178 123 tcpsocket.FUDI; mrpeach/net/udpsend-help.pd0000644000175000017500000000554013230146704016436 0ustar zmoelnigzmoelnig#N canvas 220 66 1014 638 12; #X msg 198 182 disconnect; #X msg 17 1 connect 127.0.0.1 9997; #X obj 455 482 tgl 15 0 empty empty connected 20 7 0 12 -24198 -258113 -13381 1 1; #X msg 39 23 send 0 1 2 3; #X text 115 459 udpsend sends bytes over a udp connection.; #X text 518 460 Used in conjunction with packOSC will send OSC over udp; #X obj 455 459 udpsend; #X msg 61 45 send examples/test.txt; #X obj 131 91 openpanel; #X msg 131 115 send \$1; #X obj 131 72 bng 15 250 50 0 empty empty empty 17 7 0 10 -24198 -241291 -1; #X text 248 46 send a file; #X text 142 22 send raw data; #X text 151 71 ...any file; #X msg 164 148 99 98 97; #X text 229 148 'send' prefix is optional; #X msg 301 285 multicast_interface 192.168.0.88; #X msg 276 260 multicast_interface eth1; #X msg 228 212 connect 239.200.200.200 9977; #X text 202 0 <--first connect to a host and port; #X text 284 181 <--disconnect before connecting to another address ; #X text 460 211 send to a multicast address; #X text 427 236 specify an interface to use with multicast; #X msg 253 237 multicast_interface 1; #X text 477 259 by index \, name or address; #X floatatom 393 310 5 0 256 0 - - -, f 5; #X obj 375 333 f 1; #X obj 375 313 bng 15 250 50 0 empty empty empty 17 7 0 10 -4034 -1 -1; #X text 227 334 set multicast ttl:; #X msg 375 359 multicast_ttl \$1; #X msg 425 409 multicast_loopback \$1; #X obj 425 387 tgl 15 0 empty empty empty 20 7 0 8 -24198 -241291 -1 0 1; #X text 213 385 enable multicast loopback:; #N canvas 529 111 515 225 META 0; #X text 12 173 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; #X text 12 25 LICENSE GPL v2 or later; #X text 12 153 AUTHOR Martin Peach; #X text 12 5 KEYWORDS control network; #X text 12 117 OUTLET_0 float; #X text 12 81 INLET_0 connect send list disconnect multicast_interface multicast_ttl multicast_loopback; #X text 12 135 OUTLET_1 list; #X text 12 45 DESCRIPTION sends bytes via UDP \; used in conjunction with packOSC to send OSC over UDP; #X restore 798 516 pd META; #X floatatom 508 554 3 0 0 0 - - -, f 3; #X floatatom 542 554 3 0 0 0 - - -, f 3; #X floatatom 578 554 3 0 0 0 - - -, f 3; #X floatatom 614 554 3 0 0 0 - - -, f 3; #X text 448 553 our IP; #X obj 508 526 unpack 0 0 0 0 0; #X floatatom 654 554 6 0 0 0 - - -, f 6; #X obj 508 500 route ourIP; #X text 704 593 Martin Peach 2018/01/18; #X connect 0 0 6 0; #X connect 1 0 6 0; #X connect 3 0 6 0; #X connect 6 0 2 0; #X connect 6 1 41 0; #X connect 7 0 6 0; #X connect 8 0 9 0; #X connect 9 0 6 0; #X connect 10 0 8 0; #X connect 14 0 6 0; #X connect 16 0 6 0; #X connect 17 0 6 0; #X connect 18 0 6 0; #X connect 23 0 6 0; #X connect 25 0 26 1; #X connect 26 0 29 0; #X connect 27 0 26 0; #X connect 29 0 6 0; #X connect 30 0 6 0; #X connect 31 0 30 0; #X connect 39 0 34 0; #X connect 39 1 35 0; #X connect 39 2 36 0; #X connect 39 3 37 0; #X connect 39 4 40 0; #X connect 41 0 39 0; mrpeach/net/Makefile0000644000175000017500000003573711650367742015207 0ustar zmoelnigzmoelnig## Pd library template version 1.0.11 # For instructions on how to use this template, see: # http://puredata.info/docs/developer/MakefileTemplate LIBRARY_NAME = net # add your .c source files, one object per file, to the SOURCES # variable, help files will be included automatically, and for GUI # objects, the matching .tcl file too SOURCES = httpreceive.c httpreq.c tcpclient.c tcpreceive.c tcpsend.c tcpserver.c udpreceive.c udpreceive~.c udpsend.c udpsend~.c # list all pd objects (i.e. myobject.pd) files here, and their helpfiles will # be included automatically PDOBJECTS = tcpsocket.FUDI.pd tcpsocket.OSC.pd tcpsocketserver.pd # example patches and related files, in the 'examples' subfolder EXAMPLES = test.txt # manuals and related files, in the 'manual' subfolder MANUAL = # if you want to include any other files in the source and binary tarballs, # list them here. This can be anything from header files, test patches, # documentation, etc. README.txt and LICENSE.txt are required and therefore # automatically included EXTRA_DIST = #------------------------------------------------------------------------------# # # things you might need to edit if you are using other C libraries # #------------------------------------------------------------------------------# ALL_CFLAGS = -I"$(PD_INCLUDE)" ALL_LDFLAGS = SHARED_LDFLAGS = ALL_LIBS = #------------------------------------------------------------------------------# # # you shouldn't need to edit anything below here, if we did it right :) # #------------------------------------------------------------------------------# # these can be set from outside without (usually) breaking the build CFLAGS = -Wall -W -g LDFLAGS = LIBS = # get library version from meta file LIBRARY_VERSION = $(shell sed -n 's|^\#X text [0-9][0-9]* [0-9][0-9]* VERSION \(.*\);|\1|p' $(LIBRARY_NAME)-meta.pd) ALL_CFLAGS += -DPD -DVERSION='"$(LIBRARY_VERSION)"' PD_INCLUDE = $(PD_PATH)/include/pd # where to install the library, overridden below depending on platform prefix = /usr/local libdir = $(prefix)/lib pkglibdir = $(libdir)/pd-externals objectsdir = $(pkglibdir) INSTALL = install INSTALL_PROGRAM = $(INSTALL) -p -m 644 INSTALL_DATA = $(INSTALL) -p -m 644 INSTALL_DIR = $(INSTALL) -p -m 755 -d ALLSOURCES := $(SOURCES) $(SOURCES_android) $(SOURCES_cygwin) $(SOURCES_macosx) \ $(SOURCES_iphoneos) $(SOURCES_linux) $(SOURCES_windows) DISTDIR=$(LIBRARY_NAME)-$(LIBRARY_VERSION) ORIGDIR=pd-$(LIBRARY_NAME:~=)_$(LIBRARY_VERSION) UNAME := $(shell uname -s) ifeq ($(UNAME),Darwin) CPU := $(shell uname -p) ifeq ($(CPU),arm) # iPhone/iPod Touch SOURCES += $(SOURCES_iphoneos) EXTENSION = pd_darwin SHARED_EXTENSION = dylib OS = iphoneos PD_PATH = /Applications/Pd-extended.app/Contents/Resources IPHONE_BASE=/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin CC=$(IPHONE_BASE)/gcc CPP=$(IPHONE_BASE)/cpp CXX=$(IPHONE_BASE)/g++ ISYSROOT = -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.0.sdk IPHONE_CFLAGS = -miphoneos-version-min=3.0 $(ISYSROOT) -arch armv6 OPT_CFLAGS = -fast -funroll-loops -fomit-frame-pointer ALL_CFLAGS := $(IPHONE_CFLAGS) $(ALL_CFLAGS) ALL_LDFLAGS += -arch armv6 -bundle -undefined dynamic_lookup $(ISYSROOT) SHARED_LDFLAGS += -arch armv6 -dynamiclib -undefined dynamic_lookup $(ISYSROOT) ALL_LIBS += -lc $(LIBS_iphoneos) STRIP = strip -x DISTBINDIR=$(DISTDIR)-$(OS) else # Mac OS X SOURCES += $(SOURCES_macosx) EXTENSION = pd_darwin SHARED_EXTENSION = dylib OS = macosx PD_PATH = /Applications/Pd-extended.app/Contents/Resources OPT_CFLAGS = -ftree-vectorize -ftree-vectorizer-verbose=2 -fast # build universal 32-bit on 10.4 and 32/64 on newer ifeq ($(shell uname -r | sed 's|\([0-9][0-9]*\)\.[0-9][0-9]*\.[0-9][0-9]*|\1|'), 8) FAT_FLAGS = -arch ppc -arch i386 -mmacosx-version-min=10.4 else FAT_FLAGS = -arch ppc -arch i386 -arch x86_64 -mmacosx-version-min=10.4 SOURCES += $(SOURCES_iphoneos) endif ALL_CFLAGS += $(FAT_FLAGS) -fPIC -I/sw/include # if the 'pd' binary exists, check the linking against it to aid with stripping BUNDLE_LOADER = $(shell test ! -e $(PD_PATH)/bin/pd || echo -bundle_loader $(PD_PATH)/bin/pd) ALL_LDFLAGS += $(FAT_FLAGS) -bundle $(BUNDLE_LOADER) -undefined dynamic_lookup -L/sw/lib SHARED_LDFLAGS += $(FAT_FLAGS) -dynamiclib -undefined dynamic_lookup \ -install_name @loader_path/$(SHARED_LIB) -compatibility_version 1 -current_version 1.0 ALL_LIBS += -lc $(LIBS_macosx) STRIP = strip -x DISTBINDIR=$(DISTDIR)-$(OS) # install into ~/Library/Pd on Mac OS X since /usr/local isn't used much pkglibdir=$(HOME)/Library/Pd endif endif # Tho Android uses Linux, we use this fake uname to provide an easy way to # setup all this things needed to cross-compile for Android using the NDK ifeq ($(UNAME),ANDROID) CPU := arm SOURCES += $(SOURCES_android) EXTENSION = pd_linux SHARED_EXTENSION = so OS = android PD_PATH = /usr NDK_BASE := /usr/local/android-ndk NDK_PLATFORM_VERSION := 5 NDK_SYSROOT=$(NDK_BASE)/platforms/android-$(NDK_PLATFORM_VERSION)/arch-arm NDK_UNAME := $(shell uname -s | tr '[A-Z]' '[a-z]') NDK_TOOLCHAIN_BASE=$(NDK_BASE)/toolchains/arm-linux-androideabi-4.4.3/prebuilt/$(NDK_UNAME)-x86 CC := $(NDK_TOOLCHAIN_BASE)/bin/arm-linux-androideabi-gcc --sysroot=$(NDK_SYSROOT) OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer CFLAGS += LDFLAGS += -rdynamic -shared SHARED_LDFLAGS += -Wl,-soname,$(SHARED_LIB) -shared LIBS += -lc $(LIBS_android) STRIP := $(NDK_TOOLCHAIN_BASE)/bin/arm-linux-androideabi-strip \ --strip-unneeded -R .note -R .comment DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m) endif ifeq ($(UNAME),Linux) CPU := $(shell uname -m) SOURCES += $(SOURCES_linux) EXTENSION = pd_linux SHARED_EXTENSION = so OS = linux PD_PATH = /usr OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer ALL_CFLAGS += -fPIC ALL_LDFLAGS += -rdynamic -shared -fPIC -Wl,-rpath,"\$$ORIGIN",--enable-new-dtags SHARED_LDFLAGS += -Wl,-soname,$(SHARED_LIB) -shared ALL_LIBS += -lc $(LIBS_linux) STRIP = strip --strip-unneeded -R .note -R .comment DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m) endif ifeq ($(UNAME),GNU) # GNU/Hurd, should work like GNU/Linux for basically all externals CPU := $(shell uname -m) SOURCES += $(SOURCES_linux) EXTENSION = pd_linux SHARED_EXTENSION = so OS = linux PD_PATH = /usr OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer ALL_CFLAGS += -fPIC ALL_LDFLAGS += -rdynamic -shared -fPIC -Wl,-rpath,"\$$ORIGIN",--enable-new-dtags SHARED_LDFLAGS += -shared -Wl,-soname,$(SHARED_LIB) ALL_LIBS += -lc $(LIBS_linux) STRIP = strip --strip-unneeded -R .note -R .comment DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m) endif ifeq ($(UNAME),GNU/kFreeBSD) # Debian GNU/kFreeBSD, should work like GNU/Linux for basically all externals CPU := $(shell uname -m) SOURCES += $(SOURCES_linux) EXTENSION = pd_linux SHARED_EXTENSION = so OS = linux PD_PATH = /usr OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer ALL_CFLAGS += -fPIC ALL_LDFLAGS += -rdynamic -shared -fPIC -Wl,-rpath,"\$$ORIGIN",--enable-new-dtags SHARED_LDFLAGS += -shared -Wl,-soname,$(SHARED_LIB) ALL_LIBS += -lc $(LIBS_linux) STRIP = strip --strip-unneeded -R .note -R .comment DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m) endif ifeq (CYGWIN,$(findstring CYGWIN,$(UNAME))) CPU := $(shell uname -m) SOURCES += $(SOURCES_cygwin) EXTENSION = dll SHARED_EXTENSION = dll OS = cygwin PD_PATH = $(shell cygpath $$PROGRAMFILES)/pd OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer ALL_CFLAGS += ALL_LDFLAGS += -rdynamic -shared -L"$(PD_PATH)/src" -L"$(PD_PATH)/bin" SHARED_LDFLAGS += -shared -Wl,-soname,$(SHARED_LIB) ALL_LIBS += -lc -lpd $(LIBS_cygwin) STRIP = strip --strip-unneeded -R .note -R .comment DISTBINDIR=$(DISTDIR)-$(OS) endif ifeq (MINGW,$(findstring MINGW,$(UNAME))) CPU := $(shell uname -m) SOURCES += $(SOURCES_windows) EXTENSION = dll SHARED_EXTENSION = dll OS = windows PD_PATH = $(shell cd "$$PROGRAMFILES/pd" && pwd) # MinGW doesn't seem to include cc so force gcc CC=gcc OPT_CFLAGS = -O3 -funroll-loops -fomit-frame-pointer ALL_CFLAGS += -mms-bitfields ALL_LDFLAGS += -s -shared -Wl,--enable-auto-import -L"$(PD_PATH)/src" -L"$(PD_PATH)/bin" -L"$(PD_PATH)/obj" SHARED_LDFLAGS += -shared ALL_LIBS += -lpd -lwsock32 -lkernel32 -luser32 -lgdi32 $(LIBS_windows) STRIP = strip --strip-unneeded -R .note -R .comment DISTBINDIR=$(DISTDIR)-$(OS) endif # in case somebody manually set the HELPPATCHES above HELPPATCHES ?= $(SOURCES:.c=-help.pd) $(PDOBJECTS:.pd=-help.pd) ALL_CFLAGS := $(ALL_CFLAGS) $(CFLAGS) $(OPT_CFLAGS) ALL_LDFLAGS := $(LDFLAGS) $(ALL_LDFLAGS) ALL_LIBS := $(LIBS) $(ALL_LIBS) SHARED_SOURCE ?= $(shell test ! -e lib$(LIBRARY_NAME).c || \ echo lib$(LIBRARY_NAME).c ) SHARED_HEADER ?= $(shell test ! -e $(LIBRARY_NAME).h || echo $(LIBRARY_NAME).h) SHARED_LIB = $(SHARED_SOURCE:.c=.$(SHARED_EXTENSION)) .PHONY = install libdir_install single_install install-doc install-examples install-manual clean distclean dist etags $(LIBRARY_NAME) all: $(SOURCES:.c=.$(EXTENSION)) $(SHARED_LIB) %.o: %.c $(CC) $(ALL_CFLAGS) -o "$*.o" -c "$*.c" %.$(EXTENSION): %.o $(SHARED_LIB) $(CC) $(ALL_LDFLAGS) -o "$*.$(EXTENSION)" "$*.o" $(ALL_LIBS) $(SHARED_LIB) chmod a-x "$*.$(EXTENSION)" # this links everything into a single binary file $(LIBRARY_NAME): $(SOURCES:.c=.o) $(LIBRARY_NAME).o $(CC) $(ALL_LDFLAGS) -o $(LIBRARY_NAME).$(EXTENSION) $(SOURCES:.c=.o) $(LIBRARY_NAME).o $(ALL_LIBS) chmod a-x $(LIBRARY_NAME).$(EXTENSION) $(SHARED_LIB): $(SHARED_SOURCE:.c=.o) $(CC) $(SHARED_LDFLAGS) -o $(SHARED_LIB) $(SHARED_SOURCE:.c=.o) $(LIBS) install: libdir_install # The meta and help files are explicitly installed to make sure they are # actually there. Those files are not optional, then need to be there. libdir_install: $(SOURCES:.c=.$(EXTENSION)) $(SHARED_LIB) install-doc install-examples install-manual $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) $(INSTALL_DATA) $(LIBRARY_NAME)-meta.pd \ $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) test -z "$(strip $(SOURCES))" || (\ $(INSTALL_PROGRAM) $(SOURCES:.c=.$(EXTENSION)) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) && \ $(STRIP) $(addprefix $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/,$(SOURCES:.c=.$(EXTENSION)))) test -z "$(strip $(SHARED_LIB))" || \ $(INSTALL_DATA) $(SHARED_LIB) \ $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) test -z "$(strip $(wildcard $(SOURCES:.c=.tcl)))" || \ $(INSTALL_DATA) $(wildcard $(SOURCES:.c=.tcl)) \ $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) test -z "$(strip $(PDOBJECTS))" || \ $(INSTALL_DATA) $(PDOBJECTS) \ $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) # install library linked as single binary single_install: $(LIBRARY_NAME) install-doc install-examples install-manual $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) $(INSTALL_PROGRAM) $(LIBRARY_NAME).$(EXTENSION) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) $(STRIP) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/$(LIBRARY_NAME).$(EXTENSION) install-doc: $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) test -z "$(strip $(SOURCES) $(PDOBJECTS))" || \ $(INSTALL_DATA) $(HELPPATCHES) \ $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) $(INSTALL_DATA) README.txt $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/README.txt $(INSTALL_DATA) LICENSE.txt $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/LICENSE.txt install-examples: test -z "$(strip $(EXAMPLES))" || \ $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/examples && \ for file in $(EXAMPLES); do \ $(INSTALL_DATA) examples/$$file $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/examples; \ done install-manual: test -z "$(strip $(MANUAL))" || \ $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/manual && \ for file in $(MANUAL); do \ $(INSTALL_DATA) manual/$$file $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/manual; \ done clean: -rm -f -- $(SOURCES:.c=.o) $(SOURCES_LIB:.c=.o) $(SHARED_SOURCE:.c=.o) -rm -f -- $(SOURCES:.c=.$(EXTENSION)) -rm -f -- $(LIBRARY_NAME).o -rm -f -- $(LIBRARY_NAME).$(EXTENSION) -rm -f -- $(SHARED_LIB) distclean: clean -rm -f -- $(DISTBINDIR).tar.gz -rm -rf -- $(DISTBINDIR) -rm -f -- $(DISTDIR).tar.gz -rm -rf -- $(DISTDIR) -rm -f -- $(ORIGDIR).tar.gz -rm -rf -- $(ORIGDIR) $(DISTBINDIR): $(INSTALL_DIR) $(DISTBINDIR) libdir: all $(DISTBINDIR) $(INSTALL_DATA) $(LIBRARY_NAME)-meta.pd $(DISTBINDIR) $(INSTALL_DATA) $(SOURCES) $(SHARED_SOURCE) $(SHARED_HEADER) $(DISTBINDIR) $(INSTALL_DATA) $(HELPPATCHES) $(DISTBINDIR) test -z "$(strip $(EXTRA_DIST))" || \ $(INSTALL_DATA) $(EXTRA_DIST) $(DISTBINDIR) # tar --exclude-vcs -czpf $(DISTBINDIR).tar.gz $(DISTBINDIR) $(DISTDIR): $(INSTALL_DIR) $(DISTDIR) $(ORIGDIR): $(INSTALL_DIR) $(ORIGDIR) dist: $(DISTDIR) $(INSTALL_DATA) Makefile $(DISTDIR) $(INSTALL_DATA) README.txt $(DISTDIR) $(INSTALL_DATA) LICENSE.txt $(DISTDIR) $(INSTALL_DATA) $(LIBRARY_NAME)-meta.pd $(DISTDIR) test -z "$(strip $(ALLSOURCES))" || \ $(INSTALL_DATA) $(ALLSOURCES) $(DISTDIR) test -z "$(strip $(wildcard $(ALLSOURCES:.c=.tcl)))" || \ $(INSTALL_DATA) $(wildcard $(ALLSOURCES:.c=.tcl)) $(DISTDIR) test -z "$(strip $(SHARED_HEADER))" || \ $(INSTALL_DATA) $(SHARED_HEADER) $(DISTDIR) test -z "$(strip $(SHARED_SOURCE))" || \ $(INSTALL_DATA) $(SHARED_SOURCE) $(DISTDIR) test -z "$(strip $(PDOBJECTS))" || \ $(INSTALL_DATA) $(PDOBJECTS) $(DISTDIR) test -z "$(strip $(HELPPATCHES))" || \ $(INSTALL_DATA) $(HELPPATCHES) $(DISTDIR) test -z "$(strip $(EXTRA_DIST))" || \ $(INSTALL_DATA) $(EXTRA_DIST) $(DISTDIR) test -z "$(strip $(EXAMPLES))" || \ $(INSTALL_DIR) $(DISTDIR)/examples && \ for file in $(EXAMPLES); do \ $(INSTALL_DATA) examples/$$file $(DISTDIR)/examples; \ done test -z "$(strip $(MANUAL))" || \ $(INSTALL_DIR) $(DISTDIR)/manual && \ for file in $(MANUAL); do \ $(INSTALL_DATA) manual/$$file $(DISTDIR)/manual; \ done tar --exclude-vcs -czpf $(DISTDIR).tar.gz $(DISTDIR) # make a Debian source package dpkg-source: debclean make distclean dist mv $(DISTDIR) $(ORIGDIR) tar --exclude-vcs -czpf ../$(ORIGDIR).orig.tar.gz $(ORIGDIR) rm -f -- $(DISTDIR).tar.gz rm -rf -- $(DISTDIR) $(ORIGDIR) cd .. && dpkg-source -b $(LIBRARY_NAME) etags: etags *.h $(SOURCES) ../../pd/src/*.[ch] /usr/include/*.h /usr/include/*/*.h showsetup: @echo "CC: $(CC)" @echo "CFLAGS: $(CFLAGS)" @echo "LDFLAGS: $(LDFLAGS)" @echo "LIBS: $(LIBS)" @echo "ALL_CFLAGS: $(ALL_CFLAGS)" @echo "ALL_LDFLAGS: $(ALL_LDFLAGS)" @echo "ALL_LIBS: $(ALL_LIBS)" @echo "PD_INCLUDE: $(PD_INCLUDE)" @echo "PD_PATH: $(PD_PATH)" @echo "objectsdir: $(objectsdir)" @echo "LIBRARY_NAME: $(LIBRARY_NAME)" @echo "LIBRARY_VERSION: $(LIBRARY_VERSION)" @echo "SOURCES: $(SOURCES)" @echo "SHARED_HEADER: $(SHARED_HEADER)" @echo "SHARED_SOURCE: $(SHARED_SOURCE)" @echo "SHARED_LIB: $(SHARED_LIB)" @echo "PDOBJECTS: $(PDOBJECTS)" @echo "ALLSOURCES: $(ALLSOURCES)" @echo "ALLSOURCES TCL: $(wildcard $(ALLSOURCES:.c=.tcl))" @echo "UNAME: $(UNAME)" @echo "CPU: $(CPU)" @echo "pkglibdir: $(pkglibdir)" @echo "DISTDIR: $(DISTDIR)" @echo "ORIGDIR: $(ORIGDIR)" mrpeach/net/udpsend~.h0000644000175000017500000001065011464353051015532 0ustar zmoelnigzmoelnig/* udpsend~.h modified by Martin Peach from netsend~.h: */ /* ------------------------ netsend~ ------------------------------------------ */ /* */ /* Tilde object to send uncompressed audio data to netreceive~. */ /* Written by Olaf Matthes . */ /* Based on streamout~ by Guenter Geiger. */ /* Get source at http://www.akustische-kunst.org/ */ /* */ /* This program is free software; you can redistribute it and/or */ /* modify it under the terms of the GNU General Public License */ /* as published by the Free Software Foundation; either version 2 */ /* of the License, or (at your option) any later version. */ /* */ /* See file LICENSE for further informations on licensing terms. */ /* */ /* This program is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with this program; if not, write to the Free Software */ /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* */ /* Based on PureData by Miller Puckette and others. */ /* */ /* This project was commissioned by the Society for Arts and Technology [SAT], */ /* Montreal, Quebec, Canada, http://www.sat.qc.ca/. */ /* */ /* ---------------------------------------------------------------------------- */ /* This file is based on and inspired by stream.h (C) Guenter Geiger 1999. */ /* Some enhancements have been made with the goal of keeping compatibility */ /* between the stream formats of streamout~/in~ and netsend~/receive~. */ #define VERSION "0.34" #define DEFAULT_AUDIO_CHANNELS 32 /* nax. number of audio channels we support */ #define DEFAULT_AUDIO_BUFFER_SIZE 2048 /*1024*/ /* number of samples in one audio block */ #define DEFAULT_UDP_PACKT_SIZE 8192 /* number of bytes we send in one UDP datagram (OS X only) */ #define DEFAULT_PORT 8000 /* default network port number */ #ifdef _WIN32 #ifndef HAVE_INT32_T typedef int int32_t; #define HAVE_INT32_T #endif #ifndef HAVE_INT16_T typedef short int16_t; #define HAVE_INT16_T #endif #ifndef HAVE_U_INT32_T typedef unsigned int u_int32_t; #define HAVE_U_INT32_T #endif #ifndef HAVE_U_INT16_T typedef unsigned short u_int16_t; #define HAVE_U_INT16_T #endif #endif typedef union _flint { int i32; t_float f32; } flint; /* format specific stuff */ #define SF_FLOAT 1 #define SF_DOUBLE 2 /* not implemented */ #define SF_8BIT 10 #define SF_16BIT 11 #define SF_32BIT 12 /* not implemented */ #define SF_ALAW 20 /* not implemented */ #define SF_MP3 30 /* not implemented */ #define SF_AAC 31 /* AAC encoding using FAAC */ #define SF_VORBIS 40 /* not implemented */ #define SF_FLAC 50 /* not implemented */ #define SF_SIZEOF(a) (a == SF_FLOAT ? sizeof(t_float) : \ a == SF_16BIT ? sizeof(short) : 1) typedef struct _tag { /* size (bytes) */ char tag[4]; /* 4 */ /*"TAG!"*/ char format; /* 1 */ int count; /* 4 */ char channels; /* 1 */ int framesize; /* 4 */ char reserved[2]; /* 2 */ /* pad to 16 bytes */ } t_tag; /*-----*/ /* 16 */ typedef struct _frame { t_tag tag; char *data; } t_frame; /* fin udpsend~.h */ mrpeach/net/tcpsocket.OSC.pd0000644000175000017500000000462711522100264016466 0ustar zmoelnigzmoelnig#N canvas 636 71 455 534 10; #X obj 50 49 == \$2; #X obj 7 28 route in socket; #X obj 7 76 spigot; #N canvas 622 183 512 335 reset 0; #X obj 23 41 route \$2; #X obj 23 63 route reset; #X obj 23 83 t b b; #X msg 55 170 done; #X obj 23 113 outlet; #X text 161 33 this is used to:; #X text 87 114 a) reset the sockethandler on a new connection; #X text 88 129 (for instance \, if the previous connection was quitted in the middle of a packet).; #X text 55 213 b) check for the socketserver \, if a sockethandler on specified socket already exists.; #X obj 55 191 s \$1.TCPSOCKET; #X obj 23 19 r \$1.TCPSOCKET; #X connect 0 0 1 0; #X connect 1 0 2 0; #X connect 2 0 4 0; #X connect 2 1 3 0; #X connect 3 0 9 0; #X connect 10 0 0 0; #X restore 40 102 pd reset; #X obj 104 280 route socket ip; #X obj 41 367 list append; #X obj 58 323 list append; #X obj 7 299 t a b b b; #X obj 7 414 list prepend out; #X obj 41 391 list prepend socket.out; #X obj 58 345 list prepend ip.out; #X obj 7 442 list trim; #X text 16 220 the lower part makes [tcpsocketserver] behave like [tcpserver] ; #X obj -2 136 cnv 15 450 70 empty empty empty 20 12 0 14 -204786 -66577 0; #X text 70 162 <- PUT HERE THE PROTOCOL SPECIFIC DELIMITER CODE; #X text 15 197 -------------------------------------------------------- ; #X text 13 129 -------------------------------------------------------- ; #X obj 7 6 r \$1.TCPSOCKET; #X obj 7 465 s \$1.TCPSOCKET; #X obj 104 256 r \$1.TCPSOCKET; #X text 200 454 Author: Roman Haefeli; #X text 55 75 <- only pass stream of own socket; #N canvas 389 116 266 236 OSC 0; #X obj 27 18 inlet; #X obj 27 186 outlet; #X obj 144 23 inlet; #X text 194 23 reset; #X obj 27 123 mrpeach/slipdec 16384; #X obj 27 151 spigot 1; #X obj 144 45 t b b b; #X msg 163 67 192 192; #X msg 183 99 0; #X msg 144 100 1; #X connect 0 0 4 0; #X connect 2 0 6 0; #X connect 4 0 5 0; #X connect 5 0 1 0; #X connect 6 0 9 0; #X connect 6 1 7 0; #X connect 6 2 8 0; #X connect 7 0 4 0; #X connect 8 0 5 1; #X connect 9 0 5 1; #X restore 7 161 pd OSC; #X text 201 474 Version: 2011-01-05; #X connect 0 0 2 1; #X connect 1 0 2 0; #X connect 1 1 0 0; #X connect 2 0 22 0; #X connect 3 0 22 1; #X connect 4 0 5 1; #X connect 4 1 6 1; #X connect 5 0 9 0; #X connect 6 0 10 0; #X connect 7 0 8 0; #X connect 7 2 5 0; #X connect 7 3 6 0; #X connect 8 0 11 0; #X connect 9 0 11 0; #X connect 10 0 11 0; #X connect 11 0 18 0; #X connect 17 0 1 0; #X connect 19 0 4 0; #X connect 22 0 7 0; mrpeach/net/tcpreceive.c0000644000175000017500000002436011533505450016020 0ustar zmoelnigzmoelnig/* x_net_tcpreceive.c 20060424. Martin Peach did it based on x_net.c. x_net.c header follows: */ /* Copyright (c) 1997-1999 Miller Puckette. * For information on usage and redistribution, and for a DISCLAIMER OF ALL * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ #include "m_pd.h" #include "s_stuff.h" #ifdef _WIN32 #include #include /* for socklen_t */ #else #include #include #include #include #include #include #endif /* ----------------------------- tcpreceive ------------------------- */ static t_class *tcpreceive_class; #define MAX_UDP_RECEIVE 65536L // longer than data in maximum UDP packet #define MAX_CONNECTIONS 128 // this is going to cause trouble down the line...:( typedef struct _tcpconnection { long addr; unsigned short port; int socket; } t_tcpconnection; typedef struct _tcpreceive { t_object x_obj; t_outlet *x_msgout; t_outlet *x_addrout; t_outlet *x_connectout; int x_connectsocket; int x_nconnections; t_tcpconnection x_connection[MAX_CONNECTIONS]; t_atom x_addrbytes[5]; t_atom x_msgoutbuf[MAX_UDP_RECEIVE]; unsigned char x_msginbuf[MAX_UDP_RECEIVE]; } t_tcpreceive; void tcpreceive_setup(void); static void tcpreceive_free(t_tcpreceive *x); static void *tcpreceive_new(t_floatarg fportno); static void tcpreceive_read(t_tcpreceive *x, int sockfd); static void tcpreceive_connectpoll(t_tcpreceive *x); static int tcpreceive_addconnection(t_tcpreceive * x, int fd, long addr, unsigned short port); static int tcpreceive_removeconnection(t_tcpreceive * x, int fd); static void tcpreceive_closeall(t_tcpreceive *x); static long tcpreceive_getconnection(t_tcpreceive * x, int fd); static unsigned short tcpreceive_getconnectionport(t_tcpreceive * x, int fd); static void tcpreceive_read(t_tcpreceive *x, int sockfd) { int i, read = 0; long addr; unsigned short port; // read = recvfrom(sockfd, x->x_msginbuf, MAX_UDP_RECEIVE, 0, (struct sockaddr *)&from, &fromlen); read = recv(sockfd, x->x_msginbuf, MAX_UDP_RECEIVE, 0); #ifdef DEBUG post("tcpreceive_read: read %lu x->x_connectsocket = %d", read, x->x_connectsocket); #endif if (read < 0) { sys_sockerror("tcpreceive_read: recv"); sys_rmpollfn(sockfd); sys_closesocket(sockfd); tcpreceive_removeconnection(x, sockfd); outlet_float(x->x_connectout, --x->x_nconnections); } else if (read == 0) { post("tcpreceive: EOF on socket %d\n", sockfd); sys_rmpollfn(sockfd); sys_closesocket(sockfd); tcpreceive_removeconnection(x, sockfd); outlet_float(x->x_connectout, --x->x_nconnections); } else if (read > 0) { for (i = 0; i < read; ++i) { /* convert the bytes in the buffer to floats in a list */ x->x_msgoutbuf[i].a_w.w_float = (float)x->x_msginbuf[i]; } /* find sender's ip address and output it */ addr = tcpreceive_getconnection(x, sockfd); port = tcpreceive_getconnectionport(x, sockfd); x->x_addrbytes[0].a_w.w_float = (addr & 0xFF000000)>>24; x->x_addrbytes[1].a_w.w_float = (addr & 0x0FF0000)>>16; x->x_addrbytes[2].a_w.w_float = (addr & 0x0FF00)>>8; x->x_addrbytes[3].a_w.w_float = (addr & 0x0FF); x->x_addrbytes[4].a_w.w_float = port; outlet_list(x->x_addrout, &s_list, 5L, x->x_addrbytes); /* send the list out the outlet */ if (read > 1) outlet_list(x->x_msgout, &s_list, read, x->x_msgoutbuf); else outlet_float(x->x_msgout, x->x_msgoutbuf[0].a_w.w_float); } } static void *tcpreceive_new(t_floatarg fportno) { t_tcpreceive *x; struct sockaddr_in server; int sockfd, portno = fportno; int intarg, i; /* create a socket */ sockfd = socket(AF_INET, SOCK_STREAM, 0); #ifdef DEBUG post("tcpreceive_new: socket %d port %d", sockfd, portno); #endif if (sockfd < 0) { sys_sockerror("tcpreceive: socket"); return (0); } server.sin_family = AF_INET; server.sin_addr.s_addr = INADDR_ANY; /* ask OS to allow another Pd to repoen this port after we close it. */ intarg = 1; if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&intarg, sizeof(intarg)) < 0) post("tcpreceive: setsockopt (SO_REUSEADDR) failed"); /* Stream (TCP) sockets are set NODELAY */ intarg = 1; if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char *)&intarg, sizeof(intarg)) < 0) post("setsockopt (TCP_NODELAY) failed\n"); /* assign server port number */ server.sin_port = htons((u_short)portno); /* name the socket */ if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0) { sys_sockerror("tcpreceive: bind"); sys_closesocket(sockfd); return (0); } x = (t_tcpreceive *)pd_new(tcpreceive_class); x->x_msgout = outlet_new(&x->x_obj, &s_anything); x->x_addrout = outlet_new(&x->x_obj, &s_list); x->x_connectout = outlet_new(&x->x_obj, &s_float); /* clear the connection list */ for (i = 0; i < MAX_CONNECTIONS; ++i) { x->x_connection[i].socket = -1; x->x_connection[i].addr = 0L; x->x_connection[i].port = 0; } /* convert the bytes in the buffer to floats in a list */ for (i = 0; i < MAX_UDP_RECEIVE; ++i) { x->x_msgoutbuf[i].a_type = A_FLOAT; x->x_msgoutbuf[i].a_w.w_float = 0; } for (i = 0; i < 5; ++i) { x->x_addrbytes[i].a_type = A_FLOAT; x->x_addrbytes[i].a_w.w_float = 0; } /* streaming protocol */ if (listen(sockfd, 5) < 0) { sys_sockerror("tcpreceive: listen"); sys_closesocket(sockfd); sockfd = -1; } else { sys_addpollfn(sockfd, (t_fdpollfn)tcpreceive_connectpoll, x); } x->x_connectsocket = sockfd; x->x_nconnections = 0; //udp version... sys_addpollfn(x->x_connectsocket, (t_fdpollfn)tcpreceive_read, x); return (x); } /* tcpreceive_connectpoll checks for incoming connection requests on the original socket */ /* a new socket is assigned */ static void tcpreceive_connectpoll(t_tcpreceive *x) { struct sockaddr_in from; socklen_t fromlen = sizeof(from); long addr; unsigned short port; int fd; fd = accept(x->x_connectsocket, (struct sockaddr *)&from, &fromlen); if (fd < 0) post("tcpreceive: accept failed"); else { // t_socketreceiver *y = socketreceiver_new((void *)x, // (t_socketnotifier)tcpreceive_notify, // 0, 0); /* get the sender's ip */ addr = ntohl(from.sin_addr.s_addr); port = ntohs(from.sin_port); if (tcpreceive_addconnection(x, fd, addr, port)) { sys_addpollfn(fd, (t_fdpollfn)tcpreceive_read, x); outlet_float(x->x_connectout, ++x->x_nconnections); x->x_addrbytes[0].a_w.w_float = (addr & 0xFF000000)>>24; x->x_addrbytes[1].a_w.w_float = (addr & 0x0FF0000)>>16; x->x_addrbytes[2].a_w.w_float = (addr & 0x0FF00)>>8; x->x_addrbytes[3].a_w.w_float = (addr & 0x0FF); x->x_addrbytes[4].a_w.w_float = port; outlet_list(x->x_addrout, &s_list, 5L, x->x_addrbytes); } else { error ("tcpreceive: Too many connections"); sys_closesocket(fd); } } } /* tcpreceive_addconnection tries to add the socket fd to the list */ /* returns 1 on success, else 0 */ static int tcpreceive_addconnection(t_tcpreceive *x, int fd, long addr, unsigned short port) { int i; for (i = 0; i < MAX_CONNECTIONS; ++i) { if (x->x_connection[i].socket == -1) { x->x_connection[i].socket = fd; x->x_connection[i].addr = addr; x->x_connection[i].port = port; return 1; } } return 0; } /* tcpreceive_closeall closes all open sockets and deletes them from the list */ static void tcpreceive_closeall(t_tcpreceive *x) { int i; for (i = 0; ((i < MAX_CONNECTIONS) && (x->x_nconnections > 0)); ++i) { if (x->x_connection[i].socket != -1) { post ("tcpreceive: closing socket %d", x->x_connection[i].socket); sys_rmpollfn(x->x_connection[i].socket); sys_closesocket(x->x_connection[i].socket); x->x_connection[i].socket = -1; x->x_connection[i].addr = 0L; x->x_connection[i].port = 0; outlet_float(x->x_connectout, --x->x_nconnections); } } } /* tcpreceive_removeconnection tries to delete the socket fd from the list */ /* returns 1 on success, else 0 */ static int tcpreceive_removeconnection(t_tcpreceive *x, int fd) { int i; for (i = 0; i < MAX_CONNECTIONS; ++i) { if (x->x_connection[i].socket == fd) { x->x_connection[i].socket = -1; x->x_connection[i].addr = 0L; x->x_connection[i].port = 0; return 1; } } return 0; } /* tcpreceive_getconnectionport tries to find the socket fd in the list */ /* returns port on success, else 0 */ static u_short tcpreceive_getconnectionport(t_tcpreceive *x, int fd) { int i; for (i = 0; i < MAX_CONNECTIONS; ++i) { if (x->x_connection[i].socket == fd) return x->x_connection[i].port; } return 0; } /* tcpreceive_getconnection tries to find the socket fd in the list */ /* returns addr on success, else 0 */ static long tcpreceive_getconnection(t_tcpreceive *x, int fd) { int i; for (i = 0; i < MAX_CONNECTIONS; ++i) { if (x->x_connection[i].socket == fd) return x->x_connection[i].addr; } return 0; } static void tcpreceive_free(t_tcpreceive *x) { /* is this ever called? */ if (x->x_connectsocket >= 0) { sys_rmpollfn(x->x_connectsocket); sys_closesocket(x->x_connectsocket); } tcpreceive_closeall(x); } void tcpreceive_setup(void) { tcpreceive_class = class_new(gensym("tcpreceive"), (t_newmethod)tcpreceive_new, (t_method)tcpreceive_free, sizeof(t_tcpreceive), CLASS_NOINLET, A_DEFFLOAT, 0); } /* end x_net_tcpreceive.c */ mrpeach/net/tcpsocketserver-help.pd0000644000175000017500000002305311732442422020222 0ustar zmoelnigzmoelnig#N canvas 361 252 878 523 10; #X declare -stdpath extra/mrpeach; #X declare -stdpath extra/mrpeach; #X declare -lib moocow; #X declare -stdpath extra/mrpeach; #X declare -lib moocow; #X msg 471 74 print; #X text 521 75 list of connections; #X text 627 103 send to all clients; #X text 629 132 send to client 1; #X text 615 155 send to client on socket 504; #X text 613 28 'send' prefix is optional; #X text 474 48 (the first number is socket number); #X msg 556 257 disconnectsocket \$1; #X msg 484 284 disconnectclient \$1; #X floatatom 506 215 5 0 0 0 - - -; #X obj 484 235 f; #X obj 484 216 bng 15 250 50 0 empty empty empty 17 7 0 10 -258699 -241291 -1; #X floatatom 578 216 5 0 0 0 - - -; #X obj 556 235 f; #X obj 556 216 bng 15 250 50 0 empty empty empty 17 7 0 10 -258699 -241291 -1; #X text 483 197 disconnect by socket or client number; #X obj 618 335 unpack 0 0 0 0; #X floatatom 618 355 3 0 0 0 - - -; #X floatatom 649 355 3 0 0 0 - - -; #X floatatom 681 356 3 0 0 0 - - -; #X floatatom 715 356 3 0 0 0 - - -; #X text 616 372 IP; #X floatatom 569 355 5 0 0 0 - - -; #X text 566 371 socket; #X floatatom 520 376 5 0 0 0 - - -; #X text 520 391 number of connections; #X obj 471 433 spigot; #X obj 510 413 tgl 15 0 empty empty enable_print 17 7 0 10 -24198 -258699 -258699 0 1; #X text 15 37 [tcpsocketserver ]; #X obj 469 311 cnv 15 185 22 empty empty empty 20 12 0 14 -204786 -66577 0; #X obj 471 314 tcpsocketserver FUDI 2468; #X text 15 115 [tcpsocketserver] is able to handle multiple sockets of a packet oriented protocol correctly \, unlike [tcpserver] \, which might mix up packets from different sockets.; #X text 24 308 - OSC; #X text 16 245 each protocol requires its own specific socket handler abstraction \, which should be named [tcpsocket.PROTOCOL]. currently available are the protocols:; #X text 23 293 - FUDI; #N canvas 702 157 472 356 EXTENDABILITY 0; #X text 3 39 Support for more protocols can easily be added. In order to do so:; #X text 5 10 EXTENDABILITY; #X text 6 105 - open tcpsocket.NEWPROTOCOL.pd; #X text 7 127 - edit the green-marked subpatch; #X text 10 208 - save it; #X text 12 227 - in order to use it \, instantiate:; #X text 46 247 [tcpsocketserver NEWPROTOCOL ]; #X text 8 148 - replace code with code \, that creates proper packets out of the incoming stream for the desired protocol. don't forget to implement a reset mechanism \, in case a socket is closed in the middle of packet transmission.; #X text 5 83 - copy tcpsocket.FUDI.pd to tcpsocket.NEWPROTOCOL.pd; #X restore 21 387 pd EXTENDABILITY; #X text 17 453 Author: Roman Haefeli; #X text 16 468 Version: 2009-01-11; #X text 15 65 [tcpsocketserver] is meant to be a protocol-aware drop-in replacement for [tcpserver]. it uses same the same inlet and outlet configuration as [tcpserver].; #X text 469 478 only well-formed FUDI messages are received here.; #N canvas 463 454 147 274 EXAMPLES 0; #N canvas 705 77 571 769 FUDI 0; #X obj 8 52 cnv 15 550 240 empty empty client_1 20 12 0 14 -249661 -66577 0; #X obj 24 206 tcpclient; #X msg 368 107 connect localhost 11001; #X msg 392 128 disconnect; #X obj 368 85 sel 1 0; #X obj 368 64 tgl 15 0 empty empty empty 17 7 0 10 -261234 -1 -1 0 1; #X obj 24 272 print CLIENT_1; #X msg 24 83 one two; #X obj 24 104 any2string 0 -1; #X msg 68 164 59 10; #X msg 32 130 32 116 104 114 101 101 23; #X obj 8 299 cnv 15 550 150 empty empty client_2 20 12 0 14 -249661 -66577 0; #X msg 368 354 connect localhost 11001; #X msg 392 375 disconnect; #X obj 368 332 sel 1 0; #X obj 368 311 tgl 15 0 empty empty empty 17 7 0 10 -261234 -1 -1 0 1; #X obj 24 227 string2any 0 59; #X obj 24 247 route bang; #X obj 24 386 netclient; #X obj 24 415 print CLIENT_2; #X text 168 337 <- send FUDI message; #X obj 9 457 cnv 15 550 300 empty empty FUDI_server 20 12 0 14 -241408 -66577 0; #X obj 11 613 tcpsocketserver FUDI 11001; #X obj 11 687 string2any 0 59; #X obj 11 708 route bang; #X obj 190 633 unpack 0 0 0 0; #X floatatom 190 653 3 0 0 0 - - -; #X floatatom 221 653 3 0 0 0 - - -; #X floatatom 253 654 3 0 0 0 - - -; #X floatatom 287 654 3 0 0 0 - - -; #X text 188 670 IP; #X floatatom 130 653 5 0 0 0 - - -; #X floatatom 70 654 5 0 0 0 - - -; #X text 59 669 clients; #X text 126 669 socket; #X text 131 688 <--; #X text 164 688 [tcpsocketserver FUDI] does _not_ remove the trailing ' \; '; #X text 164 83 1) start a FUDI message; #X text 231 131 2) continue; #X text 117 165 3) finish FUDI message (with semicolon - newline); #X text 390 65 connect; #X text 389 309 connect; #X text 19 488 [tcpsocketserver FUDI] doesn't take care of building FUDI-compliant messages. this should be done by the user.; #X text 153 229 4) try sending a message from client_2 during composing a message with client_1 and see \, how the server behaves.; #X text 278 535 <- this doesn't work; #X text 314 562 <- this should; #X msg 24 336 send four five six; #X msg 42 563 client 2 115 101 118 101 110 32 59 10; #X msg 41 534 client 2 115 101 118 101 110 32; #X obj 11 733 print SERVER; #X obj 20 32 import moocow; #X connect 1 0 16 0; #X connect 2 0 1 0; #X connect 3 0 1 0; #X connect 4 0 2 0; #X connect 4 1 3 0; #X connect 5 0 4 0; #X connect 7 0 8 0; #X connect 8 0 1 0; #X connect 9 0 1 0; #X connect 10 0 1 0; #X connect 12 0 18 0; #X connect 13 0 18 0; #X connect 14 0 12 0; #X connect 14 1 13 0; #X connect 15 0 14 0; #X connect 16 0 17 0; #X connect 17 1 6 0; #X connect 18 0 19 0; #X connect 22 0 23 0; #X connect 22 1 32 0; #X connect 22 2 31 0; #X connect 22 3 25 0; #X connect 23 0 24 0; #X connect 24 1 49 0; #X connect 25 0 26 0; #X connect 25 1 27 0; #X connect 25 2 28 0; #X connect 25 3 29 0; #X connect 46 0 18 0; #X connect 47 0 22 0; #X connect 48 0 22 0; #X restore 23 25 pd FUDI; #N canvas 697 77 579 756 OSC 0; #X obj 9 39 cnv 15 550 240 empty empty client_1 20 12 0 14 -249661 -66577 0; #X obj 25 211 tcpclient; #X msg 357 229 disconnect; #X obj 333 186 sel 1 0; #X obj 333 165 tgl 15 0 empty empty empty 17 7 0 10 -261234 -1 -1 0 1; #X obj 25 259 print CLIENT_1; #X obj 9 286 cnv 15 550 150 empty empty client_2 20 12 0 14 -249661 -66577 0; #X msg 393 362 disconnect; #X obj 369 319 sel 1 0; #X obj 369 298 tgl 15 0 empty empty empty 17 7 0 10 -261234 -1 -1 0 1; #X obj 25 417 print CLIENT_2; #X obj 10 444 cnv 15 550 300 empty empty OSC_server 20 12 0 14 -241408 -66577 0; #X obj 188 636 unpack 0 0 0 0; #X floatatom 188 656 3 0 0 0 - - -; #X floatatom 219 656 3 0 0 0 - - -; #X floatatom 251 657 3 0 0 0 - - -; #X floatatom 285 657 3 0 0 0 - - -; #X text 186 673 IP; #X floatatom 130 656 5 0 0 0 - - -; #X floatatom 73 657 5 0 0 0 - - -; #X text 62 672 clients; #X text 126 672 socket; #X text 355 166 connect; #X text 390 296 connect; #X obj 16 616 tcpsocketserver OSC 11002; #X obj 16 694 unpackOSC; #X obj 16 720 print SERVER; #X msg 333 208 connect localhost 11002; #X msg 369 341 connect localhost 11002; #X obj 25 234 unpackOSCstream; #X obj 25 373 tcpclient; #X obj 25 395 unpackOSCstream; #X msg 49 498 /synth1/tone3/freq 440; #X msg 25 79 0 0 0 16 47 102 114 101 113; #X msg 41 104 0 0 0 44 105 0 0 0 0 1 184; #X text 155 324 send OSC message; #X msg 25 323 /amplitude 0.78; #X obj 25 347 packOSCstream; #X obj 16 522 packOSCstream; #X obj 16 594 list trim; #X msg 16 473 /synth3/tone4/amplitude 0.36; #X obj 180 555 hradio 15 1 0 2 empty empty empty 0 -8 0 10 -4034 -1 -1 0; #X obj 180 573 + 1; #X text 221 555 client; #X obj 16 551 list prepend 1; #X obj 16 573 list prepend client; #X text 236 80 1) start sending an OSC packet; #X text 247 106 2) complete the OSC packet; #X text 59 137 also try sending an OSC packet from client_2 between 1) and 2); #X text 124 520 <- use [packOSCstream] in order to create OSC packets suitable for tcp transport.; #X text 238 486 send to clients; #X text 93 695 <---; #X text 139 694 CAUTION: not [unpackOSCstream] is used here \, since [tcpsocket.OSC] already unwraps the OSC message; #X obj 8 9 import moocow; #X connect 1 0 29 0; #X connect 2 0 1 0; #X connect 3 0 27 0; #X connect 3 1 2 0; #X connect 4 0 3 0; #X connect 7 0 30 0; #X connect 8 0 28 0; #X connect 8 1 7 0; #X connect 9 0 8 0; #X connect 12 0 13 0; #X connect 12 1 14 0; #X connect 12 2 15 0; #X connect 12 3 16 0; #X connect 24 0 25 0; #X connect 24 1 19 0; #X connect 24 2 18 0; #X connect 24 3 12 0; #X connect 25 0 26 0; #X connect 27 0 1 0; #X connect 28 0 30 0; #X connect 29 0 5 0; #X connect 30 0 31 0; #X connect 31 0 10 0; #X connect 32 0 38 0; #X connect 33 0 1 0; #X connect 34 0 1 0; #X connect 36 0 37 0; #X connect 37 0 30 0; #X connect 38 0 44 0; #X connect 39 0 24 0; #X connect 40 0 38 0; #X connect 41 0 42 0; #X connect 42 0 44 1; #X connect 44 0 45 0; #X connect 45 0 39 0; #X restore 23 49 pd OSC; #X restore 21 365 pd EXAMPLES; #X obj 471 455 print FUDI; #X msg 471 101 broadcast 97 98 99 59 10; #X msg 471 128 client 1 97 98 99 59 10; #X msg 471 155 send 504 97 98 99 59 10; #X msg 471 28 10 97 98 99 59 10; #X text 17 8 TCPSOCKETSERVER - a protocol-aware wrapper aroun [tcpserver] ; #X text 13 167 [tcpsocketserver] dynamically creates (internally) an instance of a socket handler abstraction [tcpsocket.PROTOCOL] for each opened socket. every socket handler creates proper packets from the incoming stream and sends them to the left outlet of [tcpsocketserver]. ; #X connect 0 0 30 0; #X connect 7 0 30 0; #X connect 8 0 30 0; #X connect 9 0 10 1; #X connect 10 0 8 0; #X connect 11 0 10 0; #X connect 12 0 13 1; #X connect 13 0 7 0; #X connect 14 0 13 0; #X connect 16 0 17 0; #X connect 16 1 18 0; #X connect 16 2 19 0; #X connect 16 3 20 0; #X connect 26 0 41 0; #X connect 27 0 26 1; #X connect 30 0 26 0; #X connect 30 1 24 0; #X connect 30 2 22 0; #X connect 30 3 16 0; #X connect 42 0 30 0; #X connect 43 0 30 0; #X connect 44 0 30 0; #X connect 45 0 30 0; mrpeach/net/httpreceive.c0000644000175000017500000002076311530532140016205 0ustar zmoelnigzmoelnig/* httpreceive.c Started by Martin Peach 20110111 */ /* httpreceive will process http 1.1 responses received as lists of bytes from something like [tcpclient] */ /* See http://www.w3.org/Protocols/rfc2616/rfc2616.html */ #include "m_pd.h" #include #include static t_class *httpreceive_class; #define STATUS_BUF_LEN 4096 /* how big can the status part get? */ typedef struct _httpreceive { t_object x_obj; t_outlet *x_status_out; t_outlet *x_message_out; t_outlet *x_statuscode_out; int x_state; int x_remaining; int x_verbosity; char *x_status_buf; size_t x_status_buf_len; int x_status_buf_write_index; } t_httpreceive; #define MAX_GETSTRING 256 static void httpreceive_bang(t_httpreceive *x); static void httpreceive_list(t_httpreceive *x, t_symbol *s, int argc, t_atom *argv); static void httpreceive_verbosity(t_httpreceive *x, t_floatarg verbosity); static void httpreceive_free (t_httpreceive *x); static void *httpreceive_new (void); void httpreceive_setup(void); static void httpreceive_bang(t_httpreceive *x) { post("httpreceive_bang %p", x); } static void httpreceive_list(t_httpreceive *x, t_symbol *s, int argc, t_atom *argv) { int i, j, k, m, n, message_len = 0; char buf[256]; t_atom status_list[2]; /* first check that all the atoms are integer floats on 0-255 */ for (i = 0; i < argc; ++i) { if (argv[i].a_type != A_FLOAT) { pd_error(x, "list element %d is not a float", i); return; } j = argv[i].a_w.w_float; if (j != argv[i].a_w.w_float) { pd_error(x, "list element %d is not an integer", i); return; } if ((j < -128) || (j > 255)) { pd_error(x, "list element %d is not on [0...255]", i); return; } } if (x->x_verbosity) post ("httpreceive_list %d elements, x_state %d x_remaining %d", i, x->x_state, x->x_remaining); for (i = 0; ((i < argc) && (x->x_state == 0)); ++i) { j = argv[i].a_w.w_float; x->x_status_buf[x->x_status_buf_write_index] = j; /* status ends with CRLFCRLF */ if ( (x->x_status_buf_write_index > 3) && (j == 10) && (x->x_status_buf[x->x_status_buf_write_index-1] == 13) && (x->x_status_buf[x->x_status_buf_write_index-2] == 10) && (x->x_status_buf[x->x_status_buf_write_index-3] == 13) ) { x->x_state = 1;/* complete status header is in x->x_status_buf */ x->x_status_buf[x->x_status_buf_write_index+1] = 0; if (x->x_verbosity) post("httpreceive_list: status: %s", x->x_status_buf); /* get status code from first line */ if ((1 != sscanf(x->x_status_buf, "HTTP/1.1 %d", &j)) && (1 != sscanf(x->x_status_buf, "HTTP/1.0 %d", &j))) { pd_error(x, "httpreceive_list: malformed status line"); post("httpreceive_list: status: %s", x->x_status_buf); } else { outlet_float(x->x_statuscode_out, j); if (x->x_verbosity) post("httpreceive_list: status code: %d", j); for (j = 8; j < x->x_status_buf_write_index; ++j) if (x->x_status_buf[j] >= 'A') break; /* skip to start of reason phrase */ for (k = 0; j < x->x_status_buf_write_index; ++j, ++k) { if (13 == x->x_status_buf[j]) break; buf[k] = x->x_status_buf[j];/* copy reason phrase to buf */ } buf[k] = 0; /* make buf into a symbol */ SETSYMBOL(&status_list[0], gensym(buf)); /* output it through status outlet */ outlet_anything(x->x_status_out, gensym("reason"), 1, &status_list[0]); /* loop through all the response header fields */ do { /* skip to first non-whitespace on next line: */ for (; j < x->x_status_buf_write_index; ++j) if (x->x_status_buf[j] > 32) break; /* copy the field name to buf */ for (k = 0; j < x->x_status_buf_write_index; ++j, ++k) { if (':' == x->x_status_buf[j]) break; buf[k] = x->x_status_buf[j]; } j++; /* skip the colon */ buf[k] = 0; SETSYMBOL(&status_list[0], gensym(buf)); /* field name */ /* skip whitespace: */ for (; j < x->x_status_buf_write_index; ++j) if (x->x_status_buf[j] != 32) break; /* copy the token to buf */ for (k = 0; j < x->x_status_buf_write_index; ++j, ++k) { if (13 == x->x_status_buf[j]) break; buf[k] = x->x_status_buf[j]; } buf[k] = 0; /* if the value is a number, set it to a float, else it's a symbol */ for (m = 0; m < k; ++m) if ((buf[m] < '0' || buf[m] > '9')) break; if (m == k) { sscanf(buf, "%d", &n); SETFLOAT(&status_list[1], n); /* if this is Content-Length, we know the message_length */ if (atom_getsymbol(&status_list[0]) == gensym("Content-Length")) x->x_remaining = n; } else SETSYMBOL(&status_list[1], gensym(buf)); outlet_anything(x->x_status_out, status_list[0].a_w.w_symbol, 1, &status_list[1]); } while (j < x->x_status_buf_write_index-3); } } // if end of status response else x->x_status_buf_write_index++; if (x->x_status_buf_write_index >= x->x_status_buf_len) { pd_error(x, "httpreceive_list: status buffer full"); x->x_status_buf_write_index = 0; x->x_state = 0; x->x_remaining = 0; } } // for each byte if (1 == x->x_state) { /* any remaining atoms are the message body. For now just output them */ /* but if the incoming bytes are in more than one list this won't work, */ /*we'll need to cache them until we have Content-Length */ if (x->x_verbosity) post ("httpreceive_list: x->x_remaining is %d", x->x_remaining); message_len = argc - i; if (x->x_verbosity) post ("httpreceive_list: message_len is %d", message_len); if (message_len <= x->x_remaining) x->x_remaining -= message_len; outlet_list(x->x_message_out, &s_list, message_len, &argv[i]); x->x_status_buf_write_index = 0; if (0 == x->x_remaining) x->x_state = 0; } } static void httpreceive_verbosity(t_httpreceive *x, t_float verbosity) { x->x_verbosity = verbosity; if (x->x_verbosity != 0) post ("httpreceive_verbosity %d", x->x_verbosity); } static void httpreceive_free (t_httpreceive *x) { if ((NULL != x->x_status_buf)&&(0 != x->x_status_buf_len)) freebytes(x->x_status_buf, x->x_status_buf_len); } static void *httpreceive_new (void) { t_httpreceive *x = (t_httpreceive *)pd_new(httpreceive_class); if (NULL != x) { x->x_message_out = outlet_new(&x->x_obj, &s_anything); x->x_status_out = outlet_new(&x->x_obj, &s_anything); x->x_statuscode_out = outlet_new(&x->x_obj, &s_float); /* rightmost outlet */ x->x_state = 0; /* waiting for a list of bytes */ x->x_status_buf_len = STATUS_BUF_LEN; if (NULL == (x->x_status_buf = getbytes(STATUS_BUF_LEN))) { pd_error(x, "httpreceive_new: no memory available for x_status_buf"); x->x_status_buf_len = 0; } x->x_status_buf_write_index = 0; x->x_remaining = 0; x->x_verbosity = 0; } return (void *)x; } void httpreceive_setup(void) { httpreceive_class = class_new(gensym("httpreceive"), (t_newmethod)httpreceive_new, (t_method)httpreceive_free, sizeof(t_httpreceive), CLASS_DEFAULT, 0); class_addbang(httpreceive_class, httpreceive_bang); class_addlist (httpreceive_class, (t_method)httpreceive_list); class_addmethod(httpreceive_class, (t_method)httpreceive_verbosity, gensym("verbosity"), A_FLOAT, 0); } /* fin httpreceive.c */ mrpeach/net/udpsndrcv-help.pd0000644000175000017500000000501112303446646017005 0ustar zmoelnigzmoelnig#N canvas 193 98 901 628 12; #X declare -lib mrpeach; #X msg 166 354 status; #X text 18 334 get status on right outlet:; #N canvas 510 620 494 344 META 0; #X text 12 155 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; #X text 12 25 LICENSE GPL v2 or later; #X text 12 5 KEYWORDS control network; #X text 12 45 DESCRIPTION receive datagrams over a udp connection and outputs them as raw bytes; #X text 12 95 OUTLET_0 anything; #X text 12 135 AUTHOR Martin Peach \, Dennis Engdahl; #X text 12 75 INLET_0 status port connect disconnect float(s); #X text 12 115 OUTLET_1 received total; #X restore 821 567 pd META; #X obj 208 416 udpsndrcv; #X msg 197 385 disconnect; #X msg 105 260 send /info; #X text -12 3 [udpsndrcv] sends datagrams over udp and receives datagrams over a udp connection and outputs them as raw bytes. It uses the same port for both send and receive.; #X text 168 134 IP address to send to/listen on (required); #X text 323 447 Total bytes received.; #X text 242 544 Data received.; #X text -3 60 This was cadged together by Dennis Engdahl (engdahl@snowcrest.net) to allow communication with a Behringer X32. The program below demonstrates this.; #X obj 105 293 packOSC; #X obj 238 481 unpackOSC; #X text 169 149 Port number to send to (required); #X text 31 132 Creation Arguments:; #X obj 490 78 import mrpeach; #X text 202 176 (Must be unique among instances - see below); #X msg 25 213 connect 192.168.1.101 10023 10023; #X text 584 598 Dennis Engdahl \, Martin Peach 20104/02/26; #X obj 268 447 print a; #X obj 238 518 print Instance_1; #X obj 208 455 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1; #X msg 496 354 status; #X text 348 334 get status on right outlet:; #X obj 538 416 udpsndrcv; #X msg 527 385 disconnect; #X msg 435 260 send /info; #X text 653 447 Total bytes received.; #X text 572 544 Data received.; #X obj 435 293 packOSC; #X obj 568 481 unpackOSC; #X obj 538 455 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1; #X msg 355 213 connect 192.168.1.101 10023 10024; #X obj 598 447 print b; #X obj 568 518 print Instance_2; #X text 168 163 Port number to send from and listen on (required); #X connect 0 0 3 0; #X connect 3 0 21 0; #X connect 3 1 12 0; #X connect 3 2 19 0; #X connect 4 0 3 0; #X connect 5 0 11 0; #X connect 11 0 3 0; #X connect 12 0 20 0; #X connect 17 0 3 0; #X connect 22 0 24 0; #X connect 24 0 31 0; #X connect 24 1 30 0; #X connect 24 2 33 0; #X connect 25 0 24 0; #X connect 26 0 29 0; #X connect 29 0 24 0; #X connect 30 0 34 0; #X connect 32 0 24 0; mrpeach/net/README.txt0000644000175000017500000000046211650353267015225 0ustar zmoelnigzmoelnigA collection of network objects for Pure Data. For more info see http://puredata.org or http://sourceforge.net/projects/pure-data/ Bugs and feature requests should be filed at http://sourceforge.net/tracker/?group_id=55736 Send questions to the mailing list at http://lists.puredata.info/listinfo/pd-list mrpeach/life2x/0000755000175000017500000000000013605444732014130 5ustar zmoelnigzmoelnigmrpeach/life2x/life2x.c0000644000175000017500000005262211151111713015454 0ustar zmoelnigzmoelnig/* Life2x.c -- The Game of Life (2D Cellular Automaton) ------- */ /* Bill Vorn 2002 */ /* modified by Martin Peach September 2002 */ /* implemented grey scale display*/ /* change gen_ arrays to pointers for better memory peformance */ /* <> */ /* MP20060517 Windows version */ /* MP 20080819 pd version with no graphics */ #include "m_pd.h" #include /* for sprintf() */ #include /* for random() */ #include /* for clock() */ #ifdef _WIN32 /* Windows doesn't have these named correctly ;) */ # define random rand # define srandom srand #endif #define MAXSIZE 1024 #define DEFAULT_DIM 16 static t_class *life2x_class; typedef struct life2x { t_object x_obj; char *gen_origin_ptr; /* [MAXSIZE]X[MAXSIZE]; */ char *gen_finale_ptr; /* [MAXSIZE][MAXSIZE]; */ char *gen_start_ptr; /* [MAXSIZE][MAXSIZE]; */ char *gen_shift_ptr; /* [MAXSIZE][MAXSIZE]; */ t_atom *l_column_list; /* values for one column */ long l_cellmax; /* number of bytes in gen */ long l_xcellnum; long l_ycellnum; long l_gennum; long l_livenum; long l_deltanum; long l_lastdeltanum; long l_novarinum; long l_novar; short l_deadflag; short l_thruflag; short l_xshift; short l_yshift; short l_invertflag; t_outlet *l_genout; t_outlet *l_liveout; t_outlet *l_deltaout; t_outlet **l_cellouts; t_outlet *l_novariout; t_outlet *l_deadout; t_outlet *l_dumpout; char l_survive[9]; /* rule for survival according to neighbour count */ char l_born[9]; /* rule for birth according to neighbour count */ } t_life2x; static void life2x_bang(t_life2x *x); static void life2x_output_cells(t_life2x *x); static void life2x_set(t_life2x *x, t_floatarg xx, t_floatarg yy, t_floatarg state); static void life2x_clear(t_life2x *x); static void life2x_reset(t_life2x *x); static void life2x_return(t_life2x *x); static void life2x_dump(t_life2x *x); static void life2x_rule(t_life2x *x, t_symbol *s); static void life2x_randomize(t_life2x *x, t_floatarg f); static void life2x_thru(t_life2x *x, t_floatarg f); static void life2x_shift(t_life2x *x, t_floatarg f1, t_floatarg f2); static void life2x_flipv(t_life2x *x); static void life2x_fliph(t_life2x *x); static void life2x_invert(t_life2x *x, t_floatarg f); static void life2x_novar(t_life2x *x, t_floatarg f); static void life2x_free(t_life2x *x); static void *life2x_new(t_symbol *s, short ac, t_atom *av); void life2x_setup(void) { life2x_class = class_new(gensym("life2x"), (t_newmethod)life2x_new, (t_method)life2x_free, sizeof(t_life2x), CLASS_DEFAULT, A_GIMME, 0); class_addbang(life2x_class, life2x_bang); class_addmethod(life2x_class, (t_method)life2x_clear, gensym("clear"), 0); class_addmethod(life2x_class, (t_method)life2x_reset, gensym("reset"), 0); class_addmethod(life2x_class, (t_method)life2x_return, gensym("return"), 0); class_addmethod(life2x_class, (t_method)life2x_dump, gensym("dump"), 0); class_addmethod(life2x_class, (t_method)life2x_rule, gensym("rule") ,A_DEFSYMBOL, 0); class_addmethod(life2x_class, (t_method)life2x_randomize, gensym("randomize"), A_DEFFLOAT, 0); class_addmethod(life2x_class, (t_method)life2x_thru, gensym("thru") ,A_DEFFLOAT, 0); class_addmethod(life2x_class, (t_method)life2x_shift, gensym("shift"), A_DEFFLOAT, A_DEFFLOAT, 0); class_addmethod(life2x_class, (t_method)life2x_set, gensym("set"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); class_addmethod(life2x_class, (t_method)life2x_flipv, gensym("flipv"), 0); class_addmethod(life2x_class, (t_method)life2x_fliph, gensym("fliph"), 0); class_addmethod(life2x_class, (t_method)life2x_invert, gensym("invert"), A_DEFFLOAT, 0); class_addmethod(life2x_class, (t_method)life2x_novar, gensym("novar"), A_DEFFLOAT, 0); return; } static void life2x_bang(t_life2x *x) { short i, j, m, n, p, q; short i_pre, i_post, j_pre, j_post; short xmax, ymax; unsigned long cellmax; short xshft, yshft; char c; short cellval; long gendiff, lastgendiff; char *g_start, *g_origin, *g_final, *g_shift; int c_live; xmax = x->l_xcellnum - 1; ymax = x->l_ycellnum - 1; cellmax = x->l_xcellnum * x->l_ycellnum; xshft = x->l_xshift; yshft = x->l_yshift; if (x->l_gennum == 0) { g_start = x->gen_start_ptr; g_origin = x->gen_origin_ptr; for (j = 0; j < cellmax; ++j) *g_start++ = *g_origin++; } for (j = 0; j <= ymax; j++) { j_pre = j-1; if (j_pre < 0) j_pre = ymax; j_post = j+1; if (j_post > ymax) j_post = 0; for (i = 0; i <= xmax; i++) { i_pre = i-1; if (i_pre < 0) i_pre = xmax; i_post = i+1; if (i_post > xmax) i_post = 0; /* check each neighbour */ cellval = (*(x->gen_origin_ptr+(j_pre*x->l_xcellnum)+(i_pre)) != 0) +(*(x->gen_origin_ptr+(j_pre*x->l_xcellnum)+i) != 0) +(*(x->gen_origin_ptr+(j_pre*x->l_xcellnum)+i_post) != 0) +(*(x->gen_origin_ptr+(j*x->l_xcellnum)+i_pre) != 0) +(*(x->gen_origin_ptr+(j*x->l_xcellnum)+i_post) != 0) +(*(x->gen_origin_ptr+(j_post*x->l_xcellnum)+i_pre) != 0) +(*(x->gen_origin_ptr+(j_post*x->l_xcellnum)+i) != 0) +(*(x->gen_origin_ptr+(j_post*x->l_xcellnum)+i_post) != 0); c = *(x->gen_origin_ptr+(j*x->l_xcellnum)+i); /* current value of cell */ g_final = (x->gen_finale_ptr+(j*x->l_xcellnum)+i); /* apply the rule */ if (c == 0) c_live = x->l_born[cellval]; /* cell is born if it has the right number of neighbours */ else c_live = x->l_survive[cellval]; /* cell survives if it has the right number of neighbours */ if (c_live == 1) { if (c < 8) *g_final = c + 1; else *g_final = 8; } else *g_final = 0; } } if ((xshft != 0) || (yshft != 0)) { /* if there is a shift offset */ for (j = 0; j <= ymax; j++) { n = j + yshft; if (n < 0) q = (n + ymax) + 1; else if (n > ymax) q = (n - ymax) - 1; else q = n; for (i = 0; i <= xmax; i++) { m = i + xshft; if (m < 0) p = (m + xmax) + 1; else if (m > xmax) p = (m - xmax) - 1; else p = m; *(x->gen_shift_ptr+(q * x->l_xcellnum)+p) = *(x->gen_finale_ptr+(j * x->l_xcellnum)+i); } } g_final = x->gen_finale_ptr; g_shift = x->gen_shift_ptr; for (j = 0; j <= cellmax; j++) *g_final++ = *g_shift++; } x->l_gennum = x->l_gennum + 1; /* increment generation # */ outlet_float(x->l_genout, x->l_gennum); /* output generation # */ life2x_output_cells(x); gendiff = x->l_livenum - x->l_deltanum; /* compare # of live cells from last gen to current gen */ outlet_float(x->l_deltaout, gendiff); /* output delta # of live cells from last gen to current gen */ x->l_deltanum = x->l_livenum; /* store # of live cells from current gen */ outlet_float(x->l_liveout, x->l_livenum); /* output # of live cells in current generation */ lastgendiff = x->l_lastdeltanum; if (gendiff == lastgendiff) x->l_novar--; else x->l_novar = x->l_novarinum; /* reset countdown */ if (x->l_novar == 0) { outlet_bang(x->l_novariout); x->l_novar = x->l_novarinum; } x->l_lastdeltanum = gendiff; x->l_deadflag = 0; for (j = 0; j < x->l_ycellnum; j++) { for (i = 0; i < x->l_xcellnum; i++) { g_final = (x->gen_finale_ptr+(j*x->l_xcellnum)+i); g_origin = (x->gen_origin_ptr+(j*x->l_xcellnum)+i); /* check for gen difference: */ if (*g_final != *g_origin) x->l_deadflag = 1; *g_origin = *g_final; /* this generation becomes last generation */ } } /* check for dead world: */ if (x->l_deadflag == 0) outlet_bang(x->l_deadout); return; } static void life2x_output_cells(t_life2x *x) { char *g_final; short i, j; long d = 0; for (i = 0; i < x->l_xcellnum; i++) { /* output all cells state for each column */ for (j = 0; j < x->l_ycellnum; j++) { g_final = (x->gen_finale_ptr+(j*x->l_xcellnum)+i); if (x->l_invertflag != 0) x->l_column_list[j].a_w.w_float = (10 - *g_final)%9; else x->l_column_list[j].a_w.w_float = *g_final; if (*g_final != 0) d++; } outlet_list(x->l_cellouts[x->l_xcellnum-1-i], &s_list, j, x->l_column_list); } x->l_livenum = d; return; } static void life2x_set(t_life2x *x, t_floatarg xx, t_floatarg yy, t_floatarg state) { /* a list of three floats to set the state of cell (xx,yy) */ short i, j, k; if (xx < 0) i = 0; if (xx >= x->l_xcellnum) i = x->l_xcellnum - 1; else i = (short)xx; if (yy < 0) j = 0; if (yy > x->l_ycellnum) j = x->l_ycellnum - 1; else j = (short)yy; if (state < 0) k = 0; if (state > 8) k = 8; else k = (short)state; *(x->gen_origin_ptr+(j*x->l_xcellnum+i)) = k; *(x->gen_finale_ptr+(j*x->l_xcellnum+i)) = k; if (x->l_thruflag != 0) life2x_output_cells(x); return; } static void life2x_clear(t_life2x *x) { short j; char *g_origin, * g_final; g_origin = x->gen_origin_ptr; g_final = x->gen_finale_ptr; for (j = 0; j < x->l_cellmax; ++j) *g_origin++ = *g_final++ = 0; if (x->l_thruflag != 0) life2x_output_cells(x); return; } static void life2x_reset(t_life2x *x) { short j; char *g_origin, * g_final; g_origin = x->gen_origin_ptr; g_final = x->gen_finale_ptr; x->l_gennum = 0; outlet_float (x->l_genout, x->l_gennum); /* output generation 0 */ for (j = 0; j < x->l_cellmax; ++j) *g_origin++ = *g_final++ = 0; x->l_xshift = 0; x->l_yshift = 0; x->l_deltanum = 0; x->l_novar = x->l_novarinum; if (x->l_thruflag != 0) life2x_output_cells(x); return; } static void life2x_return(t_life2x *x) { short i, j; char *g_origin, *g_start, *g_final; x->l_gennum = 0; outlet_float (x->l_genout, x->l_gennum); /* output generation 0 */ for (j = 0; j < x->l_ycellnum; j++) { for (i = 0; i < x->l_xcellnum; i++) { g_origin = (x->gen_origin_ptr+(j*x->l_xcellnum)+i); g_start = (x->gen_start_ptr+(j*x->l_xcellnum)+i); g_final = (x->gen_finale_ptr+(j*x->l_xcellnum)+i); *g_origin = *g_start; *g_final = *g_start; } } if (x->l_thruflag != 0) life2x_output_cells(x); return; } static void life2x_dump(t_life2x *x) { short i, j, k; unsigned long count = 0; unsigned long outVal[3]; t_atom outList[3]; char *g_final = x->gen_finale_ptr; for (j = 0; j < x->l_ycellnum; ++j) { for (i = 0; i < x->l_xcellnum; ++i) { if (*g_final++) { outVal[0] = count; outVal[1] = i; outVal[2] = j; for (k = 0; k < 3; k++) SETFLOAT(&outList[k], outVal[k]); outlet_list (x->l_dumpout, &s_list, 3, outList); count++; } } } return; } static void life2x_rule(t_life2x *x, t_symbol *s) { short i; char survive[9]; /* one entry for each possible neighbour count, set to one if cell survives with that many neighbours */ char born[9]; /* one entry for each possible neighbour count, set to one if cell is born with that many neighbours */ for (i = 0; i < 9; ++i) survive[i] = born[i] = 0; for (i = 0; s->s_name[i] != 0; ++i) { if (s->s_name[i] == '/') break; if ((s->s_name[i] < 0x30)||(s->s_name[i] > 0x38)) { error("life2x_rule: bad character in rule: %c", s->s_name[i]); return; } survive[s->s_name[i]-0x30] = 1; } if (s->s_name[i] != '/') { error("life2x_rule: missing / separator"); return; } for (++i; s->s_name[i] != 0; ++i) { if ((s->s_name[i] < 0x30)||(s->s_name[i] > 0x38)) { error("life2x_rule: bad character in rule: %c", s->s_name[i]); return; } born[s->s_name[i]-0x30] = 1; } for (i = 0; i < 9; ++i) { /* update the rule */ x->l_survive[i] = survive[i]; x->l_born[i] = born[i]; } return; } static void life2x_randomize(t_life2x *x, t_floatarg f) { /* set a random fraction of the array alive */ short i, j; float threshold; if (f > 1.0) f = 1.0; else if (f < 0.0) f = 0.0; threshold = RAND_MAX*f; /* RAND_MAX is 0x7FFFFFFF on linux */ for (j = 0; j < x->l_ycellnum; j++) { for (i = 0; i < x->l_xcellnum; i++) { if ((random() < threshold)) { *(x->gen_origin_ptr+(j*x->l_xcellnum)+i) = 1; *(x->gen_finale_ptr+(j*x->l_xcellnum)+i) = 1; } } } if (x->l_thruflag != 0) life2x_output_cells(x); return; } static void life2x_thru(t_life2x *x, t_floatarg f) { long n = (long)f; x->l_thruflag = (n == 0)? 0: 1; return; } static void life2x_shift(t_life2x *x, t_floatarg f1, t_floatarg f2) { long n = (long)f1; n %= x->l_xcellnum; x->l_xshift = n; n = (long)f2; n %= x->l_ycellnum; x->l_yshift = n; return; } static void life2x_flipv(t_life2x *x) { short a, i, j; for (i = 0; i < x->l_xcellnum; ++i) { a = x->l_xcellnum - 1; for (j = 0; j < x->l_xcellnum; ++j) { *(x->gen_shift_ptr+(a*x->l_xcellnum)+i) = *(x->gen_finale_ptr+(j*x->l_xcellnum)+i); a--; } } for (j = 0; j < x->l_ycellnum; ++j) { for (i = 0; i < x->l_xcellnum; ++i) { *(x->gen_finale_ptr+(j*x->l_xcellnum)+i) = *(x->gen_shift_ptr+(j*x->l_xcellnum)+i); *(x->gen_origin_ptr+(j*x->l_xcellnum)+i) = *(x->gen_shift_ptr+(j*x->l_xcellnum)+i); } } if (x->l_thruflag != 0) life2x_output_cells(x); return; } static void life2x_fliph(t_life2x *x) { short a, i, j; for (j = 0; j < x->l_ycellnum - 1; ++j) { a = x->l_xcellnum - 1; for (i = 0; i < x->l_xcellnum; ++i) { *(x->gen_shift_ptr+(j*x->l_xcellnum)+a) = *(x->gen_finale_ptr+(j*x->l_xcellnum)+i); a--; } } for (j = 0; j < x->l_ycellnum - 1; ++j) { for (i = 0; i < x->l_xcellnum - 1; ++i) { *(x->gen_finale_ptr+(j*x->l_xcellnum)+i) = *(x->gen_shift_ptr+(j*x->l_xcellnum)+i); *(x->gen_origin_ptr+(j*x->l_xcellnum)+i) = *(x->gen_shift_ptr+(j*x->l_xcellnum)+i); } } if (x->l_thruflag != 0) life2x_output_cells(x); return; } static void life2x_invert(t_life2x *x, t_floatarg f) { x->l_invertflag = (f == 0)? 0: 1; if (x->l_thruflag != 0) life2x_output_cells(x); return; } static void life2x_novar(t_life2x *x, t_floatarg f) { long n = (long)f; if (n < 0) { error("life2x: novar argument must be positive"); return; } else { x->l_novarinum = n; x->l_novar = n; } return; } static void life2x_free(t_life2x *x) { if (x->gen_origin_ptr != NULL) freebytes (x->gen_origin_ptr, x->l_cellmax); if (x->gen_finale_ptr != NULL) freebytes (x->gen_finale_ptr, x->l_cellmax); if (x->gen_start_ptr != NULL) freebytes (x->gen_start_ptr, x->l_cellmax); if (x->gen_shift_ptr != NULL) freebytes (x->gen_shift_ptr, x->l_cellmax); if (x->l_column_list != NULL) freebytes(x->l_column_list, x->l_ycellnum*sizeof (t_atom)); if (x->l_cellouts != NULL) freebytes(x->l_cellouts, x->l_xcellnum*sizeof (t_outlet*)); return; } static void *life2x_new(t_symbol *s, short ac, t_atom *av) { t_life2x *x; short i; short j; short xmax, ymax; x = (t_life2x *)pd_new(life2x_class); if (ac > 0) { /* if there is at least 1 argument */ if (av[0].a_type == A_FLOAT) { /* if first arg is an int */ x->l_xcellnum = av[0].a_w.w_float; /* arg sets # of horiz cells */ if (x->l_xcellnum < 4) { error("Life: first argument < 4, set to 4"); x->l_xcellnum = 4; /* min # of horiz cells */ } if (x->l_xcellnum > MAXSIZE) { error("Life: first argument > %d, set to %d", MAXSIZE, MAXSIZE); x->l_xcellnum = MAXSIZE; /* max # of horiz cells */ } /* if 2 arguments */ if ((ac > 1) && (av[1].a_type == A_FLOAT)) { /* if 2nd arg is an int */ x->l_ycellnum = av[1].a_w.w_float; /* 2nd arg sets # of verti cells */ if (x->l_ycellnum < 4) { error("Life: 2nd argument < 4, set to 4"); x->l_ycellnum = 4; /* min # of verti cells */ } if (x->l_ycellnum > MAXSIZE) { error("Life: 2nd argument > %d, set to %d", MAXSIZE, MAXSIZE); x->l_ycellnum = MAXSIZE; /* max # of verti cells */ } } else if (ac > 1) { /* if 2nd arg not an int */ error("Life: 2nd argument must be int"); x->l_ycellnum = DEFAULT_DIM; /* default # of verti cells */ } else { /* if no 2nd arg */ x->l_ycellnum = x->l_xcellnum; /* # of verti cells = # of horiz cells */ } } else { /*if first arg not an int */ error("Life: first argument must be int"); x->l_xcellnum = DEFAULT_DIM; /* default # of horiz cells */ x->l_ycellnum = DEFAULT_DIM; /* default # of verti cells */ } } else { /* if no arg */ x->l_xcellnum = DEFAULT_DIM; /* default # of horiz cells */ x->l_ycellnum = DEFAULT_DIM; /* default # of verti cells */ } x->l_cellmax = x->l_xcellnum*x->l_ycellnum; if ((x->gen_origin_ptr = getbytes(x->l_cellmax)) != NULL) if ((x->gen_finale_ptr = getbytes(x->l_cellmax)) != NULL) if ((x->gen_start_ptr = getbytes(x->l_cellmax)) != NULL) x->gen_shift_ptr = getbytes(x->l_cellmax); if ( (x->gen_origin_ptr == NULL) || (x->gen_finale_ptr == NULL) || (x->gen_start_ptr == NULL) || (x->gen_shift_ptr == NULL) ) { error ("Unable to allocate memory for the life array (%luX%lu needs %lu bytes)", x->l_xcellnum, x->l_ycellnum, x->l_cellmax*4L); life2x_free (x); return x; } x->l_column_list = getbytes(x->l_ycellnum*sizeof (t_atom)); if (x->l_column_list == NULL) { error("life2x_new: Unable to allocate %lu bytes for column list", x->l_ycellnum*sizeof (t_atom)); life2x_free (x); return x; } for (j = 0; j < x->l_ycellnum; ++j) SETFLOAT(&x->l_column_list[j], 0); /* (we can go faster later by making the atoms floats now) */ xmax = x->l_xcellnum - 1; ymax = x->l_ycellnum - 1; post("life new...(%d X %d)", x->l_xcellnum, x->l_ycellnum); for (j = 0; j <= ymax; j++) { /* sets all cells to 0 */ for (i = 0; i <= xmax; i++) { *(x->gen_origin_ptr+(j*x->l_xcellnum)+i) = 0; *(x->gen_finale_ptr+(j*x->l_xcellnum)+i) = 0; *(x->gen_start_ptr+(j*x->l_xcellnum)+i) = 0; *(x->gen_shift_ptr+(j*x->l_xcellnum)+i) = 0; } } x->l_xshift = 0; x->l_yshift = 0; x->l_deltanum = 0; x->l_lastdeltanum = 0; x->l_novarinum = 32; x->l_novar = 32; x->l_cellouts = getbytes(x->l_xcellnum*sizeof (t_outlet*)); if (x->l_cellouts == NULL) { error("life2x_new: Unable to allocate %lu bytes for column outlets", x->l_xcellnum*sizeof (t_outlet*)); life2x_free (x); return x; } for (i = xmax; i >= 0; i--) x->l_cellouts[i] = outlet_new(&x->x_obj, &s_list);/* create an outlet for each column */ x->l_deltaout = outlet_new(&x->x_obj, &s_float); /* create outlet for live cell diff from previous gen */ x->l_liveout = outlet_new(&x->x_obj, &s_float); /* sets outlet for # of live cells in current generation */ x->l_genout = outlet_new(&x->x_obj, &s_float); /* sets outlet for current generation # */ x->l_dumpout = outlet_new(&x->x_obj, &s_list); /* sets outlet for list dumping */ x->l_novariout = outlet_new(&x->x_obj, &s_bang); /* sets outlet for no variation period bang */ x->l_deadout = outlet_new(&x->x_obj, &s_bang); /* sets first outlet for dead world bang */ x->l_gennum = 0; /* sets first generation # */ outlet_float(x->l_genout, x->l_gennum); x->l_thruflag = 1; /* sets thru mode on */ x->l_invertflag = 0; /* sets invert off */ /* set up default Conway rule */ life2x_rule(x, gensym("23/3")); /* survive if 2 or 3 neighbours / born if 3 neighbours */ srandom(clock()); /* seed the random number generator */ return (x); } /* end of life2x.c */ mrpeach/life2x/life2x-help.pd0000644000175000017500000005256411533622476016611 0ustar zmoelnigzmoelnig#N canvas 1 53 898 909 10; #X obj 369 293 bng 15 250 50 0 empty empty single_step 17 7 0 10 -4160 -4034 -4034; #X msg 124 46 dump; #X msg 103 25 clear; #X msg 250 172 reset; #X msg 271 193 return; #X msg 166 88 flipv; #X msg 145 67 fliph; #X msg 187 109 invert \$1; #X obj 259 94 tgl 15 0 empty empty empty 17 7 0 10 -4160 -4034 -1 0 1; #X floatatom -9 224 2 0 0 0 - - -; #X floatatom 8 224 2 0 0 0 - - -; #X floatatom 25 224 2 0 0 0 - - -; #X floatatom 43 224 2 0 0 0 - - -; #X floatatom 60 224 2 0 0 0 - - -; #X floatatom 78 224 2 0 0 0 - - -; #X floatatom 95 224 2 0 0 0 - - -; #X floatatom 112 224 2 0 0 0 - - -; #X floatatom 130 224 2 0 0 0 - - -; #X floatatom 147 224 2 0 0 0 - - -; #X floatatom 165 224 2 0 0 0 - - -; #X floatatom 182 224 2 0 0 0 - - -; #X floatatom 199 224 2 0 0 0 - - -; #X floatatom 217 224 2 0 0 0 - - -; #X floatatom 234 224 2 0 0 0 - - -; #X floatatom 252 224 2 0 0 0 - - -; #X obj 398 337 life2x 16 16 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ; #X obj -1 204 unpack 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; #X obj -43 187 r c0; #X obj 398 361 s c0; #X floatatom -9 266 2 0 0 0 - - -; #X floatatom 8 266 2 0 0 0 - - -; #X floatatom 25 266 2 0 0 0 - - -; #X floatatom 43 266 2 0 0 0 - - -; #X floatatom 60 266 2 0 0 0 - - -; #X floatatom 78 266 2 0 0 0 - - -; #X floatatom 95 266 2 0 0 0 - - -; #X floatatom 112 266 2 0 0 0 - - -; #X floatatom 130 266 2 0 0 0 - - -; #X floatatom 147 266 2 0 0 0 - - -; #X floatatom 165 266 2 0 0 0 - - -; #X floatatom 182 266 2 0 0 0 - - -; #X floatatom 199 266 2 0 0 0 - - -; #X floatatom 217 266 2 0 0 0 - - -; #X floatatom 234 266 2 0 0 0 - - -; #X floatatom 252 266 2 0 0 0 - - -; #X obj -9 246 unpack 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; #X floatatom -10 309 2 0 0 0 - - -; #X floatatom 7 309 2 0 0 0 - - -; #X floatatom 24 309 2 0 0 0 - - -; #X floatatom 42 309 2 0 0 0 - - -; #X floatatom 59 309 2 0 0 0 - - -; #X floatatom 77 309 2 0 0 0 - - -; #X floatatom 94 309 2 0 0 0 - - -; #X floatatom 111 309 2 0 0 0 - - -; #X floatatom 129 309 2 0 0 0 - - -; #X floatatom 146 309 2 0 0 0 - - -; #X floatatom 164 309 2 0 0 0 - - -; #X floatatom 181 309 2 0 0 0 - - -; #X floatatom 198 309 2 0 0 0 - - -; #X floatatom 216 309 2 0 0 0 - - -; #X floatatom 233 309 2 0 0 0 - - -; #X floatatom 251 309 2 0 0 0 - - -; #X obj -10 289 unpack 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; #X floatatom -10 351 2 0 0 0 - - -; #X floatatom 7 351 2 0 0 0 - - -; #X floatatom 24 351 2 0 0 0 - - -; #X floatatom 42 351 2 0 0 0 - - -; #X floatatom 59 351 2 0 0 0 - - -; #X floatatom 77 351 2 0 0 0 - - -; #X floatatom 94 351 2 0 0 0 - - -; #X floatatom 111 351 2 0 0 0 - - -; #X floatatom 129 351 2 0 0 0 - - -; #X floatatom 146 351 2 0 0 0 - - -; #X floatatom 164 351 2 0 0 0 - - -; #X floatatom 181 351 2 0 0 0 - - -; #X floatatom 198 351 2 0 0 0 - - -; #X floatatom 216 351 2 0 0 0 - - -; #X floatatom 233 351 2 0 0 0 - - -; #X floatatom 251 351 2 0 0 0 - - -; #X obj -10 331 unpack 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; #X floatatom -10 393 2 0 0 0 - - -; #X floatatom 7 393 2 0 0 0 - - -; #X floatatom 24 393 2 0 0 0 - - -; #X floatatom 42 393 2 0 0 0 - - -; #X floatatom 59 393 2 0 0 0 - - -; #X floatatom 77 393 2 0 0 0 - - -; #X floatatom 94 393 2 0 0 0 - - -; #X floatatom 111 393 2 0 0 0 - - -; #X floatatom 129 393 2 0 0 0 - - -; #X floatatom 146 393 2 0 0 0 - - -; #X floatatom 164 393 2 0 0 0 - - -; #X floatatom 181 393 2 0 0 0 - - -; #X floatatom 198 393 2 0 0 0 - - -; #X floatatom 216 393 2 0 0 0 - - -; #X floatatom 233 393 2 0 0 0 - - -; #X floatatom 251 393 2 0 0 0 - - -; #X obj -10 373 unpack 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; #X floatatom -10 435 2 0 0 0 - - -; #X floatatom 7 435 2 0 0 0 - - -; #X floatatom 24 435 2 0 0 0 - - -; #X floatatom 42 435 2 0 0 0 - - -; #X floatatom 59 435 2 0 0 0 - - -; #X floatatom 77 435 2 0 0 0 - - -; #X floatatom 94 435 2 0 0 0 - - -; #X floatatom 111 435 2 0 0 0 - - -; #X floatatom 129 435 2 0 0 0 - - -; #X floatatom 146 435 2 0 0 0 - - -; #X floatatom 164 435 2 0 0 0 - - -; #X floatatom 181 435 2 0 0 0 - - -; #X floatatom 198 435 2 0 0 0 - - -; #X floatatom 216 435 2 0 0 0 - - -; #X floatatom 233 435 2 0 0 0 - - -; #X floatatom 251 435 2 0 0 0 - - -; #X obj -10 415 unpack 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; #X floatatom -10 477 2 0 0 0 - - -; #X floatatom 7 477 2 0 0 0 - - -; #X floatatom 24 477 2 0 0 0 - - -; #X floatatom 42 477 2 0 0 0 - - -; #X floatatom 59 477 2 0 0 0 - - -; #X floatatom 77 477 2 0 0 0 - - -; #X floatatom 94 477 2 0 0 0 - - -; #X floatatom 111 477 2 0 0 0 - - -; #X floatatom 129 477 2 0 0 0 - - -; #X floatatom 146 477 2 0 0 0 - - -; #X floatatom 164 477 2 0 0 0 - - -; #X floatatom 181 477 2 0 0 0 - - -; #X floatatom 198 477 2 0 0 0 - - -; #X floatatom 216 477 2 0 0 0 - - -; #X floatatom 233 477 2 0 0 0 - - -; #X floatatom 251 477 2 0 0 0 - - -; #X obj -10 457 unpack 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; #X floatatom -10 518 2 0 0 0 - - -; #X floatatom 7 518 2 0 0 0 - - -; #X floatatom 24 518 2 0 0 0 - - -; #X floatatom 42 518 2 0 0 0 - - -; #X floatatom 59 518 2 0 0 0 - - -; #X floatatom 77 518 2 0 0 0 - - -; #X floatatom 94 518 2 0 0 0 - - -; #X floatatom 111 518 2 0 0 0 - - -; #X floatatom 129 518 2 0 0 0 - - -; #X floatatom 146 518 2 0 0 0 - - -; #X floatatom 164 518 2 0 0 0 - - -; #X floatatom 181 518 2 0 0 0 - - -; #X floatatom 198 518 2 0 0 0 - - -; #X floatatom 216 518 2 0 0 0 - - -; #X floatatom 233 518 2 0 0 0 - - -; #X floatatom 251 518 2 0 0 0 - - -; #X obj -10 498 unpack 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; #X obj 415 384 s c1; #X obj 432 361 s c2; #X obj 449 384 s c3; #X obj 466 361 s c4; #X obj 483 384 s c5; #X obj 500 361 s c6; #X obj 517 384 s c7; #X obj 534 361 s c8; #X obj 551 384 s c9; #X obj 568 361 s c10; #X obj 585 384 s c11; #X obj 602 361 s c12; #X obj 619 384 s c13; #X obj 636 361 s c14; #X obj 653 384 s c15; #X obj -43 229 r c1; #X obj -44 272 r c2; #X obj -44 314 r c3; #X obj -44 356 r c4; #X obj -44 398 r c5; #X obj -44 440 r c6; #X obj -44 481 r c7; #X obj 448 270 metro 1000; #X obj 417 255 tgl 15 0 empty empty run -3 -8 0 10 -4160 -4034 -4034 0 1; #X floatatom -11 560 2 0 0 0 - - -; #X floatatom 6 560 2 0 0 0 - - -; #X floatatom 23 560 2 0 0 0 - - -; #X floatatom 41 560 2 0 0 0 - - -; #X floatatom 58 560 2 0 0 0 - - -; #X floatatom 76 560 2 0 0 0 - - -; #X floatatom 93 560 2 0 0 0 - - -; #X floatatom 110 560 2 0 0 0 - - -; #X floatatom 128 560 2 0 0 0 - - -; #X floatatom 145 560 2 0 0 0 - - -; #X floatatom 163 560 2 0 0 0 - - -; #X floatatom 180 560 2 0 0 0 - - -; #X floatatom 197 560 2 0 0 0 - - -; #X floatatom 215 560 2 0 0 0 - - -; #X floatatom 232 560 2 0 0 0 - - -; #X floatatom 250 560 2 0 0 0 - - -; #X obj -11 540 unpack 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; #X floatatom -11 602 2 0 0 0 - - -; #X floatatom 6 602 2 0 0 0 - - -; #X floatatom 23 602 2 0 0 0 - - -; #X floatatom 41 602 2 0 0 0 - - -; #X floatatom 58 602 2 0 0 0 - - -; #X floatatom 76 602 2 0 0 0 - - -; #X floatatom 93 602 2 0 0 0 - - -; #X floatatom 110 602 2 0 0 0 - - -; #X floatatom 128 602 2 0 0 0 - - -; #X floatatom 145 602 2 0 0 0 - - -; #X floatatom 163 602 2 0 0 0 - - -; #X floatatom 180 602 2 0 0 0 - - -; #X floatatom 197 602 2 0 0 0 - - -; #X floatatom 215 602 2 0 0 0 - - -; #X floatatom 232 602 2 0 0 0 - - -; #X floatatom 250 602 2 0 0 0 - - -; #X obj -11 582 unpack 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; #X floatatom -12 645 2 0 0 0 - - -; #X floatatom 5 645 2 0 0 0 - - -; #X floatatom 22 645 2 0 0 0 - - -; #X floatatom 40 645 2 0 0 0 - - -; #X floatatom 57 645 2 0 0 0 - - -; #X floatatom 75 645 2 0 0 0 - - -; #X floatatom 92 645 2 0 0 0 - - -; #X floatatom 109 645 2 0 0 0 - - -; #X floatatom 127 645 2 0 0 0 - - -; #X floatatom 144 645 2 0 0 0 - - -; #X floatatom 162 645 2 0 0 0 - - -; #X floatatom 179 645 2 0 0 0 - - -; #X floatatom 196 645 2 0 0 0 - - -; #X floatatom 214 645 2 0 0 0 - - -; #X floatatom 231 645 2 0 0 0 - - -; #X floatatom 249 645 2 0 0 0 - - -; #X obj -12 625 unpack 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; #X floatatom -12 687 2 0 0 0 - - -; #X floatatom 5 687 2 0 0 0 - - -; #X floatatom 22 687 2 0 0 0 - - -; #X floatatom 40 687 2 0 0 0 - - -; #X floatatom 57 687 2 0 0 0 - - -; #X floatatom 75 687 2 0 0 0 - - -; #X floatatom 92 687 2 0 0 0 - - -; #X floatatom 109 687 2 0 0 0 - - -; #X floatatom 127 687 2 0 0 0 - - -; #X floatatom 144 687 2 0 0 0 - - -; #X floatatom 162 687 2 0 0 0 - - -; #X floatatom 179 687 2 0 0 0 - - -; #X floatatom 196 687 2 0 0 0 - - -; #X floatatom 214 687 2 0 0 0 - - -; #X floatatom 231 687 2 0 0 0 - - -; #X floatatom 249 687 2 0 0 0 - - -; #X obj -12 667 unpack 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; #X floatatom -12 729 2 0 0 0 - - -; #X floatatom 5 729 2 0 0 0 - - -; #X floatatom 22 729 2 0 0 0 - - -; #X floatatom 40 729 2 0 0 0 - - -; #X floatatom 57 729 2 0 0 0 - - -; #X floatatom 75 729 2 0 0 0 - - -; #X floatatom 92 729 2 0 0 0 - - -; #X floatatom 109 729 2 0 0 0 - - -; #X floatatom 127 729 2 0 0 0 - - -; #X floatatom 144 729 2 0 0 0 - - -; #X floatatom 162 729 2 0 0 0 - - -; #X floatatom 179 729 2 0 0 0 - - -; #X floatatom 196 729 2 0 0 0 - - -; #X floatatom 214 729 2 0 0 0 - - -; #X floatatom 231 729 2 0 0 0 - - -; #X floatatom 249 729 2 0 0 0 - - -; #X obj -12 709 unpack 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; #X floatatom -12 771 2 0 0 0 - - -; #X floatatom 5 771 2 0 0 0 - - -; #X floatatom 22 771 2 0 0 0 - - -; #X floatatom 40 771 2 0 0 0 - - -; #X floatatom 57 771 2 0 0 0 - - -; #X floatatom 75 771 2 0 0 0 - - -; #X floatatom 92 771 2 0 0 0 - - -; #X floatatom 109 771 2 0 0 0 - - -; #X floatatom 127 771 2 0 0 0 - - -; #X floatatom 144 771 2 0 0 0 - - -; #X floatatom 162 771 2 0 0 0 - - -; #X floatatom 179 771 2 0 0 0 - - -; #X floatatom 196 771 2 0 0 0 - - -; #X floatatom 214 771 2 0 0 0 - - -; #X floatatom 231 771 2 0 0 0 - - -; #X floatatom 249 771 2 0 0 0 - - -; #X obj -12 751 unpack 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; #X floatatom -12 813 2 0 0 0 - - -; #X floatatom 5 813 2 0 0 0 - - -; #X floatatom 22 813 2 0 0 0 - - -; #X floatatom 40 813 2 0 0 0 - - -; #X floatatom 57 813 2 0 0 0 - - -; #X floatatom 75 813 2 0 0 0 - - -; #X floatatom 92 813 2 0 0 0 - - -; #X floatatom 109 813 2 0 0 0 - - -; #X floatatom 127 813 2 0 0 0 - - -; #X floatatom 144 813 2 0 0 0 - - -; #X floatatom 162 813 2 0 0 0 - - -; #X floatatom 179 813 2 0 0 0 - - -; #X floatatom 196 813 2 0 0 0 - - -; #X floatatom 214 813 2 0 0 0 - - -; #X floatatom 231 813 2 0 0 0 - - -; #X floatatom 249 813 2 0 0 0 - - -; #X obj -12 793 unpack 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; #X floatatom -12 854 2 0 0 0 - - -; #X floatatom 5 854 2 0 0 0 - - -; #X floatatom 22 854 2 0 0 0 - - -; #X floatatom 40 854 2 0 0 0 - - -; #X floatatom 57 854 2 0 0 0 - - -; #X floatatom 75 854 2 0 0 0 - - -; #X floatatom 92 854 2 0 0 0 - - -; #X floatatom 109 854 2 0 0 0 - - -; #X floatatom 127 854 2 0 0 0 - - -; #X floatatom 144 854 2 0 0 0 - - -; #X floatatom 162 854 2 0 0 0 - - -; #X floatatom 179 854 2 0 0 0 - - -; #X floatatom 196 854 2 0 0 0 - - -; #X floatatom 214 854 2 0 0 0 - - -; #X floatatom 231 854 2 0 0 0 - - -; #X floatatom 249 854 2 0 0 0 - - -; #X obj -12 834 unpack 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; #X obj -45 523 r c8; #X obj -45 565 r c9; #X obj -46 608 r c10; #X obj -45 651 r c11; #X obj -45 692 r c12; #X obj -46 734 r c13; #X obj -46 776 r c14; #X obj -46 817 r c15; #X floatatom 268 114 5 0 0 0 - - -; #X msg 208 130 novar \$1; #X obj 704 407 nbx 5 14 -1e+37 1e+37 0 0 empty empty generation -65 8 0 10 -4160 -4034 -4034 0 256; #X obj 670 441 nbx 5 14 -1e+37 1e+37 0 0 empty empty delta -35 8 0 10 -4160 -4034 -4034 0 256; #X obj 687 424 nbx 5 14 -1e+37 1e+37 0 0 empty empty alive -35 8 0 10 -4160 -4034 -4034 0 256; #X obj 755 389 bng 15 250 50 0 empty empty dead 17 7 0 10 -258113 -262144 -4034; #X obj 738 440 bng 15 250 50 0 empty empty no_variation 17 7 0 10 -258113 -262144 -4034; #X obj 721 360 print dump_id_x_y; #X obj 448 197 pack 0 0; #X obj 466 162 t b f; #X obj 448 126 nbx 3 14 -99 99 0 0 empty empty x_shift -40 8 0 10 -4160 -4034 -4034 0 256; #X obj 466 144 nbx 3 14 -99 99 0 0 empty empty y_shift -40 8 0 10 -4160 -4034 -4034 0 256; #X msg 234 3 23/3; #X msg 349 271 rule \$1; #X obj 349 135 symbol; #X msg 270 39 012345678/; #X text 272 1 Rule for Conway life (default): A live cell survives if it has 2 or 3 neighbours. A dead cell becomes alive if it has 2 neighbours.; #X text 343 38 Rule to freeze the current state; #X msg 291 60 23/36; #X text 328 60 "High Life" rule; #X msg 312 81 5678/35678; #X text 384 81 "Diamoeba" rule; #X text 433 320 creation arguments: number of columns \, number of rows; #X obj 582 256 nbx 5 14 1 1e+37 0 1 empty empty period_(ms) -70 8 0 10 -4160 -4034 -4034 125 256; #X msg 335 104 /123; #X msg 292 214 shift \$1 \$2; #X obj 382 220 tgl 15 0 empty empty empty 17 7 0 10 -4160 -4034 -4034 0 1; #X msg 313 235 thru \$1; #X text 401 219 If thru is on \, output state changes other than generations ; #X msg 533 185 set \$1 \$2 \$3; #X obj 533 158 pack 0 0 0; #X floatatom 537 107 3 0 0 0 - - -; #X floatatom 561 107 3 0 0 0 - - -; #X floatatom 590 107 3 0 0 0 - - -; #X obj 533 134 f; #X obj 533 68 bng 15 250 50 0 empty empty set_cell 17 7 0 10 -4160 -4034 -4034; #X text 587 89 state; #X text 535 89 col; #X text 558 89 row; #X msg 230 151 randomize \$1; #X msg 313 134 0.5; #X text -28 25 clear the array to 0:; #X text -38 151 randomly set a fraction of the array alive:; #X text -67 47 output locations of live cells:; #X text -2 69 flip array horizontal:; #X text 33 89 flip array vertical:; #X text 25 109 invert values for display:; #X text -40 130 generations of no variation before bang:; #N canvas 529 268 494 344 META 0; #X text 12 135 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; #X text 12 115 AUTHOR Martin Peach; #X text 12 65 INLET_0 clear dump fliph flipv invert novar randomize reset return shift thru rule set; #X text 12 95 OUTLET_N list; #X text 12 25 LICENSE GPL v3 or later; #X text 12 45 DESCRIPTION Game of Life; #X text 12 5 KEYWORDS control; #X restore 784 627 pd META; #X connect 0 0 25 0; #X connect 1 0 25 0; #X connect 2 0 25 0; #X connect 3 0 25 0; #X connect 4 0 25 0; #X connect 5 0 25 0; #X connect 6 0 25 0; #X connect 7 0 25 0; #X connect 8 0 7 0; #X connect 25 0 28 0; #X connect 25 1 148 0; #X connect 25 2 149 0; #X connect 25 3 150 0; #X connect 25 4 151 0; #X connect 25 5 152 0; #X connect 25 6 153 0; #X connect 25 7 154 0; #X connect 25 8 155 0; #X connect 25 9 156 0; #X connect 25 10 157 0; #X connect 25 11 158 0; #X connect 25 12 159 0; #X connect 25 13 160 0; #X connect 25 14 161 0; #X connect 25 15 162 0; #X connect 25 16 319 0; #X connect 25 17 320 0; #X connect 25 18 318 0; #X connect 25 19 323 0; #X connect 25 20 322 0; #X connect 25 20 356 0; #X connect 25 21 321 0; #X connect 26 0 9 0; #X connect 26 1 10 0; #X connect 26 2 11 0; #X connect 26 3 12 0; #X connect 26 4 13 0; #X connect 26 5 14 0; #X connect 26 6 15 0; #X connect 26 7 16 0; #X connect 26 8 17 0; #X connect 26 9 18 0; #X connect 26 10 19 0; #X connect 26 11 20 0; #X connect 26 12 21 0; #X connect 26 13 22 0; #X connect 26 14 23 0; #X connect 26 15 24 0; #X connect 27 0 26 0; #X connect 45 0 29 0; #X connect 45 1 30 0; #X connect 45 2 31 0; #X connect 45 3 32 0; #X connect 45 4 33 0; #X connect 45 5 34 0; #X connect 45 6 35 0; #X connect 45 7 36 0; #X connect 45 8 37 0; #X connect 45 9 38 0; #X connect 45 10 39 0; #X connect 45 11 40 0; #X connect 45 12 41 0; #X connect 45 13 42 0; #X connect 45 14 43 0; #X connect 45 15 44 0; #X connect 62 0 46 0; #X connect 62 1 47 0; #X connect 62 2 48 0; #X connect 62 3 49 0; #X connect 62 4 50 0; #X connect 62 5 51 0; #X connect 62 6 52 0; #X connect 62 7 53 0; #X connect 62 8 54 0; #X connect 62 9 55 0; #X connect 62 10 56 0; #X connect 62 11 57 0; #X connect 62 12 58 0; #X connect 62 13 59 0; #X connect 62 14 60 0; #X connect 62 15 61 0; #X connect 79 0 63 0; #X connect 79 1 64 0; #X connect 79 2 65 0; #X connect 79 3 66 0; #X connect 79 4 67 0; #X connect 79 5 68 0; #X connect 79 6 69 0; #X connect 79 7 70 0; #X connect 79 8 71 0; #X connect 79 9 72 0; #X connect 79 10 73 0; #X connect 79 11 74 0; #X connect 79 12 75 0; #X connect 79 13 76 0; #X connect 79 14 77 0; #X connect 79 15 78 0; #X connect 96 0 80 0; #X connect 96 1 81 0; #X connect 96 2 82 0; #X connect 96 3 83 0; #X connect 96 4 84 0; #X connect 96 5 85 0; #X connect 96 6 86 0; #X connect 96 7 87 0; #X connect 96 8 88 0; #X connect 96 9 89 0; #X connect 96 10 90 0; #X connect 96 11 91 0; #X connect 96 12 92 0; #X connect 96 13 93 0; #X connect 96 14 94 0; #X connect 96 15 95 0; #X connect 113 0 97 0; #X connect 113 1 98 0; #X connect 113 2 99 0; #X connect 113 3 100 0; #X connect 113 4 101 0; #X connect 113 5 102 0; #X connect 113 6 103 0; #X connect 113 7 104 0; #X connect 113 8 105 0; #X connect 113 9 106 0; #X connect 113 10 107 0; #X connect 113 11 108 0; #X connect 113 12 109 0; #X connect 113 13 110 0; #X connect 113 14 111 0; #X connect 113 15 112 0; #X connect 130 0 114 0; #X connect 130 1 115 0; #X connect 130 2 116 0; #X connect 130 3 117 0; #X connect 130 4 118 0; #X connect 130 5 119 0; #X connect 130 6 120 0; #X connect 130 7 121 0; #X connect 130 8 122 0; #X connect 130 9 123 0; #X connect 130 10 124 0; #X connect 130 11 125 0; #X connect 130 12 126 0; #X connect 130 13 127 0; #X connect 130 14 128 0; #X connect 130 15 129 0; #X connect 147 0 131 0; #X connect 147 1 132 0; #X connect 147 2 133 0; #X connect 147 3 134 0; #X connect 147 4 135 0; #X connect 147 5 136 0; #X connect 147 6 137 0; #X connect 147 7 138 0; #X connect 147 8 139 0; #X connect 147 9 140 0; #X connect 147 10 141 0; #X connect 147 11 142 0; #X connect 147 12 143 0; #X connect 147 13 144 0; #X connect 147 14 145 0; #X connect 147 15 146 0; #X connect 163 0 45 0; #X connect 164 0 62 0; #X connect 165 0 79 0; #X connect 166 0 96 0; #X connect 167 0 113 0; #X connect 168 0 130 0; #X connect 169 0 147 0; #X connect 170 0 25 0; #X connect 171 0 170 0; #X connect 188 0 172 0; #X connect 188 1 173 0; #X connect 188 2 174 0; #X connect 188 3 175 0; #X connect 188 4 176 0; #X connect 188 5 177 0; #X connect 188 6 178 0; #X connect 188 7 179 0; #X connect 188 8 180 0; #X connect 188 9 181 0; #X connect 188 10 182 0; #X connect 188 11 183 0; #X connect 188 12 184 0; #X connect 188 13 185 0; #X connect 188 14 186 0; #X connect 188 15 187 0; #X connect 205 0 189 0; #X connect 205 1 190 0; #X connect 205 2 191 0; #X connect 205 3 192 0; #X connect 205 4 193 0; #X connect 205 5 194 0; #X connect 205 6 195 0; #X connect 205 7 196 0; #X connect 205 8 197 0; #X connect 205 9 198 0; #X connect 205 10 199 0; #X connect 205 11 200 0; #X connect 205 12 201 0; #X connect 205 13 202 0; #X connect 205 14 203 0; #X connect 205 15 204 0; #X connect 222 0 206 0; #X connect 222 1 207 0; #X connect 222 2 208 0; #X connect 222 3 209 0; #X connect 222 4 210 0; #X connect 222 5 211 0; #X connect 222 6 212 0; #X connect 222 7 213 0; #X connect 222 8 214 0; #X connect 222 9 215 0; #X connect 222 10 216 0; #X connect 222 11 217 0; #X connect 222 12 218 0; #X connect 222 13 219 0; #X connect 222 14 220 0; #X connect 222 15 221 0; #X connect 239 0 223 0; #X connect 239 1 224 0; #X connect 239 2 225 0; #X connect 239 3 226 0; #X connect 239 4 227 0; #X connect 239 5 228 0; #X connect 239 6 229 0; #X connect 239 7 230 0; #X connect 239 8 231 0; #X connect 239 9 232 0; #X connect 239 10 233 0; #X connect 239 11 234 0; #X connect 239 12 235 0; #X connect 239 13 236 0; #X connect 239 14 237 0; #X connect 239 15 238 0; #X connect 256 0 240 0; #X connect 256 1 241 0; #X connect 256 2 242 0; #X connect 256 3 243 0; #X connect 256 4 244 0; #X connect 256 5 245 0; #X connect 256 6 246 0; #X connect 256 7 247 0; #X connect 256 8 248 0; #X connect 256 9 249 0; #X connect 256 10 250 0; #X connect 256 11 251 0; #X connect 256 12 252 0; #X connect 256 13 253 0; #X connect 256 14 254 0; #X connect 256 15 255 0; #X connect 273 0 257 0; #X connect 273 1 258 0; #X connect 273 2 259 0; #X connect 273 3 260 0; #X connect 273 4 261 0; #X connect 273 5 262 0; #X connect 273 6 263 0; #X connect 273 7 264 0; #X connect 273 8 265 0; #X connect 273 9 266 0; #X connect 273 10 267 0; #X connect 273 11 268 0; #X connect 273 12 269 0; #X connect 273 13 270 0; #X connect 273 14 271 0; #X connect 273 15 272 0; #X connect 290 0 274 0; #X connect 290 1 275 0; #X connect 290 2 276 0; #X connect 290 3 277 0; #X connect 290 4 278 0; #X connect 290 5 279 0; #X connect 290 6 280 0; #X connect 290 7 281 0; #X connect 290 8 282 0; #X connect 290 9 283 0; #X connect 290 10 284 0; #X connect 290 11 285 0; #X connect 290 12 286 0; #X connect 290 13 287 0; #X connect 290 14 288 0; #X connect 290 15 289 0; #X connect 307 0 291 0; #X connect 307 1 292 0; #X connect 307 2 293 0; #X connect 307 3 294 0; #X connect 307 4 295 0; #X connect 307 5 296 0; #X connect 307 6 297 0; #X connect 307 7 298 0; #X connect 307 8 299 0; #X connect 307 9 300 0; #X connect 307 10 301 0; #X connect 307 11 302 0; #X connect 307 12 303 0; #X connect 307 13 304 0; #X connect 307 14 305 0; #X connect 307 15 306 0; #X connect 308 0 188 0; #X connect 309 0 205 0; #X connect 310 0 222 0; #X connect 311 0 239 0; #X connect 312 0 256 0; #X connect 313 0 273 0; #X connect 314 0 290 0; #X connect 315 0 307 0; #X connect 316 0 317 0; #X connect 317 0 25 0; #X connect 324 0 341 0; #X connect 325 0 324 0; #X connect 325 1 324 1; #X connect 326 0 324 0; #X connect 327 0 325 0; #X connect 328 0 330 0; #X connect 329 0 25 0; #X connect 330 0 329 0; #X connect 331 0 330 0; #X connect 334 0 330 0; #X connect 336 0 330 0; #X connect 339 0 170 1; #X connect 340 0 330 0; #X connect 341 0 25 0; #X connect 342 0 343 0; #X connect 343 0 25 0; #X connect 345 0 25 0; #X connect 346 0 345 0; #X connect 347 0 350 1; #X connect 348 0 346 1; #X connect 349 0 346 2; #X connect 350 0 346 0; #X connect 351 0 350 0; #X connect 355 0 25 0; #X connect 356 0 355 0; mrpeach/tabfind/0000755000175000017500000000000013605444731014345 5ustar zmoelnigzmoelnigmrpeach/tabfind/tabfind-help.pd0000644000175000017500000000365311533765040017233 0ustar zmoelnigzmoelnig#N canvas 1 53 510 378 10; #X obj 0 299 table pig; #X obj 94 138 tabfind pig; #X obj -3 24 f; #X obj -3 7 bng 15 250 50 0 empty empty empty 17 7 0 10 -4034 -257985 -1; #X msg 89 116 set wig; #X obj 64 299 table wig; #X msg 70 97 set pig; #X msg 0 266 \; wig 0 88 89 88 83 22 0 11; #X msg 51 78 nth \$1; #X text 107 61 By default tabfind finds the first instance of the input. ; #X text 98 77 The [nth( message sets which instance to fnd.; #X obj 55 194 loadbang; #X text 131 96 The [set( message sets which array to look in.; #X text 148 159 index \, or length of array if input not found.; #X msg 16 43 76 72 71; #X msg 45 221 \; pig 0 72 73 75 76 72 71 72 76 88 0 0 99 100 101 102 76 72 71 99 98 97; #X text 281 297 2008_11_20 Martin Peach; #X obj 51 62 nbx 5 14 1 1e+37 0 1 empty empty empty 0 -8 0 10 -4034 -16662 -1 1 256; #X obj 17 7 nbx 3 14 -1e+37 1e+37 0 1 empty empty empty 0 -8 0 10 -4034 -16662 -1 99 256; #X obj 94 160 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -8 0 10 -4032 -258113 -1 0 256; #X text -4 -30 [tabfind] searches an array and outputs the index at which the input float or list of floats is found.; #X text 166 137 argument is the name of the array to search in.; #X text 55 6 <--find this number.; #X text 71 43 <-- or find this sequence.; #N canvas 434 305 494 344 META 0; #X text 12 135 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; #X text 12 25 LICENSE GPL v2 or later; #X text 12 115 AUTHOR Martin Peach; #X text 12 5 KEYWORDS control array; #X text 12 46 DESCRIPTION search an array and output the index at which the input float or list of floats is found; #X text 12 75 INLET_0 float list nth set; #X text 12 95 OUTLET_0 float; #X restore 444 310 pd META; #X connect 1 0 19 0; #X connect 2 0 1 0; #X connect 3 0 2 0; #X connect 4 0 1 0; #X connect 6 0 1 0; #X connect 8 0 1 0; #X connect 11 0 15 0; #X connect 11 0 7 0; #X connect 14 0 1 0; #X connect 17 0 8 0; #X connect 18 0 2 1; mrpeach/tabfind/tabfind.c0000644000175000017500000001074412430234120016106 0ustar zmoelnigzmoelnig/* ---------- tabfind: return the index of the input (float or list of floats)in the given table */ /* based on tabread in d_array.c */ /* Started 20081120 by Martin Peach (mrpeach) */ #include "m_pd.h" #if (PD_MINOR_VERSION > 40) #define USE_GETFLOATWORDS *//* if garray_getfloatwords is implemented */ #endif /* garray_getfloatwords uses t_word but doesn't exist in some versions of pd */ /* garray_getfloatarray uses t_float but is not 64-bit */ static t_class *tabfind_class; typedef struct _tabfind { t_object x_obj; t_symbol *x_arrayname; int x_nth; /* which match to find */ } t_tabfind; static void tabfind_bang(t_tabfind *x); static void tabfind_float(t_tabfind *x, t_float f); static void tabfind_list(t_tabfind *x, t_symbol *s, int argc, t_atom *argv); static void tabfind_nth(t_tabfind *x, t_float nth); static void tabfind_set(t_tabfind *x, t_symbol *s); static void *tabfind_new(t_symbol *s); void tabfind_setup(void); static void tabfind_nth(t_tabfind *x, t_float fnth) { /* set to find the nth instance of the key */ int inth; if (fnth >= 1) inth = (int)fnth; else { inth = 1; pd_error(x, "tabfind: nth must be at least 1"); } x->x_nth = inth; } static void tabfind_list(t_tabfind *x, t_symbol *s, int argc, t_atom *argv) { /* find the nth occurrence of the list of floats argv in the array */ t_garray *a; int npoints; #ifdef USE_GETFLOATWORDS t_word *vec; #else t_float *vec; #endif int n, count = 0; int i; /* first check the list for floatness... */ for (i = 0; i < argc; ++i) { if (argv[i].a_type != A_FLOAT) { pd_error(x, "tabfind: list must be all floats"); return; } } /* then find the array again... */ if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class))) pd_error(x, "tabfind: %s: no such array", x->x_arrayname->s_name); #ifdef USE_GETFLOATWORDS else if (!garray_getfloatwords(a, &npoints, &vec)) #else else if (!garray_getfloatarray(a, &npoints, &vec)) #endif pd_error(x, "tabfind: %s: bad template for tabread", x->x_arrayname->s_name); else /* try to find the nth instance of the list in a and output its index */ { for (n = 0; n < npoints; ++n) { for (i = 0; ((i < argc) && ((n+i) < npoints)); ++i) #ifdef USE_GETFLOATWORDS if (vec[n+i].w_float != argv[i].a_w.w_float) break; #else if (vec[n+i] != argv[i].a_w.w_float) break; #endif if ((i == argc) && (x->x_nth == ++count)) break; } outlet_float(x->x_obj.ob_outlet, n); } } static void tabfind_bang(t_tabfind *x) { } static void tabfind_float(t_tabfind *x, t_float f) { /* find the nth occurrence of the float f in the array */ t_garray *a; int npoints; #ifdef USE_GETFLOATWORDS t_word *vec; #else t_float *vec; #endif int n, count = 0; if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class))) pd_error(x, "tabfind: %s: no such array", x->x_arrayname->s_name); #ifdef USE_GETFLOATWORDS else if (!garray_getfloatwords(a, &npoints, &vec)) #else else if (!garray_getfloatarray(a, &npoints, &vec)) #endif pd_error(x, "tabfind: %s: bad template for tabread", x->x_arrayname->s_name); else /* find the nth instance of f in a and output its index */ { for (n = 0; n < npoints; ++n) { #ifdef USE_GETFLOATWORDS if (vec[n].w_float == f) #else if (vec[n] == f) #endif if (x->x_nth == ++count) break; } outlet_float(x->x_obj.ob_outlet, n); } } static void tabfind_set(t_tabfind *x, t_symbol *s) { /* set the name of the array we're working on */ x->x_arrayname = s; } static void *tabfind_new(t_symbol *s) { t_tabfind *x = (t_tabfind *)pd_new(tabfind_class); x->x_arrayname = s; outlet_new(&x->x_obj, &s_float); x->x_nth = 1; return (x); } void tabfind_setup(void) { tabfind_class = class_new(gensym("tabfind"), (t_newmethod)tabfind_new, 0, sizeof(t_tabfind), 0, A_DEFSYM, 0); class_addbang(tabfind_class, (t_method)tabfind_bang); class_addfloat(tabfind_class, (t_method)tabfind_float); class_addlist(tabfind_class, (t_method)tabfind_list); class_addmethod(tabfind_class, (t_method)tabfind_nth, gensym("nth"), A_FLOAT, 0); class_addmethod(tabfind_class, (t_method)tabfind_set, gensym("set"), A_SYMBOL, 0); } mrpeach/tab2flist/0000755000175000017500000000000013605444731014630 5ustar zmoelnigzmoelnigmrpeach/tab2flist/tab2flist-help.pd0000644000175000017500000000276611533764733020015 0ustar zmoelnigzmoelnig#N canvas 1 53 535 282 10; #X obj 152 152 tab2flist zig; #X obj 10 -5 bng 15 250 50 0 empty empty empty 17 7 0 10 -4034 -257985 -1; #X obj 152 173 print; #X obj 190 173 table zig; #X floatatom 227 124 5 0 0 0 - - -; #X floatatom 64 48 5 0 0 0 - - -; #X text 33 -8 Banging tab2flist outputs a list of floats from the table. ; #X msg 36 19 set zag; #X text 240 152 Argument is table name.; #X text 150 190 Points outside the table will be output as zeroes. ; #X text 98 47 A single float sets offset.; #X text 89 18 Set the table by name.; #X obj 250 173 table zag; #X msg 86 69 5 10; #X text 150 204 Negative length outputs a list as long as the table. ; #X text 263 123 Float in second inlet sets length of list.; #X text 118 68 Two floats set offset and length.; #X msg 109 92 delimiter 10 13; #X text 207 91 Output stops when a delimiter is encountered.; #X text 145 243 2009_1_28 Martin Peach; #N canvas 456 322 494 344 META 0; #X text 12 155 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; #X text 12 25 LICENSE GPL v2 or later; #X text 12 135 AUTHOR Martin Peach; #X text 12 5 KEYWORDS control conversion array list_op; #X text 12 46 DESCRIPTION output the values from an array as a list of floats; #X text 12 75 INLET_0 bang float list set delimiter; #X text 12 95 INLET_1 float; #X text 12 115 OUTLET_0 list; #X restore 474 246 pd META; #X connect 0 0 2 0; #X connect 1 0 0 0; #X connect 4 0 0 1; #X connect 5 0 0 0; #X connect 7 0 0 0; #X connect 13 0 0 0; #X connect 17 0 0 0; mrpeach/tab2flist/tab2flist.c0000644000175000017500000001541211140150766016663 0ustar zmoelnigzmoelnig/* tab2flist started 20090121 by mrpeach */ /* Message with two floats dumps a list of floats from a table at offset,length */ /* Bang dumps the entire table as a list of floats */ /* Floats at negative offsets will not be dumped. */ #include "m_pd.h" #if (PD_MINOR_VERSION > 40) #define USE_GETFLOATWORDS *//* if garray_getfloatwords is implemented */ #endif /* garray_getfloatwords uses t_word but doesn't exist in some versions of pd */ /* garray_getfloatarray uses t_float but is not 64-bit */ static t_class *tab2flist_class; typedef struct _tab2flist { t_object x_obj; t_outlet *x_listout; t_symbol *x_arrayname; t_float x_offset; t_float x_length; t_float *x_delimiters; int x_n_delimiters; } t_tab2flist; static void tab2flist_delimit(t_tab2flist *x, int *argc, t_atom *argv); //static void tab2flist_list(t_tab2flist *x, t_symbol *s, int argc, t_atom *argv); static void tab2flist_float(t_tab2flist *x, t_float f); static void tab2flist_bang(t_tab2flist *x); static void tab2flist_set(t_tab2flist *x, t_symbol *s); static void tab2flist_delimiter(t_tab2flist *x, t_symbol *s, int argc, t_atom *argv); static void tab2flist_free(t_tab2flist *x); static void *tab2flist_new(t_symbol *s); void tab2flist_setup(void); static void tab2flist_bang(t_tab2flist *x) { /* output a list of x_length floats from the table starting from x_offset */ /* output zero for elements outside the table (e.g. negative x_offset) */ /* if delimiters are specified, stop when encountering a delimiter */ t_garray *a; int n, i, tabpoints, listpoints; int listsize; t_atom *atomlist = NULL; #ifdef USE_GETFLOATWORDS t_word *vec; #else t_float *vec; #endif /* Read in the array */ if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class))) pd_error(x, "tab2flist_list: %s: no such array", x->x_arrayname->s_name); #ifdef USE_GETFLOATWORDS else if (!garray_getfloatwords(a, &tabpoints, &vec)) #else else if (!garray_getfloatarray(a, &tabpoints, &vec)) #endif pd_error(x, "tab2flist_list: %s: bad template", x->x_arrayname->s_name); else if (x->x_length != 0) { if (x->x_length > 0) listpoints = x->x_length; else listsize = tabpoints; /* when x_length < 0, output the whole table */ listsize = listpoints * sizeof(t_atom); atomlist = getbytes(listsize); if (atomlist == NULL) { pd_error(x, "tab2flist_list: unable to allocate %lu bytes for list", listsize); return; } else { for (n = x->x_offset, i = 0; i < listpoints; ++n) { if ((n >= 0) && (n < tabpoints)) { #ifdef USE_GETFLOATWORDS SETFLOAT(&atomlist[i], vec[n].w_float); #else SETFLOAT(&atomlist[i], vec[n]); #endif } else { #ifdef USE_GETFLOATWORDS SETFLOAT(&atomlist[i], 0); #else SETFLOAT(&atomlist[i], 0); #endif } i++; } if (x->x_n_delimiters > 0) tab2flist_delimit(x, &listpoints, atomlist); outlet_list(x->x_listout, &s_list, listpoints, atomlist); freebytes(atomlist, listsize); } } } static void tab2flist_delimit(t_tab2flist *x, int *argc, t_atom *argv) { /* for each element in argv, check if it matches a delimiter */ /* if so, truncate the list and set the new length */ int i,j, n = *argc; t_float f; for (i = 0; i < n; ++i) { f = atom_getfloat(&argv[i]); for (j = 0; j < x->x_n_delimiters; ++j) { if (f == x->x_delimiters[j]) { *argc = i; return; } } } } #ifdef NOWAY static void tab2flist_list(t_tab2flist *x, t_symbol *s, int argc, t_atom *argv) { int i; /* expect a list of 2 floats for offset and packet length */ /* Check the incoming list for length = 2 */ if (argc != 2) { pd_error(x, "tab2flist_list: list must contain exactly two floats (offset, length)"); return; } /* Check the incoming list for floatness... */ for (i = 0; i < 2; ++i) { if (argv[i].a_type != A_FLOAT) { pd_error(x, "tab2flist_list: list must contain exactly two floats (offset, length)"); return; } } /* Read offset and packet size from incoming list */ x->x_offset = argv[0].a_w.w_float; x->x_length = argv[1].a_w.w_float; } #endif static void tab2flist_float(t_tab2flist *x, t_float f) { x->x_offset = f; } static void tab2flist_set(t_tab2flist *x, t_symbol *s) { x->x_arrayname = s; } static void tab2flist_delimiter(t_tab2flist *x, t_symbol *s, int argc, t_atom *argv) { int i; /* expect a list of at least one float for delimiter values */ /* Check the incoming list for floatness... */ for (i = 0; i < argc; ++i) { if (argv[i].a_type != A_FLOAT) { pd_error(x, "tab2flist_delimiter: list must contain only floats"); return; } } /* allocate storage for the delimiters */ if (x->x_delimiters == NULL) x->x_delimiters = getbytes(argc*sizeof(t_float)); else x->x_delimiters = resizebytes(x->x_delimiters, x->x_n_delimiters*sizeof(t_float), argc*sizeof(t_float)); if (x->x_delimiters == NULL) { pd_error(x, "tab2flist_delimiter can't get %lu bytes for delimiters", argc*sizeof(t_float)); x->x_n_delimiters = 0; return; } x->x_n_delimiters = argc; for (i = 0; i < argc; ++i) x->x_delimiters[i] = atom_getfloat(&argv[i]); } static void tab2flist_free(t_tab2flist *x) { if (x->x_n_delimiters > 0) freebytes(x->x_delimiters, x->x_n_delimiters*sizeof(t_float)); } static void *tab2flist_new(t_symbol *s) { t_tab2flist *x = (t_tab2flist *)pd_new(tab2flist_class); x->x_listout = outlet_new(&x->x_obj, &s_list); floatinlet_new(&x->x_obj, &x->x_length); x->x_offset = x->x_n_delimiters = 0; x->x_delimiters = NULL; x->x_length = -1; /* default to output the whole table */ x->x_arrayname = s; return (x); } void tab2flist_setup(void) { tab2flist_class = class_new(gensym("tab2flist"), (t_newmethod)tab2flist_new, (t_method) tab2flist_free, sizeof(t_tab2flist), 0, A_DEFSYM, 0); class_addbang(tab2flist_class, (t_method)tab2flist_bang); // class_addlist(tab2flist_class, (t_method)tab2flist_list); class_addfloat(tab2flist_class, (t_method)tab2flist_float); class_addmethod(tab2flist_class, (t_method)tab2flist_set, gensym("set"), A_SYMBOL, 0); class_addmethod(tab2flist_class, (t_method)tab2flist_delimiter, gensym("delimiter"), A_GIMME, 0); } mrpeach/rojo~/0000755000175000017500000000000013605444731014105 5ustar zmoelnigzmoelnigmrpeach/rojo~/rojo~.c0000644000175000017500000002534711315550005015417 0ustar zmoelnigzmoelnig/* Martin Peach 20060827 start porting this to pd */ /* 20060828 move the used functions from ruidolib.c to this file */ /* * ruido.c * Copyright (C) 2004 jos manuel berenguer * generador de nmeros aleatorios para max/msp * Este programa es Software Libre; usted puede redistribuirlo * y/o modificarlo bajo los trminos de la "GNU General Public * License" como lo publica la "FSF Free Software Foundation", * o (a su eleccin) de cualquier versin posterior. * Este programa es distribuido con la esperanza de que le ser * til, pero SIN NINGUNA GARANTIA; incluso sin la garanta * implcita por el MERCADEO o EJERCICIO DE ALGUN PROPOSITO en * particular. Vea la "GNU General Public License" para ms * detalles. * Usted debe haber recibido una copia de la "GNU General Public * License" junto con este programa, si no, escriba a la "FSF * Free Software Foundation, Inc.", 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include "m_pd.h" #include void *rojo_class; typedef struct _rojo { t_object x_obj; t_float x_scale; t_float x_alpha; double x_u[97]; double x_c; double x_cd; double x_cm; int x_i97; int x_j97; int x_test; } t_rojo; static t_int *perform0(t_int *w); static void rojo_dsp(t_rojo *x, t_signal **sp); static void rojo_assist(t_rojo *x, void *b, long m, long a, char *s); static void *rojo_new(t_symbol *s, short ac, t_atom *av); void rojo_tilde_setup(void); static void rojo_RandomInitialise(t_rojo *x, int ij,int kl); static double rojo_RandomUniform(t_rojo *x); static double rojo_RandomGaussian(t_rojo *x, double mean, double stddev); static double rojo_RuidoRojo(t_rojo *x, double c, double a, double media, double desviacion); /* some defines from ruidolib.h: */ #ifndef ABS #define ABS(x) (x < 0 ? -(x) : (x)) #endif #ifndef TRUE #define TRUE 1 #define FALSE 0 #endif /*------------------------------------------------------------------*/ void rojo_tilde_setup(void) { rojo_class = class_new(gensym("rojo~"), (t_newmethod)rojo_new, 0, sizeof(t_rojo), CLASS_NOINLET, A_GIMME, 0); class_addmethod(rojo_class, (t_method)rojo_dsp, gensym("dsp"), 0); } /*------------------------------------------------------------------*/ static t_int *perform0(t_int *w) { t_rojo *x = (t_rojo *)(w[1]); t_float *out = (t_float *)(w[2]); double scale = x->x_scale; double alpha = x->x_alpha; int n = (int)(w[3]); if (alpha > 1.0) alpha = 1.0;/* MP 20060827 audio sticks if this is allowed */ else if (alpha < -1.0) alpha = -1.0;/* MP 20060827 audio sticks if this is allowed */ while (--n) *++out = scale * rojo_RuidoRojo(x, 0.0, alpha, 0.0, 1.0); return (w+4); } /*------------------------------------------------------------------*/ static void rojo_dsp(t_rojo *x, t_signal **sp) { dsp_add(perform0, 3, x, sp[0]->s_vec, sp[0]->s_n); } /*------------------------------------------------------------------*/ /* outlet 0: red noise outlet */ /* inlet 0: (float) scale (0, x) */ /* inlet 1: (float), alpha (-1, 1) */ /*------------------------------------------------------------------*/ static void *rojo_new(t_symbol *s, short ac, t_atom *av) { t_rojo *x = (t_rojo *)pd_new(rojo_class); outlet_new(&x->x_obj, gensym("signal")); floatinlet_new(&x->x_obj, &x->x_scale); floatinlet_new(&x->x_obj, &x->x_alpha); post("rojo~ x[n] = scale * (alpha * x[n-1] + z[n])", 0); if (ac == 2) { x->x_scale = (t_float) av[0].a_w.w_float; x->x_alpha = (t_float) av[1].a_w.w_float; } else { x->x_scale = (t_float)0.1; x->x_alpha = (t_float)0.7; } post("scale %lf", x->x_scale); post("alpha %lf", x->x_alpha); x->x_test = FALSE; return (x); } /* Miscellaneous routines */ /* This Random Number Generator is based on the algorithm in a FORTRAN version published by George Marsaglia and Arif Zaman, Florida State University; ref.: see original comments below. At the fhw (Fachhochschule Wiesbaden, W.Germany), Dept. of Computer Science, we have written sources in further languages (C, Modula-2 Turbo-Pascal(3.0, 5.0), Basic and Ada) to get exactly the same test results compared with the original FORTRAN version. April 1989 Karl-L. Noell and Helmut Weber This random number generator originally appeared in "Toward a Universal Random Number Generator" by George Marsaglia and Arif Zaman. Florida State University Report: FSU-SCRI-87-50 (1987) It was later modified by F. James and published in "A Review of Pseudo- random Number Generators" THIS IS THE BEST KNOWN RANDOM NUMBER GENERATOR AVAILABLE. (However, a newly discovered technique can yield a period of 10^600. But that is still in the development stage.) It passes ALL of the tests for random number generators and has a period of 2^144, is completely portable (gives bit identical results on all machines with at least 24-bit mantissas in the floating point representation). The algorithm is a combination of a Fibonacci sequence (with lags of 97 and 33, and operation "subtraction plus one, modulo one") and an "arithmetic sequence" (using subtraction). Use IJ = 1802 & KL = 9373 to test the random number generator. The subroutine RANMAR should be used to generate 20000 random numbers. Then display the next six random numbers generated multiplied by 4096*4096 If the random number generator is working properly, the random numbers should be: 6533892.0 14220222.0 7275067.0 6172232.0 8354498.0 10633180.0 */ /* This is the initialization routine for the random number generator. NOTE: The seed variables can have values between: 0 <= IJ <= 31328 0 <= KL <= 30081 The random number sequences created by these two seeds are of sufficient length to complete an entire calculation with. For example, if sveral different groups are working on different parts of the same calculation, each group could be assigned its own IJ seed. This would leave each group with 30000 choices for the second seed. That is to say, this random number generator can create 900 million different subsequences -- with each subsequence having a length of approximately 10^30. */ static void rojo_RandomInitialise(t_rojo *x, int ij, int kl) { double s, t; int ii, i, j, k, l, jj, m; /* Handle the seed range errors: First random number seed must be between 0 and 31328. Second seed must have a value between 0 and 30081. */ if (ij < 0 || ij > 31328 || kl < 0 || kl > 30081) { ij = 1802; kl = 9373; } i = (ij / 177) % 177 + 2; j = (ij % 177) + 2; k = (kl / 169) % 178 + 1; l = (kl % 169); for (ii=0; ii<97; ii++) { s = 0.0; t = 0.5; for (jj=0; jj<24; jj++) { m = (((i * j) % 179) * k) % 179; i = j; j = k; k = m; l = (53 * l + 1) % 169; if (((l * m % 64)) >= 32) s += t; t *= 0.5; } x->x_u[ii] = s; } x->x_c = 362436.0 / 16777216.0; x->x_cd = 7654321.0 / 16777216.0; x->x_cm = 16777213.0 / 16777216.0; x->x_i97 = 97; x->x_j97 = 33; x->x_test = TRUE; } /* This is the random number generator proposed by George Marsaglia in Florida State University Report: FSU-SCRI-87-50 */ static double rojo_RandomUniform(t_rojo *x) { double uni; /* Make sure the initialisation routine has been called */ if (!x->x_test) rojo_RandomInitialise(x, 1802,9373); uni = x->x_u[x->x_i97-1] - x->x_u[x->x_j97-1]; if (uni <= 0.0) uni++; x->x_u[x->x_i97-1] = uni; x->x_i97--; if (x->x_i97 == 0) x->x_i97 = 97; x->x_j97--; if (x->x_j97 == 0) x->x_j97 = 97; x->x_c -= x->x_cd; if (x->x_c < 0.0) x->x_c += x->x_cm; uni -= x->x_c; if (uni < 0.0) uni++; return(uni); } /* ALGORITHM 712, COLLECTED ALGORITHMS FROM ACM. THIS WORK PUBLISHED IN TRANSACTIONS ON MATHEMATICAL SOFTWARE, VOL. 18, NO. 4, DECEMBER, 1992, PP. 434-435. The function returns a normally distributed pseudo-random number with a given mean and standard devaiation. Calls are made to a function subprogram which must return independent random numbers uniform in the interval (0,1). The algorithm uses the ratio of uniforms method of A.J. Kinderman and J.F. Monahan augmented with quadratic bounding curves. */ static double rojo_RandomGaussian(t_rojo *x, double mean, double stddev) { double q, u, v, xx, y; /* Generate P = (u,v) uniform in rect. enclosing acceptance region Make sure that any random numbers <= 0 are rejected, since gaussian() requires uniforms > 0, but RandomUniform() delivers >= 0. */ do { u = rojo_RandomUniform(x); v = rojo_RandomUniform(x); if (u <= 0.0 || v <= 0.0) { u = 1.0; v = 1.0; } v = 1.7156 * (v - 0.5); /* Evaluate the quadratic form */ xx = u - 0.449871; y = ABS(v) + 0.386595; q = xx * xx + y * (0.19600 * y - 0.25472 * xx); /* Accept P if inside inner ellipse */ if (q < 0.27597) break; /* Reject P if outside outer ellipse, or outside acceptance region */ } while ((q > 0.27846) || (v * v > -4.0 * log(u) * u * u)); /* Return ratio of P's coordinates as the normal deviate */ return (mean + stddev * v / u); } /*------------------------------------------------------------------------- Esta calcula una muestra de una secuencia de ruido rojo obtenida por un proceso autoregresivo de primer orden (AR(1)) del tipo x[n] = c + a x[n-1] + z[n] donce c constante (casi siempre = 0 para su uso en max a es constante -1 > a < 1 z[n] es la innovacin. una muestra de un ruido gaussiano x[n] es la muestra actual x[n-1] es la anterior muestra obtenida media es la media del ruido gaussiano y desviacion es la desviacin tipica del ruido gaussiano */ /*---------translated by mrpeach: Calculate a sample of a sequence of red noise obtained by a first-order autoregressive process (AR(1)) of type x[n] = c + a x[n-1] + z[n] where: c = constant (always = 0 for maximum output) a = constant (-1 < a < 1) z[n] is a new sample of gaussian noise x[n] is the current sample x[n-1] is the previous sample obtained media is the mean and desviacion is the standard deviation of the gaussian noise */ static double rojo_RuidoRojo(t_rojo *x, double c, double a, double media, double desviacion) { static double xx; xx = c + a * xx + rojo_RandomGaussian(x, media, desviacion); return xx; } /* end of rojo~.c */ mrpeach/rojo~/rojo~-help.pd0000644000175000017500000000177611533764274016547 0ustar zmoelnigzmoelnig#N canvas 1 53 450 312 10; #X obj 49 161 *~; #X obj 22 -12 vsl 15 128 0 1 0 0 empty empty vol 0 -9 0 10 -4034 -13381 -13381 0 1; #X obj 50 200 dac~; #X obj 52 31 hsl 128 15 0 1 0 1 empty empty scale -2 -8 0 10 -4034 -13381 -13381 2500 1; #X obj 79 66 hsl 128 15 0 0.99 0 0 empty empty alpha -2 -8 0 10 -4034 -13381 -13381 0 1; #X text 57 -15 rojo~ is a red noise generator; #X text 138 242 2008 Martin Peach; #X text 137 221 Based on ruido.c by jose manuel berenguer; #X obj 49 83 rojo~; #N canvas 367 170 494 344 META 0; #X text 12 145 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; #X text 12 25 LICENSE GPL v2 or later; #X text 12 125 AUTHOR Martin Peach; #X text 12 5 KEYWORDS signal random; #X text 12 45 DESCRIPTION red noise generator; #X text 12 65 INLET_0 float; #X text 12 85 INLET_1 float; #X text 12 105 OUTLET_0 signal; #X restore 393 254 pd META; #X connect 0 0 2 0; #X connect 0 0 2 1; #X connect 1 0 0 1; #X connect 3 0 8 0; #X connect 4 0 8 1; #X connect 8 0 0 0; mrpeach/serializer/0000755000175000017500000000000013605444727015114 5ustar zmoelnigzmoelnigmrpeach/serializer/sprint-help.pd0000644000175000017500000000176313572277060017712 0ustar zmoelnigzmoelnig#N canvas 148 283 903 374 12; #X obj 203 269 print serialized; #X msg 115 112 hello; #X floatatom 179 176 5 0 0 0 - - -; #X msg 26 23 1023; #X msg 94 91 one two three; #X msg 158 154 11 222 33333; #X msg 71 68 1 two 3; #X msg 49 46 one 2 three; #X text 257 92 [sprint] works like [print] but 'prints' to its outlet. This can be useful for sending to character devices like [comport]. ; #X text 207 308 Martin Peach 2019/12/05; #X msg 136 133 3e+12; #X obj 203 198 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 -1; #X text 219 195 bang resends the previous message; #X text 260 150 The 'list' selector is ignored but other selectors are considered part of the input.; #X text 279 218 argument is ASCII code or literal character of optional separator (32 is space); #X obj 203 219 sprint 32; #X connect 1 0 15 0; #X connect 2 0 15 0; #X connect 3 0 15 0; #X connect 4 0 15 0; #X connect 5 0 15 0; #X connect 6 0 15 0; #X connect 7 0 15 0; #X connect 10 0 15 0; #X connect 11 0 15 0; #X connect 15 0 0 0; mrpeach/serializer/f2b-help.pd0000644000175000017500000000150012120146501017010 0ustar zmoelnigzmoelnig#N canvas 626 544 450 300 10; #X obj 57 151 f2b; #X msg 57 118 3.14159; #X obj 57 187 unpack 0 0 0 0; #X floatatom 57 228 5 0 0 0 - - -; #X floatatom 92 228 5 0 0 0 - - -; #X floatatom 127 228 5 0 0 0 - - -; #X floatatom 162 228 5 0 0 0 - - -; #X text 244 268 Martin Peach 2013_03_13; #X msg 135 118 100000; #X text 53 8 [f2b] converts floats to lists of four bytes suitable for sending through a serial connection. This is the binary representation \, so the receiver must use the same floating-point format.; #X obj 213 114 * 4; #X floatatom 213 141 12 0 0 0 - - -; #X obj 213 91 atan; #X msg 213 68 1; #X connect 0 0 2 0; #X connect 1 0 0 0; #X connect 2 0 3 0; #X connect 2 1 4 0; #X connect 2 2 5 0; #X connect 2 3 6 0; #X connect 8 0 0 0; #X connect 10 0 11 0; #X connect 10 0 0 0; #X connect 12 0 10 0; #X connect 13 0 12 0; mrpeach/serializer/b2f-help.pd0000644000175000017500000000067712120146501017026 0ustar zmoelnigzmoelnig#N canvas 666 174 450 300 10; #X obj 103 178 b2f; #X msg 103 83 0 1 2 3; #X text 77 53 [b2f] converts lists of 4 bytes to floats.; #X text 43 17 Assuming you received 4 bytes as a binary representation of a floating-point number \,; #X text 234 258 Martin Peach 2013_03_13; #X msg 181 83 208 15 73 64; #X floatatom 103 209 12 0 0 0 - - -; #X msg 269 83 219 15 73 64; #X connect 0 0 6 0; #X connect 1 0 0 0; #X connect 5 0 0 0; #X connect 7 0 0 0; mrpeach/serializer/sprint.c0000644000175000017500000000664113572277060016603 0ustar zmoelnigzmoelnig /* sprint started 20191205 by Martin Peach chakekatzil@gmail.com based on print from x_interface.c */ #include "m_pd.h" #include #include #include /* -------------------------- sprint ------------------------------ */ static t_class *sprint_class; typedef struct _sprint { t_object x_obj; t_symbol *x_sym; int x_separator; int x_len; // length of string in x_buf char x_buf[MAXPDSTRING]; } t_sprint; static void *sprint_new(t_symbol *sel, int argc, t_atom *argv) { int i; t_sprint *x = (t_sprint *)pd_new(sprint_class); if (argc == 0) { x->x_sym = gensym("sprint"); x->x_separator = -1; // = 'no separator' } else if (argc >= 1 && argv->a_type == A_SYMBOL) { t_symbol *s = atom_getsymbolarg(0, argc, argv); if (1 == strlen(s->s_name)) x->x_separator = s->s_name[0]; } else if (argc >= 1 && argv->a_type == A_FLOAT) { float f = argv->a_w.w_float; int i = f; if ((f == i) && (i >= 0) && (i < 256)) x->x_separator = i; // some 8-bit value } outlet_new(&x->x_obj, &s_float); x->x_len = 0; return (x); } /* sprint_drip outputs x_buf one character at a time as floats */ void sprint_drip(t_sprint *x) { int i; char c; float f; for (i = 0; i < x->x_len; ++i) { c = x->x_buf[i]; f = c; outlet_float(x->x_obj.ob_outlet, f); } } static void sprint_bang(t_sprint *x) { // bang redoes the output sprint_drip(x); } static void sprint_float(t_sprint *x, t_float f) { // single floats x->x_len = sprintf(x->x_buf, "%g", f); sprint_drip(x); } static void sprint_list(t_sprint *x, t_symbol *s, int argc, t_atom *argv) { // lists with float as first element int i; //post ("selector %s", s->s_name); if (strncmp(s->s_name, "list", 5)) x->x_len = sprintf(x->x_buf, "%s", s->s_name); else x->x_len = 0; for (i = 0; i < argc; ++i) { if ((x->x_len != 0)&&(x->x_separator != -1)) x->x_len += sprintf(x->x_buf+x->x_len, "%c", x->x_separator); if (argv[i].a_type == A_SYMBOL) { x->x_len += sprintf(x->x_buf+x->x_len, "%s", argv[i].a_w.w_symbol->s_name); } else if (argv[i].a_type == A_FLOAT) { x->x_len += sprintf(x->x_buf+x->x_len, "%g", argv[i].a_w.w_float); } } sprint_drip(x); } static void sprint_anything(t_sprint *x, t_symbol *s, int argc, t_atom *argv) { // here we get symbols and lists of symbols int i; //post ("selector %s", s->s_name); x->x_len = sprintf(x->x_buf, "%s", s->s_name); for (i = 0; i < argc; ++i) { if ((x->x_len != 0)&&(x->x_separator != -1)) x->x_len += sprintf(x->x_buf+x->x_len, "%c", x->x_separator); if (argv[i].a_type == A_SYMBOL) { x->x_len += sprintf(x->x_buf+x->x_len, "%s", argv[i].a_w.w_symbol->s_name); } else if (argv[i].a_type == A_FLOAT) { x->x_len += sprintf(x->x_buf+x->x_len, "%g", argv[i].a_w.w_float); } } sprint_drip(x); } void sprint_setup(void) { sprint_class = class_new(gensym("sprint"), (t_newmethod)sprint_new, 0, sizeof(t_sprint), 0, A_GIMME, 0); class_addbang(sprint_class, sprint_bang); class_addfloat(sprint_class, sprint_float); class_addlist(sprint_class, sprint_list); class_addanything(sprint_class, sprint_anything); } // fin sprint.c mrpeach/serializer/b2f.c0000644000175000017500000000363512430232701015716 0ustar zmoelnigzmoelnig/* b2f.c MP 20130313 */ /* Convert a list of 4 bytes to a Pd float */ #include "m_pd.h" #include typedef struct _b2f { t_object x_obj; t_outlet *x_out; } t_b2f; static t_class *b2f_class; void b2f_setup(void); static void *b2f_new(t_symbol *s, int argc, t_atom *argv); static void b2f_free(t_b2f *x); static void b2f_list(t_b2f *x, t_symbol *s, int argc, t_atom *argv); union fbuf { t_float f; unsigned char b[4]; }; static void b2f_list(t_b2f *x, t_symbol *s, int argc, t_atom *argv) { int i, d; union fbuf buf; //post("b2f_list: s is %s, argc is %d", s->s_name, argc); if (0 != strncmp("list", s->s_name, 4)) { post("b2f_list: not a list of floats"); return; } if (argc != 4) { post("b2f_list: need 4 floats"); return; } for (i = 0; i < 4; ++i) { if (argv[i].a_type != A_FLOAT) { post("b2f_list: list element %d is not a float", i); return; } d = argv[i].a_w.w_float; if (d != argv[i].a_w.w_float) { post("b2f_list: list element %d is not an integer", i); return; } if (d < 0 || d > 255) { post("b2f_list: list element %d is not an integer on [0..255]", i); return; } buf.b[i] = d; } outlet_float(x->x_out, buf.f); } static void b2f_free(t_b2f *x) { return; } static void *b2f_new(t_symbol *s, int argc, t_atom *argv) { t_b2f *x; x = (t_b2f *)pd_new(b2f_class); if (x == NULL) return (x); x->x_out = outlet_new((t_object *)x, &s_float); return (x); } void b2f_setup(void) { b2f_class = class_new(gensym("b2f"), (t_newmethod)b2f_new, (t_method)b2f_free, sizeof(t_b2f), 0, 0); /* no arguments */ class_addlist(b2f_class, b2f_list); } /* end b2f.c */ mrpeach/serializer/f2b.c0000644000175000017500000000233212430232701015707 0ustar zmoelnigzmoelnig/* f2b.c MP 20130313 */ /* Convert a Pd float to a list of 4 bytes */ #include "m_pd.h" #include typedef struct _f2b { t_object x_obj; t_outlet *x_out; } t_f2b; static t_class *f2b_class; void f2b_setup(void); static void *f2b_new(t_symbol *s, int argc, t_atom *argv); static void f2b_free(t_f2b *x); static void f2b_float(t_f2b *x, t_float f); union fbuf { t_float f; unsigned char b[4]; }; static void f2b_float(t_f2b *x, t_float f) { int i; union fbuf buf; t_atom outs[4]; //post("f2b_float: f is %f", f); buf.f = f; for (i = 0; i < 4; ++i) SETFLOAT(&outs[i], buf.b[i]); outlet_list(x->x_out, gensym("list"), 4, outs); } static void f2b_free(t_f2b *x) { return; } static void *f2b_new(t_symbol *s, int argc, t_atom *argv) { t_f2b *x; x = (t_f2b *)pd_new(f2b_class); if (x == NULL) return (x); x->x_out = outlet_new((t_object *)x, &s_float); return (x); } void f2b_setup(void) { f2b_class = class_new(gensym("f2b"), (t_newmethod)f2b_new, (t_method)f2b_free, sizeof(t_f2b), 0, 0); /* no arguments */ class_addfloat(f2b_class, f2b_float); } /* end f2b.c */ mrpeach/slipdec/0000755000175000017500000000000013605444731014361 5ustar zmoelnigzmoelnigmrpeach/slipdec/slipdec-help.pd0000644000175000017500000000532311533764433017264 0ustar zmoelnigzmoelnig#N canvas 1 53 901 442 10; #X obj 388 325 print decoded; #X msg 319 159 192 192 192 192 192; #X floatatom 339 182 5 0 0 0 - - -; #X obj 382 238 cnv 15 60 30 empty empty empty 20 12 0 14 -4034 -66577 0; #X text -57 298 The motivation behind SLIP is the need to determine the boundaries of a packet when it is received one byte at a time \, as with a serial channel. Bytes are integers between 0 and 255; #X msg 185 25 verbosity \$1; #X obj 185 6 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1 ; #X text -57 355 SLIP (RFC 1055) is a simple encoding that prefixes each packet with 192 \, and replaces 192s inside the packet with 219 followed by 220 Any 219 will be replaced with 219 and 221 The packet ends with 192; #X text 443 160 Null packets are invisible; #X obj 427 274 print valid; #X text -57 193 Note that the SLIP specification limits the maximum packet size to 1006...; #X obj 388 245 slipdec; #X text -57 221 ...but a float argument to slipdec or slipenc will set another maximum packet size; #X msg 229 69 192 \, 1.33 \, 192; #X text 335 45 This should give 1 192; #X text 321 69 Only bytes are permitted; #X msg 275 115 192 219 5 6 7 192; #X msg 253 93 1 43 5 6 7 192; #X text 348 92 Missing 192 at start is OK; #X text -58 139 [slipdec]; #X text 548 404 Author: Martin Peach \, 2010/10/01; #X msg 205 45 192 1 \, 219 \, 220 \, 192; #X msg 297 137 1 25 5 6 7; #X text -57 257 Input can be any combination of float and list of floats as long as they are integers on [0...255]; #X text 385 115 Bad escapes are invalid; #X text 368 136 Unterminated input will be accumulated until end is received; #X text 636 368 See also:; #X obj 695 370 slipenc; #X text -58 153 Decodes bytes from SLIP to raw. Useful for receiving OSC via [comport].; #X text 427 290 Right outlet is one whenever a valid packet is output \, zero if packet could not be decoded (bad packets are not output). ; #X text 389 341 Left outlet gives lists of decoded bytes whenever valid = 1; #X text 267 24 Verbosity might be useful if things don't seem to be working; #N canvas 500 267 494 344 META 0; #X text 12 155 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; #X text 12 25 LICENSE GPL v2 or later; #X text 12 135 AUTHOR Martin Peach; #X text 12 5 KEYWORDS control conversion; #X text 12 46 DESCRIPTION decode bytes from SLIP to raw. Useful for receiving OSC via [comport]; #X text 12 75 INLET_0 float list verbosity; #X text 12 95 OUTLET_0 anything; #X text 12 115 OUTLET_1 float; #X restore 775 403 pd META; #X connect 1 0 11 0; #X connect 2 0 11 0; #X connect 5 0 11 0; #X connect 6 0 5 0; #X connect 11 0 0 0; #X connect 11 1 9 0; #X connect 13 0 11 0; #X connect 16 0 11 0; #X connect 17 0 11 0; #X connect 21 0 11 0; #X connect 22 0 11 0; mrpeach/slipdec/slipdec.c0000644000175000017500000001710612454771160016155 0ustar zmoelnigzmoelnig/* slipdec.c 20100513 Martin Peach */ /* decode a list of SLIP-encoded bytes */ #include "m_pd.h" /* -------------------------- slipdec -------------------------- */ #ifndef _SLIPCODES /* SLIP special character codes */ #define SLIP_END 0300 /* decimal 192 indicates end of packet */ #define SLIP_ESC 0333 /* decimal 219 indicates byte stuffing */ #define SLIP_ESC_END 0334 /* decimal 220 SLIP_ESC_END means SLIP_END as data byte */ #define SLIP_ESC_ESC 0335 /* decimal 221 SLIP_ESC_ESC means SLIP_ESC as data byte */ #define MAX_SLIP 1006 /* maximum SLIP packet size */ #define _SLIPCODES #endif /* _SLIPCODES */ static t_class *slipdec_class; typedef struct _slipdec { t_object x_obj; t_outlet *x_slipdec_out; t_outlet *x_status_out; t_atom *x_slip_buf; int x_slip_length; int x_slip_max_length; int x_valid_SLIP; int x_esced; int x_verbose; } t_slipdec; static void *slipdec_new(t_symbol *s, int argc, t_atom *argv); static void slipdec_dump(t_slipdec *x, int dosend); static void slipdec_list(t_slipdec *x, t_symbol *s, int ac, t_atom *av); static void slipdec_float(t_slipdec *x, t_float f); static void slipdec_verbosity(t_slipdec *x, t_float f); static void slipdec_free(t_slipdec *x); void slipdec_setup(void); static void *slipdec_new(t_symbol *s, int argc, t_atom *argv) { int i; t_slipdec *x = (t_slipdec *)pd_new(slipdec_class); if (x == NULL) return x; x->x_slip_max_length = MAX_SLIP;// default unless a float argument is given for (i = 0; i < argc; ++i) { if (argv[i].a_type == A_FLOAT) { x->x_slip_max_length = atom_getfloat(&argv[i]); post("slipdec: maximum packet length is %d", x->x_slip_max_length); break; } } x->x_slip_buf = (t_atom *)getbytes(sizeof(t_atom)*x->x_slip_max_length); if(x->x_slip_buf == NULL) { error("slipdec: unable to allocate %lu bytes for x_slip_buf", (long)sizeof(t_atom)*x->x_slip_max_length); return NULL; } /* init the slip buf atoms to float type */ for (i = 0; i < x->x_slip_max_length; ++i) x->x_slip_buf[i].a_type = A_FLOAT; x->x_slipdec_out = outlet_new(&x->x_obj, &s_list); x->x_status_out = outlet_new(&x->x_obj, &s_anything); x->x_valid_SLIP = 1; return (x); } static void slipdec_dump(t_slipdec *x, int dosend) { outlet_float(x->x_status_out, x->x_valid_SLIP); if(dosend) { if ((0 != x->x_valid_SLIP) && (x->x_slip_length > 0)) outlet_list(x->x_slipdec_out, &s_list, x->x_slip_length, x->x_slip_buf); } x->x_slip_length = x->x_esced = 0; x->x_valid_SLIP = 1; } static void slipdec_list(t_slipdec *x, t_symbol *s, int ac, t_atom *av) { /* SLIP decode a list of bytes */ float f; int i, c; if (x->x_verbose) post ("slipdec_list: buffer length %d, esc = %d", x->x_slip_length, x->x_esced); /* x_slip_length will be non-zero if an incomplete packet is in the buffer */ if ((ac + x->x_slip_length) > x->x_slip_max_length) { pd_error (x, "slipdec_list: input packet longer than %d", x->x_slip_max_length); x->x_valid_SLIP = 0; /* not valid SLIP */ slipdec_dump(x,0);// reset return; } /* for each byte in the packet, send the appropriate character sequence */ for(i = 0; ((i < ac) && (x->x_slip_length < x->x_slip_max_length)); ++i) { /* check each atom for byteness */ f = atom_getfloat(&av[i]); c = (((int)f) & 0x0FF); if (c != f) { /* abort, input list needs to be fixed before this is gonna wuk */ pd_error (x, "slipdec: input %f out of range [0..255]", f); x->x_valid_SLIP = 0; /* not valid SLIP */ slipdec_dump(x,0);// reset return; } if(SLIP_END == c) { if (x->x_verbose) post ("slipdec_list: SLIP_END at %d", x->x_slip_length); /* If it's the beginning of a packet, ignore it */ if (x->x_slip_length) { if (x->x_verbose) post ("slipdec_list: end of packet"); /* send the packet */ slipdec_dump(x, 1); } continue; } if (SLIP_ESC == c) { if (x->x_verbose) post ("slipdec_list: SLIP_ESC %f = %d", f, c); x->x_esced = 1; continue; } if (1 == x->x_esced) { if (SLIP_ESC_END == c) c = SLIP_END; else if (SLIP_ESC_ESC == c) c = SLIP_ESC; else { pd_error (x, "slipdec_list: SLIP_ESC not followed by 220 or 221 (%d)", c); x->x_valid_SLIP = 0; /* not valid SLIP */ slipdec_dump(x,0);/* reset */ return; } x->x_esced = 0; } /* Add the character to the buffer */ if (x->x_verbose) post ("slipdec_list: adding character %d to buffer[%d]", c, x->x_slip_length); x->x_slip_buf[x->x_slip_length++].a_w.w_float = c; } } static void slipdec_float(t_slipdec *x, t_float f) { /* SLIP decode a byte */ int c; if (x->x_verbose) post ("slipdec_float: buffer length %d, esc = %d", x->x_slip_length, x->x_esced); /* for each byte in the packet, send the appropriate character sequence */ /* check each atom for byteness */ c = (((int)f) & 0x0FF); if (c != f) { /* abort, input list needs to be fixed before this is gonna wuk */ pd_error (x, "slipdec: input %f out of range [0..255]", f); x->x_valid_SLIP = 0; /* not valid SLIP */ slipdec_dump(x,0);/* reset */ return; } if(SLIP_END == c) { if (x->x_verbose) post ("slipdec_float: SLIP_END at %d", x->x_slip_length); /* If it's the beginning of a packet, ignore it */ if (0 == x->x_slip_length) return; /* send the packet */ else { if (x->x_verbose) post ("slipdec_float: end of packet"); slipdec_dump(x, 1); return; } } if (SLIP_ESC == c) { if (x->x_verbose) post ("slipdec_float: SLIP_ESC %f = %d", f, c); x->x_esced = 1; return; } if (1 == x->x_esced) { if (SLIP_ESC_END == c) c = SLIP_END; else if (SLIP_ESC_ESC == c) c = SLIP_ESC; else { x->x_valid_SLIP = 0; /* not valid SLIP */ slipdec_dump(x,0);/* reset */ pd_error (x, "slipdec_float: SLIP_ESC not followed by 220 or 221 (%d)", c); return; } if (x->x_verbose) post ("slipdec_float: ESCED %f = %d", f, c); x->x_esced = 0; } /* Add the character to the buffer */ if (x->x_slip_length < x->x_slip_max_length) { if (x->x_verbose) post ("slipdec_float: adding character %d to buffer[%d]", c, x->x_slip_length); x->x_slip_buf[x->x_slip_length++].a_w.w_float = c; } else { pd_error (x, "slipdec: input packet longer than %d", x->x_slip_length); x->x_valid_SLIP = 0; /* not valid SLIP */ slipdec_dump(x,0);/* reset */ } } static void slipdec_verbosity(t_slipdec *x, t_float f) { x->x_verbose = (0 != f)?1:0; } static void slipdec_free(t_slipdec *x) { if (x->x_slip_buf != NULL) freebytes((void *)x->x_slip_buf, sizeof(t_atom)*x->x_slip_max_length); } void slipdec_setup(void) { slipdec_class = class_new(gensym("slipdec"), (t_newmethod)slipdec_new, (t_method)slipdec_free, sizeof(t_slipdec), 0, A_GIMME, 0); class_addlist(slipdec_class, slipdec_list); class_addfloat(slipdec_class, slipdec_float); class_addmethod(slipdec_class, (t_method)slipdec_verbosity, gensym("verbosity"), A_FLOAT, 0); } /* fin slipdec.c */ mrpeach/binfile/0000755000175000017500000000000013605444731014346 5ustar zmoelnigzmoelnigmrpeach/binfile/binfile.c0000644000175000017500000003207612271525540016126 0ustar zmoelnigzmoelnig/* binfile.c An external for Pure Data that reads and writes binary files * Copyright (C) 2007-2014 Martin Peach * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * The latest version of this file can be found at: * http://pure-data.cvs.sourceforge.net/pure-data/externals/mrpeach/binfile/ * * martin.peach@sympatico.ca */ #include "m_pd.h" #include #include static t_class *binfile_class; #define ALLOC_BLOCK_SIZE 65536 /* number of bytes to add when resizing buffer */ #define PATH_BUF_SIZE 1024 /* maximumn length of a file path */ /* support older Pd versions without sys_open(), sys_fopen(), sys_fclose() */ #if PD_MAJOR_VERSION == 0 && PD_MINOR_VERSION < 44 #define sys_open open #define sys_fopen fopen #define sys_fclose fclose #endif typedef struct t_binfile { t_object x_obj; t_outlet *x_bin_outlet; t_outlet *x_info_outlet; t_outlet *x_bang_outlet; FILE *x_fP; t_symbol *x_our_directory; char x_fPath[PATH_BUF_SIZE]; char *x_buf; /* read/write buffer in memory for file contents */ size_t x_buf_length; /* current length of buf */ size_t x_length; /* current length of valid data in buf */ size_t x_rd_offset; /* current read offset into the buffer */ size_t x_wr_offset; /* current write offset into the buffer */ } t_binfile; static void binfile_rewind (t_binfile *x); static void binfile_free(t_binfile *x); static FILE *binfile_open_path(t_binfile *x, char *path, char *mode); static void binfile_read(t_binfile *x, t_symbol *path, t_float max_bytes); static void binfile_write(t_binfile *x, t_symbol *path); static void binfile_bang(t_binfile *x); static void binfile_float(t_binfile *x, t_float val); static void binfile_list(t_binfile *x, t_symbol *s, int argc, t_atom *argv); static void binfile_add(t_binfile *x, t_symbol *s, int argc, t_atom *argv); static void binfile_clear(t_binfile *x); static void binfile_info(t_binfile *x); static void binfile_set(t_binfile *x, t_symbol *s, int argc, t_atom *argv); static void binfile_set_read_index(t_binfile *x, t_float offset); static void binfile_set_write_index(t_binfile *x, t_float offset); static void *binfile_new(t_symbol *s, int argc, t_atom *argv); void binfile_setup(void); void binfile_setup(void) { binfile_class = class_new (gensym("binfile"), (t_newmethod) binfile_new, (t_method)binfile_free, sizeof(t_binfile), CLASS_DEFAULT, A_GIMME, 0); class_addbang(binfile_class, binfile_bang); class_addfloat(binfile_class, binfile_float); class_addlist(binfile_class, binfile_list); class_addmethod(binfile_class, (t_method)binfile_read, gensym("read"), A_DEFSYMBOL, A_DEFFLOAT, 0); class_addmethod(binfile_class, (t_method)binfile_write, gensym("write"), A_DEFSYMBOL, 0); class_addmethod(binfile_class, (t_method)binfile_add, gensym("add"), A_GIMME, 0); class_addmethod(binfile_class, (t_method)binfile_set, gensym("set"), A_GIMME, 0); class_addmethod(binfile_class, (t_method)binfile_set_read_index, gensym("readat"), A_DEFFLOAT, 0); class_addmethod(binfile_class, (t_method)binfile_set_write_index, gensym("writeat"), A_DEFFLOAT, 0); class_addmethod(binfile_class, (t_method)binfile_clear, gensym("clear"), 0); class_addmethod(binfile_class, (t_method)binfile_rewind, gensym("rewind"), 0); class_addmethod(binfile_class, (t_method)binfile_info, gensym("info"), 0); } static void *binfile_new(t_symbol *s, int argc, t_atom *argv) { t_binfile *x = (t_binfile *)pd_new(binfile_class); t_symbol *pathSymbol; int i; if (x == NULL) { error("binfile: Could not create..."); return x; } x->x_fP = NULL; x->x_fPath[0] = '\0'; x->x_our_directory = canvas_getcurrentdir();/* get the current directory to use as the base for relative file paths */ x->x_rd_offset = x->x_wr_offset = x->x_length = 0L; x->x_buf_length = 0;//ALLOC_BLOCK_SIZE; /* find the first string in the arg list and interpret it as a path to a file */ /* find the first float in the arg list and interpret it as the size of the buffer */ for (i = 0; i < argc; ++i) { if (argv[i].a_type == A_FLOAT) { x->x_buf_length = atom_getfloat(&argv[i]); break; // take the first number } } for (i = 0; i < argc; ++i) { if (argv[i].a_type == A_SYMBOL) { pathSymbol = atom_getsymbol(&argv[i]); if (pathSymbol != NULL) binfile_read(x, pathSymbol, x->x_buf_length); break; // only try one path } } if ((x->x_buf = getbytes(x->x_buf_length)) == NULL) error ("binfile: Unable to allocate %lu bytes for buffer", x->x_buf_length); x->x_bin_outlet = outlet_new(&x->x_obj, gensym("float")); x->x_info_outlet = outlet_new(&x->x_obj, gensym("list")); x->x_bang_outlet = outlet_new(&x->x_obj, gensym("bang")); /* bang at end of file */ return (void *)x; } static void binfile_free(t_binfile *x) { if (x->x_buf != NULL) freebytes(x->x_buf, x->x_buf_length); x->x_buf = NULL; x->x_buf_length = 0L; } static FILE *binfile_open_path(t_binfile *x, char *path, char *mode) /* path is a string. Up to PATH_BUF_SIZE-1 characters will be copied into x->x_fPath. */ /* mode should be "rb" or "wb" */ /* x->x_fPath will be used as a file name to open. */ /* binfile_open_path attempts to open the file for binary mode reading. */ /* Returns FILE pointer if successful, else 0. */ { FILE *fP = NULL; char tryPath[PATH_BUF_SIZE]; char slash[] = "/"; /* If the first character of the path is a slash then the path is absolute */ /* On MSW if the second character of the path is a colon then the path is absolute */ if ((path[0] == '/') || (path[0] == '\\') || (path[1] == ':')) { strncpy(tryPath, path, PATH_BUF_SIZE-1); /* copy path into a length-limited buffer */ /* ...if it doesn't work we won't mess up x->fPath */ tryPath[PATH_BUF_SIZE-1] = '\0'; /* just make sure there is a null termination */ fP = sys_fopen(tryPath, mode); } if (fP == NULL) { /* Then try to open the path from the current directory */ strncpy(tryPath, x->x_our_directory->s_name, PATH_BUF_SIZE-1); /* copy directory into a length-limited buffer */ strncat(tryPath, slash, PATH_BUF_SIZE-1); /* append path to a length-limited buffer */ strncat(tryPath, path, PATH_BUF_SIZE-1); /* append path to a length-limited buffer */ /* ...if it doesn't work we won't mess up x->fPath */ tryPath[PATH_BUF_SIZE-1] = '\0'; /* make sure there is a null termination */ fP = sys_fopen(tryPath, mode); } if (fP != NULL) strncpy(x->x_fPath, tryPath, PATH_BUF_SIZE); else x->x_fPath[0] = '\0'; return fP; } static void binfile_write(t_binfile *x, t_symbol *path) /* open the file for writing and write the entire buffer to it, then close it */ { size_t bytes_written = 0L; if (0==(x->x_fP = binfile_open_path(x, path->s_name, "wb"))) error("binfile: Unable to open %s for writing", path->s_name); bytes_written = fwrite(x->x_buf, 1L, x->x_length, x->x_fP); if (bytes_written != x->x_length) post("binfile: %ld bytes written != %ld", bytes_written, x->x_length); else post("binfile: wrote %ld bytes to %s", bytes_written, path->s_name); sys_fclose(x->x_fP); x->x_fP = NULL; } static void binfile_read(t_binfile *x, t_symbol *path, t_float max_bytes) /* open the file for reading and load it into the buffer, then close it */ /* if max_bytes > 0 read only max_bytes into the buffer */ { size_t file_length = 0L; size_t bytes_read = 0L; if (0==(x->x_fP = binfile_open_path(x, path->s_name, "rb"))) { error("binfile: Unable to open %s for reading", path->s_name); return; } /* get length of file up to max_bytes */ if (max_bytes > 0) while ((EOF != getc(x->x_fP))&&(file_length < max_bytes)) ++file_length; else while (EOF != getc(x->x_fP)) ++file_length; if (file_length == 0L) return; /* get storage for file contents */ if (0 != x->x_buf) freebytes(x->x_buf, x->x_buf_length); x->x_buf = getbytes(file_length); if (NULL == x->x_buf) { x->x_buf_length = 0L; error ("binfile: unable to allocate %ld bytes for %s", file_length, path->s_name); return; } x->x_rd_offset = 0L; /* read file into buf */ rewind(x->x_fP); bytes_read = fread(x->x_buf, 1L, file_length, x->x_fP); x->x_buf_length = bytes_read; x->x_wr_offset = x->x_buf_length; /* write new data at end of file */ x->x_length = x->x_buf_length; /* file length is same as buffer size 7*/ x->x_rd_offset = 0L; /* read from start of file */ sys_fclose (x->x_fP); x->x_fP = NULL; if (bytes_read != file_length) post("binfile length %ld not equal to bytes read (%ld)", file_length, bytes_read); else post("binfle: read %ld bytes from %s", bytes_read, path->s_name); } static void binfile_bang(t_binfile *x) /* get the next byte in the file and send it out x_bin_list_outlet */ { unsigned char c; if (x->x_rd_offset < x->x_length) { c = x->x_buf[x->x_rd_offset++]; outlet_float(x->x_bin_outlet, (float)c); } else outlet_bang(x->x_bang_outlet); } /* The arguments of the ``list''-method * a pointer to the class-dataspace * a pointer to the selector-symbol (always &s_list) * the number of atoms and a pointer to the list of atoms: */ static void binfile_add(t_binfile *x, t_symbol *s, int argc, t_atom *argv) /* add a list of bytes to the buffer */ { int i, j; float f; for (i = 0; i < argc; ++i) { if (A_FLOAT == argv[i].a_type) { j = atom_getint(&argv[i]); f = atom_getfloat(&argv[i]); if (j < -128 || j > 255) { error("binfile: input (%d) out of range [0..255]", j); return; } if (j != f) { error("binfile: input (%f) not an integer", f); return; } if (x->x_buf_length <= x->x_wr_offset) { x->x_buf = resizebytes(x->x_buf, x->x_buf_length, x->x_buf_length+ALLOC_BLOCK_SIZE); if (x->x_buf == NULL) { error("binfile: unable to resize buffer"); return; } x->x_buf_length += ALLOC_BLOCK_SIZE; } x->x_buf[x->x_wr_offset++] = j; if (x->x_length < x->x_wr_offset) x->x_length = x->x_wr_offset; } else { error("binfile: input %d not a float", i); return; } } } static void binfile_list(t_binfile *x, t_symbol *s, int argc, t_atom *argv) { binfile_add(x, s, argc, argv); } static void binfile_set(t_binfile *x, t_symbol *s, int argc, t_atom *argv) /* clear then add a list of bytes to the buffer */ { binfile_clear(x); binfile_add(x, s, argc, argv); } static void binfile_set_read_index(t_binfile *x, t_float offset) /* set the read offset, always < length */ { size_t intoffset = offset; if (intoffset < x->x_length) x->x_rd_offset = intoffset; else if (x->x_length > 0) x->x_rd_offset = x->x_length-1; else x->x_rd_offset = 0L; } static void binfile_set_write_index(t_binfile *x, t_float offset) /* set the write offset, always <= length */ { size_t intoffset = offset; if (intoffset <= x->x_length) x->x_wr_offset = intoffset; else x->x_wr_offset = x->x_length; } static void binfile_clear(t_binfile *x) { x->x_wr_offset = 0L; x->x_rd_offset = 0L; x->x_length = 0L; } static void binfile_float(t_binfile *x, t_float val) /* add a single byte to the file */ { t_atom a; SETFLOAT(&a, val); binfile_add(x, gensym("float"), 1, &a); } static void binfile_rewind (t_binfile *x) { x->x_rd_offset = 0L; } static void binfile_info(t_binfile *x) { t_atom *output_atom = getbytes(sizeof(t_atom)); SETFLOAT(output_atom, x->x_buf_length); outlet_anything( x->x_info_outlet, gensym("buflength"), 1, output_atom); SETFLOAT(output_atom, x->x_length); outlet_anything( x->x_info_outlet, gensym("length"), 1, output_atom); SETFLOAT(output_atom, x->x_rd_offset); outlet_anything( x->x_info_outlet, gensym("readoffset"), 1, output_atom); SETFLOAT(output_atom, x->x_wr_offset); outlet_anything( x->x_info_outlet, gensym("writeoffset"), 1, output_atom); freebytes(output_atom,sizeof(t_atom)); } /* fin binfile.c */ mrpeach/binfile/binfile-help.pd0000644000175000017500000000722512271525540017233 0ustar zmoelnigzmoelnig#N canvas 237 152 1080 699 12; #X msg 103 98 rewind; #X obj 267 577 textfile; #X msg 80 75 bang; #X msg 179 174 clear; #X msg 282 277 set 2 4 6 8; #X obj 181 -89 binfile; #X text 246 -90 read and write binary files; #X msg 202 197 add 10 20 255; #X obj 410 425 binfile; #X text 344 576 to read and write text files; #X msg 305 300 write afile.bin; #X text 534 449 This outlet gives a bang when you hit the end of the sequence.; #X text 481 539 This outlet gives the bytes in sequence \, or bangs if no more bytes.; #X text 370 275 clear the buffer and then add some bytes; #X text 224 173 empty the buffer; #X text 155 98 set the read pointer to the beginnning of the buffer ; #X text 119 75 output one byte from the buffer as a float; #X text 422 298 write the entire buffer to a file; #X obj 410 545 print one; #X obj 35 60 bng 15 250 50 0 empty empty empty 17 7 0 10 -4034 -257985 -1; #X text 266 559 See also:; #X obj 57 -13 openpanel; #X obj 57 -37 bng 15 250 50 0 empty empty read_any_file_into_buffer 17 7 0 10 -4032 -258113 -1; #X msg 57 52 read \$1; #X obj 39 354 bng 15 250 50 0 empty empty save_buffer_as_any_file 17 7 0 10 -4032 -258113 -1; #X msg 397 392 write \$1; #X obj 400 369 savepanel; #X msg 237 232 77 128 129 130; #X text 254 -50 The binfile object reads and writes binary files to and from a buffer in memory. You can read a file and output its contents one byte at a time as floats.; #X text 442 46 To add bytes to the buffer \, first send "clear" to empty the buffer and then "add" to add bytes. Finally \, "write" will save the entire buffer as a binary file.; #X floatatom 259 255 5 0 0 0 - - -; #X text 299 253 add one byte \, same as "add"; #X text 349 231 add a list of bytes \, same as "add"; #X msg 15 10 info; #X obj 433 515 print info; #X obj 466 455 print end; #X msg 328 323 readat 3; #X msg 351 346 writeat 3; #X text 425 346 set the write position; #X text 395 323 set the read position; #X text 512 509 This outlet gives a list of current parameters from the info message.; #X text 303 197 add a list of byte-floats to the buffer at the current write offset; #X text 65 10 output current buffer length and pointer values through the middle outlet.; #X text 233 121 read a file into the buffer and make it the new buffer ; #X obj 456 493 tgl 15 0 empty empty empty 17 7 0 10 -258113 -257985 -1 0 1; #N canvas 507 310 494 344 META 0; #X text 12 175 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; #X text 12 25 LICENSE GPL v2 or later; #X text 12 5 KEYWORDS control filesystem; #X text 12 45 DESCRIPTION read and write binary files; #X text 12 65 INLET_0 float bang list info read rewind clear add set write readat writeat symbol; #X text 12 95 OUTLET_0 float bang; #X text 12 115 OUTLET_1 list; #X text 12 135 OUTLET_2 bang; #X text 12 155 AUTHOR Martin Peach; #X restore 882 607 pd META; #X text 525 363 You can also use this object simply for storing heterogeneous sequences of bytes.; #X text 481 404 Optional arguments for filename and length to be read (same as [read( message; #X msg 151 146 read test.txt 5; #X msg 126 121 read test.txt; #X text 267 145 read the first 5 bytes of a file into the buffer; #X text 760 580 Martin Peach 2014/01/27; #X connect 0 0 8 0; #X connect 2 0 8 0; #X connect 3 0 8 0; #X connect 4 0 8 0; #X connect 7 0 8 0; #X connect 8 0 18 0; #X connect 8 1 34 0; #X connect 8 2 35 0; #X connect 8 2 44 0; #X connect 10 0 8 0; #X connect 19 0 2 0; #X connect 21 0 23 0; #X connect 22 0 21 0; #X connect 23 0 8 0; #X connect 24 0 26 0; #X connect 25 0 8 0; #X connect 26 0 25 0; #X connect 27 0 8 0; #X connect 30 0 8 0; #X connect 33 0 8 0; #X connect 36 0 8 0; #X connect 37 0 8 0; #X connect 48 0 8 0; #X connect 49 0 8 0; mrpeach/Makefile0000644000175000017500000004013412571126663014402 0ustar zmoelnigzmoelnig## based on Pd library template version 1.0.14 ## (with some modifications to allow for sources/helppatches in subdirectories) LIBRARY_NAME = mrpeach # add your .c source files, one object per file, to the SOURCES # variable, help files will be included automatically, and for GUI # objects, the matching .tcl file too SOURCES = \ f2b.c b2f.c \ slipdec.c slipenc.c \ packxbee.c unpackxbee.c \ binfile.c \ midifile.c \ life2x.c \ op~.c \ rc~.c \ rcosc~.c \ rojo~.c \ runningmean.c \ sqosc~.c \ str.c \ tab2flist.c \ tabfind.c \ flist2tab.c \ which.c ## where to find the source files (and help-patches) VPATH=binfile:flist2tab:life2x:midifile:op~:rc~:rcosc~:rojo~:runningmean:serializer:slipdec:slipenc:sqosc~:str:tab2flist:tabfind:which:xbee # list all pd objects (i.e. myobject.pd) files here, and their helpfiles will # be included automatically PDOBJECTS = # example patches and related files, in the 'examples' subfolder EXAMPLES = # manuals and related files, in the 'manual' subfolder MANUAL = # if you want to include any other files in the source and binary tarballs, # list them here. This can be anything from header files, test patches, # documentation, etc. README.txt and LICENSE.txt are required and therefore # automatically included EXTRA_DIST = pdxbee.h # unit tests and related files here, in the 'unittests' subfolder UNITTESTS = #------------------------------------------------------------------------------# # # things you might need to edit if you are using other C libraries # #------------------------------------------------------------------------------# ALL_CFLAGS = -I"$(PD_INCLUDE)" ALL_LDFLAGS = SHARED_LDFLAGS = ALL_LIBS = #------------------------------------------------------------------------------# # # you shouldn't need to edit anything below here, if we did it right :) # #------------------------------------------------------------------------------# # these can be set from outside without (usually) breaking the build CFLAGS = -Wall -W -g LDFLAGS = LIBS = # get library version from meta file LIBRARY_VERSION = $(shell sed -n 's|^\#X text [0-9][0-9]* [0-9][0-9]* VERSION \(.*\);|\1|p' $(LIBRARY_NAME)-meta.pd) ALL_CFLAGS += -DPD -DVERSION='"$(LIBRARY_VERSION)"' PD_INCLUDE = $(PD_PATH)/include/pd # where to install the library, overridden below depending on platform prefix = /usr/local libdir = $(prefix)/lib pkglibdir = $(libdir)/pd-externals objectsdir = $(pkglibdir) INSTALL = install INSTALL_PROGRAM = $(INSTALL) -p -m 644 INSTALL_DATA = $(INSTALL) -p -m 644 INSTALL_DIR = $(INSTALL) -p -m 755 -d ALLSOURCES := $(SOURCES) $(SOURCES_android) $(SOURCES_cygwin) $(SOURCES_macosx) \ $(SOURCES_iphoneos) $(SOURCES_linux) $(SOURCES_windows) DISTDIR=$(LIBRARY_NAME)-$(LIBRARY_VERSION) ORIGDIR=pd-$(LIBRARY_NAME:~=)_$(LIBRARY_VERSION) UNAME := $(shell uname -s) ifeq ($(UNAME),Darwin) CPU := $(shell uname -p) ifeq ($(CPU),arm) # iPhone/iPod Touch SOURCES += $(SOURCES_iphoneos) EXTENSION = pd_darwin SHARED_EXTENSION = dylib OS = iphoneos PD_PATH = /Applications/Pd-extended.app/Contents/Resources IPHONE_BASE=/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin CC=$(IPHONE_BASE)/gcc CPP=$(IPHONE_BASE)/cpp CXX=$(IPHONE_BASE)/g++ ISYSROOT = -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.0.sdk IPHONE_CFLAGS = -miphoneos-version-min=3.0 $(ISYSROOT) -arch armv6 OPT_CFLAGS = -fast -funroll-loops -fomit-frame-pointer ALL_CFLAGS := $(IPHONE_CFLAGS) $(ALL_CFLAGS) ALL_LDFLAGS += -arch armv6 -bundle -undefined dynamic_lookup $(ISYSROOT) SHARED_LDFLAGS += -arch armv6 -dynamiclib -undefined dynamic_lookup $(ISYSROOT) ALL_LIBS += -lc $(LIBS_iphoneos) STRIP = strip -x DISTBINDIR=$(DISTDIR)-$(OS) else # Mac OS X SOURCES += $(SOURCES_macosx) EXTENSION = pd_darwin SHARED_EXTENSION = dylib OS = macosx PD_PATH = /Applications/Pd-extended.app/Contents/Resources OPT_CFLAGS = -ftree-vectorize -ftree-vectorizer-verbose=2 -fast # build universal 32-bit on 10.4 and 32/64 on newer ifeq ($(shell uname -r | sed 's|\([0-9][0-9]*\)\.[0-9][0-9]*\.[0-9][0-9]*|\1|'), 8) FAT_FLAGS = -arch ppc -arch i386 -mmacosx-version-min=10.4 else SOURCES += $(SOURCES_iphoneos) # Starting with Xcode 4.0, the PowerPC compiler is not installed by default ifeq ($(wildcard /usr/llvm-gcc-4.2/libexec/gcc/powerpc*), ) FAT_FLAGS = -arch i386 -arch x86_64 -mmacosx-version-min=10.5 else FAT_FLAGS = -arch ppc -arch i386 -arch x86_64 -mmacosx-version-min=10.4 endif endif ALL_CFLAGS += $(FAT_FLAGS) -fPIC -I/sw/include # if the 'pd' binary exists, check the linking against it to aid with stripping BUNDLE_LOADER = $(shell test ! -e $(PD_PATH)/bin/pd || echo -bundle_loader $(PD_PATH)/bin/pd) ALL_LDFLAGS += $(FAT_FLAGS) -headerpad_max_install_names -bundle $(BUNDLE_LOADER) \ -undefined dynamic_lookup -L/sw/lib SHARED_LDFLAGS += $(FAT_FLAGS) -dynamiclib -undefined dynamic_lookup \ -install_name @loader_path/$(SHARED_LIB) -compatibility_version 1 -current_version 1.0 ALL_LIBS += -lc $(LIBS_macosx) STRIP = strip -x DISTBINDIR=$(DISTDIR)-$(OS) # install into ~/Library/Pd on Mac OS X since /usr/local isn't used much pkglibdir=$(HOME)/Library/Pd endif endif # Tho Android uses Linux, we use this fake uname to provide an easy way to # setup all this things needed to cross-compile for Android using the NDK ifeq ($(UNAME),ANDROID) CPU := arm SOURCES += $(SOURCES_android) EXTENSION = so SHARED_EXTENSION = so OS = android PD_PATH = /usr NDK_BASE := /opt/android-ndk NDK_PLATFORM_LEVEL ?= 5 NDK_ABI=arm NDK_COMPILER_VERSION = 4.6 NDK_SYSROOT=$(NDK_BASE)/platforms/android-$(NDK_PLATFORM_LEVEL)/arch-$(NDK_ABI) NDK_UNAME:=$(shell uname -s | tr '[A-Z]' '[a-z]') ifeq ($(NDK_ABI),x86) HOST = i686-linux-android NDK_TOOLCHAIN = $(NDK_ABI)-$(NDK_COMPILER_VERSION) else HOST = $(NDK_ABI)-linux-androideabi NDK_TOOLCHAIN = $(HOST)-$(NDK_COMPILER_VERSION) endif NDK_TOOLCHAIN_BASE=$(NDK_BASE)/toolchains/$(NDK_TOOLCHAIN)/prebuilt/$(NDK_UNAME)-$(NDK_PROCESSOR) CC := $(NDK_TOOLCHAIN_BASE)/bin/$(HOST)-gcc --sysroot=$(NDK_SYSROOT) LD := $(NDK_TOOLCHAIN_BASE)/bin/$(HOST)-ld OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer CFLAGS += LDFLAGS += -rdynamic -shared SHARED_LDFLAGS += -Wl,-soname,$(SHARED_LIB) -shared LIBS += -lc $(LIBS_android) STRIP := $(NDK_TOOLCHAIN_BASE)/bin/$(HOST)-strip) \ --strip-unneeded -R .note -R .comment DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m) endif ifeq ($(UNAME),Linux) CPU := $(shell uname -m) SOURCES += $(SOURCES_linux) EXTENSION = pd_linux SHARED_EXTENSION = so OS = linux PD_PATH = /usr OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer ALL_CFLAGS += -fPIC ALL_LDFLAGS += -rdynamic -shared -fPIC -Wl,-rpath,"\$$ORIGIN",--enable-new-dtags SHARED_LDFLAGS += -Wl,-soname,$(SHARED_LIB) -shared ALL_LIBS += -lc $(LIBS_linux) STRIP = strip --strip-unneeded -R .note -R .comment DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m) endif ifeq ($(UNAME),GNU) # GNU/Hurd, should work like GNU/Linux for basically all externals CPU := $(shell uname -m) SOURCES += $(SOURCES_linux) EXTENSION = pd_linux SHARED_EXTENSION = so OS = linux PD_PATH = /usr OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer ALL_CFLAGS += -fPIC ALL_LDFLAGS += -rdynamic -shared -fPIC -Wl,-rpath,"\$$ORIGIN",--enable-new-dtags SHARED_LDFLAGS += -shared -Wl,-soname,$(SHARED_LIB) ALL_LIBS += -lc $(LIBS_linux) STRIP = strip --strip-unneeded -R .note -R .comment DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m) endif ifeq ($(UNAME),GNU/kFreeBSD) # Debian GNU/kFreeBSD, should work like GNU/Linux for basically all externals CPU := $(shell uname -m) SOURCES += $(SOURCES_linux) EXTENSION = pd_linux SHARED_EXTENSION = so OS = linux PD_PATH = /usr OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer ALL_CFLAGS += -fPIC ALL_LDFLAGS += -rdynamic -shared -fPIC -Wl,-rpath,"\$$ORIGIN",--enable-new-dtags SHARED_LDFLAGS += -shared -Wl,-soname,$(SHARED_LIB) ALL_LIBS += -lc $(LIBS_linux) STRIP = strip --strip-unneeded -R .note -R .comment DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m) endif ifeq (CYGWIN,$(findstring CYGWIN,$(UNAME))) CPU := $(shell uname -m) SOURCES += $(SOURCES_cygwin) EXTENSION = dll SHARED_EXTENSION = dll OS = cygwin PD_PATH = $(shell cygpath $$PROGRAMFILES)/pd OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer ALL_CFLAGS += ALL_LDFLAGS += -rdynamic -shared -L"$(PD_PATH)/src" -L"$(PD_PATH)/bin" SHARED_LDFLAGS += -shared -Wl,-soname,$(SHARED_LIB) ALL_LIBS += -lc -lpd $(LIBS_cygwin) STRIP = strip --strip-unneeded -R .note -R .comment DISTBINDIR=$(DISTDIR)-$(OS) endif ifeq (MINGW,$(findstring MINGW,$(UNAME))) CPU := $(shell uname -m) SOURCES += $(SOURCES_windows) EXTENSION = dll SHARED_EXTENSION = dll OS = windows PD_PATH = $(shell cd "$$PROGRAMFILES/pd" && pwd) # MinGW doesn't seem to include cc so force gcc CC=gcc OPT_CFLAGS = -O3 -funroll-loops -fomit-frame-pointer ALL_CFLAGS += -mms-bitfields ALL_LDFLAGS += -s -shared -Wl,--enable-auto-import SHARED_LDFLAGS += -shared ALL_LIBS += -L"$(PD_PATH)/src" -L"$(PD_PATH)/bin" -L"$(PD_PATH)/obj" \ -lpd -lwsock32 -lkernel32 -luser32 -lgdi32 -liberty $(LIBS_windows) STRIP = strip --strip-unneeded -R .note -R .comment DISTBINDIR=$(DISTDIR)-$(OS) endif # in case somebody manually set the HELPPATCHES above HELPPATCHES ?= $(SOURCES:.c=-help.pd) $(PDOBJECTS:.pd=-help.pd) ALL_CFLAGS := $(ALL_CFLAGS) $(CFLAGS) $(OPT_CFLAGS) ALL_LDFLAGS := $(LDFLAGS) $(ALL_LDFLAGS) ALL_LIBS := $(LIBS) $(ALL_LIBS) SHARED_SOURCE ?= $(wildcard lib$(LIBRARY_NAME).c) SHARED_HEADER ?= $(shell test ! -e $(LIBRARY_NAME).h || echo $(LIBRARY_NAME).h) SHARED_LIB ?= $(SHARED_SOURCE:.c=.$(SHARED_EXTENSION)) SHARED_TCL_LIB = $(wildcard lib$(LIBRARY_NAME).tcl) .PHONY = install libdir_install single_install install-objects install-libobject install-doc install-examples install-manual install-unittests clean distclean dist etags $(LIBRARY_NAME) all: $(SOURCES:.c=.$(EXTENSION)) $(SHARED_LIB) %.o: %.c $(CC) $(ALL_CFLAGS) -o $@ -c $< %.$(EXTENSION): %.o $(SHARED_LIB) $(CC) $(ALL_LDFLAGS) -o $@ $^ $(ALL_LIBS) chmod a-x $@ # this links everything into a single binary file $(LIBRARY_NAME): $(SOURCES:.c=.o) $(LIBRARY_NAME).o lib$(LIBRARY_NAME).o $(CC) $(ALL_LDFLAGS) -o $(LIBRARY_NAME).$(EXTENSION) $(SOURCES:.c=.o) \ $(LIBRARY_NAME).o lib$(LIBRARY_NAME).o $(ALL_LIBS) chmod a-x $(LIBRARY_NAME).$(EXTENSION) $(SHARED_LIB): $(SHARED_SOURCE:.c=.o) $(CC) $(SHARED_LDFLAGS) -o $(SHARED_LIB) $(SHARED_SOURCE:.c=.o) $(ALL_LIBS) install: libdir_install # The meta and help files are explicitly installed to make sure they are # actually there. Those files are not optional, then need to be there. install-objects: $(SOURCES:.c=.$(EXTENSION)) $(SHARED_LIB) $(PDOBJECTS) $(SHARED_TCL_LIB) $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) $(INSTALL_DATA) $(LIBRARY_NAME)-meta.pd \ $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) $(INSTALL_DATA) $^ $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) test -z "$(strip $(wildcard $(SOURCES:.c=.tcl)))" || \ $(INSTALL_DATA) $(wildcard $(SOURCES:.c=.tcl)) \ $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) libdir_install: install-objects install-doc install-examples install-manual install-unittests # install library linked as single binary install-libobject: $(LIBRARY_NAME).$(EXTENSION) $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) $(INSTALL_PROGRAM) $@ $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) $(STRIP) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/$@ single_install: install-libobject install-doc install-examples install-manual install-unittests install-doc: $(HELPPATCHES) $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) $(INSTALL_DATA) $^ $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) $(INSTALL_DATA) README.txt $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/README.txt $(INSTALL_DATA) LICENSE.txt $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/LICENSE.txt install-examples: test -z "$(strip $(EXAMPLES))" || \ $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/examples && \ for file in $(EXAMPLES); do \ $(INSTALL_DATA) examples/$$file $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/examples; \ done install-manual: test -z "$(strip $(MANUAL))" || \ $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/manual && \ for file in $(MANUAL); do \ $(INSTALL_DATA) manual/$$file $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/manual; \ done install-unittests: test -z "$(strip $(UNITTESTS))" || \ $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/unittests && \ for file in $(UNITTESTS); do \ $(INSTALL_DATA) unittests/$$file $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/unittests; \ done clean: -rm -f -- $(SOURCES:.c=.o) $(SOURCES_LIB:.c=.o) $(SHARED_SOURCE:.c=.o) -rm -f -- $(SOURCES:.c=.$(EXTENSION)) -rm -f -- $(LIBRARY_NAME).o -rm -f -- $(LIBRARY_NAME).$(EXTENSION) -rm -f -- $(SHARED_LIB) distclean: clean -rm -f -- $(DISTBINDIR).tar.gz -rm -rf -- $(DISTBINDIR) -rm -f -- $(DISTDIR).tar.gz -rm -rf -- $(DISTDIR) -rm -f -- $(ORIGDIR).tar.gz -rm -rf -- $(ORIGDIR) $(DISTBINDIR): $(INSTALL_DIR) $(DISTBINDIR) libdir: all $(DISTBINDIR) $(INSTALL_DATA) $(LIBRARY_NAME)-meta.pd $(DISTBINDIR) $(INSTALL_DATA) $(SOURCES) $(SHARED_SOURCE) $(SHARED_HEADER) $(DISTBINDIR) $(INSTALL_DATA) $(HELPPATCHES) $(DISTBINDIR) test -z "$(strip $(EXTRA_DIST))" || \ $(INSTALL_DATA) $(EXTRA_DIST) $(DISTBINDIR) # tar --exclude-vcs -czpf $(DISTBINDIR).tar.gz $(DISTBINDIR) $(DISTDIR): $(INSTALL_DIR) $(DISTDIR) $(ORIGDIR): $(INSTALL_DIR) $(ORIGDIR) dist: $(ALLSOURCES) $(HELPPATCHES) $(EXTRA_DIST) $(SHARED_HEADER) $(SHARED_SOURCE) $(SHARED_TCL_LIB) $(PDOBJECTS) $(INSTALL_DIR) $(DISTDIR) $(INSTALL_DATA) Makefile $(DISTDIR) $(INSTALL_DATA) README.txt $(DISTDIR) $(INSTALL_DATA) LICENSE.txt $(DISTDIR) $(INSTALL_DATA) $(LIBRARY_NAME)-meta.pd $(DISTDIR) test -z "$(strip $^)" || \ $(INSTALL_DATA) $^ $(DISTDIR) test -z "$(strip $(wildcard $(ALLSOURCES:.c=.tcl)))" || \ $(INSTALL_DATA) $(wildcard $(ALLSOURCES:.c=.tcl)) $(DISTDIR) test -z "$(strip $(wildcard $(LIBRARY_NAME).c))" || \ $(INSTALL_DATA) $(LIBRARY_NAME).c $(DISTDIR) test -z "$(strip $(EXAMPLES))" || \ $(INSTALL_DIR) $(DISTDIR)/examples && \ for file in $(EXAMPLES); do \ $(INSTALL_DATA) examples/$$file $(DISTDIR)/examples; \ done test -z "$(strip $(MANUAL))" || \ $(INSTALL_DIR) $(DISTDIR)/manual && \ for file in $(MANUAL); do \ $(INSTALL_DATA) manual/$$file $(DISTDIR)/manual; \ done test -z "$(strip $(UNITTESTS))" || \ $(INSTALL_DIR) $(DISTDIR)/unittests && \ for file in $(UNITTESTS); do \ $(INSTALL_DATA) unittests/$$file $(DISTDIR)/unittests; \ done tar --exclude-vcs -czpf $(DISTDIR).tar.gz $(DISTDIR) # make a Debian source package dpkg-source: debclean make distclean dist mv $(DISTDIR) $(ORIGDIR) tar --exclude-vcs -czpf ../$(ORIGDIR).orig.tar.gz $(ORIGDIR) rm -f -- $(DISTDIR).tar.gz rm -rf -- $(DISTDIR) $(ORIGDIR) cd .. && dpkg-source -b $(LIBRARY_NAME) etags: TAGS TAGS: $(wildcard $(PD_INCLUDE)/*.h) $(SOURCES) $(SHARED_SOURCE) $(SHARED_HEADER) etags $(wildcard $(PD_INCLUDE)/*.h) etags -a *.h $(SOURCES) $(SHARED_SOURCE) $(SHARED_HEADER) etags -a --language=none --regex="/proc[ \t]+\([^ \t]+\)/\1/" *.tcl showsetup: @echo "CC: $(CC)" @echo "CFLAGS: $(CFLAGS)" @echo "LDFLAGS: $(LDFLAGS)" @echo "LIBS: $(LIBS)" @echo "ALL_CFLAGS: $(ALL_CFLAGS)" @echo "ALL_LDFLAGS: $(ALL_LDFLAGS)" @echo "ALL_LIBS: $(ALL_LIBS)" @echo "PD_INCLUDE: $(PD_INCLUDE)" @echo "PD_PATH: $(PD_PATH)" @echo "objectsdir: $(objectsdir)" @echo "LIBRARY_NAME: $(LIBRARY_NAME)" @echo "LIBRARY_VERSION: $(LIBRARY_VERSION)" @echo "SOURCES: $(SOURCES)" @echo "SHARED_HEADER: $(SHARED_HEADER)" @echo "SHARED_SOURCE: $(SHARED_SOURCE)" @echo "SHARED_LIB: $(SHARED_LIB)" @echo "SHARED_TCL_LIB: $(SHARED_TCL_LIB)" @echo "PDOBJECTS: $(PDOBJECTS)" @echo "ALLSOURCES: $(ALLSOURCES)" @echo "ALLSOURCES TCL: $(wildcard $(ALLSOURCES:.c=.tcl))" @echo "UNAME: $(UNAME)" @echo "CPU: $(CPU)" @echo "pkglibdir: $(pkglibdir)" @echo "DISTDIR: $(DISTDIR)" @echo "ORIGDIR: $(ORIGDIR)" @echo "NDK_TOOLCHAIN: $(NDK_TOOLCHAIN)" @echo "NDK_BASE: $(NDK_BASE)" @echo "NDK_SYSROOT: $(NDK_SYSROOT)" @echo "VPATH: $(VPATH)" mrpeach/flist2tab/0000755000175000017500000000000013605444732014631 5ustar zmoelnigzmoelnigmrpeach/flist2tab/flist2tab-help.pd0000644000175000017500000000262211533622047017773 0ustar zmoelnigzmoelnig#N canvas 1 53 420 332 10; #X obj -12 175 table pig; #X obj 115 203 flist2tab pig; #X obj 92 163 any2string; #X msg 92 140 Hello; #X floatatom 190 162 5 0 0 0 - - -; #X msg 6 77 81 28 0 33 55 1 2 3; #X text -45 -12 flist2tab loads floats or lists of floats into a table ; #X text -45 4 at an offset determined by a float in the second inlet. ; #X text -45 20 Negative offsets will be ignored.; #X obj -12 152 table twig; #X msg 36 107 set twig; #X text 93 106 set the working table; #X text 203 203 argument is table name; #X text -45 36 Offsets greater than the table length cause the table to be resized to fit.; #X text 224 162 default offset is 0; #X floatatom 62 220 7 0 0 0 - - -; #X text 108 220 Array size is output after each input.; #X text 202 260 2009_01_28 Martin Peach; #N canvas 425 246 494 344 META 0; #X text 12 155 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; #X text 12 135 AUTHOR Martin Peach; #X text 12 75 INLET_0 float list set; #X text 12 95 INLET_1 float; #X text 12 115 OUTLET_0 float; #X text 12 45 DESCRIPTION load floats or lists of floats into a table at an offset determined by a float in the second inlet; #X text 12 5 KEYWORDS control array list_op conversion; #X text 12 25 LICENSE GPL v2 or later; #X restore 314 297 pd META; #X connect 1 0 15 0; #X connect 2 0 1 0; #X connect 3 0 2 0; #X connect 4 0 1 1; #X connect 5 0 1 0; #X connect 10 0 1 0; mrpeach/flist2tab/flist2tab.c0000644000175000017500000001074411140150526016660 0ustar zmoelnigzmoelnig/* flist2tab started 20090121 by mrpeach */ /* loads table from a list of floats at offset specified by second inlet */ /* floats negative offsets will not be loaded. */ /* Table will be resized to fit all the floats at positive offsets */ #include "m_pd.h" #if (PD_MINOR_VERSION > 40) #define USE_GETFLOATWORDS *//* if garray_getfloatwords is implemented */ #endif /* garray_getfloatwords uses t_word but doesn't exist in some versions of pd */ /* garray_getfloatarray uses t_float but is not 64-bit */ static t_class *flist2tab_class; typedef struct _flist2tab { t_object x_obj; t_symbol *x_arrayname; t_float x_ft1; t_float x_offset; t_outlet *x_sizeout; } t_flist2tab; static void flist2tab_list(t_flist2tab *x, t_symbol *s, int argc, t_atom *argv); static void flist2tab_float(t_flist2tab *x, t_float f); static void flist2tab_set(t_flist2tab *x, t_symbol *s); static void *flist2tab_new(t_symbol *s); void flist2tab_setup(void); static void flist2tab_list(t_flist2tab *x, t_symbol *s, int argc, t_atom *argv) { t_garray *a; #ifdef USE_GETFLOATWORDS t_word *vec; #else t_float *vec; #endif int npoints, newsize, i; int offset = x->x_offset; /* first check the list for floatness... */ for (i = 0; i < argc; ++i) { if (argv[i].a_type != A_FLOAT) { pd_error(x, "flist2tab_list: list must be all floats"); return; } } /* then find the array again... */ if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class))) pd_error(x, "flist2tab_list: %s: no such array", x->x_arrayname->s_name); #ifdef USE_GETFLOATWORDS else if (!garray_getfloatwords(a, &npoints, &vec)) #else else if (!garray_getfloatarray(a, &npoints, &vec)) #endif pd_error(x, "fflist2tab_list: %s: bad template", x->x_arrayname->s_name); else /* put the list in a starting at offset */ { newsize = offset + argc; if (newsize >= npoints) { garray_resize(a, newsize); #ifdef USE_GETFLOATWORDS if (!garray_getfloatwords(a, &npoints, &vec)) #else if (!garray_getfloatarray(a, &npoints, &vec)) #endif pd_error(x, "fflist2tab_list: %s: bad template", x->x_arrayname->s_name); } for (i = 0; i < argc; ++i) { if (i+offset >= 0) #ifdef USE_GETFLOATWORDS vec[i+offset].w_float = argv[i].a_w.w_float; #else vec[i+offset] = argv[i].a_w.w_float; #endif } /* output the size of the array */ outlet_float(x->x_sizeout, npoints); } } static void flist2tab_float(t_flist2tab *x, t_float f) { int i, npoints, offset = x->x_offset; t_garray *a; #ifdef USE_GETFLOATWORDS t_word *vec; #else t_float *vec; #endif if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class))) pd_error(x, "flist2tab_float %s: no such array", x->x_arrayname->s_name); #ifdef USE_GETFLOATWORDS else if (!garray_getfloatwords(a, &npoints, &vec)) #else else if (!garray_getfloatarray(a, &npoints, &vec)) #endif pd_error(x, "flist2tab_float %s: bad template", x->x_arrayname->s_name); else if (offset >= 0) { if (offset >= npoints) { garray_resize(a, offset+1); #ifdef USE_GETFLOATWORDS if (!garray_getfloatwords(a, &npoints, &vec)) #else if (!garray_getfloatarray(a, &npoints, &vec)) #endif pd_error(x, "flist2tab_float %s: bad template", x->x_arrayname->s_name); } #ifdef USE_GETFLOATWORDS vec[offset].w_float = f; #else vec[offset] = f; #endif garray_redraw(a); /* output the size of the array */ outlet_float(x->x_sizeout, npoints); } } static void flist2tab_set(t_flist2tab *x, t_symbol *s) { x->x_arrayname = s; } static void *flist2tab_new(t_symbol *s) { t_flist2tab *x = (t_flist2tab *)pd_new(flist2tab_class); x->x_offset = 0; x->x_arrayname = s; x->x_sizeout = outlet_new(&x->x_obj, &s_float); floatinlet_new(&x->x_obj, &x->x_offset); return (x); } void flist2tab_setup(void) { flist2tab_class = class_new(gensym("flist2tab"), (t_newmethod)flist2tab_new, 0, sizeof(t_flist2tab), 0, A_DEFSYM, 0); class_addfloat(flist2tab_class, (t_method)flist2tab_float); class_addlist(flist2tab_class, (t_method)flist2tab_list); class_addmethod(flist2tab_class, (t_method)flist2tab_set, gensym("set"), A_SYMBOL, 0); } mrpeach/README.txt0000644000175000017500000000124712571126663014442 0ustar zmoelnigzmoelnigmrpeach - bag of tricks === ## serial communication slipenc, slipdec: SLIP encoder/decoder f2b, b2f : float32<->bytes converter ## xbee communication with the XBee ## binfile read raw files (as bytes) ## midifile play and record MIDI-files ## general purpose objects [life2x] game of life [op~] signal comparision [rc~] resistor-capacitor circuit [rcosc~] resistor-capacitor oscillator [rojo~] red noise generator [runningmean] moving average filter [sqosc~] bandlimited pulse generator [str] strings [tabfind] find a number in a table [flist2tab] write lists of floats into a table [tab2flist] extract lists of floats from a table [which] output path to a Pd-object mrpeach/rc~/0000755000175000017500000000000013605444731013540 5ustar zmoelnigzmoelnigmrpeach/rc~/rc~.c0000644000175000017500000000334411352226732014506 0ustar zmoelnigzmoelnig/* rc~.c by Martin Peach 20100315 */ /* Pd external emulating a resistor-capacitor low-pass filter */ /* The control parameter is a time constant in seconds (or resistance X capacitance) */ #include "m_pd.h" static t_class *rc_tilde_class; typedef struct _rc_tilde { t_object rc_obj; t_float rc_rc; t_float rc_f; t_sample rc_node; } t_rc_tilde; static t_int *rc_tilde_perform(t_int *w); static void rc_tilde_dsp(t_rc_tilde *x, t_signal **sp); static void *rc_tilde_new(t_floatarg f); static t_int *rc_tilde_perform(t_int *w) { t_rc_tilde *x = (t_rc_tilde *)(w[1]); t_sample *in = (t_sample *)(w[2]); t_sample *out = (t_sample *)(w[3]); int n = (int)(w[4]); float slewrate; float sp = 1.0/sys_getsr(); if (x->rc_rc < sp) slewrate = 1.0; else slewrate = sp/x->rc_rc; while (n--) { x->rc_node += (*in++ - x->rc_node)*slewrate; *out++ = x->rc_node; } return (w+5); } static void rc_tilde_dsp(t_rc_tilde *x, t_signal **sp) { dsp_add(rc_tilde_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n); } static void *rc_tilde_new(t_floatarg f) { t_rc_tilde *x = (t_rc_tilde *)pd_new(rc_tilde_class); x->rc_rc = f; x->rc_node = 0.0; floatinlet_new (&x->rc_obj, &x->rc_rc); outlet_new(&x->rc_obj, &s_signal); return (void *)x; } void rc_tilde_setup(void) { rc_tilde_class = class_new(gensym("rc~"), (t_newmethod)rc_tilde_new, 0, sizeof(t_rc_tilde), CLASS_DEFAULT, A_DEFFLOAT, 0); class_addmethod(rc_tilde_class, (t_method)rc_tilde_dsp, gensym("dsp"), 0); CLASS_MAINSIGNALIN(rc_tilde_class, t_rc_tilde, rc_f); } /* fin rc~.c */ mrpeach/rc~/rc~-help.pd0000644000175000017500000000235511533764114015620 0ustar zmoelnigzmoelnig#N canvas 1 53 450 377 10; #X obj 52 180 dac~; #X obj 53 143 *~; #X obj 53 79 tgl 15 0 empty empty empty 17 7 0 10 -4034 -13381 -1 0 1; #X obj 80 79 nbx 5 14 0 1e+37 0 1 empty empty seconds 60 8 0 10 -4034 -13381 -13381 0.73 256; #X obj 53 57 metro 1000; #X obj 53 36 tgl 15 0 empty empty empty 17 7 0 10 -4034 -13381 -1 0 1; #X obj 53 99 rc~ 1; #X text 191 167 Author: Martin Peach; #X text 191 186 2010/03/15; #X obj 67 121 noise~; #X obj 136 230 lop~; #X text 63 230 similar to:; #X text 49 -22 rc~ emulates a capacitor charging through a resistor. The creation argument can be overriden by the right inlet \, and represents a charging time constant in seconds.; #N canvas 453 86 494 344 META 0; #X text 12 145 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; #X text 12 25 LICENSE GPL v2 or later; #X text 12 125 AUTHOR Martin Peach; #X text 12 46 DESCRIPTION emulate a capacitor charging through a resistor ; #X text 12 65 INLET_0 float; #X text 12 85 INLET_1 float; #X text 12 105 OUTLET_0 signal; #X text 12 5 KEYWORDS signal; #X restore 379 329 pd META; #X connect 1 0 0 0; #X connect 1 0 0 1; #X connect 2 0 6 0; #X connect 3 0 6 1; #X connect 4 0 2 0; #X connect 5 0 4 0; #X connect 6 0 1 0; #X connect 9 0 1 1; mrpeach/sqosc~/0000755000175000017500000000000013605444732014265 5ustar zmoelnigzmoelnigmrpeach/sqosc~/sqosc~.c0000644000175000017500000003151411317724674015767 0ustar zmoelnigzmoelnig/* sqosc.c Martin Peach 20060613 based on d_osc.c */ /* 20060707 using x-x^3/3 to smooth the ramp */ /* 20070328 added call to finite() to eliminate possible NaNs */ /* d_osc.c is: */ /* Copyright (c) 1997-1999 Miller Puckette. * For information on usage and redistribution, and for a DISCLAIMER OF ALL * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ /* sinusoidal oscillator and table lookup; see also tabosc4~ in d_array.c. */ #include "m_pd.h" #include #define UNITBIT32 1572864. /* 3*2^19; bit 32 has place value 1 */ /* machine-dependent definitions. These ifdefs really * should have been by CPU type and not by operating system! */ #ifdef IRIX /* big-endian. Most significant byte is at low address in memory */ #define HIOFFSET 0 /* word offset to find MSB */ #define LOWOFFSET 1 /* word offset to find LSB */ #define int32 long /* a data type that has 32 bits */ #endif /* IRIX */ #ifdef _WIN32 /* little-endian; most significant byte is at highest address */ #define HIOFFSET 1 #define LOWOFFSET 0 #define int32 long #include /* for _finite */ #define finite _finite #endif // _WIN32 #if defined(__FreeBSD__) || defined(__APPLE__) #include #endif #ifdef __APPLE__ #define __BYTE_ORDER BYTE_ORDER #define __LITTLE_ENDIAN LITTLE_ENDIAN #endif #ifdef __linux__ #include #endif #if defined(__unix__) || defined(__APPLE__) #if !defined(__BYTE_ORDER) || !defined(__LITTLE_ENDIAN) #error No byte order defined #endif #if __BYTE_ORDER == __LITTLE_ENDIAN #define HIOFFSET 1 #define LOWOFFSET 0 #else #define HIOFFSET 0 /* word offset to find MSB */ #define LOWOFFSET 1 /* word offset to find LSB */ #endif /* __BYTE_ORDER */ #include #define int32 int32_t #endif /* __unix__ or __APPLE__*/ union tabfudge { double tf_d; int32 tf_i[2]; }; static t_class *sqosc_class; /* COSTABSIZE is 512 in m_pd.h, we start with that... */ #define LOGSQOSCTABSIZE 9 #define SQOSCTABSIZE 512 #define HALFSQOSCTABSIZE 256 typedef struct _sqosc { t_object x_obj; double x_phase; float x_conv; float x_f; /* frequency if scalar */ float x_pw; /* pulse width 0-1, default 0.5 */ float x_bw; /* bandwidth */ float x_slew; /* slew time in samples */ double x_dpw; /* pulse width in this pulse */ int x_pulse_ended; /* nonzero if pulse has finished */ } t_sqosc; void sqosc_tilde_setup(void); static void sqosc_ft1(t_sqosc *x, t_float f); static void sqosc_pw(t_sqosc *x, t_float pw); static void sqosc_dsp(t_sqosc *x, t_signal **sp); static t_int *sqosc_perform(t_int *w); static void *sqosc_new(t_floatarg f, t_floatarg pw, t_float bw); static void *sqosc_new(t_floatarg f, t_floatarg pw, t_floatarg bw) { t_sqosc *x = (t_sqosc *)pd_new(sqosc_class); x->x_f = f; /* the initial frequency in Hz */ outlet_new(&x->x_obj, gensym("signal")); inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1")); inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("pw")); post("sqosc_new frequency %f, pulsewidth %f bandwidth %f", f, pw, bw); x->x_phase = 0; x->x_conv = 0; if ((pw <= 0)||(pw >= 1)) { post("sqosc: second argument (pulse width) must be greater than 0 and less than 1, using 0.5"); x->x_pw = 0.5 * SQOSCTABSIZE; } else x->x_pw = pw * SQOSCTABSIZE; if (bw < 0) { post("sqosc: third argument (bandwidth) must be greater than 0, using 10000"); x->x_bw = 10000; } else x->x_bw = bw; x->x_slew = HALFSQOSCTABSIZE/x->x_bw;/* slew = time of half bandwidth cycle */ x->x_dpw = x->x_pw; /* pulse width in this pulse */ x->x_pulse_ended = 1; /* nonzero if pulse has finished */ return (x); } /* This is corrected from Chun Lee's explanation in an email at: http://music.columbia.edu/pipermail/music-dsp/2004-November/028814.html 1-> a double variable UNITBIT32 is assigned to 1572864. This is what it looks like in memory in a little endian machine: byte 7 byte 6 byte 5 byte 4 byte 3 byte 2 byte 1 byte 0 00000000 00000000 00000000 00000000 00000000 00000000 0001 1100 1000001 0 |<------fraction------------------>|<----1572864--------->|exponent |sign| The reason for 1572864 (1.5 X 2^20) is that its representation in IEEE754 format (double) has 51 zeros to the right of a placeholding 1 bit, which can then be used as a wide fixed-point register with the binary point at bit 32, so the lower 32 bits can be used as a fractional accumulator with 32-bit precision. Adding 1 to INITBIT32 adds a 1 at bit 32, with no change in exponent, so the lower 32 bits act as a fraction of one. The 31 zero bits in the integer part can be set as high as 2147483647 (31 1s) without affecting the precision. The upper 32 bits are 1094189056, or 01000001 00111000 00000000 00000000 in binary. The sign bit is zero, or positive. The upper bit of the exponent is one, meaning the number is normalized, or full precision.The exponent is 1043 minus the bias of 1023, or 20. This is the representation of the number 1.5 X 2^20 = 1572864: IEEE Standard 754 Double Precision Storage Format (double): 63 62 52 51 32 31 0 +--------+----------------+-------------------+------------------------------+ | s 1bit | e[62:52] 11bit | f[51:32] 20bit | f[31:0] 32bit | +--------+----------------+-------------------+------------------------------+ B0-------------->B1---------->B2----->B3----->B4----->B5----->B6----->B7-----> 0 10000010011 1000000000000000000000000000000000000000000000000000 2-> there is the tabfudge like: Union tabfudge { double tf_d; int32 tf_i[2]; } In dsp_perfrom: Union tabfudge tf; tf.tf_d = UNITBIT32; 3-> the phase is accumulated into tf_d plus the UNITBIT32 Double dphase = x_phase + UNITBIT32; 4-> byte 0 to byte 3 is stored as a separate variable as: int normhipart = tf.tf_I[HIOFFSET]; //where HIOFFSET is used to find MSB 5-> in the actual dsp block, although the phase is accumulated into tf.tf_d, bytes 0 to 3 of tf.tf_d are constantly forced to be a constant by: tf.tf_i[HIOFFSET] = normhipart; 6-> because of this, to get the fraction part out of the tf.tf_d, simply do: tf.tf_d - UNITBIT32; 7-> mission accomplished!!!!! */ static t_int *sqosc_perform(t_int *w) { t_sqosc *x = (t_sqosc *)(w[1]); t_float *in = (t_float *)(w[2]); t_float *out = (t_float *)(w[3]); t_float sample; int n = (int)(w[4]); float f1, f2, frac; int index; double dphase = x->x_phase + UNITBIT32; int normhipart; union tabfudge tf; float conv = x->x_conv; double lastin, slewindex; static double twothirds = 2.0/3.0; static double onethird = 1.0/3.0; tf.tf_d = UNITBIT32; /* set the phase accumulator to (1.5 X 2^20) making it effectively fixed-point */ normhipart = tf.tf_i[HIOFFSET]; /* save the sign, exponent, and integer part of a fixed accumulator */ tf.tf_d = dphase; /* the current phase plus the "frame" */ lastin = *in++; /* latest frequency */ if (lastin < 0) lastin = -lastin;/* negative frequency is the same as positive here */ if (lastin > x->x_bw) lastin = x->x_bw;/* limit frequency to bandwidth */ slewindex = x->x_slew*lastin; dphase += lastin * conv; /* new phase is old phase + (frequency * table period) */ index = tf.tf_i[HIOFFSET] & (SQOSCTABSIZE-1); tf.tf_i[HIOFFSET] = normhipart; /* zero the non-fractional part of the phase */ frac = tf.tf_d - UNITBIT32; /* extract the fractional part of the phase */ while (--n) { tf.tf_d = dphase; if (index <= slewindex) { /* rising phase */ if(x->x_pulse_ended) {/* set pw for this pulse once only*/ if(x->x_pw < slewindex)x->x_dpw = slewindex; else if (x->x_pw > SQOSCTABSIZE-slewindex)x->x_dpw = SQOSCTABSIZE-slewindex; else x->x_dpw = x->x_pw; x->x_pulse_ended = 0; } f1 = 1.0-2.0*(slewindex-index)/slewindex;/* a ramp from -1 to +1 */ f1 = f1 - pow(f1, 3.0)*onethird;/* smooth the ramp */ } else if (index < x->x_dpw) f1 = twothirds; /* risen */ else if (index <= slewindex+x->x_dpw) { /* falling phase */ f1 = -1.0+2.0*(slewindex-index+x->x_dpw)/slewindex;/* a ramp from +1 to -1 */ f1 = f1 - pow(f1, 3.0)*onethird;/* smooth the ramp */ x->x_pulse_ended = 1; } else { /* fallen */ f1 = -twothirds; } lastin = *in++; if (lastin < 0) lastin = -lastin;/* negative frequency is the same as positive here */ if (lastin > x->x_bw) lastin = x->x_bw;/* limit frequency to bandwidth */ slewindex = x->x_slew*lastin; dphase += lastin * conv; /* next phase */ if (index+1 <= slewindex) { f2 = 1.0-2.0*(slewindex-index-1)/slewindex; f2 = f2 - pow(f2, 3.0)*onethird; } else if (index+1 < x->x_dpw) f2 = twothirds; else if (index+1 <= slewindex+x->x_dpw) { f2 = -1.0+2.0*(slewindex-index-1+x->x_dpw)/slewindex; f2 = f2 - pow(f2, 3.0)*onethird; } else f2 = -twothirds; sample = f1 + frac * (f2 - f1); /* output first sample plus fraction of second sample (linear interpolation) */ *out++ = sample; index = tf.tf_i[HIOFFSET] & (SQOSCTABSIZE-1); tf.tf_i[HIOFFSET] = normhipart; /* zero the non-fractional part */ frac = tf.tf_d - UNITBIT32; /* get next fractional part */ } if (index <= slewindex) { if(x->x_pulse_ended) {/* set pw for this pulse once only*/ if(x->x_pw < slewindex)x->x_dpw = slewindex; else if (x->x_pw > SQOSCTABSIZE-slewindex)x->x_dpw = SQOSCTABSIZE-slewindex; else x->x_dpw = x->x_pw; x->x_pulse_ended = 0; } f1 = 1.0-2.0*(slewindex-index)/slewindex; f1 = f1 - pow(f1, 3.0)*onethird; } else if (index < x->x_dpw) f1 = twothirds; /* risen */ else if (index <= slewindex+x->x_dpw) { /* falling phase */ f1 = -1.0+2.0*(slewindex-index+x->x_dpw)/slewindex; f1 = f1 - pow(f1, 3.0)*onethird; x->x_pulse_ended = 1; } else { /* fallen */ f1 = -twothirds; } if (index+1 <= slewindex) { f2 = 1.0-2.0*(slewindex-index-1)/slewindex; f2 = f2 - pow(f2, 3.0)*onethird; } else if (index+1 < x->x_dpw) f2 = twothirds; else if (index+1 <= slewindex+x->x_dpw) { f2 = -1.0+2.0*(slewindex-index-1+x->x_dpw)/slewindex; f2 = f2 - pow(f2, 3.0)*onethird; } else f2 = -twothirds; sample = f1 + frac * (f2 - f1); /* the final sample */ if (finite(sample))*out++ = sample; else *out++ = 0.0; tf.tf_d = UNITBIT32 * SQOSCTABSIZE; /* this just changes the exponent if the table size is a power of 2 */ normhipart = tf.tf_i[HIOFFSET]; /* ...so we get more integer digits but fewer fractional ones */ tf.tf_d = dphase + (UNITBIT32 * SQOSCTABSIZE - UNITBIT32); /* subtract one UNITBIT32 we added at the beginning */ tf.tf_i[HIOFFSET] = normhipart; /* wrap any overflow to the table size */ x->x_phase = tf.tf_d - UNITBIT32 * SQOSCTABSIZE; /* extract just the phase */ return (w+5); } static void sqosc_dsp(t_sqosc *x, t_signal **sp) { x->x_conv = SQOSCTABSIZE/sp[0]->s_sr; /* conv = table period = (samples/cycle)/(samples/sec) = sec/cycle = 0.011610sec for 512/44100 */ dsp_add(sqosc_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n); } static void sqosc_ft1(t_sqosc *x, t_float f) { x->x_phase = SQOSCTABSIZE * f; } static void sqosc_pw(t_sqosc *x, t_float pw) { if ((pw <= 0)||(pw >= 1)) return; x->x_pw = pw * SQOSCTABSIZE; } void sqosc_tilde_setup(void) { sqosc_class = class_new(gensym("sqosc~"), (t_newmethod)sqosc_new, 0, sizeof(t_sqosc), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); CLASS_MAINSIGNALIN(sqosc_class, t_sqosc, x_f);/* x_f is used when no signal is input */ class_addmethod(sqosc_class, (t_method)sqosc_dsp, gensym("dsp"), 0); class_addmethod(sqosc_class, (t_method)sqosc_ft1, gensym("ft1"), A_FLOAT, 0); class_addmethod(sqosc_class, (t_method)sqosc_pw, gensym("pw"), A_FLOAT, 0); } /* end of sqosc.c */ mrpeach/sqosc~/sqosc~-help.pd0000644000175000017500000000507211533764572017077 0ustar zmoelnigzmoelnig#N canvas 1 53 580 638 12; #X obj 107 298 dac~; #X obj 177 281 tabwrite~ wave; #X obj 422 259 table wave 512; #X floatatom 127 114 5 0 0 2 pulse_frequency - -; #X floatatom 254 180 5 0 0 0 - - -; #X obj 418 25 line; #X msg 442 -27 0.01 10000; #X msg 441 -4 0.99 10000; #X obj 393 112 metro 100; #X obj 393 93 tgl 15 0 empty empty graph_waveform 20 8 0 8 -24198 -42246 -1 0 1; #X obj 184 10 mtof; #X obj 184 -33 counter 127; #X obj 184 -123 tgl 15 0 empty empty play_all_the_midi_notes 20 8 0 8 -24198 -42246 -1 0 1; #X obj 184 -57 metro 100; #X floatatom 251 -78 5 0 0 0 - - -; #X msg 251 -102 10000; #X text 47 402 outlet: pulse; #X obj 254 109 random 1000; #X obj 254 135 * 0.001; #X obj 254 85 metro 100; #X obj 254 14 tgl 15 0 empty empty random_pulse_widths 20 8 0 8 -24198 -42246 -1 0 1; #X floatatom 321 63 5 0 0 0 - - -; #X msg 321 38 100; #X obj 107 234 sqosc~ 440 0.5 2000; #X obj 21 -60 osc~ 1; #X obj 22 -37 +~ 1; #X floatatom 48 2 5 0 0 2 fm_depth - -; #X floatatom 21 -90 0 0 0 2 fm_frequency - -; #X obj 393 158 spigot; #X obj 436 136 tgl 15 0 empty empty sync_graph 20 7 0 8 -24198 -42246 -1 0 1; #X msg 393 182 0; #X obj 108 162 +~; #X text 349 418 2007_MartinPeach; #X text 270 258 click to see graph:; #X obj 21 29 *~ 0; #X text 32 -174 sqosc~ is a bandlimited pulse generator; #X text 79 351 frequency(Hz) pulsewidth(0-1) bandwidth(Hz); #X text 49 334 creation arguments:; #X text 78 385 frequency(Hz) phase(0-1) pulsewidth(0-1); #X text 47 368 inlets:; #N canvas 393 221 494 344 META 0; #X text 12 165 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; #X text 12 25 LICENSE GPL v2 or later; #X text 12 145 AUTHOR Martin Peach; #X text 12 5 KEYWORDS signal bandlimited; #X text 12 46 DESCRIPTION bandlimited pulse generator; #X text 12 65 INLET_0 signal; #X text 12 85 INLET_1 float; #X text 12 105 INLET_2 float; #X text 12 125 OUTLET_0 signal; #X restore 513 433 pd META; #X connect 3 0 31 1; #X connect 4 0 23 2; #X connect 5 0 4 0; #X connect 6 0 5 0; #X connect 7 0 5 0; #X connect 8 0 1 0; #X connect 8 0 28 0; #X connect 9 0 8 0; #X connect 10 0 3 0; #X connect 11 0 10 0; #X connect 12 0 13 0; #X connect 13 0 11 0; #X connect 14 0 13 1; #X connect 15 0 14 0; #X connect 17 0 18 0; #X connect 18 0 4 0; #X connect 19 0 17 0; #X connect 20 0 19 0; #X connect 21 0 19 1; #X connect 22 0 21 0; #X connect 23 0 1 0; #X connect 23 0 0 1; #X connect 23 0 0 0; #X connect 24 0 25 0; #X connect 25 0 34 0; #X connect 26 0 34 1; #X connect 27 0 24 0; #X connect 28 0 30 0; #X connect 29 0 28 1; #X connect 30 0 23 1; #X connect 31 0 23 0; #X connect 34 0 31 0; mrpeach/xbee/0000755000175000017500000000000013605444731013661 5ustar zmoelnigzmoelnigmrpeach/xbee/packxbee.c0000644000175000017500000011034412163362417015610 0ustar zmoelnigzmoelnig/* packxbee outputs a list of floats which are the bytes making up an xbee api packet. */ /* The packet can then be sent through [comport]. */ /* Started by Martin Peach 20110731 */ /* Information taken from "XBee/XBee-PRO ZB RF Modules" (document 90000976_G, 11/15/2010)*/ /* by Digi International Inc. http://www.digi.com */ /* Series 1 info from "XBee/XBee-PRO RF Modules" (document 90000982_L 4/30/2013) */ #include #include #include "m_pd.h" #include "pdxbee.h" static t_class *packxbee_class; typedef struct _packxbee { t_object x_obj; t_outlet *x_listout; int x_api_mode; unsigned char x_frameID; unsigned char x_frameType; int x_verbosity; t_atom x_outbuf[MAX_XBEE_PACKET_LENGTH]; } t_packxbee; static void *packxbee_new(t_floatarg f); static int packxbee_outbuf_add(t_packxbee *x, int index, unsigned char val); static void packxbee_AT(t_packxbee *x, t_symbol *s, int argc, t_atom *argv); static void packxbee_RAT(t_packxbee *x, t_symbol *s, int argc, t_atom *argv); static void packxbee_ATQ(t_packxbee *x, t_symbol *s, int argc, t_atom *argv); static void packxbee_TX(t_packxbee *x, t_symbol *s, int argc, t_atom *argv); static void packxbee_TX64(t_packxbee *x, t_symbol *s, int argc, t_atom *argv); static void packxbee_TX16(t_packxbee *x, t_symbol *s, int argc, t_atom *argv); static void packxbee_pack_remote_frame(t_packxbee *x, t_symbol *s, int argc, t_atom *argv); static void packxbee_pack_frame(t_packxbee *x, t_symbol *s, int argc, t_atom *argv); static void packxbee_API(t_packxbee *x, t_float api); static void packxbee_verbosity(t_packxbee *x, t_float verbosity_level); static void packxbee_free(t_packxbee *x); void packxbee_setup(void); static void *packxbee_new(t_floatarg f) { int i; t_packxbee *x = (t_packxbee *)pd_new(packxbee_class); if (x) { x->x_listout = outlet_new(&x->x_obj, &s_list); if (1 == f) x->x_api_mode = 1; else x->x_api_mode = 2; /* default to escaped mode */ x->x_verbosity = 0; /* debug level */ for(i = 0; i < MAX_XBEE_PACKET_LENGTH; ++i) x->x_outbuf[i].a_type = A_FLOAT; /* init output atoms as floats */ } return (x); } static void packxbee_API(t_packxbee *x, t_float api) { if ((api == 1) || (api ==2)) x->x_api_mode = api; else error ("packxbee: api mode must be 1 or 2"); } static void packxbee_verbosity(t_packxbee *x, t_float verbosity_level) { if (verbosity_level >= 0) x->x_verbosity = verbosity_level; else error ("packxbee: verbosity_level must be positive"); } static int packxbee_outbuf_add(t_packxbee *x, int index, unsigned char val) { int i = index; /* if API mode is 2 all characters after the first are escaped if they are one of the sacred texts */ /* to escape the character prefix it with XSCAPE and XOR it with 0x20 */ if ( (2 == x->x_api_mode) && ( ((0 < index)&&(XFRAME == val)) ||(XSCAPE == val) ||(XON == val) ||(XOFF == val) ) ) { /* escape the character */ x->x_outbuf[i].a_w.w_float = XSCAPE; ++i; x->x_outbuf[i].a_w.w_float = val ^ 0x20; ++i; } else { /* otherwise just put it in the buffer */ x->x_outbuf[i++].a_w.w_float = val; } return i; } /* send a packet given a 64-bit address, a 16-bit address, broadcast radius, options, followed by raw data (Series2 ZB only) */ static void packxbee_TX(t_packxbee *x, t_symbol *s, int argc, t_atom *argv) { unsigned char floatstring[256]; /* longer than the longest hex number with each character escaped plus the header and checksum overhead */ unsigned long long dest64; unsigned int dest16; int result; char checksum = 0xFF; unsigned char broadcast_radius, options; t_float f; int d, i, j, k; int length = 0; unsigned char c; if (argc < 5) { error("packxbee_TX: not enough parameters"); return; } /* first arg is dest64, a symbol starting with "0x" */ if (argv[0].a_type != A_SYMBOL) { error("packxbee_TX: first argument is not a symbol"); return; } if ((argv[0].a_w.w_symbol->s_name[0] != '0')||(argv[0].a_w.w_symbol->s_name[1] != 'x')) { error("packxbee_TX: first argument is not a hex string beginning with \"0x\""); return; } #ifdef _MSC_VER result = sscanf(argv[0].a_w.w_symbol->s_name, "0x%I64X", &dest64); #else result = sscanf(argv[0].a_w.w_symbol->s_name, "0x%LX", &dest64); #endif if (result == 0) { error("packxbee_TX: first argument is not a hex string"); return; } #ifdef _MSC_VER if (x->x_verbosity > 1) post ("packxbee_TX: dest64:0x%016I64X", dest64); #else if (x->x_verbosity > 1) post ("packxbee_TX: dest64:0x%016LX", dest64); #endif /* second arg is dest16 also a symbol starting with "0x" */ if (argv[1].a_type != A_SYMBOL) { error("packxbee_TX: second argument is not a symbol"); return; } if ((argv[1].a_w.w_symbol->s_name[0] != '0')||(argv[1].a_w.w_symbol->s_name[1] != 'x')) { error("packxbee_TX: second argument is not a hex string beginning with \"0x\""); return; } result = sscanf(argv[1].a_w.w_symbol->s_name, "0x%X", &dest16); if (result == 0) { error("packxbee_TX: second argument is not a hex string"); return; } if (x->x_verbosity > 1) post ("packxbee_TX: dest16: 0x%X", dest16); /* broadcast radius is a single byte as a float */ if (argv[2].a_type != A_FLOAT) { error("packxbee_TX: third argument is not a float"); return; } f = argv[2].a_w.w_float; if (x->x_verbosity > 1) post("packxbee_TX: float parameter %f", f); d = ((unsigned int)f)&0x0FF; if (f != d) { error ("packxbee_TX: third argument is not a positive integer from 0 to 255"); return; } else broadcast_radius = d; if (x->x_verbosity > 1) post("packxbee_TX: broadcast_radius: %d", d); /* options is a single byte as a float */ if (argv[3].a_type != A_FLOAT) { error("packxbee_TX: fourth argument is not a float"); return; } f = argv[3].a_w.w_float; if (x->x_verbosity > 1) post("packxbee_TX: float parameter %f", f); d = ((unsigned int)f)&0x0FF; if (f != d) { error ("packxbee_TX: fourth argument is not a positive integer from 0 to 255"); return; } else options = d; if (x->x_verbosity > 1) post("packxbee_TX: options: %d", d); x->x_frameType = ZigBee_Transmit_Request;/* because we're building a queued AT frame */ floatstring[0] = XFRAME; /* as usual */ floatstring[1] = 0; /* length MSB */ floatstring[2] = 0;/* length LSB */ floatstring[3] = x->x_frameType; checksum -= x->x_frameType; if (0 == x->x_frameID) x->x_frameID++; checksum -= x->x_frameID; /* frame ID */ floatstring[4] = x->x_frameID++; /* raw 8 byte address in big-endian order: */ floatstring[5] = (dest64>>56)&0x0FF; checksum -= floatstring[5]; floatstring[6] = (dest64>>48)&0x0FF; checksum -= floatstring[6]; floatstring[7] = (dest64>>40)&0x0FF; checksum -= floatstring[7]; floatstring[8] = (dest64>>32)&0x0FF; checksum -= floatstring[8]; floatstring[9] = (dest64>>24)&0x0FF; checksum -= floatstring[9]; floatstring[10] = (dest64>>16)&0x0FF; checksum -= floatstring[10]; floatstring[11] = (dest64>>8)&0x0FF; checksum -= floatstring[11]; floatstring[12] = (dest64)&0x0FF; checksum -= floatstring[12]; floatstring[13] = (dest16>>8)&0x0FF; checksum -= floatstring[13]; floatstring[14] = (dest16)&0x0FF; checksum -= floatstring[14]; floatstring[15] = broadcast_radius; checksum -= floatstring[15]; floatstring[16] = options; checksum -= floatstring[16]; /* the rest is payload */ i = 17; for (k = 4; k < argc; ++k) { if (A_FLOAT == argv[k].a_type) { f = argv[k].a_w.w_float; if (x->x_verbosity > 1) post("packxbee_TX: float parameter %f", f); d = ((unsigned int)f)&0x0FF; if (f != d) { error ("packxbee_TX: argument %d is not a positive integer from 0 to 255", k+1); return; } floatstring[i++] = d; checksum -= d; } else if (A_SYMBOL == argv[k].a_type) { if (x->x_verbosity > 1) post("packxbee_TX: symbol parameter %s", argv[k].a_w.w_symbol->s_name); j = i; i += sprintf((char *)&floatstring[i], "%s", argv[k].a_w.w_symbol->s_name); for (;j < i; ++j) checksum -= floatstring[j]; } else { error("packxbee_TX: argument %d is not a float or a symbol", k+1); return; } } length = i-3; floatstring[LENGTH_LSB_INDEX] = length & 0x0FF; floatstring[LENGTH_MSB_INDEX] = length >> 8; floatstring[i++] = checksum; k = j = 0; /* j indexes the outbuf, k indexes the floatbuf, i is the length of floatbuf */ for (k = 0; k < i; ++k) j = packxbee_outbuf_add(x, j, floatstring[k]); outlet_list(x->x_listout, &s_list, j, x->x_outbuf); if(x->x_verbosity > 1) { for (k = 0; k < j; ++k) { c = (unsigned char)atom_getfloat(&x->x_outbuf[k]); post("buf[%d]: %d [0x%02X]", k, c, c); } } } /* send a packet given a 64-bit address, options, followed by raw data (Series1 only) */ static void packxbee_TX64(t_packxbee *x, t_symbol *s, int argc, t_atom *argv) { unsigned char floatstring[256]; /* longer than the longest hex number with each character escaped plus the header and checksum overhead */ unsigned long long dest64; int result; char checksum = 0xFF; unsigned char options; t_float f; int d, i, j, k; int length = 0; unsigned char c; if (argc < 3) { error("packxbee_TX64: not enough parameters"); return; } /* first arg is dest64, a symbol starting with "0x" */ if (argv[0].a_type != A_SYMBOL) { error("packxbee_TX64: first argument is not a symbol"); return; } if ((argv[0].a_w.w_symbol->s_name[0] != '0')||(argv[0].a_w.w_symbol->s_name[1] != 'x')) { error("packxbee_TX64: first argument is not a hex string beginning with \"0x\""); return; } #ifdef _MSC_VER result = sscanf(argv[0].a_w.w_symbol->s_name, "0x%I64X", &dest64); #else result = sscanf(argv[0].a_w.w_symbol->s_name, "0x%LX", &dest64); #endif if (result == 0) { error("packxbee_TX64: first argument is not a hex string"); return; } #ifdef _MSC_VER if (x->x_verbosity > 1) post ("packxbee_TX64: dest64:0x%016I64X", dest64); #else if (x->x_verbosity > 1) post ("packxbee_TX64: dest64:0x%016LX", dest64); #endif /* options is a single byte as a float */ if (argv[1].a_type != A_FLOAT) { error("packxbee_TX64: second argument is not a float"); return; } f = argv[1].a_w.w_float; if (x->x_verbosity > 1) post("packxbee_TX64 float parameter %f", f); d = ((unsigned int)f)&0x0FF; if (f != d) { error("packxbee_TX64 second argument is not a positive integer from 0 to 255"); return; } else options = d; if (x->x_verbosity > 1) post("packxbee_TX64: options: %d", d); x->x_frameType = Transmit_Request_64_Bit_Address; floatstring[0] = XFRAME; /* as usual */ floatstring[1] = 0; /* length MSB */ floatstring[2] = 0;/* length LSB */ floatstring[3] = x->x_frameType; checksum -= x->x_frameType; if (0 == x->x_frameID) x->x_frameID++; checksum -= x->x_frameID; /* frame ID */ floatstring[4] = x->x_frameID++; /* raw 8 byte address in big-endian order: */ floatstring[5] = (dest64>>56)&0x0FF; checksum -= floatstring[5]; floatstring[6] = (dest64>>48)&0x0FF; checksum -= floatstring[6]; floatstring[7] = (dest64>>40)&0x0FF; checksum -= floatstring[7]; floatstring[8] = (dest64>>32)&0x0FF; checksum -= floatstring[8]; floatstring[9] = (dest64>>24)&0x0FF; checksum -= floatstring[9]; floatstring[10] = (dest64>>16)&0x0FF; checksum -= floatstring[10]; floatstring[11] = (dest64>>8)&0x0FF; checksum -= floatstring[11]; floatstring[12] = (dest64)&0x0FF; checksum -= floatstring[12]; floatstring[13] = options; checksum -= floatstring[13]; /* the rest is payload */ i = 14; for (k = 2; k < argc; ++k) { if (A_FLOAT == argv[k].a_type) { f = argv[k].a_w.w_float; if (x->x_verbosity > 1) post("packxbee_TX64: float parameter %f", f); d = ((unsigned int)f)&0x0FF; if (f != d) { error("packxbee_TX64: argument %d is not a positive integer from 0 to 255", k+1); return; } floatstring[i++] = d; checksum -= d; } else if (A_SYMBOL == argv[k].a_type) { if (x->x_verbosity > 1) post("packxbee_TX64: symbol parameter %s", argv[k].a_w.w_symbol->s_name); j = i; i += sprintf((char *)&floatstring[i], "%s", argv[k].a_w.w_symbol->s_name); for (;j < i; ++j) checksum -= floatstring[j]; } else { error("packxbee_TX64: argument %d is not a float or a symbol", k+1); return; } } length = i-3; floatstring[LENGTH_LSB_INDEX] = length & 0x0FF; floatstring[LENGTH_MSB_INDEX] = length >> 8; floatstring[i++] = checksum; k = j = 0; /* j indexes the outbuf, k indexes the floatbuf, i is the length of floatbuf */ for (k = 0; k < i; ++k) j = packxbee_outbuf_add(x, j, floatstring[k]); outlet_list(x->x_listout, &s_list, j, x->x_outbuf); if(x->x_verbosity > 1) { for (k = 0; k < j; ++k) { c = (unsigned char)atom_getfloat(&x->x_outbuf[k]); post("buf[%d]: %d [0x%02X]", k, c, c); } } } /* send a packet given a 16-bit address, options, followed by raw data (Series1 only) */ static void packxbee_TX16(t_packxbee *x, t_symbol *s, int argc, t_atom *argv) { unsigned char floatstring[256]; /* longer than the longest hex number with each character escaped plus the header and checksum overhead */ unsigned int dest16; int result; char checksum = 0xFF; unsigned char options; t_float f; int d, i, j, k; int length = 0; unsigned char c; if (argc < 3) { error("packxbee_TX16: not enough parameters"); return; } /* first arg is dest16 also a symbol starting with "0x" */ if (argv[0].a_type != A_SYMBOL) { error("packxbee_TX16: first argument is not a symbol"); return; } if ((argv[0].a_w.w_symbol->s_name[0] != '0')||(argv[0].a_w.w_symbol->s_name[1] != 'x')) { error("packxbee_TX16: first argument is not a hex string beginning with \"0x\""); return; } result = sscanf(argv[0].a_w.w_symbol->s_name, "0x%X", &dest16); if (result == 0) { error("packxbee_TX16: first argument is not a hex string"); return; } if (x->x_verbosity > 1) post ("packxbee_TX16: dest16: 0x%X", dest16); /* options is a single byte as a float */ if (argv[1].a_type != A_FLOAT) { error("packxbee_TX16: second argument is not a float"); return; } f = argv[1].a_w.w_float; if (x->x_verbosity > 1) post("packxbee_TX16: float parameter %f", f); d = ((unsigned int)f)&0x0FF; if (f != d) { post ("packxbee_TX16: second argument is not a positive integer from 0 to 255"); return; } else options = d; if (x->x_verbosity > 1) post("packxbee_TX16: options: %d", d); x->x_frameType = Transmit_Request_16_bit_Address; floatstring[0] = XFRAME; /* as usual */ floatstring[1] = 0; /* length MSB */ floatstring[2] = 0;/* length LSB */ floatstring[3] = x->x_frameType; checksum -= x->x_frameType; if (0 == x->x_frameID) x->x_frameID++; checksum -= x->x_frameID; /* frame ID */ floatstring[4] = x->x_frameID++; /* 16-bit address in big-endian order */ floatstring[5] = (dest16>>8)&0x0FF; checksum -= floatstring[5]; floatstring[6] = (dest16)&0x0FF; checksum -= floatstring[6]; floatstring[7] = options; checksum -= floatstring[7]; /* the rest is payload */ i = 8; for (k = 2; k < argc; ++k) { if (A_FLOAT == argv[k].a_type) { f = argv[k].a_w.w_float; if (x->x_verbosity > 1) post("packxbee_TX16: float parameter %f", f); d = ((unsigned int)f)&0x0FF; if (f != d) { error ("packxbee_TX16: argument %d is not a positive integer from 0 to 255", k+1); return; } floatstring[i++] = d; checksum -= d; } else if (A_SYMBOL == argv[k].a_type) { if (x->x_verbosity > 1) post("packxbee_TX16: symbol parameter %s", argv[k].a_w.w_symbol->s_name); j = i; i += sprintf((char *)&floatstring[i], "%s", argv[k].a_w.w_symbol->s_name); for (;j < i; ++j) checksum -= floatstring[j]; } else { error("packxbee_TX16: argument %d is not a float or a symbol", k+1); return; } } length = i-3; floatstring[LENGTH_LSB_INDEX] = length & 0x0FF; floatstring[LENGTH_MSB_INDEX] = length >> 8; floatstring[i++] = checksum; k = j = 0; /* j indexes the outbuf, k indexes the floatbuf, i is the length of floatbuf */ for (k = 0; k < i; ++k) j = packxbee_outbuf_add(x, j, floatstring[k]); outlet_list(x->x_listout, &s_list, j, x->x_outbuf); if(x->x_verbosity > 1) { for (k = 0; k < j; ++k) { c = (unsigned char)atom_getfloat(&x->x_outbuf[k]); post("buf[%d]: %d [0x%02X]", k, c, c); } } } /* format a queued AT packet and send it through x_listout as a list of floats */ static void packxbee_ATQ(t_packxbee *x, t_symbol *s, int argc, t_atom *argv) { x->x_frameType = AT_Command_Queue_Parameter_Value;/* we're building a queued AT frame */ packxbee_pack_frame(x, s, argc, argv); } /* format an AT packet and send it through x_listout as a list of floats */ static void packxbee_AT(t_packxbee *x, t_symbol *s, int argc, t_atom *argv) { x->x_frameType = AT_Command;/* we're building an AT frame */ packxbee_pack_frame(x, s, argc, argv); } /* format a remote AT packet and send it through x_listout as a list of floats */ static void packxbee_RAT(t_packxbee *x, t_symbol *s, int argc, t_atom *argv) { x->x_frameType = Remote_Command_Request;/* we're building a remote AT frame */ if (argc < 3) { error("packxbee_RAT: not enough parameters"); return; } packxbee_pack_remote_frame(x, s, argc, argv); } static void packxbee_pack_remote_frame(t_packxbee *x, t_symbol *s, int argc, t_atom *argv) { int i, j, k, maxdigits, d; char checksum = 0xFF; unsigned char floatstring[256]; /* longer than the longest hex number with each character escaped plus the header and checksum overhead */ int length = 0; unsigned char c, digits; t_float f; unsigned long long dest64; unsigned int dest16; int result; unsigned char options; if (x->x_verbosity > 0) post("packxbee_AT s is %s, argc is %d", s->s_name, argc); if (argc >= 4) /* we must have addr64, addr16, option byte, and an AT command */ { /* first arg is dest64, a symbol starting with "0x" */ if (argv[0].a_type != A_SYMBOL) { error("packxbee_pack_remote_frame: first argument is not a symbol"); return; } if ((argv[0].a_w.w_symbol->s_name[0] != '0')||(argv[0].a_w.w_symbol->s_name[1] != 'x')) { error("packxbee_pack_remote_frame: first argument is not a hex string beginning with \"0x\""); return; } #ifdef _MSC_VER result = sscanf(argv[0].a_w.w_symbol->s_name, "0x%I64X", &dest64); #else result = sscanf(argv[0].a_w.w_symbol->s_name, "0x%LX", &dest64); #endif if (result == 0) { error("packxbee_pack_remote_frame: first argument is not a hex string"); return; } #ifdef _MSC_VER if (x->x_verbosity > 0) post ("packxbee_pack_remote_frame: dest64:0x%016I64X", dest64); #else if (x->x_verbosity > 0) post ("packxbee_pack_remote_frame: dest64:0x%016LX", dest64); #endif /* second arg is dest16 also a symbol starting with "0x" */ if (argv[1].a_type != A_SYMBOL) { error("packxbee_pack_remote_frame: second argument is not a symbol"); return; } if ((argv[1].a_w.w_symbol->s_name[0] != '0')||(argv[1].a_w.w_symbol->s_name[1] != 'x')) { error("packxbee_pack_remote_frame: second argument is not a hex string beginning with \"0x\""); return; } result = sscanf(argv[1].a_w.w_symbol->s_name, "0x%X", &dest16); if (result == 0) { error("packxbee_pack_remote_frame: second argument is not a hex string"); return; } if (x->x_verbosity > 0) post ("packxbee_pack_remote_frame: dest16: 0x%X", dest16); /* options is a single byte as a float */ if (argv[2].a_type != A_FLOAT) { error("packxbee_pack_remote_frame: third argument is not a float"); return; } f = argv[2].a_w.w_float; if (x->x_verbosity > 0) post("packxbee_pack_remote_frame float parameter %f", f); d = ((unsigned int)f)&0x0FF; if (f != d) { post ("packxbee_pack_remote_frame third argument not a positive integer from 0 to 255"); return; } else options = d; if (x->x_verbosity > 0) post("packxbee_pack_remote_frame: options: %d", d); if (argv[3].a_type != A_SYMBOL) { post ("packxbee_pack_remote_frame: argument 4 must be an AT command"); return; } if (x->x_verbosity > 0) post ("packxbee_pack_remote_frame: argument 4 is %s", argv[3].a_w.w_symbol->s_name); if (2 != strlen(argv[3].a_w.w_symbol->s_name)) { post ("packxbee_pack_remote_frame: argument 4 must be a two-character AT command"); return; } if (((argv[3].a_w.w_symbol->s_name[0] < 0x20) || (argv[3].a_w.w_symbol->s_name[0] & 0x80)) || ((argv[3].a_w.w_symbol->s_name[1] < 0x20) || (argv[3].a_w.w_symbol->s_name[1] & 0x80))) { post ("packxbee_pack_remote_frame: argument 4 must be printable ascii"); return; } /* parameters seem valid, now build the frame */ i = 0; floatstring[i++] = XFRAME; /* as usual */ floatstring[i++] = 0; /* length MSB */ floatstring[i++] = 0;/* length LSB */ floatstring[i++] = x->x_frameType; checksum -= x->x_frameType; if (0 == x->x_frameID) x->x_frameID++; /* never use zero as frame ID */ floatstring[i] = x->x_frameID++; checksum -= floatstring[i++]; /* raw 8 byte address in big-endian order: */ floatstring[i] = (dest64>>56)&0x0FF; checksum -= floatstring[i++]; floatstring[i] = (dest64>>48)&0x0FF; checksum -= floatstring[i++]; floatstring[i] = (dest64>>40)&0x0FF; checksum -= floatstring[i++]; floatstring[i] = (dest64>>32)&0x0FF; checksum -= floatstring[i++]; floatstring[i] = (dest64>>24)&0x0FF; checksum -= floatstring[i++]; floatstring[i] = (dest64>>16)&0x0FF; checksum -= floatstring[i++]; floatstring[i] = (dest64>>8)&0x0FF; checksum -= floatstring[i++]; floatstring[i] = (dest64)&0x0FF; checksum -= floatstring[i++]; floatstring[i] = (dest16>>8)&0x0FF; checksum -= floatstring[i++]; floatstring[i] = (dest16)&0x0FF; checksum -= floatstring[i++]; floatstring[i] = options; checksum -= floatstring[i++]; c = argv[3].a_w.w_symbol->s_name[0];/* the first character of the AT command */ floatstring[i] = c; checksum -= floatstring[i++]; c = argv[3].a_w.w_symbol->s_name[1];/* the second character of the AT command */ floatstring[i] = c; checksum -= floatstring[i++]; j = i; /* save i in j so we can calculate checksum on any further parameters */ /* parameters if any */ if (argc >= 5) { /* some parameters */ if (argv[4].a_type == A_SYMBOL) { if (x->x_verbosity > 0) post("packxbee_pack_remote_frame symbol parameter %s", argv[4].a_w.w_symbol->s_name); if (('0' == argv[4].a_w.w_symbol->s_name[0])&&(('x' == argv[4].a_w.w_symbol->s_name[1]))) { /* this is a hexadecimal number: copy to the buffer as raw binary */ result = sscanf(argv[4].a_w.w_symbol->s_name, "0x%X", &d); if (result == 0) { post("packxbee_pack_remote_frame: argument 4 is not a hex string"); } else { // put the significant part of the raw value into floatstring in big endian order if (0 != ((d>>24) & 0x0FF)) digits = 4; else if (0 != ((d>>16) & 0x0FF)) digits = 3; else if (0 != ((d>>8) & 0x0FF)) digits = 2; else digits = 1; if (4 == digits) floatstring[i++] = (d>>24) & 0x0FF; if (3 <= digits) floatstring[i++] = (d>>16) & 0x0FF; if (2 <= digits) floatstring[i++] = (d>>8) & 0x0FF; floatstring[i++] = d & 0x0FF; } } else // if ((0 == strncmp("NI", argv[0].a_w.w_symbol->s_name, 2))||(0 == strncmp("DN", argv[0].a_w.w_symbol->s_name, 2))) { /* we hope it's just an ascii string for the NI command */ for (k = 0; (k < 20); ++k) /* no more than 20 characters in a node identifier */ { c = argv[4].a_w.w_symbol->s_name[k]; if (0 == c) break; floatstring[i++] = c; } } } else if (argv[4].a_type == A_FLOAT) { f = argv[4].a_w.w_float; if (x->x_verbosity > 0) post("packxbee_pack_remote_frame float parameter %f", f); d = (unsigned int)f; if (f != d) { post ("packxbee_pack_remote_frame parameter not an integer"); } else { // put the significant part of the raw value into floatstring in big endian order if (0 != ((d>>24) & 0x0FF)) digits = 4; else if (0 != ((d>>16) & 0x0FF)) digits = 3; else if (0 != ((d>>8) & 0x0FF)) digits = 2; else digits = 1; if (4 == digits) floatstring[i++] = (d>>24) & 0x0FF; if (3 <= digits) floatstring[i++] = (d>>16) & 0x0FF; if (2 <= digits) floatstring[i++] = (d>>8) & 0x0FF; floatstring[i++] = d & 0x0FF; } } else { post("packxbee_pack_remote_frame parameter not symbol or float: ignoring"); } maxdigits = 32; /* the longest possible hex string is for the encryption key */ /* we leave it up to the user to send the correct values */ if (j != i) { /* update the checksum */ for (; ((j < maxdigits)&&(j < i)); ++j) { c = floatstring[j]; if (0 == c) break; checksum -= c; } } } /* argc >= 5 */ } /* argc >= 4 */ else { error("packxbee_pack_remote_frame: not enough parameters"); return; } length = i-3; floatstring[LENGTH_LSB_INDEX] = length & 0x0FF; floatstring[LENGTH_MSB_INDEX] = length >> 8; floatstring[i++] = checksum; k = j = 0; /* j indexes the outbuf, k indexes the floatbuf, i is the length of floatbuf */ for (k = 0; k < i; ++k) j = packxbee_outbuf_add(x, j, floatstring[k]); outlet_list(x->x_listout, &s_list, j, x->x_outbuf); if(x->x_verbosity > 1) { for (k = 0; k < j; ++k) { c = (unsigned char)atom_getfloat(&x->x_outbuf[k]); post("buf[%d]: %d [0x%02X]", k, c, c); } } } static void packxbee_pack_frame(t_packxbee *x, t_symbol *s, int argc, t_atom *argv) { int i, j, k, maxdigits, d; char checksum = 0xFF; unsigned char floatstring[256]; /* longer than the longest hex number with each character escaped plus the header and checksum overhead */ int length = 0; unsigned char c, digits; int result; t_float f; if (x->x_verbosity > 0) post("packxbee_AT s is %s, argc is %d", s->s_name, argc); if (argc >= 1) { if (argv[0].a_type != A_SYMBOL) { post ("packxbee_AT: argument 1 must be an AT command"); return; } if (x->x_verbosity > 0) post ("packxbee_AT: argument 1 is %s", argv[0].a_w.w_symbol->s_name); if (2 != strlen(argv[0].a_w.w_symbol->s_name)) { post ("packxbee_AT: argument 1 must be a two-character AT command"); return; } if (((argv[0].a_w.w_symbol->s_name[0] < 0x20) || (argv[0].a_w.w_symbol->s_name[0] & 0x80)) || ((argv[0].a_w.w_symbol->s_name[1] < 0x20) || (argv[0].a_w.w_symbol->s_name[1] & 0x80))) { post ("packxbee_AT: argument 1 must be printable ascii"); return; } i = 0; floatstring[i++] = XFRAME; /* as usual */ floatstring[i++] = 0; /* length MSB */ floatstring[i++] = 0;/* length LSB */ floatstring[i] = x->x_frameType; checksum -= floatstring[i++]; if (0 == x->x_frameID) x->x_frameID++; floatstring[i] = x->x_frameID++; checksum -= floatstring[i++]; c = argv[0].a_w.w_symbol->s_name[0];/* the first character of the AT command */ floatstring[i] = c; checksum -= floatstring[i++]; c = argv[0].a_w.w_symbol->s_name[1];/* the second character of the AT command */ floatstring[i] = c; checksum -= floatstring[i++]; j = i; /* store i in j to see if anything gets added later and we need to update the checksum */ /* parameters if any */ if (argc >= 2) { /* some parameters */ if (argv[1].a_type == A_SYMBOL) { if (x->x_verbosity > 0) post("packxbee_AT symbol parameter %s", argv[1].a_w.w_symbol->s_name); if (('0' == argv[1].a_w.w_symbol->s_name[0])&&(('x' == argv[1].a_w.w_symbol->s_name[1]))) { /* this is a hexadecimal number: strip the "0x" and copy the rest to the buffer as ascii digits */ result = sscanf(argv[1].a_w.w_symbol->s_name, "0x%X", &d); if (result == 0) { post("packxbee_pack_remote_frame: argument 1 is not a hex string"); } else { // put the significant part of the raw value into floatstring in big endian order if (0 != ((d>>24) & 0x0FF)) digits = 4; else if (0 != ((d>>16) & 0x0FF)) digits = 3; else if (0 != ((d>>8) & 0x0FF)) digits = 2; else digits = 1; if (4 == digits) floatstring[i++] = (d>>24) & 0x0FF; if (3 <= digits) floatstring[i++] = (d>>16) & 0x0FF; if (2 <= digits) floatstring[i++] = (d>>8) & 0x0FF; floatstring[i++] = d & 0x0FF; } } else // if ((0 == strncmp("NI", argv[0].a_w.w_symbol->s_name, 2))||(0 == strncmp("DN", argv[0].a_w.w_symbol->s_name, 2))) { /* we hope it's just an ascii string for the NI command */ for (k = 0; (k < 20); ++k) /* no more than 20 characters in a node identifier */ { c = argv[1].a_w.w_symbol->s_name[k]; if (0 == c) break; floatstring[i++] = c; } } } else if (argv[1].a_type == A_FLOAT) { f = argv[1].a_w.w_float; if (x->x_verbosity > 0) post("packxbee_AT float parameter %f", f); d = (unsigned int)f; if (f != d) { post ("packxbee_AT parameter not an integer"); } else { // put the significant part of the raw value into floatstring in big endian order if (0 != ((d>>24) & 0x0FF)) digits = 4; else if (0 != ((d>>16) & 0x0FF)) digits = 3; else if (0 != ((d>>8) & 0x0FF)) digits = 2; else digits = 1; if (4 == digits) floatstring[i++] = (d>>24) & 0x0FF; if (3 <= digits) floatstring[i++] = (d>>16) & 0x0FF; if (2 <= digits) floatstring[i++] = (d>>8) & 0x0FF; floatstring[i++] = d & 0x0FF; } } else { post("packxbee_AT parameter not symbol or float: ignoring"); } maxdigits = 32; /* the longest possible hex string is for the encryption key */ /* we leave it up to the user to send the correct values */ /* if anything was added to floatstring, calculate the checksum on it */ /* update the checksum */ if (j != i) { for (; ((j < maxdigits)&&(j < i)); ++j) { c = floatstring[j]; if (0 == c) break; checksum -= c; } } } /* argc >= 2 */ length = i-3; floatstring[LENGTH_LSB_INDEX] = length & 0x0FF; floatstring[LENGTH_MSB_INDEX] = length >> 8; floatstring[i++] = checksum; k = j = 0; /* j indexes the outbuf, k indexes the floatbuf, i is the length of floatbuf */ for (k = 0; k < i; ++k) j = packxbee_outbuf_add(x, j, floatstring[k]); outlet_list(x->x_listout, &s_list, j, x->x_outbuf); if(x->x_verbosity > 1) { for (k = 0; k < j; ++k) { c = (unsigned char)atom_getfloat(&x->x_outbuf[k]); post("buf[%d]: %d [0x%02X]", k, c, c); } } } /* argc >= 1 */ } static void packxbee_free(t_packxbee *x) { /* free any memory we allocated */ /* stop any callbacks */ } void packxbee_setup(void) { packxbee_class = class_new(gensym("packxbee"), (t_newmethod)packxbee_new, (t_method)packxbee_free, sizeof(t_packxbee), 0, A_DEFFLOAT, 0); class_addmethod(packxbee_class, (t_method)packxbee_AT, gensym("AT"), A_GIMME, 0); class_addmethod(packxbee_class, (t_method)packxbee_ATQ, gensym("ATQ"), A_GIMME, 0); class_addmethod(packxbee_class, (t_method)packxbee_RAT, gensym("RAT"), A_GIMME, 0); class_addmethod(packxbee_class, (t_method)packxbee_TX, gensym("TX"), A_GIMME, 0); class_addmethod(packxbee_class, (t_method)packxbee_TX64, gensym("TX64"), A_GIMME, 0); class_addmethod(packxbee_class, (t_method)packxbee_TX16, gensym("TX16"), A_GIMME, 0); class_addmethod(packxbee_class, (t_method)packxbee_API, gensym("API"), A_DEFFLOAT, 0); class_addmethod(packxbee_class, (t_method)packxbee_verbosity, gensym("verbosity"), A_DEFFLOAT, 0); } /* fin packxbee.c*/ mrpeach/xbee/unpackxbee-help.pd0000644000175000017500000002411212120117057017246 0ustar zmoelnigzmoelnig#N canvas 26 77 1250 833 10; #X declare -lib mrpeach; #X obj -15 0 cnv 15 600 240 empty empty empty 20 12 0 14 -262130 -66577 0; #X obj -15 239 cnv 15 1400 550 empty empty unpackxbee_status: 1 12 0 14 -203904 -159808 0; #X msg 280 103 verbosity \$1; #X obj 280 82 hradio 15 1 0 3 empty empty verbosity 0 -8 0 10 -4034 -1 -1 0; #X obj 330 170 unpackxbee 2; #X obj 591 6 import mrpeach; #N canvas 771 111 381 332 META 1; #X text 22 55 LICENSE GPL v2 or later; #X text 22 183 AUTHOR Martin Peach; #X text 22 15 KEYWORDS control network wireless xbee; #X text 22 203 HELP_PATCH_AUTHORS Martin Peach; #X text 22 35 NAME unpackxbee; #X text 22 75 DESCRIPTION [unpackxbee] unpacks packets from xbees in API modes 1 or 2; #X text 22 110 INLET_0 list; #X text 23 125 OUTLET_0 list data; #X text 23 145 OUTLET_1 list sample frame; #X text 23 165 OUTLET_2 list status; #X restore 634 26 pd META; #X obj 330 130 comport 98 9600; #X text 27 5 [unpackxbee] is used to unpack API mode 1 or 2 packets received from xbees. Usually the output of a [comport] object is connected to the inlet.; #X text 26 53 Packet status comes out the right \, data is emitted from the left outlet.; #X floatatom 174 441 5 0 0 0 - - -; #X obj 244 322 print unpack5; #X obj 63 269 route AT_Command_Response; #X obj 63 305 list split 3; #X obj 174 343 list trim; #X symbolatom 191 457 7 0 0 0 - - -; #X symbolatom 209 474 20 0 0 0 - - -; #X obj 63 343 unpack 0 0 0; #X floatatom 63 367 5 0 0 0 - - -; #X floatatom 97 387 5 0 0 0 - - -; #X floatatom 132 407 5 0 0 0 - - -; #X text -11 367 packet type; #X text 29 387 packet ID; #X text 54 406 data length; #X text 61 438 AT command status; #X text 145 456 addr16; #X text 165 472 addr64; #X obj 408 286 route ZigBee_Transmit_Status; #X floatatom 408 328 5 0 0 0 - - -; #X floatatom 429 346 5 0 0 0 - - -; #X text 334 328 packet type; #X text 361 346 packet ID; #X symbolatom 450 363 7 0 0 0 - - -; #X text 407 362 addr16; #X floatatom 513 415 5 0 0 0 - - -; #X floatatom 492 398 5 0 0 0 - - -; #X floatatom 471 381 5 0 0 0 - - -; #X text 340 379 transmit retry count; #X text 391 396 delivery status; #X text 407 413 discovery status; #X symbolatom 226 491 32 0 0 0 - - -; #X symbolatom 244 509 7 0 0 0 - - -; #X symbolatom 297 562 7 0 0 0 - - -; #X symbolatom 315 580 7 0 0 0 - - -; #X obj 174 419 unpack 0 s s s s 0 0 s s; #X floatatom 262 527 5 0 0 0 - - -; #X floatatom 279 544 5 0 0 0 - - -; #X text 129 490 Node Identifier; #X text 197 508 parent; #X text 187 524 device type; #X text 199 542 source event; #X text 242 560 profile; #X text 237 578 manufacturer; #X obj 408 308 unpack 0 0 s 0 0 0; #X obj 596 303 route ZigBee_Receive_Packet; #X obj 1101 337 print someotherpacket; #X symbolatom 665 400 7 0 0 0 - - -; #X symbolatom 642 382 17 0 0 0 - - -; #X text 619 399 addr16; #X text 598 380 addr64; #X floatatom 596 346 5 0 0 0 - - -; #X text 522 346 packet type; #X floatatom 689 418 5 0 0 0 - - -; #X text 590 416 receive options; #X obj 689 468 tgl 15 0 empty empty acknowledged 17 7 0 10 -4034 -1 -1 0 1; #X obj 729 488 tgl 15 0 empty empty broadcast 17 7 0 10 -4034 -1 -1 0 1; #X obj 769 508 tgl 15 0 empty empty encrypted 17 7 0 10 -4034 -1 -1 0 1; #X obj 809 528 tgl 15 0 empty empty from_end_device 17 7 0 10 -4034 -1 -1 0 1; #X obj 689 432 & 1; #X obj 729 432 & 2; #X obj 769 432 & 32; #X obj 809 432 & 64; #X obj 596 324 unpack 0 0 s s 0; #X floatatom 619 363 5 0 0 0 - - -; #X text 545 363 data length; #X obj 491 437 select 0 2 21 33 34 35 36 37; #X symbolatom 491 634 32 0 0 0 - - -; #X msg 491 461 set success; #X msg 656 619 set unknown; #X msg 511 480 set CCA_failurs; #X msg 552 520 set Network_ACK_Failure; #X msg 532 500 set Invalid_Destination_Endpoint; #X msg 573 540 set Not_Joined_To_Network; #X msg 592 560 set Self-Addresed; #X msg 614 579 set Address_Not_Found; #X msg 635 599 set Route_Not_Found; #X text 388 633 delivery status:; #X symbolatom 512 770 32 0 0 0 - - -; #X msg 593 755 set unknown; #X obj 512 658 select 0 1 2 3; #X msg 512 679 set No_Discovery_Overhead; #X msg 532 698 set Address_Discovery; #X msg 553 717 set Route_Discovery; #X msg 573 736 set Address_And_Route_Discovery; #X text 408 768 discovery status:; #X obj 856 320 route Remote_Command_Response; #X floatatom 856 373 5 0 0 0 - - -; #X floatatom 875 395 5 0 0 0 - - -; #X text 782 373 packet type; #X text 807 395 packet ID; #X floatatom 973 502 5 0 0 0 - - -; #X symbolatom 895 435 20 0 0 0 - - -; #X text 851 433 addr64; #X symbolatom 914 416 7 0 0 0 - - -; #X symbolatom 934 457 7 0 0 0 - - -; #X text 888 456 command; #X floatatom 953 479 5 0 0 0 - - -; #X text 903 503 data length; #X text 911 479 status; #X obj 856 347 unpack 0 0 s s s 0 0; #X obj 237 390 print AT_response; #X text 868 415 addr16; #X obj 1021 383 select 0 1 2 3 4; #X symbolatom 1021 583 32 0 0 0 - - -; #X text 978 582 delivery status:; #X msg 1021 410 set OK; #X msg 1039 430 set ERROR; #X msg 1058 449 set Invalid_Command; #X msg 1077 469 set Invalid_Parameter; #X msg 1095 492 set Transmission_Failed; #X obj 174 365 route ND SL; #X obj 51 532 print SL; #X obj 330 216 print unpackxbee_data; #X obj 462 187 print unpackxbee_status; #X text 645 195 Martin Peach 2013_03_13; #N canvas 4 77 541 300 sample_frame 0; #X obj 32 23 inlet; #X obj 32 76 route D0 D1 D2 D3 D4 D5 D10 D11 D12 A0 A1 A2 A3 A7; #X obj 26 106 cnv 15 300 50 empty empty Digital_Inputs 20 12 0 14 -204786 -13381 0; #X obj 26 157 cnv 15 400 90 empty empty Analog_Inputs 20 12 0 14 -232576 -45076 0; #X obj 29 190 nbx 5 14 -1e+37 1e+37 0 0 empty empty A0 40 8 0 10 -204800 -13330 -159808 0 256; #X obj 89 190 nbx 5 14 -1e+37 1e+37 0 0 empty empty A1 40 8 0 10 -204800 -13330 -159808 0 256; #X obj 149 190 nbx 5 14 -1e+37 1e+37 0 0 empty empty A2 40 8 0 10 -204800 -13330 -159808 0 256; #X obj 209 190 nbx 5 14 -1e+37 1e+37 0 0 empty empty A3 40 8 0 10 -204800 -13330 -159808 0 256; #X obj 269 190 nbx 5 14 -1e+37 1e+37 0 0 empty empty V+ 40 8 0 10 -204800 -13330 -159808 0 256; #X obj 32 132 nbx 2 14 -1e+37 1e+37 0 0 empty empty D0 8 20 0 10 -4034 -1 -258113 0 256; #X obj 72 132 nbx 2 14 -1e+37 1e+37 0 0 empty empty D1 8 20 0 10 -4034 -1 -258113 0 256; #X obj 102 132 nbx 2 14 -1e+37 1e+37 0 0 empty empty D2 8 20 0 10 -4034 -1 -258113 0 256; #X obj 132 132 nbx 2 14 -1e+37 1e+37 0 0 empty empty D3 8 20 0 10 -4034 -1 -258113 0 256; #X obj 162 132 nbx 2 14 -1e+37 1e+37 0 0 empty empty D4 8 20 0 10 -4034 -1 -258113 0 256; #X obj 192 132 nbx 2 14 -1e+37 1e+37 0 0 empty empty D5 8 20 0 10 -4034 -1 -258113 0 256; #X obj 222 132 nbx 2 14 -1e+37 1e+37 0 0 empty empty P0 8 20 0 10 -4034 -1 -258113 0 256; #X obj 252 132 nbx 2 14 -1e+37 1e+37 0 0 empty empty P1 8 20 0 10 -4034 -1 -258113 0 256; #X obj 282 132 nbx 2 14 -1e+37 1e+37 0 0 empty empty P2 8 20 0 10 -4034 -1 -258113 0 256; #X obj 29 229 nbx 5 14 -1e+37 1e+37 0 0 empty empty A0_mV 40 8 0 10 -204800 -13330 -159808 0 256; #X obj 29 209 * 1.17302; #X obj 109 229 nbx 5 14 -1e+37 1e+37 0 0 empty empty A1_mV 40 8 0 10 -204800 -13330 -159808 0 256; #X obj 109 209 * 1.17302; #X obj 189 229 nbx 5 14 -1e+37 1e+37 0 0 empty empty A2_mV 40 8 0 10 -204800 -13330 -159808 0 256; #X obj 189 209 * 1.17302; #X obj 269 229 nbx 5 14 -1e+37 1e+37 0 0 empty empty A3_mV 40 8 0 10 -204800 -13330 -159808 0 256; #X obj 269 209 * 1.17302; #X obj 349 229 nbx 5 14 -1e+37 1e+37 0 0 empty empty V+_mV 40 8 0 10 -204800 -13330 -159808 0 256; #X obj 349 209 * 1.17302; #X obj 32 48 list trim; #X obj 329 100 print more_sample_frame_stuff; #X connect 0 0 28 0; #X connect 1 0 9 0; #X connect 1 1 10 0; #X connect 1 2 11 0; #X connect 1 3 12 0; #X connect 1 4 13 0; #X connect 1 5 14 0; #X connect 1 6 15 0; #X connect 1 7 16 0; #X connect 1 8 17 0; #X connect 1 9 4 0; #X connect 1 9 19 0; #X connect 1 10 5 0; #X connect 1 10 21 0; #X connect 1 11 6 0; #X connect 1 11 23 0; #X connect 1 12 7 0; #X connect 1 12 25 0; #X connect 1 13 8 0; #X connect 1 13 27 0; #X connect 1 14 29 0; #X connect 19 0 18 0; #X connect 21 0 20 0; #X connect 23 0 22 0; #X connect 25 0 24 0; #X connect 27 0 26 0; #X connect 28 0 1 0; #X restore 364 197 pd sample_frame; #X connect 2 0 4 0; #X connect 3 0 2 0; #X connect 4 0 122 0; #X connect 4 1 125 0; #X connect 4 2 123 0; #X connect 4 2 12 0; #X connect 7 0 4 0; #X connect 12 0 13 0; #X connect 12 1 27 0; #X connect 13 0 17 0; #X connect 13 1 14 0; #X connect 13 2 11 0; #X connect 14 0 120 0; #X connect 17 0 18 0; #X connect 17 1 19 0; #X connect 17 2 20 0; #X connect 27 0 53 0; #X connect 27 1 54 0; #X connect 44 0 10 0; #X connect 44 1 15 0; #X connect 44 2 16 0; #X connect 44 3 40 0; #X connect 44 4 41 0; #X connect 44 5 45 0; #X connect 44 6 46 0; #X connect 44 7 42 0; #X connect 44 8 43 0; #X connect 53 0 28 0; #X connect 53 1 29 0; #X connect 53 2 32 0; #X connect 53 3 36 0; #X connect 53 4 35 0; #X connect 53 4 75 0; #X connect 53 5 34 0; #X connect 53 5 89 0; #X connect 54 0 72 0; #X connect 54 1 95 0; #X connect 62 0 68 0; #X connect 62 0 69 0; #X connect 62 0 70 0; #X connect 62 0 71 0; #X connect 68 0 64 0; #X connect 69 0 65 0; #X connect 70 0 66 0; #X connect 71 0 67 0; #X connect 72 0 60 0; #X connect 72 1 73 0; #X connect 72 2 57 0; #X connect 72 3 56 0; #X connect 72 4 62 0; #X connect 75 0 77 0; #X connect 75 1 79 0; #X connect 75 2 81 0; #X connect 75 3 80 0; #X connect 75 4 82 0; #X connect 75 5 83 0; #X connect 75 6 84 0; #X connect 75 7 85 0; #X connect 75 8 78 0; #X connect 77 0 76 0; #X connect 78 0 76 0; #X connect 79 0 76 0; #X connect 80 0 76 0; #X connect 81 0 76 0; #X connect 82 0 76 0; #X connect 83 0 76 0; #X connect 84 0 76 0; #X connect 85 0 76 0; #X connect 88 0 87 0; #X connect 89 0 90 0; #X connect 89 1 91 0; #X connect 89 2 92 0; #X connect 89 3 93 0; #X connect 89 4 88 0; #X connect 90 0 87 0; #X connect 91 0 87 0; #X connect 92 0 87 0; #X connect 93 0 87 0; #X connect 95 0 109 0; #X connect 95 1 55 0; #X connect 109 0 96 0; #X connect 109 1 97 0; #X connect 109 2 101 0; #X connect 109 3 103 0; #X connect 109 4 104 0; #X connect 109 5 106 0; #X connect 109 5 112 0; #X connect 109 6 100 0; #X connect 112 0 115 0; #X connect 112 1 116 0; #X connect 112 2 117 0; #X connect 112 3 118 0; #X connect 112 4 119 0; #X connect 115 0 113 0; #X connect 116 0 113 0; #X connect 117 0 113 0; #X connect 118 0 113 0; #X connect 119 0 113 0; #X connect 120 0 44 0; #X connect 120 1 121 0; #X connect 120 2 110 0; mrpeach/xbee/pdxbee.h0000644000175000017500000000421712222625545015303 0ustar zmoelnigzmoelnig#ifndef _PDXBEE #define _PDXBEE // MAX_XBEE_PACKET_LENGTH is around 80 #define MAX_XBEE_PACKET_LENGTH 128 #define LENGTH_MSB_INDEX 1 /* offset in x_outbuf */ #define LENGTH_LSB_INDEX 2 /* offset in x_outbuf */ #define FRAME_TYPE_INDEX 3 /* offset in x_outbuf */ #define FRAME_ID_INDEX 4 /* offset in x_outbuf */ #define AT_COMMAND_INDEX 5 /* offset in x_outbuf */ #define AT_PARAMETER_INDEX 6 /* offset in x_outbuf */ /* API Frame Names and Values */ #define Transmit_Request_64_Bit_Address 0x00 #define Transmit_Request_16_bit_Address 0x01 #define AT_Command 0x08 #define AT_Command_Queue_Parameter_Value 0x09 #define ZigBee_Transmit_Request 0x10 #define Explicit_Addressing_ZigBee_Command_Frame 0x11 #define Remote_Command_Request 0x17 #define Create_Source_Route 0x21 #define Receive_Packet_64_Bit_Address 0x80 #define Receive_Packet_16_Bit_Address 0x81 #define Receive_Packet_64_Bit_Address_IO 0x82 #define Receive_Packet_16_Bit_Address_IO 0x83 #define AT_Command_Response 0x88 #define Transmit_Status 0x89 #define Modem_Status 0x8A #define ZigBee_Transmit_Status 0x8B #define ZigBee_Receive_Packet 0x90 #define ZigBee_Explicit_Rx_Indicator 0x91 #define ZigBee_IO_Data_Sample_Rx_Indicator 0x92 #define XBee_Sensor_Read_Indicator 0x94 #define Node_Identification_Indicator 0x95 #define Remote_Command_Response 0x97 #define Over_the_Air_Firmware_Update_Status 0xA0 #define Route_Record_Indicator 0xA1 #define Many_to_One_Route_Request_Indicator 0xA3 /* if API mode is 2 all characters after the first are escaped if they are one of */ #define XFRAME 0x7E /* Frame Delimiter */ #define XSCAPE 0x7D /* Escape */ #define XON 0x11 /* XON */ #define XOFF 0x13 /* XOFF */ /* to escape the character prefix it with XSCAPE and XOR it with 0x20 */ #endif /* _PDXBEE */ mrpeach/xbee/packxbee-example.pd0000644000175000017500000001013712424230076017414 0ustar zmoelnigzmoelnig#N canvas 300 169 770 718 10; #X text 84 159 data packet: 64-bit_destination 16-bit_destination broadcast_radius options data; #X obj 80 115 hsl 128 15 0 127 0 0 empty empty empty -2 -8 0 10 -262144 -1 -1 5800 0; #X obj 77 134 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -8 0 10 -262144 -1 -1 58 256; #X obj 77 10 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1 ; #X obj 77 247 packxbee 2; #X msg 49 309 devices; #X obj 77 354 comport 4 9600; #X msg 6 266 info; #X msg 28 288 open 4; #X obj 77 424 print data; #X obj 77 396 unpackxbee 2; #X obj 77 30 metro 500; #X obj 77 58 random 32; #X obj 77 88 + 32; #X floatatom 146 470 5 0 0 0 - - -; #X floatatom 167 490 5 0 0 0 - - -; #X symbolatom 188 510 10 0 0 0 - - -; #X floatatom 209 530 5 0 0 0 - - -; #X floatatom 230 550 5 0 0 0 - - -; #X obj 590 470 print other_status; #X floatatom 251 571 5 0 0 0 - - -; #X text 109 489 packet_#; #X text 23 509 destination 16-bit address; #X text 103 529 transmit_retries; #X text 131 549 delivery_status; #X obj 146 448 unpack 0 0 s 0 0 0; #X text 146 570 discovery_status; #X floatatom 128 8 10 0 0 0 - - -; #X floatatom 294 597 5 0 0 0 - - -; #X floatatom 317 618 5 0 0 0 - - -; #X symbolatom 340 638 20 0 0 0 - - -; #X floatatom 387 679 5 0 0 0 - - -; #X text 259 617 packet_#; #X symbolatom 363 658 10 0 0 0 - - -; #X text 195 637 sender's 64-bit address; #X text 217 657 sender's 16-bit address; #X obj 294 448 unpack 0 0 s s 0; #X text 288 678 receive options; #X text 46 469 frame_type (139); #X text 194 596 frame_type (144); #X msg 18 171 AT AI; #X obj 146 424 route ZigBee_Transmit_Status ZigBee_Receive_Packet; #X obj 443 448 route AT_Command_Response; #X floatatom 443 492 5 0 0 0 - - -; #X floatatom 462 512 5 0 0 0 - - -; #X text 406 511 packet_#; #X obj 443 470 unpack 0 0 0 s 0 0 0; #X floatatom 482 532 5 0 0 0 - - -; #X symbolatom 501 550 5 0 0 0 - - -; #X text 434 549 AT command; #X floatatom 521 572 5 0 0 0 - - -; #X floatatom 540 592 5 0 0 0 - - -; #X text 484 591 packet_#; #X floatatom 560 612 5 0 0 0 - - -; #X text 494 611 data bytes; #X text 416 531 data_bytes; #X text 343 491 frame_type (136); #X text 476 571 status; #X msg 304 379 verbosity \$1; #X obj 304 352 hradio 15 1 0 3 empty empty empty 0 -8 0 10 -4034 -204786 -1 0; #X text 188 53 This example transmits a single byte of "data" through an xbee in API mode 2 connected to serial port 4 at 9600 baud.; #X msg 77 211 TX 0x0013A200406BFD76 0xFA99 0 0 \$1; #X msg 480 171 TX 0x0013A200406BFEDF 0x1100 0 0 \$1; #X text 700 172 yellow; #X text 297 210 green; #X text 700 148 blue; #X msg 516 230 verbosity \$1; #X obj 516 203 hradio 15 1 0 3 empty empty empty 0 -8 0 10 -4034 -204786 -1 0; #X text 439 679 Martin Peach 2014_10_29; #X msg 480 147 TX 0x0013A200406BFE6C 0x9ED2 0 0 \$1; #X text 700 124 blue; #X msg 480 123 TX 0x0013A200406BFE6C 0xFFFE 0 0 \$1; #X text 83 184 The destination xbee 64-bit address and the 16-bit address must be set first (16-bit address can be 0xFFFE if unknown):; #X obj 157 375 print comport_status; #X msg 70 330 ports; #X text 108 329 <-list available serial ports via outlet 2; #X text 38 267 <-list current serial port state via outlet 2; #X text 98 309 <-list available serial ports in console window; #X connect 1 0 2 0; #X connect 2 0 61 0; #X connect 3 0 11 0; #X connect 4 0 6 0; #X connect 5 0 6 0; #X connect 6 0 10 0; #X connect 6 1 73 0; #X connect 7 0 6 0; #X connect 8 0 6 0; #X connect 10 0 9 0; #X connect 10 2 41 0; #X connect 11 0 12 0; #X connect 12 0 13 0; #X connect 13 0 1 0; #X connect 25 0 14 0; #X connect 25 1 15 0; #X connect 25 2 16 0; #X connect 25 3 17 0; #X connect 25 4 18 0; #X connect 25 5 20 0; #X connect 27 0 11 1; #X connect 36 0 28 0; #X connect 36 1 29 0; #X connect 36 2 30 0; #X connect 36 3 33 0; #X connect 36 4 31 0; #X connect 40 0 4 0; #X connect 41 0 25 0; #X connect 41 1 36 0; #X connect 41 2 42 0; #X connect 42 0 46 0; #X connect 42 1 19 0; #X connect 46 0 43 0; #X connect 46 1 44 0; #X connect 46 2 47 0; #X connect 46 3 48 0; #X connect 46 4 50 0; #X connect 46 5 51 0; #X connect 46 6 53 0; #X connect 58 0 10 0; #X connect 59 0 58 0; #X connect 61 0 4 0; #X connect 66 0 4 0; #X connect 67 0 66 0; #X connect 74 0 6 0; mrpeach/xbee/xbeeio.pd0000644000175000017500000007751712424234300015465 0ustar zmoelnigzmoelnig#N canvas 263 330 984 636 10; #X obj -4 -46 cnv 15 220 380 empty empty Get_Current_IO_Parameters 20 12 0 14 -204800 -13330 0; #X text 2 457 remote AT command: 64-bit address \, 16-bit address \, options \, command \, parameters; #X msg 292 136 RAT 0x0013A200406BFE6C 0x9A17 2 D0 4; #X obj 383 244 packxbee 2; #X msg 355 306 devices; #X obj 383 351 comport 4 9600; #X msg 312 263 info; #X msg 334 285 open 4; #X obj 407 305 print data; #X obj 383 393 unpackxbee 2; #X obj 464 398 print status; #X floatatom 759 483 5 0 0 0 - - -; #X floatatom 780 503 5 0 0 0 - - -; #X symbolatom 801 523 10 0 0 0 - - -; #X floatatom 822 543 5 0 0 0 - - -; #X floatatom 843 563 5 0 0 0 - - -; #X obj 1557 502 print other_status; #X floatatom 864 584 5 0 0 0 - - -; #X text 722 502 packet_#; #X text 636 522 destination 16-bit address; #X text 716 542 transmit_retries; #X text 744 562 delivery_status; #X obj 759 461 unpack 0 0 s 0 0 0; #X text 759 583 discovery_status; #X floatatom 907 610 5 0 0 0 - - -; #X floatatom 930 631 5 0 0 0 - - -; #X symbolatom 953 651 20 0 0 0 - - -; #X floatatom 1000 692 5 0 0 0 - - -; #X text 872 630 packet_#; #X symbolatom 976 671 10 0 0 0 - - -; #X text 808 650 sender's 64-bit address; #X text 830 670 sender's 16-bit address; #X obj 907 461 unpack 0 0 s s 0; #X text 901 691 receive options; #X text 659 482 frame_type (139); #X text 807 609 frame_type (144); #X msg 324 168 AT AI; #X obj 759 437 route ZigBee_Transmit_Status ZigBee_Receive_Packet; #X obj 1056 461 route AT_Command_Response; #X floatatom 1056 505 5 0 0 0 - - -; #X floatatom 1075 525 5 0 0 0 - - -; #X text 1019 524 packet_#; #X obj 1056 483 unpack 0 0 0 s 0 0 0; #X floatatom 1095 545 5 0 0 0 - - -; #X symbolatom 1114 563 5 0 0 0 - - -; #X text 1047 562 AT command; #X floatatom 1134 585 5 0 0 0 - - -; #X floatatom 1153 605 5 0 0 0 - - -; #X text 1097 604 packet_#; #X floatatom 1173 625 5 0 0 0 - - -; #X text 1107 624 data bytes; #X msg 344 188 AT DH; #X text 1029 544 data_bytes; #X text 956 504 frame_type (136); #X text 1089 584 status; #X msg 478 376 verbosity \$1; #X obj 478 357 hradio 15 1 0 3 empty empty empty 0 -8 0 10 -4034 -204786 -1 2; #X text 1052 692 Martin Peach 2013_02_20; #X obj 452 420 route Remote_Command_Response; #X floatatom 452 473 5 0 0 0 - - -; #X floatatom 471 495 5 0 0 0 - - -; #X text 1129 537 packet type; #X text 1154 559 packet ID; #X floatatom 569 602 5 0 0 0 - - -; #X symbolatom 491 535 20 0 0 0 - - -; #X text 447 533 addr64; #X symbolatom 510 516 7 0 0 0 - - -; #X symbolatom 530 557 7 0 0 0 - - -; #X text 484 556 command; #X floatatom 549 579 5 0 0 0 - - -; #X text 499 603 data length; #X text 507 579 status; #X obj 452 447 unpack 0 0 s s s 0 0; #X text 464 515 addr16; #X obj 549 633 select 0 1 2 3 4; #X symbolatom 623 276 32 0 0 0 - - -; #X msg 549 653 set OK; #X msg 567 674 set ERROR; #X msg 586 693 set Invalid_Command; #X msg 605 712 set Invalid_Parameter; #X msg 623 730 set Transmission_Failed; #X msg 463 227 verbosity \$1; #X obj 463 208 hradio 15 1 0 3 empty empty empty 0 -8 0 10 -4034 -204786 -1 0; #X msg 292 243 close; #X msg -1 21 IR; #X msg -1 373 RAT 0x0013A200406BFE6C 0x9A17 0; #X obj -1 395 list append; #X obj -1 416 list trim; #X msg -1 -23 IC; #X obj -1 342 t b a; #X msg -1 131 P0; #X msg -1 154 P1; #X msg -1 176 P2; #X msg -1 198 D0; #X msg -1 219 D1; #X msg -1 241 D2; #X msg -1 263 D3; #X msg -1 285 D4; #X msg -1 306 D5; #X msg -1 -1 LT; #X msg -1 109 PR; #X msg -1 65 RP; #X msg -1 43 %V; #X msg -1 87 V+; #X text 287 -53 This patcher uses the remote AT command message to get and set the I/O pins of a remote xbee; #X obj -2 436 s tox; #X obj 383 217 r tox; #X text 28 20 IO sample rate; #X text 27 42 supply voltage; #X text 27 64 RSSI PWM time; #X text 26 86 Voltage Supply Monitoring; #X text 27 108 Pull-up Resistor bitmap; #X text 27 130 PWM0 (pin 6)function; #X text 27 153 DIO11 (pin 7) function; #X text 27 175 DIO12 (pin 4) function; #X text 26 197 AD0/DIO0 (pin 20) function; #X text 27 218 AD1/DIO1 (pin 19) function; #X text 27 240 AD2/DIO2 (pin 18) function; #X text 27 262 AD3/DIO3 (pin 17) function; #X text 27 284 DIO4 (pin 11) function; #X text 27 305 DIO5 (pin 15) function; #X obj 383 612 list prepend; #X obj 383 636 list trim; #X text 26 -24 I/O Digital Change Detection; #N canvas 74 83 1202 457 remote_status 0; #X obj 228 97 cnv 15 320 130 empty empty I/O_Pin_Function 20 12 0 14 -204786 -13381 0; #X obj 249 330 cnv 15 300 72 empty empty Pull-up_Resistor_Bitmap 4 12 0 14 -204786 -13381 0; #X obj 131 426 cnv 15 300 72 empty empty I/O_Digital_Change_Detection_Bitmap 4 12 0 14 -261682 -86853 0; #X obj 93 -11 inlet; #X obj 152 502 unpack 0 0; #X obj 152 561 +; #X obj 152 584 * 1.17188; #X obj 152 605 nbx 7 14 -1e+37 1e+37 0 0 empty empty mV 56 8 0 10 -4034 -258113 -1 0 256; #X text 386 309 1024/1200:; #X obj 171 36 * 100; #X obj 171 78 nbx 7 14 -1e+37 1e+37 0 0 empty empty ms 56 8 0 10 -4034 -258113 -1 0 256; #X obj 191 623 unpack 0 0; #X obj 191 682 +; #X obj 191 705 * 1.17188; #X obj 191 729 nbx 7 14 -1e+37 1e+37 0 0 empty empty mV 56 8 0 10 -4034 -258113 -1 0 256; #X text -40 56 Associate LED blink time:; #X text 85 77 RSSI PWM time:; #X text 60 602 supply voltage:; #X text -8 727 supply voltage monitor threshold:; #X obj 211 230 unpack 0 0; #X obj 211 289 +; #X text 281 292 Pull-up Resistor bitmap:; #X obj 230 134 vradio 15 1 0 6 P0Val empty P0 0 -8 0 10 -4034 -260097 -1 1; #X obj 250 134 vradio 15 1 0 6 P1Val empty P1 0 -8 0 10 -4034 -260097 -1 0; #X obj 270 134 vradio 15 1 0 6 P2Val empty P2 0 -8 0 10 -4034 -260097 -1 0; #X obj 310 134 vradio 15 1 0 6 D1Val empty D1 0 -8 0 10 -4034 -260097 -1 0; #X obj 330 134 vradio 15 1 0 6 D2Val empty D2 0 -8 0 10 -4034 -260097 -1 0; #X obj 350 134 vradio 15 1 0 6 D3Val empty D3 0 -8 0 10 -4034 -260097 -1 0; #X obj 370 134 vradio 15 1 0 6 D4Val empty D4 0 -8 0 10 -4034 -260097 -1 0; #X obj 390 134 vradio 15 1 0 6 D5Val empty D5 0 -8 0 10 -4034 -260097 -1 1; #X obj 290 134 vradio 15 1 0 6 empty D0Val D0 0 -8 0 10 -4034 -260097 -1 1; #X obj 617 3 print other; #X obj 112 37 * 10; #X obj 112 59 nbx 7 14 -1e+37 1e+37 0 0 empty empty ms 56 8 0 10 -4034 -258113 -1 0 256; #X obj 93 325 unpack 0 0; #X obj 93 384 +; #X obj 251 369 vradio 15 1 0 2 empty empty D7 0 -8 0 10 -4034 -260097 -1 0; #X obj 271 369 vradio 15 1 0 2 empty empty P1 0 -8 0 10 -4034 -260097 -1 1; #X obj 291 369 vradio 15 1 0 2 empty empty P0 0 -8 0 10 -4034 -260097 -1 1; #X obj 311 369 vradio 15 1 0 2 empty empty P2 0 -8 0 10 -4034 -260097 -1 1; #X obj 331 369 vradio 15 1 0 2 empty empty D9 0 -8 0 10 -4034 -260097 -1 1; #X obj 351 369 vradio 15 1 0 2 empty empty D5 0 -8 0 10 -4034 -260097 -1 1; #X obj 371 369 vradio 15 1 0 2 empty empty DI 0 -8 0 10 -4034 -260097 -1 1; #X obj 391 369 vradio 15 1 0 2 empty empty D8 0 -8 0 10 -4034 -260097 -1 1; #X obj 411 369 vradio 15 1 0 2 empty empty D6 0 -8 0 10 -4034 -260097 -1 1; #X obj 431 369 vradio 15 1 0 2 empty empty D0 0 -8 0 10 -4034 -260097 -1 1; #X obj 451 369 vradio 15 1 0 2 empty empty D1 0 -8 0 10 -4034 -260097 -1 1; #X obj 491 369 vradio 15 1 0 2 empty empty D3 0 -8 0 10 -4034 -260097 -1 1; #X obj 511 369 vradio 15 1 0 2 empty empty D4 0 -8 0 10 -4034 -260097 -1 1; #X obj 471 369 vradio 15 1 0 2 empty empty D2 0 -8 0 10 -4034 -260097 -1 1; #X obj 211 311 bits xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ; #X obj 133 465 vradio 15 1 0 2 empty empty D7 0 -8 0 10 -4034 -260097 -1 0; #X obj 153 465 vradio 15 1 0 2 empty empty P1 0 -8 0 10 -4034 -260097 -1 0; #X obj 173 465 vradio 15 1 0 2 empty empty P0 0 -8 0 10 -4034 -260097 -1 0; #X obj 193 465 vradio 15 1 0 2 empty empty P2 0 -8 0 10 -4034 -260097 -1 0; #X obj 213 465 vradio 15 1 0 2 empty empty D9 0 -8 0 10 -4034 -260097 -1 0; #X obj 233 465 vradio 15 1 0 2 empty empty D5 0 -8 0 10 -4034 -260097 -1 0; #X obj 253 465 vradio 15 1 0 2 empty empty DI 0 -8 0 10 -4034 -260097 -1 0; #X obj 273 465 vradio 15 1 0 2 empty empty D8 0 -8 0 10 -4034 -260097 -1 0; #X obj 293 465 vradio 15 1 0 2 empty empty D6 0 -8 0 10 -4034 -260097 -1 0; #X obj 313 465 vradio 15 1 0 2 empty empty D0 0 -8 0 10 -4034 -260097 -1 0; #X obj 333 465 vradio 15 1 0 2 empty empty D1 0 -8 0 10 -4034 -260097 -1 0; #X obj 373 465 vradio 15 1 0 2 empty empty D3 0 -8 0 10 -4034 -260097 -1 0; #X obj 393 465 vradio 15 1 0 2 empty empty D4 0 -8 0 10 -4034 -260097 -1 0; #X obj 353 465 vradio 15 1 0 2 empty empty D2 0 -8 0 10 -4034 -260097 -1 0; #X obj 93 406 bits xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx; #X text 402 132 -Disabled; #X text 402 162 -Analog Input; #X text 402 177 -Digital Input; #X text 402 192 -Digital Output Low; #X text 402 207 -Digital Output High; #X text 523 365 -OFF; #X text 523 382 -ON; #X text 405 462 -OFF; #X text 405 479 -ON; #X text 213 584 scale factor (1024/1200); #X text 252 704 scale factor (1024/1200); #X text 404 116 _FUNCTION___________; #X text 402 147 -Special Function; #X text 33 182 I/O Sample Rate; #X obj 132 103 unpack 0 0; #X obj 132 162 +; #X obj 132 185 nbx 7 14 -1e+37 1e+37 0 0 empty empty ms 56 8 0 10 -4034 -258113 -1 0 256; #X obj 587 266 cnv 15 324 68 empty empty Enabled_Digital_Ins 4 12 0 14 -204786 -13381 0; #X text 709 214 1024/1200:; #X obj 587 105 +; #X obj 587 244 bits xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ; #X floatatom 566 53 5 0 0 0 - - -; #X floatatom 587 131 5 0 0 0 - - -; #X obj 132 125 * 256; #X obj 212 252 * 256; #X obj 587 73 * 256; #X obj 93 347 * 256; #X obj 152 524 * 256; #X obj 191 645 * 256; #X obj 631 361 cnv 15 324 48 empty empty Enabled_Analog_Ins 4 12 0 14 -204786 -13381 0; #X text 805 337 1024/1200:; #X obj 630 339 bits xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ; #X floatatom 630 53 5 0 0 0 - - -; #X obj 651 165 cnv 15 348 74 empty empty Digital_In_Values 4 12 0 14 -261682 -13381 0; #X text 826 141 1024/1200:; #X obj 651 95 +; #X obj 651 143 bits xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ; #X floatatom 651 121 5 0 0 0 - - -; #X obj 651 73 * 256; #X obj 694 95 +; #X floatatom 694 121 5 0 0 0 - - -; #X obj 694 73 * 256; #X obj 737 95 +; #X floatatom 737 121 5 0 0 0 - - -; #X obj 737 73 * 256; #X obj 780 95 +; #X floatatom 780 121 5 0 0 0 - - -; #X obj 780 73 * 256; #X obj 822 95 +; #X floatatom 822 121 5 0 0 0 - - -; #X obj 822 73 * 256; #X obj 865 95 +; #X floatatom 865 121 5 0 0 0 - - -; #X obj 865 73 * 256; #X obj 566 32 unpack 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 ; #X obj 1000 79 cnv 15 140 160 empty empty IO_Samples 20 12 0 14 -261682 -66577 0; #X obj 1016 111 nbx 5 14 -1e+37 1e+37 0 0 empty empty 1st 60 8 0 10 -260097 -86853 -86853 0 256; #X obj 1016 131 nbx 5 14 -1e+37 1e+37 0 0 empty empty 2nd 60 8 0 10 -260097 -86853 -86853 0 256; #X obj 1016 151 nbx 5 14 -1e+37 1e+37 0 0 empty empty 3rd 60 8 0 10 -260097 -86853 -86853 0 256; #X obj 1016 171 nbx 5 14 -1e+37 1e+37 0 0 empty empty 4th 60 8 0 10 -260097 -86853 -86853 0 256; #X obj 1016 191 nbx 5 14 -1e+37 1e+37 0 0 empty empty 5th 60 8 0 10 -260097 -86853 -86853 0 256; #X obj 1016 211 nbx 5 14 -1e+37 1e+37 0 0 empty empty 6th 60 8 0 10 -260097 -86853 -86853 0 256; #X obj 933 375 vradio 15 1 0 2 empty empty A0 0 -8 0 10 -4034 -260097 -1 0; #X obj 912 375 vradio 15 1 0 2 empty empty A1 0 -8 0 10 -4034 -260097 -1 0; #X obj 892 375 vradio 15 1 0 2 empty empty A2 0 -8 0 10 -4034 -260097 -1 0; #X obj 872 375 vradio 15 1 0 2 empty empty A3 0 -8 0 10 -4034 -260097 -1 0; #X obj 791 375 vradio 15 1 0 2 empty empty V+ 0 -8 0 10 -4034 -260097 -1 0; #X obj 890 300 vradio 15 1 0 2 empty empty D0 0 -8 0 10 -4034 -260097 -1 0; #X obj 869 300 vradio 15 1 0 2 empty empty D1 0 -8 0 10 -4034 -260097 -1 0; #X obj 849 300 vradio 15 1 0 2 empty empty D2 0 -8 0 10 -4034 -260097 -1 0; #X obj 829 300 vradio 15 1 0 2 empty empty D3 0 -8 0 10 -4034 -260097 -1 0; #X obj 809 300 vradio 15 1 0 2 empty empty D4 0 -8 0 10 -4034 -260097 -1 0; #X obj 789 300 vradio 15 1 0 2 empty empty D5 0 -8 0 10 -4034 -260097 -1 0; #X obj 768 300 vradio 15 1 0 2 empty empty D6 0 -8 0 10 -4034 -260097 -1 0; #X obj 748 300 vradio 15 1 0 2 empty empty D7 0 -8 0 10 -4034 -260097 -1 0; #X obj 687 300 vradio 15 1 0 2 empty empty P0 0 -8 0 10 -4034 -260097 -1 0; #X obj 667 300 vradio 15 1 0 2 empty empty P1 0 -8 0 10 -4034 -260097 -1 0; #X obj 647 300 vradio 15 1 0 2 empty empty P2 0 -8 0 10 -4034 -260097 -1 0; #X text 905 313 -ON; #X text 905 297 -OFF; #X text 947 388 -ON; #X text 947 372 -OFF; #X obj 954 204 vradio 15 1 0 2 empty empty D0 0 -8 0 10 -4034 -260097 -1 0; #X obj 933 204 vradio 15 1 0 2 empty empty D1 0 -8 0 10 -4034 -260097 -1 0; #X obj 913 204 vradio 15 1 0 2 empty empty D2 0 -8 0 10 -4034 -260097 -1 0; #X obj 893 204 vradio 15 1 0 2 empty empty D3 0 -8 0 10 -4034 -260097 -1 0; #X obj 873 204 vradio 15 1 0 2 empty empty D4 0 -8 0 10 -4034 -260097 -1 0; #X obj 853 204 vradio 15 1 0 2 empty empty D5 0 -8 0 10 -4034 -260097 -1 0; #X obj 832 204 vradio 15 1 0 2 empty empty D6 0 -8 0 10 -4034 -260097 -1 0; #X obj 812 204 vradio 15 1 0 2 empty empty D7 0 -8 0 10 -4034 -260097 -1 0; #X obj 751 204 vradio 15 1 0 2 empty empty P0 0 -8 0 10 -4034 -260097 -1 0; #X obj 731 204 vradio 15 1 0 2 empty empty P1 0 -8 0 10 -4034 -260097 -1 0; #X obj 711 204 vradio 15 1 0 2 empty empty P2 0 -8 0 10 -4034 -260097 -1 0; #X text 969 217 -ON; #X text 969 201 -OFF; #X obj 93 15 route IC LT IR %V RP V+ PR P0 P1 P2 D0 D1 D2 D3 D4 D5 IS; #X obj 466 -10 route SAMPLE_FRAME; #X connect 3 0 161 0; #X connect 4 0 93 0; #X connect 4 1 5 1; #X connect 5 0 6 0; #X connect 6 0 7 0; #X connect 9 0 10 0; #X connect 11 0 94 0; #X connect 11 1 12 1; #X connect 12 0 13 0; #X connect 13 0 14 0; #X connect 19 0 90 0; #X connect 19 1 20 1; #X connect 20 0 50 0; #X connect 32 0 33 0; #X connect 34 0 92 0; #X connect 34 1 35 1; #X connect 35 0 65 0; #X connect 50 2 36 0; #X connect 50 3 37 0; #X connect 50 4 38 0; #X connect 50 5 39 0; #X connect 50 6 40 0; #X connect 50 7 41 0; #X connect 50 8 42 0; #X connect 50 9 43 0; #X connect 50 10 44 0; #X connect 50 11 45 0; #X connect 50 12 46 0; #X connect 50 13 49 0; #X connect 50 14 47 0; #X connect 50 15 48 0; #X connect 65 2 51 0; #X connect 65 3 52 0; #X connect 65 4 53 0; #X connect 65 5 54 0; #X connect 65 6 55 0; #X connect 65 7 56 0; #X connect 65 8 57 0; #X connect 65 9 58 0; #X connect 65 10 59 0; #X connect 65 11 60 0; #X connect 65 12 61 0; #X connect 65 13 64 0; #X connect 65 14 62 0; #X connect 65 15 63 0; #X connect 80 0 89 0; #X connect 80 1 81 1; #X connect 81 0 82 0; #X connect 85 0 86 0; #X connect 85 0 88 0; #X connect 86 3 143 0; #X connect 86 4 142 0; #X connect 86 5 141 0; #X connect 86 8 140 0; #X connect 86 9 139 0; #X connect 86 10 138 0; #X connect 86 11 137 0; #X connect 86 12 136 0; #X connect 86 13 135 0; #X connect 86 14 134 0; #X connect 86 15 133 0; #X connect 89 0 81 0; #X connect 90 0 20 0; #X connect 91 0 85 0; #X connect 92 0 35 0; #X connect 93 0 5 0; #X connect 94 0 12 0; #X connect 97 8 132 0; #X connect 97 12 131 0; #X connect 97 13 130 0; #X connect 97 14 129 0; #X connect 97 15 128 0; #X connect 101 0 102 0; #X connect 101 0 103 0; #X connect 101 0 122 0; #X connect 102 3 158 0; #X connect 102 4 157 0; #X connect 102 5 156 0; #X connect 102 8 155 0; #X connect 102 9 154 0; #X connect 102 10 153 0; #X connect 102 11 152 0; #X connect 102 12 151 0; #X connect 102 13 150 0; #X connect 102 14 149 0; #X connect 102 15 148 0; #X connect 104 0 101 0; #X connect 105 0 106 0; #X connect 105 0 123 0; #X connect 107 0 105 0; #X connect 108 0 109 0; #X connect 108 0 124 0; #X connect 110 0 108 0; #X connect 111 0 112 0; #X connect 111 0 125 0; #X connect 113 0 111 0; #X connect 114 0 115 0; #X connect 114 0 126 0; #X connect 116 0 114 0; #X connect 117 0 118 0; #X connect 117 0 127 0; #X connect 119 0 117 0; #X connect 120 0 87 0; #X connect 120 1 91 0; #X connect 120 2 85 1; #X connect 120 3 98 0; #X connect 120 3 97 0; #X connect 120 4 104 0; #X connect 120 5 101 1; #X connect 120 6 107 0; #X connect 120 7 105 1; #X connect 120 8 110 0; #X connect 120 9 108 1; #X connect 120 10 113 0; #X connect 120 11 111 1; #X connect 120 12 116 0; #X connect 120 13 114 1; #X connect 120 14 119 0; #X connect 120 15 117 1; #X connect 161 0 34 0; #X connect 161 1 32 0; #X connect 161 2 80 0; #X connect 161 3 4 0; #X connect 161 4 9 0; #X connect 161 5 11 0; #X connect 161 6 19 0; #X connect 161 7 22 0; #X connect 161 8 23 0; #X connect 161 9 24 0; #X connect 161 10 30 0; #X connect 161 11 25 0; #X connect 161 12 26 0; #X connect 161 13 27 0; #X connect 161 14 28 0; #X connect 161 15 29 0; #X connect 161 16 120 0; #X connect 161 17 162 0; #X connect 162 0 120 0; #X connect 162 1 31 0; #X restore 383 659 pd remote_status; #X obj 714 -44 cnv 15 420 80 empty empty Set_Digital_Outputs 40 12 0 14 -204786 -13381 0; #X obj 913 -17 tgl 15 0 empty empty D5 1 8 0 10 -4034 -258113 -1 0 1; #X obj 718 -17 tgl 15 0 empty empty P0 1 8 0 10 -4034 -258113 -1 0 1; #N canvas 54 264 589 223 digital_outs 0; #X obj 6 -38 cnv 15 560 200 empty empty empty 20 12 0 14 -232576 -66577 0; #X obj 26 37 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1 ; #X msg 26 83 4; #X msg 53 83 5; #X obj 26 58 sel 0 1; #X obj 26 -27 inlet; #X obj 86 -27 inlet; #X obj 146 -27 inlet; #X obj 206 -27 inlet; #X obj 266 -27 inlet; #X obj 326 -27 inlet; #X obj 386 -27 inlet; #X obj 446 -27 inlet; #X obj 506 -27 inlet; #X obj 86 37 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1 ; #X msg 86 83 4; #X msg 113 83 5; #X obj 86 58 sel 0 1; #X obj 146 37 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1; #X msg 146 83 4; #X msg 173 83 5; #X obj 146 58 sel 0 1; #X obj 206 37 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1; #X msg 206 83 4; #X msg 233 83 5; #X obj 206 58 sel 0 1; #X obj 266 37 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1; #X msg 266 83 4; #X msg 293 83 5; #X obj 266 58 sel 0 1; #X obj 326 37 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1; #X msg 326 83 4; #X msg 353 83 5; #X obj 326 58 sel 0 1; #X obj 386 37 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1; #X msg 386 83 4; #X msg 413 83 5; #X obj 386 58 sel 0 1; #X obj 446 37 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1; #X msg 446 83 4; #X msg 473 83 5; #X obj 446 58 sel 0 1; #X obj 506 37 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1; #X msg 506 83 4; #X msg 533 83 5; #X obj 506 58 sel 0 1; #X obj 26 127 outlet; #X obj 86 127 outlet; #X obj 146 127 outlet; #X obj 206 127 outlet; #X obj 266 127 outlet; #X obj 326 127 outlet; #X obj 386 127 outlet; #X obj 446 127 outlet; #X obj 506 127 outlet; #X connect 1 0 4 0; #X connect 2 0 46 0; #X connect 3 0 46 0; #X connect 4 0 2 0; #X connect 4 1 3 0; #X connect 5 0 1 0; #X connect 6 0 14 0; #X connect 7 0 18 0; #X connect 8 0 22 0; #X connect 9 0 26 0; #X connect 10 0 30 0; #X connect 11 0 34 0; #X connect 12 0 38 0; #X connect 13 0 42 0; #X connect 14 0 17 0; #X connect 15 0 47 0; #X connect 16 0 47 0; #X connect 17 0 15 0; #X connect 17 1 16 0; #X connect 18 0 21 0; #X connect 19 0 48 0; #X connect 20 0 48 0; #X connect 21 0 19 0; #X connect 21 1 20 0; #X connect 22 0 25 0; #X connect 23 0 49 0; #X connect 24 0 49 0; #X connect 25 0 23 0; #X connect 25 1 24 0; #X connect 26 0 29 0; #X connect 27 0 50 0; #X connect 28 0 50 0; #X connect 29 0 27 0; #X connect 29 1 28 0; #X connect 30 0 33 0; #X connect 31 0 51 0; #X connect 32 0 51 0; #X connect 33 0 31 0; #X connect 33 1 32 0; #X connect 34 0 37 0; #X connect 35 0 52 0; #X connect 36 0 52 0; #X connect 37 0 35 0; #X connect 37 1 36 0; #X connect 38 0 41 0; #X connect 39 0 53 0; #X connect 40 0 53 0; #X connect 41 0 39 0; #X connect 41 1 40 0; #X connect 42 0 45 0; #X connect 43 0 54 0; #X connect 44 0 54 0; #X connect 45 0 43 0; #X connect 45 1 44 0; #X restore 718 4 pd digital_outs xxxxxxxxxxxxxxxxx; #X obj 742 -17 tgl 15 0 empty empty P1 1 8 0 10 -4034 -258113 -1 0 1; #X obj 766 -17 tgl 15 0 empty empty P2 1 8 0 10 -4034 -258113 -1 0 1; #X obj 791 -17 tgl 15 0 empty empty D0 1 8 0 10 -4034 -258113 -1 0 1; #X obj 815 -17 tgl 15 0 empty empty D1 1 8 0 10 -4034 -258113 -1 0 1; #X obj 839 -17 tgl 15 0 empty empty D2 1 8 0 10 -4034 -258113 -1 0 1; #X obj 864 -17 tgl 15 0 empty empty D3 1 8 0 10 -4034 -258113 -1 0 1; #X obj 888 -17 tgl 15 0 empty empty D4 1 8 0 10 -4034 -258113 -1 0 1; #X text 624 132 P0 = pin6; #X text 624 142 P1 = pin7; #X text 624 152 P2 = pin4; #X text 624 162 D0 = pin20; #X text 624 172 D1 = pin19; #X text 624 182 D2 = pin18; #X text 624 192 D3 = pin17; #X text 624 202 D4 = pin11; #X text 624 212 D5 = pin15; #X obj 714 37 cnv 15 420 230 empty empty Set_Remote_IO_Pin_Function 40 12 0 14 -261682 -86853 0; #N canvas 4 77 1271 611 set_pin_functions 0; #X obj 26 -23 cnv 15 1200 600 empty empty empty 20 12 0 14 -204800 -66577 0; #X obj 176 326 list append; #X msg 176 228 RAT; #X msg 41 199 0x0013A200406BFE6C; #X obj 176 356 list append; #X msg 305 253 0x9A17; #X obj 176 406 list append; #X msg 271 350 2; #X obj 176 467 list append; #X msg 273 450 P0; #X obj 176 493 list append; #X obj 176 514 list trim; #X obj 41 -7 inlet; #X obj 286 -7 inlet; #X obj 396 -7 inlet; #X obj 506 -7 inlet; #X obj 616 -7 inlet; #X obj 726 -7 inlet; #X obj 836 -7 inlet; #X obj 946 -7 inlet; #X obj 176 541 outlet; #X obj 1056 -7 inlet; #X obj 176 147 t b b b b b b f; #X obj 41 22 route remote64 remote16; #X obj 41 94 prepend set; #X obj 108 125 prepend set; #X obj 286 147 t b b b b b b f; #X obj 396 147 t b b b b b b f; #X obj 506 147 t b b b b b b f; #X obj 616 147 t b b b b b b f; #X obj 726 147 t b b b b b b f; #X obj 836 147 t b b b b b b f; #X obj 946 147 t b b b b b b f; #X obj 1056 147 t b b b b b b f; #X msg 303 450 P1; #X msg 333 450 P2; #X msg 363 450 D0; #X msg 393 450 D1; #X msg 423 450 D2; #X msg 453 450 D3; #X msg 483 450 D4; #X msg 513 450 D5; #X connect 1 0 4 0; #X connect 2 0 1 0; #X connect 3 0 1 1; #X connect 4 0 6 0; #X connect 5 0 4 1; #X connect 6 0 8 0; #X connect 7 0 6 1; #X connect 8 0 10 0; #X connect 9 0 8 1; #X connect 10 0 11 0; #X connect 11 0 20 0; #X connect 12 0 23 0; #X connect 13 0 26 0; #X connect 14 0 27 0; #X connect 15 0 28 0; #X connect 16 0 29 0; #X connect 17 0 30 0; #X connect 18 0 31 0; #X connect 19 0 32 0; #X connect 21 0 33 0; #X connect 22 0 2 0; #X connect 22 2 3 0; #X connect 22 3 5 0; #X connect 22 4 7 0; #X connect 22 5 9 0; #X connect 22 6 10 1; #X connect 23 0 24 0; #X connect 23 1 25 0; #X connect 23 2 22 0; #X connect 24 0 3 0; #X connect 25 0 5 0; #X connect 26 0 2 0; #X connect 26 2 3 0; #X connect 26 3 5 0; #X connect 26 4 7 0; #X connect 26 5 34 0; #X connect 26 6 10 1; #X connect 27 0 2 0; #X connect 27 2 3 0; #X connect 27 3 5 0; #X connect 27 4 7 0; #X connect 27 5 35 0; #X connect 27 6 10 1; #X connect 28 0 2 0; #X connect 28 2 3 0; #X connect 28 3 5 0; #X connect 28 4 7 0; #X connect 28 5 36 0; #X connect 28 6 10 1; #X connect 29 0 2 0; #X connect 29 2 3 0; #X connect 29 3 5 0; #X connect 29 5 37 0; #X connect 29 6 10 1; #X connect 30 0 2 0; #X connect 30 2 3 0; #X connect 30 3 5 0; #X connect 30 4 7 0; #X connect 30 5 38 0; #X connect 30 6 10 1; #X connect 31 0 2 0; #X connect 31 2 3 0; #X connect 31 3 5 0; #X connect 31 4 7 0; #X connect 31 5 39 0; #X connect 31 6 10 1; #X connect 32 0 2 0; #X connect 32 2 3 0; #X connect 32 3 5 0; #X connect 32 4 7 0; #X connect 32 5 40 0; #X connect 32 6 10 1; #X connect 33 0 2 0; #X connect 33 2 3 0; #X connect 33 3 5 0; #X connect 33 4 7 0; #X connect 33 5 41 0; #X connect 33 6 10 1; #X connect 34 0 8 1; #X connect 35 0 8 1; #X connect 36 0 8 1; #X connect 37 0 8 1; #X connect 38 0 8 1; #X connect 39 0 8 1; #X connect 40 0 8 1; #X connect 41 0 8 1; #X restore 718 227 pd set_pin_functions XXXXXXXXXXXXXXXXXXXXXXXXXX ; #X obj 718 79 vradio 15 1 0 6 empty empty P0 0 -8 0 10 -4034 -260097 -1 1; #X obj 752 79 vradio 15 1 0 6 empty empty P1 0 -8 0 10 -4034 -260097 -1 0; #X obj 787 79 vradio 15 1 0 6 empty empty P2 0 -8 0 10 -4034 -260097 -1 0; #X obj 857 79 vradio 15 1 0 6 empty empty D1 0 -8 0 10 -4034 -260097 -1 0; #X obj 892 79 vradio 15 1 0 6 empty empty D2 0 -8 0 10 -4034 -260097 -1 0; #X obj 927 79 vradio 15 1 0 6 empty empty D3 0 -8 0 10 -4034 -260097 -1 0; #X obj 962 79 vradio 15 1 0 6 empty empty D4 0 -8 0 10 -4034 -260097 -1 0; #X obj 997 79 vradio 15 1 0 6 empty empty D5 0 -8 0 10 -4034 -260097 -1 1; #X obj 822 79 vradio 15 1 0 6 empty empty D0 0 -8 0 10 -4034 -260097 -1 0; #X text 1009 77 -Disabled; #X text 1009 107 -Analog Input; #X text 1009 122 -Digital Input; #X text 1009 137 -Digital Output Low; #X text 1009 152 -Digital Output High; #X text 1011 61 _FUNCTION___________; #X text 1009 92 -Special Function; #X msg 501 -7 remote64 0x0013A200406BFE6C; #X msg 536 28 remote16 0x9A17; #X text 501 -24 set the 64-bit remote address; #X text 535 10 set the 16-bit remote address; #X obj 713 297 cnv 15 600 140 empty empty Sample 20 12 0 14 -257985 -83269 0; #X msg 722 325 IS; #X text 749 324 force sample; #X obj 1139 36 r P0Val; #X obj 1139 62 prepend set; #X obj 1219 62 prepend set; #X obj 1219 36 r P1Val; #X obj 1299 62 prepend set; #X obj 1379 62 prepend set; #X obj 1459 62 prepend set; #X obj 1539 62 prepend set; #X obj 1619 62 prepend set; #X obj 1699 62 prepend set; #X obj 1779 62 prepend set; #X obj 1299 36 r P2Val; #X obj 1459 36 r D1Val; #X obj 1539 36 r D2Val; #X obj 1619 36 r D3Val; #X obj 1699 36 r D4Val; #X obj 1779 36 r D5Val; #X text 27 -2 Associate LED blink time; #X obj 1379 36 r D0Val; #X obj 1320 478 route ZigBee_IO_Data_Sample_Rx_Indicator; #X text 275 60 set sample rate; #X floatatom 388 52 5 0 0 0 - - -; #X obj 373 75 f; #X obj 373 30 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 -1; #X msg 1344 519 SAMPLE_FRAME; #X floatatom 1320 563 5 0 0 0 - - -; #X floatatom 1343 583 5 0 0 0 - - -; #X symbolatom 1366 603 20 0 0 0 - - -; #X floatatom 1412 645 5 0 0 0 - - -; #X msg 248 60 0; #X symbolatom 1389 623 10 0 0 0 - - -; #X text 1220 562 frame_type (146); #X obj 1320 541 unpack 0 0 s s 0; #X text 1242 622 sender's 16-bit address; #X text 1220 602 sender's 64-bit address; #X text 1315 644 receive_options; #X text 1270 582 data length; #X obj 1187 310 print else; #X text 874 245 Sample Frame; #X obj 417 577 list trim; #X obj 872 266 route D0 D1 D2 D3 D4 D5 D10 D11 D12 A0 A1 A2 A3 A7; #X obj 866 296 cnv 15 300 50 empty empty Digital_Inputs 20 12 0 14 -204786 -13381 0; #X obj 866 347 cnv 15 400 90 empty empty Analog_Inputs 20 12 0 14 -232576 -45076 0; #X obj 869 380 nbx 5 14 -1e+37 1e+37 0 0 empty empty A0 40 8 0 10 -204800 -13330 -159808 0 256; #X obj 929 380 nbx 5 14 -1e+37 1e+37 0 0 empty empty A1 40 8 0 10 -204800 -13330 -159808 0 256; #X obj 989 380 nbx 5 14 -1e+37 1e+37 0 0 empty empty A2 40 8 0 10 -204800 -13330 -159808 0 256; #X obj 1049 380 nbx 5 14 -1e+37 1e+37 0 0 empty empty A3 40 8 0 10 -204800 -13330 -159808 0 256; #X obj 1109 380 nbx 5 14 -1e+37 1e+37 0 0 empty empty V+ 40 8 0 10 -204800 -13330 -159808 0 256; #X obj 872 322 nbx 2 14 -1e+37 1e+37 0 0 empty empty D0 8 20 0 10 -4034 -1 -258113 0 256; #X obj 912 322 nbx 2 14 -1e+37 1e+37 0 0 empty empty D1 8 20 0 10 -4034 -1 -258113 0 256; #X obj 942 322 nbx 2 14 -1e+37 1e+37 0 0 empty empty D2 8 20 0 10 -4034 -1 -258113 0 256; #X obj 972 322 nbx 2 14 -1e+37 1e+37 0 0 empty empty D3 8 20 0 10 -4034 -1 -258113 0 256; #X obj 1002 322 nbx 2 14 -1e+37 1e+37 0 0 empty empty D4 8 20 0 10 -4034 -1 -258113 0 256; #X obj 1032 322 nbx 2 14 -1e+37 1e+37 0 0 empty empty D5 8 20 0 10 -4034 -1 -258113 0 256; #X obj 1062 322 nbx 2 14 -1e+37 1e+37 0 0 empty empty P0 8 20 0 10 -4034 -1 -258113 0 256; #X obj 1092 322 nbx 2 14 -1e+37 1e+37 0 0 empty empty P1 8 20 0 10 -4034 -1 -258113 0 256; #X obj 1122 322 nbx 2 14 -1e+37 1e+37 0 0 empty empty P2 8 20 0 10 -4034 -1 -258113 0 256; #X msg 270 114 RAT 0x0013A200406BFE6C 0x9A17 2 V+ \$1; #X obj 521 78 nbx 5 14 -1e+37 1e+37 0 0 empty empty Supply_Voltage_Threshold 0 -8 0 10 -4034 -13381 -1 0 256; #X obj 869 419 nbx 5 14 -1e+37 1e+37 0 0 empty empty A0_mV 40 8 0 10 -204800 -13330 -159808 0 256; #X obj 869 399 * 1.17302; #X obj 949 419 nbx 5 14 -1e+37 1e+37 0 0 empty empty A1_mV 40 8 0 10 -204800 -13330 -159808 0 256; #X obj 949 399 * 1.17302; #X obj 1029 419 nbx 5 14 -1e+37 1e+37 0 0 empty empty A2_mV 40 8 0 10 -204800 -13330 -159808 0 256; #X obj 1029 399 * 1.17302; #X obj 1109 419 nbx 5 14 -1e+37 1e+37 0 0 empty empty A3_mV 40 8 0 10 -204800 -13330 -159808 0 256; #X obj 1109 399 * 1.17302; #X obj 1189 419 nbx 5 14 -1e+37 1e+37 0 0 empty empty V+_mV 40 8 0 10 -204800 -13330 -159808 0 256; #X obj 1189 399 * 1.17302; #X msg 248 92 RAT 0x0013A200406BFE6C 0x9A17 2 IR \$1; #X text 424 51 ms; #X obj 506 97 f; #X obj 506 48 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 -1; #X connect 2 0 3 0; #X connect 3 0 5 0; #X connect 4 0 5 0; #X connect 5 0 9 0; #X connect 5 1 10 0; #X connect 6 0 5 0; #X connect 7 0 5 0; #X connect 9 0 121 0; #X connect 9 1 209 0; #X connect 9 2 58 0; #X connect 22 0 11 0; #X connect 22 1 12 0; #X connect 22 2 13 0; #X connect 22 3 14 0; #X connect 22 4 15 0; #X connect 22 5 17 0; #X connect 32 0 24 0; #X connect 32 1 25 0; #X connect 32 2 26 0; #X connect 32 3 29 0; #X connect 32 4 27 0; #X connect 36 0 3 0; #X connect 37 0 22 0; #X connect 37 1 32 0; #X connect 37 2 38 0; #X connect 38 0 42 0; #X connect 38 1 189 0; #X connect 42 0 39 0; #X connect 42 1 40 0; #X connect 42 2 43 0; #X connect 42 3 44 0; #X connect 42 4 46 0; #X connect 42 5 47 0; #X connect 42 6 49 0; #X connect 51 0 3 0; #X connect 55 0 9 0; #X connect 56 0 55 0; #X connect 58 0 72 0; #X connect 58 1 37 0; #X connect 72 0 59 0; #X connect 72 1 60 0; #X connect 72 2 64 0; #X connect 72 3 66 0; #X connect 72 4 67 0; #X connect 72 4 121 1; #X connect 72 5 69 0; #X connect 72 5 74 0; #X connect 72 6 63 0; #X connect 74 0 76 0; #X connect 74 1 77 0; #X connect 74 2 78 0; #X connect 74 3 79 0; #X connect 74 4 80 0; #X connect 76 0 75 0; #X connect 77 0 75 0; #X connect 78 0 75 0; #X connect 79 0 75 0; #X connect 80 0 75 0; #X connect 81 0 3 0; #X connect 82 0 81 0; #X connect 83 0 5 0; #X connect 84 0 89 0; #X connect 85 0 86 0; #X connect 86 0 87 0; #X connect 87 0 105 0; #X connect 88 0 89 0; #X connect 89 0 85 0; #X connect 89 1 86 1; #X connect 90 0 89 0; #X connect 91 0 89 0; #X connect 92 0 89 0; #X connect 93 0 89 0; #X connect 94 0 89 0; #X connect 95 0 89 0; #X connect 96 0 89 0; #X connect 97 0 89 0; #X connect 98 0 89 0; #X connect 99 0 89 0; #X connect 100 0 89 0; #X connect 101 0 89 0; #X connect 102 0 89 0; #X connect 103 0 89 0; #X connect 106 0 3 0; #X connect 121 0 122 0; #X connect 122 0 124 0; #X connect 126 0 128 8; #X connect 127 0 128 0; #X connect 128 0 147 0; #X connect 128 1 148 0; #X connect 128 2 149 0; #X connect 128 3 155 0; #X connect 128 4 150 0; #X connect 128 5 151 0; #X connect 128 6 152 0; #X connect 128 7 153 0; #X connect 128 8 154 0; #X connect 129 0 128 1; #X connect 130 0 128 2; #X connect 131 0 128 3; #X connect 132 0 128 4; #X connect 133 0 128 5; #X connect 134 0 128 6; #X connect 135 0 128 7; #X connect 146 0 3 0; #X connect 147 0 146 0; #X connect 148 0 146 1; #X connect 149 0 146 2; #X connect 150 0 146 4; #X connect 151 0 146 5; #X connect 152 0 146 6; #X connect 153 0 146 7; #X connect 154 0 146 8; #X connect 155 0 146 3; #X connect 163 0 146 0; #X connect 164 0 146 0; #X connect 168 0 89 0; #X connect 170 0 171 0; #X connect 171 0 147 0; #X connect 172 0 148 0; #X connect 173 0 172 0; #X connect 174 0 149 0; #X connect 175 0 155 0; #X connect 176 0 150 0; #X connect 177 0 151 0; #X connect 178 0 152 0; #X connect 179 0 153 0; #X connect 180 0 154 0; #X connect 181 0 174 0; #X connect 182 0 176 0; #X connect 183 0 177 0; #X connect 184 0 178 0; #X connect 185 0 179 0; #X connect 186 0 180 0; #X connect 188 0 175 0; #X connect 189 0 194 0; #X connect 189 0 202 0; #X connect 189 1 16 0; #X connect 191 0 192 1; #X connect 192 0 239 0; #X connect 193 0 192 0; #X connect 194 0 121 1; #X connect 199 0 239 0; #X connect 202 0 195 0; #X connect 202 1 196 0; #X connect 202 2 197 0; #X connect 202 3 200 0; #X connect 202 4 198 0; #X connect 209 0 210 0; #X connect 210 0 218 0; #X connect 210 1 219 0; #X connect 210 2 220 0; #X connect 210 3 221 0; #X connect 210 4 222 0; #X connect 210 5 223 0; #X connect 210 6 224 0; #X connect 210 7 225 0; #X connect 210 8 226 0; #X connect 210 9 213 0; #X connect 210 9 230 0; #X connect 210 10 214 0; #X connect 210 10 232 0; #X connect 210 11 215 0; #X connect 210 11 234 0; #X connect 210 12 216 0; #X connect 210 12 236 0; #X connect 210 13 217 0; #X connect 210 13 238 0; #X connect 210 14 207 0; #X connect 227 0 3 0; #X connect 228 0 241 1; #X connect 230 0 229 0; #X connect 232 0 231 0; #X connect 234 0 233 0; #X connect 236 0 235 0; #X connect 238 0 237 0; #X connect 239 0 3 0; #X connect 241 0 227 0; #X connect 242 0 241 0; mrpeach/xbee/packxbee-help.pd0000644000175000017500000005532612424234300016714 0ustar zmoelnigzmoelnig#N canvas 468 125 626 764 10; #X declare -lib mrpeach; #X obj 400 56 cnv 15 150 160 empty empty empty 20 12 0 14 -232576 -66577 0; #X obj -15 8 cnv 15 400 280 empty empty empty 20 12 0 14 -232576 -66577 0; #X obj -15 290 cnv 15 600 240 empty empty empty 20 12 0 14 -204786 -66577 0; #X obj -15 533 cnv 15 600 200 empty empty empty 20 12 0 14 -262130 -66577 0; #X obj 269 664 cnv 15 300 25 empty empty unpackxbee: 1 12 0 14 -257985 -159808 0; #X obj 74 181 cnv 15 300 25 empty empty packxbee: 1 12 0 14 -159808 -257985 0; #X obj 119 134 r topackxbee; #X msg 251 301 devices; #X msg -1 14 API 1; #X msg 21 36 API 2; #X text 38 13 set API mode 1; #X text 62 37 set API mode 2 (escaped characters); #X text 43 51 mode 2 is the default setting; #X msg 326 376 baud 115200; #X msg 350 400 baud 9600; #X msg 280 570 verbosity \$1; #X obj 280 549 hradio 15 1 0 3 empty empty verbosity 0 -8 0 10 -4034 -1 -1 0; #X obj 360 446 t f f; #X obj 360 695 print data; #N canvas 23 645 1232 329 status 0; #X obj 73 16 inlet; #X floatatom 184 218 5 0 0 0 - - -; #X obj 254 99 print unpack5; #X obj 73 46 route AT_Command_Response; #X obj 73 82 list split 3; #X obj 184 120 list trim; #X symbolatom 201 234 7 0 0 0 - - -; #X symbolatom 219 251 20 0 0 0 - - -; #X obj 73 120 unpack 0 0 0; #X floatatom 73 144 5 0 0 0 - - -; #X floatatom 107 164 5 0 0 0 - - -; #X floatatom 142 184 5 0 0 0 - - -; #X text -1 144 packet type; #X text 39 164 packet ID; #X text 64 183 data length; #X text 71 215 AT command status; #X text 155 233 addr16; #X text 175 249 addr64; #X obj 428 63 route ZigBee_Transmit_Status; #X floatatom 428 105 5 0 0 0 - - -; #X floatatom 449 123 5 0 0 0 - - -; #X text 354 105 packet type; #X text 381 123 packet ID; #X symbolatom 470 140 7 0 0 0 - - -; #X text 427 139 addr16; #X floatatom 533 192 5 0 0 0 - - -; #X floatatom 512 175 5 0 0 0 - - -; #X floatatom 491 158 5 0 0 0 - - -; #X text 360 156 transmit retry count; #X text 411 173 delivery status; #X text 427 190 discovery status; #X symbolatom 236 268 32 0 0 0 - - -; #X symbolatom 254 286 7 0 0 0 - - -; #X symbolatom 307 339 7 0 0 0 - - -; #X symbolatom 325 357 7 0 0 0 - - -; #X obj 184 196 unpack 0 s s s s 0 0 s s; #X floatatom 272 304 5 0 0 0 - - -; #X floatatom 289 321 5 0 0 0 - - -; #X text 139 267 Node Identifier; #X text 207 285 parent; #X text 197 301 device type; #X text 209 319 source event; #X text 252 337 profile; #X text 247 355 manufacturer; #X obj 428 85 unpack 0 0 s 0 0 0; #X obj 616 80 route ZigBee_Receive_Packet; #X obj 1181 114 print someotherpacket; #X symbolatom 685 177 7 0 0 0 - - -; #X symbolatom 662 159 17 0 0 0 - - -; #X text 639 176 addr16; #X text 618 157 addr64; #X floatatom 616 123 5 0 0 0 - - -; #X text 542 123 packet type; #X floatatom 709 195 5 0 0 0 - - -; #X text 610 193 receive options; #X obj 709 245 tgl 15 0 empty empty acknowledged 17 7 0 10 -4034 -1 -1 0 1; #X obj 749 265 tgl 15 0 empty empty broadcast 17 7 0 10 -4034 -1 -1 0 1; #X obj 789 285 tgl 15 0 empty empty encrypted 17 7 0 10 -4034 -1 -1 0 1; #X obj 829 305 tgl 15 0 empty empty from_end_device 17 7 0 10 -4034 -1 -1 0 1; #X obj 709 209 & 1; #X obj 749 209 & 2; #X obj 789 209 & 32; #X obj 829 209 & 64; #X obj 616 101 unpack 0 0 s s 0; #X floatatom 639 140 5 0 0 0 - - -; #X text 565 140 data length; #X obj 511 214 select 0 2 21 33 34 35 36 37; #X symbolatom 511 411 32 0 0 0 - - -; #X msg 511 238 set success; #X msg 676 396 set unknown; #X msg 531 257 set CCA_failurs; #X msg 572 297 set Network_ACK_Failure; #X msg 552 277 set Invalid_Destination_Endpoint; #X msg 593 317 set Not_Joined_To_Network; #X msg 612 337 set Self-Addresed; #X msg 634 356 set Address_Not_Found; #X msg 655 376 set Route_Not_Found; #X text 408 410 delivery status:; #X symbolatom 532 547 32 0 0 0 - - -; #X msg 613 532 set unknown; #X obj 532 435 select 0 1 2 3; #X msg 532 456 set No_Discovery_Overhead; #X msg 552 475 set Address_Discovery; #X msg 573 494 set Route_Discovery; #X msg 593 513 set Address_And_Route_Discovery; #X text 428 545 discovery status:; #X obj 936 97 route Remote_Command_Response; #X floatatom 936 150 5 0 0 0 - - -; #X floatatom 955 172 5 0 0 0 - - -; #X text 862 150 packet type; #X text 887 172 packet ID; #X floatatom 1053 279 5 0 0 0 - - -; #X symbolatom 975 212 20 0 0 0 - - -; #X text 931 210 addr64; #X symbolatom 994 193 7 0 0 0 - - -; #X symbolatom 1014 234 7 0 0 0 - - -; #X text 968 233 command; #X floatatom 1033 256 5 0 0 0 - - -; #X text 983 280 data length; #X text 991 256 status; #X obj 936 124 unpack 0 0 s s s 0 0; #X obj 247 167 print AT_response; #X text 948 192 addr16; #X obj 1101 160 select 0 1 2 3 4; #X symbolatom 1101 360 32 0 0 0 - - -; #X text 998 359 delivery status:; #X msg 1101 187 set OK; #X msg 1119 207 set ERROR; #X msg 1138 226 set Invalid_Command; #X msg 1157 246 set Invalid_Parameter; #X msg 1175 269 set Transmission_Failed; #X obj 184 142 route ND SL; #X obj 61 309 print SL; #X connect 0 0 3 0; #X connect 3 0 4 0; #X connect 3 1 18 0; #X connect 4 0 8 0; #X connect 4 1 5 0; #X connect 4 2 2 0; #X connect 5 0 111 0; #X connect 8 0 9 0; #X connect 8 1 10 0; #X connect 8 2 11 0; #X connect 18 0 44 0; #X connect 18 1 45 0; #X connect 35 0 1 0; #X connect 35 1 6 0; #X connect 35 2 7 0; #X connect 35 3 31 0; #X connect 35 4 32 0; #X connect 35 5 36 0; #X connect 35 6 37 0; #X connect 35 7 33 0; #X connect 35 8 34 0; #X connect 44 0 19 0; #X connect 44 1 20 0; #X connect 44 2 23 0; #X connect 44 3 27 0; #X connect 44 4 26 0; #X connect 44 4 66 0; #X connect 44 5 25 0; #X connect 44 5 80 0; #X connect 45 0 63 0; #X connect 45 1 86 0; #X connect 53 0 59 0; #X connect 53 0 60 0; #X connect 53 0 61 0; #X connect 53 0 62 0; #X connect 59 0 55 0; #X connect 60 0 56 0; #X connect 61 0 57 0; #X connect 62 0 58 0; #X connect 63 0 51 0; #X connect 63 1 64 0; #X connect 63 2 48 0; #X connect 63 3 47 0; #X connect 63 4 53 0; #X connect 66 0 68 0; #X connect 66 1 70 0; #X connect 66 2 72 0; #X connect 66 3 71 0; #X connect 66 4 73 0; #X connect 66 5 74 0; #X connect 66 6 75 0; #X connect 66 7 76 0; #X connect 66 8 69 0; #X connect 68 0 67 0; #X connect 69 0 67 0; #X connect 70 0 67 0; #X connect 71 0 67 0; #X connect 72 0 67 0; #X connect 73 0 67 0; #X connect 74 0 67 0; #X connect 75 0 67 0; #X connect 76 0 67 0; #X connect 79 0 78 0; #X connect 80 0 81 0; #X connect 80 1 82 0; #X connect 80 2 83 0; #X connect 80 3 84 0; #X connect 80 4 79 0; #X connect 81 0 78 0; #X connect 82 0 78 0; #X connect 83 0 78 0; #X connect 84 0 78 0; #X connect 86 0 100 0; #X connect 86 1 46 0; #X connect 100 0 87 0; #X connect 100 1 88 0; #X connect 100 2 92 0; #X connect 100 3 94 0; #X connect 100 4 95 0; #X connect 100 5 97 0; #X connect 100 5 103 0; #X connect 100 6 91 0; #X connect 103 0 106 0; #X connect 103 1 107 0; #X connect 103 2 108 0; #X connect 103 3 109 0; #X connect 103 4 110 0; #X connect 106 0 104 0; #X connect 107 0 104 0; #X connect 108 0 104 0; #X connect 109 0 104 0; #X connect 110 0 104 0; #X connect 111 0 35 0; #X connect 111 1 112 0; #X connect 111 2 101 0; #X restore 429 695 pd status; #X obj 387 487 spigot; #X obj 420 467 tgl 15 0 empty empty print_serial_in 17 7 0 10 -4034 -1 -1 0 1; #X obj 178 227 spigot; #X obj 211 208 tgl 15 0 empty empty print_packets 17 7 0 10 -4034 -1 -1 0 1; #X obj 153 185 packxbee 2; #X obj 360 667 unpackxbee 2; #X obj 491 6 import mrpeach; #N canvas 24 396 595 216 META 0; #X text 22 55 LICENSE GPL v2 or later; #X text 22 153 AUTHOR Martin Peach; #X text 22 15 KEYWORDS control network wireless xbee; #X text 22 173 HELP_PATCH_AUTHORS Martin Peach; #X text 22 35 NAME packxbee; #X text 22 130 OUTLET_0 list data; #X text 22 110 INLET_0 API TX TX64 TX16 AT ATQ RAT verbosity; #X text 22 75 DESCRIPTION [packxbee] builds packets for Series 1 or 2 XBees in API modes 1 or 2; #X restore 534 26 pd META; #X msg 291 341 info; #X msg 271 321 open 4; #N canvas 501 298 758 479 IO_COMMANDS 0; #X obj 400 426 s topackxbee; #X msg 274 283 AT D7; #X msg 256 265 AT D6; #X msg 28 37 AT IR; #X text 66 36 get IO sample rate; #X msg 48 57 AT IC; #X text 86 56 get IO digital change detection; #X msg 68 77 AT P0; #X text 106 76 get PWM0 function; #X msg 88 97 AT P1; #X text 126 96 get PWM1 function; #X msg 108 117 AT P2; #X text 146 116 get PWM2 function; #X msg 128 137 AT P3; #X text 166 136 get PWM3 function; #X msg 148 157 AT D0; #X text 192 156 get AD0/DIO0 function; #X msg 166 175 AT D1; #X msg 184 193 AT D2; #X text 228 192 get AD2/DIO2 function; #X text 210 174 get AD1/DIO1 function; #X msg 202 211 AT D3; #X msg 220 229 AT D4; #X msg 238 247 AT D5; #X text 246 210 get AD3/DIO3 function; #X text 264 228 get DIO4 function; #X text 282 246 get DIO5 function; #X text 294 264 get DIO6 configuration; #X text 312 282 get DIO7 configuration; #X msg 292 301 AT D8; #X text 330 300 get DIO8 configuration; #X msg 311 320 AT LT; #X text 346 318 get Associate LED blink time 10ms; #X msg 329 338 AT PR; #X text 364 336 get pullup resistors; #X text 387 354 get supply voltage 1200/1024mV; #X msg 348 357 AT %V; #X msg 368 377 AT V+; #X text 407 374 get supply voltage threshold 1200/1024mV; #X msg 388 397 AT TP; #X text 427 394 get temperature C; #X msg 451 213 AT IS; #X msg 471 233 AT 1S; #X text 499 211 force sample; #X text 509 231 force xbee sample; #X obj 507 286 s topackxbee; #X connect 1 0 0 0; #X connect 2 0 0 0; #X connect 3 0 0 0; #X connect 5 0 0 0; #X connect 7 0 0 0; #X connect 9 0 0 0; #X connect 11 0 0 0; #X connect 13 0 0 0; #X connect 15 0 0 0; #X connect 17 0 0 0; #X connect 18 0 0 0; #X connect 21 0 0 0; #X connect 22 0 0 0; #X connect 23 0 0 0; #X connect 29 0 0 0; #X connect 31 0 0 0; #X connect 33 0 0 0; #X connect 36 0 0 0; #X connect 37 0 0 0; #X connect 39 0 0 0; #X connect 41 0 45 0; #X connect 42 0 45 0; #X restore 408 148 pd IO_COMMANDS; #N canvas 3 90 1158 513 NETWORK_COMMANDS 0; #X msg 80 53 AT DH 0x0013A200; #X text 193 52 set upper 32 bits of destination address; #X msg 103 76 AT DL 0x407694DB; #X msg 128 101 AT MY; #X text 80 9 get upper 32 bits of destination address; #X msg 37 10 AT DH; #X msg 60 33 AT DL; #X msg 148 121 AT MP; #X text 171 99 get our 16-bit address (Read Only); #X msg 171 144 AT NC; #X text 210 141 get number of remaining children (Read Only); #X msg 193 166 AT SH; #X text 232 163 get serial number high 32 bits (Read Only); #X text 253 184 get serial number low 32 bits (Read Only); #X msg 214 187 AT SL; #X msg 234 207 AT NI diddley; #X text 321 204 set node identifier string; #X msg 254 227 AT NI; #X text 299 225 get node identifier string; #X msg 274 247 AT NP; #X text 319 245 get maximum payload; #X msg 294 267 AT DD; #X text 336 264 get device type identifier; #X text 191 119 get endpoint parent's 16-bit address (Read Only); #X text 210 74 set lower 32 bits of destination address; #X text 97 31 get lower 32 bits of destination address; #X obj 497 487 s topackxbee; #X msg 448 11 AT CH; #X text 486 10 get operating channel; #X msg 468 31 AT ID; #X text 506 30 get 64-bit PAN ID; #X text 649 52 set 64-bit PAN ID; #X msg 510 73 AT ID 0x0; #X text 578 72 set coordinator chosen 64-bit PAN ID; #X msg 490 53 AT ID 0xFEEAFEEBFEECFEED; #X msg 532 95 AT OP; #X text 575 93 get operating 64-bit PAN ID; #X msg 552 115 AT NH; #X msg 572 135 AT NH 0xFF; #X text 648 153 set maximum unicast hops (float arg); #X text 645 133 set maximum unicast hops (symbol arg); #X text 595 113 get maximum unicast hops (no arg); #X msg 612 175 AT BH; #X text 655 173 get maximum broadcastcast hops (no arg); #X text 705 193 set maximum broadcast hops (symbol arg); #X msg 632 195 AT BH 0x1E; #X msg 652 215 AT BH 3; #X text 705 212 set maximum broadcast hops (float arg); #X msg 672 235 AT OI; #X text 715 233 get operating 16-bit PAN ID; #X msg 592 155 AT NH 2; #X msg 693 256 AT NT; #X text 736 254 get node discovery timeout; #X text 782 274 set node discovery timeout; #X msg 713 276 AT NT 0xFF; #X msg 733 296 AT NO; #X msg 753 316 AT NO 3; #X text 776 294 get node discovery options; #X text 804 314 set node discovery options; #X msg 774 337 AT SC; #X msg 793 356 AT SC 0xFFFF; #X text 817 335 get scan channel bitmask; #X text 874 355 set scan channels; #X msg 812 375 AT SD; #X msg 831 394 AT SD 3; #X text 855 373 get scan duration; #X text 882 393 set scan duration; #X obj 907 487 s topackxbee; #X text 66 230 get zigbee stack profile; #X text 94 250 set zigbee stack profile; #X msg 28 231 AT ZS; #X msg 47 250 AT ZS 0; #X msg 68 271 AT NJ; #X msg 88 291 AT NJ 0xFF; #X text 106 270 get node join time; #X text 161 290 set node join time; #X msg 108 311 AT JV; #X text 146 310 get channel verification; #X text 181 330 set channel verification; #X msg 128 331 AT JV 1; #X obj 267 487 s topackxbee; #X msg 429 402 AT AI; #X text 468 399 get association indication; #X msg 386 359 AT ND; #X text 425 356 node discover; #X text 436 319 resolve destination node; #X msg 346 319 AT DN IMCA_R1; #X connect 0 0 26 0; #X connect 2 0 26 0; #X connect 3 0 26 0; #X connect 5 0 26 0; #X connect 6 0 26 0; #X connect 7 0 26 0; #X connect 9 0 26 0; #X connect 11 0 26 0; #X connect 14 0 26 0; #X connect 15 0 26 0; #X connect 17 0 26 0; #X connect 19 0 26 0; #X connect 21 0 26 0; #X connect 27 0 67 0; #X connect 29 0 67 0; #X connect 32 0 67 0; #X connect 34 0 67 0; #X connect 35 0 67 0; #X connect 37 0 67 0; #X connect 38 0 67 0; #X connect 42 0 67 0; #X connect 45 0 67 0; #X connect 46 0 67 0; #X connect 48 0 67 0; #X connect 50 0 67 0; #X connect 51 0 67 0; #X connect 54 0 67 0; #X connect 55 0 67 0; #X connect 56 0 67 0; #X connect 59 0 67 0; #X connect 60 0 67 0; #X connect 63 0 67 0; #X connect 64 0 67 0; #X connect 70 0 80 0; #X connect 71 0 80 0; #X connect 72 0 80 0; #X connect 73 0 80 0; #X connect 76 0 80 0; #X connect 79 0 80 0; #X connect 81 0 26 0; #X connect 83 0 26 0; #X connect 86 0 26 0; #X restore 408 167 pd NETWORK_COMMANDS; #N canvas 3 90 450 300 RADIO_COMMANDS 0; #X text 129 52 get power level; #X msg 91 53 AT PL; #X msg 111 73 AT PM; #X text 149 72 get power mode; #X msg 131 93 AT DB; #X msg 151 113 AT PP; #X text 189 112 get peak power dBm; #X text 169 92 get received signal strength -dBm; #X obj 187 166 s topackxbee; #X connect 1 0 8 0; #X connect 2 0 8 0; #X connect 4 0 8 0; #X connect 5 0 8 0; #X restore 408 129 pd RADIO_COMMANDS; #N canvas 3 90 675 320 SERIAL_COMMANDS 0; #X obj 280 290 s topackxbee; #X text 83 37 get API mode; #X msg 45 38 AT AP; #X msg 125 118 AT AO; #X text 163 117 get API options; #X msg 155 148 AT BD; #X text 193 147 get interface data rate; #X msg 175 168 AT NB; #X text 213 167 get interface parity; #X msg 195 188 AT SB; #X text 233 187 get interface stop bits; #X msg 215 208 AT RO; #X text 253 207 get packetization timeout; #X text 114 57 set API mode; #X msg 65 58 AT AP 1; #X text 134 77 set API mode; #X msg 85 78 AT AP 2; #X msg 106 99 AT CC; #X text 145 96 get AT command sequence character; #X text 440 79 queue set interface data rate; #X msg 366 79 ATQ BD 7; #X text 460 99 queue set interface data rate; #X msg 386 99 ATQ BD 3; #X obj 490 220 s topackxbee; #X msg 246 239 AT VR; #X text 285 236 get firmware version; #X msg 266 259 AT HV; #X text 305 256 get hardware version; #X msg 419 132 AT AC; #X text 459 130 apply changes; #X connect 2 0 0 0; #X connect 3 0 0 0; #X connect 5 0 0 0; #X connect 7 0 0 0; #X connect 9 0 0 0; #X connect 11 0 0 0; #X connect 14 0 0 0; #X connect 16 0 0 0; #X connect 17 0 0 0; #X connect 20 0 23 0; #X connect 22 0 23 0; #X connect 24 0 0 0; #X connect 26 0 0 0; #X connect 28 0 23 0; #X restore 408 110 pd SERIAL_COMMANDS; #N canvas 3 90 450 233 DANGEROUS_COMMANDS 0; #X obj 185 172 s topackxbee; #X msg 72 42 AT AC; #X text 112 40 apply changes; #X msg 92 62 AT WR; #X text 132 60 write parameters to non-volatile memory; #X msg 112 82 AT RE; #X text 152 80 restore defaults; #X msg 132 102 AT FR; #X text 172 100 software reset; #X msg 152 122 AT NR; #X text 192 120 network reset; #X msg 172 142 AT CB 1; #X text 222 140 commisioning pushbutton; #X text 25 25 ***DANGEROUS***; #X connect 1 0 0 0; #X connect 3 0 0 0; #X connect 5 0 0 0; #X connect 7 0 0 0; #X connect 9 0 0 0; #X connect 11 0 0 0; #X restore 408 187 pd DANGEROUS_COMMANDS; #N canvas 368 164 744 407 TRANSMIT_COMMANDS 0; #X obj 172 292 s topackxbee; #X msg 79 182 TX 0x0013A20040769444 0xFFFE 0 0 1 2 3 4; #X obj 60 107 hsl 128 15 0 127 0 0 empty empty empty -2 -8 0 10 -262144 -1 -1 0 0; #X obj 57 126 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -8 0 10 -262144 -1 -1 0 256; #X obj 57 84 f; #X obj 100 84 + 1; #X obj 144 82 % 128; #X obj 57 42 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1 ; #X obj 57 62 metro 2000; #X text 22 326 (prefix hexadecimal parameters with 0x to force Pd to see them as symbols); #X text 314 225 Series 1 data packet: 64-bit_destination options data ; #X msg 121 224 TX64 0x0013A200406ADE1E 0 255; #X msg 144 247 TX16 0x79D5 0 255; #X text 257 248 Series 1 data packet: 16-bit_destination options data ; #X text 281 151 Series 2 data packet: 64-bit_destination 16-bit_destination broadcast_radius options data; #X msg 57 160 TX 0x0013A200406BFE6C 0x9A17 0 0 \$1; #X msg 100 203 TX 0x0013A200406ADE1E 0x79D6 0 0 64; #X connect 1 0 0 0; #X connect 2 0 3 0; #X connect 3 0 15 0; #X connect 4 0 5 0; #X connect 4 0 2 0; #X connect 5 0 6 0; #X connect 6 0 4 1; #X connect 7 0 8 0; #X connect 8 0 4 0; #X connect 11 0 0 0; #X connect 12 0 0 0; #X connect 15 0 0 0; #X connect 16 0 0 0; #X restore 408 70 pd TRANSMIT_COMMANDS; #X msg 85 100 verbosity \$1; #X obj 83 79 hradio 15 1 0 3 empty empty verbosity 0 -8 0 10 -4034 -1 -1 0; #X obj 58 244 print packet; #X obj 457 444 print serial_info; #X text 148 375 set the interface baud rate; #X text 302 300 (find the one with an xbee connected to it); #X text 6 300 list available serial ports to console; #X text 65 320 open a port by number or by name; #X text 128 340 get current serial status; #X obj 214 264 spigot; #X obj 247 245 tgl 15 0 empty empty transmit_packets 17 7 0 10 -4034 -1 -1 0 1; #X obj 387 509 print serial_in; #X obj 249 135 packxbee-example; #X text -9 113 [packxbee] formats packets for use with xbees in API modes 1 or 2; #X text -9 150 [packxbee] outputs lists of bytes that are typically passed to a [comport] object.; #X obj 360 427 comport 98 9600; #X text -10 626 The output of [comport] can be connected to an [unpackxbee] object to (at least partially) unpack the received packets.; #N canvas 195 133 741 379 REMOTE_COMMANDS 0; #X obj 72 25 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1 ; #X msg 72 138 4; #X msg 117 138 5; #X obj 72 74 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1 ; #X obj 72 95 sel 0 1; #X obj 72 50 metro 200; #X msg 223 206 RAT 0x0013A200406BFE6C 0x51D6 0 SL; #X text 169 123 remote AT command: 64-bit address \, 16-bit address \, options \, command \, parameters; #X obj 294 294 s topackxbee; #X msg 171 154 RAT 0x0013A200406BFE6C 0x9A17 2 P1 \$1; #X msg 246 230 RAT 0x0013A200406BFE6C 0x9A17 2 D0 4; #X text 324 250 switch remote IO pin 0 low (options = 2 = apply changes immediately); #X text 203 169 set PWM1/DIO11 (pin 7) on remote xbee to digital out high or low immediately; #X msg 29 263 RAT 0x0013A200406BFE6C 0x9A17 0; #X obj 29 285 list append; #X obj 29 306 list trim; #X obj 29 232 t b a; #X msg 29 195 IS; #X text 56 194 force sample; #X obj 28 326 s topackxbee; #X connect 0 0 5 0; #X connect 1 0 9 0; #X connect 2 0 9 0; #X connect 3 0 4 0; #X connect 4 0 1 0; #X connect 4 1 2 0; #X connect 5 0 3 0; #X connect 6 0 8 0; #X connect 9 0 8 0; #X connect 10 0 8 0; #X connect 13 0 14 0; #X connect 14 0 15 0; #X connect 15 0 19 0; #X connect 16 0 13 0; #X connect 16 1 14 1; #X connect 17 0 16 0; #X restore 408 90 pd REMOTE_COMMANDS; #N canvas 235 602 596 319 sample_frame 0; #X obj 62 53 inlet; #X obj 62 106 route D0 D1 D2 D3 D4 D5 D10 D11 D12 A0 A1 A2 A3 A7; #X obj 56 136 cnv 15 300 50 empty empty Digital_Inputs 20 12 0 14 -204786 -13381 0; #X obj 56 187 cnv 15 400 90 empty empty Analog_Inputs 20 12 0 14 -232576 -45076 0; #X obj 59 220 nbx 5 14 -1e+37 1e+37 0 0 empty empty A0 40 8 0 10 -204800 -13330 -159808 0 256; #X obj 119 220 nbx 5 14 -1e+37 1e+37 0 0 empty empty A1 40 8 0 10 -204800 -13330 -159808 0 256; #X obj 179 220 nbx 5 14 -1e+37 1e+37 0 0 empty empty A2 40 8 0 10 -204800 -13330 -159808 0 256; #X obj 239 220 nbx 5 14 -1e+37 1e+37 0 0 empty empty A3 40 8 0 10 -204800 -13330 -159808 0 256; #X obj 299 220 nbx 5 14 -1e+37 1e+37 0 0 empty empty V+ 40 8 0 10 -204800 -13330 -159808 0 256; #X obj 62 162 nbx 2 14 -1e+37 1e+37 0 0 empty empty D0 8 20 0 10 -4034 -1 -258113 0 256; #X obj 102 162 nbx 2 14 -1e+37 1e+37 0 0 empty empty D1 8 20 0 10 -4034 -1 -258113 0 256; #X obj 132 162 nbx 2 14 -1e+37 1e+37 0 0 empty empty D2 8 20 0 10 -4034 -1 -258113 0 256; #X obj 162 162 nbx 2 14 -1e+37 1e+37 0 0 empty empty D3 8 20 0 10 -4034 -1 -258113 0 256; #X obj 192 162 nbx 2 14 -1e+37 1e+37 0 0 empty empty D4 8 20 0 10 -4034 -1 -258113 0 256; #X obj 222 162 nbx 2 14 -1e+37 1e+37 0 0 empty empty D5 8 20 0 10 -4034 -1 -258113 0 256; #X obj 252 162 nbx 2 14 -1e+37 1e+37 0 0 empty empty P0 8 20 0 10 -4034 -1 -258113 0 256; #X obj 282 162 nbx 2 14 -1e+37 1e+37 0 0 empty empty P1 8 20 0 10 -4034 -1 -258113 0 256; #X obj 312 162 nbx 2 14 -1e+37 1e+37 0 0 empty empty P2 8 20 0 10 -4034 -1 -258113 0 256; #X obj 59 259 nbx 5 14 -1e+37 1e+37 0 0 empty empty A0_mV 40 8 0 10 -204800 -13330 -159808 0 256; #X obj 59 239 * 1.17302; #X obj 139 259 nbx 5 14 -1e+37 1e+37 0 0 empty empty A1_mV 40 8 0 10 -204800 -13330 -159808 0 256; #X obj 139 239 * 1.17302; #X obj 219 259 nbx 5 14 -1e+37 1e+37 0 0 empty empty A2_mV 40 8 0 10 -204800 -13330 -159808 0 256; #X obj 219 239 * 1.17302; #X obj 299 259 nbx 5 14 -1e+37 1e+37 0 0 empty empty A3_mV 40 8 0 10 -204800 -13330 -159808 0 256; #X obj 299 239 * 1.17302; #X obj 379 259 nbx 5 14 -1e+37 1e+37 0 0 empty empty V+_mV 40 8 0 10 -204800 -13330 -159808 0 256; #X obj 379 239 * 1.17302; #X obj 62 78 list trim; #X obj 359 130 print more_sample_frame_stuff; #X connect 0 0 28 0; #X connect 1 0 9 0; #X connect 1 1 10 0; #X connect 1 2 11 0; #X connect 1 3 12 0; #X connect 1 4 13 0; #X connect 1 5 14 0; #X connect 1 6 15 0; #X connect 1 7 16 0; #X connect 1 8 17 0; #X connect 1 9 4 0; #X connect 1 9 19 0; #X connect 1 10 5 0; #X connect 1 10 21 0; #X connect 1 11 6 0; #X connect 1 11 23 0; #X connect 1 12 7 0; #X connect 1 12 25 0; #X connect 1 13 8 0; #X connect 1 13 27 0; #X connect 1 14 29 0; #X connect 19 0 18 0; #X connect 21 0 20 0; #X connect 23 0 22 0; #X connect 25 0 24 0; #X connect 27 0 26 0; #X connect 28 0 1 0; #X restore 394 714 pd sample_frame; #X obj 401 222 cnv 15 150 60 empty empty empty 20 12 0 14 -261234 -66577 0; #X text 404 221 remote xbee pin control:; #X obj 426 251 xbeeio; #X connect 6 0 24 0; #X connect 7 0 51 0; #X connect 8 0 24 0; #X connect 9 0 24 0; #X connect 13 0 51 0; #X connect 14 0 51 0; #X connect 15 0 25 0; #X connect 16 0 15 0; #X connect 17 0 25 0; #X connect 17 1 20 0; #X connect 20 0 47 0; #X connect 21 0 20 1; #X connect 22 0 38 0; #X connect 23 0 22 1; #X connect 24 0 22 0; #X connect 24 0 45 0; #X connect 25 0 18 0; #X connect 25 1 54 0; #X connect 25 2 19 0; #X connect 28 0 51 0; #X connect 29 0 51 0; #X connect 36 0 24 0; #X connect 37 0 36 0; #X connect 45 0 51 0; #X connect 46 0 45 1; #X connect 51 0 17 0; #X connect 51 1 39 0; mrpeach/xbee/bits.pd0000644000175000017500000000423212112750177015144 0ustar zmoelnigzmoelnig#N canvas 218 231 1058 225 10; #X obj 37 29 inlet; #X obj 37 159 outlet; #X obj 37 77 & 32768; #X obj 87 77 & 16384; #X obj 137 77 & 8192; #X obj 187 77 & 4096; #X obj 237 77 & 2048; #X obj 287 77 & 1024; #X obj 337 77 & 512; #X obj 387 77 & 256; #X obj 437 77 & 128; #X obj 487 77 & 64; #X obj 537 77 & 32; #X obj 587 77 & 16; #X obj 637 77 & 8; #X obj 687 77 & 4; #X obj 737 77 & 2; #X obj 787 77 & 1; #X text 837 84 Martin Peach 2013_02_21; #X obj 37 118 != 0; #X obj 87 159 outlet; #X obj 87 118 != 0; #X obj 137 159 outlet; #X obj 137 118 != 0; #X obj 187 159 outlet; #X obj 187 118 != 0; #X obj 237 159 outlet; #X obj 237 118 != 0; #X obj 287 159 outlet; #X obj 287 118 != 0; #X obj 337 159 outlet; #X obj 337 118 != 0; #X obj 387 159 outlet; #X obj 387 118 != 0; #X obj 437 159 outlet; #X obj 437 118 != 0; #X obj 487 159 outlet; #X obj 487 118 != 0; #X obj 537 159 outlet; #X obj 537 118 != 0; #X obj 587 159 outlet; #X obj 587 118 != 0; #X obj 637 159 outlet; #X obj 637 118 != 0; #X obj 687 159 outlet; #X obj 687 118 != 0; #X obj 737 159 outlet; #X obj 737 118 != 0; #X obj 787 159 outlet; #X obj 787 118 != 0; #X text 104 30 [bits] outputs up to 16 bits of a number; #X connect 0 0 2 0; #X connect 0 0 3 0; #X connect 0 0 4 0; #X connect 0 0 5 0; #X connect 0 0 6 0; #X connect 0 0 7 0; #X connect 0 0 8 0; #X connect 0 0 9 0; #X connect 0 0 10 0; #X connect 0 0 11 0; #X connect 0 0 12 0; #X connect 0 0 13 0; #X connect 0 0 14 0; #X connect 0 0 15 0; #X connect 0 0 16 0; #X connect 0 0 17 0; #X connect 2 0 19 0; #X connect 3 0 21 0; #X connect 4 0 23 0; #X connect 5 0 25 0; #X connect 6 0 27 0; #X connect 7 0 29 0; #X connect 8 0 31 0; #X connect 9 0 33 0; #X connect 10 0 35 0; #X connect 11 0 37 0; #X connect 12 0 39 0; #X connect 13 0 41 0; #X connect 14 0 43 0; #X connect 15 0 45 0; #X connect 16 0 47 0; #X connect 17 0 49 0; #X connect 19 0 1 0; #X connect 21 0 20 0; #X connect 23 0 22 0; #X connect 25 0 24 0; #X connect 27 0 26 0; #X connect 29 0 28 0; #X connect 31 0 30 0; #X connect 33 0 32 0; #X connect 35 0 34 0; #X connect 37 0 36 0; #X connect 39 0 38 0; #X connect 41 0 40 0; #X connect 43 0 42 0; #X connect 45 0 44 0; #X connect 47 0 46 0; #X connect 49 0 48 0; mrpeach/xbee/unpackxbee.c0000644000175000017500000007113712222625545016161 0ustar zmoelnigzmoelnig/* [unpackxbee] outputs a list of floats which are the bytes making up the data part of an xbee api packet. */ /* a status outlet provides the address and status information for each packet received */ /* a sample outlet emits IO samples */ /* [unpackxbee]'s inlet is typically connected to the data outlet of a [comport] object */ /* Started by Martin Peach 20110731 */ /* Information taken from "XBee/XBee-PRO ZB RF Modules" (document 90000976_G, 11/15/2010)*/ /* by Digi International Inc. http://www.digi.com */ /* Series 1 info from "XBee/XBee-PRO RF Modules" (document 90000982_L 4/30/2013) */ #include //#include #include "m_pd.h" #include "pdxbee.h" static t_class *unpackxbee_class; typedef struct _unpackxbee { t_object x_obj; t_outlet *x_status_out; t_outlet *x_sample_out; t_outlet *x_payload_out; int x_api_mode; unsigned char x_frame_ID; unsigned char x_frame_type; unsigned int x_frame_length; int x_verbosity; unsigned char x_message[MAX_XBEE_PACKET_LENGTH]; unsigned int x_message_index; int x_escaped; t_atom x_outbuf[MAX_XBEE_PACKET_LENGTH]; } t_unpackxbee; static void *unpackxbee_new(t_floatarg f); static void unpackxbee_input(t_unpackxbee *x, t_symbol *s, int argc, t_atom *argv); static void unpackxbee_API(t_unpackxbee *x, t_float api); static void unpackxbee_verbosity(t_unpackxbee *x, t_float verbosity_level); static int unpackxbee_add(t_unpackxbee *x, unsigned char d); static void unpackxbee_free(t_unpackxbee *x); void unpackxbee_setup(void); static void *unpackxbee_new(t_floatarg f) { int i; t_unpackxbee *x = (t_unpackxbee *)pd_new(unpackxbee_class); if (x) { x->x_payload_out = outlet_new(&x->x_obj, &s_list); /* the outlet on the left fro raw data */ x->x_sample_out = outlet_new(&x->x_obj, &s_list); /* the middle outlet for sample frames */ x->x_status_out = outlet_new(&x->x_obj, &s_list); /* the rightmost outlet for status */ if (1 == f) x->x_api_mode = 1; else x->x_api_mode = 2; /* default to escaped mode */ x->x_verbosity = 0; /* debug level */ for(i = 0; i < MAX_XBEE_PACKET_LENGTH; ++i) x->x_outbuf[i].a_type = A_FLOAT; /* init output atoms as floats */ } return (x); } static void unpackxbee_API(t_unpackxbee *x, t_float api) { if ((api == 1) || (api ==2)) x->x_api_mode = api; else error ("unpackxbee: api mode must be 1 or 2"); } static void unpackxbee_verbosity(t_unpackxbee *x, t_float verbosity_level) { if (verbosity_level >= 0) x->x_verbosity = verbosity_level; else error ("packxbee: verbosity_level must be positive"); } static int unpackxbee_add(t_unpackxbee *x, unsigned char d) { if (XFRAME == d) { if (x->x_verbosity > 0) post ("frame start"); x->x_message_index = 0; x->x_frame_length = 0; x->x_frame_type = 0; x->x_escaped = 0; } if (2 == x->x_api_mode) { if (XSCAPE == d) { x->x_escaped = 1; /* we need to xor the next character with 0x20 */ return 0; /* don't store the escape character */ } else if (1 == x->x_escaped) { d ^= 0x20; /* xor with 0x20 to restore the original character */ x->x_escaped = 0; /* don't do it again */ } } if (LENGTH_LSB_INDEX == x->x_message_index) /* length is a bigendian pair */ { x->x_frame_length = (x->x_message[LENGTH_MSB_INDEX]<<8) + d; if (x->x_verbosity > 0) post ("frame length %d", x->x_frame_length); } else if (FRAME_TYPE_INDEX == x->x_message_index) { x->x_frame_type = d; if (x->x_verbosity > 0) post ("frame type 0x%02X", x->x_frame_type); } else if (FRAME_ID_INDEX == x->x_message_index) { /* this is part of the payload and may not be valid in some frame types */ x->x_frame_ID = d; if (x->x_verbosity > 0) post ("frame ID %d", x->x_frame_ID); } x->x_message[x->x_message_index++] = d; /* add the unescaped character to the output list */ return 1; } static void unpackxbee_input(t_unpackxbee *x, t_symbol *s, int argc, t_atom *argv) { int i , j, k; t_float f; unsigned int d, checksum = 0; unsigned char c; t_symbol *type_selector; int statuslength = 0, payloadstart = 0; int payload_is_sample_frame = 0; int digital_bits = 0, digital_ins = 0, digital_channel = 0; int analog_bits = 0, analog_channel = 0; char atbuf[64]; unsigned char floatstring[256]; /* longer than the longest hex number with each character escaped plus the header and checksum overhead */ t_atom status_atoms[32]; /* some number bigger than we will ever reach */ t_atom sample_atoms[12]; /* up to 5 analog samples + 1 digital sample + their names */ unsigned long long addr64; unsigned int addr16; if (x->x_verbosity > 0) post("unpackxbee_input: s is %s, argc is %d", s->s_name, argc); for (i = 0; i < argc; ++i) { if (A_FLOAT == argv[i].a_type) { f = argv[i].a_w.w_float; d = ((unsigned int)f)&0x0FF; if (x->x_verbosity > 0) post("unpackxbee_input: argv[%d] is %f int is %d", i, f, d); if (f != d) { post ("unpackxbee_input not a positive integer from 0 to 255"); } else unpackxbee_add(x, d); } else post("unpackxbee_input: item %d is not a float", i+1); } if ((x->x_frame_length > 0)&&(x->x_frame_length + 4 == x->x_message_index)) { /* end of frame reached */ k = x->x_frame_length+4; /* total packet length is payload + 1 start 2 length 1 checksum*/ if(x->x_verbosity > 0) { post("frame end"); for (j = 0; j < k; ++j) { c = x->x_message[j]; post("unpackxbee buf[%d]: %d [0x%02X]", j, c, c); } } for (j = 3; j < k; ++j) { checksum += x->x_message[j]; } checksum &= 0x0FF; if (checksum != 0xFF) { post("unpackxbee: wrong checksum; dropping packet"); return; } if(x->x_verbosity > 0) post("unpackxbee checksum %d [0x%02X]", checksum, checksum); switch(x->x_frame_type) { case AT_Command: type_selector = gensym("AT_Command"); break; case AT_Command_Queue_Parameter_Value: type_selector = gensym("AT_Command_Queue_Parameter_Value"); break; case ZigBee_Transmit_Request: type_selector = gensym("ZigBee_Transmit_Request"); break; case Explicit_Addressing_ZigBee_Command_Frame: type_selector = gensym("Explicit_Addressing_ZigBee_Command_Frame"); break; case Remote_Command_Request: type_selector = gensym("Remote_Command_Request"); break; case Create_Source_Route: type_selector = gensym("Create_Source_Route"); break; case AT_Command_Response: type_selector = gensym("AT_Command_Response"); break; case Modem_Status: type_selector = gensym("Modem_Status"); break; case Transmit_Status: type_selector = gensym("Transmit_Status"); break; case ZigBee_Transmit_Status: type_selector = gensym("ZigBee_Transmit_Status"); break; case ZigBee_Receive_Packet: type_selector = gensym("ZigBee_Receive_Packet"); break; case Receive_Packet_64_Bit_Address: type_selector = gensym("Receive_Packet_64_Bit_Address"); break; case Receive_Packet_16_Bit_Address: type_selector = gensym("Receive_Packet_16_Bit_Address"); break; case Receive_Packet_64_Bit_Address_IO: type_selector = gensym("Receive_Packet_64_Bit_Address_IO"); break; case Receive_Packet_16_Bit_Address_IO: type_selector = gensym("Receive_Packet_16_Bit_Address_IO"); break; case ZigBee_Explicit_Rx_Indicator: type_selector = gensym("ZigBee_Explicit_Rx_Indicator"); break; case ZigBee_IO_Data_Sample_Rx_Indicator: type_selector = gensym("ZigBee_IO_Data_Sample_Rx_Indicator"); break; case XBee_Sensor_Read_Indicator: type_selector = gensym("XBee_Sensor_Read_Indicator"); break; case Node_Identification_Indicator: type_selector = gensym("Node_Identification_Indicator"); break; case Remote_Command_Response: type_selector = gensym("Remote_Command_Response"); break; case Over_the_Air_Firmware_Update_Status: type_selector = gensym("Over_the_Air_Firmware_Update_Status"); break; case Route_Record_Indicator: type_selector = gensym("Route_Record_Indicator"); break; case Many_to_One_Route_Request_Indicator: type_selector = gensym("Many_to_One_Route_Request_Indicator"); break; default: type_selector = gensym("unknown"); } statuslength = 0; SETFLOAT(&status_atoms[statuslength], x->x_frame_type); statuslength++; switch (x->x_frame_type) { case AT_Command_Response: case AT_Command: case AT_Command_Queue_Parameter_Value: if (x->x_verbosity > 0) post("AT_Command_Response AT_Command AT_Command_Queue_Parameter_Value statuslength %d", statuslength); SETFLOAT(&status_atoms[statuslength], x->x_frame_ID); statuslength++; /* data doesn't include 1byte frame type 1byte ID 2byte AT command 1byte AT command status = 5bytes */ SETFLOAT(&status_atoms[statuslength], x->x_frame_length-5); statuslength++; atbuf[0] = x->x_message[5]; /* the AT command string */ atbuf[1] = x->x_message[6]; atbuf[2] = '\0'; SETSYMBOL(&status_atoms[statuslength], gensym(atbuf)); statuslength++; SETFLOAT(&status_atoms[statuslength], x->x_message[7]);/* AT command status */ statuslength++; if ((0 == x->x_message[7]) && ('N' == x->x_message[5]) && ('D' == x->x_message[6])) { /* a succesful node discover response: output the addresses as symbols */ /* buf[0]: 126 [0x7E] ND packet start buf[1]: 0 [0x00] Length MSB buf[2]: 25 [0x19] Length LSB buf[3]: 136 [0x88] AT response buf[4]: 5 [0x05] packet ID buf[5]: 78 [0x4E] N buf[6]: 68 [0x44] D buf[7]: 0 [0x00] status */ addr16 = (x->x_message[8]<<8) + x->x_message[9]; sprintf((char *)floatstring, "0x%X", addr16); SETSYMBOL(&status_atoms[statuslength], gensym((char *)floatstring)); statuslength++; /* buf[8]: 121 [0x79] MY buf[9]: 214 [0xD6] */ /* now switch endianness */ addr64 = x->x_message[10]; addr64 <<= 8; addr64 |= x->x_message[11]; addr64 <<= 8; addr64 |= x->x_message[12]; addr64 <<= 8; addr64 |= x->x_message[13]; addr64 <<= 8; addr64 |= x->x_message[14]; addr64 <<= 8; addr64 |= x->x_message[15]; addr64 <<= 8; addr64 |= x->x_message[16]; addr64 <<= 8; addr64 |= x->x_message[17]; #ifdef _MSC_VER sprintf((char *)floatstring, "0x%016I64X", addr64); #else sprintf((char *)floatstring, "0x%016LX", addr64); #endif SETSYMBOL(&status_atoms[statuslength], gensym((char *)floatstring)); /* addr64 */ statuslength++; /* buf[10]: 0 [0x00] SH buf[11]: 19 [0x13] buf[12]: 162 [0xA2] buf[13]: 0 [0x00] buf[14]: 64 [0x40] SL buf[15]: 106 [0x6A] buf[16]: 222 [0xDE] buf[17]: 30 [0x1E] */ for (j = 0, i = 18; i < k; ++i, ++j) { floatstring[j] = x->x_message[i]; if (0 == floatstring[j]) { i++; break;/* Node Identifier should be a null-terminated ascii string */ } } SETSYMBOL(&status_atoms[statuslength], gensym((char *)floatstring)); /* Node Identifier */ statuslength++; /* buf[18]: 32 [0x20] NI buf[19]: 0 [0x00] */ addr16 = (x->x_message[i]<<8) + x->x_message[i+1]; sprintf((char *)floatstring, "0x%X", addr16); i += 2; SETSYMBOL(&status_atoms[statuslength], gensym((char *)floatstring)); /* parent addr16 */ statuslength++; /* buf[20]: 255 [0xFF] parent buf[21]: 254 [0xFE] */ SETFLOAT(&status_atoms[statuslength], x->x_message[i++]);/* Device Type */ statuslength++; /* buf[22]: 1 [0x01] device type */ SETFLOAT(&status_atoms[statuslength], x->x_message[i++]);/* Source Event */ statuslength++; /* buf[23]: 0 [0x00] source event */ addr16 = x->x_message[i++]<<8; addr16 |= x->x_message[i++]; sprintf((char *)floatstring, "0x%X", addr16); SETSYMBOL(&status_atoms[statuslength], gensym((char *)floatstring)); /* Profile ID */ statuslength++; /* buf[24]: 193 [0xC1] Profile ID buf[25]: 5 [0x05] */ addr16 = (x->x_message[i]<<8) + x->x_message[i+1]; sprintf((char *)floatstring, "0x%X", addr16); i += 2; SETSYMBOL(&status_atoms[statuslength], gensym((char *)floatstring)); /* Manufacturer ID */ statuslength++; /* buf[26]: 16 [0x10] Manufacturer ID buf[27]: 30 [0x1E] */ /* buf[28]: 36 [0x24] checksum */ payloadstart = 0;/* no payload */ } else { payloadstart = 8; } break; /* RAT */ case Remote_Command_Response: if (x->x_verbosity > 0) post("Remote_Command_Response statuslength %d", statuslength); SETFLOAT(&status_atoms[statuslength], x->x_frame_ID); statuslength++; /* buf[0]: 126 [0x7E] packet start buf[1]: 0 [0x00] Length MSB buf[2]: 25 [0x19] Length LSB buf[3]: 151 [0x97] remote response frame type buf[4]: 5 [0x05] packet ID buf[5-12]: 0 [0x00] 64-bit source (remote) address buf[13-14]: 68 [0x44] 16-bit source address buf[15-16]: AT command buf[17]: status buf[18...] data */ addr64 = x->x_message[5]; addr64 <<= 8; addr64 |= x->x_message[6]; addr64 <<= 8; addr64 |= x->x_message[7]; addr64 <<= 8; addr64 |= x->x_message[8]; addr64 <<= 8; addr64 |= x->x_message[9]; addr64 <<= 8; addr64 |= x->x_message[10]; addr64 <<= 8; addr64 |= x->x_message[11]; addr64 <<= 8; addr64 |= x->x_message[12]; #ifdef _MSC_VER sprintf((char *)floatstring, "0x%016I64X", addr64); #else sprintf((char *)floatstring, "0x%016LX", addr64); #endif SETSYMBOL(&status_atoms[statuslength], gensym((char *)floatstring)); /* addr64 */ statuslength++; addr16 = (x->x_message[13]<<8) + x->x_message[14]; sprintf((char *)floatstring, "0x%X", addr16); SETSYMBOL(&status_atoms[statuslength], gensym((char *)floatstring)); statuslength++; atbuf[0] = x->x_message[15]; /* the remote AT command string */ atbuf[1] = x->x_message[16]; atbuf[2] = '\0'; SETSYMBOL(&status_atoms[statuslength], gensym(atbuf)); statuslength++; if ((atbuf[0] == 'I') && (atbuf[1] == 'S')) payload_is_sample_frame = 1; /* output sample frame via middle outlet */ SETFLOAT(&status_atoms[statuslength], x->x_message[17]);/* AT command status */ statuslength++; /* data doesn't include 1byte frame type 1byte ID 8byte addr64 2byte addr16 2byte AT command 1byte status = 15bytes */ SETFLOAT(&status_atoms[statuslength], x->x_frame_length-15); statuslength++; payloadstart = 18; break; /* RAT */ case Transmit_Status: if (x->x_verbosity > 0) post("Transmit_Status statuslength %d", statuslength); SETFLOAT(&status_atoms[statuslength], x->x_frame_ID); statuslength++; SETFLOAT(&status_atoms[statuslength], x->x_message[5]);/* Delivery Status */ statuslength++; payloadstart = 0; /* no payload */ break; case ZigBee_Transmit_Status: if (x->x_verbosity > 0) post("ZigBee_Transmit_Status statuslength %d", statuslength); SETFLOAT(&status_atoms[statuslength], x->x_frame_ID); statuslength++; sprintf(atbuf, "0x%X", (x->x_message[5]<<8) + x->x_message[6]); /* the 16-bit address as a symbol */ SETSYMBOL(&status_atoms[statuslength], gensym(atbuf)); statuslength++; SETFLOAT(&status_atoms[statuslength], x->x_message[7]);/* Transmit Retry Count */ statuslength++; SETFLOAT(&status_atoms[statuslength], x->x_message[8]);/* Delivery Status */ statuslength++; SETFLOAT(&status_atoms[statuslength], x->x_message[9]);/* Discovery Status */ statuslength++; payloadstart = 0; /* no payload */ break; case ZigBee_Receive_Packet: if (x->x_verbosity > 0) post("ZigBee_Receive_Packet statuslength %d", statuslength); /* data doesn't include 1byte frametype, 8byte addr64, 2byte addr16, 1byte options = 12bytes*/ SETFLOAT(&status_atoms[statuslength], x->x_frame_length-12); statuslength++; /* frame type */ /* 64-bit source address */ i = 4; addr64 = x->x_message[i++]; addr64 <<= 8; addr64 |= x->x_message[i++]; addr64 <<= 8; addr64 |= x->x_message[i++]; addr64 <<= 8; addr64 |= x->x_message[i++]; addr64 <<= 8; addr64 |= x->x_message[i++]; addr64 <<= 8; addr64 |= x->x_message[i++]; addr64 <<= 8; addr64 |= x->x_message[i++]; addr64 <<= 8; addr64 |= x->x_message[i++]; #ifdef _MSC_VER sprintf((char *)floatstring, "0x%016I64X", addr64); #else sprintf((char *)floatstring, "0x%016LX", addr64); #endif SETSYMBOL(&status_atoms[statuslength], gensym((char *)floatstring)); /* addr64 */ statuslength++; /* 16-bit source address */ addr16 = x->x_message[i++]<<8; addr16 |= x->x_message[i++]; sprintf((char *)floatstring, "0x%X", addr16); SETSYMBOL(&status_atoms[statuslength], gensym((char *)floatstring)); /* addr16 */ statuslength++; /* receive options byte */ SETFLOAT(&status_atoms[statuslength], x->x_message[i++]);/* 1 2 32 64 */ statuslength++; /* data */ payloadstart = i; break; case Receive_Packet_64_Bit_Address: if (x->x_verbosity > 0) post("Receive_Packet_64_Bit_Address statuslength %d", statuslength); /* data doesn't include 1byte frametype, 8byte addr64, 1byte RSSI, 1byte options = 11bytes*/ SETFLOAT(&status_atoms[statuslength], x->x_frame_length-11); statuslength++; /* frame type */ /* 64-bit source address */ i = 4; addr64 = x->x_message[i++]; addr64 <<= 8; addr64 |= x->x_message[i++]; addr64 <<= 8; addr64 |= x->x_message[i++]; addr64 <<= 8; addr64 |= x->x_message[i++]; addr64 <<= 8; addr64 |= x->x_message[i++]; addr64 <<= 8; addr64 |= x->x_message[i++]; addr64 <<= 8; addr64 |= x->x_message[i++]; addr64 <<= 8; addr64 |= x->x_message[i++]; #ifdef _MSC_VER sprintf((char *)floatstring, "0x%016I64X", addr64); #else sprintf((char *)floatstring, "0x%016LX", addr64); #endif SETSYMBOL(&status_atoms[statuslength], gensym((char *)floatstring)); /* addr64 */ statuslength++; /* receive signal strength indicator */ SETFLOAT(&status_atoms[statuslength], x->x_message[i++]); statuslength++; /* receive options byte */ SETFLOAT(&status_atoms[statuslength], x->x_message[i++]);/* 1 2 32 64 */ statuslength++; /* data */ payloadstart = i; break; case Receive_Packet_16_Bit_Address: if (x->x_verbosity > 0) post("Receive_Packet_16_Bit_Address statuslength %d", statuslength); /* data doesn't include 1byte frametype, 2byte addr64, 1byte RSSI, 1byte options = 5bytes*/ SETFLOAT(&status_atoms[statuslength], x->x_frame_length-5); statuslength++; /* frame type */ /* 16-bit source address */ i = 4; /* 16-bit source address */ addr16 = x->x_message[i++]<<8; addr16 |= x->x_message[i++]; sprintf((char *)floatstring, "0x%X", addr16); SETSYMBOL(&status_atoms[statuslength], gensym((char *)floatstring)); /* addr16 */ statuslength++; /* receive signal strength indicator */ SETFLOAT(&status_atoms[statuslength], x->x_message[i++]); statuslength++; /* receive options byte */ SETFLOAT(&status_atoms[statuslength], x->x_message[i++]);/* 1 2 32 64 */ statuslength++; /* data */ payloadstart = i; break; case ZigBee_IO_Data_Sample_Rx_Indicator: if (x->x_verbosity > 0) post("ZigBee_IO_Data_Sample_Rx_Indicator statuslength %d", statuslength); payload_is_sample_frame = 1; /* data doesn't include 1byte frametype, 8byte addr64, 2byte addr16, 1byte options = 12bytes*/ SETFLOAT(&status_atoms[statuslength], x->x_frame_length-12); statuslength++; /* frame type */ /* 64-bit source address */ i = 4; addr64 = x->x_message[i++]; addr64 <<= 8; addr64 |= x->x_message[i++]; addr64 <<= 8; addr64 |= x->x_message[i++]; addr64 <<= 8; addr64 |= x->x_message[i++]; addr64 <<= 8; addr64 |= x->x_message[i++]; addr64 <<= 8; addr64 |= x->x_message[i++]; addr64 <<= 8; addr64 |= x->x_message[i++]; addr64 <<= 8; addr64 |= x->x_message[i++]; #ifdef _MSC_VER sprintf((char *)floatstring, "0x%016I64X", addr64); #else sprintf((char *)floatstring, "0x%016LX", addr64); #endif SETSYMBOL(&status_atoms[statuslength], gensym((char *)floatstring)); /* addr64 */ statuslength++; /* 16-bit source address */ addr16 = x->x_message[i++]<<8; addr16 |= x->x_message[i++]; sprintf((char *)floatstring, "0x%X", addr16); SETSYMBOL(&status_atoms[statuslength], gensym((char *)floatstring)); /* addr16 */ statuslength++; /* receive options byte */ SETFLOAT(&status_atoms[statuslength], x->x_message[i++]);/* 1 2 32 64 */ statuslength++; /* data */ payloadstart = i; break; default: if (x->x_verbosity > 0) post("some other packet statuslength %d", statuslength); SETFLOAT(&status_atoms[statuslength], x->x_frame_ID);/* may not be valid */ statuslength++; SETFLOAT(&status_atoms[statuslength], x->x_frame_length-2);/* payload doesn't include frame type and ID */ statuslength++; payloadstart = 5; } /* end of switch */ outlet_anything(x->x_status_out, type_selector, statuslength, status_atoms); if (payloadstart > 0) { if (payload_is_sample_frame) { /* sample frame payload first byte is always 1 */ i = payloadstart; if (x->x_message[i] != 1) post ("unpackxbee: bad sample frame"); else { digital_bits = (x->x_message[i+1]<<8) + x->x_message[i+2]; if (x->x_verbosity > 0) post("digital bitmask %04X", digital_bits); analog_bits = x->x_message[i+3]; if (x->x_verbosity > 0) post("analog bitmask %04X", analog_bits); i = i+4; if (0 != digital_bits) { digital_channel = 0; digital_ins = (x->x_message[i]<<8) + x->x_message[i+1]; while (0 != digital_bits) { while (0 == (digital_bits & 1)) { digital_bits >>= 1; digital_ins >>= 1; digital_channel++; } sprintf(atbuf, "D%d", digital_channel); SETFLOAT(&sample_atoms[0], ((digital_ins & 1)?1:0)); outlet_anything(x->x_sample_out, gensym(atbuf), 1, sample_atoms); digital_bits >>= 1; digital_ins >>= 1; digital_channel++; } i += 2; } analog_channel = 0; while ((i < k-1) && (0 != analog_bits)) { while (0 == (analog_bits & 1)) { analog_bits >>= 1; analog_channel++; } sprintf(atbuf, "A%d", analog_channel); SETFLOAT(&sample_atoms[0], (x->x_message[i]<<8) + x->x_message[i+1]); outlet_anything(x->x_sample_out, gensym(atbuf), 1, sample_atoms); analog_bits >>= 1; analog_channel++; i += 2; } } } for (j = 0, i = payloadstart; i < k-1; ++j, ++i) SETFLOAT(&x->x_outbuf[j], x->x_message[i]); /* the payload */ if (j > 0) outlet_list(x->x_payload_out, &s_list, j, x->x_outbuf); } } } static void unpackxbee_free(t_unpackxbee *x) { } void unpackxbee_setup(void) { unpackxbee_class = class_new(gensym("unpackxbee"), (t_newmethod)unpackxbee_new, (t_method)unpackxbee_free, sizeof(t_unpackxbee), 0, A_DEFFLOAT, 0); class_addanything(unpackxbee_class, (t_method)unpackxbee_input); class_addmethod(unpackxbee_class, (t_method)unpackxbee_API, gensym("API"), A_DEFFLOAT, 0); class_addmethod(unpackxbee_class, (t_method)unpackxbee_verbosity, gensym("verbosity"), A_DEFFLOAT, 0); } /* fin unpackxbee.c*/