From 8dbec761cf858ea65900c8a094599857208d8c3a Mon Sep 17 00:00:00 2001 From: "N.N." Date: Tue, 5 Jan 2010 22:49:36 +0000 Subject: svn path=/trunk/; revision=12907 --- desiredata/src/desire.c | 7139 ----------------------------------------------- 1 file changed, 7139 deletions(-) delete mode 100644 desiredata/src/desire.c (limited to 'desiredata/src/desire.c') diff --git a/desiredata/src/desire.c b/desiredata/src/desire.c deleted file mode 100644 index 18c04141..00000000 --- a/desiredata/src/desire.c +++ /dev/null @@ -1,7139 +0,0 @@ -/* $Id: desire.c,v 1.1.2.217.2.235 2007-08-21 19:50:25 matju Exp $ - - This file is part of DesireData. - Copyright (c) 2004-2007 by Mathieu Bouchard. - Portions Copyright (c) 1997-2005 Miller Puckette, Günter Geiger, Krzysztof Czaja, - Johannes Zmoelnig, Thomas Musil, Joseph Sarlo, etc. - The remains of IEMGUI Copyright (c) 2000-2001 Thomas Musil (IEM KUG Graz Austria) - For information on usage and redistribution, and for a DISCLAIMER OF ALL - WARRANTIES, see the file, "LICENSE.txt," in this distribution. -*/ - -#define PD_PLUSPLUS_FACE -#include "desire.h" -using namespace desire; -#include -#include -#include -#include -#include -#include -#include "m_simd.h" -#include -#include -#include -#include -#include -#include - -#ifdef MSW -#include -#define snprintf _snprintf -#else -#include -#endif - -/* -#define sys_vgui(args...) do { \ - fprintf(stderr,"\e[0;1;31m"); \ - L fprintf(stderr,args); \ - fprintf(stderr,"\e[0m"); \ - sys_vgui(args); } while(0) -*/ - -#define foreach(ITER,COLL) for(typeof(COLL.begin()) ITER = COLL.begin(); ITER != (COLL).end(); ITER++) - -#define boxes_each(CHILD,BOXES) for(t_gobj *CHILD= (BOXES)->first(); CHILD; CHILD=CHILD->next()) -#define canvas_each(CHILD,CANVAS) for(t_gobj *CHILD=(CANVAS)->boxes->first(); CHILD; CHILD=CHILD->next()) -#define canvas_wires_each(WIRE,TRAV,CANVAS) \ - for (t_outconnect *WIRE=(t_outconnect *)666; WIRE==(t_outconnect *)666; ) \ - for (t_linetraverser TRAV(CANVAS); (WIRE=linetraverser_next(&TRAV)); ) - -#undef SET -#define SET(attr,value) do {gobj_changed(x,#attr); x->attr = (value);} while(0) - -#define a_float a_w.w_float -#define a_symbol a_w.w_symbol - -#define CLAMP(_var,_min,_max) do {if (_var<_min) _var=_min; else if (_var>_max) _var=_max;} while(0) -#define IS_A_FLOAT(atom,index) ((atom+index)->a_type == A_FLOAT) -#define IS_A_SYMBOL(atom,index) ((atom+index)->a_type == A_SYMBOL) - -template T *realloc2(T *p, size_t n) {return (T *)realloc(p,n*sizeof(T));} - -int imin(int a, int b) {return ab?a:b;} -t_symbol *s_empty, *s_pd, *s_Pd; - -std::ostream &operator << (std::ostream &str, t_pd *self) { - t_binbuf *b; - if (self->_class->patchable && (b = ((t_text *)self)->binbuf)) { - char *buf; int bufn; - binbuf_gettext(b,&buf,&bufn); - str << "[" << buf << "]"; - free(buf); - } else str << "<" << self->_class->name->name << ":" << std::hex << (long)self << ">"; - return str; -} - -//-------------------------------------------------------------------------- - -t_class *boxes_class; - -struct t_boxes : t_gobj { - typedef std::map M; - typedef std::pair KV; -//private: - std::map map; -public: - void invariant () {size();} - t_boxes() {} - size_t size() { - size_t n=0; - boxes_each(g,this) n++; - if (map.size()!=n) post("map size=%d list size=%d",map.size(),n); - return n; - } - t_gobj *first() {return map.begin() != map.end() ? map.begin()->second : 0;} - t_gobj *last() {M::iterator iter = map.end(); iter--; return iter->second;} - t_gobj *next(t_gobj *x) { - M::iterator iter = map.begin(); - while (iter->second != x) iter++; - iter++; - return iter == map.end() ? 0 : iter->second; - } - t_gobj *get(int i) {return map.find(i)==map.end() ? 0 : map[i];} - void add(t_gobj *x) {map.insert(KV(x->dix->index,x)); invariant();} - void remove(int i) {map.erase(i); invariant();} - void remove_by_value(t_gobj *x) {map.erase(x->dix->index); invariant();} -}; - -t_boxes *boxes_new() { - t_boxes *self = (t_boxes *)pd_new(boxes_class); - new(self) t_boxes; - return self; -} - -void boxes_notice(t_boxes *self, t_gobj *origin, int argc, t_atom *argv) { - gobj_changed3(self,origin,argc,argv); -} - -void boxes_free(t_boxes *self) {self->~t_boxes();} - -t_gobj *_gobj::next() {return dix->canvas->boxes->next(this);} - -//-------------------------------------------------------------------------- - -t_class *gop_filtre_class; - -struct t_gop_filtre : t_gobj { - t_canvas *canvas; -}; - -// test for half-open interval membership -bool inside (int x, int x0, int x1) {return x0<=x && xcanvas; - if (0/* check for messagebox, comment, but you can't check for objectboxes in general */) return; - if (c->goprect) { - if (!inside(o->x, c->xmargin, c->xmargin + c->pixwidth )) return; - if (!inside(o->y, c->ymargin, c->ymargin + c->pixheight)) return; - } - gobj_changed3(self,origin,argc,argv); -} - -t_gobj *gop_filtre_new(t_canvas *canvas) { - t_gop_filtre *self = (t_gop_filtre *)pd_new(gop_filtre_class); - new(self) t_gop_filtre; - self->canvas = canvas; - gobj_subscribe(canvas->boxes,self); - return self; -} - -void gop_filtre_free(t_boxes *self) {} - -//-------------------------------------------------------------------------- -// t_appendix: an extension to t_gobj made by matju so that all t_gobj's may have new fields -// without sacrificing binary compat with externals compiled for PureMSP. - -typedef t_hash t_visual; - -t_appendix *appendix_new (t_gobj *master) { - //fprintf(stderr,"appendix_new %p\n",master); - t_appendix *self = (t_appendix *)malloc(sizeof(t_appendix)); - self->canvas = 0; - self->nobs = 0; - self->obs = 0; - self->visual = new t_visual(1); - self->index = 0; - self->elapsed = 0; - return self; -} - -void appendix_save (t_gobj *master, t_binbuf *b) { - t_visual *h = master->dix->visual; - //fprintf(stderr,"appendix_save %p size=%ld\n",master,hash_size(h)); - if (!h->size()) return; - t_symbol *k; - t_arglist *v; - int i=0; - binbuf_addv(b,"t","#V"); - hash_foreach(k,v,h) { - t_arglist *al = (t_arglist *)v; - binbuf_addv(b,"s",k); - binbuf_add(b,al->c,al->v); - if (size_t(i+1)==h->size()) binbuf_addv(b, ";"); else binbuf_addv(b,"t",","); - i++; - } -} - -void appendix_free (t_gobj *master) { - t_appendix *self = master->dix; - t_symbol *k; - t_arglist *v; - if (self->visual) { - hash_foreach(k,v,self->visual) free(v); - delete self->visual; - } - free(self); -} - -/* subscribing N spies takes N*N time, but it's not important for now */ -/* subscription could become just a special use of t_outlet in the future, or sometimes become implied. */ -/* perhaps use [bindelem] here? */ -void gobj_subscribe(t_gobj *self, t_gobj *observer) { - t_appendix *d = self->dix; - for (size_t i=0; inobs; i++) if (d->obs[i]) return; - d->obs=realloc2(d->obs,1+d->nobs); - d->obs[d->nobs++] = observer; - t_onsubscribe ons = self->_class->onsubscribe; - ons(self,observer); - //post("x%p has %d observers",self,(int)d->nobs); -} - -void gobj_unsubscribe (t_gobj *self, t_gobj *observer) { - t_appendix *d = self->dix; - size_t i; - for (i=0; inobs; i++) if (d->obs[i]) break; - if (i==d->nobs) return; - d->nobs--; - for (; inobs; i++) d->obs[i] = d->obs[i+1]; - // should have something like onunsubscribe too, to handle delete?... or just use onsubscribe differently. -} - -void gobj_setcanvas (t_gobj *self, t_canvas *c) { - if (self->dix->canvas == c) return; - if (self->dix->canvas) gobj_unsubscribe(self,self->dix->canvas); - self->dix->canvas = c; - if (self->dix->canvas) gobj_subscribe(self,self->dix->canvas); -} - -/* for future use */ -t_canvas *gobj_canvas (t_gobj *self) {return self->dix->canvas;} - -// if !k then suppose all of the object might have changed. -void gobj_changed (t_gobj *self, const char *k) { - int dirty = k ? (1<_class,k)) : -1; - t_atom argv[1]; - SETFLOAT(argv,(float)dirty); - gobj_changed3(self,self,1,argv); -} -//#define gobj_changed(SELF,K) do {L; gobj_changed(SELF,K);} while(0) - -// if only a float is sent, it's a bitset of at most 25 elements -// else it may mean whatever else... -void gobj_changed2 (t_gobj *self, int argc, t_atom *argv) { - gobj_changed3(self,self,argc,argv); -} - -void gobj_changed3 (t_gobj *self, t_gobj *origin, int argc, t_atom *argv) { - t_appendix *d = self->dix; - std::ostringstream s; - for (int i=0; inobs; i++) { - t_gobj *obs = d->obs[i]; - t_notice ice = obs->_class->notice; - if (ice) ice(obs,origin,argc,argv); - else post("null func ptr for class %s",self->_class->name->name); - } -} - -//-------------------------------------------------------------------------- -// some simple ringbuffer-style queue -// when this becomes too small, use a bigger constant or a better impl. - -#define QUEUE_SIZE 16384 -struct t_queue { - int start,len; - t_pd *o[QUEUE_SIZE]; -}; - -t_queue *queue_new () { - t_queue *self = (t_queue *)getbytes(sizeof(t_queue)); - self->start = self->len = 0; - return self; -} - -static bool debug_queue=0; - -static void pd_print (t_pd *self, const char *header) { - if (self->_class->gobj && (object_table->get(self)&1)==0) {printf("%s %p dead\n",header,self); return;} - if (self->_class->patchable) { - t_binbuf *b = ((t_text *)self)->binbuf; - if (b) { - char *buf; int bufn; - binbuf_gettext(b,&buf,&bufn); - printf("%s %p [%.*s]\n",header,self,bufn,buf); - return; - } - } - printf("%s %p (%s)\n",header,self,self->_class->name->name); -} - -void queue_put (t_queue *self, t_pd *stuff) { - if (debug_queue) pd_print(stuff,"queue_put"); - if (self->len==QUEUE_SIZE) {bug("queue full"); return;} - self->o[(self->start+self->len)%QUEUE_SIZE] = stuff; - self->len++; - if (debug_queue) post("queue_put: items in queue: %d",self->len); -} - -void *queue_get (t_queue *self) { - t_pd *stuff = self->o[self->start]; - self->start = (self->start+1)%QUEUE_SIZE; - self->len--; - if (debug_queue) {post("queue_get: items in queue: %d",self->len); pd_print(stuff,"queue_get");} - return stuff; -} - -#define queue_each(i,self) \ - for (int i=self->start; i!=(self->start+self->len)%QUEUE_SIZE; i=(i+1)%QUEUE_SIZE) - -void queue_free (t_queue *self) { - abort(); - free(self); -} - -int queue_empty (t_queue *self) {return self->len==0;} -int queue_full (t_queue *self) {return self->len==QUEUE_SIZE;} - -//-------------------------------------------------------------------------- -// reply system: - -struct t_reply : t_gobj { - short serial; - void *answer; -}; - -t_class *reply_class; - -static t_reply *reply_new (short serial, void *answer) { - t_reply *self = (t_reply *)pd_new(reply_class); - self->dix = appendix_new(self); - self->serial = serial; - self->answer = answer; - return self; -} - -static void reply_send (t_reply *self) { - sys_vgui("serial %ld x%lx\n",(long)self->serial,(long)self->answer); -} - -static void reply_free (t_reply *self) {} - -//-------------------------------------------------------------------------- -// update manager: - -struct t_dirtyentry { - long fields; - size_t start,end; - t_dirtyentry() {} -}; - -typedef t_hash t_dirtyset; - -struct t_manager : t_text { - t_queue *q; - t_clock *clock; - t_binbuf *b; /* reusable, for processing messages from the gui */ - t_dirtyset *dirty; -}; - -static t_class *manager_class; -t_manager *manager; - -void manager_call (void *foo) { - t_manager *self = (t_manager *)foo; - while (!queue_empty(self->q)) { - t_gobj *o = (t_gobj *)queue_get(self->q); - if (!o) continue; /* cancelled notice */ - //fprintf(stderr,"manager_call, o->_class=%s\n",o->_class->c_name->name); - if (o->_class == reply_class) { - reply_send((t_reply *)o); - pd_free(o); - } else { - if (self->dirty->exists(o)) { - pd_upload(o); - self->dirty->del(o); - } - } - } - clock_delay(self->clock,25); -} - -void manager_notice (t_gobj *self_, t_gobj *origin, int argc, t_atom *argv) { - t_manager *self = (t_manager *)self_; - if (!self->dirty->exists(origin)) { - //std::cerr << "manager_notice:"; - //for (int i=0; iq,origin); - self->dirty->set(origin,0); - } -} - -t_manager *manager_new (t_symbol *s, int argc, t_atom *argv) { - t_manager *self = (t_manager *)pd_new(manager_class); - self->q = queue_new(); - self->clock = clock_new(self,(t_method)manager_call); - self->b = binbuf_new(); - clock_delay(self->clock,0); - self->dirty = new t_dirtyset(127); - return self; -} - -void manager_free (t_manager *self) { - clock_free(self->clock); - queue_free(self->q); - binbuf_free(self->b); - pd_free(self); -} - -extern "C" void manager_anything (t_manager *self, t_symbol *s, int argc, t_atom *argv) { - binbuf_clear(self->b); - binbuf_addv(self->b,"s",s); - binbuf_add(self->b,argc,argv); - binbuf_eval(self->b,0,0,0); -} - -//-------------------------------------------------------------------------- -/* -IOhannes changed the canvas_restore, so that it might accept $args as well -(like "pd $0_test") so you can make multiple & distinguishable templates. -*/ - -#define CANVAS_DEFCANVASWIDTH 450 -#define CANVAS_DEFCANVASHEIGHT 300 - -#ifdef __APPLE__ -#define CANVAS_DEFCANVASYLOC 22 -#else -#define CANVAS_DEFCANVASYLOC 0 -#endif - -extern short next_object; -extern t_pd *newest; -t_class *canvas_class; -int canvas_dspstate; /* whether DSP is on or off */ -t_canvas *canvas_whichfind; /* last canvas we did a find in */ -std::map windowed_canvases; /* where int is dummy */ -static void canvas_setbounds(t_canvas *x, t_floatarg x1, t_floatarg y1, t_floatarg x2, t_floatarg y2); -static t_symbol *canvas_newfilename = &s_; -static t_symbol *canvas_newdirectory = &s_; -static int canvas_newargc; -static t_atom *canvas_newargv; - -/* add a canvas the list of "root" canvases (toplevels without parents.) */ -/* should those two functions still exist? */ -static void canvas_addtolist(t_canvas *x) { - windowed_canvases.insert(std::pair(x,42)); - if (x->havewindow) gobj_subscribe(x,manager); -} -static void canvas_takeofflist(t_canvas *x) {windowed_canvases.erase(x);} - -/* if there's an old one lying around free it here. - This happens if an abstraction is loaded but never gets as far as calling canvas_new(). */ -void canvas_setargs(int argc, t_atom *argv) { - if (canvas_newargv) free(canvas_newargv); - canvas_newargc = argc; - canvas_newargv = (t_atom *)copybytes(argv, argc * sizeof(t_atom)); -} - -void glob_setfilename(void *self, t_symbol *filesym, t_symbol *dirsym) { - canvas_newfilename = filesym; - canvas_newdirectory = dirsym; -} - -t_canvas *canvas_getcurrent () {return ((t_canvas *)pd_findbyclass(&s__X, canvas_class));} - -t_canvasenvironment *canvas_getenv(t_canvas *x) { - while (!x->env) x = x->dix->canvas; - return x->env; -} - -int canvas_getdollarzero () { - t_canvas *x = canvas_getcurrent(); - t_canvasenvironment *env = x ? canvas_getenv(x) : 0; - return env ? env->dollarzero : 0; -} - -t_symbol *canvas_realizedollar(t_canvas *x, t_symbol *s) { - if (strchr(s->name,'$')) { - t_canvasenvironment *env = canvas_getenv(x); - pd_pushsym(x); - t_symbol *ret = binbuf_realizedollsym(s, env->argc, env->argv, 1); - pd_popsym(x); - return ret; - } - return s; -} - -t_symbol *canvas_getcurrentdir () {return canvas_getenv(canvas_getcurrent())->dir;} -t_symbol *canvas_getdir(t_canvas *x) {return canvas_getenv( x)->dir;} - -char *canvas_makefilename(t_canvas *x, char *file, char *result, int resultsize) { - char *dir = canvas_getenv(x)->dir->name; - if (file[0] == '/' || (file[0] && file[1] == ':') || !*dir) { - if (!result) return strdup(file); - strncpy(result, file, resultsize); - result[resultsize-1] = 0; - } else { - if (result) {snprintf(result,resultsize,"%s/%s",dir,file); result[resultsize-1] = 0;} - else asprintf(&result, "%s/%s",dir,file); - } - return result; -} - -static void canvas_rename(t_canvas *x, t_symbol *s, t_symbol *dir) { - t_symbol *bs = canvas_makebindsym(s); - if (x->name!=s_Pd) pd_unbind(x, bs); - SET(name,s); - if (x->name!=s_Pd) pd_bind(x, bs); - if (dir && dir != &s_) { - canvas_getenv(x)->dir = dir; - gobj_changed(x,"dir"); - } -} - -/* --------------- traversing the set of lines in a canvas ----------- */ - -t_linetraverser::t_linetraverser(t_canvas *canvas) {linetraverser_start(this,canvas);} - -void linetraverser_start(t_linetraverser *t, t_canvas *x) { - t->from = 0; - t->canvas = x; - t->next = 0; - t->nextoutno = t->nout = 0; -} - -t_outconnect *linetraverser_next(t_linetraverser *t) { - t_outconnect *rval = t->next; - while (!rval) { - int outno = t->nextoutno; - while (outno == t->nout) { - t_object *ob = 0; - t_gobj *y = t->from ? t->from->next() : t->canvas->boxes->first(); - for (; y; y = y->next()) if ((ob = pd_checkobject(y))) break; - if (!ob) return 0; - t->from = ob; - t->nout = obj_noutlets(ob); - outno = 0; - } - t->nextoutno = outno + 1; - rval = obj_starttraverseoutlet(t->from, &t->outletp, outno); - t->outlet = outno; - } - t->next = obj_nexttraverseoutlet(rval, &t->to, &t->inletp, &t->inlet); - t->nin = obj_ninlets(t->to); - if (!t->nin) bug("linetraverser_next"); - return rval; -} - -/* -------------------- the canvas object -------------------------- */ -static int hack = 1; - -static t_canvas *canvas_new2() { - t_canvas *x = (t_canvas *)pd_new(canvas_class); - /* zero out every field except "pd" and "dix" */ - memset(((char *)x) + sizeof(t_gobj), 0, sizeof(*x) - sizeof(t_gobj)); - x->xlabel = (t_symbol **)getbytes(0); - x->ylabel = (t_symbol **)getbytes(0); - // only manage this canvas if it's not one of the 3 invisible builtin canvases - x->boxes = boxes_new(); - return x; -} - -static void canvas_vis(t_canvas *x, t_floatarg f); - -/* make a new canvas. It will either be a "root" canvas or else it appears as - a "text" object in another window (canvas_getcurrent() tells us which.) */ -static t_canvas *canvas_new(void *self, t_symbol *sel, int argc, t_atom *argv) { - t_canvas *x = canvas_new2(); - t_canvas *owner = canvas_getcurrent(); - t_symbol *s = &s_; - int width = CANVAS_DEFCANVASWIDTH, xloc = 0; - int height = CANVAS_DEFCANVASHEIGHT, yloc = CANVAS_DEFCANVASYLOC; - int vis=0, font = owner?owner->font:10; - if (!owner) canvas_addtolist(x); - /* toplevel vs subwindow */ - if (argc==5) pd_scanargs(argc,argv,"iiiii", &xloc,&yloc,&width,&height,&font); - else if (argc==6) pd_scanargs(argc,argv,"iiiisi",&xloc,&yloc,&width,&height,&s,&vis); - /* (otherwise assume we're being created from the menu.) */ - if (canvas_newdirectory->name[0]) { - static long dollarzero = 1000; - t_canvasenvironment *env = x->env = (t_canvasenvironment *)getbytes(sizeof(*x->env)); - if (!canvas_newargv) canvas_newargv = (t_atom *)getbytes(0); - env->dir = canvas_newdirectory; - env->argc = canvas_newargc; - env->argv = canvas_newargv; - env->dollarzero = dollarzero++; - env->path = 0; - canvas_newdirectory = &s_; - canvas_newargc = 0; - canvas_newargv = 0; - } else x->env = 0; - - if (yloc < CANVAS_DEFCANVASYLOC) yloc = CANVAS_DEFCANVASYLOC; - if (xloc < 0) xloc = 0; - x->x1 = 0; x->y1 = 0; - x->x2 = 1; x->y2 = 1; - canvas_setbounds(x, xloc, yloc, xloc + width, yloc + height); - gobj_setcanvas(x,owner); - x->name = *s->name ? s : canvas_newfilename ? canvas_newfilename : s_Pd; - if (x->name != s_Pd) pd_bind(x, canvas_makebindsym(x->name)); - x->goprect = 0; /* no GOP rectangle unless it's turned on later */ - /* cancel "vis" flag if we're a subpatch of an abstraction inside another patch. - A separate mechanism prevents the toplevel abstraction from showing up. */ - if (vis && gensym("#X")->thing && gensym("#X")->thing->_class == canvas_class) { - t_canvas *z = (t_canvas *)(gensym("#X")->thing); - while (z && !z->env) z = z->dix->canvas; - if (z && canvas_isabstraction(z) && z->dix->canvas) vis = 0; - } - if (vis) canvas_vis(x,vis); - x->font = 10 /*sys_nearestfontsize(font)*/; - pd_pushsym(x); - newest = x; - return x; -} - -void canvas_setgraph(t_canvas *x, int flag, int nogoprect); - -static void canvas_coords(t_canvas *x, t_symbol *s, int argc, t_atom *argv) { - pd_scanargs(argc,argv,"ffffii*",&x->x1,&x->y1,&x->x2,&x->y2,&x->pixwidth,&x->pixheight); - if (argc <= 7) canvas_setgraph(x, atom_getintarg(6, argc, argv), 1); - else { - canvas_setgraph(x, atom_getintarg(6, argc, argv), 0); - SET(xmargin, atom_getintarg(7, argc, argv)); - SET(ymargin, atom_getintarg(8, argc, argv)); - } - gobj_changed(x,0); -} - -//template void swap(T &a, T &b) {T c=a; a=b; b=c;} -#define swap std::swap - -#define CANVAS_DEFGRAPHWIDTH 200 -#define CANVAS_DEFGRAPHHEIGHT 140 -/* make a new canvas and add it to this canvas. It will appear as a "graph", not a text object. */ -static t_canvas *canvas_addcanvas(t_canvas *g, t_symbol *sym, -float x1, float y1, float x2, float y2, -float px1, float py1, float px2, float py2) { - static int gcount = 0; - int menu = 0; - t_canvas *x = canvas_new2(); - if (!*sym->name) { - sym = symprintf("graph%d", ++gcount); - menu = 1; - } else if (!strncmp(sym->name,"graph",5)) { - int zz = atoi(sym->name+5); - if (zz>gcount) gcount = zz; - } - /* in 0.34 and earlier, the pixel rectangle and the y bounds were reversed; this would behave the same, - except that the dialog window would be confusing. The "correct" way is to have "py1" be the value - that is higher on the screen. */ - if (py2 < py1) {swap(y1,y2); swap(py1,py2);} - if (x1 == x2 || y1 == y2) {x1=0; x2=100; y1=1; y2=-1;} - if (px1 >= px2 || py1 >= py2) { - px1=100; px2=px1+CANVAS_DEFGRAPHWIDTH; - py1=20; py2=py1+CANVAS_DEFGRAPHHEIGHT; - } - x->name = sym; - SET(x1,x1); SET(y1,y1); SET(x,short(px1)); SET(pixwidth ,int(px2-px1)); - SET(x2,x2); SET(y2,y2); SET(y,short(py1)); SET(pixheight,int(py2-py1)); - x->font = (canvas_getcurrent() ? canvas_getcurrent()->font : 42 /*sys_defaultfont*/); - x->screenx1 = x->screeny1 = 0; x->screenx2 = 450; x->screeny2 = 300; - if (x->name != s_Pd) pd_bind(x, canvas_makebindsym(x->name)); - gobj_setcanvas(x,g); - x->gop = 1; - x->goprect = 0; - x->binbuf = binbuf_new(); - binbuf_addv(x->binbuf,"t","graph"); - if (!menu) pd_pushsym(x); - canvas_add(g,x); - return x; -} - -static void canvas_canvas(t_canvas *g, t_symbol *s, int argc, t_atom *argv) { - t_symbol *sym; - float x1,y1,x2,y2,px1,py1,px2,py2; - pd_scanargs(argc,argv,"sffffffff",&sym,&x1,&y1,&x2,&y2,&px1,&py1,&px2,&py2); - canvas_addcanvas(g, sym, x1, y1, x2, y2, px1, py1, px2, py2); -} - -static void canvas_redraw(t_canvas *x) { - gobj_changed(x,0); - canvas_each(y,x) if (y->_class==canvas_class) canvas_redraw((t_canvas *)y); else gobj_changed(y,0); -} - -/* This is sent from the GUI to inform a toplevel that its window has been moved or resized. */ -static void canvas_setbounds(t_canvas *x, t_floatarg x1, t_floatarg y1, t_floatarg x2, t_floatarg y2) { - int heightwas = int(y2-y1); - if (x->screenx1 == x1 && x->screeny1 == y1 && - x->screenx2 == x2 && x->screeny2 == y2) return; - x->screenx1 = int(x1); x->screeny1 = int(y1); - x->screenx2 = int(x2); x->screeny2 = int(y2); - if (!x->gop && x->y2 < x->y1) { - /* if it's flipped so that y grows upward, fix so that zero is bottom edge and redraw. - This is only appropriate if we're a regular "text" object on the parent. */ - float diff = x->y1 - x->y2; - x->y1 = heightwas * diff; - x->y2 = x->y1 - diff; - canvas_redraw(x); - } -} - -t_symbol *canvas_makebindsym(t_symbol *s) {return symprintf("pd-%s",s->name);} - -static void canvas_vis(t_canvas *x, t_floatarg f) { - int hadwindow = x->havewindow; - SET(havewindow,!!f); - if (hadwindow && !x->havewindow) gobj_unsubscribe(x,manager); - if (!hadwindow && x->havewindow) gobj_subscribe(x,manager); -} - -/* we call this on a non-toplevel canvas to "open" it into its own window. */ -static void canvas_menu_open(t_canvas *x) { - if (canvas_isvisible(x) && !canvas_istoplevel(x)) { - if (!x->dix->canvas) {error("this works only on subpatch or abstraction"); return;} - SET(havewindow,1); - } -} - -int canvas_isvisible(t_canvas *x) {return gstack_empty() && canvas_getcanvas(x)->havewindow;} - -/* we consider a graph "toplevel" if it has its own window or if it appears as a box in its parent window - so that we don't draw the actual contents there. */ -int canvas_istoplevel(t_canvas *x) {return x->havewindow || !x->gop;} - -static void canvas_free(t_canvas *x) { - int dspstate = canvas_suspend_dsp(); - if (canvas_whichfind == x) canvas_whichfind = 0; - t_gobj *y; - while ((y = x->boxes->first())) canvas_delete(x, y); - canvas_vis(x, 0); - if (x->name != s_Pd) pd_unbind(x,canvas_makebindsym(x->name)); - if (x->env) { - free(x->env->argv); - free(x->env); - } - canvas_resume_dsp(dspstate); - free(x->xlabel); - free(x->ylabel); - if (!x->dix->canvas) canvas_takeofflist(x); -} - -/* kill all lines for one inlet or outlet */ -void canvas_deletelinesforio(t_canvas *x, t_text *text, t_inlet *inp, t_outlet *outp) { - canvas_wires_each(oc,t,x) - if ((t.from == text && t.outletp == outp) || - (t.to == text && t.inletp == inp)) - obj_disconnect(t.from, t.outlet, t.to, t.inlet); -} -void canvas_deletelinesfor(t_canvas *x, t_text *text) { - canvas_wires_each(oc,t,x) - if (t.from == text || t.to == text) - obj_disconnect(t.from, t.outlet, t.to, t.inlet); -} - -static void canvas_resortinlets(t_canvas *x); -static void canvas_resortoutlets(t_canvas *x); -static void canvas_push(t_canvas *x, t_floatarg f) {pd_pushsym(x);} -/* assuming that this only ever gets called on toplevel canvases (?) */ -static void canvas_pop(t_canvas *x, t_floatarg fvis) { - pd_popsym(x); canvas_resortinlets(x); canvas_resortoutlets(x); - if (fvis) canvas_vis(x, 1); -} -extern "C" void canvas_popabstraction(t_canvas *x) { - pd_set_newest(x); - pd_popsym(x); canvas_resortinlets(x); canvas_resortoutlets(x); -} - -void canvas_objfor(t_canvas *gl, t_text *x, int argc, t_atom *argv); - -const char *atomtype_name(t_atomtype i) { -#define T(TYPE) case TYPE: return #TYPE; - switch (i) { - T(A_NULL) - T(A_FLOAT) T(A_SYMBOL) T(A_POINTER) - T(A_SEMI) T(A_COMMA) - T(A_DEFFLOAT) T(A_DEFSYM) - T(A_DOLLAR) T(A_DOLLSYM) - T(A_GIMME) - T(A_CANT) -/* regular pd stops here, before #12 */ - T(A_ATOM) - T(A_LIST) - T(A_GRID) - T(A_GRIDOUT) - default: return "A_UNKNOWN"; - } -} - -void canvas_restore(t_canvas *x, t_symbol *s, int argc, t_atom *argv) { - if (argc > 3) { - t_atom *ap=argv+3; - if (ap->a_type == A_SYMBOL) { - t_canvasenvironment *e = canvas_getenv(canvas_getcurrent()); - for (int i=0; iargc; i++) post("restore: arg %d has type %s",i,atomtype_name(e->argv[i].a_type)); - canvas_rename(x, binbuf_realizedollsym(ap->a_symbol,e->argc,e->argv,1), 0); - } - } - canvas_pop(x,0); /* 0 means "don't touch" here. */ - t_pd *z = gensym("#X")->thing; - if (!z) {error("out of context"); return;} - if (z->_class != canvas_class) {error("wasn't a canvas"); return;} - gobj_setcanvas(x,(t_canvas *)z); - canvas_objfor((t_canvas *)z, x, argc, argv); - newest = x; -} - -static void canvas_loadbang(t_canvas *x); - -static void canvas_loadbangabstractions(t_canvas *x) { - canvas_each(y,x) if (y->_class == canvas_class) { - t_canvas *z = (t_canvas *)y; - if (canvas_isabstraction(z)) canvas_loadbang(z); else canvas_loadbangabstractions(z); - } -} - -void canvas_loadbangsubpatches(t_canvas *x) { - t_symbol *s = gensym("loadbang"); - canvas_each(y,x) if (y->_class == canvas_class) { - t_canvas *z = (t_canvas *)y; - if (!canvas_isabstraction(z)) canvas_loadbangsubpatches(z); - } - canvas_each(y,x) if ((y->_class != canvas_class) && zgetfn(y,s)) pd_vmess(y,s,""); -} - -static void canvas_loadbang(t_canvas *x) { - canvas_loadbangabstractions(x); - canvas_loadbangsubpatches(x); -} - -/* When you ask a canvas its size the result is 2 pixels more than what you gave it to open it; - perhaps there's a 1-pixel border all around it or something. Anyway, we just add the 2 pixels back here; - seems we have to do this for linux but not MSW; not sure about MacOS. */ -#ifdef MSW -#define HORIZBORDER 0 -#define VERTBORDER 0 -#else -#define HORIZBORDER 2 -#define VERTBORDER 2 -#endif - -static void canvas_relocate(t_canvas *x, t_symbol *canvasgeom, t_symbol *topgeom) { - int cxpix, cypix, cw, ch, txpix, typix, tw, th; - if (sscanf(canvasgeom->name, "%dx%d+%d+%d", &cw, &ch, &cxpix, &cypix) < 4 || - sscanf( topgeom->name, "%dx%d+%d+%d", &tw, &th, &txpix, &typix) < 4) - bug("canvas_relocate"); - /* for some reason this is initially called with cw=ch=1 so we just suppress that here. */ - if (cw>5 && ch>5) canvas_setbounds(x, txpix, typix, txpix + cw - HORIZBORDER, typix + ch - VERTBORDER); -} - -void pd_set_newest (t_pd *x) {newest = x;} - -static void *subcanvas_new(t_symbol *s) { - t_atom a[6]; - t_canvas *z = canvas_getcurrent(); - if (!*s->name) s = gensym("/SUBPATCH/"); - SETFLOAT(a, 0); - SETFLOAT(a+1, CANVAS_DEFCANVASYLOC); - SETFLOAT(a+2, CANVAS_DEFCANVASWIDTH); - SETFLOAT(a+3, CANVAS_DEFCANVASHEIGHT); - SETSYMBOL(a+4, s); - SETFLOAT(a+5, 1); - t_canvas *x = canvas_new(0, 0, 6, a); - gobj_setcanvas(x,z); - canvas_pop(x, 1); - return x; -} - -static void canvas_rename_method(t_canvas *x, t_symbol *s, int ac, t_atom *av) { - if (ac && av->a_type == A_SYMBOL) canvas_rename(x, av->a_symbol, 0); - else if (ac && av->a_type == A_DOLLSYM) { - t_canvasenvironment *e = canvas_getenv(x); - pd_pushsym(x); - canvas_rename(x, binbuf_realizedollsym(av->a_symbol, e->argc, e->argv, 1), 0); - pd_popsym(x); - } else canvas_rename(x, gensym("Pd"), 0); -} - -/* ------------------ table ---------------------------*/ - -static t_garray *graph_array(t_canvas *gl, t_symbol *s, t_symbol *tmpl, t_floatarg f, t_floatarg saveit); - -static int tabcount = 0; - -static void *table_new(t_symbol *s, t_floatarg f) { - t_atom a[9]; - t_canvas *z = canvas_getcurrent(); - if (s == &s_) s = symprintf("table%d", tabcount++); - if (f <= 1) f = 100; - SETFLOAT(a, 0); - SETFLOAT(a+1, CANVAS_DEFCANVASYLOC); - SETFLOAT(a+2, 600); - SETFLOAT(a+3, 400); - SETSYMBOL(a+4, s); - SETFLOAT(a+5, 0); - t_canvas *x = canvas_new(0,0,6,a); - gobj_setcanvas(x,z); - /* create a graph for the table */ - t_canvas *gl = canvas_addcanvas(x, &s_, 0, -1, (f > 1 ? f-1 : 1), 1, 50, 350, 550, 50); - graph_array(gl, s, &s_float, f, 0); - canvas_pop(x, 0); - return x; -} - -/* return true if the "canvas" object is an abstraction (so we don't save its contents, fogr example.) */ -int canvas_isabstraction(t_canvas *x) {return x->env!=0;} - -/* return true if the "canvas" object is a "table". */ -int canvas_istable(t_canvas *x) { - t_atom *argv = x->binbuf ? binbuf_getvec( x->binbuf) : 0; - int argc = x->binbuf ? binbuf_getnatom(x->binbuf) : 0; - return argc && argv[0].a_type == A_SYMBOL && argv[0].a_symbol == gensym("table"); -} - -/* return true if the "canvas" object should be treated as a text - object. This is true for abstractions but also for "table"s... */ -/* JMZ: add a flag to gop-abstractions to hide the title */ -static int canvas_showtext(t_canvas *x) { - t_atom *argv = x->binbuf? binbuf_getvec( x->binbuf) : 0; - int argc = x->binbuf? binbuf_getnatom(x->binbuf) : 0; - int isarray = argc && argv[0].a_type == A_SYMBOL && argv[0].a_symbol == gensym("graph"); - return x->hidetext ? 0 : !isarray; -} - -/* get the document containing this canvas */ -t_canvas *canvas_getrootfor(t_canvas *x) { - if (!x->dix->canvas || canvas_isabstraction(x)) return x; - return canvas_getrootfor(x->dix->canvas); -} - -/* ------------------------- DSP chain handling ------------------------- */ - -typedef struct _dspcontext t_dspcontext; - -extern void ugen_start (); -extern void ugen_stop (); -extern "C" t_dspcontext *ugen_start_graph(int toplevel, t_signal **sp, int ninlets, int noutlets); -extern "C" void ugen_add(t_dspcontext *dc, t_object *x); -extern "C" void ugen_connect(t_dspcontext *dc, t_object *from, int outlet, t_object *to, int inlet); -extern "C" void ugen_done_graph(t_dspcontext *dc); - -/* schedule one canvas for DSP. This is called below for all "root" canvases, - but is also called from the "dsp" method for sub-canvases, which are treated almost like any other tilde object. */ -static void canvas_dodsp(t_canvas *x, int toplevel, t_signal **sp) { - t_object *ob; - t_symbol *dspsym = gensym("dsp"); - t_dspcontext *dc = ugen_start_graph(toplevel, sp, obj_nsiginlets(x), obj_nsigoutlets(x)); - canvas_each(y,x) {ob = pd_checkobject(y); if (ob && zgetfn(y,dspsym)) ugen_add(dc, ob);} - canvas_wires_each(oc,t,x) if (obj_issignaloutlet(t.from, t.outlet)) ugen_connect(dc, t.from, t.outlet, t.to, t.inlet); - ugen_done_graph(dc); -} - -static void canvas_dsp(t_canvas *x, t_signal **sp) {canvas_dodsp(x, 0, sp);} - -/* this routine starts DSP for all root canvases. */ -static void canvas_start_dsp() { - if (canvas_dspstate) ugen_stop(); - else sys_gui("pdtk_pd_dsp 1\n"); - ugen_start(); - //timeval v0,v1; gettimeofday(&v0,0); - foreach(x,windowed_canvases) canvas_dodsp(x->first,1,0); - //gettimeofday(&v1,0); printf("canvas_start_dsp took %ld us\n",(v1.tv_sec-v0.tv_sec)*1000000+(v1.tv_usec-v0.tv_usec)); - canvas_dspstate = 1; -} - -/*static*/ void canvas_stop_dsp() { - if (canvas_dspstate) { - ugen_stop(); - sys_gui("pdtk_pd_dsp 0\n"); - canvas_dspstate = 0; - } -} - -/* DSP can be suspended before, and resumed after, operations which might affect the DSP chain. - For example, we suspend before loading and resume afterwards, so that DSP doesn't get resorted for every DSP object in the patch. */ -int canvas_suspend_dsp () { - int rval = canvas_dspstate; - if (rval) canvas_stop_dsp(); - return rval; -} -void canvas_resume_dsp(int oldstate) {if (oldstate) canvas_start_dsp();} -/* this is equivalent to suspending and resuming in one step. */ -void canvas_update_dsp () {if (canvas_dspstate) canvas_start_dsp();} - -extern "C" void glob_dsp(void *self, t_symbol *s, int argc, t_atom *argv) { - if (argc) { - int newstate = atom_getintarg(0, argc, argv); - if (newstate && !canvas_dspstate) { - canvas_start_dsp(); - sys_set_audio_state(1); - } else if (!newstate && canvas_dspstate) { - sys_set_audio_state(0); - canvas_stop_dsp(); - } - } else post("dsp state %d", canvas_dspstate); -} - -extern "C" void *canvas_getblock(t_class *blockclass, t_canvas **canvasp) { - t_canvas *canvas = *canvasp; - void *ret = 0; - canvas_each(g,canvas) if (g->_class == blockclass) ret = g; - *canvasp = canvas->dix->canvas; - return ret; -} - -/******************* redrawing data *********************/ - -static t_float slot_getcoord(t_slot *f, t_template *, t_word *wp, int loud); -static void slot_setcoord(t_slot *f, t_template *, t_word *wp, float pix, int loud); -static t_float slot_cvttocoord(t_slot *f, float val); -static t_template *template_new(t_symbol *sym, int argc, t_atom *argv); -static void template_free(t_template *x); -static int template_match(t_template *x1, t_template *x2); -static int template_find_field(t_template *x, t_symbol*name, int*p_onset, int*p_type, t_symbol **p_arraytype); -static t_float template_getfloat( t_template *x, t_symbol *fieldname, t_word *wp, int loud); -static void template_setfloat( t_template *x, t_symbol *fieldname, t_word *wp, t_float f, int loud); -static t_symbol *template_getsymbol(t_template *x, t_symbol *fieldname, t_word *wp, int loud); -static void template_setsymbol(t_template *x, t_symbol *fieldname, t_word *wp, t_symbol *s, int loud); -static t_template *gtemplate_get(t_gtemplate *x); -static t_template *template_findbyname(t_symbol *s); -static t_canvas *template_findcanvas(t_template *tmpl); -static void template_notify(t_template *, t_symbol *s, int argc, t_atom *argv); - -/* find the template defined by a canvas, and redraw all elements for that */ -void canvas_redrawallfortemplatecanvas(t_canvas *x, int action) { - t_template *tmpl; - t_symbol *s1 = gensym("struct"); - canvas_each(g,x) { - t_object *ob = pd_checkobject(g); - if (!ob || /* ob->type != T_OBJECT || */ binbuf_getnatom(ob->binbuf) < 2) continue; - t_atom *argv = binbuf_getvec(ob->binbuf); - if (argv[0].a_type != A_SYMBOL || argv[1].a_type != A_SYMBOL || argv[0].a_symbol != s1) - continue; - tmpl = template_findbyname(argv[1].a_symbol); - //canvas_redrawallfortemplate(tmpl, action); - } - //canvas_redrawallfortemplate(0, action); -} - -void canvas_disconnect(t_canvas *x, float from_, float outlet, float to_, float inlet) { - int ifrom=(int)from_, ito=int(to_); - t_gobj *from=0, *to=0; - canvas_each(gfrom,x) if (gfrom->dix->index == ifrom) {from=gfrom; break;} - canvas_each( gto,x) if ( gto->dix->index == ito) { to= gto; break;} - if (!from || !to) goto bad; - obj_disconnect((t_object *)from, int(outlet), (t_object *)to, int(inlet)); - return; -bad: - post("dumb."); -} - -static t_binbuf *canvas_cut_wires(t_canvas *x, t_gobj *o); -static void canvas_paste_wires(t_canvas *x, t_binbuf *buf); - -/* recursively check for abstractions to reload as result of a save. - Don't reload the one we just saved ("except") though. */ -/* LATER try to do the same trick for externs. */ -static void canvas_doreload(t_canvas *gl, t_symbol *name, t_symbol *dir, t_gobj *except) { - int i=0, nobj = gl->boxes->size(); - for (t_gobj *g = gl->boxes->first(); g && i < nobj; i++) { - if (g != except && g->_class == canvas_class) { - t_canvas *c = (t_canvas *)g; - if (canvas_isabstraction(c) && c->name==name && canvas_getdir(c) == dir) { - /* we're going to remake the object, so "g" will go stale. Get its index here, and afterwards restore g. - Also, the replacement will be at the end of the list, so we don't do g = g->next() in this case. */ - int j = g->dix->index; - int hadwindow = gl->havewindow; - if (!hadwindow) canvas_vis(canvas_getcanvas(gl), 1); - t_binbuf *buf = canvas_cut_wires(gl,g); - gl->boxes->remove(j); - //MISSING: remake the object here. - canvas_paste_wires(gl,buf); - if (!hadwindow) canvas_vis(canvas_getcanvas(gl), 0); - continue; - } - canvas_doreload(c,name,dir,except); - } - g = g->next(); - } -} - -void canvas_reload(t_symbol *name, t_symbol *dir, t_gobj *except) { - foreach(x,windowed_canvases) canvas_doreload(x->first, name, dir, except); -} - -/* ------------------------ event handling ------------------------ */ - -/* set a canvas up as a graph-on-parent. - Set reasonable defaults for any missing paramters and redraw things if necessary. */ -void canvas_setgraph(t_canvas *x, int flag, int nogoprect) { - if (!flag && x->gop) { - x->gop = 0; - } else if (flag) { - if (x->pixwidth <= 0) x->pixwidth = CANVAS_DEFGRAPHWIDTH; - if (x->pixheight <= 0) x->pixheight = CANVAS_DEFGRAPHHEIGHT; - SET(gop,1); - SET(hidetext,!!(flag&2)); - if (!nogoprect && !x->goprect) canvas_each(g,x) if (pd_checkobject(g)) {SET(goprect,1); break;} - if (canvas_isvisible(x) && x->goprect) gobj_changed(x,0); - } -} - -/* keep me */ -static int canvas_isconnected (t_canvas *x, t_text *ob1, int n1, t_text *ob2, int n2) { - canvas_wires_each(oc,t,x) - if (t.from == ob1 && t.outlet == n1 && t.to == ob2 && t.inlet == n2) return 1; - return 0; -} - -/* ----------------------------- window stuff ----------------------- */ - -void canvas_close(t_canvas *x) { - if (x->dix->canvas) canvas_vis(x, 0); else pd_free(x); -} - -static int canvas_find_index1, canvas_find_index2; -static t_binbuf *canvas_findbuf; -int binbuf_match(t_binbuf *inbuf, t_binbuf *searchbuf); - -/* find an atom or string of atoms */ -static int canvas_dofind(t_canvas *x, int *myindex1p) { - int myindex1 = *myindex1p, myindex2=0; - if (myindex1 >= canvas_find_index1) { - canvas_each(y,x) { - t_object *ob = pd_checkobject(y); - if (ob && binbuf_match(ob->ob_binbuf, canvas_findbuf)) { - if (myindex1 > canvas_find_index1 || - (myindex1 == canvas_find_index1 && myindex2 > canvas_find_index2)) { - canvas_find_index1 = myindex1; - canvas_find_index2 = myindex2; - vmess(x,gensym("menu-open"),""); - return 1; - } - } - myindex2++; - } - } - myindex2=0; - canvas_each(y,x) { - if (y->_class == canvas_class) { - (*myindex1p)++; - if (canvas_dofind((t_canvas *)y, myindex1p)) return 1; - } - myindex2++; - } - return 0; -} - -static void canvas_find_parent(t_canvas *x) { - if (x->dix->canvas) canvas_vis(canvas_getcanvas(x->dix->canvas), 1); -} - -static int canvas_dofinderror(t_canvas *gl, void *error_object) { - canvas_each(g,gl) { - if (g==error_object) { - /* got it... now show it. */ - canvas_vis(canvas_getcanvas(gl), 1); - return 1; - } else if (g->_class == canvas_class) { - if (canvas_dofinderror((t_canvas *)g, error_object)) return 1; - } - } - return 0; -} - -void canvas_finderror(void *error_object) { - foreach(x,windowed_canvases) if (canvas_dofinderror(x->first, error_object)) return; - post("... sorry, I couldn't find the source of that error."); -} - -extern t_class *text_class; -extern t_class *dummy_class; - -static int is_dummy (t_text *x) {return x->_class==dummy_class;} - -long canvas_base_o_index(void); - -void canvas_connect(t_canvas *x, t_floatarg ffrom, t_floatarg foutlet, t_floatarg fto,t_floatarg finlet) { - int base = canvas_base_o_index(); - int ifrom=base+int(ffrom), outlet=(int)foutlet; - int ito=base+int(fto), inlet=(int)finlet; - t_gobj *gfrom=0, *gto=0; - t_object *from=0, *to=0; - t_outconnect *oc; - if (ifrom<0) goto bad; - if (ito <0) goto bad; - canvas_each(zfrom,x) if (zfrom->dix->index == ifrom) {gfrom=zfrom; break;} - if (!gfrom) goto bad; - canvas_each( zto,x) if ( zto->dix->index == ito) { gto= zto; break;} - if (!gto) goto bad; - from = pd_checkobject(gfrom); - to = pd_checkobject( gto); - if (!from || !to) goto bad; - /* if object creation failed, make dummy inlets or outlets as needed */ - if (is_dummy(from)) while (outlet >= obj_noutlets(from)) outlet_new(from, &s_); - if (is_dummy(to)) while ( inlet >= obj_ninlets(to)) inlet_new(to,to,&s_,&s_); - if (!(oc = obj_connect(from,outlet,to,inlet))) goto bad; - pd_set_newest(oc); - gobj_setcanvas(oc,x); - oc->dix->index = x->next_w_index++; - return; -bad: - post("%s %d %d %d %d (%s->%s) connection failed", x->name->name,ifrom,outlet,ito,inlet, - from ? class_getname(from->_class) : "???", - to ? class_getname( to->_class) : "???"); -} - -#define ARRAYPAGESIZE 1000 /* this should match the page size in u_main.tk */ -/* aux routine to bash leading '#' to '$' for dialogs in u_main.tk which can't send symbols - starting with '$' (because the Pd message interpreter would change them!) */ -static t_symbol *sharptodollar(t_symbol *s) { - if (*s->name != '#') return s; - return symprintf("$%s",s->name+1); -} - -/* --------- "pure" arrays with scalars for elements. --------------- */ - -/* Pure arrays have no a priori graphical capabilities. -They are instantiated by "garrays" below or can be elements of other -scalars (g_scalar.c); their graphical behavior is defined accordingly. */ - -t_class *array_class; - -static t_array *array_new(t_symbol *tsym, t_gpointer *parent) { - t_array *x = (t_array *)pd_new(array_class); - t_template *t = template_findbyname(tsym); - x->tsym = tsym; - x->n = 1; - x->elemsize = sizeof(t_word) * t->n; - x->vec = (char *)getalignedbytes(x->elemsize); - /* note here we blithely copy a gpointer instead of "setting" a new one; this gpointer isn't accounted for - and needn't be since we'll be deleted before the thing pointed to gets deleted anyway; see array_free. */ - x->gp = *parent; - word_init((t_word *)x->vec, t, parent); - return x; -} - -void array_resize(t_array *x, int n) { - t_template *t = template_findbyname(x->tsym); - if (n < 1) n = 1; - int oldn = x->n; - int elemsize = sizeof(t_word) * t->n; - x->vec = (char *)resizealignedbytes(x->vec, oldn * elemsize, n * elemsize); - x->n = n; - if (n > oldn) { - char *cp = x->vec + elemsize * oldn; - for (int i = n-oldn; i--; cp += elemsize) { - t_word *wp = (t_word *)cp; - word_init(wp, t, &x->gp); - } - } -} - -static void array_resize_and_redraw(t_array *array, int n) {array_resize(array,n); gobj_changed(array,0);} - -void word_free(t_word *wp, t_template *t); - -static void array_free(t_array *x) { - t_template *scalartemplate = template_findbyname(x->tsym); - for (int i=0; i < x->n; i++) word_free((t_word *)(x->vec + x->elemsize*i), scalartemplate); - freealignedbytes(x->vec, x->elemsize * x->n); -} - -/* --------------------- graphical arrays (garrays) ------------------- */ -t_class *garray_class; -static t_pd *garray_arraytemplatecanvas; -void pd_eval_text2(const char *s) {pd_eval_text(s,strlen(s));} - -/* create invisible, built-in canvases to determine the templates for floats and float-arrays. */ -extern "C" void garray_init () { - hack = 0; /* invisible canvases must be, uh, invisible */ - if (garray_arraytemplatecanvas) return; - t_binbuf *b = binbuf_new(); - glob_setfilename(0, gensym("_float"), gensym(".")); - pd_eval_text2( - "#N canvas 0 0 458 153 10;\n" - "#X obj 43 31 struct _float_array array z float float style float linewidth float color;\n" - "#X obj 43 70 plot z color linewidth 0 0 1 style;\n"); - vmess(s__X.thing, gensym("pop"), "i", 0); - glob_setfilename(0, gensym("_float_array"), gensym(".")); - pd_eval_text2( - "#N canvas 0 0 458 153 10;\n" - "#X obj 39 26 struct float float y;\n"); - garray_arraytemplatecanvas = s__X.thing; - vmess(s__X.thing, gensym("pop"), "i", 0); - glob_setfilename(0, &s_, &s_); - binbuf_free(b); - hack = 1; /* enable canvas visibility for upcoming canvases */ -} - -/* create a new scalar attached to a symbol. Used to make floating-point arrays (the scalar will be of type "_float_array"). - Currently this is always called by graph_array() below; - but when we make a more general way to save and create arrays this might get called more directly. */ -static t_garray *graph_scalar(t_canvas *gl, t_symbol *s, t_symbol *tsym, int saveit) { - if (!template_findbyname(tsym)) return 0; - t_garray *x = (t_garray *)pd_new(garray_class); - x->scalar = scalar_new(gl, tsym); - x->realname = s; - x->realname = canvas_realizedollar(gl, s); - pd_bind(x,x->realname); - x->usedindsp = 0; - x->saveit = saveit; - x->listviewing = 0; - canvas_add(gl,x); - x->canvas = gl; - return x; -} - -#define TEMPLATE_CHECK(tsym,ret) if (!t) {error("couldn't find template %s", tsym->name); return ret;} -#define TEMPLATE_FLOATY(a,ret) if (!a) {error("%s: needs floating-point 'y' field", x->realname->name); return ret;} - -/* get a garray's "array" structure. */ -t_array *garray_getarray(t_garray *x) { - int zonset, ztype; - t_symbol *zarraytype; - t_scalar *sc = x->scalar; - t_template *t = template_findbyname(sc->t); - TEMPLATE_CHECK(sc->t,0) - if (!template_find_field(t,gensym("z"),&zonset,&ztype,&zarraytype)) { - error("template %s has no 'z' field", sc->t->name); - return 0; - } - if (ztype != DT_ARRAY) {error("template %s, 'z' field is not an array", sc->t->name); return 0;} - return sc->v[zonset].w_array; -} - -/* get the "array" structure and furthermore check it's float */ -static t_array *garray_getarray_floatonly(t_garray *x, int *yonsetp, int *elemsizep) { - t_array *a = garray_getarray(x); - int yonset, type; - t_symbol *arraytype; - t_template *t = template_findbyname(a->tsym); - if (!template_find_field(t,&s_y,&yonset,&type,&arraytype) || type != DT_FLOAT) return 0; - *yonsetp = yonset; - *elemsizep = a->elemsize; - return a; -} - -/* get the array's name. Return nonzero if it should be hidden */ -int garray_getname(t_garray *x, t_symbol **namep) { -// *namep = x->name; - *namep = x->realname; - return x->hidename; -} - -/* if there is one garray in a graph, reset the graph's coordinates to fit a new size and style for the garray */ -static void garray_fittograph(t_garray *x, int n, int style) { - t_array *array = garray_getarray(x); - t_canvas *gl = x->canvas; - if (gl->boxes->first() == x && !x->next()) - vmess(gl,gensym("bounds"),"ffff",0.,gl->y1, double(style==PLOTSTYLE_POINTS || n==1 ? n : n-1), gl->y2); - array_resize_and_redraw(array, n); -} - -/* handle "array" message to canvases; call graph_scalar above with an appropriate template; then set size and flags. - This is called from the menu and in the file format for patches. LATER replace this by a more coherent (and general) invocation. */ -t_garray *graph_array(t_canvas *gl, t_symbol *s, t_symbol *templateargsym, t_floatarg fsize, t_floatarg fflags) { - int n = (int)fsize, zonset, ztype, saveit; - t_symbol *zarraytype; - t_symbol *tsym = gensym("pd-_float_array"); - int flags = (int)fflags; - int filestyle = (flags & 6)>>1; - int style = filestyle == 0 ? PLOTSTYLE_POLY : filestyle == 1 ? PLOTSTYLE_POINTS : filestyle; - if (templateargsym != &s_float) {error("%s: only 'float' type understood", templateargsym->name); return 0;} - t_template *t = template_findbyname(tsym); - TEMPLATE_CHECK(tsym,0) - if (!template_find_field(t,gensym("z"),&zonset,&ztype,&zarraytype)) {error("template %s has no 'z' field", tsym->name); return 0;} - if (ztype != DT_ARRAY) {error("template %s, 'z' field is not an array", tsym->name); return 0;} - t_template *ztemplate = template_findbyname(zarraytype); - if (!ztemplate) {error("no template of type %s", zarraytype->name); return 0;} - saveit = (flags & 1) != 0; - t_garray *x = graph_scalar(gl, s, tsym, saveit); - x->hidename = (flags>>3)&1; - if (n <= 0) n = 100; - array_resize(x->scalar->v[zonset].w_array, n); - template_setfloat(t, gensym("style"), x->scalar->v, style, 1); - template_setfloat(t, gensym("linewidth"), x->scalar->v, style==PLOTSTYLE_POINTS?2:1, 1); - t_pd *x2 = pd_findbyclass(gensym("#A"), garray_class); - if (x2) pd_unbind(x2,gensym("#A")); - pd_bind(x,gensym("#A")); - garray_redraw(x); - return x; -} - -/* find the graph most recently added to this canvas; if none exists, return 0. */ -static t_canvas *canvas_findgraph(t_canvas *x) { - t_gobj *y = 0; - canvas_each(z,x) if (z->_class==canvas_class && ((t_canvas *)z)->gop) y = z; - return (t_canvas *)y; -} - -/* this is called back from the dialog window to create a garray. - The otherflag requests that we find an existing graph to put it in. */ -static void canvas_arraydialog(t_canvas *parent, t_symbol *name, t_floatarg size, t_floatarg fflags, t_floatarg otherflag) { - int flags = (int)fflags; - if (size<1) size=1; - t_canvas *gl = otherflag ? canvas_findgraph(parent) : 0; - if (!gl) gl = canvas_addcanvas(parent, &s_, 0, 1, (size>1 ? size-1 : size), -1, 0, 0, 0, 0); - graph_array(gl, sharptodollar(name), &s_float, size, flags); -} - -void garray_arrayviewlist_close(t_garray *x) { - x->listviewing = 0; - sys_vgui("pdtk_array_listview_closeWindow %s\n", x->realname->name); -} - -/* this is called from the properties dialog window for an existing array */ -void garray_arraydialog(t_garray *x, t_symbol *name, t_floatarg fsize, t_floatarg fflags, t_floatarg deleteit) { - int flags = (int)fflags; - int saveit = (flags&1)!=0; - int style = (flags>>1)&3; - float stylewas = template_getfloat(template_findbyname(x->scalar->t), gensym("style"), x->scalar->v, 1); - if (deleteit) {canvas_delete(x->canvas,x); return;} - t_symbol *argname = sharptodollar(name); - t_array *a = garray_getarray(x); - t_template *scalartemplate; - if (!a) {error("can't find array"); return;} - if (!(scalartemplate = template_findbyname(x->scalar->t))) {error("no template of type %s", x->scalar->t->name); return;} - if (argname != x->realname) { - if (x->listviewing) garray_arrayviewlist_close(x); - x->realname = argname; /* is this line supposed to exist? */ - pd_unbind(x,x->realname); - x->realname = canvas_realizedollar(x->canvas, argname); - pd_bind(x,x->realname); - gobj_changed(x,0); - } - int size = max(1,int(fsize)); - if (size != a->n) garray_resize(x, size); else if (style != stylewas) garray_fittograph(x, size, style); - template_setfloat(scalartemplate, gensym("style"), x->scalar->v, (float)style, 0); - garray_setsaveit(x, saveit!=0); - garray_redraw(x); -} - -void garray_arrayviewlist_new(t_garray *x) { - char *s = x->realname->name; - int yonset=0, elemsize=0; - char cmdbuf[200]; - t_array *a = garray_getarray_floatonly(x, &yonset, &elemsize); - if (!a) {error("garray_arrayviewlist_new()"); return;} - x->listviewing = 1; - sprintf(cmdbuf, "pdtk_array_listview_new %%s %s %d\n",s,0); - for (int i=0; i < ARRAYPAGESIZE && i < a->n; i++) { - float yval = *(float *)(a->vec + elemsize*i + yonset); - sys_vgui(".%sArrayWindow.lb insert %d {%d) %g}\n",s,i,i,yval); - } -} - -void garray_arrayviewlist_fillpage(t_garray *x, t_float page, t_float fTopItem) { - char *s = x->realname->name; - int yonset=0, elemsize=0, topItem=(int)fTopItem; - t_array *a = garray_getarray_floatonly(x, &yonset, &elemsize); - if (!a) {error("garray_arrayviewlist_fillpage()"); return;} - if (page<0) { - page = 0; - } else if ((page * ARRAYPAGESIZE) >= a->n) { - page = int(((int)a->n - 1)/ (int)ARRAYPAGESIZE); - } - sys_vgui("pdtk_array_listview_setpage %s %d\n",s,(int)page); - sys_vgui(".%sArrayWindow.lb delete 0 %d\n",s,ARRAYPAGESIZE-1); - for (int i = (int)page * ARRAYPAGESIZE; (i < (page+1)*ARRAYPAGESIZE && i < a->n); i++) { - float yval = *(float *)(a->vec + elemsize*i + yonset); - sys_vgui(".%sArrayWindow.lb insert %d {%d) %g}\n",s,i%ARRAYPAGESIZE,i,yval); - } - sys_vgui(".%sArrayWindow.lb yview %d\n",s,topItem); -} - -static void garray_free(t_garray *x) { - if (x->listviewing) garray_arrayviewlist_close(x); - pd_unbind(x,x->realname); - /* LATER find a way to get #A unbound earlier (at end of load?) */ - t_pd *x2; - while ((x2 = pd_findbyclass(gensym("#A"), garray_class))) pd_unbind(x2, gensym("#A")); -} - -/* ------------- code used by both array and plot widget functions ---- */ - -static void array_redraw(t_array *a, t_canvas *canvas) { - /* what was that for? */ - scalar_redraw(a->gp.scalar, canvas); -} - -static int canvas_xtopixels(t_canvas *x, float xval); -static int canvas_ytopixels(t_canvas *x, float yval); - -/* routine to get screen coordinates of a point in an array */ -static void array_getcoordinate(t_canvas *canvas, char *elem, int xonset, int yonset, int wonset, int indx, -float basex, float basey, float xinc, t_slot *xslot, t_slot *yslot, t_slot *wslot, -float *xp, float *yp, float *wp) { - float xval, yval, ypix, wpix; - if (xonset >= 0) xval = *(float *)(elem + xonset); else xval = indx * xinc; - if (yonset >= 0) yval = *(float *)(elem + yonset); else yval = 0; - ypix = canvas_ytopixels(canvas, basey + slot_cvttocoord(yslot, yval)); - if (wonset >= 0) { - /* found "w" field which controls linewidth. */ - float wval = *(float *)(elem + wonset); - wpix = canvas_ytopixels(canvas, basey + slot_cvttocoord(yslot,yval) + slot_cvttocoord(wslot,wval)) - ypix; - if (wpix < 0) wpix = -wpix; - } else wpix = 1; - *xp = canvas_xtopixels(canvas, basex + slot_cvttocoord(xslot, xval)); - *yp = ypix; - *wp = wpix; -} - -static struct { - float xcumulative, ycumulative; - t_slot *xfield, *yfield; - t_canvas *canvas; - t_scalar *scalar; - t_array *array; - t_word *wp; - t_template *t; - int npoints, elemsize; - float initx, xperpix, yperpix; - int lastx, fatten; -} ammo; - -/* LATER protect against the template changing or the scalar disappearing - probably by attaching a gpointer here ... */ -#if 0 -static void array_motion(void *z, t_floatarg dx, t_floatarg dy) { - ammo.xcumulative += dx * ammo.xperpix; - ammo.ycumulative += dy * ammo.yperpix; - if (ammo.xfield) {// xy plot - for (int i=0; i ammo.lastx ? -1 : 1; - nchange = 1 + increment * (ammo.lastx - thisx); - x2 = thisx; - for (int i=0; i 1) newy -= ydiff/(nchange-1); - } - ammo.lastx = thisx; - } - if (ammo.scalar) scalar_redraw(ammo.scalar, ammo.canvas); - if (ammo.array) array_redraw(ammo.array, ammo.canvas); -} -#endif - -int scalar_doclick(t_word *data, t_template *t, t_scalar *sc, t_array *ap, t_canvas *owner, float xloc, float yloc, -int xpix, int ypix, int shift, int alt, int dbl, int doit); - -static int array_getfields(t_symbol *elemtsym, t_canvas **elemtemplatecanvasp, -t_template **elemtemplatep, int *elemsizep, t_slot *xslot, t_slot *yslot, t_slot *wslot, -int *xonsetp, int *yonsetp, int *wonsetp); - -/* try clicking on an element of the array as a scalar (if clicking on the trace of the array failed) */ -static int array_doclick_element(t_array *array, t_canvas *canvas, t_scalar *sc, t_array *ap, -t_symbol *elemtsym, float linewidth, float xloc, float xinc, float yloc, -t_slot *xfield, t_slot *yfield, t_slot *wfield, int xpix, int ypix, int shift, int alt, int dbl, int doit) { - t_canvas *elemtemplatecanvas; - t_template *elemtemplate; - int elemsize, yonset, wonset, xonset, incr; - //float xsum=0; - if (elemtsym == &s_float) return 0; - if (array_getfields(elemtsym,&elemtemplatecanvas,&elemtemplate,&elemsize,xfield,yfield,wfield,&xonset,&yonset,&wonset)) return 0; - /* if it has more than 2000 points, just check 300 of them. */ - if (array->n < 2000) incr=1; else incr = array->n/300; - for (int i=0; i < array->n; i += incr) { - //float usexloc = xonset>=0 ? xloc + slot_cvttocoord(xfield, *(float *)&array->vec[elemsize*i+xonset]) : xloc + xsum; - //if (xonset>=0) xsum += xinc; - //float useyloc = yloc + (yonset>=0 ? slot_cvttocoord(yfield, *(float *)&array->vec[elemsize*i+yonset]):0); - int hit = 0; - /* hit = scalar_doclick((t_word *)&array->vec[elemsize*i], - elemtemplate, 0, array, canvas, usexloc, useyloc, xpix, ypix, shift, alt, dbl, doit);*/ - if (hit) return hit; - } - return 0; -} - -static float canvas_pixelstox(t_canvas *x, float xpix); -static float canvas_pixelstoy(t_canvas *x, float xpix); - -/* convert an X screen distance to an X coordinate increment. */ -static float canvas_dpixtodx(t_canvas*x,float dxpix){return dxpix*(canvas_pixelstox(x,1)-canvas_pixelstox(x,0));} -static float canvas_dpixtody(t_canvas*x,float dypix){return dypix*(canvas_pixelstoy(x,1)-canvas_pixelstoy(x,0));} - -/* LATER move this and others back into plot parentwidget code, so they can be static (look in g_canvas.h for candidates). */ -int array_doclick(t_array *array, t_canvas *canvas, t_scalar *sc, t_array *ap, -t_symbol *elemtsym, float linewidth, float xloc, float xinc, float yloc, float scalarvis, -t_slot *xfield, t_slot *yfield, t_slot *wfield, int xpix, int ypix, int shift, int alt, int dbl, int doit) { - t_canvas *elemtemplatecanvas; - t_template *elemtemplate; - int elemsize, yonset, wonset, xonset; - if (!array_getfields(elemtsym, &elemtemplatecanvas, &elemtemplate, &elemsize, - xfield, yfield, wfield, &xonset, &yonset, &wonset)) { - float best = 100; - /* if it has more than 2000 points, just check 1000 of them. */ - int incr = (array->n <= 2000 ? 1 : array->n / 1000); - for (int i=0; i < array->n; i += incr) { - float pxpix, pypix, pwpix, dx, dy; - array_getcoordinate(canvas, &array->vec[elemsize*i], xonset, yonset, wonset, i, - xloc, yloc, xinc, xfield, yfield, wfield, &pxpix, &pypix, &pwpix); - if (pwpix < 4) pwpix = 4; - dx = fabs(pxpix-xpix); if (dx>8) continue; - dy = fabs(pypix-ypix); if (dx+dy= 0) { - dy = fabs(pypix+pwpix-ypix); if (dx+dy < best) best = dx+dy; - dy = fabs(pypix-pwpix-ypix); if (dx+dy < best) best = dx+dy; - } - } if (best > 8) { - if (scalarvis != 0) return array_doclick_element(array, canvas, sc, ap, elemtsym, - linewidth, xloc, xinc, yloc, xfield, yfield, wfield, xpix, ypix, shift, alt, dbl, doit); - return 0; - } - best += 0.001; /* add truncation error margin */ - for (int i=0; i < array->n; i += incr) { - float pxpix, pypix, pwpix, dx, dy, dy2, dy3; - array_getcoordinate(canvas, &array->vec[elemsize*i], xonset, yonset, wonset, i, - xloc, yloc, xinc, xfield, yfield, wfield, &pxpix, &pypix, &pwpix); - if (pwpix < 4) pwpix = 4; - dx = fabs(pxpix-xpix); - dy = fabs(pypix-ypix); - if (wonset >= 0) { - dy2 = fabs(pypix+pwpix-ypix); - dy3 = fabs(pypix-pwpix-ypix); - if (yonset < 0) dy = 100; - } else dy2 = dy3 = 100; - if (dx + dy <= best || dx + dy2 <= best || dx + dy3 <= best) { - if (dyvec; - ammo.elemsize = elemsize; - ammo.canvas = canvas; - ammo.scalar = sc; - ammo.array = ap; - ammo.t = elemtemplate; - ammo.xperpix = canvas_dpixtodx(canvas, 1); - ammo.yperpix = canvas_dpixtody(canvas, 1); - if (alt && xpix < pxpix) { /* delete a point */ - if (array->n <= 1) return 0; - memmove(&array->vec[elemsize*i], &array->vec[elemsize*(i+1)], (array->n-1-i) * elemsize); - array_resize_and_redraw(array, array->n - 1); - return 0; - } else if (alt) { - /* add a point (after the clicked-on one) */ - array_resize_and_redraw(array, array->n + 1); - elem = array->vec; - memmove(elem + elemsize * (i+1), elem + elemsize*i, (array->n-i-1) * elemsize); - i++; - } - if (xonset >= 0) { - ammo.xfield = xfield; - ammo.xcumulative = slot_getcoord(xfield,ammo.t,(t_word *)(elem+elemsize*i),1); - ammo.wp = (t_word *)(elem + elemsize*i); - if (shift) ammo.npoints = array->n - i; - else ammo.npoints = 1; - } else { - ammo.xfield = 0; - ammo.xcumulative = 0; - ammo.wp = (t_word *)elem; - ammo.npoints = array->n; - ammo.initx = i; - ammo.lastx = i; - ammo.xperpix *= (xinc == 0 ? 1 : 1./xinc); - } - if (ammo.fatten) { - ammo.yfield = wfield; - ammo.ycumulative = slot_getcoord(wfield,ammo.t,(t_word *)(elem+elemsize*i),1); - ammo.yperpix *= -ammo.fatten; - } else if (yonset >= 0) { - ammo.yfield = yfield; - ammo.ycumulative = slot_getcoord(yfield,ammo.t,(t_word *)(elem+elemsize*i),1); - } else { - ammo.yfield = 0; - ammo.ycumulative = 0; - } - /* canvas_grab(canvas, 0, array_motion, 0, xpix, ypix); */ - } - return 0; - } - } - } - return 0; -} - -static void garray_save(t_gobj *z, t_binbuf *b) { - t_garray *x = (t_garray *)z; - t_array *array = garray_getarray(x); - /* LATER "save" the scalar as such */ - if (x->scalar->t != gensym("pd-_float_array")) {error("can't save arrays of type %s yet", x->scalar->t->name); return;} - t_template *scalartemplate = template_findbyname(x->scalar->t); - if (!scalartemplate) {error("no template of type %s", x->scalar->t->name); return;} - int style = (int)template_getfloat(scalartemplate, gensym("style"), x->scalar->v, 0); - int filestyle = (style == PLOTSTYLE_POINTS ? 1 : (style == PLOTSTYLE_POLY ? 0 : style)); - binbuf_addv(b, "ttsisi;","#X","array", x->realname, array->n, &s_float, x->saveit+2*filestyle+8*x->hidename); - if (x->saveit) { - int n = array->n, n2 = 0; - while (n2 < n) { - int chunk = imin(n-n2,1000); - binbuf_addv(b,"ti","#A",n2); - for (int i=0; ivec)[n2+i]); - binbuf_addv(b, ";"); - n2 += chunk; - } - } -} - -/* required by d_array.c and d_soundfile */ -void garray_redraw(t_garray *x) {gobj_changed(x,0);} - -/* those three required by d_array.c */ -void garray_usedindsp(t_garray *x) {x->usedindsp = 1;} -int garray_npoints(t_garray *x) {return garray_getarray(x)->n;} /* get the length */ -char *garray_vec(t_garray *x) {return (char *)garray_getarray(x)->vec;} /* get the contents */ - -/* routine that checks if we're just an array of floats and if so returns the goods */ -int garray_getfloatarray(t_garray *x, int *size, t_float **vec) { - int yonset, elemsize; t_array *a = garray_getarray_floatonly(x, &yonset, &elemsize); - TEMPLATE_FLOATY(a,0) - if (elemsize != sizeof(t_word)) {error("%s: has more than one field", x->realname->name); return 0;} - *size = garray_npoints(x); - *vec = (float *)garray_vec(x); - return 1; -} - -/* set the "saveit" flag */ -void garray_setsaveit(t_garray *x, int saveit) { - if (x->saveit && !saveit) post("warning: array %s: clearing save-in-patch flag", x->realname->name); - x->saveit = saveit; -} - -static void garray_const(t_garray *x, t_floatarg g) { - int yonset, elemsize; t_array *array = garray_getarray_floatonly(x, &yonset, &elemsize); - TEMPLATE_FLOATY(array,) - for (int i=0; in; i++) *((float *)(array->vec + elemsize*i) + yonset) = g; - garray_redraw(x); -} - -/* sum of Fourier components; called from functions below */ -static void garray_dofo(t_garray *x, int npoints, float dcval, int nsin, t_float *vsin, int sineflag) { - int yonset, elemsize; t_array *array = garray_getarray_floatonly(x, &yonset, &elemsize); - TEMPLATE_FLOATY(array,) - if (npoints == 0) npoints = 512; /* dunno what a good default would be... */ - if (npoints != (1<tsym->name, npoints); - } - garray_resize(x, npoints + 3); - double phaseincr = 2. * 3.14159 / npoints; - double phase = -phaseincr; - for (int i=0; in; i++, phase += phaseincr) { - double fj; - double sum = dcval; - int j; - if (sineflag) for (j=0, fj=phase; jvec + elemsize*i) + yonset) = sum; - } - garray_redraw(x); -} - -static void garray_sinesum(t_garray *x, t_symbol *s, int argc, t_atom *argv) { - if (argc < 2) {error("%s: need number of points and partial strengths", x->realname->name); return;} - t_float *svec = (t_float *)getbytes(sizeof(t_float) * argc); - int npoints = atom_getintarg(0,argc--,argv++); - argv++, argc--; /* is it normal that this happens a second time? */ - for (int i=0; i < argc; i++) svec[i] = atom_getfloatarg(i, argc, argv); - garray_dofo(x, npoints, 0, argc, svec, 1); - free(svec); -} -static void garray_cosinesum(t_garray *x, t_symbol *s, int argc, t_atom *argv) { - if (argc < 2) {error("%s: need number of points and partial strengths", x->realname->name); return;} - t_float *svec = (t_float *)getbytes(sizeof(t_float) * argc); - int npoints = atom_getintarg(0,argc--,argv++); - for (int i=0; i < argc; i++) svec[i] = atom_getfloatarg(i, argc, argv); - garray_dofo(x, npoints, 0, argc, svec, 0); - free(svec); -} - -static void garray_normalize(t_garray *x, t_float f) { - int yonset, elemsize; t_array *array = garray_getarray_floatonly(x, &yonset, &elemsize); - double maxv=0; - TEMPLATE_FLOATY(array,) - if (f <= 0) f = 1; - for (int i=0; i < array->n; i++) { - double v = *((float *)(array->vec + elemsize*i) + yonset); - if ( v > maxv) maxv = v; - if (-v > maxv) maxv = -v; - } - if (maxv > 0) { - double renormer = f/maxv; - for (int i=0; i < array->n; i++) *((float *)(array->vec + elemsize*i) + yonset) *= renormer; - } - garray_redraw(x); -} - -/* list: the first value is an index; subsequent values are put in the "y" slot of the array. */ -static void garray_list(t_garray *x, t_symbol *s, int argc, t_atom *argv) { - int yonset, elemsize; t_array *array = garray_getarray_floatonly(x, &yonset, &elemsize); - TEMPLATE_FLOATY(array,) - if (argc < 2) return; - int firstindex = atom_getintarg(0,argc--,argv++); - if (firstindex < 0) { /* drop negative x values */ - argc += firstindex; - argv -= firstindex; - firstindex = 0; - } - if (argc + firstindex > array->n) argc = array->n - firstindex; - for (int i=0; i < argc; i++) *((float *)(array->vec + elemsize * (i + firstindex)) + yonset) = atom_getfloat(argv + i); - garray_redraw(x); -} - -static void garray_bounds(t_garray *x, t_floatarg x1, t_floatarg y1, t_floatarg x2, t_floatarg y2) -{vmess(x->canvas, gensym("bounds"), "ffff", x1, y1, x2, y2);} -static void garray_xticks(t_garray *x, t_floatarg point, t_floatarg inc, t_floatarg f) -{vmess(x->canvas, gensym("xticks"), "fff", point, inc, f);} -static void garray_yticks(t_garray *x, t_floatarg point, t_floatarg inc, t_floatarg f) -{vmess(x->canvas, gensym("yticks"), "fff", point, inc, f);} -static void garray_xlabel(t_garray *x, t_symbol *s, int argc, t_atom *argv) {typedmess(x->canvas, s, argc, argv);} -static void garray_ylabel(t_garray *x, t_symbol *s, int argc, t_atom *argv) {typedmess(x->canvas, s, argc, argv);} - -static void garray_rename(t_garray *x, t_symbol *s) { - if (x->listviewing) garray_arrayviewlist_close(x); - pd_unbind(x,x->realname); - x->realname = s; - pd_bind(x,x->realname); - garray_redraw(x); -} - -static void garray_read(t_garray *x, t_symbol *filename) { - int yonset, elemsize; t_array *array = garray_getarray_floatonly(x, &yonset, &elemsize); - FILE *fd; - char *buf, *bufptr; - TEMPLATE_FLOATY(array,) - int nelem = array->n; - int filedesc = canvas_open2(canvas_getcanvas(x->canvas), filename->name, "", &buf, &bufptr, 0); - if (filedesc<0) {error("%s: can't open", filename->name); free(buf); return;} - if (!(fd = fdopen(filedesc, "r"))) {error("%s: can't open", filename->name); free(buf); return;} - int i; - for (i=0; i < nelem; i++) { - if (!fscanf(fd, "%f", (float *)(array->vec + elemsize*i) + yonset)) { - post("%s: read %d elements into table of size %d", filename->name, i, nelem); - break; - } - } - while (i < nelem) *((float *)(array->vec + elemsize*i) + yonset) = 0, i++; - fclose(fd); - garray_redraw(x); - free(buf); -} - -static void garray_write(t_garray *x, t_symbol *filename) { - int yonset, elemsize; t_array *array = garray_getarray_floatonly(x, &yonset, &elemsize); - TEMPLATE_FLOATY(array,) - char *buf = canvas_makefilename(canvas_getcanvas(x->canvas),filename->name,0,0); - sys_bashfilename(buf, buf); - FILE *fd = fopen(buf, "w"); - if (!fd) {error("can't create file '%s'", buf); free(buf); return;} - free(buf); - for (int i=0; i < array->n; i++) { - if (fprintf(fd, "%g\n", *(float *)(((array->vec + sizeof(t_word) * i)) + yonset)) < 1) { - post("%s: write error", filename->name); - break; - } - } - fclose(fd); -} - -/* d_soundfile.c uses this! */ -int garray_ambigendian () { - unsigned short s = 1; - unsigned char c = *(char *)(&s); - return c==0; -} - -/* d_soundfile.c uses this! */ -void garray_resize(t_garray *x, t_floatarg f) { - t_array *array = garray_getarray(x); - int n = f<1?1:(int)f; - garray_fittograph(x, n, (int)template_getfloat(template_findbyname(x->scalar->t), gensym("style"), x->scalar->v, 1)); - array_resize_and_redraw(array, n); - if (x->usedindsp) canvas_update_dsp(); -} - -static void garray_print(t_garray *x) { - t_array *array = garray_getarray(x); - post("garray %s: template %s, length %d", x->realname->name, array->tsym->name, array->n); -} - -static void g_array_setup() { - t_class *c = garray_class = class_new2("array",0,garray_free,sizeof(t_garray),CLASS_GOBJ,""); - class_addlist(garray_class, garray_list); - class_addmethod2(c, garray_const, "const", "F"); - class_addmethod2(c, garray_bounds, "bounds", "ffff"); - class_addmethod2(c, garray_xticks, "xticks", "fff"); - class_addmethod2(c, garray_xlabel, "xlabel", "*"); - class_addmethod2(c, garray_yticks, "yticks", "fff"); - class_addmethod2(c, garray_ylabel, "ylabel", "*"); - class_addmethod2(c, garray_rename, "rename", "s"); - class_addmethod2(c, garray_read, "read", "s"); - class_addmethod2(c, garray_write, "write", "s"); - class_addmethod2(c, garray_resize, "resize", "f"); - class_addmethod2(c, garray_print, "print", ""); - class_addmethod2(c, garray_sinesum, "sinesum", "*"); - class_addmethod2(c, garray_cosinesum, "cosinesum", "*"); - class_addmethod2(c, garray_normalize, "normalize", "F"); - class_addmethod2(c, garray_arraydialog, "arraydialog", "sfff"); - class_addmethod2(c, garray_arrayviewlist_new, "arrayviewlistnew", ""); - class_addmethod2(c, garray_arrayviewlist_fillpage, "arrayviewlistfillpage", "fF"); - class_addmethod2(c, garray_arrayviewlist_close, "arrayviewclose", ""); - class_setsavefn(c, garray_save); - array_class = class_new2("array_really",0,array_free,sizeof(t_array),CLASS_GOBJ,""); -} - -static void graph_graphrect(t_gobj *z, t_canvas *canvas, int *xp1, int *yp1, int *xp2, int *yp2); - -void canvas_add_debug(t_canvas *x, t_gobj *y) { - if (!y->_class->patchable) { - printf("canvas_add %p %p class=%s (non-t_text)\n",x,y,y->_class->name->name); - } else { - t_binbuf *bb = ((t_text *)y)->binbuf; - if (binbuf_getvec(bb)) { - char *buf; int bufn; - binbuf_gettext(bb,&buf,&bufn); - printf("canvas_add %p %p [%.*s]\n",x,y,bufn,buf); - free(buf); - } else { - printf("canvas_add %p %p class=%s (binbuf without b_vec !)\n",x,y,y->_class->name->name); - } - } -} - -void canvas_add(t_canvas *x, t_gobj *y, int index) { - //post("canvas_add index=%d next_o_index=%d",index,x->next_o_index); - gobj_setcanvas(y,x); - if (index<0) y->dix->index = x->next_o_index++; - else y->dix->index = index; - x->boxes->add(y); - if (x->gop && !x->goprect && pd_checkobject(y)) SET(goprect,1); - //if (class_isdrawcommand(y->_class)) canvas_redrawallfortemplate(template_findbyname(canvas_makebindsym(canvas_getcanvas(x)->name)), 0); -} - -/* delete an object from a canvas and free it */ -void canvas_delete(t_canvas *x, t_gobj *y) { - bool chkdsp = !!zgetfn(y,gensym("dsp")); - //int drawcommand = class_isdrawcommand(y->_class); - /* if we're a drawing command, erase all scalars now, before deleting it; we'll redraw them once it's deleted below. */ - //if (drawcommand) canvas_redrawallfortemplate(template_findbyname(canvas_makebindsym(canvas_getcanvas(x)->name)), 2); - canvas_deletelinesfor(x,(t_text *)y); - x->boxes->remove_by_value(y); - /* BUG: should call gobj_onsubscribe here, to flush the zombie */ - pd_free(y); - if (chkdsp) canvas_update_dsp(); - //if (drawcommand) canvas_redrawallfortemplate(template_findbyname(canvas_makebindsym(canvas_getcanvas(x)->name)), 1); -} - -static void canvas_clear(t_canvas *x) { - t_gobj *y; - int dspstate = 0, suspended = 0; - t_symbol *dspsym = gensym("dsp"); - /* to avoid unnecessary DSP resorting, we suspend DSP only if we find a DSP object. */ - canvas_each(y,x) if (!suspended && pd_checkobject(y) && zgetfn(y,dspsym)) {dspstate = canvas_suspend_dsp(); suspended=1;} - while ((y = x->boxes->first())) x->boxes->remove_by_value(y); - if (suspended) canvas_resume_dsp(dspstate); -} - - -t_canvas *canvas_getcanvas(t_canvas *x) { - while (x->dix->canvas && !x->havewindow && x->gop) x = x->dix->canvas; - return x; -} - -static void scalar_getbasexy(t_scalar *x, float *basex, float *basey); - -static float gobj_getxforsort(t_gobj *g) { - if (g->_class!=scalar_class) return 0; - float x1, y1; - scalar_getbasexy((t_scalar *)g, &x1, &y1); - return x1; -} - -// three-way comparison (T is assumed Comparable) -// template static inline T cmp(T a, T b) {return ab;} - -bool canvas_sort_lt(t_gobj * const &a, t_gobj * const &b) /* is a StrictWeakOrdering */ { - return gobj_getxforsort(a) < gobj_getxforsort(b); -} - -void canvas_sort(t_canvas *x) { - std::vector v; - canvas_each(y,x) v.push_back(y); - sort(v.begin(),v.end(),canvas_sort_lt); - x->boxes->map.clear(); - int i=0; - foreach(y,v) {(*y)->dix->index=i++; x->boxes->add(*y);} -} - -static t_inlet *canvas_addinlet(t_canvas *x, t_pd *who, t_symbol *s, t_symbol* h) { - t_inlet *ip = inlet_new(x,who,s,0); inlet_settip(ip,h); - if (gstack_empty()) canvas_resortinlets(x); - gobj_changed(x,0); return ip; -} -static t_outlet *canvas_addoutlet(t_canvas *x, t_pd *who, t_symbol *s) { - t_outlet *op = outlet_new(x,s); - if (gstack_empty()) canvas_resortoutlets(x); - gobj_changed(x,0); return op; -} - -static void canvas_rminlet(t_canvas *x, t_inlet *ip) { - if (x->dix->canvas) canvas_deletelinesforio(x->dix->canvas,x,ip,0); - inlet_free(ip); /*gobj_changed(x,0);*/ -} -static void canvas_rmoutlet(t_canvas *x, t_outlet *op) { - if (x->dix->canvas) canvas_deletelinesforio(x->dix->canvas,x,0,op); - outlet_free(op); /*gobj_changed(x,0);*/ -} - -extern "C" t_inlet *vinlet_getit(t_pd *x); -extern "C" t_outlet *voutlet_getit(t_pd *x); - -typedef int (*t_order)(const void *, const void *); -int gobj_order_x (t_object **a, t_object **b) {return (*a)->x - (*b)->x;} - -//{std::ostringstream s; s<<"disorder:"; for (int i=0; ix; post("%s",s.str().data());} - -void obj_moveinletfirst(t_object *x, t_inlet *i); -void obj_moveoutletfirst(t_object *x, t_outlet *o); - -static void canvas_resortinlets(t_canvas *x) { - int n=0; canvas_each(y,x) if (y->_class==vinlet_class) n++; - t_object **vec = new t_object *[n], **vp = vec; - canvas_each(y,x) if (y->_class==vinlet_class) *vp++ = (t_object *)y; - qsort(vec,n,sizeof(t_object *),(t_order)gobj_order_x); - for (int i=n; i--;) obj_moveinletfirst(x,vinlet_getit(vec[i])); - delete[] vec; -} -static void canvas_resortoutlets(t_canvas *x) { - int n=0; canvas_each(y,x) if (y->_class==voutlet_class) n++; - t_object **vec = new t_object *[n], **vp = vec; - canvas_each(y,x) if (y->_class==voutlet_class) *vp++ = (t_object *)y; - qsort(vec,n,sizeof(t_object *),(t_order)gobj_order_x); - for (int i=n; i--;) obj_moveoutletfirst(x,voutlet_getit(vec[i])); - delete[] vec; -} - -static void graph_bounds(t_canvas *x, t_floatarg x1, t_floatarg y1, t_floatarg x2, t_floatarg y2) { - x->x1 = x1; x->y1 = y1; - x->x2 = x2; x->y2 = y2; - if (x->x2 == x->x1 || x->y2 == x->y1) { - error("empty bounds rectangle"); - x->x1 = x->y1 = 0; - x->x2 = x->y2 = 1; - } - gobj_changed(x,0); -} - -static void graph_xticks(t_canvas *x, t_floatarg point, t_floatarg inc, t_floatarg f) -{t_tick *t = &x->xtick; t->point = point; t->inc = inc; t->lperb = (int)f; gobj_changed(x,"xticks");} -static void graph_yticks(t_canvas *x, t_floatarg point, t_floatarg inc, t_floatarg f) -{t_tick *t = &x->ytick; t->point = point; t->inc = inc; t->lperb = (int)f; gobj_changed(x,"yticks");} - -static void graph_xlabel(t_canvas *x, t_symbol *s, int argc, t_atom *argv) { - if (argc < 1) {error("graph_xlabel: no y value given"); return;} - x->xlabely = atom_getfloatarg(0,argc--,argv++); - x->xlabel = realloc2(x->xlabel,argc); - x->nxlabels = argc; - for (int i=0; i < argc; i++) x->xlabel[i] = atom_gensym(&argv[i]); - gobj_changed(x,"xlabel"); -} -static void graph_ylabel(t_canvas *x, t_symbol *s, int argc, t_atom *argv) { - if (argc < 1) {error("graph_ylabel: no x value given"); return;} - x->ylabelx = atom_getfloatarg(0,argc--,argv++); - x->ylabel = realloc2(x->ylabel,argc); - x->nylabels = argc; - for (int i=0; i < argc; i++) x->ylabel[i] = atom_gensym(&argv[i]); - gobj_changed(x,"ylabel"); -} - -/* if we appear as a text box on parent, our range in our coordinates (x1, etc.) - specifies the coordinate range of a one-pixel square at top left of the window. - if we're a graph when shown on parent, but own our own window right now, our range - in our coordinates (x1, etc.) is spread over the visible window size, given by screenx1, etc. - otherwise, we appear in a graph within a parent canvas, so get our screen rectangle on parent and transform. */ -static float canvas_pixelstox(t_canvas *x, float xpix) { - int x1, y1, x2, y2; float width = x->x2-x->x1; - if (!x->gop) return x->x1 + width * xpix; - if (x->havewindow) return x->x1 + width * xpix / (x->screenx2-x->screenx1); - graph_graphrect(x, x->dix->canvas, &x1, &y1, &x2, &y2); - return x->x1 + width * (xpix-x1) / (x2-x1); -} -static float canvas_pixelstoy(t_canvas *x, float ypix) { - int x1, y1, x2, y2; float height = x->y2-x->y1; - if (!x->gop) return x->y1 + height * ypix; - if (x->havewindow) return x->y1 + height * ypix / (x->screeny2-x->screeny1); - graph_graphrect(x, x->dix->canvas, &x1, &y1, &x2, &y2); - return x->y1 + height * (ypix-y1) / (y2-y1); -} - -/* convert an x coordinate value to an x pixel location in window */ -static int canvas_xtopixels(t_canvas *x, float xval) { - int x1, y1, x2, y2; float width = x->x2-x->x1; - if (!x->gop) return int((xval-x->x1)/width); - if (x->havewindow) return int((x->screenx2-x->screenx1) * (xval-x->x1) / width); - graph_graphrect(x, x->dix->canvas, &x1, &y1, &x2, &y2); - return int(x1 + (x2-x1) * (xval-x->x1) / width); -} -static int canvas_ytopixels(t_canvas *x, float yval) { - int x1, y1, x2, y2; float height = x->y2-x->y1; - if (!x->gop) return int((yval-x->y1)/height); - if (x->havewindow) return int((x->screeny2-x->screeny1) * (yval-x->y1) / height); - graph_graphrect(x, x->dix->canvas, &x1, &y1, &x2, &y2); - return int(y1 + (y2-y1) * (yval-x->y1) / height); -} - -/* --------------------------- widget behavior ------------------- */ -/* don't remove this code yet: has to be rewritten in tcl */ -#if 1 -#define FONT "pourier" -static void graph_vis(t_gobj *gr, int vis) { - t_canvas *x = (t_canvas *)gr; - t_canvas *c = canvas_getcanvas(x->dix->canvas); - char tag[50]; - int x1=69, y1=69, x2=69, y2=69; - sprintf(tag, "graph%lx", (t_int)x); - if (vis) { - sys_mgui(x,"ninlets=","i",0/*obj_ninlets(x)*/); - sys_mgui(x,"noutlets=","i",0/*obj_noutlets(x)*/); - } - /* if we look like a graph but have been moved to a toplevel, just show the bounding rectangle */ - if (x->havewindow) { - /*if (vis) sys_vgui(".x%lx.c create polygon %d %d %d %d %d %d %d %d %d %d -tags %s -fill #c0c0c0\n", - (long)c, x1, y1, x1, y2, x2, y2, x2, y1, x1, y1, tag);*/ - return; - } - /* draw a rectangle around the graph */ - sys_vgui(".x%lx.c create line %d %d %d %d %d %d %d %d %d %d -tags %s\n", - (long)c, x1, y1, x1, y2, x2, y2, x2, y1, x1, y1, tag); - /* if there's just one "garray" in the graph, write its name along the top */ - int i = min(y1,y2)-1; - t_symbol *arrayname; - canvas_each(g,x) if (g->g_pd == garray_class && !garray_getname((t_garray *)g, &arrayname)) { - // i -= sys_fontheight(glist_getfont(x)); - sys_vgui(".x%lx.c create text %d %d -text {%s} -anchor nw\ - -font -*-courier-bold--normal--%d-* -tags %s\n", - (long)canvas_getcanvas(x), x1, i, arrayname->name, - 42/*sys_hostfontsize(canvas_getfont(x))*/, tag); - } - - /* draw ticks on horizontal borders. If lperb field is zero, this is disabled. */ - #define DRAWTICK(x1,y1,x2,y2) sys_vgui(".x%lx.c create line %d %d %d %d -tags %s\n", \ - (long)c, int(x1),int(y1),int(x2),int(y2),tag) - float f; - if (x->xtick.lperb) { - float upix, lpix; - if (y2xtick.point; f<0.99*x->x2+0.01*x->x1; i++, f+=x->xtick.inc) { - int tickpix = i%x->xtick.lperb?2:4, x0 = canvas_xtopixels(x,f); - DRAWTICK(x0,upix,x0,upix-tickpix); - DRAWTICK(x0,lpix,x0,lpix+tickpix); - } - for (i=1,f=x->xtick.point-x->xtick.inc; f>0.99*x->x1+0.01*x->x2; i++,f-=x->xtick.inc) { - int tickpix = i%x->xtick.lperb?2:4, x0 = canvas_xtopixels(x,f); - DRAWTICK(x0,upix,x0,upix-tickpix); - DRAWTICK(x0,lpix,x0,lpix+tickpix); - } - } - /* draw ticks in vertical borders*/ - if (x->ytick.lperb) { - float ubound, lbound; - if (x->y2y1) {ubound = x->y1; lbound = x->y2;} - else {ubound = x->y2; lbound = x->y1;} - for (i=0,f=x->ytick.point; f<0.99*ubound+0.01*lbound; i++, f += x->ytick.inc) { - int tickpix = i%x->ytick.lperb?2:4, y0 = canvas_ytopixels(x,f); - DRAWTICK(x1,y0,x1+tickpix,y0); - DRAWTICK(x2,y0,x2-tickpix,y0); - } - for (i=1,f=x->ytick.point-x->ytick.inc; f>0.99*lbound+0.01*ubound; i++,f-=x->ytick.inc) { - int tickpix = i%x->ytick.lperb?2:4, y0 = canvas_ytopixels(x,f); - DRAWTICK(x1,y0,x1+tickpix,y0); - DRAWTICK(x2,y0,x2-tickpix,y0); - } - } - /* draw labels */ - #define DRAWLABEL(x1,y1) sys_vgui(".x%lx.c create text %d %d -text {%s} -font "FONT" -tags %s\n", (long)c, \ - int(canvas_xtopixels(x,x1)),int(canvas_ytopixels(x,y1)),s,42,tag); - for (int i=0; i < x->nxlabels; i++) {char *s = x->xlabel[i]->name; DRAWLABEL(atof(s),x->xlabely);} - for (int i=0; i < x->nylabels; i++) {char *s = x->ylabel[i]->name; DRAWLABEL(x->ylabelx,atof(s));} -} -#endif - -/* nonstatic (to fix a -lib load error) */ -extern "C" int text_xpix(t_text *x, t_canvas *canvas) { - float width = canvas->x2-canvas->x1; - if (canvas->havewindow || !canvas->gop) return x->x; - if (canvas->goprect) return canvas->x+x->x-canvas->xmargin; - return canvas_xtopixels(canvas, canvas->x1 + width * x->x / (canvas->screenx2-canvas->screenx1)); -} -extern "C" int text_ypix(t_text *x, t_canvas *canvas) { - float height = canvas->y2-canvas->y1; - if (canvas->havewindow || !canvas->gop) return x->y; - if (canvas->goprect) return canvas->y+x->y-canvas->ymargin; - return canvas_ytopixels(canvas, canvas->y1 + height* x->y / (canvas->screeny2-canvas->screeny1)); -} -static void graph_graphrect(t_gobj *z, t_canvas *canvas, int *xp1, int *yp1, int *xp2, int *yp2) { - t_canvas *x = (t_canvas *)z; - *xp1 = text_xpix(x,canvas); *xp2 = *xp1+x->pixwidth; - *yp1 = text_ypix(x,canvas); *yp2 = *yp1+x->pixheight; -} - -#if 1 -static float graph_lastxpix, graph_lastypix; -static void graph_motion(void *z, t_floatarg dx, t_floatarg dy) { - t_canvas *x = (t_canvas *)z; - float newxpix = graph_lastxpix + dx, newypix = graph_lastypix + dy; - t_garray *a = (t_garray *)x->boxes->first(); - int oldx = int(0.5 + canvas_pixelstox(x, graph_lastxpix)); - int newx = int(0.5 + canvas_pixelstox(x, newxpix)); - float oldy = canvas_pixelstoy(x, graph_lastypix); - float newy = canvas_pixelstoy(x, newypix); - graph_lastxpix = newxpix; - graph_lastypix = newypix; - // verify that the array is OK - if (!a || a->_class != garray_class) return; - int nelem; - t_float *vec; - if (!garray_getfloatarray(a, &nelem, &vec)) return; - if (oldx < 0) oldx = 0; else if (oldx >= nelem) oldx = nelem - 1; - if (newx < 0) newx = 0; else if (newx >= nelem) newx = nelem - 1; - if (oldx < newx - 1) {for (int i=oldx+1; i<=newx; i++) vec[i] = newy + (oldy-newy) * float(newx-i)/float(newx - oldx);} - else if (oldx > newx + 1) {for (int i=oldx-1; i>=newx; i--) vec[i] = newy + (oldy-newy) * float(newx-i)/float(newx - oldx);} - else vec[newx] = newy; - garray_redraw(a); -} -#endif - -/* functions to read and write canvases to files: canvas_savetofile() writes a root canvas to a "pd" file. - (Reading "pd" files is done simply by passing the contents to the pd message interpreter.) - Alternatively, the glist_read() and glist_write() functions read and write "data" from and to files - (reading reads into an existing canvas), using a file format as in the dialog window for data. */ -static t_class *declare_class; -void canvas_savedeclarationsto(t_canvas *x, t_binbuf *b); - -/* the following functions read "scalars" from a file into a canvas. */ -static int canvas_scanbinbuf(int natoms, t_atom *vec, int *p_indexout, int *p_next) { - int i; - int indexwas = *p_next; - *p_indexout = indexwas; - if (indexwas >= natoms) return 0; - for (i = indexwas; i < natoms && vec[i].a_type != A_SEMI; i++) {} - if (i >= natoms) *p_next = i; else *p_next = i+1; - return i-indexwas; -} -static int canvas_readscalar(t_canvas *x, int natoms, t_atom *vec, int *p_nextmsg, int selectit); -static void canvas_readerror(int natoms, t_atom *vec, int message, int nline, const char *s) { - error("%s",s); - startpost("line was:"); - postatom(nline, vec + message); - endpost(); -} - -/* fill in the contents of the scalar into the vector w. */ -static void canvas_readatoms(t_canvas *x, int natoms, t_atom *vec, int *p_nextmsg, t_symbol *tsym, t_word *w, int argc, t_atom *argv) { - t_template *t = template_findbyname(tsym); - if (!t) {error("%s: no such template", tsym->name); *p_nextmsg = natoms; return;} - word_restore(w, t, argc, argv); - int n = t->n; - for (int i=0; ivec[i].type == DT_ARRAY) { - t_array *a = w[i].w_array; - int elemsize = a->elemsize, nitems = 0; - t_symbol *arraytsym = t->vec[i].arraytemplate; - t_template *arraytemplate = template_findbyname(arraytsym); - if (!arraytemplate) error("%s: no such template", arraytsym->name); - else while (1) { - int message; - t_word *element; - int nline = canvas_scanbinbuf(natoms, vec, &message, p_nextmsg); - /* empty line terminates array */ - if (!nline) break; - array_resize(a, nitems + 1); - element = (t_word *)&a->vec[nitems*elemsize]; - canvas_readatoms(x, natoms, vec, p_nextmsg, arraytsym, element, nline, vec + message); - nitems++; - } - } else if (t->vec[i].type == DT_CANVAS) { - while (1) { - if (!canvas_readscalar(w->w_canvas, natoms, vec, p_nextmsg, 0)) break; - } - } - } -} - -static int canvas_readscalar(t_canvas *x, int natoms, t_atom *vec, int *p_nextmsg, int selectit) { - int nextmsg = *p_nextmsg; - //int wasvis = canvas_isvisible(x); - if (nextmsg >= natoms || vec[nextmsg].a_type != A_SYMBOL) { - if (nextmsg < natoms) post("stopping early: type %d", vec[nextmsg].a_type); - *p_nextmsg = natoms; return 0; - } - t_symbol *ts = canvas_makebindsym(vec[nextmsg].a_symbol); - *p_nextmsg = nextmsg + 1; - t_template *t = template_findbyname(ts); - if (!t) {error("%s: no such template", ts->name); *p_nextmsg = natoms; return 0;} - t_scalar *sc = scalar_new(x, ts); - if (!sc) {error("couldn't create scalar \"%s\"", ts->name); *p_nextmsg = natoms; return 0;} - //if (wasvis) canvas_getcanvas(x)->mapped = 0; - canvas_add(x,sc); - int message; - int nline = canvas_scanbinbuf(natoms, vec, &message, p_nextmsg); - canvas_readatoms(x, natoms, vec, p_nextmsg, ts, sc->v, nline, vec + message); - //if (wasvis) canvas_getcanvas(x)->mapped = 1; - gobj_changed(sc,0);//is this necessary? - return 1; -} - -static void canvas_readfrombinbuf(t_canvas *x, t_binbuf *b, const char *filename, int selectem) { - int message, nextmsg = 0; - int natoms = binbuf_getnatom(b); - t_atom *vec = binbuf_getvec(b); - /* check for file type */ - int nline = canvas_scanbinbuf(natoms, vec, &message, &nextmsg); - if (nline!=1 && vec[message].a_type != A_SYMBOL && strcmp(vec[message].a_symbol->name, "data")) { - error("%s: file apparently of wrong type", filename); - binbuf_free(b); - return; - } - /* read in templates and check for consistency */ - while (1) { - t_template *newt, *existt; - t_atom *targs = (t_atom *)getbytes(0); - int ntargs = 0; - nline = canvas_scanbinbuf(natoms, vec, &message, &nextmsg); - if (nline < 2) break; - else if (nline > 2) canvas_readerror(natoms, vec, message, nline, "extra items ignored"); - else if (vec[message].a_type != A_SYMBOL || strcmp(vec[message].a_symbol->name, "template") || - vec[message+1].a_type != A_SYMBOL) { - canvas_readerror(natoms, vec, message, nline, "bad template header"); - continue; - } - t_symbol *tsym = canvas_makebindsym(vec[message + 1].a_symbol); - while (1) { - nline = canvas_scanbinbuf(natoms, vec, &message, &nextmsg); - if (nline!=2 && nline!=3) break; - int newnargs = ntargs + nline; - targs = realloc2(targs,newnargs); - targs[ntargs] = vec[message]; - targs[ntargs+1] = vec[message+1]; - if (nline==3) targs[ntargs+2] = vec[message+2]; - ntargs = newnargs; - } - newt = template_new(tsym, ntargs, targs); - free(targs); - existt = template_findbyname(tsym); - if (!existt) {error("%s: template not found in current patch", tsym->name); template_free(newt); return;} - if (!template_match(existt, newt)) { - error("%s: template doesn't match current one", tsym->name); - template_free(newt); - return; - } - template_free(newt); - } - while (nextmsg < natoms) canvas_readscalar(x, natoms, vec, &nextmsg, selectem); -} - -static void canvas_doread(t_canvas *x, t_symbol *filename, t_symbol *format, int clearme) { - t_binbuf *b = binbuf_new(); - t_canvas *canvas = canvas_getcanvas(x); - int wasvis = canvas_isvisible(canvas); - int cr = strcmp(format->name, "cr")==0; - if (!cr && *format->name) error("unknown flag: %s", format->name); - /* flag 2 means eval continuously. this is required to autodetect the syntax */ - if (binbuf_read_via_path(b, filename->name, canvas_getdir(canvas)->name, cr|2)) { - error("read failed"); - binbuf_free(b); - return; - } - if (wasvis) canvas_vis(canvas, 0); - if (clearme) canvas_clear(x); - /* canvas_readfrombinbuf(x, b, filename->name, 0); */ /* what's this for? */ - if (wasvis) canvas_vis(canvas, 1); - binbuf_free(b); -} - -static void canvas_read( t_canvas *x, t_symbol *filename, t_symbol *format) {canvas_doread(x,filename,format,1);} -static void canvas_mergefile(t_canvas *x, t_symbol *filename, t_symbol *format) {canvas_doread(x,filename,format,0);} - -/* read text from a "properties" window, in answer to scalar_properties(). - We try to restore the object; if successful - we delete the scalar and put the new thing in its place on the list. */ -void canvas_dataproperties(t_canvas *x, t_scalar *sc, t_binbuf *b) { -// t_gobj *oldone = 0; -// t_gobj *newone = 0; - x->boxes->remove_by_value(sc); -// if (!newone) {error("couldn't update properties (perhaps a format problem?)"); return;} -// if (!oldone) {bug("data_properties: couldn't find old element"); return;} - canvas_readfrombinbuf(x, b, "properties dialog", 0); -} - -static void canvas_doaddtemplate(t_symbol *tsym, int *p_ntemplates, t_symbol ***p_templatevec) { - int n = *p_ntemplates; - t_symbol **templatevec = *p_templatevec; - for (int i=0; i < n; i++) if (templatevec[i] == tsym) return; - templatevec = realloc2(templatevec,n+1); - templatevec[n] = tsym; - *p_templatevec = templatevec; - *p_ntemplates = n+1; -} - -static void canvas_writelist(t_gobj *y, t_binbuf *b); - -static void canvas_writescalar(t_symbol *tsym, t_word *w, t_binbuf *b, int amarrayelement) { - t_template *t = template_findbyname(tsym); - t_atom *a = (t_atom *)getbytes(0); - int n = t->n; - if (!amarrayelement) { - t_atom templatename; - SETSYMBOL(&templatename, gensym(tsym->name + 3)); - binbuf_add(b, 1, &templatename); - } - if (!t) bug("canvas_writescalar"); - /* write the atoms (floats and symbols) */ - int natom = 0; - for (int i=0; ivec[i].type; - if (ty==DT_FLOAT || ty==DT_SYMBOL) { - a = realloc2(a,natom+1); - if (t->vec[i].type == DT_FLOAT) SETFLOAT( a + natom, w[i].w_float); - else SETSYMBOL(a + natom, w[i].w_symbol); - natom++; - } - } - /* array elements have to have at least something */ - if (natom == 0 && amarrayelement) {SETSYMBOL(a + natom, &s_bang); natom++;} - binbuf_add(b, natom, a); - binbuf_addsemi(b); - free(a); - for (int i=0; ivec[i].type == DT_ARRAY) { - t_array *a = w[i].w_array; - int elemsize = a->elemsize, nitems = a->n; - t_symbol *arraytsym = t->vec[i].arraytemplate; - for (int j = 0; j < nitems; j++) canvas_writescalar(arraytsym, (t_word *)&a->vec[elemsize*j], b, 1); - binbuf_addsemi(b); - } else if (t->vec[i].type == DT_CANVAS) { - canvas_writelist(w->w_canvas->boxes->first(), b); - binbuf_addsemi(b); - } - } -} - -static void canvas_writelist(t_gobj *y, t_binbuf *b) { - for (; y; y = y->next()) if (y->_class==scalar_class) { - t_scalar *z = (t_scalar *)y; - canvas_writescalar(z->t, z->v, b, 0); - } -} - -static void canvas_addtemplatesforlist(t_gobj *y, int *p_ntemplates, t_symbol ***p_templatevec); - -static void canvas_addtemplatesforscalar(t_symbol *tsym, t_word *w, int *p_ntemplates, t_symbol ***p_templatevec) { - t_template *t = template_findbyname(tsym); - canvas_doaddtemplate(tsym, p_ntemplates, p_templatevec); - if (!t) {bug("canvas_addtemplatesforscalar"); return;} - t_dataslot *ds = t->vec; - for (int i=t->n; i--; ds++, w++) { - if (ds->type == DT_ARRAY) { - t_array *a = w->w_array; - int elemsize = a->elemsize, nitems = a->n; - t_symbol *arraytsym = ds->arraytemplate; - canvas_doaddtemplate(arraytsym, p_ntemplates, p_templatevec); - for (int j=0; jvec[elemsize*j], p_ntemplates, p_templatevec); - } else if (ds->type == DT_CANVAS) - canvas_addtemplatesforlist(w->w_canvas->boxes->first(), p_ntemplates, p_templatevec); - } -} - -static void canvas_addtemplatesforlist(t_gobj *y, int *p_ntemplates, t_symbol ***p_templatevec) { - for (; y; y = y->next()) if (y->_class == scalar_class) { - t_scalar *z = (t_scalar *)y; - canvas_addtemplatesforscalar(z->t, z->v, p_ntemplates, p_templatevec); - } -} - -static t_binbuf *canvas_writetobinbuf(t_canvas *x) { - t_symbol **templatevec = (t_symbol **)getbytes(0); - int ntemplates = 0; - t_binbuf *b = binbuf_new(); - canvas_each(y,x) if (y->_class==scalar_class) { - t_scalar *s = (t_scalar *)y; - canvas_addtemplatesforscalar(s->t, s->v, &ntemplates, &templatevec); - } - binbuf_addv(b,"t;","data"); - for (int i=0; in; - /* drop "pd-" prefix from template symbol to print it: */ - binbuf_addv(b,"tt;","template",templatevec[i]->name + 3); - for (int j=0; jvec[j].type) { - case DT_FLOAT: type = &s_float; break; - case DT_SYMBOL: type = &s_symbol; break; - case DT_ARRAY: type = gensym("array"); break; - case DT_CANVAS: type = &s_list; break; - default: type = &s_float; bug("canvas_write"); - } - if (t->vec[j].type == DT_ARRAY) - binbuf_addv(b,"sst;", type, t->vec[j].name, t->vec[j].arraytemplate->name + 3); - else binbuf_addv(b,"ss;", type, t->vec[j].name); - } - binbuf_addsemi(b); - } - binbuf_addsemi(b); - /* now write out the objects themselves */ - canvas_each(y,x) if (y->_class==scalar_class) { - t_scalar *z = (t_scalar *)y; - canvas_writescalar(z->t, z->v, b, 0); - } - return b; -} - -static void canvas_write(t_canvas *x, t_symbol *filename, t_symbol *format) { - t_canvas *canvas = canvas_getcanvas(x); - char *buf = canvas_makefilename(canvas,filename->name,0,0); - int cr = strcmp(format->name, "cr")==0; - if (!cr && *format->name) error("canvas_write: unknown flag: %s", format->name); - t_binbuf *b = canvas_writetobinbuf(x); - if (b) { - if (binbuf_write(b, buf, "", cr)) error("%s: write failed", filename->name); - binbuf_free(b); - } - free(buf); -} - -/* ------ functions to save and restore canvases (patches) recursively. ----*/ - -/* save to a binbuf, called recursively; cf. canvas_savetofile() which saves the document, and is only called on root canvases. */ -void canvas_savecontainerto(t_canvas *x, t_binbuf *b) { - /* have to go to original binbuf to find out how we were named. */ - t_binbuf *bz = binbuf_new(); - t_symbol *patchsym = &s_; - if (x->binbuf) { - binbuf_addbinbuf(bz, x->binbuf); - patchsym = atom_getsymbolarg(1, binbuf_getnatom(bz), binbuf_getvec(bz)); - binbuf_free(bz); - } - int x1=x->screenx1, xs=x->screenx2-x1; - int y1=x->screeny1, ys=x->screeny2-y1; - binbuf_addv(b,"ttiiii","#N","canvas",x1,y1,xs,ys); - if (x->dix->canvas && !x->env) { /* subpatch */ - binbuf_addv(b, "si;", (patchsym != &s_ ? patchsym: gensym("(subpatch)")), x->havewindow); - } else { /* root or abstraction */ - binbuf_addv(b, "i;", (int)x->font); - canvas_savedeclarationsto(x, b); - } -} - -static void canvas_savecoordsto(t_canvas *x, t_binbuf *b) { - /* if everything is the default, skip saving this line */ - if (!x->gop && x->x1==0 && x->y1==0 && x->x2==1 && x->y2==1 && x->pixwidth==0 && x->pixheight==0) return; - /* if we have a graph-on-parent rectangle, we're new style. The format is arranged so - that old versions of Pd can at least do something with it. - otherwise write in 0.38-compatible form. */ - binbuf_addv(b,"ttffffffi","#X","coords", x->x1,x->y1,x->x2,x->y2, (float)x->pixwidth,(float)x->pixheight, x->gop?x->hidetext?2:1:0); - if (x->goprect) binbuf_addv(b, "ff", (float)x->xmargin, (float)x->ymargin); - binbuf_addv(b,";"); -} - -/* get the index of a gobj in a canvas. If y is zero, return the total number of objects. */ -int canvas_oldindex(t_canvas *x, t_gobj *y) { - int i=0; - canvas_each(y2,x) {if (y2==y) break; else i++;} - return i; -} - -static void canvas_saveto(t_canvas *x, t_binbuf *b) { - canvas_savecontainerto(x,b); - canvas_each(y,x) gobj_save(y, b); - canvas_wires_each(oc,t,x) { - int from = canvas_oldindex(x,t.from); - int to = canvas_oldindex(x,t.to); - binbuf_addv(b, "ttiiii;","#X","connect", from, t.outlet, to, t.inlet); - appendix_save(oc,b); - } - canvas_savecoordsto(x,b); -} - -/* call this recursively to collect all the template names for a canvas or for the selection. */ -static void canvas_collecttemplatesfor(t_canvas *x, int *ntemplatesp, t_symbol ***templatevecp) { - canvas_each(y,x) { - if (y->_class==scalar_class) { - t_scalar *z = (t_scalar *)y; - canvas_addtemplatesforscalar(z->t, z->v, ntemplatesp, templatevecp); - } else if (y->_class==canvas_class) { - canvas_collecttemplatesfor((t_canvas *)y, ntemplatesp, templatevecp); - } - } -} - -/* save the templates needed by a canvas to a binbuf. */ -static void canvas_savetemplatesto(t_canvas *x, t_binbuf *b) { - t_symbol **templatevec = (t_symbol **)getbytes(0); - int ntemplates = 0; - canvas_collecttemplatesfor(x, &ntemplates, &templatevec); - for (int i=0; i < ntemplates; i++) { - t_template *t = template_findbyname(templatevec[i]); - if (!t) { - bug("canvas_savetemplatesto"); - continue; - } - /* drop "pd-" prefix from template symbol to print */ - binbuf_addv(b,"ttt","#N","struct",templatevec[i]->name+3); - for (int j=0; jn; j++) { - t_symbol *type; - switch (t->vec[j].type) { - case DT_FLOAT: type = &s_float; break; - case DT_SYMBOL: type = &s_symbol; break; - case DT_ARRAY: type = gensym("array"); break; - case DT_CANVAS: type = &s_list; break; - default: type = &s_float; bug("canvas_write"); - } - binbuf_addv(b,"ss",type,t->vec[j].name); - if (t->vec[j].type == DT_ARRAY) binbuf_addv(b, "t", t->vec[j].arraytemplate->name + 3); - } - binbuf_addsemi(b); - } -} - -/* save a "root" canvas to a file; cf. canvas_saveto() which saves the body (and which is called recursively.) */ -static void canvas_savetofile(t_canvas *x, t_symbol *filename, t_symbol *dir) { - t_binbuf *b = binbuf_new(); - int dsp_status = canvas_suspend_dsp(); - canvas_savetemplatesto(x, b); - canvas_saveto(x, b); - if (!binbuf_write(b, filename->name, dir->name, 0)) { - /* if not an abstraction, reset title bar and directory */ - if (!x->dix->canvas) canvas_rename(x, filename, dir); - post("saved to: %s/%s", dir->name, filename->name); - canvas_reload(filename,dir,x); - } - binbuf_free(b); - canvas_resume_dsp(dsp_status); -} - -/////////////////////////////////////////////////////////////////////////// -// from g_io.c - -/* graphical inlets and outlets, both for control and signals. */ -/* iohannes added multiple samplerates support in vinlet/voutlet */ - -extern "C" void signal_setborrowed(t_signal *sig, t_signal *sig2); -extern "C" void signal_makereusable(t_signal *sig); -extern "C" void inlet_sethelp(t_inlet* i,t_symbol* s); - -/* ------------------------- vinlet -------------------------- */ -t_class *vinlet_class; - -struct t_vinlet : t_object { - t_canvas *canvas; - t_inlet *inlet; - int bufsize; - t_float *buf; /* signal buffer; zero if not a signal */ - t_float *endbuf; - t_float *fill; - t_float *read; - int hop; - /* if not reblocking, the next slot communicates the parent's inlet signal from the prolog to the DSP routine: */ - t_signal *directsignal; - t_resample updown; /* IOhannes */ -}; - -static void *vinlet_new(t_symbol *s) { - t_vinlet *x = (t_vinlet *)pd_new(vinlet_class); - x->canvas = canvas_getcurrent(); - x->inlet = canvas_addinlet(x->canvas,x,0,s); - x->bufsize = 0; - x->buf = 0; - outlet_new(x, 0); - return x; -} - -static void vinlet_bang(t_vinlet *x) {x->outlet->send();} -static void vinlet_pointer(t_vinlet *x, t_gpointer *v) {x->outlet->send(v);} -static void vinlet_float(t_vinlet *x, t_float v) {x->outlet->send(v);} -static void vinlet_symbol(t_vinlet *x, t_symbol *v) {x->outlet->send(v);} -static void vinlet_list( t_vinlet *x, t_symbol *s, int argc, t_atom *argv) {x->outlet->send( argc,argv);} -static void vinlet_anything(t_vinlet *x, t_symbol *s, int argc, t_atom *argv) {x->outlet->send(s,argc,argv);} - -static void vinlet_free(t_vinlet *x) { - canvas_rminlet(x->canvas, x->inlet); - resample_free(&x->updown); -} - -t_inlet *vinlet_getit(t_pd *x) { - if (pd_class(x) != vinlet_class) bug("vinlet_getit"); - return ((t_vinlet *)x)->inlet; -} - -/* ------------------------- signal inlet -------------------------- */ -int vinlet_issignal(t_vinlet *x) {return x->buf!=0;} - -t_int *vinlet_perform(t_int *w) { - PERFORM3ARGS(t_vinlet *,x, t_float *,out, int,n); - t_float *in = x->read; - while (n--) *out++ = *in++; - if (in == x->endbuf) in = x->buf; - x->read = in; - return w+4; -} -/* tb: vectorized */ -t_int *vinlet_perf8(t_int *w) { - PERFORM3ARGS(t_vinlet *,x, t_float *,out, int,n); - t_float *in = x->read; - for (; n; n -= 8, in += 8, out += 8) { - out[0] = in[0]; out[1] = in[1]; out[2] = in[2]; out[3] = in[3]; - out[4] = in[4]; out[5] = in[5]; out[6] = in[6]; out[7] = in[7]; - } - if (in == x->endbuf) in = x->buf; - x->read = in; - return w+4; -} -/* T.Grill: SIMD version */ -t_int *vinlet_perfsimd(t_int *w) { - PERFORM3ARGS(t_vinlet *,x, t_float *,out, int,n); - t_float *in = x->read; - copyvec_simd(out,in,n); - if (in == x->endbuf) in = x->buf; - x->read = in; - return w+4; -} -static void vinlet_dsp(t_vinlet *x, t_signal **sp) { - if (!x->buf) return; /* no buffer means we're not a signal inlet */ - t_signal *outsig = sp[0]; - if (x->directsignal) signal_setborrowed(sp[0], x->directsignal); - else { - const int vecsize = outsig->vecsize; - /* if the outsig->v is aligned the x->read will also be... */ - if(vecsize&7) dsp_add(vinlet_perform, 3, x, outsig->v,vecsize); - else if(SIMD_CHECK1(outsig->n,outsig->v)) - dsp_add(vinlet_perfsimd, 3, x, outsig->v,vecsize); - else dsp_add(vinlet_perf8, 3, x, outsig->v,vecsize); - x->read = x->buf; - } -} -/* prolog code: loads buffer from parent patch */ -t_int *vinlet_doprolog(t_int *w) { - PERFORM3ARGS(t_vinlet *,x, t_float *,in, int,n); - t_float *out = x->fill; - if (out == x->endbuf) { - t_float *f1 = x->buf, *f2 = x->buf + x->hop; - int nshift = x->bufsize - x->hop; - out -= x->hop; - while (nshift--) *f1++ = *f2++; - } - while (n--) *out++ = *in++; - x->fill = out; - return w+4; -} - -extern "C" int inlet_getsignalindex(t_inlet *x); - -/* set up prolog DSP code */ -void vinlet_dspprolog(t_vinlet *x, t_signal **parentsigs, int myvecsize, int calcsize, int phase, int period, -int frequency, int downsample, int upsample, int reblock, int switched) { - t_signal *insig; - x->updown.downsample = downsample; - x->updown.upsample = upsample; - /* if the "reblock" flag is set, arrange to copy data in from the parent. */ - if (reblock) { - int parentvecsize, bufsize, oldbufsize, prologphase; - int re_parentvecsize; /* resampled parentvectorsize: IOhannes */ - /* this should never happen: */ - if (!x->buf) return; - /* the prolog code counts from 0 to period-1; the - phase is backed up by one so that AFTER the prolog code - runs, the "fill" phase is in sync with the "read" phase. */ - prologphase = (phase - 1) & (period - 1); - if (parentsigs) { - insig = parentsigs[inlet_getsignalindex(x->inlet)]; - parentvecsize = insig->vecsize; - re_parentvecsize = parentvecsize * upsample / downsample; - } else { - insig = 0; - parentvecsize = 1; - re_parentvecsize = 1; - } - bufsize = max(re_parentvecsize,myvecsize); - oldbufsize = x->bufsize; - if (bufsize != oldbufsize) { - t_float *buf = x->buf; - buf = (t_float *)resizealignedbytes(buf,oldbufsize * sizeof(*buf), bufsize * sizeof(*buf)); - memset((char *)buf, 0, bufsize * sizeof(*buf)); - x->bufsize = bufsize; - x->endbuf = buf + bufsize; - x->buf = buf; - } - if (parentsigs) { - /* IOhannes { */ - x->hop = period * re_parentvecsize; - x->fill = x->endbuf - (x->hop - prologphase * re_parentvecsize); - if (upsample * downsample == 1) - dsp_add(vinlet_doprolog, 3, x, insig->v, re_parentvecsize); - else { - resamplefrom_dsp(&x->updown, insig->v, parentvecsize, re_parentvecsize, x->updown.method); - dsp_add(vinlet_doprolog, 3, x, x->updown.v, re_parentvecsize); - } - /* } IOhannes */ - /* if the input signal's reference count is zero, we have to free it here because we didn't in ugen_doit(). */ - if (!insig->refcount) signal_makereusable(insig); - } else memset((char *)x->buf, 0, bufsize * sizeof(*x->buf)); - x->directsignal = 0; - } else { - /* no reblocking; in this case our output signal is "borrowed" and merely needs to be pointed to the real one. */ - x->directsignal = parentsigs[inlet_getsignalindex(x->inlet)]; - } -} - -static void *vinlet_newsig(t_symbol *s) { - t_vinlet *x = (t_vinlet *)pd_new(vinlet_class); - x->canvas = canvas_getcurrent(); - x->inlet = canvas_addinlet(x->canvas,x,&s_signal,s); - x->endbuf = x->buf = (t_float *)getalignedbytes(0); - x->bufsize = 0; - x->directsignal = 0; - outlet_new(x, &s_signal); - resample_init(&x->updown); - /* this should be thought over: it might prove hard to provide consistency between labeled up- & downsampling methods - maybe indices would be better... - up till now we provide several upsampling methods and 1 single downsampling method (no filtering !) */ - if (s) { - char c=*s->name; - switch(c) { - case'h':case'H':x->updown.method=RESAMPLE_HOLD; break; /* up: sample and hold */ - case'l':case'L':x->updown.method=RESAMPLE_LINEAR; break; /* up: linear interpolation */ - case'b':case'B':x->updown.method=RESAMPLE_BLOCK; break; /* down: ignore the 2nd half of the block */ - default: x->updown.method=RESAMPLE_ZERO; /* up: zero-padding */ - } - } - return x; -} - -static void vinlet_setup() { - t_class *c = vinlet_class = class_new2("inlet",vinlet_new,vinlet_free,sizeof(t_vinlet),CLASS_NOINLET,"S"); - class_addcreator2("inlet~",vinlet_newsig,"S"); - class_addbang( c, vinlet_bang); - class_addpointer( c, vinlet_pointer); - class_addfloat( c, vinlet_float); - class_addsymbol( c, vinlet_symbol); - class_addlist( c, vinlet_list); - class_addanything(c, vinlet_anything); - class_addmethod2( c, vinlet_dsp,"dsp",""); - class_sethelpsymbol(c, gensym("pd")); -} - -/* ------------------------- voutlet -------------------------- */ - -t_class *voutlet_class; - -struct t_voutlet : t_object { - t_canvas *canvas; - t_outlet *parentoutlet; - int bufsize; - t_float *buf; /* signal buffer; zero if not a signal */ - t_float *endbuf; - t_float *empty; /* next to read out of buffer in epilog code */ - t_float *write; /* next to write in to buffer */ - int hop; /* hopsize */ - /* vice versa from the inlet, if we don't block, this holds the - parent's outlet signal, valid between the prolog and the dsp setup functions. */ - t_signal *directsignal; - /* and here's a flag indicating that we aren't blocked but have to do a copy (because we're switched). */ - char justcopyout; - t_resample updown; /* IOhannes */ -}; - -static void *voutlet_new(t_symbol *s) { - t_voutlet *x = (t_voutlet *)pd_new(voutlet_class); - x->canvas = canvas_getcurrent(); - x->parentoutlet = canvas_addoutlet(x->canvas,x,0); - inlet_new(x,x,0,0); - x->bufsize = 0; - x->buf = 0; - return x; -} - -static void voutlet_bang( t_voutlet *x) {x->parentoutlet->send( );} -static void voutlet_pointer( t_voutlet *x, t_gpointer *v) {x->parentoutlet->send(v);} -static void voutlet_float( t_voutlet *x, t_float v) {x->parentoutlet->send(v);} -static void voutlet_symbol( t_voutlet *x, t_symbol *v) {x->parentoutlet->send(v);} -static void voutlet_list( t_voutlet *x, t_symbol *s, int argc, t_atom *argv) {x->parentoutlet->send( argc,argv);} -static void voutlet_anything(t_voutlet *x, t_symbol *s, int argc, t_atom *argv) {x->parentoutlet->send(s,argc,argv);} - -static void voutlet_free(t_voutlet *x) {canvas_rmoutlet(x->canvas, x->parentoutlet); resample_free(&x->updown);} -t_outlet *voutlet_getit(t_pd *x) { - if (pd_class(x) != voutlet_class) bug("voutlet_getit"); - return ((t_voutlet *)x)->parentoutlet; -} - -int voutlet_issignal(t_voutlet *x) {return x->buf!=0;} - -/* LATER optimize for non-overlapped case where the "+=" isn't needed */ -t_int *voutlet_perform(t_int *w) { - PERFORM3ARGS(t_voutlet *,x, t_float *,in, int,n); - t_float *out = x->write, *outwas = out, *end = x->endbuf; - while (n--) { - *out++ += *in++; - if (out == end) out = x->buf; - } - outwas += x->hop; - if (outwas >= end) outwas = x->buf; - x->write = outwas; - return w+4; -} -/* epilog code for blocking: write buffer to parent patch */ -static t_int *voutlet_doepilog(t_int *w) { - PERFORM3ARGS(t_voutlet *,x, t_float *,out, int,n); - t_float *in = x->empty; - if (x->updown.downsample != x->updown.upsample) out = x->updown.v; /* IOhannes */ - for (; n--; in++) *out++ = *in, *in = 0; - if (in == x->endbuf) in = x->buf; - x->empty = in; - return w+4; -} - -/* IOhannes { */ -static t_int *voutlet_doepilog_resampling(t_int *w) { - PERFORM2ARGS(t_voutlet *,x, int,n); - t_float *in = x->empty; - t_float *out = x->updown.v; /* IOhannes */ - for (; n--; in++) *out++ = *in, *in = 0; - if (in == x->endbuf) in = x->buf; - x->empty = in; - return w+3; -} -/* } IOhannes */ -extern "C" int outlet_getsignalindex(t_outlet *x); - -/* prolog for outlets -- store pointer to the outlet on the parent, which, if "reblock" is false, will want to refer - back to whatever we see on our input during the "dsp" method called later. */ -void voutlet_dspprolog(t_voutlet *x, t_signal **parentsigs, int myvecsize, int calcsize, int phase, int period, -int frequency, int downsample, int upsample, int reblock, int switched) { - x->updown.downsample=downsample; x->updown.upsample=upsample; /* IOhannes */ - x->justcopyout = (switched && !reblock); - if (reblock) { - x->directsignal = 0; - } else { - if (!parentsigs) bug("voutlet_dspprolog"); - x->directsignal = parentsigs[outlet_getsignalindex(x->parentoutlet)]; - } -} - -static void voutlet_dsp(t_voutlet *x, t_signal **sp) { - if (!x->buf) return; - t_signal *insig = sp[0]; - if (x->justcopyout) dsp_add_copy(insig->v, x->directsignal->v, insig->n); - else if (x->directsignal) { - /* if we're just going to make the signal available on the parent patch, hand it off to the parent signal. */ - /* this is done elsewhere--> sp[0]->refcount++; */ - signal_setborrowed(x->directsignal, sp[0]); - } else dsp_add(voutlet_perform, 3, x, insig->v, insig->n); -} - -/* set up epilog DSP code. If we're reblocking, this is the - time to copy the samples out to the containing object's outlets. - If we aren't reblocking, there's nothing to do here. */ -void voutlet_dspepilog(t_voutlet *x, t_signal **parentsigs, -int myvecsize, int calcsize, int phase, int period, int frequency, int downsample, int upsample, int reblock, int switched) { - if (!x->buf) return; /* this shouldn't be necesssary... */ - x->updown.downsample=downsample; - x->updown.upsample=upsample; /* IOhannes */ - if (reblock) { - t_signal *outsig; - int parentvecsize, bufsize, oldbufsize; - int re_parentvecsize; /* IOhannes */ - int bigperiod, epilogphase, blockphase; - if (parentsigs) { - outsig = parentsigs[outlet_getsignalindex(x->parentoutlet)]; - parentvecsize = outsig->vecsize; - re_parentvecsize = parentvecsize * upsample / downsample; - } else { - outsig = 0; - parentvecsize = 1; - re_parentvecsize = 1; - } - bigperiod = myvecsize/re_parentvecsize; /* IOhannes */ - if (!bigperiod) bigperiod = 1; - epilogphase = phase & (bigperiod - 1); - blockphase = (phase + period - 1) & (bigperiod - 1) & (- period); - bufsize = re_parentvecsize; /* IOhannes */ - if (bufsize < myvecsize) bufsize = myvecsize; - if (bufsize != (oldbufsize = x->bufsize)) { - t_float *buf = x->buf; - buf = (t_float *)resizealignedbytes(buf,oldbufsize * sizeof(*buf),bufsize * sizeof(*buf)); - memset((char *)buf, 0, bufsize * sizeof(*buf)); - x->bufsize = bufsize; - x->endbuf = buf + bufsize; - x->buf = buf; - } - /* IOhannes: { */ - if (re_parentvecsize * period > bufsize) bug("voutlet_dspepilog"); - x->write = x->buf + re_parentvecsize * blockphase; - if (x->write == x->endbuf) x->write = x->buf; - if (period == 1 && frequency > 1) x->hop = re_parentvecsize / frequency; - else x->hop = period * re_parentvecsize; - /* } IOhannes */ - if (parentsigs) { - /* set epilog pointer and schedule it */ - /* IOhannes { */ - x->empty = x->buf + re_parentvecsize * epilogphase; - if (upsample*downsample==1) - dsp_add(voutlet_doepilog, 3, x, outsig->v, re_parentvecsize); - else { - dsp_add(voutlet_doepilog_resampling, 2, x, re_parentvecsize); - resampleto_dsp(&x->updown, outsig->v, re_parentvecsize, parentvecsize, x->updown.method); - } - /* } IOhannes */ - } - } - /* if we aren't blocked but we are switched, the epilog code just - copies zeros to the output. In this case the blocking code actually jumps over the epilog if the block is running. */ - else if (switched) { - if (parentsigs) { - t_signal *outsig = parentsigs[outlet_getsignalindex(x->parentoutlet)]; - dsp_add_zero(outsig->v, outsig->n); - } - } -} - -static void *voutlet_newsig(t_symbol *s) { - t_voutlet *x = (t_voutlet *)pd_new(voutlet_class); - x->canvas = canvas_getcurrent(); - x->parentoutlet = canvas_addoutlet(x->canvas,x,&s_signal); - inlet_new(x,x,&s_signal,&s_signal); - x->endbuf = x->buf = (t_float *)getalignedbytes(0); - x->bufsize = 0; - resample_init(&x->updown); - /* this should be though over: - * it might prove hard to provide consistency between labeled up- & downsampling methods - * maybe indeces would be better... - * up till now we provide several upsampling methods and 1 single downsampling method (no filtering !) */ - if (s) { - char c=*s->name; - switch(c) { - case 'h': case 'H': x->updown.method=RESAMPLE_HOLD; break; /* up: sample and hold */ - case 'l': case 'L': x->updown.method=RESAMPLE_LINEAR; break; /* up: linear interpolation */ - case 'b': case 'B': x->updown.method=RESAMPLE_BLOCK; break; /* down: ignore the 2nd half of the block */ - default: x->updown.method=RESAMPLE_ZERO; /* up: zero-padding */ - } - } - return x; -} - -static void voutlet_setup() { - t_class *c = voutlet_class = class_new2("outlet",voutlet_new,voutlet_free,sizeof(t_voutlet),CLASS_NOINLET,"S"); - class_addcreator2("outlet~",voutlet_newsig,"S"); - class_addbang( c, voutlet_bang); - class_addpointer( c, voutlet_pointer); - class_addfloat( c, (t_method)voutlet_float); - class_addsymbol( c, voutlet_symbol); - class_addlist( c, voutlet_list); - class_addanything(c, voutlet_anything); - class_addmethod2( c, voutlet_dsp, "dsp", ""); - class_sethelpsymbol(c, gensym("pd")); -} - -/* This file defines the "scalar" object, which is not a text object, just a - "gobj". Scalars have templates which describe their structures, which can contain numbers, sublists, and arrays. - IOhannes changed the canvas_restore, so that it might accept $args as well (like "pd $0_test") - so you can make multiple & distinguishable templates; added Krzysztof Czajas fix to avoid crashing... */ -t_class *scalar_class; - -void word_init(t_word *wp, t_template *t, t_gpointer *gp) { - t_dataslot *datatypes = t->vec; - for (int i=0; i < t->n; i++, datatypes++, wp++) { - int type = datatypes->type; - if (type == DT_FLOAT) wp->w_float = 0; - else if (type == DT_SYMBOL) wp->w_symbol = &s_symbol; - else if (type == DT_ARRAY) wp->w_array = array_new(datatypes->arraytemplate, gp); - else if (type == DT_CANVAS) { - /* LATER test this and get it to work */ - wp->w_canvas = canvas_new(0,0,0,0); - } - } -} - -void word_restore(t_word *wp, t_template *t, int argc, t_atom *argv) { - t_dataslot *datatypes = t->vec; - for (int i=0; in; i++, datatypes++, wp++) { - int type = datatypes->type; - if (type == DT_FLOAT) { - float f=0; - if (argc) {f = atom_getfloat(argv); argv++; argc--;} - wp->w_float = f; - } else if (type == DT_SYMBOL) { - t_symbol *s=&s_; - if (argc) {s = atom_getsymbol(argv); argv++; argc--;} - wp->w_symbol = s; - } - } - if (argc) post("warning: word_restore: extra arguments"); -} - -void word_free(t_word *wp, t_template *t) { - t_dataslot *dt = t->vec; - for (int i=0; in; i++, dt++) { - if (dt->type == DT_ARRAY) pd_free(wp[i].w_array); - else if (dt->type == DT_CANVAS) pd_free(wp[i].w_canvas); - } -} - -static void gpointer_setcanvas(t_gpointer *gp, t_canvas *canvas, t_scalar *x); -static void gpointer_setarray(t_gpointer *gp, t_array *array, t_word *w); -static t_word *gpointer_word(t_gpointer *gp) {return gp->o->_class == array_class ? gp->w : gp->scalar->v;} -static t_canvas *gpointer_getcanvas(t_gpointer *gp) { - if (gp->o->_class != array_class) return gp->canvas; - return 0; /* FIXME */ -} -static t_scalar *gpointer_getscalar(t_gpointer *gp) { - if (gp->o->_class != array_class) return gp->scalar; - return 0; -} - -/* make a new scalar and add to the canvas. We create a "gp" here which will be used for array items to point back here. - This gp doesn't do reference counting or "validation" updates though; the parent won't go away without the contained - arrays going away too. The "gp" is copied out by value in the word_init() routine so we can throw our copy away. */ -t_scalar *scalar_new(t_canvas *owner, t_symbol *tsym) { - t_gpointer gp; - gpointer_init(&gp); - t_template *t = template_findbyname(tsym); - TEMPLATE_CHECK(tsym,0) - t_scalar *x = (t_scalar *)getbytes(sizeof(t_scalar) + (t->n - 1) * sizeof(*x->v)); - x->_class = scalar_class; - x->t = tsym; - gpointer_setcanvas(&gp, owner, x); - word_init(x->v, t, &gp); - return x; -} - -/* Pd method to create a new scalar, add it to a canvas, and initialize it from the message arguments. */ -int canvas_readscalar(t_canvas *x, int natoms, t_atom *vec, int *p_nextmsg, int selectit); -static void canvas_scalar(t_canvas *canvas, t_symbol *classname, t_int argc, t_atom *argv) { - t_symbol *tsym = canvas_makebindsym(atom_getsymbolarg(0, argc, argv)); - if (!template_findbyname(tsym)) {error("%s: no such template", atom_getsymbolarg(0, argc, argv)->name); return;} - int nextmsg; - t_binbuf *b = binbuf_new(); - binbuf_restore(b, argc, argv); - canvas_readscalar(canvas, binbuf_getnatom(b), binbuf_getvec(b), &nextmsg, 0); - binbuf_free(b); -} - -static void scalar_getbasexy(t_scalar *x, float *basex, float *basey) { - t_template *t = template_findbyname(x->t); - *basex = template_getfloat(t,&s_x,x->v,0); - *basey = template_getfloat(t,&s_y,x->v,0); -} - -/* -static void scalar_displace(t_gobj *z, t_canvas *canvas, int dx, int dy) { - t_scalar *x = (t_scalar *)z; - t_symbol *tsym = x->t; - t_template *t = template_findbyname(tsym); - t_symbol *zz; - int xonset, yonset, xtype, ytype, gotx, goty; - TEMPLATE_CHECK(tsym,) - gotx = template_find_field(t,&s_x,&xonset,&xtype,&zz); - if (gotx && (xtype != DT_FLOAT)) gotx = 0; - goty = template_find_field(t,&s_y,&yonset,&ytype,&zz); - if (goty && (ytype != DT_FLOAT)) goty = 0; - if (gotx) *(t_float *)(((char *)(x->v)) + xonset) += dx * (canvas_pixelstox(canvas, 1) - canvas_pixelstox(canvas, 0)); - if (goty) *(t_float *)(((char *)(x->v)) + yonset) += dy * (canvas_pixelstoy(canvas, 1) - canvas_pixelstoy(canvas, 0)); - scalar_redraw(x, canvas); -}*/ - -static void scalar_vis(t_gobj *z, t_canvas *owner, int vis) { - t_scalar *x = (t_scalar *)z; - t_template *t = template_findbyname(x->t); - t_canvas *templatecanvas = template_findcanvas(t); - float basex, basey; - scalar_getbasexy(x, &basex, &basey); - /* if we don't know how to draw it, make a small rectangle */ - if (!templatecanvas) { - if (vis) { - int x1 = canvas_xtopixels(owner, basex); - int y1 = canvas_ytopixels(owner, basey); - sys_vgui(".x%lx.c create rectangle %d %d %d %d -tags scalar%lx\n", - (long)canvas_getcanvas(owner), x1-1, y1-1, x1+1, y1+1, (long)x); - } else sys_vgui(".x%lx.c delete scalar%lx\n", (long)canvas_getcanvas(owner), (long)x); - return; - } - //canvas_each(y,templatecanvas) pd_getparentwidget(y)->w_parentvisfn(y,owner,x->v,t,basex,basey,vis); - //sys_unqueuegui(x); -} - -static void scalar_doredraw(t_gobj *client, t_canvas *canvas) { - scalar_vis(client, canvas, 0); - scalar_vis(client, canvas, 1); -} - -void scalar_redraw(t_scalar *x, t_canvas *canvas) { - //if (canvas_isvisible(canvas)) sys_queuegui(x, canvas, scalar_doredraw); -} - -#if 0 -int scalar_doclick(t_word *data, t_template *t, t_scalar *sc, t_array *ap, t_canvas *owner, -float xloc, float yloc, int xpix, int ypix, int shift, int alt, int dbl, int doit) { - t_canvas *templatecanvas = template_findcanvas(t); - float basex = template_getfloat(t,&s_x,data,0); - float basey = template_getfloat(t,&s_y,data,0); - canvas_each(y,templatecanvas) { - int hit = pd_getparentwidget(y)->w_parentclickfn(y, owner, data, t, sc, ap, basex+xloc, basey+yloc, - xpix, ypix, shift, alt, dbl, doit); - if (hit) return hit; - }*/ - return 0; -} -#endif - -static int scalar_click(t_gobj *z, t_canvas *owner, int xpix, int ypix, int shift, int alt, int dbl, int doit) { - t_scalar *x = (t_scalar *)z; - t_template *t = template_findbyname(x->t); - return scalar_doclick(x->v, t, x, 0, owner, 0, 0, xpix, ypix, shift, alt, dbl, doit); -} - -void canvas_writescalar(t_symbol *tsym, t_word *w, t_binbuf *b, int amarrayelement); - -static void scalar_save(t_gobj *z, t_binbuf *b) { - t_scalar *x = (t_scalar *)z; - t_binbuf *b2 = binbuf_new(); - canvas_writescalar(x->t, x->v, b2, 0); - binbuf_addv(b,"tt","#X","scalar"); - binbuf_addbinbuf(b, b2); - binbuf_addsemi(b); - binbuf_free(b2); -} - -/* -static void scalar_properties(t_gobj *z, t_canvas *owner) { - t_scalar *x = (t_scalar *)z; - char *buf, buf2[80]; - int bufsize; - t_binbuf *b; - b = canvas_writetobinbuf(owner, 0); - binbuf_gettext(b, &buf, &bufsize); - binbuf_free(b); - buf = realloc2(buf,bufsize+1); - buf[bufsize] = 0; - sprintf(buf2, "pdtk_data_dialog %%s {"); - sys_gui(buf); - sys_gui("}\n"); - free(buf); -} -*/ - -static void scalar_free(t_scalar *x) { - t_template *t = template_findbyname(x->t); - TEMPLATE_CHECK(x->t,) - word_free(x->v, t); - /* the "size" field in the class is zero, so Pd doesn't try to free us automatically (see pd_free()) */ - free(x); -} - -static void g_scalar_setup() { - scalar_class = class_new2("scalar",0,scalar_free,0,CLASS_GOBJ,""); - class_setsavefn(scalar_class, scalar_save); -} - -void array_redraw(t_array *a, t_canvas *canvas); - -/* -This file contains text objects you would put in a canvas to define a -template. Templates describe objects of type "array" (g_array.c) and "scalar" (g_scalar.c). */ -/* the structure of a "struct" object (also the obsolete "gtemplate" you get when using the name "template" in a box.) */ -struct t_gtemplate : t_object { - t_template *t; - t_canvas *owner; - t_symbol *sym; - t_gtemplate *next; - int argc; - t_atom *argv; -}; - -static void template_conformarray(t_template *tfrom, t_template *tto, int *conformaction, t_array *a); -static void template_conformcanvas(t_template *tfrom, t_template *tto, int *conformaction, t_canvas *canvas); -static t_class *gtemplate_class; -static t_class *template_class; - -/* there's a pre-defined "float" template. LATER should we bind this to a symbol such as "pd-float"??? */ - -/* return true if two dataslot definitions match */ -static int dataslot_matches(t_dataslot *ds1, t_dataslot *ds2, int nametoo) { - return (!nametoo || ds1->name == ds2->name) && ds1->type == ds2->type && - (ds1->type != DT_ARRAY || ds1->arraytemplate == ds2->arraytemplate); -} - -/* -- templates, the active ingredient in gtemplates defined below. ------- */ - -static t_template *template_new(t_symbol *tsym, int argc, t_atom *argv) { - t_template *x = (t_template *)pd_new(template_class); - x->n = 0; - x->vec = (t_dataslot *)getbytes(0); - while (argc > 0) { - int newtype, oldn, newn; - t_symbol *newname, *newarraytemplate = &s_, *newtypesym; - if (argc < 2 || argv[0].a_type != A_SYMBOL || argv[1].a_type != A_SYMBOL) goto bad; - newtypesym = argv[0].a_symbol; - newname = argv[1].a_symbol; - if (newtypesym == &s_float) newtype = DT_FLOAT; - else if (newtypesym == &s_symbol) newtype = DT_SYMBOL; - else if (newtypesym == &s_list) newtype = DT_CANVAS; - else if (newtypesym == gensym("array")) { - if (argc < 3 || argv[2].a_type != A_SYMBOL) {error("array lacks element template or name"); goto bad;} - newarraytemplate = canvas_makebindsym(argv[2].a_symbol); - newtype = DT_ARRAY; - argc--; - argv++; - } else {error("%s: no such type", newtypesym->name); goto bad;} - newn = (oldn = x->n) + 1; - x->vec = realloc2(x->vec,newn); - x->n = newn; - x->vec[oldn].type = newtype; - x->vec[oldn].name = newname; - x->vec[oldn].arraytemplate = newarraytemplate; - bad: - argc -= 2; argv += 2; - } - x->sym = tsym; - if (tsym->name) pd_bind(x,x->sym); - return x; -} - -int template_size(t_template *x) {return x->n * sizeof(t_word);} - -int template_find_field(t_template *x, t_symbol *name, int *p_onset, int *p_type, t_symbol **p_arraytype) { - if (!x) {bug("template_find_field"); return 0;} - for (int i = 0; in; i++) if (x->vec[i].name == name) { - if (p_onset) *p_onset = i*sizeof(t_word); - if (p_type) *p_type = x->vec[i].type; - if (p_arraytype) *p_arraytype = x->vec[i].arraytemplate; - return 1; - } - return 0; -} - -#define ERR(msg,ret) do {\ - if (loud) error("%s.%s: "msg, x->sym->name, fieldname->name);\ - return ret;} while(0); -static t_float template_getfloat(t_template *x, t_symbol *fieldname, t_word *wp, int loud) { - int onset, type; t_symbol *arraytype; - if (!template_find_field(x, fieldname, &onset, &type, &arraytype)) ERR("no such field",0); - if (type != DT_FLOAT) ERR("not a number",0); - return *(t_float *)(((char *)wp) + onset); -} -static t_symbol *template_getsymbol(t_template *x, t_symbol *fieldname, t_word *wp, int loud) { - int onset, type; t_symbol *arraytype; - if (!template_find_field(x, fieldname, &onset, &type, &arraytype)) ERR("no such field",&s_); - if (type != DT_SYMBOL) ERR("not a symbol",&s_); - return *(t_symbol **)(((char *)wp) + onset); -} -static void template_setfloat(t_template *x, t_symbol *fieldname, t_word *wp, t_float f, int loud) { - int onset, type; t_symbol *arraytype; - if (!template_find_field(x, fieldname, &onset, &type, &arraytype)) ERR("no such field",); - if (type != DT_FLOAT) ERR("not a number",); - *(t_float *)(((char *)wp) + onset) = f; -} -static void template_setsymbol(t_template *x, t_symbol *fieldname, t_word *wp, t_symbol *s, int loud) { - int onset, type; t_symbol *arraytype; - if (!template_find_field(x, fieldname, &onset, &type, &arraytype)) ERR("no such field",); - if (type != DT_SYMBOL) ERR("not a symbol",); - *(t_symbol **)(((char *)wp) + onset) = s; -} -#undef ERR - -/* stringent check to see if a "saved" template, x2, matches the current -one (x1). It's OK if x1 has additional scalar elements but not (yet) -arrays or lists. This is used for reading in "data files". */ -static int template_match(t_template *x1, t_template *x2) { - if (x1->n < x2->n) return 0; - for (int i=x2->n; i < x1->n; i++) - if (x1->vec[i].type == DT_ARRAY || x1->vec[i].type == DT_CANVAS) return 0; - if (x2->n > x1->n) post("add elements..."); - for (int i=0; i < x2->n; i++) if (!dataslot_matches(&x1->vec[i], &x2->vec[i], 1)) return 0; - return 1; -} - -/* --------------- CONFORMING TO CHANGES IN A TEMPLATE ------------ */ - -/* the following functions handle updating scalars to agree with changes -in their template. The old template is assumed to be the "installed" one -so we can delete old items; but making new ones we have to avoid scalar_new -which would make an old one whereas we will want a new one (but whose array -elements might still be old ones.) - LATER deal with graphics updates too... */ - -/* conform the word vector of a scalar to the new template */ -static void template_conformwords(t_template *tfrom, t_template *tto, int *conformaction, t_word *wfrom, t_word *wto) { - for (int i=0; in; i++) { - if (conformaction[i] >= 0) { - /* we swap the two, in case it's an array or list, so that when "wfrom" is deleted the old one gets cleaned up. */ - t_word wwas = wto[i]; - wto[i] = wfrom[conformaction[i]]; - wfrom[conformaction[i]] = wwas; - } - } -} - -/* conform a scalar, recursively conforming sublists and arrays */ -static t_scalar *template_conformscalar(t_template *tfrom, t_template *tto, int *conformaction, t_canvas *canvas, t_scalar *scfrom) { - t_scalar *x; - t_template *scalartemplate; - /* possibly replace the scalar */ - if (scfrom->t == tfrom->sym) { - t_gpointer gp; - /* see scalar_new() for comment about the gpointer. */ - gpointer_init(&gp); - x = (t_scalar *)getbytes(sizeof(t_scalar) + (tto->n - 1) * sizeof(*x->v)); - x->_class = scalar_class; - x->t = tfrom->sym; - gpointer_setcanvas(&gp, canvas, x); - /* Here we initialize to the new template, but array and list elements will still belong to old template. */ - word_init(x->v, tto, &gp); - template_conformwords(tfrom, tto, conformaction, scfrom->v, x->v); - /* replace the old one with the new one in the list */ - canvas->boxes->remove_by_value(scfrom); - canvas->boxes->add(x); - pd_free(scfrom); - scalartemplate = tto; - } else { - x = scfrom; - scalartemplate = template_findbyname(x->t); - } - /* convert all array elements and sublists */ - for (int i=0; i < scalartemplate->n; i++) { - t_dataslot *ds = scalartemplate->vec + i; - if (ds->type == DT_CANVAS) template_conformcanvas(tfrom, tto, conformaction, x->v[i].w_canvas); - if (ds->type == DT_ARRAY) template_conformarray( tfrom, tto, conformaction, x->v[i].w_array); - } - return x; -} - -/* conform an array, recursively conforming sublists and arrays */ -static void template_conformarray(t_template *tfrom, t_template *tto, int *conformaction, t_array *a) { - t_template *scalartemplate = 0; - if (a->tsym == tfrom->sym) { - /* the array elements must all be conformed */ - int oldelemsize = sizeof(t_word) * tfrom->n; - int newelemsize = sizeof(t_word) * tto->n; - char *newarray = (char *)getbytes(newelemsize * a->n); - char *oldarray = a->vec; - if (a->elemsize != oldelemsize) bug("template_conformarray"); - for (int i=0; in; i++) { - t_word *wp = (t_word *)(newarray + newelemsize*i); - word_init(wp, tto, &a->gp); - template_conformwords(tfrom, tto, conformaction, (t_word *)(oldarray + oldelemsize*i), wp); - word_free((t_word *)(oldarray + oldelemsize*i), tfrom); - } - scalartemplate = tto; - a->vec = newarray; - free(oldarray); - } else scalartemplate = template_findbyname(a->tsym); - /* convert all arrays and sublist fields in each element of the array */ - for (int i=0; in; i++) { - t_word *wp = (t_word *)(a->vec + sizeof(t_word) * a->n * i); - for (int j=0; j < scalartemplate->n; j++) { - t_dataslot *ds = scalartemplate->vec + j; - if (ds->type == DT_CANVAS) template_conformcanvas(tfrom, tto, conformaction, wp[j].w_canvas); - if (ds->type == DT_ARRAY) template_conformarray( tfrom, tto, conformaction, wp[j].w_array); - } - } -} - -/* this routine searches for every scalar in the canvas that belongs - to the "from" template and makes it belong to the "to" template. Descend canvases recursively. - We don't handle redrawing here; this is to be filled in LATER... */ -t_array *garray_getarray(t_garray *x); -static void template_conformcanvas(t_template *tfrom, t_template *tto, int *conformaction, t_canvas *canvas) { - canvas_each(g,canvas) { - t_class *c = g->_class; - /* what's the purpose of the assignment here?... consult original code */ - if (c==scalar_class) g = template_conformscalar(tfrom, tto, conformaction, canvas, (t_scalar *)g); - else if (c==canvas_class) template_conformcanvas(tfrom, tto, conformaction, (t_canvas *)g); - else if (c==garray_class) template_conformarray(tfrom, tto, conformaction, garray_getarray((t_garray *)g)); - } -} - -/* globally conform all scalars from one template to another */ -void template_conform(t_template *tfrom, t_template *tto) { - int nto = tto->n, nfrom = tfrom->n, doit = 0; - int *conformaction = (int *)getbytes(sizeof(int) * nto); - int *conformedfrom = (int *)getbytes(sizeof(int) * nfrom); - for (int i=0; i< nto; i++) conformaction[i] = -1; - for (int i=0; ivec[i]; - for (int j=0; jvec[j]; - if (dataslot_matches(dataslot, dataslot2, 1)) { - conformaction[i] = j; - conformedfrom[j] = 1; - } - } - } - for (int i=0; ivec[i]; - for (int j=0; jvec[j], 0)) { - conformaction[i] = j; - conformedfrom[j] = 1; - } - } - if (nto != nfrom) doit = 1; - else for (int i=0; isym->name); - for (int i=0; ifirst); - } - free(conformaction); - free(conformedfrom); -} - -t_template *template_findbyname(t_symbol *s) {return (t_template *)pd_findbyclass(s, template_class);} - -t_canvas *template_findcanvas(t_template *t) { - if (!t) bug("template_findcanvas"); - t_gtemplate *gt = t->list; - if (!gt) return 0; - return gt->owner; - /* return ((t_canvas *)pd_findbyclass(t->sym, canvas_class)); */ -} - -void template_notify(t_template *t, t_symbol *s, int argc, t_atom *argv) {if (t->list) t->list->outlet->send(s,argc,argv);} - -/* bash the first of (argv) with a pointer to a scalar, and send on - to template as a notification message */ -static void template_notifyforscalar(t_template *t, t_canvas *owner, t_scalar *sc, t_symbol *s, int argc, t_atom *argv) { - t_gpointer gp; - gpointer_init(&gp); - gpointer_setcanvas(&gp, owner, sc); - SETPOINTER(argv, &gp); - template_notify(t, s, argc, argv); - gpointer_unset(&gp); -} - -/* call this when reading a patch from a file to declare what templates - we'll need. If there's already a template, check if it matches. - If it doesn't it's still OK as long as there are no "struct" (gtemplate) - objects hanging from it; we just conform everyone to the new template. - If there are still struct objects belonging to the other template, we're - in trouble. LATER we'll figure out how to conform the new patch's objects - to the pre-existing struct. */ -static void *template_usetemplate(void *dummy, t_symbol *s, int argc, t_atom *argv) { - t_symbol *tsym = canvas_makebindsym(atom_getsymbolarg(0, argc, argv)); - t_template *x = (t_template *)pd_findbyclass(tsym, template_class); - if (!argc) return 0; - argc--; argv++; - if (x) { - t_template *y = template_new(&s_, argc, argv); - /* If the new template is the same as the old one, there's nothing to do. */ - if (!template_match(x, y)) { /* Are there "struct" objects upholding this template? */ - if (x->list) { - error("%s: template mismatch", tsym->name); - } else { - template_conform(x, y); - pd_free(x); - t_template *y2 = template_new(tsym, argc, argv); - y2->list = 0; - } - } - pd_free(y); - } else template_new(tsym, argc, argv); - return 0; -} - -/* here we assume someone has already cleaned up all instances of this. */ -void template_free(t_template *x) { - if (*x->sym->name) pd_unbind(x,x->sym); - free(x->vec); -} - -/* ---------------- gtemplates. One per canvas. ----------- */ - -/* "Struct": an object that searches for, and if necessary creates, -a template (above). Other objects in the canvas then can give drawing -instructions for the template. The template doesn't go away when the -"struct" is deleted, so that you can replace it with another one to add new fields, for example. */ -static void *gtemplate_donew(t_symbol *sym, int argc, t_atom *argv) { - t_gtemplate *x = (t_gtemplate *)pd_new(gtemplate_class); - t_template *t = template_findbyname(sym); - x->owner = canvas_getcurrent(); - x->next = 0; - x->sym = sym; - x->argc = argc; - x->argv = (t_atom *)getbytes(argc * sizeof(t_atom)); - for (int i=0; iargv[i] = argv[i]; - /* already have a template by this name? */ - if (t) { - x->t = t; - /* if it's already got a "struct" object we - just tack this one to the end of the list and leave it there. */ - if (t->list) { - t_gtemplate *x2, *x3; - for (x2 = x->t->list; (x3 = x2->next); x2 = x3) {} - x2->next = x; - post("template %s: warning: already exists.", sym->name); - } else { - /* if there's none, we just replace the template with our own and conform it. */ - t_template *y = template_new(&s_, argc, argv); - //canvas_redrawallfortemplate(t, 2); - /* Unless the new template is different from the old one, there's nothing to do. */ - if (!template_match(t, y)) { - /* conform everyone to the new template */ - template_conform(t, y); - pd_free(t); - t = template_new(sym, argc, argv); - } - pd_free(y); - t->list = x; - //canvas_redrawallfortemplate(t, 1); - } - } else { - /* otherwise make a new one and we're the only struct on it. */ - x->t = t = template_new(sym, argc, argv); - t->list = x; - } - outlet_new(x,0); - return x; -} - -static void *gtemplate_new(t_symbol *s, int argc, t_atom *argv) { - t_symbol *sym = atom_getsymbolarg(0, argc, argv); - if (argc >= 1) {argc--; argv++;} - return (gtemplate_donew(canvas_makebindsym(sym), argc, argv)); -} - -/* old version (0.34) -- delete 2003 or so */ -static void *gtemplate_new_old(t_symbol *s, int argc, t_atom *argv) { - t_symbol *sym = canvas_makebindsym(canvas_getcurrent()->name); - static int warned; - if (!warned) { - post("warning -- 'template' (%s) is obsolete; replace with 'struct'", sym->name); - warned = 1; - } - return gtemplate_donew(sym, argc, argv); -} - -t_template *gtemplate_get(t_gtemplate *x) {return x->t;} - -static void gtemplate_free(t_gtemplate *x) { - /* get off the template's list */ - t_template *t = x->t; - if (x == t->list) { - //canvas_redrawallfortemplate(t, 2); - if (x->next) { - /* if we were first on the list, and there are others on the list, make a new template corresponding - to the new first-on-list and replace the existing template with it. */ - t_template *z = template_new(&s_, x->next->argc, x->next->argv); - template_conform(t, z); - pd_free(t); - pd_free(z); - z = template_new(x->sym, x->next->argc, x->next->argv); - z->list = x->next; - for (t_gtemplate *y=z->list; y ; y=y->next) y->t=z; - } else t->list = 0; - //canvas_redrawallfortemplate(t, 1); - } else { - t_gtemplate *x2, *x3; - for (x2=t->list; (x3=x2->next); x2=x3) if (x==x3) {x2->next=x3->next; break;} - } - free(x->argv); -} - -/* --------------- FIELD DESCRIPTORS (NOW CALLED SLOT) ---------------------- */ -/* a field descriptor can hold a constant or a variable's name; in the latter case, - it's the name of a field in the template we belong to. LATER, we might want to cache the offset - of the field so we don't have to search for it every single time we draw the object. -*/ -/* note: there is also t_dataslot which plays a similar role. could they be merged someday? */ - -struct _slot { - char type; /* LATER consider removing this? */ - char var; - union { - t_float f; /* the field is a constant float */ - t_symbol *s; /* the field is a constant symbol */ - t_symbol *varsym; /* the field is variable and this is the name */ - }; - float min,max; - float scrmin,scrmax; /* min and max screen values */ - float quantum; /* quantization in value */ -}; - -static void slot_setfloat_const( t_slot *fd, float f) { - fd->type = A_FLOAT; fd->var = 0; fd->f = f; fd->min = fd->max = fd->scrmin = fd->scrmax = fd->quantum = 0;} -static void slot_setsymbol_const(t_slot *fd, t_symbol *s) { - fd->type = A_SYMBOL; fd->var = 0; fd->s = s; fd->min = fd->max = fd->scrmin = fd->scrmax = fd->quantum = 0;} - -static void slot_setfloat_var(t_slot *fd, t_symbol *s) { - char *s1, *s2, *s3; - fd->type = A_FLOAT; - fd->var = 1; - if (!(s1 = strchr(s->name, '(')) || !(s2 = strchr(s->name, ')')) || s1>s2) { - fd->varsym = s; - fd->min = fd->max = fd->scrmin = fd->scrmax = fd->quantum = 0; - } else { - fd->varsym = symprintf("%.*s",s1-s->name,s->name); - t_int got = sscanf(s1, "(%f:%f)(%f:%f)(%f)", &fd->min, &fd->max, &fd->scrmin, &fd->scrmax, &fd->quantum); - if (got < 2) goto fail; - if (got == 3 || (got < 4 && strchr(s2, '('))) goto fail; - if (got < 5 && (s3 = strchr(s2, '(')) && strchr(s3+1, '(')) goto fail; - if (got == 4) fd->quantum = 0; - else if (got == 2) { - fd->quantum = 0; - fd->scrmin = fd->min; - fd->scrmax = fd->max; - } - return; - fail: - error("parse error: %s", s->name); - fd->min = fd->scrmin = fd->max = fd->scrmax = fd->quantum = 0; - } -} - -#define CLOSED 1 -#define BEZ 2 -#define NOMOUSE 4 -#define A_ARRAY 55 /* LATER decide whether to enshrine this in m_pd.h */ - -static void slot_setfloatarg(t_slot *fd, int argc, t_atom *argv) { - if (argc <= 0) slot_setfloat_const(fd, 0); - else if (argv->a_type == A_SYMBOL) slot_setfloat_var( fd, argv->a_symbol); - else slot_setfloat_const(fd, argv->a_float); -} -static void slot_setsymbolarg(t_slot *fd, int argc, t_atom *argv) { - if (argc <= 0) slot_setsymbol_const(fd, &s_); - else if (argv->a_type == A_SYMBOL) { - fd->type = A_SYMBOL; - fd->var = 1; - fd->varsym = argv->a_symbol; - fd->min = fd->max = fd->scrmin = fd->scrmax = fd->quantum = 0; - } else slot_setsymbol_const(fd, &s_); -} -static void slot_setarrayarg(t_slot *fd, int argc, t_atom *argv) { - if (argc <= 0) slot_setfloat_const(fd, 0); - else if (argv->a_type == A_SYMBOL) { - fd->type = A_ARRAY; - fd->var = 1; - fd->varsym = argv->a_symbol; - } else slot_setfloat_const(fd, argv->a_float); -} - -/* getting and setting values via slots -- note confusing names; the above are setting up the slot itself. */ - -/* convert a variable's value to a screen coordinate via its slot */ -static t_float slot_cvttocoord(t_slot *f, float val) { - float coord, extreme, div; - if (f->max == f->min) return val; - div = (f->scrmax - f->scrmin)/(f->max - f->min); - coord = f->scrmin + (val - f->min) * div; - extreme = f->scrminscrmax ? f->scrmin : f->scrmax; if (coordscrmin>f->scrmax ? f->scrmin : f->scrmax; if (coord>extreme) coord = extreme; - return coord; -} - -/* read a variable via slot and convert to screen coordinate */ -static t_float slot_getcoord(t_slot *f, t_template *t, t_word *wp, int loud) { - if (f->type!=A_FLOAT) {if (loud) error("symbolic data field used as number"); return 0;} - if (f->var) return slot_cvttocoord(f, template_getfloat(t, f->varsym, wp, loud)); - return f->f; -} -static t_float slot_getfloat(t_slot *f, t_template *t, t_word *wp, int loud) { - if (f->type!=A_FLOAT) {if (loud) error("symbolic data field used as number"); return 0;} - if (f->var) return template_getfloat(t, f->varsym, wp, loud); - return f->f; -} -static t_symbol *slot_getsymbol(t_slot *f, t_template *t, t_word *wp, int loud) { - if (f->type!=A_SYMBOL) {if (loud) error("numeric data field used as symbol"); return &s_;} - if (f->var) return template_getsymbol(t, f->varsym, wp, loud); - return f->s; -} - -/* convert from a screen coordinate to a variable value */ -static float slot_cvtfromcoord(t_slot *f, float coord) { - if (f->scrmax == f->scrmin) return coord; - else { - float div = (f->max - f->min)/(f->scrmax - f->scrmin); - float extreme; - float val = f->min + (coord - f->scrmin) * div; - if (f->quantum != 0) val = ((int)((val/f->quantum) + 0.5)) * f->quantum; - extreme = f->minmax ? f->min : f->max; if (valmin>f->max ? f->min : f->max; if (val>extreme) val=extreme; - return val; - } - } - -static void slot_setcoord(t_slot *f, t_template *t, t_word *wp, float coord, int loud) { - if (f->type == A_FLOAT && f->var) { - float val = slot_cvtfromcoord(f, coord); - template_setfloat(t, f->varsym, wp, val, loud); - } else { - if (loud) error("attempt to set constant or symbolic data field to a number"); - } -} - -#define FIELDSET(T,F,D) if (argc) slot_set##T##arg(&x->F,argc--,argv++); \ - else slot_setfloat_const(&x->F,D); - -/* curves belong to templates and describe how the data in the template are to be drawn. - The coordinates of the curve (and other display features) can be attached to fields in the template. */ - -t_class *curve_class; - -/* includes polygons too */ -struct t_curve : t_object { - int flags; /* CLOSED and/or BEZ and/or NOMOUSE */ - t_slot fillcolor, outlinecolor, width, vis; - int npoints; - t_slot *vec; - t_canvas *canvas; -}; - -static void *curve_new(t_symbol *classsym, t_int argc, t_atom *argv) { - t_curve *x = (t_curve *)pd_new(curve_class); - char *classname = classsym->name; - int flags = 0; - x->canvas = canvas_getcurrent(); - if (classname[0] == 'f') {classname += 6; flags |= CLOSED;} else classname += 4; - slot_setfloat_const(&x->vis, 1); - if (classname[0] == 'c') flags |= BEZ; - while (1) { - t_symbol *firstarg = atom_getsymbolarg(0, argc, argv); - if (!strcmp(firstarg->name,"-v") && argc > 1) { - slot_setfloatarg(&x->vis, 1, argv+1); - argc -= 2; argv += 2; - } else - if (!strcmp(firstarg->name,"-x")) { - flags |= NOMOUSE; - argc -= 1; argv += 1; - } else break; - } - x->flags = flags; - if (flags&CLOSED&&argc) slot_setfloatarg( &x->fillcolor, argc--,argv++); - else slot_setfloat_const(&x->fillcolor, 0); - FIELDSET(float,outlinecolor,0); - FIELDSET(float,width,1); - if (argc < 0) argc = 0; - int nxy = argc + (argc&1); - x->npoints = nxy>>1; - x->vec = (t_slot *)getbytes(nxy * sizeof(t_slot)); - t_slot *fd = x->vec; - for (int i=0; ivis.type != A_FLOAT || x->vis.var) {error("global vis/invis for a template with variable visibility"); return;} - int viswas = x->vis.f!=0; - if ((f!=0 && viswas) || (f==0 && !viswas)) return; - canvas_redrawallfortemplatecanvas(x->canvas, 2); - slot_setfloat_const(&x->vis, f!=0); - canvas_redrawallfortemplatecanvas(x->canvas, 1); -} - -static int rangecolor(int n) {return n*9/255;} - -static void numbertocolor(int n, char *s) { - n = (int)max(n,0); - sprintf(s, "#%2.2x%2.2x%2.2x", rangecolor(n/100), rangecolor((n/10)%10), rangecolor(n%10)); -} - -static void curve_vis(t_gobj *z, t_canvas *canvas, t_word *data, t_template *t, float basex, float basey, int vis) { - t_curve *x = (t_curve *)z; - int n = x->npoints; - t_slot *f = x->vec; - if (!slot_getfloat(&x->vis, t, data, 0)) return; - if (vis) { - if (n > 1) { - int flags = x->flags; - char outline[20], fill[20]; - int pix[200]; - if (n > 100) n = 100; - /* calculate the pixel values before we start printing out the TK message so that - "error" printout won't be interspersed with it. Only show up to 100 points so we don't - have to allocate memory here. */ - for (int i=0; ioutlinecolor, t, data, 1), outline); - if (flags & CLOSED) { - numbertocolor((int)slot_getfloat(&x->fillcolor, t, data, 1), fill); - //sys_vgui(".x%lx.c create polygon\\\n", (long)canvas_getcanvas(canvas)); - } else sys_vgui(".x%lx.c create line\\\n", (long)canvas_getcanvas(canvas)); - for (int i=0; iwidth, t, data, 1),1.0f)); - if (flags & CLOSED) sys_vgui("-fill %s -outline %s\\\n", fill, outline); - else sys_vgui("-fill %s\\\n", outline); - if (flags & BEZ) sys_vgui("-smooth 1\\\n"); - sys_vgui("-tags curve%lx\n", (long)data); - } else post("warning: curves need at least two points to be graphed"); - } else { - if (n > 1) sys_vgui(".x%lx.c delete curve%lx\n", (long)canvas_getcanvas(canvas), (long)data); - } -} - -static struct { - int field; - float xcumulative, xbase, xper; - float ycumulative, ybase, yper; - t_canvas *canvas; - t_scalar *scalar; - t_array *array; - t_word *wp; - t_template *t; - t_gpointer gpointer; -} cm; - -/* LATER protect against the template changing or the scalar disappearing probably by attaching a gpointer here ... */ -#if 0 -static void curve_motion(void *z, t_floatarg dx, t_floatarg dy) { - t_curve *x = (t_curve *)z; - t_slot *f = x->vec + cm.field; - t_atom at; - if (!gpointer_check(&curve_motion_gpointer, 0)) {post("curve_motion: scalar disappeared"); return;} - cm.xcumulative += dx; - cm.ycumulative += dy; - if (f[0].var && dx!=0) slot_setcoord(f, cm.t, cm.wp, cm.xbase + cm.xcumulative*cm.xper, 1); - if (f[1].var && dy!=0) slot_setcoord(f+1, cm.t, cm.wp, cm.ybase + cm.ycumulative*cm.yper, 1); - /* LATER figure out what to do to notify for an array? */ - if (cm.scalar) template_notifyforscalar(cm.t, cm.canvas, cm.scalar, gensym("change"), 1, &at); - if (cm.scalar) gobj_changed(cm.scalar,0); else gobj_changed(cm.array,0); -} -#endif - -int iabs(int a) {return a<0?-a:a;} - -static int curve_click(t_gobj *z, t_canvas *canvas, t_word *data, t_template *t, t_scalar *sc, -t_array *ap, float basex, float basey, int xpix, int ypix, int shift, int alt, int dbl, int doit) { - t_curve *x = (t_curve *)z; - int bestn = -1; - int besterror = 0x7fffffff; - t_slot *f = x->vec; - if (!slot_getfloat(&x->vis, t, data, 0)) return 0; - for (int i=0; inpoints; i++, f += 2) { - int xval = (int)slot_getcoord(f , t, data, 0), xloc = canvas_xtopixels(canvas, basex + xval); - int yval = (int)slot_getcoord(f+1, t, data, 0), yloc = canvas_ytopixels(canvas, basey + yval); - int xerr = iabs(xloc-xpix); - int yerr = iabs(yloc-ypix); - if (!f->var && !(f+1)->var) continue; - if (yerr > xerr) xerr = yerr; - if (xerr < besterror) { - cm.xbase = xval; - cm.ybase = yval; - besterror = xerr; - bestn = i; - } - } - if (besterror > 10) return 0; - if (doit) { - cm.xper = canvas_pixelstox(canvas, 1) - canvas_pixelstox(canvas, 0); - cm.yper = canvas_pixelstoy(canvas, 1) - canvas_pixelstoy(canvas, 0); - cm.xcumulative = cm.ycumulative = 0; - cm.canvas = canvas; - cm.scalar = sc; - cm.array = ap; - cm.wp = data; - cm.field = 2*bestn; - cm.t = t; - if (cm.scalar) gpointer_setcanvas(&cm.gpointer, cm.canvas, cm.scalar); - else gpointer_setarray(&cm.gpointer, cm.array, cm.wp); - /* canvas_grab(canvas, z, curve_motion, 0, xpix, ypix); */ - } - return 1; -} - -t_class *plot_class; - -struct t_plot : t_object { - t_canvas *canvas; - t_slot outlinecolor, width, xloc, yloc, xinc, style; - t_slot data, xpoints, ypoints, wpoints; - t_slot vis; - t_slot scalarvis; /* true if drawing the scalar at each point */ -}; - -static void *plot_new(t_symbol *classsym, t_int argc, t_atom *argv) { - t_plot *x = (t_plot *)pd_new(plot_class); - int defstyle = PLOTSTYLE_POLY; - x->canvas = canvas_getcurrent(); - slot_setfloat_var(&x->xpoints,&s_x); - slot_setfloat_var(&x->ypoints,&s_y); - slot_setfloat_var(&x->wpoints, gensym("w")); - slot_setfloat_const(&x->vis, 1); - slot_setfloat_const(&x->scalarvis, 1); - while (1) { - const char *f = atom_getsymbolarg(0, argc, argv)->name; - argc--; argv++; - if (!strcmp(f, "curve") || !strcmp(f, "-c")) defstyle = PLOTSTYLE_BEZ; - else if (!strcmp(f,"-v") &&argc>0) {slot_setfloatarg(&x->vis, 1,argv+1);argc--;argv++;} - else if (!strcmp(f,"-vs")&&argc>0) {slot_setfloatarg(&x->scalarvis,1,argv+1);argc--;argv++;} - else if (!strcmp(f,"-x") &&argc>0) {slot_setfloatarg(&x->xpoints, 1,argv+1);argc--;argv++;} - else if (!strcmp(f,"-y") &&argc>0) {slot_setfloatarg(&x->ypoints, 1,argv+1);argc--;argv++;} - else if (!strcmp(f,"-w") &&argc>0) {slot_setfloatarg(&x->wpoints, 1,argv+1);argc--;argv++;} - else break; - } - FIELDSET(array,data,1); - FIELDSET(float,outlinecolor,0); - FIELDSET(float,width,1); - FIELDSET(float,xloc,1); - FIELDSET(float,yloc,1); - FIELDSET(float,xinc,1); - FIELDSET(float,style,defstyle); - return x; -} - -void plot_float(t_plot *x, t_floatarg f) { - int viswas; - if (x->vis.type != A_FLOAT || x->vis.var) {error("global vis/invis for a template with variable visibility"); return;} - viswas = x->vis.f!=0; - if ((f!=0 && viswas) || (f==0 && !viswas)) return; - canvas_redrawallfortemplatecanvas(x->canvas, 2); - slot_setfloat_const(&x->vis, f!=0); - canvas_redrawallfortemplatecanvas(x->canvas, 1); -} - -struct t_pelote { - t_symbol *elemtsym; - t_array *array; - float linewidth; - float xloc; - float xinc; - float yloc; - float style; - float vis; - float scalarvis; -}; - -/* get everything we'll need from the owner template of the array being - plotted. Not used for garrays, but see below */ -static int plot_readownertemplate(t_plot *x, t_word *data, t_template *ownertemplate, t_pelote *out) { - int arrayonset, type; - t_symbol *elemtsym; - t_array *array; - if (x->data.type != A_ARRAY || !x->data.var) {error("needs an array field"); return -1;} - if (!template_find_field(ownertemplate, x->data.varsym, &arrayonset, &type, &elemtsym)) { - error("%s: no such field", x->data.varsym->name); - return -1; - } - if (type != DT_ARRAY) {error("%s: not an array", x->data.varsym->name); return -1;} - array = *(t_array **)(((char *)data) + arrayonset); -#define SLUT(FIELD) slot_getfloat(&x->FIELD, ownertemplate, data, 1); - out->linewidth = SLUT(width); - out->xloc = SLUT(xloc); - out->xinc = SLUT(xinc); - out->yloc = SLUT(yloc); - out->style = SLUT(style); - out->vis = SLUT(vis); - out->scalarvis = SLUT(scalarvis); -#undef SLUT - out->elemtsym = elemtsym; - out->array = array; - return 0; -} - -/* get everything else you could possibly need about a plot, - either for plot's own purposes or for plotting a "garray" */ -static int array_getfields(t_symbol *elemtsym, t_canvas **elemtemplatecanvasp, -t_template **elemtemplatep, int *elemsizep, t_slot *xslot, t_slot *yslot, t_slot *wslot, -int *xonsetp, int *yonsetp, int *wonsetp) { - int type; - t_symbol *dummy, *varname; - t_canvas *elemtemplatecanvas = 0; - /* the "float" template is special in not having to have a canvas; - template_findbyname is hardwired to return a predefined template. */ - t_template *elemtemplate = template_findbyname(elemtsym); - if (!elemtemplate) {error("%s: no such template", elemtsym->name); return -1;} - if (!(elemtsym==&s_float || (elemtemplatecanvas = template_findcanvas(elemtemplate)))) { - error("%s: no canvas for this template", elemtsym->name); - return -1; - } - *elemtemplatecanvasp = elemtemplatecanvas; - *elemtemplatep = elemtemplate; - *elemsizep = elemtemplate->n * sizeof(t_word); -#define FOO(f,name,onset) \ - varname = f && f->var ? f->varsym : gensym(name); \ - if (!template_find_field(elemtemplate,varname,&onset,&type,&dummy) || type!=DT_FLOAT) onset=-1; - FOO(yslot,"y",*yonsetp) - FOO(xslot,"x",*xonsetp) - FOO(wslot,"w",*wonsetp) -#undef FOO - return 0; -} - -static void plot_vis(t_gobj *z, t_canvas *canvas, t_word *data, t_template *t, float basex, float basey, int tovis) { - t_plot *x = (t_plot *)z; - int elemsize, yonset, wonset, xonset; - t_canvas *elemtemplatecanvas; - t_template *elemtemplate; - float xsum, yval; - t_pelote p; - if (plot_readownertemplate(x,data,t,&p)) return; - t_slot *xslot = &x->xpoints, *yslot = &x->ypoints, *wslot = &x->wpoints; - if (!p.vis) return; - if (array_getfields(p.elemtsym,&elemtemplatecanvas,&elemtemplate,&elemsize,xslot,yslot,wslot,&xonset,&yonset,&wonset)) return; - int nelem = p.array->n; - char *elem = (char *)p.array->vec; - if (tovis) { - if (p.style == PLOTSTYLE_POINTS) { - float minyval = 1e20, maxyval = -1e20; - int ndrawn = 0; - xsum = basex + p.xloc; - for (int i=0; i= 0) { - float usexloc = basex + p.xloc + *(float *)((elem + elemsize*i) + xonset); - ixpix = canvas_xtopixels(canvas, slot_cvttocoord(xslot, usexloc)); - inextx = ixpix + 2; - } else { - ixpix = canvas_xtopixels(canvas, slot_cvttocoord(xslot, xsum)); xsum += p.xinc; - inextx = canvas_xtopixels(canvas, slot_cvttocoord(xslot, xsum)); - } - yval = yonset>=0 ? p.yloc + *(float *)((elem + elemsize*i) + yonset) : 0; - if (yval > maxyval) maxyval = yval; - if (yval < minyval) minyval = yval; - if (i == nelem-1 || inextx != ixpix) { - sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill black -width 0 -tags plot%lx\n", - (long)canvas_getcanvas(canvas), ixpix, - (int) canvas_ytopixels(canvas, basey + slot_cvttocoord(yslot, minyval)), inextx, - (int)(canvas_ytopixels(canvas, basey + slot_cvttocoord(yslot, maxyval))+p.linewidth), - (long)data); - ndrawn++; - minyval = 1e20; - maxyval = -1e20; - } - } - } else { - char outline[20]; - int lastpixel = -1, ndrawn = 0; - float yval = 0, wval = 0; - int ixpix = 0; - /* draw the trace */ - numbertocolor((int)slot_getfloat(&x->outlinecolor, t, data, 1), outline); - if (wonset >= 0) { - /* found "w" field which controls linewidth. The trace is a filled polygon with 2n points. */ - //sys_vgui(".x%lx.c create polygon \\\n", (long)canvas_getcanvas(canvas)); - xsum = p.xloc; -#define FOO float usexloc = xonset>=0 ? p.xloc+*(float *)(elem+elemsize*i+xonset) : xsum; \ - float yval = yonset>=0 ? *(float *)(elem+elemsize*i+yonset) : 0; \ - wval = *(float *)(elem+elemsize*i+wonset); \ - float xpix = canvas_xtopixels(canvas, basex + slot_cvttocoord(xslot, usexloc)); \ - ixpix = int(roundf(xpix)); \ - float w = slot_cvttocoord(wslot,wval); - for (int i=0; i=0 || ixpix!=lastpixel) { - sys_vgui("%d %f \\\n", ixpix, canvas_ytopixels(canvas, basey + slot_cvttocoord(yslot,yval+p.yloc) - w)); - ndrawn++;} - lastpixel = ixpix;} - lastpixel = -1; - for (int i=nelem-1; i>=0; i--) { - xsum-=p.xinc; FOO; - if (xonset>=0 || ixpix!=lastpixel) { - sys_vgui("%d %f \\\n", ixpix, canvas_ytopixels(canvas, basey + p.yloc + slot_cvttocoord(yslot,yval)+w)); - ndrawn++;} - lastpixel = ixpix;} -#undef FOO - /* TK will complain if there aren't at least 3 points. There should be at least two already. */ - if (ndrawn < 4) { - int y = int(slot_cvttocoord(yslot, yval)); - int w = int(slot_cvttocoord(wslot, wval)); - sys_vgui("%d %f %d %f\\\n", - ixpix + 10, canvas_ytopixels(canvas, basey + p.yloc + y + w), - ixpix + 10, canvas_ytopixels(canvas, basey + p.yloc + y - w));} - sys_vgui(" -width 1 -fill %s -outline %s", outline, outline); - if (p.style == PLOTSTYLE_BEZ) sys_vgui("-smooth 1"); - sys_vgui("-tags plot%lx\n", (long)data); - } else if (p.linewidth>0) { - /* no "w" field. If the linewidth is positive, draw a segmented line with the - requested width; otherwise don't draw the trace at all. */ - sys_vgui(".x%lx.c create line \\\n", (long)canvas_getcanvas(canvas)); - xsum = p.xloc; - for (int i=0; i=0 ? p.xloc+*(float *)(elem+elemsize*i+xonset) : xsum; if (xonset>=0) xsum+=int(p.xinc); - float yval = yonset>=0 ? *(float *)(elem+elemsize*i+yonset) : 0; - float xpix = canvas_xtopixels(canvas, basex + slot_cvttocoord(xslot, usexloc)); - ixpix = (int)roundf(xpix); - if (xonset >= 0 || ixpix != lastpixel) { - sys_vgui("%d %f \\\n", ixpix, canvas_ytopixels(canvas, basey + p.yloc + slot_cvttocoord(yslot, yval))); - ndrawn++; - } - lastpixel = ixpix; - } - /* TK will complain if there aren't at least 2 points... */ - if (ndrawn == 0) sys_vgui("0 0 0 0 \\\n"); - else if (ndrawn == 1) sys_vgui("%d %f \\\n", ixpix + 10, - canvas_ytopixels(canvas, basey + p.yloc + slot_cvttocoord(yslot, yval))); - sys_vgui("-width %f -fill %s -smooth %d -tags plot%lx",p.linewidth,outline,p.style==PLOTSTYLE_BEZ,(long)data); - } - } - /* We're done with the outline; now draw all the points. */ - if (p.scalarvis) { - int xsum = int(p.xloc); - for (int i=0; i=0 ? basex + xloc + *(float *)(elem+elemsize*i+xonset) : basex+xsum; - if (xonset>=0) xsum+=int(p.xinc); - yval = yonset>=0 ? *(float *)(elem+elemsize*i+yonset) : 0; - //float useyloc = basey + yloc + slot_cvttocoord(yslot, yval); - /*canvas_each(y,elemtemplatecanvas) pd_getparentwidget(y)->w_parentvisfn(y, canvas, - (t_word *)(elem+elemsize*i), elemtemplate, usexloc, useyloc, tovis);*/ - } - } - } else { - /* un-draw the individual points */ - /* if (scalarvis) for (int i=0; iw_parentvisfn(y, canvas, (t_word *)(elem+elemsize*i), elemtemplate,0,0,0);*/ - /* and then the trace */ - sys_vgui(".x%lx.c delete plot%lx\n", (long)canvas_getcanvas(canvas), (long)data); - } -} - -// could be merged with array_doclick -static int plot_click(t_gobj *z, t_canvas *canvas, t_word *data, t_template *t, t_scalar *sc, -t_array *ap, float basex, float basey, int xpix, int ypix, int shift, int alt, int dbl, int doit) { - t_plot *x = (t_plot *)z; - t_pelote p; - if (plot_readownertemplate(x,data,t,&p)) return 0; - if (!p.vis) return 0; - return array_doclick(p.array,canvas,sc,ap,p.elemtsym,p.linewidth,basex+p.xloc,p.xinc, - basey+p.yloc,p.scalarvis,&x->xpoints,&x->ypoints,&x->wpoints,xpix,ypix,shift,alt,dbl,doit); -} - -/* ---------------- drawnumber: draw a number (or symbol) ---------------- */ -/* drawnumbers draw numeric fields at controllable locations, with controllable color and label. - invocation: (drawnumber|drawsymbol) [-v ] variable x y color label */ - -t_class *drawnumber_class; - -#define DRAW_SYMBOL 1 - -struct t_drawnumber : t_object { - t_slot value, xloc, yloc, color, vis; - t_symbol *label; - int flags; - t_canvas *canvas; -}; - -static void *drawnumber_new(t_symbol *classsym, t_int argc, t_atom *argv) { - t_drawnumber *x = (t_drawnumber *)pd_new(drawnumber_class); - char *classname = classsym->name; - int flags = 0; - if (classname[4] == 's') flags |= DRAW_SYMBOL; - x->flags = flags; - slot_setfloat_const(&x->vis, 1); - x->canvas = canvas_getcurrent(); - while (1) { - t_symbol *firstarg = atom_getsymbolarg(0, argc, argv); - if (!strcmp(firstarg->name,"-v") && argc > 1) { - slot_setfloatarg(&x->vis, 1, argv+1); - argc -= 2; argv += 2; - } else break; - } - if (flags & DRAW_SYMBOL) { - if (argc) slot_setsymbolarg( &x->value,argc--,argv++); - else slot_setsymbol_const(&x->value,&s_); - } else FIELDSET(float,value, 0); - FIELDSET(float,xloc,0); - FIELDSET(float,yloc,0); - FIELDSET(float,color,1); - if (argc) x->label = atom_getsymbolarg(0, argc, argv); else x->label = &s_; - return x; -} - -void drawnumber_float(t_drawnumber *x, t_floatarg f) { - if (x->vis.type != A_FLOAT || x->vis.var) {error("global vis/invis for a template with variable visibility"); return;} - int viswas = x->vis.f!=0; - if ((f != 0 && viswas) || (f == 0 && !viswas)) return; - canvas_redrawallfortemplatecanvas(x->canvas, 2); - slot_setfloat_const(&x->vis, f!=0); - canvas_redrawallfortemplatecanvas(x->canvas, 1); -} - -static void drawnumber_vis(t_gobj *z, t_canvas *canvas, t_word *data, t_template *t, float basex, float basey, int vis) { - t_drawnumber *x = (t_drawnumber *)z; - if (!slot_getfloat(&x->vis, t, data, 0)) return; - if (vis) { - t_atom at; - int xloc = canvas_xtopixels(canvas, basex + slot_getcoord(&x->xloc, t, data, 0)); - int yloc = canvas_ytopixels(canvas, basey + slot_getcoord(&x->yloc, t, data, 0)); - char colorstring[20]; - numbertocolor((int)slot_getfloat(&x->color, t, data, 1), colorstring); - if (x->flags & DRAW_SYMBOL) SETSYMBOL(&at, slot_getsymbol(&x->value, t, data, 0)); - else SETFLOAT( &at, slot_getfloat( &x->value, t, data, 0)); - std::ostringstream buf; - buf << x->label->name; - atom_ostream(&at,buf); - sys_vgui(".x%lx.c create text %d %d -anchor nw -fill %s -text {%s}", - (long)canvas_getcanvas(canvas), xloc, yloc, colorstring, buf.str().data()); - sys_vgui(" -font {Courier 42} -tags drawnumber%lx\n", (long)data); /*sys_hostfontsize(canvas_getfont(canvas))*/ - } else sys_vgui(".x%lx.c delete drawnumber%lx\n", (long)canvas_getcanvas(canvas), (long)data); -} - -static struct { - float ycumulative; - t_canvas *canvas; - t_scalar *scalar; - t_array *array; - t_word *wp; - t_template *t; - t_gpointer gpointer; - int symbol; - int firstkey; -} dn; - -/* LATER protect against the template changing or the scalar disappearing probably by attaching a gpointer here ... */ -#if 0 -static void drawnumber_motion(void *z, t_floatarg dx, t_floatarg dy) { - t_drawnumber *x = (t_drawnumber *)z; - t_slot *f = &x->value; - t_atom at; - if (!gpointer_check(&dn.gpointer, 0)) {post("drawnumber_motion: scalar disappeared"); return;} - if (dn.symbol) {post("drawnumber_motion: symbol"); return;} - dn.ycumulative -= dy; - template_setfloat(dn.t, f->varsym, dn.wp, dn.ycumulative, 1); - if (dn.scalar) gobj_changed(dn.scalar); else gobj_changed(dn.array); -} -#endif - -static void drawnumber_key(void *z, t_floatarg fkey) { - //t_drawnumber *x = (t_drawnumber *)z; - int key = (int)fkey; - if (!gpointer_check(&dn.gpointer, 0)) {post("drawnumber_motion: scalar disappeared"); return;} - if (!key) return; - if (dn.symbol) { - /* key entry for a symbol field... has to be rewritten in Tcl similarly to TextBox for edition of [drawsymbol] */ - // template_getsymbol(dn.t, f->varsym, dn.wp, 1)->name; - } else { - /* key entry for a numeric field... same here... [drawnumber] */ - //t_slot *f = &x->value; - //float newf; - //if (sscanf(sbuf, "%g", &newf) < 1) newf = 0; - //template_setfloat(dn.t, f->varsym, dn.wp, newf, 1); - //t_atom at; - //if (dn.scalar) template_notifyforscalar(dn.t, dn.canvas, dn.scalar, gensym("change"), 1, &at); - //if (dn.scalar) gobj_changed(dn.scalar,0); else gobj_changed(dn.array,0); - } -} - -#if 0 -static int drawnumber_click(t_gobj *z, t_canvas *canvas, t_word *data, t_template *t, t_scalar *sc, t_array *ap, float basex, float basey, int xpix, int ypix, int shift, int alt, int dbl, int doit) { - t_drawnumber *x = (t_drawnumber *)z; - int x1, y1, x2, y2; - drawnumber_getrect(z, canvas, data, t, basex, basey, &x1, &y1, &x2, &y2); - if (xpix >= x1 && xpix <= x2 && ypix >= y1 && ypix <= y2 - && x->value.var && slot_getfloat(&x->vis, t, data, 0)) { - if (doit) { - dn.canvas = canvas; - dn.wp = data; - dn.t = t; - dn.scalar = sc; - dn.array = ap; - dn.firstkey = 1; - dn.ycumulative = slot_getfloat(&x->value, t, data, 0); - dn.symbol = (x->flags & DRAW_SYMBOL)!=0; - if (dn.scalar) - gpointer_setcanvas(&dn.gpointer, dn.canvas, dn.scalar); - else gpointer_setarray(&dn.gpointer, dn.array, dn.wp); - /* canvas_grab(glist, z, drawnumber_motion, drawnumber_key, xpix, ypix); */ - } - return 1; - } else return 0; -} -#endif - -static void drawnumber_free(t_drawnumber *x) {} - -static void g_template_setup() { - template_class = class_new2("template",0,template_free,sizeof(t_template),CLASS_PD,""); - class_addmethod2(pd_canvasmaker._class, template_usetemplate, "struct", "*"); - gtemplate_class = class_new2("struct",gtemplate_new,gtemplate_free,sizeof(t_gtemplate),CLASS_NOINLET,"*"); - class_addcreator2("template",gtemplate_new_old,"*"); - - curve_class = class_new2("drawpolygon",curve_new,0,sizeof(t_curve),0,"*"); - class_setdrawcommand(curve_class); - class_addcreator2("drawcurve", curve_new,"*"); - class_addcreator2("filledpolygon",curve_new,"*"); - class_addcreator2("filledcurve", curve_new,"*"); - class_addfloat(curve_class, curve_float); - plot_class = class_new2("plot",plot_new,0,sizeof(t_plot),0,"*"); - class_setdrawcommand(plot_class); - class_addfloat(plot_class, plot_float); - drawnumber_class = class_new2("drawnumber",drawnumber_new,drawnumber_free,sizeof(t_drawnumber),0,"*"); - class_setdrawcommand(drawnumber_class); - class_addfloat(drawnumber_class, drawnumber_float); - class_addcreator2("drawsymbol",drawnumber_new,"*"); -} - -/* ------------- gpointers - safe pointing --------------- */ - -/* call this to verify that a pointer is fresh, i.e., that it either points to real data or to the head of a list, - and that in either case the object hasn't disappeared since this pointer was generated. Unless "headok" is set, - the routine also fails for the head of a list. */ -int gpointer_check(const t_gpointer *gp, int headok) { - if (!gp->o) return 0; - if (gp->o->_class == array_class) return 1; - return headok || gp->scalar; -} - -/* get the template for the object pointer to. Assumes we've already checked freshness. Returns 0 if head of list. */ -static t_symbol *gpointer_gettsym(const t_gpointer *gp) { - if (gp->o->_class == array_class) return gp->array->tsym; - t_scalar *sc = gp->scalar; - return sc ? sc->t : 0; -} - -/* copy a pointer to another, assuming the second one hasn't yet been initialized. New gpointers should be initialized - either by this routine or by gpointer_init below. */ -void gpointer_copy(const t_gpointer *gpfrom, t_gpointer *gpto) { - *gpto = *gpfrom; - if (gpto && gpto->o) gpto->o->refcount++; else bug("gpointer_copy"); -} - -void gpointer_unset(t_gpointer *gp) { - if (gp->scalar) { - if (!--gp->o->refcount) pd_free(gp->o); - gp->o=0; - gp->scalar=0; - } -} - -static void gpointer_setcanvas(t_gpointer *gp, t_canvas *o, t_scalar *x) { - gpointer_unset(gp); - gp->o=o; gp->scalar = x; gp->o->refcount++; -} -static void gpointer_setarray(t_gpointer *gp, t_array *o, t_word *w) { - gpointer_unset(gp); - gp->o=o; gp->w = w; gp->o->refcount++; -} - -void gpointer_init(t_gpointer *gp) { - gp->o = 0; - gp->scalar = 0; -} - -/* ---------------------- pointers ----------------------------- */ - -static t_class *ptrobj_class; - -struct t_typedout { - t_symbol *type; - t_outlet *outlet; -}; - -struct t_ptrobj : t_object { - t_gpointer gp; - t_typedout *typedout; - int ntypedout; - t_outlet *otherout; - t_outlet *bangout; -}; - -static void *ptrobj_new(t_symbol *classname, int argc, t_atom *argv) { - t_ptrobj *x = (t_ptrobj *)pd_new(ptrobj_class); - t_typedout *to; - gpointer_init(&x->gp); - x->typedout = to = (t_typedout *)getbytes(argc * sizeof (*to)); - x->ntypedout = argc; - for (int n=argc; n--; to++) { - to->outlet = outlet_new(x,&s_pointer); - to->type = canvas_makebindsym(atom_getsymbol(argv++)); - } - x->otherout = outlet_new(x,&s_pointer); - x->bangout = outlet_new(x,&s_bang); - pointerinlet_new(x,&x->gp); - return x; -} - -static void ptrobj_traverse(t_ptrobj *x, t_symbol *s) { - t_canvas *canvas = (t_canvas *)pd_findbyclass(s, canvas_class); - if (canvas) gpointer_setcanvas(&x->gp, canvas, 0); - else error("list '%s' not found", s->name); -} - -static void ptrobj_vnext(t_ptrobj *x, float f) { - t_gpointer *gp = &x->gp; - int wantselected = f!=0; - if (!gp->o) {error("next: no current pointer"); return;} - if (gp->o->_class == array_class) {error("next: lists only, not arrays"); return;} - t_canvas *canvas = gp->canvas; - if (wantselected) {error("next: next-selected unsupported in desiredata"); return;} - /* if (wantselected && !canvas_isvisible(canvas)) {error("next: next-selected only works for a visible window"); return;} */ - t_gobj *gobj = gp->scalar; - if (!gobj) gobj = canvas->boxes->first(); - else gobj = gobj->next(); - while (gobj && (gobj->_class != scalar_class || wantselected)) gobj = gobj->next(); - if (gobj) { - t_typedout *to = x->typedout; - t_scalar *sc = (t_scalar *)gobj; - gp->scalar = sc; - for (int n = x->ntypedout; n--; to++) - if (to->type == sc->t) {to->outlet->send(&x->gp); return;} - x->otherout->send(&x->gp); - } else { - gpointer_unset(gp); - x->bangout->send(); - } -} - -static void ptrobj_next(t_ptrobj *x) {ptrobj_vnext(x, 0);} - -static void ptrobj_sendwindow(t_ptrobj *x, t_symbol *s, int argc, t_atom *argv) { - if (!gpointer_check(&x->gp, 1)) {error("bang: empty pointer"); return;} - t_canvas *canvas = gpointer_getcanvas(&x->gp); - if (argc && argv->a_type == A_SYMBOL) pd_typedmess(canvas_getcanvas(canvas), argv->a_symbol, argc-1, argv+1); - else error("send-window: no message?"); -} - -static void ptrobj_bang(t_ptrobj *x) { - t_typedout *to = x->typedout; - if (!gpointer_check(&x->gp, 1)) {error("bang: empty pointer"); return;} - t_symbol *tsym = gpointer_gettsym(&x->gp); - for (int n=x->ntypedout; n--; to++) if (to->type == tsym) {to->outlet->send(&x->gp); return;} - x->otherout->send(&x->gp); -} - -static void ptrobj_pointer(t_ptrobj *x, t_gpointer *gp) { - gpointer_unset(&x->gp); - gpointer_copy(gp, &x->gp); - ptrobj_bang(x); -} - -static void ptrobj_rewind(t_ptrobj *x) { - if (!gpointer_check(&x->gp, 1)) {error("rewind: empty pointer"); return;} - if (x->gp.o->_class == array_class) {error("rewind: sorry, unavailable for arrays"); return;} - gpointer_setcanvas(&x->gp, x->gp.canvas, 0); - ptrobj_bang(x); -} - -static void ptrobj_free(t_ptrobj *x) { - free(x->typedout); - gpointer_unset(&x->gp); -} - -/* ---------------------- get ----------------------------- */ - -static t_class *get_class; -struct t_getvariable { - t_symbol *sym; - t_outlet *outlet; -}; -struct t_get : t_object { - t_symbol *tsym; - int nout; - t_getvariable *variables; -}; -static void *get_new(t_symbol *why, int argc, t_atom *argv) { - t_get *x = (t_get *)pd_new(get_class); - x->tsym = canvas_makebindsym(atom_getsymbolarg(0, argc, argv)); - if (argc) argc--, argv++; - t_getvariable *sp = x->variables = (t_getvariable *)getbytes(argc * sizeof (*x->variables)); - x->nout = argc; - for (int i=0; i < argc; i++, sp++) { - sp->sym = atom_getsymbolarg(i, argc, argv); - sp->outlet = outlet_new(x,0); - /* LATER connect with the template and set the outlet's type correctly. - We can't yet guarantee that the template is there before we hit this routine. */ - } - return x; -} - -static void get_pointer(t_get *x, t_gpointer *gp) { - int nitems = x->nout; - t_template *t = template_findbyname(x->tsym); - t_getvariable *vp; - TEMPLATE_CHECK(x->tsym,) - if (!gpointer_check(gp, 0)) {error("stale or empty pointer"); return;} - t_word *vec = gpointer_word(gp); - vp = x->variables + nitems-1; - for (int i=nitems-1; i>=0; i--, vp--) { - int onset, type; - t_symbol *arraytype; - if (template_find_field(t, vp->sym, &onset, &type, &arraytype)) { - if (type == DT_FLOAT ) vp->outlet->send( *(t_float *)(((char *)vec) + onset)); - else if (type == DT_SYMBOL) vp->outlet->send(*(t_symbol **)(((char *)vec) + onset)); - else error("%s.%s is not a number or symbol", t->sym->name, vp->sym->name); - } else error("%s.%s: no such field", t->sym->name, vp->sym->name); - } -} - -static void get_free(t_get *x) {free(x->variables);} - -/* ---------------------- set ----------------------------- */ - -static t_class *set_class; - -struct t_setvariable { - t_symbol *sym; - union word w; -}; - -struct t_set : t_object { - t_gpointer gp; - t_symbol *tsym; - int nin; - int issymbol; - t_setvariable *variables; -}; - -static void *set_new(t_symbol *why, int argc, t_atom *argv) { - t_set *x = (t_set *)pd_new(set_class); - if (argc && (argv[0].a_type == A_SYMBOL) && !strcmp(argv[0].a_symbol->name,"-symbol")) { - x->issymbol = 1; - argc--; - argv++; - } - else x->issymbol = 0; - x->tsym = canvas_makebindsym(atom_getsymbolarg(0, argc, argv)); - if (argc) argc--, argv++; - t_setvariable *sp = x->variables = (t_setvariable *)getbytes(argc * sizeof (*x->variables)); - x->nin = argc; - if (argc) { - for (int i=0; isym = atom_getsymbolarg(i, argc, argv); - if (x->issymbol) sp->w.w_symbol = &s_; - else sp->w.w_float = 0; - if (i) { - if (x->issymbol) symbolinlet_new(x,&sp->w.w_symbol); - else floatinlet_new(x, &sp->w.w_float); - } - } - } - pointerinlet_new(x,&x->gp); - gpointer_init(&x->gp); - return x; -} - -static void set_bang(t_set *x) { - int nitems = x->nin; - t_template *t = template_findbyname(x->tsym); - t_gpointer *gp = &x->gp; - TEMPLATE_CHECK(x->tsym,) - if (!gpointer_check(gp, 0)) {error("empty pointer"); return;} - if (gpointer_gettsym(gp) != x->tsym) { - error("%s: got wrong template (%s)",x->tsym->name,gpointer_gettsym(gp)->name); - return; - } - if (!nitems) return; - t_word *vec = gpointer_word(gp); - t_setvariable *vp=x->variables; - if (x->issymbol) for (int i=0; isym, vec, vp->w.w_symbol, 1); - else for (int i=0; isym, vec, vp->w.w_float, 1); - scalar_redraw(gp->scalar, gpointer_getcanvas(gp)); /* but ought to use owner_array->gp.scalar */ -} - -static void set_float(t_set *x, t_float f) { - if (x->nin && !x->issymbol) {x->variables[0].w.w_float = f; set_bang(x);} - else error("type mismatch or no field specified"); -} -static void set_symbol(t_set *x, t_symbol *s) { - if (x->nin && x->issymbol) {x->variables[0].w.w_symbol = s; set_bang(x);} - else error("type mismatch or no field specified"); -} - -static void set_free(t_set *x) { - free(x->variables); - gpointer_unset(&x->gp); -} - -/* ---------------------- elem ----------------------------- */ - -static t_class *elem_class; - -struct t_elem : t_object { - t_symbol *tsym; - t_symbol *fieldsym; - t_gpointer gp; - t_gpointer gparent; -}; - -static void *elem_new(t_symbol *tsym, t_symbol *fieldsym) { - t_elem *x = (t_elem *)pd_new(elem_class); - x->tsym = canvas_makebindsym(tsym); - x->fieldsym = fieldsym; - gpointer_init(&x->gp); - gpointer_init(&x->gparent); - pointerinlet_new(x,&x->gparent); - outlet_new(x,&s_pointer); - return x; -} - -static void elem_float(t_elem *x, t_float f) { - int indx = (int)f, nitems, onset; - t_symbol *fieldsym = x->fieldsym, *elemtsym; - t_template *t = template_findbyname(x->tsym); - t_template *elemtemplate; - t_gpointer *gparent = &x->gparent; - t_array *array; - int elemsize, type; - if (!gpointer_check(gparent, 0)) {error("empty pointer"); return;} - if (gpointer_gettsym(gparent) != x->tsym) { - error("%s: got wrong template (%s)", x->tsym->name, gpointer_gettsym(gparent)->name); - return; - } - t_word *w = gpointer_word(gparent); - TEMPLATE_CHECK(x->tsym,) - if (!template_find_field(t, fieldsym, &onset, &type, &elemtsym)) { - error("couldn't find array field %s", fieldsym->name); - return; - } - if (type != DT_ARRAY) {error("element: field %s not of type array", fieldsym->name); return;} - if (!(elemtemplate = template_findbyname(elemtsym))) { - error("couldn't find field template %s", elemtsym->name); - return; - } - elemsize = elemtemplate->n * sizeof(t_word); - array = *(t_array **)(((char *)w) + onset); - nitems = array->n; - if (indx < 0) indx = 0; - if (indx >= nitems) indx = nitems-1; - gpointer_setarray(&x->gp, array, (t_word *)&array->vec[indx*elemsize]); - x->outlet->send(&x->gp); -} - -static void elem_free(t_elem *x, t_gpointer *gp) { - gpointer_unset(&x->gp); - gpointer_unset(&x->gparent); -} - -/* ---------------------- getsize ----------------------------- */ - -static t_class *getsize_class; - -struct t_getsize : t_object { - t_symbol *tsym; - t_symbol *fieldsym; -}; - -static void *getsize_new(t_symbol *tsym, t_symbol *fieldsym) { - t_getsize *x = (t_getsize *)pd_new(getsize_class); - x->tsym = canvas_makebindsym(tsym); - x->fieldsym = fieldsym; - outlet_new(x,&s_float); - return x; -} - -static void getsize_pointer(t_getsize *x, t_gpointer *gp) { - int onset, type; - t_symbol *fieldsym = x->fieldsym, *elemtsym; - t_template *t = template_findbyname(x->tsym); - TEMPLATE_CHECK(x->tsym,) - if (!template_find_field(t, fieldsym, &onset, &type, &elemtsym)) { - error("couldn't find array field %s", fieldsym->name); - return; - } - if (type != DT_ARRAY) {error("field %s not of type array", fieldsym->name); return;} - if (!gpointer_check(gp, 0)) {error("stale or empty pointer"); return;} - if (gpointer_gettsym(gp) != x->tsym) { - error("%s: got wrong template (%s)", x->tsym->name, gpointer_gettsym(gp)->name); - return; - } - t_word *w = gpointer_word(gp); - t_array *array = *(t_array **)(((char *)w) + onset); - x->outlet->send(float(array->n)); -} - -/* ---------------------- setsize ----------------------------- */ - -static t_class *setsize_class; - -struct t_setsize : t_object { - t_symbol *tsym; - t_symbol *fieldsym; - t_gpointer gp; -}; - -static void *setsize_new(t_symbol *tsym, t_symbol *fieldsym, t_floatarg newsize) { - t_setsize *x = (t_setsize *)pd_new(setsize_class); - x->tsym = canvas_makebindsym(tsym); - x->fieldsym = fieldsym; - gpointer_init(&x->gp); - pointerinlet_new(x,&x->gp); - return x; -} - -static void setsize_float(t_setsize *x, t_float f) { - int onset, type; - t_template *t = template_findbyname(x->tsym); - int newsize = (int)f; - t_gpointer *gp = &x->gp; - if (!gpointer_check(&x->gp, 0)) {error("empty pointer"); return;} - if (gpointer_gettsym(&x->gp) != x->tsym) { - error("%s: got wrong template (%s)", x->tsym->name, gpointer_gettsym(&x->gp)->name); - return; - } - t_word *w = gpointer_word(gp); - TEMPLATE_CHECK(x->tsym,) - t_symbol *elemtsym; - if (!template_find_field(t, x->fieldsym, &onset, &type, &elemtsym)) { - error("couldn't find array field %s", x->fieldsym->name); - return; - } - if (type != DT_ARRAY) {error("field %s not of type array", x->fieldsym->name); return;} - t_template *elemtemplate = template_findbyname(elemtsym); - if (!elemtemplate) { - error("couldn't find field template %s", elemtsym->name); - return; - } - int elemsize = elemtemplate->n * sizeof(t_word); - t_array *array = *(t_array **)(((char *)w) + onset); - if (elemsize != array->elemsize) bug("setsize_gpointer"); - int nitems = array->n; - if (newsize < 1) newsize = 1; - if (newsize == nitems) return; - - /* here there was something to erase the array before resizing it */ - - /* now do the resizing and, if growing, initialize new scalars */ - array->vec = (char *)resizealignedbytes(array->vec, elemsize * nitems, elemsize * newsize); - array->n = newsize; - if (newsize > nitems) { - char *newelem = &array->vec[nitems*elemsize]; - int nnew = newsize - nitems; - while (nnew--) { - word_init((t_word *)newelem, elemtemplate, gp); - newelem += elemsize; - } - } - gobj_changed(gpointer_getscalar(gp),0); -} - -static void setsize_free(t_setsize *x) {gpointer_unset(&x->gp);} - -/* ---------------------- append ----------------------------- */ - -static t_class *append_class; - -struct t_appendvariable { - t_symbol *sym; - t_float f; -}; - -struct t_append : t_object { - t_gpointer gp; - t_symbol *tsym; - int nin; - t_appendvariable *variables; -}; - -static void *append_new(t_symbol *why, int argc, t_atom *argv) { - t_append *x = (t_append *)pd_new(append_class); - x->tsym = canvas_makebindsym(atom_getsymbolarg(0, argc, argv)); - if (argc) argc--, argv++; - x->variables = (t_appendvariable *)getbytes(argc * sizeof (*x->variables)); - x->nin = argc; - if (argc) { - t_appendvariable *sp = x->variables; - for (int i=0; isym = atom_getsymbolarg(i, argc, argv); - sp->f = 0; - if (i) floatinlet_new(x,&sp->f); - } - } - pointerinlet_new(x,&x->gp); - outlet_new(x,&s_pointer); - gpointer_init(&x->gp); - return x; -} - -static void append_float(t_append *x, t_float f) { - int nitems = x->nin; - t_template *t = template_findbyname(x->tsym); - t_gpointer *gp = &x->gp; - TEMPLATE_CHECK(x->tsym,) - if (!gp->o) {error("no current pointer"); return;} - if (gp->o->_class == array_class) {error("lists only, not arrays"); return;} - t_canvas *canvas = gp->canvas; - if (!nitems) return; - x->variables[0].f = f; - t_scalar *sc = scalar_new(canvas,x->tsym); - if (!sc) {error("%s: couldn't create scalar", x->tsym->name); return;} - canvas->boxes->add(sc); - gobj_changed(sc,0); - gp->scalar = sc; - t_word *vec = sc->v; - t_appendvariable *vp=x->variables; - for (int i=0; isym, vec, vp->f, 1); - scalar_redraw(sc, canvas); - x->outlet->send(gp); -} - -static void append_free(t_append *x) { - free(x->variables); - gpointer_unset(&x->gp); -} - -/* ---------------------- sublist ----------------------------- */ - -static t_class *sublist_class; - -struct t_sublist : t_object { - t_symbol *tsym; - t_symbol *fieldsym; - t_gpointer gp; -}; - -static void *sublist_new(t_symbol *tsym, t_symbol *fieldsym) { - t_sublist *x = (t_sublist *)pd_new(sublist_class); - x->tsym = canvas_makebindsym(tsym); - x->fieldsym = fieldsym; - gpointer_init(&x->gp); - outlet_new(x,&s_pointer); - return x; -} - -static void sublist_pointer(t_sublist *x, t_gpointer *gp) { - t_symbol *dummy; - t_template *t = template_findbyname(x->tsym); - int onset, type; - TEMPLATE_CHECK(x->tsym,) - if (!gpointer_check(gp, 0)) {error("stale or empty pointer"); return;} - if (!template_find_field(t, x->fieldsym, &onset, &type, &dummy)) { - error("couldn't find field %s", x->fieldsym->name); - return; - } - if (type != DT_CANVAS) {error("field %s not of type list", x->fieldsym->name); return;} - t_word *w = gpointer_word(gp); - gpointer_setcanvas(&x->gp, *(t_canvas **)(((char *)w) + onset), 0); - x->outlet->send(&x->gp); -} - -static void sublist_free(t_sublist *x, t_gpointer *gp) {gpointer_unset(&x->gp);} - -static void g_traversal_setup() { - t_class *c = ptrobj_class = class_new2("pointer",ptrobj_new,ptrobj_free,sizeof(t_ptrobj),0,"*"); - class_addmethod2(c, ptrobj_traverse,"traverse", "s"); - class_addmethod2(c, ptrobj_next,"next",""); - class_addmethod2(c, ptrobj_vnext,"vnext","F"); - class_addmethod2(c, ptrobj_sendwindow,"send-window","*"); - class_addmethod2(c, ptrobj_rewind, "rewind",""); - class_addpointer(c, ptrobj_pointer); - class_addbang(c, ptrobj_bang); - get_class = class_new2("get",get_new,get_free,sizeof(t_get),0,"*"); - class_addpointer(get_class, get_pointer); - set_class = class_new2("set",set_new,set_free,sizeof(t_set),0,"*"); - class_addfloat(set_class, set_float); - class_addsymbol(set_class, set_symbol); - class_addbang(set_class, set_bang); - elem_class = class_new2("element",elem_new,elem_free,sizeof(t_elem),0,"SS"); - class_addfloat(elem_class, elem_float); - getsize_class = class_new2("getsize",getsize_new,0,sizeof(t_getsize),0,"SS"); - class_addpointer(getsize_class, getsize_pointer); - setsize_class = class_new2("setsize",setsize_new,setsize_free,sizeof(t_setsize),0,"SSFF"); - class_addfloat(setsize_class, setsize_float); - append_class = class_new2("append",append_new,append_free,sizeof(t_append),0,"*"); - class_addfloat(append_class, append_float); - sublist_class = class_new2("sublist",sublist_new,sublist_free,sizeof(t_sublist),0,"SS"); - class_addpointer(sublist_class, sublist_pointer); -} - -/*EXTERN*/ void canvas_savecontainerto(t_canvas *x, t_binbuf *b); - -struct t_iemgui : t_object { - t_canvas *canvas; - int h,w; - int ldx,ldy; - int isa; /* bit 0: loadinit; bit 20: scale */ - int font_style, fontsize; - int fcol,bcol,lcol; /* foreground, background, label colors */ - t_symbol *snd,*rcv,*lab; /* send, receive, label symbols */ -}; - -struct t_bng : t_iemgui { - int count; - int ftbreak; /* flash time break (ms) */ - int fthold; /* flash time hold (ms) */ -}; - -struct t_slider : t_iemgui { - t_float val; - t_float min,max; - int steady; - int is_log; - int orient; -}; - -struct t_radio : t_iemgui { - int on, on_old; - int change; - int number; - t_atom at[2]; - int orient; - int oldstyle; -}; - -struct t_toggle : t_iemgui { - float on; - float nonzero; -}; - -struct t_cnv : t_iemgui { - t_atom at[3]; - int vis_w, vis_h; -}; - -struct t_vu : t_iemgui { - int led_size; - int peak,rms; - float fp,fr; - int scale; -}; - -struct t_nbx : t_iemgui { - double val; - double min,max; - double k; - char buf[32]; - int log_height; - int change; - int is_log; -}; - -struct t_foo { int argc; t_atom *argv; t_binbuf *b; }; -static int pd_pickle(t_foo *foo, const char *fmt, ...); -static int pd_savehead(t_binbuf *b, t_iemgui *x, const char *name); - -static t_class *radio_class, *slider_class; -static t_symbol *sym_hdl, *sym_hradio, *sym_vdl, *sym_vradio, *sym_vsl, *sym_vslider; - -t_class *dummy_class; -/*static*/ t_class *text_class; -static t_class *mresp_class; -static t_class *message_class; -static t_class *gatom_class; - -void canvas_text(t_canvas *gl, t_symbol *s, int argc, t_atom *argv) { - t_text *x = (t_text *)pd_new(text_class); - x->binbuf = binbuf_new(); - x->x = atom_getintarg(0, argc, argv); - x->y = atom_getintarg(1, argc, argv); - if (argc > 2) binbuf_restore(x->binbuf, argc-2, argv+2); - canvas_add(gl,x); - pd_set_newest(x); -} - -void canvas_getargs(int *argcp, t_atom **argvp) { - t_canvasenvironment *e = canvas_getenv(canvas_getcurrent()); - *argcp = e->argc; - *argvp = e->argv; -} - -static void canvas_objtext(t_canvas *gl, int xpix, int ypix, t_binbuf *b, int index=-1) { - t_text *x=0; - int argc, n; - t_atom *argv; - char *s; - newest = 0; - binbuf_gettext(b,&s,&n); - pd_pushsym(gl); - canvas_getargs(&argc, &argv); - binbuf_eval(b, &pd_objectmaker, argc, argv); - if (binbuf_getnatom(b)) { - if (!newest) { - char *s = binbuf_gettext2(b); - error("couldn't create %s",s); - free(s); - } else if (!(x = pd_checkobject(newest))) { - char *s = binbuf_gettext2(b); - error("didn't return a patchable object: %s",s); - free(s); - } - } - /* make a "broken object", that is, one that should appear with a dashed contour. */ - if (!x) { - x = (t_text *)pd_new(dummy_class); - pd_set_newest(x); - } - x->binbuf = b; - x->x = xpix; - x->y = ypix; - canvas_add(gl,x,index); - if (x->_class== vinlet_class) canvas_resortinlets(canvas_getcanvas(gl)); - if (x->_class==voutlet_class) canvas_resortoutlets(canvas_getcanvas(gl)); - pd_popsym(gl); -} - -void canvas_obj(t_canvas *gl, t_symbol *s, int argc, t_atom *argv) { - t_binbuf *b = binbuf_new(); - if (argc >= 2) { - binbuf_restore(b, argc-2, argv+2); - canvas_objtext(gl, atom_getintarg(0, argc, argv), atom_getintarg(1, argc, argv), b); - } else canvas_objtext(gl,0,0,b); -} - -void canvas_objfor(t_canvas *gl, t_text *x, int argc, t_atom *argv) { - x->binbuf = binbuf_new(); - x->x = atom_getintarg(0, argc, argv); - x->y = atom_getintarg(1, argc, argv); - if (argc > 2) binbuf_restore(x->binbuf, argc-2, argv+2); - canvas_add(gl,x); -} - -struct t_mresp : t_pd { - t_outlet *outlet; -}; -struct t_message : t_text { - t_mresp mresp; - t_canvas *canvas; -}; - -/* where is mresp_pointer ? */ -static void mresp_bang(t_mresp *x) {x->outlet->send();} -static void mresp_float( t_mresp *x, t_float v) {x->outlet->send(v);} -static void mresp_symbol( t_mresp *x, t_symbol *v) {x->outlet->send(v);} -static void mresp_list(t_mresp *x, t_symbol *s, int argc, t_atom *argv) {x->outlet->send( argc,argv);} -static void mresp_anything(t_mresp *x, t_symbol *s, int argc, t_atom *argv) {x->outlet->send(s,argc,argv);} - -static void message_bang(t_message *x) { binbuf_eval(x->binbuf,&x->mresp,0,0);} -static void message_float(t_message *x, t_float f) {t_atom at; SETFLOAT(&at, f); binbuf_eval(x->binbuf,&x->mresp,1,&at);} -static void message_symbol(t_message *x, t_symbol *s) {t_atom at; SETSYMBOL(&at, s); binbuf_eval(x->binbuf,&x->mresp,1,&at);} -static void message_list(t_message *x, t_symbol *s, int argc, t_atom *argv){binbuf_eval(x->binbuf, &x->mresp, argc, argv);} -static void message_add2(t_message *x, t_symbol *s, int argc, t_atom *argv){binbuf_add(x->binbuf, argc, argv); gobj_changed(x,"binbuf");} -static void message_set(t_message *x, t_symbol *s, int argc, t_atom *argv) {binbuf_clear(x->binbuf); message_add2(x,s,argc,argv);} -static void message_add(t_message *x, t_symbol *s, int argc, t_atom *argv) -{binbuf_add(x->binbuf, argc, argv); binbuf_addsemi(x->binbuf); gobj_changed(x,"binbuf");} -static void message_addcomma(t_message *x) -{t_atom a; SETCOMMA(&a); binbuf_add(x->binbuf, 1, &a); gobj_changed(x,"binbuf");} -static void message_adddollar(t_message *x, t_floatarg f) -{t_atom a; SETDOLLAR(&a, f<0?0:(int)f); binbuf_add(x->binbuf, 1, &a); gobj_changed(x,"binbuf");} -//static void message_adddollsym(t_message *x, t_symbol *s) -//{t_atom a; SETDOLLSYM(&a, s); binbuf_add(x->binbuf, 1, &a); gobj_changed(x,"binbuf");} - -static void message_adddollsym(t_message *x, t_symbol *s) { - t_atom a; - SETDOLLSYM(&a, symprintf("$%s",s->name)); - binbuf_add(x->binbuf, 1, &a); - gobj_changed(x,"binbuf"); -} - -static void message_addsemi(t_message *x) {message_add(x,0,0,0);} - -void canvas_msg(t_canvas *gl, t_symbol *s, int argc, t_atom *argv) { - t_message *x = (t_message *)pd_new(message_class); - x->mresp._class = mresp_class; - x->mresp.outlet = outlet_new(x,&s_float); - x->binbuf = binbuf_new(); - x->canvas = gl; - pd_set_newest(x); - if (argc > 1) { - x->x = atom_getintarg(0, argc, argv); - x->y = atom_getintarg(1, argc, argv); - if (argc > 2) binbuf_restore(x->binbuf, argc-2, argv+2); - } else { - x->x = 0; - x->y = 0; - } - canvas_add(gl,x); -} - -struct t_gatom : t_text { - t_atom atom; /* this holds the value and the type */ - t_canvas *canvas; /* owning canvas */ - t_float max,min; - t_symbol *label; /* symbol to show as label next to box */ - t_symbol *rcv; - t_symbol *snd; - char wherelabel; /* 0-3 for left, right, up, down */ - t_symbol *expanded_to; /* snd after $0, $1, ... expansion */ - short width; -}; - -/* prepend "-" as necessary to avoid empty strings, so we can use them in Pd messages. - A more complete solution would be to introduce some quoting mechanism; - but then we'd be much more complicated. */ -static t_symbol *gatom_escapit(t_symbol *s) { - if (!s || !*s->name) return gensym("-"); - if (*s->name == '-') { - char shmo[1000]; - snprintf(shmo,1000,"-%s",s->name); - shmo[999] = 0; - return gensym(shmo); - } - else return s; -} - -/* undo previous operation: strip leading "-" if found. */ -static t_symbol *gatom_unescapit(t_symbol *s) { - if (*s->name == '-') return gensym(s->name+1); - return s; -} - -static void gatom_set(t_gatom *x, t_symbol *s, int argc, t_atom *argv) { - t_atom oldatom = x->atom; - if (!argc) return; - if (x->atom.a_type == A_FLOAT) { - SETFLOAT( &x->atom,atom_getfloat(argv)); if (x->atom.a_float !=oldatom.a_float ) gobj_changed(x,"atom"); - } else if (x->atom.a_type == A_SYMBOL) { - SETSYMBOL(&x->atom,atom_getsymbol(argv)); if (x->atom.a_symbol!=oldatom.a_symbol) gobj_changed(x,"atom"); - } -} - -static void gatom_bang(t_gatom *x) { - t_symbol *s = x->expanded_to; - t_outlet *o = x->outlet; - if (x->atom.a_type == A_FLOAT) { - if (o) o->send(x->atom.a_float); - if (*s->name && s->thing) {if (x->snd == x->rcv) goto err; pd_float(s->thing, x->atom.a_float);} - } else if (x->atom.a_type == A_SYMBOL) { - if (o) o->send(x->atom.a_symbol); - if (*s->name && s->thing) {if (x->snd == x->rcv) goto err; pd_symbol(s->thing, x->atom.a_symbol);} - } - return; -err: - error("%s: atom with same send/receive name (infinite loop)", x->snd->name); -} - -static void gatom_float(t_gatom *x, t_float f) {t_atom at; SETFLOAT( &at, f); gatom_set(x, 0, 1, &at); gatom_bang(x);} -static void gatom_symbol(t_gatom *x, t_symbol *s) {t_atom at; SETSYMBOL(&at, s); gatom_set(x, 0, 1, &at); gatom_bang(x);} - -static void gatom_reload(t_gatom *x, t_symbol *sel, int argc, t_atom *argv) { - int width; t_float wherelabel; - t_symbol *rcv,*snd; - if (!pd_scanargs(argc,argv,"ifffaaa",&width,&x->min,&x->max,&wherelabel,&x->label,&rcv,&snd)) return; - gobj_changed(x,0); - SET(label,gatom_unescapit(x->label)); - if (x->min>=x->max) {SET(min,0); SET(max,0);} - CLAMP(width,1,80); - SET(width,width); - SET(wherelabel,(int)wherelabel&3); - if (x->rcv) pd_unbind(x, canvas_realizedollar(x->canvas, x->rcv)); - SET(rcv,gatom_unescapit(rcv)); - if (x->rcv) pd_bind( x, canvas_realizedollar(x->canvas, x->rcv)); - SET(snd,gatom_unescapit(snd)); - SET(expanded_to,canvas_realizedollar(x->canvas, x->snd)); -} - -/* We need a list method because, since there's both an "inlet" and a - "nofirstin" flag, the standard list behavior gets confused. */ -static void gatom_list(t_gatom *x, t_symbol *s, int argc, t_atom *argv) { - if (!argc) gatom_bang(x); - else if (argv->a_type == A_FLOAT) gatom_float(x, argv->a_w.w_float); - else if (argv->a_type == A_SYMBOL) gatom_symbol(x, argv->a_w.w_symbol); - else error("gatom_list: need float or symbol"); -} - -void canvas_atom(t_canvas *gl, t_atomtype type, int argc, t_atom *argv) { - t_gatom *x = (t_gatom *)pd_new(gatom_class); - if (type == A_FLOAT) {SET(width, 5); SETFLOAT(&x->atom, 0);} - else {SET(width,10); SETSYMBOL(&x->atom, &s_symbol);} - x->canvas = gl; - SET(min,0); - SET(max,0); - SET(wherelabel,0); - SET(label,0); - SET(rcv,0); - SET(snd,0); - x->expanded_to = &s_; //??? - x->binbuf = binbuf_new(); - binbuf_add(x->binbuf, 1, &x->atom); - SET(x,atom_getintarg(0, argc, argv)); - SET(y,atom_getintarg(1, argc, argv)); - inlet_new(x,x,0,0); - outlet_new(x, type == A_FLOAT ? &s_float: &s_symbol); - if (argc>2) gatom_reload(x,&s_,argc-2,argv+2); - canvas_add(gl,x); - pd_set_newest(x); -} - -void canvas_floatatom( t_canvas *gl, t_symbol *s, int argc, t_atom *argv) {canvas_atom(gl, A_FLOAT, argc, argv);} -void canvas_symbolatom(t_canvas *gl, t_symbol *s, int argc, t_atom *argv) {canvas_atom(gl, A_SYMBOL, argc, argv);} -static void gatom_free(t_gatom *x) {if (x->rcv) pd_unbind(x, canvas_realizedollar(x->canvas, x->rcv));} - -extern "C" void text_save(t_gobj *z, t_binbuf *b) { - t_text *x = (t_text *)z; - t_canvas *c = (t_canvas *)z; /* in case it is */ - if (x->_class == message_class) { - binbuf_addv(b,"ttii","#X","msg", (t_int)x->x, (t_int)x->y); - binbuf_addbinbuf(b, x->binbuf); - } else if (x->_class == gatom_class) { - t_gatom *g = (t_gatom *)x; - t_symbol *sel = g->atom.a_type==A_SYMBOL? gensym("symbolatom") : gensym("floatatom"); - binbuf_addv(b,"tsii","#X", sel, (t_int)x->x, (t_int)x->y); - binbuf_addv(b,"iffi", (t_int)g->width, g->min, g->max, (t_int)g->wherelabel); - binbuf_addv(b,"sss", gatom_escapit(g->label), gatom_escapit(g->rcv), gatom_escapit(g->snd)); - } else if (x->_class == text_class) { - binbuf_addv(b, "ttii","#X","text", (t_int)x->x, (t_int)x->y); - binbuf_addbinbuf(b, x->binbuf); - } else { - if (zgetfn(x,gensym("saveto")) && !(x->_class==canvas_class && (canvas_isabstraction(c) || canvas_istable(c)))) { - mess1(x,gensym("saveto"),b); - binbuf_addv(b,"ttii","#X","restore", (t_int)x->x, (t_int)x->y); - } else { - binbuf_addv(b,"ttii","#X","obj", (t_int)x->x, (t_int)x->y); - } - if (x->binbuf) binbuf_addbinbuf(b, x->binbuf); /*else bug("binbuf missing at #X restore !!!");*/ - } - binbuf_addv(b, ";"); -} - -static t_binbuf *canvas_cut_wires(t_canvas *x, t_gobj *o) { - t_binbuf *buf = binbuf_new(); - canvas_wires_each(oc,t,x) { - if ((o==t.from) != (o==t.to)) - binbuf_addv(buf,"ttiiii;","#X","connect", t.from->dix->index, t.outlet, t.to->dix->index, t.inlet); - } - return buf; -} -static void canvas_paste_wires(t_canvas *x, t_binbuf *buf) { - pd_bind(x,gensym("#X")); - binbuf_eval(buf,0,0,0); - pd_unbind(x,gensym("#X")); -} - -static void text_setto(t_text *x, t_canvas *canvas, char *buf, int bufsize) { - if (x->_class == message_class || x->_class == gatom_class || x->_class == text_class) { - binbuf_text(x->binbuf, buf, bufsize); - gobj_changed(x,"binbuf"); - pd_set_newest(x); - return; - } - t_binbuf *b = binbuf_new(); - binbuf_text(b, buf, bufsize); - int natom1 = binbuf_getnatom(x->binbuf); t_atom *vec1 = binbuf_getvec(x->binbuf); - int natom2 = binbuf_getnatom(b); t_atom *vec2 = binbuf_getvec(b); - /* special case: if pd args change just pass the message on. */ - if (natom1 >= 1 && natom2 >= 1 && - vec1[0].a_type == A_SYMBOL && vec1[0].a_symbol == s_pd && - vec2[0].a_type == A_SYMBOL && vec2[0].a_symbol == s_pd) { - typedmess(x,gensym("rename"),natom2-1,vec2+1); - binbuf_free(x->binbuf); - x->binbuf = b; - pd_set_newest(x); /* fake object creation, for simplicity of client */ - } else { - int xwas=x->x, ywas=x->y; - int backupi = x->dix->index; - t_binbuf *buf = canvas_cut_wires(canvas_getcanvas(canvas),x); - canvas_delete(canvas,x); - canvas_objtext(canvas,xwas,ywas,b,backupi); - t_pd *backup = newest; - post("backupi=%d newest->index=%ld",backupi,((t_object *)newest)->dix->index); - if (newest && pd_class(newest) == canvas_class) canvas_loadbang((t_canvas *)newest); - canvas_paste_wires(canvas_getcanvas(canvas), buf); - newest = backup; - } -} - -t_object *symbol2opointer(t_symbol *s) { - t_text *o; - if (sscanf(s->name,"x%lx",(long*)&o)<1) {error("expected object-id"); return 0;} - if (!object_table->exists(o)) {error("%s target is not a currently valid pointer",s->name); return 0;} - if ((object_table->get(o)&1)==0) { - error("%s target is zombie? object_table says '%ld'",s->name,object_table->get(o)); - return 0; - } - if (!o->_class->patchable) {error("%s target not a patchable object",s->name); return 0;} - return o; -} - -t_object *atom2opointer(t_atom *a) {return symbol2opointer(atom_getsymbol(a));} - -static void canvas_text_setto(t_canvas *x, t_symbol *s, int argc, t_atom *argv) { - t_text *o = atom2opointer(&argv[0]); if (!o) return; - char str[4096]; - for (int i=0; ix=(int)px; gobj_changed(o,"x"); - o->y=(int)py; gobj_changed(o,"y"); -} -static void canvas_object_delete(t_canvas *x, t_symbol *name) { - t_text *o = symbol2opointer(name); if (!o) return; - fprintf(stderr,"canvas_object_delete %p\n",o); - canvas_delete(x,o); -} - -static void canvas_object_get_tips(t_canvas *x, t_symbol *name) { - t_text *o = symbol2opointer(name); if (!o) return; - std::ostringstream foo; - if (o->_class->firstin) foo << o->_class->firsttip->name; - int n = obj_ninlets(x); - for (int i=!!o->_class->firstin; iinlet,i); - sys_mgui(o,"tips=","S",foo.str().data()); -} - -extern "C" void open_via_helppath(const char *name, const char *dir); -static void canvas_object_help(t_canvas *x, t_symbol *name) { - t_text *o = symbol2opointer(name); if (!o) return; - const char *hn = class_gethelpname(o->_class); - bool suffixed = strcmp(hn+strlen(hn)-3, ".pd")==0; - char *buf; - asprintf(&buf,"%s%s",hn,suffixed?"":".pd"); - open_via_helppath(buf, o->_class->externdir->name); - free(buf); -} - -static void canvas_reorder_last(t_canvas *x, int dest) { - int i = x->boxes->last()->dix->index; - t_gobj *foo = x->boxes->get(i); - x->boxes->remove(i); - fprintf(stderr,"canvas_reorder_last(x=%p,dest=%d) i=%d\n",x,dest,i); - fprintf(stderr,"foo=%p\n",foo); - if (!foo) {bug("couldn't remove box #%d",i); return;} - foo->dix->index = dest; - x->boxes->add(foo); -} - -/* this supposes that $2=#X */ -static void canvas_object_insert(t_canvas *x, t_symbol *s, int argc, t_atom *argv) { - if (argc<1) {error("not enough args"); return;} - if (argv[0].a_type != A_FLOAT) {error("$1 must be float"); return;} - int i = atom_getint(argv); - if (argv[2].a_type != A_SYMBOL) {error("$2 must be symbol"); return;} - s = argv[2].a_symbol; - pd_typedmess(x,s,argc-3,argv+3); - canvas_reorder_last(x,i); -/*err: pd_popsym(x);*/ -} - -static void g_text_setup() { - t_class *c; - text_class = class_new2("text", 0,0,sizeof(t_text),CLASS_NOINLET|CLASS_PATCHABLE,0); - dummy_class = class_new2("dummy",0,0,sizeof(t_text),CLASS_NOINLET|CLASS_PATCHABLE,0); - - c = mresp_class = class_new2("messresponder",0,0,sizeof(t_text),CLASS_PD,""); - class_addbang( c, mresp_bang); - class_addfloat( c, (t_method) mresp_float); - class_addsymbol( c, mresp_symbol); - class_addlist( c, mresp_list); - class_addanything(c, mresp_anything); - - c = message_class = class_new2("message",0,0,sizeof(t_message),CLASS_PATCHABLE,""); - class_addbang(c, message_bang); - class_addfloat(c, message_float); - class_addsymbol(c, message_symbol); - class_addlist(c, message_list); - class_addanything(c, message_list); - class_addmethod2(c, message_set, "set","*"); - class_addmethod2(c, message_add, "add","*"); - class_addmethod2(c, message_add2,"add2","*"); - class_addmethod2(c, message_addcomma, "addcomma", ""); - class_addmethod2(c, message_addsemi, "addsemi", ""); - class_addmethod2(c, message_adddollar, "adddollar", "f"); - class_addmethod2(c, message_adddollsym, "adddollsym","s"); - - c = gatom_class = class_new2("gatom",0,gatom_free,sizeof(t_gatom),CLASS_NOINLET|CLASS_PATCHABLE,""); - class_addbang(c, gatom_bang); - class_addfloat(c, gatom_float); - class_addsymbol(c, gatom_symbol); - class_addlist(c, gatom_list); - class_addmethod2(c, gatom_set, "set","*"); - class_addmethod2(c, gatom_reload, "reload","*"); -} - -static int iemgui_color_hex[]= { - 0xfcfcfc, 0xa0a0a0, 0x404040, 0xfce0e0, 0xfce0c0, 0xfcfcc8, 0xd8fcd8, 0xd8fcfc, 0xdce4fc, 0xf8d8fc, - 0xe0e0e0, 0x7c7c7c, 0x202020, 0xfc2828, 0xfcac44, 0xe8e828, 0x14e814, 0x28f4f4, 0x3c50fc, 0xf430f0, - 0xbcbcbc, 0x606060, 0x000000, 0x8c0808, 0x583000, 0x782814, 0x285014, 0x004450, 0x001488, 0x580050 -}; - -static int iemgui_clip_size(int size) {return max(8,size);} - -int convert_color2(int x) { - return ~ (((0xfc0000&x)>>6) | ((0xfc00&x)>>4) | ((0xfc&x)>>2)); -} - -static int convert_color(int x) { - if (x>=0) return iemgui_color_hex[x%30]; - x=~x; - return ((x&0x3f000)<<6) | ((x&0xfc0)<<4) | ((x&0x3f)<<2); -} - -static void iemgui_send(t_iemgui *x, t_symbol *s) { - SET(snd,canvas_realizedollar(x->canvas, s)); - if (x->snd==s_empty) SET(snd,0); -} - -static void iemgui_receive(t_iemgui *x, t_symbol *s) { - t_symbol *rcv = canvas_realizedollar(x->canvas, s); - if (rcv==s_empty) rcv=0; - if (rcv==x->rcv) return; - if(x->rcv) pd_unbind(x,x->rcv); - SET(rcv,rcv); - if(x->rcv) pd_bind(x,x->rcv); -} - -static void iemgui_label(t_iemgui *x, t_symbol *s) { - SET(lab,s==s_empty?0:s); -} -static void iemgui_label_pos(t_iemgui *x, t_float ldx, t_float ldy) { - SET(ldx,(int)ldx); - SET(ldy,(int)ldy); -} -static void iemgui_label_font(t_iemgui *x, t_symbol *s, int ac, t_atom *av) { - SET(fontsize,max(4,(int)atom_getintarg(1, ac, av))); - SET(font_style,atom_getintarg(0, ac, av)); -} -static void iemgui_delta(t_iemgui *x, t_symbol *s, int ac, t_atom *av) { - SET(x,x->x+(int)atom_getintarg(0, ac, av)); - SET(y,x->y+(int)atom_getintarg(1, ac, av)); -} -static void iemgui_pos(t_iemgui *x, t_symbol *s, int ac, t_atom *av) { - SET(x,x->x+(int)atom_getintarg(0, ac, av)); - SET(y,x->y+(int)atom_getintarg(1, ac, av)); -} - -static int iemgui_compatible_col(int i) {return i>=0 ? iemgui_color_hex[i%30] : (~i)&0xffffff;} - -static void iemgui_color(t_iemgui *x, t_symbol *s, int ac, t_atom *av) { - int i=0; - SET(bcol,iemgui_compatible_col(atom_getintarg(i++, ac, av))); - if(ac > 2) SET(fcol,iemgui_compatible_col(atom_getintarg(i++, ac, av))); - SET(lcol,iemgui_compatible_col(atom_getintarg(i++, ac, av))); -} - -#define NEXT p=va_arg(val,void*); /*printf("p=%p\n",p);*/ -int pd_vscanargs(int argc, t_atom *argv, const char *fmt, va_list val) { - int optional=0; - int i,j=0; - for (i=0; fmt[i]; i++) { - switch (fmt[i]) { - case 0: error("too many args"); return 0; - case '*': goto break1; /* rest is any type */ - case 'F': case 'f': case 'd': case 'i': case 'c': case 'b': - if (!IS_A_FLOAT(argv,j)) {error("expected float in $%d",i+1); return 0;} - j++; break; - case 'S': case 's': - if (!IS_A_SYMBOL(argv,j)) {error("expected symbol in $%d",i+1); return 0;} - j++; break; - case '?': break; - case 'a': - if (!IS_A_FLOAT(argv,j) && !IS_A_SYMBOL(argv,j)) {error("expected float or symbol in $%d",i+1); return 0;} - j++; break; - case ';': optional=1; break; - default: error("bad format string"); return 0; - } - } - if (jblah) relative offsets - into each struct... -*/ -int pd_vsaveargs(t_binbuf *b, const char *fmt, va_list val) { - t_atom a; - int i; - for (i=0; ; i++) { - switch (fmt[i]) { - case 0: goto break2; - case ';': continue; /* skip */ - case '?': case 'F': case 'S': break; /* skip */ - case 'd': SETFLOAT(&a,*(va_arg(val,double*))); break; - case 'f': SETFLOAT(&a,*(va_arg(val,float *))); break; - case 'i': SETFLOAT(&a,*(va_arg(val, int *))); break; - case 'b': SETFLOAT(&a,!!*(va_arg(val,int *))); break; - case 'c': /* colour, from IEM format to RGB 8:8:8 format */ - SETFLOAT(&a,convert_color2(*(va_arg(val, int *)))); break; - case 'a': - case 's': { t_symbol *s = *(va_arg(val,t_symbol**)); - SETSYMBOL(&a,s?s:s_empty); } break; - default: post("WARNING: bug using pd_saveargs()"); goto err; /* WHAT? */ - } - binbuf_add(b,1,&a); - } -break2: - binbuf_addv(b, ";"); - return 1; -err: - post("WARNING: pd_saveargs failed; fmt=%s, i=%d",fmt,i); - return 0; -} - -int pd_scanargs(int argc, t_atom *argv, const char *fmt, ...) { - int i; - va_list val; - va_start(val,fmt); - i=pd_vscanargs(argc,argv,fmt,val); - va_end(val); - return i; -} - -int pd_saveargs(t_binbuf *b, const char *fmt, ...) { - int i; - va_list val; - va_start(val,fmt); - i=pd_vsaveargs(b,fmt,val); - va_end(val); - return i; -} - -int pd_pickle(t_foo *foo, const char *fmt, ...) { - va_list val; - va_start(val,fmt); - int r = foo->b ? - pd_vsaveargs(foo->b,fmt,val) : - pd_vscanargs(foo->argc,foo->argv,fmt,val); - va_end(val); - return r; -} - -static int pd_savehead(t_binbuf *b, t_iemgui *x, const char *name) { - binbuf_addv(b, "ttiit","#X","obj", (t_int)x->x, (t_int)x->y, name); - return 1; -} - -void pd_upload(t_gobj *self) { - long alive = (long)object_table->get(self) & 1; - if (!alive) { - sys_mgui(self,"delete",""); - pd_free_zombie(self); - return; - } - t_binbuf *b = binbuf_new(); - t_class *c = self->_class; - t_text *x = (t_text *)self; - if (c==canvas_class) { - /* just the "#N canvas" line, not the contents */ - canvas_savecontainerto((t_canvas *)self,b); - canvas_savecoordsto((t_canvas *)self,b); /* this may be too early */ - binbuf_addv(b, "ttii", "#X","restore", (t_int)x->x, (t_int)x->y); - if (x->binbuf) { - //pd_print(x,"pd_upload"); - binbuf_addbinbuf(b, x->binbuf); - } else { - /*bug("binbuf missing at #X restore !!!");*/ - } - binbuf_addv(b, ";"); - } else { /* this was outside of the "else" for a while. why? I don't remember */ - c->savefn(self,b); - } - int n; - char *s; - appendix_save(self,b); - binbuf_gettext(b,&s,&n); - if (s[n-1]=='\n') n--; - if (c->patchable) { - sys_vgui("change x%lx x%lx %d {%.*s} %d %d %d\n",(long)self,(long)self->dix->canvas,self->dix->index,n,s, - obj_ninlets((t_text *)self), obj_noutlets((t_text *)self), x->_class!=dummy_class); - } else { - sys_vgui("change x%lx x%lx %d {%.*s}\n",(long)self,(long)self->dix->canvas,self->dix->index,n,s); - } - binbuf_free(b); - free(s); - if (c==canvas_class) { - t_canvas *can = (t_canvas *)self; - sys_mgui(self,"name=","s",can->name); - sys_mgui(self,"folder=","s",canvas_getenv(can)->dir); - sys_mgui(self,"havewindow=","i",can->havewindow); - } - if (c==gatom_class) { - t_gatom *g = (t_gatom *)x; - if (g->atom.a_type==A_SYMBOL) sys_mgui(g,"set","s",g->atom.a_symbol); - else sys_mgui(g,"set","f",g->atom.a_float); - } - if (object_table->exists(self)) { - object_table->set(self,object_table->get(self)|2); /* has been uploaded */ - } else post("object_table is broken"); -} - -void sys_mgui(void *self_, const char *sel, const char *fmt, ...) { - t_gobj *self = (t_gobj *)self_; - char buf[4096]; - int i=0, n=sizeof(buf); - va_list val; - va_start(val,fmt); - i+=snprintf(buf+i,n-i,"x%lx %s", (long)self, sel); - if (i>=n) goto over; - while (*fmt) { - switch (*fmt) { - case 'f': case 'd': i+=snprintf(buf+i,n-i," %f",va_arg(val,double)); break; - case 'i': i+=snprintf(buf+i,n-i," %d",va_arg(val,int)); break; - case 'p': i+=snprintf(buf+i,n-i," x%lx",(long)va_arg(val,void*)); break; - /* - case 's': i+=snprintf(buf+i,n-i," \"%s\"",va_arg(val,t_symbol *)->name); break; - case 'S': i+=snprintf(buf+i,n-i," \"%s\"",va_arg(val,const char *)); break; - */ - case 's': i+=snprintf(buf+i,n-i," {%s}",va_arg(val,t_symbol *)->name); break; - case 'S': i+=snprintf(buf+i,n-i," {%s}",va_arg(val,const char *)); break; - } - if (i>=n) goto over; - fmt++; - } - va_end(val); - i+=snprintf(buf+i,n-i,"\n"); - if (i>=n) goto over; - sys_gui(buf); - return; -over: - post("sys_mgui: can't send: buffer overflow"); - abort(); -} - -static void iemgui_subclass (t_class *c) { - class_addmethod2(c, iemgui_delta, "delta","*"); - class_addmethod2(c, iemgui_pos, "pos","*"); - class_addmethod2(c, iemgui_color, "color","*"); - class_addmethod2(c, iemgui_send, "send","S"); - class_addmethod2(c, iemgui_receive, "receive","S"); - class_addmethod2(c, iemgui_label, "label","S"); - class_addmethod2(c, iemgui_label_pos, "label_pos","ff"); - class_addmethod2(c, iemgui_label_font, "label_font","*"); -} - -t_symbol *pd_makebindsym(t_pd *x) {return symprintf(".x%lx",(long)x);} - -t_iemgui *iemgui_new(t_class *qlass) { - t_iemgui *x = (t_iemgui *)pd_new(qlass); - x->canvas = canvas_getcurrent(); - x->w = x->h = 15; - x->ldx=0; - x->ldy=-6; - x->isa=0; - x->font_style = 0; - x->fontsize = 8; - x->snd = 0; - x->rcv = 0; - x->lab = s_empty; - x->bcol = 0xffffff; - x->fcol = 0x000000; - x->lcol = 0x000000; - pd_bind(x,pd_makebindsym(x)); - return x; -} - -static void iemgui_constrain(t_iemgui *x) { - SET(fontsize,max(x->fontsize,4)); - SET(h,iemgui_clip_size(x->h)); - SET(w,iemgui_clip_size(x->w)); -} - -void iemgui_init(t_iemgui *x, t_floatarg f) {SET(isa,(x->isa&~1)|!!f);} - -void binbuf_update(t_iemgui *x, t_symbol *qlass, int argc, t_atom *argv) { - t_binbuf *buf = x->binbuf; - if (!buf) return; - binbuf_clear(buf); - t_atom foo; - SETSYMBOL(&foo,qlass); - binbuf_add(buf,1,&foo); - binbuf_add(buf,argc,argv); -} - -static /*bool*/ int iemgui_loadbang (t_iemgui *self) { - return !sys_noloadbang && self->isa&1; -} - -static /*bool*/ int iemgui_forward (t_iemgui *self) { - return !self->snd || !self->rcv || self->snd != self->rcv; -} - -static t_class *bng_class; - -static void bng_check_minmax(t_bng *x) { - if(x->ftbreak > x->fthold) { - int h = x->ftbreak; - SET(ftbreak,x->fthold); - SET(fthold,h); - } - SET(ftbreak,max(x->ftbreak,10)); - SET(fthold ,max(x->fthold, 50)); -} - -static void bng_set(t_bng *x) { - SET(count,x->count+1); - sys_mgui(x,"bang","i",x->count); -} - -static void bng_bout2(t_bng *x) { - x->outlet->send(); - if(x->snd && x->snd->thing) pd_bang(x->snd->thing); -} - -static void bng_bang(t_bng *x) { - bng_set(x); - x->outlet->send(); - if(x->snd && x->snd->thing && iemgui_forward(x)) pd_bang(x->snd->thing); -} -static void bng_bang2 (t_bng *x) { {bng_set(x); bng_bout2(x);}} -static void bng_loadbang(t_bng *x) {if(iemgui_loadbang(x)) {bng_set(x); bng_bout2(x);}} - -static void bng_size(t_bng *x, t_symbol *s, int ac, t_atom *av) { - SET(w,iemgui_clip_size((int)atom_getintarg(0, ac, av))); - SET(h,x->w); -} - -static void bng_flashtime(t_bng *x, t_symbol *s, int ac, t_atom *av) { - SET(ftbreak,atom_getintarg(0, ac, av)); - SET(fthold ,atom_getintarg(1, ac, av)); - bng_check_minmax(x); -} - -static int bng_pickle(t_bng *x, t_foo *foo) { - return pd_pickle(foo,"iiiiaaaiiiiccc",&x->w,&x->fthold,&x->ftbreak,&x->isa,&x->snd,&x->rcv,&x->lab, - &x->ldx,&x->ldy,&x->font_style,&x->fontsize,&x->bcol,&x->fcol,&x->lcol); -} - -static void bng_savefn(t_bng *x, t_binbuf *b) { - t_foo foo = {0,0,b}; if (!b) return; - pd_savehead(b,x,"bng"); bng_pickle(x,&foo); -} - -static void bng_reload(t_bng *x, t_symbol *s, int argc, t_atom *argv) { - t_foo foo = {argc,argv,0}; - binbuf_update(x,gensym("bng"),argc,argv); - if (!bng_pickle(x,&foo)) return; - SET(h,x->w); - bng_check_minmax(x); - iemgui_constrain(x); - if (x->rcv) pd_bind(x,x->rcv); -} - -static void *bng_new(t_symbol *s, int argc, t_atom *argv) { - t_bng *x = (t_bng *)iemgui_new(bng_class); - SET(ftbreak,250); - SET(fthold,50); - SET(count,0); - bng_check_minmax(x); - outlet_new(x, &s_bang); - if (argc) bng_reload(x,0,argc,argv); - return x; -} - -static void iemgui_free(t_iemgui *x) { - if(x->rcv) pd_unbind(x,x->rcv); -} - -static t_class *toggle_class; - -static void toggle_action(t_toggle *x) { - x->outlet->send(x->on); - if(x->snd && x->snd->thing) pd_float(x->snd->thing, x->on); -} - -static void toggle_bang(t_toggle *x) {SET(on,x->on?0.0:x->nonzero); toggle_action(x);} -static void toggle_set(t_toggle *x, t_floatarg f) {SET(on,f); if(f) SET(nonzero,f);} -static void toggle_float(t_toggle *x, t_floatarg f) {toggle_set(x,f);if(iemgui_forward(x)) toggle_action(x);} -static void toggle_fout (t_toggle *x, t_floatarg f) {toggle_set(x,f); toggle_action(x);} -static void toggle_loadbang(t_toggle *x) {if(iemgui_loadbang(x)) toggle_fout(x, (float)x->on);} -static void toggle_nonzero(t_toggle *x, t_floatarg f) {if (f) SET(nonzero,f);} - -static void toggle_size(t_toggle *x, t_symbol *s, int ac, t_atom *av) { - SET(w,iemgui_clip_size((int)atom_getintarg(0, ac, av))); - SET(h,x->w); -} - -static int toggle_pickle(t_toggle *x, t_foo *foo) { - return pd_pickle(foo,"iiaaaiiiicccf;f",&x->w,&x->isa,&x->snd,&x->rcv,&x->lab, - &x->ldx,&x->ldy,&x->font_style,&x->fontsize,&x->bcol,&x->fcol,&x->lcol,&x->on,&x->nonzero); -} - -static void toggle_savefn(t_toggle *x, t_binbuf *b) { - t_foo foo = {0,0,b}; if (!b) return; - pd_savehead(b,x,"tgl"); toggle_pickle(x,&foo); -} - -static void toggle_reload(t_toggle *x, t_symbol *s, int argc, t_atom *argv) { - t_foo foo = {argc,argv,0}; - binbuf_update(x,gensym("tgl"),argc,argv); - if (!toggle_pickle(x,&foo)) return; - SET(h,x->w); - SET(on,x->isa&1 && x->on ? x->nonzero : 0.0); - SET(nonzero,argc==14 && IS_A_FLOAT(argv,13) ? atom_getfloatarg(13, argc, argv) : 1.0); - if (!x->nonzero) SET(nonzero,1.0); - iemgui_constrain(x); - if (x->rcv) pd_bind(x,x->rcv); -} - -static void *toggle_new(t_symbol *s, int argc, t_atom *argv) { - t_toggle *x = (t_toggle *)iemgui_new(toggle_class); - SET(on,0.0); - SET(nonzero,1.0); - outlet_new(x, &s_float); - if (argc) toggle_reload(x,0,argc,argv); - return x; -} - -static void radio_set(t_radio *x, t_floatarg f) { - int i=(int)f; - int old=x->on_old; - CLAMP(i,0,x->number-1); - if(x->on!=old) SET(on_old,x->on); - SET(on,i); - if(x->on!=old) SET(on_old,old); -} - -static void radio_send2(t_radio *x, float a, float b) { - SETFLOAT(x->at,a); - SETFLOAT(x->at+1,b); - x->outlet->send(2,x->at); - if(x->snd && x->snd->thing) pd_list(x->snd->thing, &s_list, 2, x->at); -} - -static void radio_send(t_radio *x, float a) { - x->outlet->send(a); - if(x->snd && x->snd->thing) pd_float(x->snd->thing,a); -} - -static void radio_bang(t_radio *x) { - if (x->oldstyle) { - if(x->change && x->on!=x->on_old) radio_send2(x,x->on_old,0.0); - SET(on_old,x->on); - radio_send2(x,x->on,1.0); - } else { - radio_send(x,x->on); - } -} - -static void radio_fout2(t_radio *x, t_floatarg f, int forwardonly) { - int i=(int)f; - CLAMP(i,0,x->number-1); - if (x->oldstyle) { - /* compatibility with earlier "hdial" behavior */ - if(x->change && i!=x->on_old && (!forwardonly || iemgui_forward(x))) radio_send2(x,x->on_old,0.0); - SET(on_old,x->on); - SET(on,i); - SET(on_old,x->on); - radio_send2(x,x->on,1.0); - if (!forwardonly || iemgui_forward(x)) radio_send2(x,x->on,1.0); - } else { - SET(on,i); - if (!forwardonly || iemgui_forward(x)) radio_send(x,x->on); - SET(on_old,x->on); - } -} - -static void radio_fout (t_radio *x, t_floatarg f) {radio_fout2(x,f,0);} -static void radio_float(t_radio *x, t_floatarg f) {radio_fout2(x,f,1);} -static void radio_loadbang(t_radio *x) {if(iemgui_loadbang(x)) radio_bang(x);} -static void radio_orient(t_radio *x,t_floatarg v) {SET(orient,!!v); -post("v=%f, !!v=%d, orient=%d",v,!!v,x->orient);} - -static void radio_number(t_radio *x, t_floatarg num) { - int n=(int)num; - CLAMP(n,1,128); - if (n != x->number) { - SET(number,n); - CLAMP(x->on,0,x->number-1); gobj_changed(x,"on"); - SET(on_old,x->on); - } -} - -static void radio_size(t_radio *x, t_float size) { - SET(w,iemgui_clip_size((int)size)); - SET(h,x->w); -} - -static void radio_double_change(t_radio *x) {SET(change,1);} -static void radio_single_change(t_radio *x) {SET(change,0);} - -static int radio_pickle(t_radio *x, t_foo *foo) { - return pd_pickle(foo, "ibiiaaaiiiiccci",&x->w,&x->change,&x->isa,&x->number,&x->snd,&x->rcv,&x->lab, - &x->ldx,&x->ldy,&x->font_style,&x->fontsize,&x->bcol,&x->fcol,&x->lcol,&x->on); -} - -static t_symbol *radio_flavor(t_radio *x) { - return x->orient?x->oldstyle?sym_vdl:sym_vradio:x->oldstyle?sym_hdl:sym_hradio; -} - -static void radio_savefn(t_radio *x, t_binbuf *b) { - t_foo foo = {0,0,b}; if (!b) return; - pd_savehead(b,x,radio_flavor(x)->name); - radio_pickle(x,&foo); -} - -static void radio_reload(t_radio *x, t_symbol *s, int argc, t_atom *argv) { - t_foo foo = {argc,argv,0}; - binbuf_update(x,radio_flavor(x),argc,argv); - if (!radio_pickle(x,&foo)) return; - iemgui_constrain(x); - if (x->rcv) pd_bind(x,x->rcv); - gobj_changed(x,0); -} - -static void *radio_new(t_symbol *s, int argc, t_atom *argv) { - t_radio *x = (t_radio *)iemgui_new(radio_class); - SET(on_old,0); - SET(on,0); - SET(number,8); - SET(change,1); - if (s==sym_hdl) {SET(orient,0); SET(oldstyle,1);} else - if (s==sym_vdl) {SET(orient,1); SET(oldstyle,1);} else - if (s==sym_hradio) {SET(orient,0); SET(oldstyle,0);} else - if (s==sym_vradio) {SET(orient,1); SET(oldstyle,0);} - SET(on,x->isa&1 ? x->on : 0); - SET(on_old,x->on); - outlet_new(x, &s_list); - if (argc) radio_reload(x,0,argc,argv); - return x; -} - -#define IEM_SL_DEFAULTSIZE 128 -#define IEM_SL_MINSIZE 2 - -static void slider_check_width(t_slider *x, int w) { - double l = (double)(x->orient ? x->h : x->w)-1; - int m = (int)(l*100); - if(w < IEM_SL_MINSIZE) w = IEM_SL_MINSIZE; - if (x->orient) SET(h,w); else SET(w,w); - if(x->val > m) SET(val,m); -} - -static void slider_check_minmax(t_slider *x) { - double min=x->min, max=x->max; - if(x->is_log) { - if(min == 0.0 && max == 0.0) max = 1.0; - if(max > 0.0) { if (min<=0.0) min = 0.01*max; } - else { if (min >0.0) max = 0.01*min; } - } - SET(min,min); - SET(max,max); -} - -// the value/centipixel ratio -static double slider_ratio (t_slider *x) { - double diff = x->is_log ? log(x->max/x->min) : (x->max-x->min); - return diff / (double)(x->orient ? (x->h-1) : (x->w-1)); -} - -static void slider_set(t_slider *x, t_floatarg f) { - if(x->min > x->max) CLAMP(f,x->max,x->min); - else CLAMP(f,x->min,x->max); - SET(val,floor(100.0 * (x->is_log ? log(f/x->min) : (f-x->min)) / slider_ratio(x) + 0.5)); -} - -static void slider_bang(t_slider *x) { - double t = (double)x->val * slider_ratio(x) * 0.01; - double out = x->is_log ? x->min*exp(t) : x->min+t; - if (fabs(out) < 1.0e-10) out = 0.0; - x->outlet->send(out); - if(x->snd && x->snd->thing) pd_float(x->snd->thing, out); -} - -static void slider_size(t_slider *x, t_symbol *s, int ac, t_atom *av) { - int a = atom_getintarg(0,ac,av); - int b = ac>1 ? atom_getintarg(1,ac,av) : 0; - if (x->orient) { - SET(w,iemgui_clip_size(a)); - if(ac>1) slider_check_width(x,b); - } else { - slider_check_width(x,a); - if(ac>1) SET(h,iemgui_clip_size(b)); - } -} - -static void slider_range(t_slider *x, t_float min, t_float max) -{SET(min,min); SET(max,max); slider_check_minmax(x);} -static void slider_lin(t_slider *x) {SET(is_log,0); slider_check_minmax(x);} -static void slider_log(t_slider *x) {SET(is_log,1); slider_check_minmax(x);} -static void slider_steady(t_slider *x, t_floatarg f) {SET(steady,!!f);} -static void slider_float(t_slider *x, t_floatarg f) {slider_set(x,f);if(iemgui_forward(x))slider_bang(x);} -static void slider_loadbang(t_slider *x) {if(iemgui_loadbang(x)) slider_bang(x);} -static void slider_orient(t_slider *x,t_floatarg v) {SET(orient,!!v);} - -static int slider_pickle(t_slider *x, t_foo *foo) { - return pd_pickle(foo, "iiffbiaaaiiiicccf;b", - &x->w,&x->h,&x->min,&x->max,&x->is_log,&x->isa,&x->snd,&x->rcv,&x->lab, - &x->ldx,&x->ldy,&x->font_style,&x->fontsize,&x->bcol,&x->fcol,&x->lcol,&x->val,&x->steady); -} - -static void slider_savefn(t_slider *x, t_binbuf *b) { - t_foo foo = {0,0,b}; if (!b) return; - pd_savehead(b,x,(char *)(x->orient?"vsl":"hsl")); slider_pickle(x,&foo); -} - -static void slider_reload(t_slider *x, t_symbol *s, int argc, t_atom *argv) { - t_foo foo = {argc,argv,0}; - binbuf_update(x,gensym((char *)(x->orient?"vsl":"hsl")),argc,argv); - if (!slider_pickle(x,&foo)) return; -//this is wrong because it should happen when loading a file but not when loading from properties: - SET(val,x->isa&1 ? x->val : 0); -//end wrong. - iemgui_constrain(x); - slider_check_minmax(x); - slider_check_width(x, x->orient ? x->h : x->w); - if(x->rcv) pd_bind(x,x->rcv); - gobj_changed(x,0); -} - -static void *slider_new(t_symbol *s, int argc, t_atom *argv) { - t_slider *x = (t_slider *)iemgui_new(slider_class); - SET(orient,s==sym_vslider||s==sym_vsl); - SET(is_log,0); - SET(min,0.0); - SET(steady,1); - SET(max,(double)(IEM_SL_DEFAULTSIZE-1)); - if (x->orient) SET(h,IEM_SL_DEFAULTSIZE); else SET(w,IEM_SL_DEFAULTSIZE); - outlet_new(x, &s_float); - if (argc) slider_reload(x,0,argc,argv); - return x; -} - -static t_class *nbx_class; - -static void nbx_clip(t_nbx *x) {CLAMP(x->val,x->min,x->max);} - -static int nbx_check_minmax(t_nbx *x) { - double min=x->min, max=x->max; - int val=(int)x->val; - if(x->is_log) { - if(min==0.0 && max==0.0) max = 1.0; - if(max>0.0 && min<=0.0) min = 0.01*max; - if(max<=0.0 && min>0.0) max = 0.01*min; - } else if (min>max) swap(min,max); - SET(min,min); - SET(max,max); - CLAMP(x->val,x->min,x->max); - SET(k,x->is_log ? exp(log(x->max/x->min)/(double)(x->log_height)) : 1.0); - return x->val!=val; -} - -static void nbx_bang(t_nbx *x) { - x->outlet->send(x->val); - if(x->snd && x->snd->thing) pd_float(x->snd->thing, x->val); -} -static void nbx_set(t_nbx *x, t_floatarg f) {SET(val,f); nbx_clip(x);} -static void nbx_float(t_nbx *x, t_floatarg f) {nbx_set(x, f); if(iemgui_forward(x)) nbx_bang(x);} -static void nbx_log_height(t_nbx *x, t_floatarg lh) { - SET(log_height,max(10,(int)lh)); - SET(k,x->is_log ? exp(log(x->max/x->min)/(double)(x->log_height)) : 1.0); -} -static void nbx_size(t_nbx *x, t_symbol *s, int ac, t_atom *av) { - SET(w,max(1,(int)atom_getintarg(0, ac, av))); - if(ac > 1) SET(h,max(8,(int)atom_getintarg(1, ac, av))); -} -static void nbx_range(t_nbx *x, t_float min, t_float max) {SET(min,min); SET(max,max); nbx_check_minmax(x);} -static void nbx_lin(t_nbx *x) {SET(is_log,0); } -static void nbx_log(t_nbx *x) {SET(is_log,1); nbx_check_minmax(x);} -static void nbx_loadbang(t_nbx *x) {if(iemgui_loadbang(x)) nbx_bang(x);} -static void nbx_list(t_nbx *x, t_symbol *s, int ac, t_atom *av) { - if (!IS_A_FLOAT(av,0)) return; - nbx_set(x, atom_getfloatarg(0, ac, av)); - nbx_bang(x); -} -static int nbx_pickle(t_nbx *x, t_foo *foo) { - return pd_pickle(foo,"iiddbiaaaiiiicccd;i", - &x->w,&x->h,&x->min,&x->max,&x->is_log,&x->isa,&x->snd,&x->rcv,&x->lab, - &x->ldx,&x->ldy,&x->font_style,&x->fontsize,&x->bcol,&x->fcol,&x->lcol,&x->val,&x->log_height); -} -static void nbx_savefn(t_nbx *x, t_binbuf *b) { - t_foo foo = {0,0,b}; - if (!b) return; - pd_savehead(b,x,"nbx"); - nbx_pickle(x,&foo); -} -static void nbx_reload(t_nbx *x, t_symbol *s, int argc, t_atom *argv) { - t_foo foo = {argc,argv,0}; - binbuf_update(x,gensym("nbx"),argc,argv); - if (!nbx_pickle(x,&foo)) return; - if (!x->isa&1) SET(val,0.0); - SET(fontsize,max(x->fontsize,4)); - SET(h,iemgui_clip_size(x->h)); - SET(w,max(x->w,1)); - nbx_check_minmax(x); - SET(w,max(x->w,1)); - if (x->rcv) pd_bind(x,x->rcv); - gobj_changed(x,0); -} -static void *nbx_new(t_symbol *s, int argc, t_atom *argv) { - t_nbx *x = (t_nbx *)iemgui_new(nbx_class); - SET(log_height,256); - SET(is_log,0); - SET(w,5); - SET(h,14); - SET(min,-1.0e+37); - SET(max,1.0e+37); - x->buf[0]=0; - SET(change,0); - outlet_new(x, &s_float); - if (argc) nbx_reload(x,0,argc,argv); - return x; -} - -#define IEM_VU_STEPS 40 - -static char vu_db2i[]= { - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 9, 9, 9, 9, 9,10,10,10,10,10,11,11,11,11,11,12,12,12,12,12, - 13,13,13,13,14,14,14,14,15,15,15,15,16,16,16,16,17,17,17,18, - 18,18,19,19,19,20,20,20,21,21,22,22,23,23,24,24,25,26,27,28, - 29,30,31,32,33,33,34,34,35,35,36,36,37,37,37,38,38,38,39,39, - 39,39,39,39,40,40 -}; - -static void vu_check_height(t_vu *x, int h) { - int n=max(h/IEM_VU_STEPS,2); - SET(led_size,n-1); - SET(h,IEM_VU_STEPS * n); -} - -static void vu_scale(t_vu *x, t_floatarg fscale) {SET(scale,!!fscale);} - -static void vu_size(t_vu *x, t_symbol *s, int ac, t_atom *av) { - SET(w, iemgui_clip_size((int)atom_getintarg(0, ac, av))); - if(ac>1) vu_check_height(x, (int)atom_getintarg(1, ac, av)); -} - -static int vuify(t_vu *x, float v) { - return v<=-99.9 ? 0 : - v>=12.0 ? IEM_VU_STEPS : - vu_db2i[(int)(2.0*(v+100.0))]; -} - -static float vu_round(float v) {return 0.01*(int)(100.0*v+0.5);} - -static void vu_float0(t_vu *x, t_floatarg v) { - SET(rms, vuify(x,v)); SET(fr,vu_round(v)); x->out(0)->send(x->fr); - sys_mgui(x,"rms=","i",x->rms);} -static void vu_float1(t_vu *x, t_floatarg v) { - SET(peak,vuify(x,v)); SET(fp,vu_round(v)); x->out(1)->send(x->fp); - sys_mgui(x,"peak=","i",x->peak);} - -static void vu_bang(t_vu *x) { - x->out(1)->send(x->fp); - x->out(0)->send(x->fr); -} - -static int vu_pickle(t_vu *x, t_foo *foo) { - return pd_pickle(foo,"iiaaiiiiccb;i",&x->w,&x->h,&x->rcv,&x->lab,&x->ldx,&x->ldy,&x->font_style, - &x->fontsize,&x->bcol,&x->lcol,&x->scale,&x->isa); -} - -static void vu_savefn(t_vu *x, t_binbuf *b) { - t_foo foo = {0,0,b}; if (!b) return; - pd_savehead(b,x,"vu"); vu_pickle(x,&foo); -} - -static void vu_reload(t_vu *x, t_symbol *s, int argc, t_atom *argv) { - t_foo foo = {argc,argv,0}; - binbuf_update(x,gensym("vu"),argc,argv); - if (!vu_pickle(x,&foo)) return; - iemgui_constrain(x); - if(x->rcv) pd_bind(x,x->rcv); - gobj_changed(x,0); -} - -static t_class *vu_class; - -static void *vu_new(t_symbol *s, int argc, t_atom *argv) { - t_vu *x = (t_vu *)iemgui_new(vu_class); - outlet_new(x, &s_float); - outlet_new(x, &s_float); - SET(bcol,0x000000); - SET(h,IEM_VU_STEPS*3); - SET(scale,1); - SET(rms,0); /* ??? */ - SET(peak,0); - SET(fp,-101.0); - SET(fr,-101.0); - vu_check_height(x,x->h); - inlet_new(x,x,&s_float,gensym("ft1")); - if (argc) vu_reload(x,0,argc,argv); - return x; -} - -static t_class *cnv_class; - -static void cnv_get_pos(t_cnv *x) { - error("unimplemented (TODO)"); -// if(x->snd && x->snd->thing) {x->at[0].a_float = x; x->at[1].a_float = y; pd_list(x->snd->thing, &s_list, 2, x->at);} -} - -static void cnv_size(t_cnv *x, t_symbol *s, int ac, t_atom *av) { - SET(h,max(1,(int)atom_getintarg(0, ac, av))); - SET(w,x->h); -} - -static void cnv_vis_size(t_cnv *x, t_symbol *s, int ac, t_atom *av) { - SET(vis_w,max(1,(int)atom_getintarg(0, ac, av))); - SET(vis_h,x->w); - if(ac > 1) SET(vis_h,max(1,(int)atom_getintarg(1, ac, av))); - gobj_changed(x,0); -} - -static int cnv_pickle(t_cnv *x, t_foo *foo) { - return pd_pickle(foo,"iiiaaaiiiicc;i",&x->w,&x->vis_w,&x->vis_h, - &x->snd,&x->rcv,&x->lab,&x->ldx,&x->ldy,&x->font_style,&x->fontsize,&x->bcol,&x->lcol,&x->isa); -} - -static void cnv_savefn(t_cnv *x, t_binbuf *b) { - t_foo foo = {0,0,b}; if (!b) return; - pd_savehead(b,x,"cnv"); cnv_pickle(x,&foo); -} - -static void cnv_reload(t_cnv *x, t_symbol *s, int argc, t_atom *argv) { - t_foo foo = {argc,argv,0}; - binbuf_update(x,gensym("cnv"),argc,argv); - if (!cnv_pickle(x,&foo)) return; - SET(w,max(x->w,1)); - SET(h,x->w); - SET(vis_w,max(x->vis_w,1)); - SET(vis_h,max(x->vis_h,1)); - x->at[0].a_type = x->at[1].a_type = A_FLOAT; //??? - iemgui_constrain(x); - if (x->rcv) pd_bind(x,x->rcv); - gobj_changed(x,0); -} - -static void *cnv_new(t_symbol *s, int argc, t_atom *argv) { - t_cnv *x = (t_cnv *) iemgui_new(cnv_class); - SET(bcol,0xe0e0e0); - SET(fcol,0x000000); - SET(lcol,0x404040); - SET(w,15); - SET(vis_w,100); - SET(vis_h,60); - if (argc) cnv_reload(x,0,argc,argv); - return x; -} - -void canvas_notice(t_gobj *x, t_gobj *origin, int argc, t_atom *argv) { - t_canvas *self = (t_canvas *)x; - gobj_changed3(self,origin,argc,argv); -} - -void gobj_onsubscribe(t_gobj *x, t_gobj *observer) {gobj_changed(x,0);} - -void canvas_onsubscribe(t_gobj *x, t_gobj *observer) { - t_canvas *self = (t_canvas *)x; - gobj_onsubscribe(x,observer); - canvas_each( y,self) y->_class->onsubscribe( y,observer); - canvas_wires_each(oc,t,self) oc->_class->onsubscribe(oc,observer); -} - -/* [declare] and canvas_open come from 0.40 */ -/* ------------------------------- declare ------------------------ */ -/* put "declare" objects in a patch to tell it about the environment in which objects should be created in this canvas. - This includes directories to search ("-path", "-stdpath") and object libraries to load ("-lib" and "-stdlib"). - These must be set before the patch containing the "declare" object is filled in with its contents; so when the patch is - saved, we throw early messages to the canvas to set the environment before any objects are created in it. */ -struct t_declare : t_object { - int useme; -}; - -static void *declare_new(t_symbol *s, int argc, t_atom *argv) { - t_declare *x = (t_declare *)pd_new(declare_class); - x->useme = 1; - /* LATER update environment and/or load libraries */ - return x; -} - -static void declare_free(t_declare *x) { - x->useme = 0; - /* LATER update environment */ -} - -void canvas_savedeclarationsto(t_canvas *x, t_binbuf *b) { - canvas_each(y,x) { - if (pd_class(y) == declare_class) { - binbuf_addv(b,"t","#X"); - binbuf_addbinbuf(b, ((t_declare *)y)->binbuf); - binbuf_addv(b, ";"); - } else if (pd_class(y) == canvas_class) canvas_savedeclarationsto((t_canvas *)y, b); - } -} - -static void canvas_declare(t_canvas *x, t_symbol *s, int argc, t_atom *argv) { - t_canvasenvironment *e = canvas_getenv(x); -#if 0 - startpost("declare:: %s", s->name); - postatom(argc, argv); - endpost(); -#endif - for (int i=0; iname; - if ((argc > i+1) && !strcmp(flag, "-path")) { - e->path = namelist_append(e->path, atom_getsymbolarg(i+1, argc, argv)->name, 0); - i++; - } else if (argc>i+1 && !strcmp(flag, "-stdpath")) { - asprintf(&buf, "%s/%s", sys_libdir->name, atom_getsymbolarg(i+1, argc, argv)->name); - e->path = namelist_append(e->path,buf,0); - i++; - } else if (argc>i+1 && !strcmp(flag, "-lib")) { - sys_load_lib(x, atom_getsymbolarg(i+1, argc, argv)->name); - i++; - } else if (argc>i+1 && !strcmp(flag, "-stdlib")) { - asprintf(&buf, "%s/%s", sys_libdir->name, atom_getsymbolarg(i+1, argc, argv)->name); - sys_load_lib(0,buf); - i++; - } else post("declare: %s: unknown declaration", flag); - } -} - -/* 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.*/ -int canvas_open2(t_canvas *x, const char *name, const char *ext, char **dirresult, char **nameresult, int bin) { - int fd = -1; - /* first check if "name" is absolute (and if so, try to open) */ - if (sys_open_absolute(name, ext, dirresult, nameresult, bin, &fd)) return fd; - /* otherwise "name" is relative; start trying in directories named in this and parent environments */ - for (t_canvas *y=x; y; y = y->dix->canvas) if (y->env) { - t_canvas *x2 = x; - while (x2 && x2->dix->canvas) x2 = x2->dix->canvas; - const char *dir = x2 ? canvas_getdir(x2)->name : "."; - for (t_namelist *nl = y->env->path; nl; nl = nl->nl_next) { - char *realname; - asprintf(&realname, "%s/%s", dir, nl->nl_string); - if ((fd = sys_trytoopenone(realname, name, ext, dirresult, nameresult, bin)) >= 0) return fd; - } - } - return open_via_path2((x ? canvas_getdir(x)->name : "."), name, ext, dirresult, nameresult, bin); -} -/* end miller 0.40 */ - -int canvas_open(t_canvas *x, const char *name, const char *ext, char *dirresult, char **nameresult, unsigned int size, int bin) { - char *dirr; - int r = canvas_open2(x,name,ext,&dirr,nameresult,bin); - if (dirr) {strncpy(dirresult,dirr,size); dirresult[size-1]=0; free(dirr);} - return r; -} - -static void canvas_with_reply (t_pd *x, t_symbol *s, int argc, t_atom *argv) { - if (!( argc>=2 && IS_A_FLOAT(argv,0) && IS_A_SYMBOL(argv,1) )) return; - pd_typedmess(x,atom_getsymbol(&argv[1]),argc-2,argv+2); - queue_put(manager->q,reply_new((short)atom_getfloat(&argv[0]),newest)); -} - -static void canvas_get_elapsed (t_canvas *x) { - canvas_each(y,x) { - sys_mgui(y,"elapsed","f",y->dix->elapsed / 800000000.0); - } -} - -static void g_canvas_setup() { - reply_class = class_new2("reply",0,reply_free,sizeof(t_reply),CLASS_GOBJ,"!"); -// class_setsavefn(reply_class, (t_savefn)reply_savefn); - declare_class = class_new2("declare",declare_new,declare_free,sizeof(t_declare),CLASS_NOINLET,"*"); - t_class *c = canvas_class = class_new2("canvas",0,canvas_free,sizeof(t_canvas),CLASS_NOINLET,""); - /* here is the real creator function, invoked in patch files - by sending the "canvas" message to #N, which is bound to pd_canvasmaker. */ - class_addmethod2(pd_canvasmaker._class,canvas_new,"canvas","*"); - class_addmethod2(c,canvas_restore,"restore","*"); - class_addmethod2(c,canvas_coords,"coords","*"); - class_addmethod2(c,canvas_setbounds,"bounds","ffff"); - class_addmethod2(c,canvas_obj,"obj","*"); - class_addmethod2(c,canvas_msg,"msg","*"); - class_addmethod2(c,canvas_floatatom,"floatatom","*"); - class_addmethod2(c,canvas_symbolatom,"symbolatom","*"); - class_addmethod2(c,canvas_text,"text","*"); - class_addmethod2(c,canvas_canvas,"graph","*"); - class_addmethod2(c,canvas_scalar,"scalar","*"); - class_addmethod2(c,canvas_declare,"declare","*"); - class_addmethod2(c,canvas_push,"push",""); - class_addmethod2(c,canvas_pop,"pop","F"); - class_addmethod2(c,canvas_loadbang,"loadbang",""); - class_addmethod2(c,canvas_relocate,"relocate","ss"); - class_addmethod2(c,canvas_vis,"vis","f"); - class_addmethod2(c,canvas_menu_open,"menu-open",""); - class_addmethod2(c,canvas_clear,"clear",""); - class_addcreator2("pd",subcanvas_new,"S"); - class_addcreator2("page",subcanvas_new,"S"); - class_addmethod2(c,canvas_dsp,"dsp",""); - class_addmethod2(c,canvas_rename_method,"rename","*"); - class_addcreator2("table",table_new,"SF"); - class_addmethod2(c,canvas_close,"close","F"); - class_addmethod2(c,canvas_redraw,"redraw",""); - class_addmethod2(c,canvas_find_parent,"findparent",""); - class_addmethod2(c,canvas_arraydialog,"arraydialog","sfff"); - class_addmethod2(c,canvas_connect,"connect","ffff"); - class_addmethod2(c,canvas_disconnect,"disconnect","ffff"); - class_addmethod2(c,canvas_write,"write","sS"); - class_addmethod2(c,canvas_read, "read","sS"); - class_addmethod2(c,canvas_mergefile, "mergefile","sS"); - class_addmethod2(c,canvas_savetofile,"savetofile","ss"); - class_addmethod2(c,canvas_saveto, "saveto","!"); - class_addmethod2(c,graph_bounds,"bounds","ffff"); - class_addmethod2(c,graph_xticks,"xticks","fff"); - class_addmethod2(c,graph_xlabel,"xlabel","*"); - class_addmethod2(c,graph_yticks,"yticks","fff"); - class_addmethod2(c,graph_ylabel,"ylabel","*"); - class_addmethod2(c,graph_array,"array","sfsF"); - class_addmethod2(c,canvas_sort,"sort",""); -// dd-specific - class_addmethod2(c,canvas_object_moveto,"object_moveto","sff"); - class_addmethod2(c,canvas_object_delete,"object_delete","s"); - class_addmethod2(c,canvas_object_insert,"object_insert","*"); - class_addmethod2(c,canvas_object_get_tips,"object_get_tips","s"); - class_addmethod2(c,canvas_object_help,"object_help","s"); - class_addmethod2(c,canvas_text_setto,"text_setto","*"); - class_addmethod2(c,canvas_with_reply,"with_reply","*"); - class_addmethod2(pd_canvasmaker._class,canvas_with_reply,"with_reply","*"); - class_addmethod2(c,canvas_get_elapsed,"get_elapsed",""); - class_setnotice(c, canvas_notice); - class_setonsubscribe(c, canvas_onsubscribe); -} - -t_class *visualloader_class; - -static t_pd *visualloader_new(t_symbol *s, int argc, t_atom *argv) {return pd_new(visualloader_class);} -static void visualloader_free(t_pd *self) {free(self);} -static void copy_atoms(int argc, t_atom *argvdest, t_atom *argvsrc) {memcpy(argvdest,argvsrc,argc*sizeof(t_atom));} -static void visualloader_anything(t_gobj *self, t_symbol *s, int argc, t_atom *argv) { - int i=0,j=0; - //printf("visualloader_anything start newest=%p\n",newest); - while (jc=j-i; - copy_atoms(al->c,al->v,&argv[i]); - //printf("#V reading '%s':\n",s->name); - if (!newest) {error("#V: there is no newest object\n"); return;} - t_visual *h = ((t_gobj *)newest)->dix->visual; - if (h->exists(s)) { - //printf("'%s' exists, deleting\n",s->name); - free(h->get(s)); - } - h->set(s,al); - //fprintf(stderr,"visualloader... %p %d\n",newest,hash_size(h)); - j++; - if (jname); return; - t_binbuf *b = binbuf_new(); - binbuf_addv(b,"s",s); - newest = 0; - binbuf_eval(b,&pd_objectmaker,0,0); - if (!newest) {post("help: no such class '%s'",s->name); return;} - c = newest->_class; - pd_free(newest); - } - const char *hn = class_gethelpname(c); - char *buf; - bool suffixed = strcmp(hn+strlen(hn)-3, ".pd")==0; - asprintf(&buf,"%s%s",hn,suffixed?"":".pd"); - open_via_helppath(buf, c->externdir->name); - free(buf); -} - -extern "C" void glob_update_class_list (t_pd *self, t_symbol *cb_recv, t_symbol *cb_sel) { - t_symbol *k; t_class *v; - sys_gui("set ::class_list {"); - hash_foreach(k,v,class_table) if (k) sys_vgui("%s ", k->name); - sys_gui("}\n"); - sys_vgui("%s %s\n",cb_recv->name, cb_sel->name); -} - -EXTERN t_class *glob_pdobject; - -t_pd *pd_new2(int argc, t_atom *argv) { - if (argv[0].a_type != A_SYMBOL) {error("pd_new2: start with symbol please"); return 0;} - pd_typedmess(&pd_objectmaker,argv[0].a_symbol,argc-1,argv+1); - return newest; -} -t_pd *pd_new3(const char *s) { - t_binbuf *b = binbuf_new(); - binbuf_text(b,(char *)s,strlen(s)); - t_pd *self = pd_new2(binbuf_getnatom(b),binbuf_getvec(b)); - binbuf_free(b); - return self; -} - -extern "C" void boxes_init() { - t_class *c; - c = boxes_class = class_new2("__boxes" ,0/*boxes_new*/ , boxes_free,sizeof(t_boxes),CLASS_GOBJ,""); - class_setnotice(c,t_notice(boxes_notice)); - c = gop_filtre_class = class_new2("__gop_filtre",0/*gop_filtre_new*/,gop_filtre_free,sizeof(t_boxes),CLASS_GOBJ,""); - class_setnotice(c,t_notice(gop_filtre_notice)); -} - -static void desire_setup() { - t_class *c; - s_empty = gensym("empty"); - s_Pd = gensym("Pd"); - s_pd = gensym("pd"); - manager_class = class_new2("__manager",manager_new,manager_free,sizeof(t_manager),0,"*"); - class_addanything(manager_class,manager_anything); - class_setnotice(manager_class,manager_notice); - manager = manager_new(0,0,0); -#define S(x) x##_setup(); - S(vinlet) S(voutlet) S(g_array) S(g_canvas) S(g_scalar) S(g_template) S(g_traversal) S(g_text) -#undef S - - c = bng_class = class_new2("bng",bng_new,iemgui_free,sizeof(t_bng),0,"*"); - iemgui_subclass(c); - class_addbang (c, bng_bang); - class_addfloat (c, bng_bang2); - class_addsymbol (c, bng_bang2); - class_addpointer (c, bng_bang2); - class_addlist (c, bng_bang2); - class_addanything(c, bng_bang2); - class_addmethod2(c,bng_reload,"reload","*"); - class_addmethod2(c,bng_loadbang,"loadbang",""); - class_addmethod2(c,bng_size,"size","*"); - class_addmethod2(c,bng_flashtime,"flashtime","*"); - class_addmethod2(c,iemgui_init,"init","f"); - class_setsavefn(c, (t_savefn)bng_savefn); - class_sethelpsymbol(c, gensym("bng")); - class_setfieldnames(c, "foo bar x1 y1 class w hold break isa snd rcv lab ldx ldy fstyle fs bcol fcol lcol"); - - c = toggle_class = class_new2("tgl",toggle_new,iemgui_free,sizeof(t_toggle),0,"*"); - class_addcreator2("toggle",toggle_new,"*"); - iemgui_subclass(c); - class_addbang(c, toggle_bang); - class_addfloat(c, toggle_float); - class_addmethod2(c,toggle_reload,"reload","*"); - class_addmethod2(c,toggle_loadbang,"loadbang",""); - class_addmethod2(c,toggle_set,"set","f"); - class_addmethod2(c,toggle_size,"size","*"); - class_addmethod2(c,iemgui_init,"init","f"); - class_addmethod2(c,toggle_nonzero,"nonzero","f"); - class_setsavefn(c, (t_savefn)toggle_savefn); - class_sethelpsymbol(c, gensym("toggle")); - - c = radio_class = class_new2("radio",radio_new,iemgui_free,sizeof(t_radio),0,"*"); - iemgui_subclass(c); - class_addbang(c, radio_bang); - class_addfloat(c, radio_float); - class_addmethod2(c,radio_reload, "reload","*"); - class_addmethod2(c,radio_loadbang, "loadbang",""); - class_addmethod2(c,radio_set, "set","f"); - class_addmethod2(c,radio_size, "size","f"); - class_addmethod2(c,iemgui_init, "init","f"); - class_addmethod2(c,radio_fout, "fout","f"); - class_addmethod2(c,radio_number, "number","f"); - class_addmethod2(c,radio_orient,"orient","f"); - class_addmethod2(c,radio_single_change, "single_change",""); - class_addmethod2(c,radio_double_change, "double_change",""); - sym_hdl = gensym("hdl"); sym_hradio = gensym("hradio"); - sym_vdl = gensym("vdl"); sym_vradio = gensym("vradio"); - class_setsavefn(c,(t_savefn)radio_savefn); - class_sethelpsymbol(c, gensym("hradio")); - class_addcreator2("hradio",radio_new,"*"); - class_addcreator2("vradio",radio_new,"*"); - class_addcreator2("hdl",radio_new,"*"); - class_addcreator2("vdl",radio_new,"*"); - class_addcreator2("rdb",radio_new,"*"); - class_addcreator2("radiobut",radio_new,"*"); - class_addcreator2("radiobutton",radio_new,"*"); - - c = slider_class = class_new2("slider",slider_new,iemgui_free,sizeof(t_slider),0,"*"); - class_addcreator2("hslider",slider_new,"*"); - class_addcreator2("vslider",slider_new,"*"); - class_addcreator2("hsl" ,slider_new,"*"); - class_addcreator2("vsl" ,slider_new,"*"); - - iemgui_subclass(c); - class_addbang(c,slider_bang); - class_addfloat(c,slider_float); - class_addmethod2(c,slider_reload,"reload","*"); - class_addmethod2(c,slider_loadbang,"loadbang",""); - class_addmethod2(c,slider_set,"set","f"); - class_addmethod2(c,slider_size,"size","*"); - class_addmethod2(c,slider_range,"range","ff"); - class_addmethod2(c,slider_log,"log",""); - class_addmethod2(c,slider_lin,"lin",""); - class_addmethod2(c,iemgui_init,"init","f"); - class_addmethod2(c,slider_steady,"steady","f"); - class_addmethod2(c,slider_orient,"orient","f"); - sym_vsl = gensym("vsl"); - sym_vslider = gensym("vslider"); - class_setsavefn(c,(t_savefn)slider_savefn); - class_sethelpsymbol(c, gensym("hslider")); - - c = nbx_class = class_new2("nbx",nbx_new,iemgui_free,sizeof(t_nbx),0,"*"); - iemgui_subclass(c); - class_addbang(c,nbx_bang); - class_addfloat(c,nbx_float); - class_addlist(c, nbx_list); - class_addmethod2(c,nbx_reload,"reload","*"); - class_addmethod2(c,nbx_loadbang,"loadbang",""); - class_addmethod2(c,nbx_set,"set","f"); - class_addmethod2(c,nbx_size,"size","*"); - class_addmethod2(c,nbx_range,"range","*"); - class_addmethod2(c,nbx_log,"log",""); - class_addmethod2(c,nbx_lin,"lin",""); - class_addmethod2(c,iemgui_init,"init","f"); - class_addmethod2(c,nbx_log_height,"log_height","f"); - class_setsavefn(c,(t_savefn)nbx_savefn); - class_sethelpsymbol(c, gensym("numbox2")); - - c = cnv_class = class_new2("cnv",cnv_new,iemgui_free,sizeof(t_cnv),CLASS_NOINLET,"*"); - class_addmethod2(c,cnv_reload,"reload","*"); - class_addmethod2(c,cnv_size,"size","*"); - class_addmethod2(c,cnv_vis_size,"vis_size","*"); - class_addmethod2(c,cnv_get_pos,"get_pos",""); - iemgui_subclass(c); - class_setsavefn(c,(t_savefn)cnv_savefn); - class_sethelpsymbol(c, gensym("my_canvas")); - - c = vu_class = class_new2("vu",vu_new,iemgui_free,sizeof(t_vu),0,"*"); - iemgui_subclass(c); - class_addbang(c,vu_bang); - class_addfloat(c,vu_float0); - class_addmethod2(c,vu_float1,"ft1","f"); - class_addmethod2(c,vu_reload,"reload","*"); - class_addmethod2(c,vu_size,"size","*"); - class_addmethod2(c,vu_scale,"scale","F"); - class_setsavefn(c,(t_savefn)vu_savefn); - class_sethelpsymbol(c, gensym("vu")); - - visualloader_class = class_new2("#V",visualloader_new,visualloader_free,sizeof(t_object),CLASS_GOBJ,"*"); - class_addanything(visualloader_class,visualloader_anything); - pd_bind(pd_new(visualloader_class),gensym("#V")); -} - -/* ---------------------------------------------------------------- */ -/* formerly m_glob.c */ - -t_class *glob_pdobject; -static t_class *maxclass; - -#define IGN(sym) if (s==gensym(sym)) return; -void max_default(t_pd *x, t_symbol *s, int argc, t_atom *argv) { - IGN("audioindev"); - IGN("audiooutdev"); - IGN("audioininfo"); - IGN("audiooutinfo"); - IGN("testaudiosettingresult"); - IGN("audiodevice"); - IGN("xrun"); - IGN("audio_started"); - IGN("sys_lock_timeout"); - IGN("midiindev"); - IGN("midioutdev"); - IGN("midicurrentindev"); - IGN("midicurrentoutdev"); - IGN("audiocurrentininfo"); - IGN("audiocurrentoutinfo"); - IGN("asiolatency"); - startpost("%s: unknown message %s ", class_getname(pd_class(x)), s->name); - std::ostringstream buf; - for (int i = 0; i < argc; i++) {buf << " "; atom_ostream(argv+i,buf);} - post("%s",buf.str().data()); - endpost(); -} - -static void openit(const char *dirname, const char *filename) { - char *dirbuf; - char *nameptr; - int fd = open_via_path2(dirname,filename,"",&dirbuf,&nameptr,0); - if (fd<0) {error("%s: can't open", filename); return;} - close(fd); - glob_evalfile(0, gensym(nameptr), gensym(dirbuf)); - free(dirbuf); -} - -extern "C" t_socketreceiver *netreceive_newest_receiver(t_text *x); - -/* this should be rethought for multi-client */ -void glob_initfromgui(void *dummy, t_symbol *s) { - char buf[256], buf2[256]; - char cwd[666]; - if (!getcwd(cwd,665)) strcpy(cwd,"actual_name_is_way_too_long.oops"); - sys_socketreceiver=netreceive_newest_receiver(sys_netreceive); - sys_vgui("%s",lost_posts.str().data()); - /* load dynamic libraries specified with "-lib" args */ - for (t_namelist *nl=sys_externlist; nl; nl = nl->nl_next) - if (!sys_load_lib(0, nl->nl_string)) - post("%s: can't load library", nl->nl_string); - /* open patches specified with "-open" args */ - for (t_namelist *nl=sys_openlist; nl; nl = nl->nl_next) openit(cwd, nl->nl_string); - namelist_free(sys_openlist); - sys_openlist = 0; - /* send messages specified with "-send" args */ - for (t_namelist *nl=sys_messagelist; nl; nl = nl->nl_next) { - t_binbuf *b = binbuf_new(); - binbuf_text(b, nl->nl_string, strlen(nl->nl_string)); - binbuf_eval(b, 0, 0, 0); - binbuf_free(b); - } - namelist_free(sys_messagelist); - sys_messagelist = 0; - sys_get_audio_apis(buf); - sys_get_midi_apis(buf2); - sys_vgui("pd_startup {%s} %s %s\n", pd_version, buf, buf2); -/* - fprintf(stdout,"This line was printed on stdout\n"); - fprintf(stderr,"This line was printed on stderr\n"); -*/ -} - -void glob_meters(void *, t_floatarg f); -void glob_audiostatus(void *); -void glob_audio_properties(t_pd *, t_floatarg flongform); -void glob_audio_dialog(t_pd *, t_symbol *s, int argc, t_atom *argv); -void glob_audio_setapi(t_pd *, t_floatarg f); -void glob_midi_properties(t_pd *, t_floatarg flongform); -void glob_midi_dialog(t_pd *, t_symbol *s, int argc, t_atom *argv); -void glob_midi_setapi(t_pd *, t_floatarg f); -void glob_start_path_dialog(t_pd *, t_floatarg flongform); -void glob_path_dialog(t_pd *, t_symbol *s, int argc, t_atom *argv); -void glob_start_startup_dialog(t_pd *, t_floatarg flongform); -void glob_startup_dialog(t_pd *, t_symbol *s, int argc, t_atom *argv); -void glob_ping(t_pd *); -extern "C" { -void glob_finderror(t_pd *); -}; -/* tb: message-based audio configuration { */ -void glob_audio_testaudiosetting(t_pd *, t_symbol *s, int ac, t_atom *av); -void glob_audio_getaudioindevices(t_pd *, t_symbol *s, int ac, t_atom *av); -void glob_audio_getaudiooutdevices(t_pd *, t_symbol *s, int ac, t_atom *av); -void glob_audio_getaudioininfo(t_pd *, t_float f); -void glob_audio_getaudiooutinfo(t_pd * dummy, t_float f); -//void glob_audio_samplerate(t_pd *, t_float f); -//void glob_audio_delay(t_pd *, t_float f); -//void glob_audio_dacblocksize(t_pd *, t_float f); -//void glob_audio_scheduler(t_pd *, t_float f); -void glob_audio_device(t_pd *, t_symbol *s, int argc, t_atom *argv); -//void glob_audio_device_in(t_pd *, t_symbol *s, int argc, t_atom *argv); -//void glob_audio_device_out(t_pd *, t_symbol *s, int argc, t_atom *argv); -void glob_audio_getcurrent_devices (); -void glob_audio_asio_latencies(t_pd *, t_float f); -void glob_midi_getindevs( t_pd *, t_symbol *s, int ac, t_atom *av); -void glob_midi_getoutdevs(t_pd *, t_symbol *s, int ac, t_atom *av); -void glob_midi_getcurrentindevs(t_pd *); -void glob_midi_getcurrentoutdevs(t_pd *); -/* tb } */ - -static void glob_object_table() { - t_symbol *s_inlet = gensym("inlet"); - t_symbol *s___list = gensym("__list"); - size_t inlets=0, lists=0, zombies=0; - t_pd *k; long v; - post("object_table = {"); - hash_foreach(k,v,object_table) { - t_pd *x = (t_pd *)k; - if (!(long)v&1) {zombies++; continue;} /* skip zombies */ - //post(" %p %ld %s",k,(long)v,x->_class->name->name); - if (x->_class->name == s_inlet) {inlets++; continue;} - if (x->_class->name == s___list) {lists++; continue;} - int nobs = x->_class->gobj ? ((t_gobj *)x)->dix->nobs : 0; - // this has been duplicated as the ostream operator of t_pd * (see above). - t_binbuf *b; - if (x->_class->patchable && (b = ((t_text *)x)->binbuf)) { - char *buf; int bufn; - binbuf_gettext(b,&buf,&bufn); - post(" %p %ld (%dobs) %s [%.*s]",k,(long)v,nobs,x->_class->name->name,bufn,buf); - } else post(" %p %ld (%dobs) %s",k,(long)v,nobs,x->_class->name->name); - } - post("} (%ld non-omitted objects, plus %ld [inlet], plus %ld [__list], plus %ld zombies)", - long(object_table->size()-inlets-lists-zombies),long(inlets),long(lists),long(zombies)); -} - -void glob_symbol_table (t_pd *, float onlybound); - -extern t_class *glob_pdobject; -extern "C" void glob_init () { - /* can this one really be called "max"? isn't that a name conflict? */ - maxclass = class_new2("max",0,0,sizeof(t_pd),CLASS_DEFAULT,""); - class_addanything(maxclass, max_default); - pd_bind((t_pd *)&maxclass, gensym("max")); - - /* this smells bad... a conflict with [pd] subpatches */ - t_class *c = glob_pdobject = class_new2("pd",0,0,sizeof(t_pd),CLASS_DEFAULT,""); - class_addmethod2(c,glob_initfromgui, "init", "*"); - class_addmethod2(c,glob_setfilename, "filename", "ss"); - class_addmethod2(c,glob_evalfile, "open", "ss"); - class_addmethod2(c,glob_quit, "quit", ""); - class_addmethod2(c,glob_dsp, "dsp", "*"); - class_addmethod2(c,glob_meters, "meters", "f"); - class_addmethod2(c,glob_audiostatus, "audiostatus", ""); - class_addmethod2(c,glob_finderror, "finderror", ""); - class_addmethod2(c,glob_audio_properties, "audio-properties", "F"); - class_addmethod2(c,glob_audio_dialog, "audio-dialog", "*"); - class_addmethod2(c,glob_audio_setapi, "audio-setapi", "f"); - class_addmethod2(c,glob_midi_setapi, "midi-setapi", "f"); - class_addmethod2(c,glob_midi_properties, "midi-properties", "F"); - class_addmethod2(c,glob_midi_dialog, "midi-dialog", "*"); - class_addmethod2(c,glob_ping, "ping",""); - /* tb: message-based audio configuration { */ -// class_addmethod2(c,glob_audio_samplerate, "audio-samplerate", "F"); -// class_addmethod2(c,glob_audio_delay, "audio-delay", "F"); -// class_addmethod2(c,glob_audio_dacblocksize,"audio-dacblocksize", "F"); -// class_addmethod2(c,glob_audio_scheduler, "audio-scheduler", "F"); - class_addmethod2(c,glob_audio_device, "audio-device", "*"); -// class_addmethod2(c,glob_audio_device_in, "audio-device-in", "*"); -// class_addmethod2(c,glob_audio_device_out, "audio-device-out", "*"); - class_addmethod2(c,glob_audio_getaudioindevices, "getaudioindev", "*"); - class_addmethod2(c,glob_audio_getaudiooutdevices,"getaudiooutdev", "*"); - class_addmethod2(c,glob_audio_getaudioininfo, "getaudioininfo", "f"); - class_addmethod2(c,glob_audio_getaudiooutinfo, "getaudiooutinfo", "f"); - class_addmethod2(c,glob_audio_testaudiosetting, "testaudiosetting", "*"); - class_addmethod2(c,glob_audio_getcurrent_devices,"getaudiodevice", ""); - class_addmethod2(c,glob_audio_asio_latencies, "getasiolatencies", "F"); - class_addmethod2(c,glob_midi_getoutdevs,"getmidioutdev", "*"); - class_addmethod2(c,glob_midi_getindevs, "getmidiindev", "*"); - class_addmethod2(c,glob_midi_getcurrentoutdevs, "getmidicurrentoutdev", ""); - class_addmethod2(c,glob_midi_getcurrentindevs, "getmidicurrentindev", ""); - /* tb } */ -#ifdef UNIX - class_addmethod2(c,glob_watchdog, "watchdog", ""); -#endif - class_addmethod2(c,glob_update_class_list, "update-class-list", "ss"); - class_addmethod2(c,glob_update_class_info, "update-class-info", "sss"); - class_addmethod2(c,glob_update_path, "update-path", ""); - class_addmethod2(c,glob_help, "help", "s"); - class_addmethod2(c,glob_object_table,"object_table",""); - class_addmethod2(c,glob_symbol_table,"symbol_table","F"); - class_addanything(c, max_default); - pd_bind((t_pd *)&glob_pdobject, gensym("pd")); -} - -/* ---------------------------------------------------------------- */ -/* formerly s_print.c */ - -t_printhook sys_printhook; -FILE *sys_printtofh = 0; /* send to console by default */ - -static void dopost(const char *s) { - if (sys_printhook) sys_printhook(s); - else if (sys_printtofh) fprintf(sys_printtofh, "%s", s); - else { - std::ostringstream t; - for(int i=0; s[i]; i++) { - if (strchr("\\\"[]$\n",s[i])) t << '\\'; - t << char(s[i]=='\n' ? 'n' : s[i]); - } - sys_vgui("pdtk_post \"%s\"\n",t.str().data()); - } -} - -void post(const char *fmt, ...) { - char *buf; va_list ap; va_start(ap, fmt); - size_t n = vasprintf(&buf, fmt, ap); va_end(ap); - buf=realloc2(buf,n+2); strcpy(buf+n,"\n"); - dopost(buf); free(buf); -} -void startpost(const char *fmt, ...) { - char *buf; va_list ap; va_start(ap, fmt); - vasprintf(&buf, fmt, ap); va_end(ap); - dopost(buf); free(buf); -} - -void poststring(const char *s) {dopost(" "); dopost(s);} - -void postatom(int argc, t_atom *argv) { - std::ostringstream buf; - for (int i=0; i=0 ? pd_stack[pd_stackn-1].self : 0; -} -void error( const char *fmt, ...) {va_list ap; va_start(ap,fmt); verror(fmt,ap); va_end(ap);} -void pd_error(void *moot, const char *fmt, ...) {va_list ap; va_start(ap,fmt); verror(fmt,ap); va_end(ap);} - -void verbose(int level, const char *fmt, ...) { - char *buf; - va_list ap; - if (level>sys_verbose) return; - dopost("verbose("); - postfloat((float)level); - dopost("):"); - va_start(ap, fmt); - vasprintf(&buf,fmt,ap); - va_end(ap); - dopost(buf); - dopost("\n"); -} - -extern "C" void glob_finderror(t_pd *dummy) { - if (!error_object) {post("no findable error yet."); return;} - post("last trackable error was for object x%lx: %s",long(error_object),error_string); - sys_mgui(error_object,"show_error","S",error_string); - canvas_finderror(error_object); -} - -void bug(const char *fmt, ...) { - char *buf; - va_list ap; - dopost("bug: "); - va_start(ap, fmt); - vasprintf(&buf,fmt,ap); - va_end(ap); - dopost(buf); - free(buf); - dopost("\n"); -} - -static const char *errobject; -static const char *errstring; - -void sys_logerror (const char *object, const char *s){errobject=object; errstring = s;} -void sys_unixerror(const char *object) {errobject=object; errstring = strerror(errno);} - -void sys_ouch () { - if (*errobject) error("%s: %s", errobject, errstring); else error("%s", errstring); -} - -/* properly close all open root canvases */ -extern "C" void glob_closeall(void *dummy, t_floatarg fforce) { - foreach(x,windowed_canvases) canvas_close(x->first); -} - -/* ---------------------------------------------------------------- */ -/* formerly m_conf.c */ - -void builtins_setup (); -void builtins_dsp_setup (); -void desire_setup (); -void d_soundfile_setup (); -void d_ugen_setup (); - -extern "C" void conf_init () { - builtins_setup(); - builtins_dsp_setup(); - desire_setup(); - d_soundfile_setup(); - d_ugen_setup(); -} - -// and just to make some externs happy: -#define BYE error("%s unimplemented in desiredata!", __PRETTY_FUNCTION__); -extern "C" { - void glist_grab () {BYE} - void glist_xtopixels () {BYE} - void glist_ytopixels () {BYE} - void *glist_findrtext () {BYE return 0;} - void canvas_fixlinesfor () {BYE} - void class_setpropertiesfn () {BYE} - void glist_eraseiofor () {BYE} - void glist_getcanvas () {BYE} - void rtext_gettag () {BYE} - void class_setwidget () {BYE} - void glist_isvisible () {BYE} - void gobj_vis () {BYE} - void gfxstub_deleteforkey () {BYE} - void gfxstub_new () {BYE} - void rtext_width () {BYE} - void rtext_height () {BYE} - void *rtext_new () {BYE return 0;} - void rtext_free () {BYE} - void glist_delete(t_canvas *x, t_gobj *y) {canvas_delete(x,y);} - - //redundantwards-compatibility - void canvas_setcurrent (t_canvas *x) {pd_pushsym(x);} - void canvas_unsetcurrent(t_canvas *x) {pd_popsym(x);} - - //int sys_isreadablefile(const char *file) {} - - /* test if path is absolute or relative, based on leading /, env vars, ~, etc */ - int sys_isabsolutepath(const char *dir) { - return dir[0] == '/' || dir[0] == '~' -#ifdef MSW - || dir[0] == '%' || (dir[1] == ':' && dir[2] == '/') -#endif - ;} -}; - -t_gobj *canvas_first (t_canvas *self) {return self->boxes->first();} -t_gobj *gobj_next (t_gobj *self) {return self->next();} -- cgit v1.2.1