diff options
Diffstat (limited to 'externals/gridflow/src/classes2.cxx')
-rw-r--r-- | externals/gridflow/src/classes2.cxx | 1183 |
1 files changed, 1183 insertions, 0 deletions
diff --git a/externals/gridflow/src/classes2.cxx b/externals/gridflow/src/classes2.cxx new file mode 100644 index 00000000..6ca9a62a --- /dev/null +++ b/externals/gridflow/src/classes2.cxx @@ -0,0 +1,1183 @@ +/* + $Id: flow_objects.c 4097 2008-10-03 19:49:03Z matju $ + + GridFlow + Copyright (c) 2001-2009 by Mathieu Bouchard + + 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 ../COPYING 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. +*/ + +#include "gridflow.hxx.fcs" +#ifdef DESIRE +#include "desire.h" +#else +extern "C" { +#include "bundled/g_canvas.h" +#include "bundled/m_imp.h" +extern t_class *text_class; +}; +#endif +#include <algorithm> +#include <errno.h> +#include <sys/time.h> +#include <string> + +typedef int (*comparator_t)(const void *, const void *); + +#ifndef DESIREDATA +struct _outconnect { + struct _outconnect *next; + t_pd *to; +}; +struct _outlet { + t_object *owner; + struct _outlet *next; + t_outconnect *connections; + t_symbol *sym; +}; +#endif + +//**************************************************************** + +struct ArgSpec { + t_symbol *name; + t_symbol *type; + t_atom defaultv; +}; + +\class Args : FObject { + ArgSpec *sargv; + int sargc; + \constructor (...) { + sargc = argc; + sargv = new ArgSpec[argc]; + for (int i=0; i<argc; i++) { + if (argv[i].a_type==A_LIST) { + t_binbuf *b = (t_binbuf *)argv[i].a_gpointer; + int bac = binbuf_getnatom(b); + t_atom *bat = binbuf_getvec(b); + sargv[i].name = atom_getsymbolarg(0,bac,bat); + sargv[i].type = atom_getsymbolarg(1,bac,bat); + if (bac<3) SETNULL(&sargv[i].defaultv); else sargv[i].defaultv = bat[2]; + } else if (argv[i].a_type==A_SYMBOL) { + sargv[i].name = argv[i].a_symbol; + sargv[i].type = gensym("a"); + SETNULL(&sargv[i].defaultv); + } else RAISE("expected symbol or nested list"); + } + bself->noutlets_set(sargc); + } + ~Args () {delete[] sargv;} + \decl 0 bang (); + \decl 0 loadbang (); + void process_args (int argc, t_atom *argv); +}; +/* get the owner of the result of canvas_getenv */ +static t_canvas *canvas_getabstop(t_canvas *x) { + while (!x->gl_env) if (!(x = x->gl_owner)) bug("t_canvasenvironment", x); + return x; +} +\def 0 bang () {post("%s shouldn't bang [args] anymore.",canvas_getabstop(bself->mom)->gl_name->s_name);} +void outlet_anything2 (t_outlet *o, int argc, t_atom *argv) { + if (!argc) outlet_bang(o); + else if (argv[0].a_type==A_SYMBOL) outlet_anything(o,argv[0].a_symbol,argc-1,argv+1); + else if (argv[0].a_type==A_FLOAT && argc==1) outlet_float(o,argv[0].a_float); + else outlet_anything(o,&s_list,argc,argv); +} +void pd_anything2 (t_pd *o, int argc, t_atom *argv) { + if (!argc) pd_bang(o); + else if (argv[0].a_type==A_SYMBOL) pd_typedmess(o,argv[0].a_symbol,argc-1,argv+1); + else if (argv[0].a_type==A_FLOAT && argc==1) pd_float(o,argv[0].a_float); + else pd_typedmess(o,&s_list,argc,argv); +} +\def 0 loadbang () { + t_canvasenvironment *env = canvas_getenv(bself->mom); + int ac = env->ce_argc; + t_atom av[ac]; + for (int i=0; i<ac; i++) av[i] = env->ce_argv[i]; + //ac = handle_braces(ac,av); + t_symbol *comma = gensym(","); + int j; + for (j=0; j<ac; j++) if (av[j].a_type==A_SYMBOL && av[j].a_symbol==comma) break; + int jj = handle_braces(j,av); + process_args(jj,av); + while (j<ac) { + j++; + int k=j; + for (; j<ac; j++) if (av[j].a_type==A_SYMBOL && av[j].a_symbol==comma) break; + //outlet_anything2(bself->outlets[sargc],j-k,av+k); + t_text *t = (t_text *)canvas_getabstop(bself->mom); + if (!t->te_inlet) RAISE("can't send init-messages, because object has no [inlet]"); + pd_anything2((t_pd *)t->te_inlet,j-k,av+k); + } +} +void Args::process_args (int argc, t_atom *argv) { + t_canvas *canvas = canvas_getrootfor(bself->mom); + t_symbol *wildcard = gensym("*"); + for (int i=sargc-1; i>=0; i--) { + t_atom *v; + if (i>=argc) { + if (sargv[i].defaultv.a_type != A_NULL) { + v = &sargv[i].defaultv; + } else if (sargv[i].name!=wildcard) { + pd_error(canvas,"missing argument $%d named \"%s\"", i+1,sargv[i].name->s_name); + continue; + } + } else v = &argv[i]; + if (sargv[i].name==wildcard) { + if (argc-i>0) outlet_list(bself->outlets[i],&s_list,argc-i,argv+i); + else outlet_bang(bself->outlets[i]); + } else { + if (v->a_type==A_LIST) { + t_binbuf *b = (t_binbuf *)v->a_gpointer; + outlet_list(bself->outlets[i],&s_list,binbuf_getnatom(b),binbuf_getvec(b)); + } else if (v->a_type==A_SYMBOL) outlet_symbol(bself->outlets[i],v->a_symbol); + else outlet_anything2(bself->outlets[i],1,v); + } + } + if (argc>sargc && sargv[sargc-1].name!=wildcard) pd_error(canvas,"warning: too many args (got %d, want %d)", argc, sargc); +} +\end class {install("args",1,1);} + +//**************************************************************** + +namespace { +template <class T> void swap (T &a, T &b) {T c; c=a; a=b; b=c;} +}; + +\class ListReverse : FObject { + \constructor () {} + \decl 0 list(...); +}; +\def 0 list (...) { + for (int i=(argc-1)/2; i>=0; i--) swap(argv[i],argv[argc-i-1]); + outlet_list(bself->te_outlet,&s_list,argc,argv); +} +\end class {install("listreverse",1,1);} + +\class ListFlatten : FObject { + std::vector<t_atom2> contents; + \constructor () {} + \decl 0 list(...); + void traverse (int argc, t_atom2 *argv) { + for (int i=0; i<argc; i++) { + if (argv[i].a_type==A_LIST) traverse(binbuf_getnatom(argv[i]),(t_atom2 *)binbuf_getvec(argv[i])); + else contents.push_back(argv[i]); + } + } +}; +\def 0 list (...) { + traverse(argc,argv); + outlet_list(bself->te_outlet,&s_list,contents.size(),&contents[0]); + contents.clear(); + +} +\end class {install("listflatten",1,1);} + +// does not do recursive comparison of lists. +static bool atom_eq (t_atom &a, t_atom &b) { + if (a.a_type!=b.a_type) return false; + if (a.a_type==A_FLOAT) return a.a_float ==b.a_float; + if (a.a_type==A_SYMBOL) return a.a_symbol ==b.a_symbol; + if (a.a_type==A_POINTER) return a.a_gpointer==b.a_gpointer; + if (a.a_type==A_LIST) return a.a_gpointer==b.a_gpointer; + RAISE("don't know how to compare elements of type %d",a.a_type); +} + +\class ListFind : FObject { + int ac; + t_atom *at; + ~ListFind() {if (at) delete[] at;} + \constructor (...) {ac=0; at=0; _1_list(argc,argv);} + \decl 0 list(...); + \decl 1 list(...); + \decl 0 float(float f); + \decl 0 symbol(t_symbol *s); +}; +\def 1 list (...) { + if (at) delete[] at; + ac = argc; + at = new t_atom[argc]; + for (int i=0; i<argc; i++) at[i] = argv[i]; +} +\def 0 list (...) { + if (argc<1) RAISE("empty input"); + int i=0; for (; i<ac; i++) if (atom_eq(at[i],argv[0])) break; + outlet_float(bself->outlets[0],i==ac?-1:i); +} +\def 0 float (float f) { + int i=0; for (; i<ac; i++) if (atom_eq(at[i],argv[0])) break; + outlet_float(bself->outlets[0],i==ac?-1:i); +} +\def 0 symbol (t_symbol *s) { + int i=0; for (; i<ac; i++) if (atom_eq(at[i],argv[0])) break; + outlet_float(bself->outlets[0],i==ac?-1:i); +} +//doc:_1_list,"list to search into" +//doc:_0_float,"float to find in that list" +//doc_out:_0_float,"position of the incoming float in the stored list" +\end class {install("listfind",2,1);} + +void outlet_atom (t_outlet *self, t_atom *av) { + if (av->a_type==A_FLOAT) outlet_float( self,av->a_float); else + if (av->a_type==A_SYMBOL) outlet_symbol( self,av->a_symbol); else + if (av->a_type==A_POINTER) outlet_pointer(self,av->a_gpointer); else + outlet_list(self,gensym("list"),1,av); +} + +\class ListRead : FObject { /* sounds like tabread */ + int ac; + t_atom *at; + ~ListRead() {if (at) delete[] at;} + \constructor (...) {ac=0; at=0; _1_list(argc,argv);} + \decl 0 float(float f); + \decl 1 list(...); +}; +\def 0 float(float f) { + int i = int(f); + if (i<0) i+=ac; + if (i<0 || i>=ac) {outlet_bang(bself->outlets[0]); return;} /* out-of-range */ + outlet_atom(bself->outlets[0],&at[i]); +} +\def 1 list (...) { + if (at) delete[] at; + ac = argc; + at = new t_atom[argc]; + for (int i=0; i<argc; i++) at[i] = argv[i]; +} +\end class {install("listread",2,1);} + +\class Range : FObject { + t_float *mosusses; + int nmosusses; + \constructor (...) { + nmosusses = argc; + for (int i=0; i<argc; i++) if (argv[i].a_type!=A_FLOAT) RAISE("$%d: expected float",i+1); + mosusses = new t_float[argc]; + for (int i=0; i<argc; i++) mosusses[i]=argv[i].a_float; + bself-> ninlets_set(1+nmosusses); + bself->noutlets_set(1+nmosusses); + } + ~Range () {delete[] mosusses;} + \decl 0 float(float f); + \decl 0 list(float f); + \decl void _n_float(int i, float f); +}; +\def 0 list(float f) {_0_float(argc,argv,f);} +\def 0 float(float f) { + int i; for (i=0; i<nmosusses; i++) if (f<mosusses[i]) break; + outlet_float(bself->outlets[i],f); +} + // precedence problem in dispatcher... does this problem still exist? +\def void _n_float(int i, float f) {if (!i) _0_float(argc,argv,f); else mosusses[i-1] = f;} +\end class {install("range",1,1);} + +//**************************************************************** + +string ssprintf(const char *fmt, ...) { + std::ostringstream os; + va_list va; + va_start(va,fmt); + voprintf(os,fmt,va); + va_end(va); + return os.str(); +} + +\class GFPrint : FObject { + t_symbol *prefix; + t_pd *gp; + //t_symbol *rsym; + \constructor (t_symbol *s=0) { + //rsym = gensym(const_cast<char *>(ssprintf("gf.print:%08x",this).data())); // not in use atm. + prefix=s?s:gensym("print"); + t_atom a[1]; + SETSYMBOL(a,prefix); + pd_typedmess(&pd_objectmaker,gensym("#print"),1,a); + gp = pd_newest(); + SETPOINTER(a,(t_gpointer *)bself); + //pd_typedmess(gp,gensym("dest"),1,a); + } + ~GFPrint () { + //pd_unbind((t_pd *)bself,rsym); + pd_free(gp); + } + \decl 0 grid(...); + \decl void anything (...); +}; +std::ostream &operator << (std::ostream &self, const t_atom &a) { + switch (a.a_type) { + case A_FLOAT: self << a.a_float; break; + case A_SYMBOL: self << a.a_symbol->s_name; break; // i would rather show backslashes here... + case A_DOLLSYM: self << a.a_symbol->s_name; break; // for real, it's the same thing as A_SYMBOL in pd >= 0.40 + case A_POINTER: self << "\\p(0x" << std::hex << a.a_gpointer << std::dec << ")"; break; + case A_COMMA: self << ","; break; + case A_SEMI: self << ";"; break; + case A_DOLLAR: self << "$" << a.a_w.w_index; break; + case A_LIST: { + t_list *b = (t_list *)a.a_gpointer; + int argc = binbuf_getnatom(b); + t_atom *argv = binbuf_getvec(b); + self << "("; + for (int i=0; i<argc; i++) self << argv[i] << " )"[i==argc-1]; + break; + } + default: self << "\\a(" << a.a_type << " " << std::hex << a.a_gpointer << std::dec << ")"; break; + } + return self; +} +\def 0 grid(...) {pd_typedmess(gp,gensym("grid"),argc,argv);} +\def void anything(...) { + std::ostringstream text; + text << prefix->s_name << ":"; + if (argv[0]==gensym("_0_list") && argc>=2 && argv[1].a_type==A_FLOAT) { + // don't show the selector. + } else if (argv[0]==gensym("_0_list") && argc==2 && argv[1].a_type==A_SYMBOL) { + text << " symbol"; + } else if (argv[0]==gensym("_0_list") && argc==2 && argv[1].a_type==A_POINTER) { + text << " pointer"; + } else if (argv[0]==gensym("_0_list") && argc==1) { + text << " bang"; + } else { + text << " " << argv[0].a_symbol->s_name+3; // as is + } + for (int i=1; i<argc; i++) {text << " " << argv[i];} + post("%s",text.str().data()); +} +\end class {install("gf.print",1,0); add_creator3(fclass,"print");} + +#ifdef HAVE_DESIREDATA +t_glist *glist_getcanvas(t_glist *foo) {return foo;}//dummy +void canvas_fixlinesfor(t_glist *foo,t_text *) {}//dummy +#endif + +//#ifdef HAVE_DESIREDATA +static void display_update(void *x); +\class Display : FObject { + bool selected; + t_glist *canvas; + t_symbol *rsym; + int y,x,sy,sx; + bool vis; + std::ostringstream text; + t_clock *clock; + t_pd *gp; + \constructor () { + selected=false; canvas=0; y=0; x=0; sy=16; sx=80; vis=false; clock=0; + std::ostringstream os; + rsym = gensym(const_cast<char *>(ssprintf("display:%08x",this).data())); + pd_typedmess(&pd_objectmaker,gensym("#print"),0,0); + gp = pd_newest(); + t_atom a[1]; + SETFLOAT(a,20); + pd_typedmess(gp,gensym("maxrows"),1,a); + text << "..."; + pd_bind((t_pd *)bself,rsym); + SETPOINTER(a,(t_gpointer *)bself); + pd_typedmess(gp,gensym("dest"),1,a); + clock = clock_new((void *)this,(void(*)())display_update); + } + ~Display () { + pd_unbind((t_pd *)bself,rsym); + pd_free(gp); + if (clock) clock_free(clock); + } + \decl void anything (...); + \decl 0 set_size(int sy, int sx); + \decl 0 grid(...); + \decl 0 very_long_name_that_nobody_uses(...); + void show() { + std::ostringstream quoted; + // def quote(text) "\"" + text.gsub(/["\[\]\n\$]/m) {|x| if x=="\n" then "\\n" else "\\"+x end } + "\"" end + std::string ss = text.str(); + const char *s = ss.data(); + int n = ss.length(); + for (int i=0;i<n;i++) { + if (s[i]=='\n') quoted << "\\n"; + else if (strchr("\"[]$",s[i])) quoted << "\\" << (char)s[i]; + else quoted << (char)s[i]; + } + //return if not canvas or not @vis # can't show for now... + /* we're not using quoting for now because there's a bug in it. */ + /* btw, this quoting is using "", but we're gonna use {} instead for now, because of newlines */ + sys_vgui("display_update %s %d %d #000000 #cccccc %s {Courier -12} .x%x.c {%s}\n", + rsym->s_name,bself->te_xpix,bself->te_ypix,selected?"#0000ff":"#000000",canvas,ss.data()); + } +}; +static void display_getrectfn(t_gobj *x, t_glist *glist, int *x1, int *y1, int *x2, int *y2) { + BFObject *bself = (BFObject*)x; Display *self = (Display *)bself->self; self->canvas = glist; + *x1 = bself->te_xpix-1; + *y1 = bself->te_ypix-1; + *x2 = bself->te_xpix+1+self->sx; + *y2 = bself->te_ypix+1+self->sy; +} +static void display_displacefn(t_gobj *x, t_glist *glist, int dx, int dy) { + BFObject *bself = (BFObject*)x; Display *self = (Display *)bself->self; self->canvas = glist; + bself->te_xpix+=dx; + bself->te_ypix+=dy; + self->canvas = glist_getcanvas(glist); + self->show(); + canvas_fixlinesfor(glist, (t_text *)x); +} +static void display_selectfn(t_gobj *x, t_glist *glist, int state) { + BFObject *bself = (BFObject*)x; Display *self = (Display *)bself->self; self->canvas = glist; + self->selected=!!state; + sys_vgui(".x%x.c itemconfigure %s -outline %s\n",glist_getcanvas(glist),self->rsym->s_name,self->selected?"#0000ff":"#000000"); +} +static void display_deletefn(t_gobj *x, t_glist *glist) { + BFObject *bself = (BFObject*)x; Display *self = (Display *)bself->self; self->canvas = glist; + if (self->vis) sys_vgui(".x%x.c delete %s %sTEXT\n",glist_getcanvas(glist),self->rsym->s_name,self->rsym->s_name); + canvas_deletelinesfor(glist, (t_text *)x); +} +static void display_visfn(t_gobj *x, t_glist *glist, int flag) { + BFObject *bself = (BFObject*)x; Display *self = (Display *)bself->self; self->canvas = glist; + self->vis = !!flag; + display_update(self); +} +static void display_update(void *x) { + Display *self = (Display *)x; + if (self->vis) self->show(); +} +\def 0 set_size(int sy, int sx) {this->sy=sy; this->sx=sx;} +\def void anything (...) { + string sel = string(argv[0]).data()+3; + text.str(""); + if (sel != "float") {text << sel; if (argc>1) text << " ";} + long col = text.str().length(); + char buf[MAXPDSTRING]; + for (int i=1; i<argc; i++) { + atom_string(&argv[i],buf,MAXPDSTRING); + text << buf; + col += strlen(buf); + if (i!=argc-1) { + text << " "; + col++; + if (col>56) {text << "\\\\\n"; col=0;} + } + } + clock_delay(clock,0); +} +\def 0 grid(...) { + text.str(""); + pd_typedmess(gp,gensym("grid"),argc,argv); + clock_delay(clock,0); +} +\def 0 very_long_name_that_nobody_uses(...) { + if (text.str().length()) text << "\n"; + for (int i=0; i<argc; i++) text << (char)INT(argv[i]); +} +\end class { +#ifndef DESIRE + install("display",1,0); + t_class *qlass = fclass->bfclass; + t_widgetbehavior *wb = new t_widgetbehavior; + wb->w_getrectfn = display_getrectfn; + wb->w_displacefn = display_displacefn; + wb->w_selectfn = display_selectfn; + wb->w_activatefn = 0; + wb->w_deletefn = display_deletefn; + wb->w_visfn = display_visfn; + wb->w_clickfn = 0; + class_setwidget(qlass,wb); + sys_gui("proc display_update {self x y fg bg outline font canvas text} { \n\ + $canvas delete ${self}TEXT \n\ + $canvas create text [expr $x+2] [expr $y+2] -fill $fg -font $font -text $text -anchor nw -tag ${self}TEXT \n\ + foreach {x1 y1 x2 y2} [$canvas bbox ${self}TEXT] {} \n\ + incr x -1 \n\ + incr y -1 \n\ + set sx [expr $x2-$x1+2] \n\ + set sy [expr $y2-$y1+4] \n\ + $canvas delete ${self} \n\ + $canvas create rectangle $x $y [expr $x+$sx] [expr $y+$sy] -fill $bg -tags $self -outline $outline \n\ + $canvas create rectangle $x $y [expr $x+7] $y -fill red -tags $self -outline $outline \n\ + $canvas lower $self ${self}TEXT \n\ + pd \"$self set_size $sy $sx;\" \n\ + }\n"); +#endif +} +//#endif // ndef HAVE_DESIREDATA + +//**************************************************************** + +\class UnixTime : FObject { + \constructor () {} + \decl 0 bang (); +}; +\def 0 bang () { + timeval tv; + gettimeofday(&tv,0); + time_t t = time(0); + struct tm *tmp = localtime(&t); + if (!tmp) RAISE("localtime: %s",strerror(errno)); + char tt[MAXPDSTRING]; + strftime(tt,MAXPDSTRING,"%a %b %d %H:%M:%S %Z %Y",tmp); + t_atom a[6]; + SETFLOAT(a+0,tmp->tm_year+1900); + SETFLOAT(a+1,tmp->tm_mon-1); + SETFLOAT(a+2,tmp->tm_mday); + SETFLOAT(a+3,tmp->tm_hour); + SETFLOAT(a+4,tmp->tm_min); + SETFLOAT(a+5,tmp->tm_sec); + t_atom b[3]; + SETFLOAT(b+0,tv.tv_sec/86400); + SETFLOAT(b+1,mod(tv.tv_sec,86400)); + SETFLOAT(b+2,tv.tv_usec); + outlet_anything(bself->outlets[2],&s_list,6,a); + outlet_anything(bself->outlets[1],&s_list,3,b); + send_out(0,strlen(tt),tt); +} + +\end class UnixTime {install("unix_time",1,3);} + + +//**************************************************************** + +/* if using a DB-25 female connector as found on a PC, then the pin numbering is like: + 13 _____ 1 + 25 \___/ 14 + 1 = STROBE = the clock line is a square wave, often at 9600 Hz, + which determines the data rate in usual circumstances. + 2..9 = D0..D7 = the eight ordinary data bits + 10 = -ACK (status bit 6 ?) + 11 = BUSY (status bit 7) + 12 = PAPER_END (status bit 5) + 13 = SELECT (status bit 4 ?) + 14 = -AUTOFD + 15 = -ERROR (status bit 3 ?) + 16 = -INIT + 17 = -SELECT_IN + 18..25 = GROUND +*/ + +//#include <linux/parport.h> +#define LPCHAR 0x0601 +#define LPCAREFUL 0x0609 /* obsoleted??? wtf? */ +#define LPGETSTATUS 0x060b /* return LP_S(minor) */ +#define LPGETFLAGS 0x060e /* get status flags */ + +#include <sys/ioctl.h> + +struct ParallelPort; +void ParallelPort_call(ParallelPort *self); +\class ParallelPort : FObject { + FILE *f; + int fd; + int status; + int flags; + bool manually; + t_clock *clock; + ~ParallelPort () {if (clock) clock_free(clock); if (f) fclose(f);} + \constructor (string port, bool manually=0) { + f = fopen(port.data(),"r+"); + if (!f) RAISE("open %s: %s",port.data(),strerror(errno)); + fd = fileno(f); + status = 0xdeadbeef; + flags = 0xdeadbeef; + this->manually = manually; + clock = manually ? 0 : clock_new(this,(void(*)())ParallelPort_call); + clock_delay(clock,0); + } + void call (); + \decl 0 float (float x); + \decl 0 bang (); +}; +\def 0 float (float x) { + uint8 foo = (uint8) x; + fwrite(&foo,1,1,f); + fflush(f); +} +void ParallelPort_call(ParallelPort *self) {self->call();} +void ParallelPort::call() { + int flags; + if (ioctl(fd,LPGETFLAGS,&flags)<0) post("ioctl: %s",strerror(errno)); + if (this->flags!=flags) outlet_float(bself->outlets[2],flags); + this->flags = flags; + int status; + if (ioctl(fd,LPGETSTATUS,&status)<0) post("ioctl: %s",strerror(errno)); + if (this->status!=status) outlet_float(bself->outlets[1],status); + this->status = status; + if (clock) clock_delay(clock,2000); +} +\def 0 bang () {status = flags = 0xdeadbeef; call();} +//outlet 0 reserved (future use) +\end class {install("parallel_port",1,3);} + +//**************************************************************** + +\class Route2 : FObject { + int nsels; + t_symbol **sels; + ~Route2() {if (sels) delete[] sels;} + \constructor (...) {nsels=0; sels=0; _1_list(argc,argv); bself->noutlets_set(1+nsels);} + \decl void anything(...); + \decl 1 list(...); +}; +\def void anything(...) { + t_symbol *sel = gensym(argv[0].a_symbol->s_name+3); + int i=0; + for (i=0; i<nsels; i++) if (sel==sels[i]) break; + outlet_anything(bself->outlets[i],sel,argc-1,argv+1); +} +\def 1 list(...) { + for (int i=0; i<argc; i++) if (argv[i].a_type!=A_SYMBOL) {delete[] sels; RAISE("$%d: expected symbol",i+1);} + if (sels) delete[] sels; + nsels = argc; + sels = new t_symbol*[argc]; + for (int i=0; i<argc; i++) sels[i] = argv[i].a_symbol; +} +\end class {install("route2",1,1);} + +template <class T> int sgn(T a, T b=0) {return a<b?-1:a>b;} + +\class Shunt : FObject { + int n; + \attr int index; + \attr int mode; + \attr int hi; + \attr int lo; + \constructor (int n=2, int i=0) { + this->n=n; + this->hi=n-1; + this->lo=0; + this->mode=0; + this->index=i; + bself->noutlets_set(n); + } + \decl void anything(...); + \decl 1 float(int i); +}; +\def void anything(...) { + t_symbol *sel = gensym(argv[0].a_symbol->s_name+3); + outlet_anything(bself->outlets[index],sel,argc-1,argv+1); + if (mode) { + index += sgn(mode); + if (index<lo || index>hi) { + int k = max(hi-lo+1,0); + int m = gf_abs(mode); + if (m==1) index = mod(index-lo,k)+lo; else {mode=-mode; index+=mode;} + } + } +} +\def 1 float(int i) {index = mod(i,n);} +\end class {install("shunt",2,0);} + +struct Receives; +struct ReceivesProxy { + t_pd x_pd; + Receives *parent; + t_symbol *suffix; +}; +t_class *ReceivesProxy_class; + +\class Receives : FObject { + int ac; + ReceivesProxy **av; + t_symbol *prefix; + t_symbol *local (t_symbol *suffix) {return gensym((string(prefix->s_name) + string(suffix->s_name)).data());} + \constructor (t_symbol *prefix=&s_, ...) { + this->prefix = prefix==gensym("empty") ? &s_ : prefix; + int n = min(1,argc); + do_bind(argc-n,argv+n); + } + \decl 0 bang (); + \decl 0 symbol (t_symbol *s); + \decl 0 list (...); + void do_bind (int argc, t_atom2 *argv) { + ac = argc; + av = new ReceivesProxy *[argc]; + for (int i=0; i<ac; i++) { + av[i] = (ReceivesProxy *)pd_new(ReceivesProxy_class); + av[i]->parent = this; + av[i]->suffix = argv[i]; + pd_bind( (t_pd *)av[i],local(av[i]->suffix)); + } + } + void do_unbind () { + for (int i=0; i<ac; i++) { + pd_unbind((t_pd *)av[i],local(av[i]->suffix)); + pd_free((t_pd *)av[i]); + } + delete[] av; + } + ~Receives () {do_unbind();} +}; +\def 0 bang () {_0_list(0,0);} +\def 0 symbol (t_symbol *s) {t_atom2 a[1]; SETSYMBOL(a,s); _0_list(1,a);} +\def 0 list (...) { + do_unbind(); + do_bind(argc,argv); +} +void ReceivesProxy_anything (ReceivesProxy *self, t_symbol *s, int argc, t_atom *argv) { + outlet_symbol( self->parent->bself->outlets[1],self->suffix); + outlet_anything(self->parent->bself->outlets[0],s,argc,argv); +} +\end class { + install("receives",1,2); + ReceivesProxy_class = class_new(gensym("receives.proxy"),0,0,sizeof(ReceivesProxy),CLASS_PD|CLASS_NOINLET, A_NULL); + class_addanything(ReceivesProxy_class,(t_method)ReceivesProxy_anything); +} + +/* this can't report on bang,float,symbol,pointer,list because zgetfn can't either */ +\class ClassExists : FObject { + \constructor () {} + \decl void _0_symbol(t_symbol *s); +}; +\def void _0_symbol(t_symbol *s) { + outlet_float(bself->outlets[0],!!zgetfn(&pd_objectmaker,s)); +} +\end class {install("class_exists",1,1);} + +\class ListEqual : FObject { + t_list *list; + \constructor (...) {list=0; _1_list(argc,argv);} + \decl 0 list (...); + \decl 1 list (...); +}; +\def 1 list (...) { + if (list) list_free(list); + list = list_new(argc,argv); +} +\def 0 list (...) { + if (binbuf_getnatom(list) != argc) {outlet_float(bself->outlets[0],0); return;} + t_atom2 *at = (t_atom2 *)binbuf_getvec(list); + for (int i=0; i<argc; i++) if (!atom_eq(at[i],argv[i])) {outlet_float(bself->outlets[0],0); return;} + outlet_float(bself->outlets[0],1); +} +\end class {install("list.==",2,1);} + +//**************************************************************** +//#ifdef UNISTD +#include <sys/types.h> +#include <sys/time.h> +#include <sys/times.h> +#include <sys/param.h> +#include <unistd.h> +//#endif +#if defined (__APPLE__) || defined (__FreeBSD__) +#define HZ CLK_TCK +#endif + +uint64 cpu_hertz; +int uint64_compare(uint64 &a, uint64 &b) {return a<b?-1:a>b;} + +\class UserTime : FObject { + clock_t time; + \constructor () {_0_bang(argc,argv);} + \decl 0 bang (); + \decl 1 bang (); +}; +\def 0 bang () {struct tms t; times(&t); time = t.tms_utime;} +\def 1 bang () {struct tms t; times(&t); outlet_float(bself->outlets[0],(t.tms_utime-time)*1000/HZ);} +\end class {install("usertime",2,1);} +\class SystemTime : FObject { + clock_t time; + \constructor () {_0_bang(argc,argv);} + \decl 0 bang (); + \decl 1 bang (); +}; +\def 0 bang () {struct tms t; times(&t); time = t.tms_stime;} +\def 1 bang () {struct tms t; times(&t); outlet_float(bself->outlets[0],(t.tms_stime-time)*1000/HZ);} +\end class {install("systemtime",2,1);} +\class TSCTime : FObject { + uint64 time; + \constructor () {_0_bang(argc,argv);} + \decl 0 bang (); + \decl 1 bang (); +}; +\def 0 bang () {time=rdtsc();} +\def 1 bang () {outlet_float(bself->outlets[0],(rdtsc()-time)*1000.0/cpu_hertz);} +\end class {install("tsctime",2,1); + struct timeval t0,t1; + uint64 u0,u1; + uint64 estimates[3]; + for (int i=0; i<3; i++) { + u0=rdtsc(); gettimeofday(&t0,0); usleep(10000); + u1=rdtsc(); gettimeofday(&t1,0); + uint64 t = (t1.tv_sec-t0.tv_sec)*1000000+(t1.tv_usec-t0.tv_usec); + estimates[i] = (u1-u0)*1000000/t; + } + qsort(estimates,3,sizeof(uint64),(comparator_t)uint64_compare); + cpu_hertz = estimates[1]; +} + +\class GFError : FObject { + string format; + \constructor (...) { + std::ostringstream o; + char buf[MAXPDSTRING]; + for (int i=0; i<argc; i++) { + atom_string(&argv[i],buf,MAXPDSTRING); + o << buf; + if (i!=argc-1) o << ' '; + } + format = o.str(); + } + \decl 0 bang (); + \decl 0 float (float f); + \decl 0 symbol (t_symbol *s); + \decl 0 list (...); +}; +\def 0 bang () {_0_list(0,0);} +\def 0 float (float f) {_0_list(argc,argv);} +\def 0 symbol (t_symbol *s) {_0_list(argc,argv);} + +\def 0 list (...) { + std::ostringstream o; + pd_oprintf(o,format.data(),argc,argv); + t_canvas *canvas = canvas_getrootfor(bself->mom); + string s = o.str(); + pd_error(canvas,"%s",s.data()); +} +\end class {install("gf.error",1,0);} + +//**************************************************************** +\class ForEach : FObject { + \constructor () {} + \decl 0 list (...); +}; +\def 0 list (...) { + t_outlet *o = bself->outlets[0]; + for (int i=0; i<argc; i++) { + if (argv[i].a_type==A_FLOAT) outlet_float( o,argv[i]); + else if (argv[i].a_type==A_SYMBOL) outlet_symbol(o,argv[i]); + else RAISE("oops. unsupported."); + } +} +\end class {install("foreach",1,1);} + +//**************************************************************** + +#define MOM \ + t_canvas *mom = bself->mom; \ + for (int i=0; i<n; i++) {mom = mom->gl_owner; if (!mom) RAISE("no such canvas");} + +\class GFCanvasFileName : FObject { + int n; + \constructor (int n) {this->n=n;} + \decl 0 bang (); +}; +\def 0 bang () {MOM; outlet_symbol(bself->outlets[0],mom->gl_name ? mom->gl_name : gensym("empty"));} +\end class {install("gf/canvas_filename",1,1);} +\class GFCanvasDollarZero : FObject { + int n; + \constructor (int n) {this->n=n;} + \decl 0 bang (); +}; +\def 0 bang () {MOM; outlet_float(bself->outlets[0],canvas_getenv(mom)->ce_dollarzero);} +\end class {install("gf/canvas_dollarzero",1,1);} +\class GFCanvasGetPos : FObject { + int n; + \constructor (int n) {this->n=n;} + \decl 0 bang (); +}; +\def 0 bang () {MOM; + t_atom a[2]; + SETFLOAT(a+0,mom->gl_obj.te_xpix); + SETFLOAT(a+1,mom->gl_obj.te_ypix); + outlet_list(bself->outlets[0],&s_list,2,a); +} +\end class {install("gf/canvas_getpos",1,1);} +\class GFCanvasSetPos : FObject { + int n; + \constructor (int n) {this->n=n;} + \decl 0 list (...); +}; +\def 0 list (...) { + MOM; + if (argc!=2) RAISE("wrong number of args"); + mom->gl_obj.te_xpix = atom_getfloatarg(0,argc,argv); + mom->gl_obj.te_ypix = atom_getfloatarg(1,argc,argv); + t_canvas *granny = mom->gl_owner; + if (!granny) RAISE("no such canvas"); +#ifdef DESIREDATA + gobj_changed(mom); +#else + gobj_vis((t_gobj *)mom,granny,0); + gobj_vis((t_gobj *)mom,granny,1); + canvas_fixlinesfor(glist_getcanvas(granny), (t_text *)mom); +#endif +} +\end class {install("gf/canvas_setpos",1,0);} +\class GFCanvasEditMode : FObject { + int n; + \constructor (int n) {this->n=n;} + \decl 0 bang (); +}; +\def 0 bang () {MOM; + t_atom a[1]; SETFLOAT(a+0,0); + outlet_float(bself->outlets[0],mom->gl_edit); +} +\end class {install("gf/canvas_edit_mode",1,1);} +extern "C" void canvas_setgraph(t_glist *x, int flag, int nogoprect); +\class GFCanvasSetGOP : FObject { + int n; + \constructor (int n) {this->n=n;} + \decl 0 float (float gop); +}; +\def 0 float (float gop) {MOM; t_atom a[1]; SETFLOAT(a+0,0); canvas_setgraph(mom,gop,0);} +\end class {install("gf/canvas_setgop",1,0);} +\class GFCanvasXID : FObject { + int n; + t_symbol *name; + \constructor (int n_) { + n=n_; + name=symprintf("gf/canvas_xid:%lx",bself); + pd_bind((t_pd *)bself,name); + } + ~GFCanvasXID () {pd_unbind((t_pd *)bself,name);} + \decl 0 bang (); + \decl 0 xid (t_symbol *t, t_symbol *u); +}; +\def 0 bang () { + t_canvas *mom = bself->mom; + for (int i=0; i<n; i++) {mom = mom->gl_owner; if (!mom) RAISE("no such canvas");} + sys_vgui("pd %s xid [winfo id .x%lx.c] [winfo id .x%lx]\\;\n",name->s_name,long(mom)); +} +\def 0 xid (t_symbol *t, t_symbol *u) { + outlet_symbol(bself->outlets[0],t); + outlet_symbol(bself->outlets[1],u); +} +\end class {install("gf/canvas_xid",1,2);} + +\class GFCanvasHeHeHe : FObject { + int n; + \constructor (int n) {this->n=n;} + \decl 0 float (float y); +}; +\def 0 float (float y) {MOM; + // was 568 + mom->gl_screenx2 = mom->gl_screenx1 + 600; + if (mom->gl_screeny2-mom->gl_screeny1 < y) mom->gl_screeny2 = mom->gl_screeny1+y; + sys_vgui("wm geometry .x%lx %dx%d\n",long(mom), + int(mom->gl_screenx2-mom->gl_screenx1), + int(mom->gl_screeny2-mom->gl_screeny1)); +} +\end class {install("gf/canvas_hehehe",1,1);} + +#define DASHRECT "-outline #80d4b2 -dash {2 6 2 6}" + +\class GFCanvasHoHoHo : FObject { + int n; + t_canvas *last; + \constructor (int n) {this->n=n; last=0;} + void hide () {if (last) sys_vgui(".x%lx.c delete %lxRECT\n",long(last),bself);} + ~GFCanvasHoHoHo () {hide();} + \decl 0 list (int x1, int y1, int x2, int y2); +}; +\def 0 list (int x1, int y1, int x2, int y2) { + hide(); + MOM; + last = mom; + sys_vgui(".x%lx.c create rectangle %d %d %d %d "DASHRECT" -tags %lxRECT\n",long(last),x1,y1,x2,y2,bself); +} +\end class {install("gf/canvas_hohoho",1,0);} + +#define canvas_each(y,x) for (t_gobj *y=x->gl_list; y; y=y->g_next) +\class GFCanvasCount : FObject { + int n; + \constructor (int n) {this->n=n;} + \decl 0 bang (); +}; +\def 0 bang () {MOM; int k=0; canvas_each(y,mom) k++; outlet_float(bself->outlets[0],k);} +\end class {install("gf/canvas_count",1,1);} + +\class GFCanvasLoadbang : FObject { + int n; + \constructor (int n) {this->n=n;} + \decl 0 float (float m); +}; +\def 0 float (float m) {MOM; + int k=0; + canvas_each(y,mom) { + k++; + if (k>=m && pd_class((t_pd *)y)==canvas_class) canvas_loadbang((t_canvas *)y); + } + +} +\end class { + install("gf/canvas_loadbang",1,0); +}; + +\class GFLOL : FObject { + int n; + \constructor (int n) {this->n=n;} + \decl 0 wire_dotted (int r, int g, int b); + \decl 0 wire_hide (); + \decl 0 box_dotted (int r, int g, int b); + \decl 0 box_align (t_symbol *s, int x_start, int y_start, int incr); +}; +#define BEGIN \ + t_outlet *ouch = ((t_object *)bself->mom)->te_outlet; \ + t_canvas *can = bself->mom->gl_owner; \ + if (!can) RAISE("no such canvas"); \ + for (int i=0; i<n; i++) {ouch = ouch->next; if (!ouch) {RAISE("no such outlet");}} +#define wire_each(wire,ouchlet) for (t_outconnect *wire = ouchlet->connections; wire; wire=wire->next) +\def 0 wire_dotted (int r, int g, int b) { +#ifndef DESIREDATA + BEGIN + wire_each(wire,ouch) { + sys_vgui(".x%lx.c itemconfigure l%lx -fill #%02x%02x%02x -dash {3 3 3 3}\n",long(can),long(wire),r,g,b); + } +#else + post("doesn't work with DesireData"); +#endif +} +\def 0 wire_hide () { +#ifndef DESIREDATA + BEGIN + wire_each(wire,ouch) sys_vgui(".x%lx.c delete l%lx\n",long(can),long(wire)); +#else + post("doesn't work with DesireData"); +#endif +} +\def 0 box_dotted (int r, int g, int b) { +#ifndef DESIREDATA + BEGIN + wire_each(wire,ouch) { + t_object *t = (t_object *)wire->to; + int x1,y1,x2,y2; + gobj_getrect((t_gobj *)wire->to,can,&x1,&y1,&x2,&y2); + // was #00aa66 {3 5 3 5} + sys_vgui(".x%lx.c delete %lxRECT; .x%lx.c create rectangle %d %d %d %d "DASHRECT" -tags %lxRECT\n", + long(can),long(t),long(can),x1,y1,x2,y2,long(t)); + } +#else + post("doesn't work with DesireData"); +#endif +} +bool comment_sort_y_lt(t_object * const &a, t_object * const &b) /* is a StrictWeakOrdering */ { + return a->te_ypix < b->te_ypix; +} +#define foreach(ITER,COLL) for(typeof(COLL.begin()) ITER = COLL.begin(); ITER != (COLL).end(); ITER++) +static t_class *inlet_class, *floatinlet_class, *symbolinlet_class, *pointerinlet_class; +static bool ISINLET(t_pd *o) { + t_class *c=pd_class(o); + return c==inlet_class || c==floatinlet_class || c==symbolinlet_class || c==pointerinlet_class; +} +struct _inlet { + t_pd pd; + struct _inlet *next; + t_object *owner; + t_pd *dest; + t_symbol *symfrom; + //union inletunion un; +}; +\def 0 box_align (t_symbol *dir, int x_start, int y_start, int incr) { + int x=x_start, y=y_start; + bool horiz; + if (dir==&s_x) horiz=false; else + if (dir==&s_y) horiz=true; else RAISE("$1 must be x or y"); +#ifndef DESIREDATA + std::vector<t_object *> v; + BEGIN + wire_each(wire,ouch) { + //post("wire to object of class %s ISINLET=%d",pd_class(wire->to)->c_name->s_name,ISINLET(wire->to)); + t_object *to = ISINLET(wire->to) ? ((t_inlet *)wire->to)->owner : (t_object *)wire->to; + v.push_back(to); + } + sort(v.begin(),v.end(),comment_sort_y_lt); + foreach(tt,v) { + t_object *t = *tt; + if (t->te_xpix!=x || t->te_ypix!=y) { + gobj_vis((t_gobj *)t,can,0); + t->te_xpix=x; + t->te_ypix=y; + gobj_vis((t_gobj *)t,can,1); + canvas_fixlinesfor(can,t); + } + int x1,y1,x2,y2; + gobj_getrect((t_gobj *)t,can,&x1,&y1,&x2,&y2); + if (horiz) x += x2-x1+incr; + else y += y2-y1+incr; + } + if (horiz) outlet_float(bself->outlets[0],x-x_start); + else outlet_float(bself->outlets[0],y-y_start); +#else + post("doesn't work with DesireData"); +#endif +} + +extern t_widgetbehavior text_widgetbehavior; +t_widgetbehavior text_widgetbehavi0r; + +/* i was gonna use gobj_shouldvis but it's only for >= 0.42 */ + +static int text_chou_de_vis(t_text *x, t_glist *glist) { + return (glist->gl_havewindow || + (x->te_pd != canvas_class && x->te_pd->c_wb != &text_widgetbehavior) || + (x->te_pd == canvas_class && (((t_glist *)x)->gl_isgraph)) || + (glist->gl_goprect && (x->te_type == T_TEXT))); +} + +static void text_visfn_hax0r (t_gobj *o, t_canvas *can, int vis) { + text_widgetbehavior.w_visfn(o,can,vis); + //if (vis) return; // if you want to see #X text inlets uncomment this line + t_rtext *y = glist_findrtext(can,(t_text *)o); + if (text_chou_de_vis((t_text *)o,can)) glist_eraseiofor(can,(t_object *)o,rtext_gettag(y)); +} +\end class { + install("gf/lol",1,1); +#ifndef DESIREDATA + class_setpropertiesfn(text_class,(t_propertiesfn)0xDECAFFED); + unsigned long *lol = (unsigned long *)text_class; + int i=0; + while (lol[i]!=0xDECAFFED) i++; + *((char *)(lol+i+1) + 6) = 1; + class_setpropertiesfn(text_class,0); + t_object *bogus = (t_object *)pd_new(text_class); + inlet_class = pd_class((t_pd *) inlet_new(bogus,0,0,0)); + floatinlet_class = pd_class((t_pd *) floatinlet_new(bogus,0)); + symbolinlet_class = pd_class((t_pd *) symbolinlet_new(bogus,0)); + pointerinlet_class = pd_class((t_pd *)pointerinlet_new(bogus,0)); + memcpy(&text_widgetbehavi0r,&text_widgetbehavior,sizeof(t_widgetbehavior)); + text_widgetbehavi0r.w_visfn = text_visfn_hax0r; + class_setwidget(text_class,&text_widgetbehavi0r); +#endif +} + +\class GFStringReplace : FObject { + t_symbol *from; + t_symbol *to; + \constructor (t_symbol *from, t_symbol *to=&s_) {this->from=from; this->to=to;} + \decl 0 symbol (t_symbol *victim); +}; +\def 0 symbol (t_symbol *victim) { + string a = string(victim->s_name); + string b = string(from->s_name); + string c = string(to->s_name); + for (size_t i=0;;) { + i = a.find(b,i); + if (i==string::npos) break; + a = a.replace(i,b.length(),c); + i += c.length(); + } + outlet_symbol(bself->outlets[0],gensym(a.c_str())); +} +\end class {install("gf/string_replace",1,1);} + +\class GFStringLessThan : FObject { + t_symbol *than; + \constructor (t_symbol *than=&s_) {this->than=than;} + \decl 0 symbol (t_symbol *it); + \decl 1 symbol (t_symbol *than); +}; +\def 0 symbol (t_symbol *it) {outlet_float(bself->outlets[0],strcmp(it->s_name,than->s_name)<0);} +\def 1 symbol (t_symbol *than) {this->than=than;} +\end class {install("gf/string_<",2,1);} + +void startup_flow_objects2 () { + \startall +} |