Update of /cvsroot/pure-data/externals/gridflow/bridge In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21117/bridge
Added Files: placebo.rb puredata.c puredata.rb Log Message: starting to commit gridflow 0.8.0 ... if you know how to use "cvs import" please mail me and i'll use it for 0.8.1
--- NEW FILE: puredata.c --- /* $Id: puredata.c,v 1.1 2005/10/04 02:02:13 matju Exp $
GridFlow Copyright (c) 2001,2002,2003,2004,2005 by Mathieu Bouchard
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
See file ../COPYING for further informations on licensing terms.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* 'bridge_puredata.c' becomes 'gridflow.pd_linux' which loads Ruby and tells Ruby to load the other 95% of Gridflow. GridFlow creates the FObject class and then subclasses it many times, each time calling FObject.install(), which tells the bridge to register a class in puredata. Puredata objects have proxies for each of the non-first inlets so that any inlet may receive any distinguished message. All inlets are typed as 'anything', and the 'anything' method translates the whole message to Ruby objects and tries to call a Ruby method of the proper name. */
#define IS_BRIDGE #include "../base/grid.h.fcs" /* resolving conflict: T_OBJECT will be PD's, not Ruby's */ #undef T_OBJECT #undef EXTERN #include <m_pd.h> #include <ctype.h> #include <stdarg.h> #include <unistd.h> #include "g_canvas.h"
/* **************************************************************** */ struct BFObject; struct FMessage { BFObject *self; int winlet; t_symbol *selector; int ac; const t_atom *at; bool is_init; }; #include <sys/time.h> #include <signal.h> #include <setjmp.h> #define rb_sym_name rb_sym_name_r4j static const char *rb_sym_name(Ruby sym) {return rb_id2name(SYM2ID(sym));}
static BuiltinSymbols *syms;
void CObject_freeee (void *victim) { CObject *self = (CObject *)victim; self->check_magic(); if (!self->rself) { fprintf(stderr,"attempt to free object that has no rself\n"); abort(); } self->rself = 0; /* paranoia */ delete self; }
/* can't even refer to the other mGridFlow because we don't link statically to the other gridflow.so */ static Ruby mGridFlow2=0; static Ruby mPointer=0;
\class Pointer < CObject struct Pointer : CObject { void *p; Pointer() { assert(!"DYING HORRIBLY"); } Pointer(void *_p) : p(_p) {} \decl Ruby ptr (); }; \def Ruby ptr () { return LONG2NUM(((long)p)); } \classinfo { IEVAL(rself, "self.module_eval{" "def inspect; p=('%08x'%ptr).gsub(/^\.\.f/,''); "#Pointer:#{p}" % ptr; end;" "alias to_s inspect }" );} \end class Pointer Ruby Pointer_s_new (void *ptr) { return Data_Wrap_Struct(EVAL("GridFlow::Pointer"), 0, 0, new Pointer(ptr)); } void *Pointer_get (Ruby rself) { DGS(Pointer); return self->p; }
static Ruby make_error_message () { char buf[1000]; sprintf(buf,"%s: %s",rb_class2name(rb_obj_class(ruby_errinfo)), rb_str_ptr(rb_funcall(ruby_errinfo,SI(to_s),0))); Ruby ary = rb_ary_new2(2); Ruby backtrace = rb_funcall(ruby_errinfo,SI(backtrace),0); rb_ary_push(ary,rb_str_new2(buf)); for (int i=0; i<2 && i<rb_ary_len(backtrace); i++) rb_ary_push(ary,rb_funcall(backtrace,SI([]),1,INT2NUM(i))); // rb_ary_push(ary,rb_funcall(rb_funcall(backtrace,SI(length),0),SI(to_s),0)); return ary; }
static int ninlets_of (Ruby qlass) { if (!rb_ivar_defined(qlass,SYM2ID(syms->iv_ninlets))) RAISE("no inlet count"); return INT(rb_ivar_get(qlass,SYM2ID(syms->iv_ninlets))); }
static int noutlets_of (Ruby qlass) { if (!rb_ivar_defined(qlass,SYM2ID(syms->iv_noutlets))) RAISE("no outlet count"); return INT(rb_ivar_get(qlass,SYM2ID(syms->iv_noutlets))); }
#ifndef STACK_GROW_DIRECTION #define STACK_GROW_DIRECTION -1 #endif extern "C" void Init_stack(VALUE *addr); static VALUE *localize_sysstack () { long bp; sscanf(RUBY_STACK_END,"0x%08lx",&bp); //fprintf(stderr,"old RUBY_STACK_END = %08lx\n",bp); // HACK (2004.08.29: alx has a problem; i hope it doesn't get worse) // this rounds to the last word of a 4k block // cross fingers that no other OS does it too different // !@#$ doesn't use STACK_GROW_DIRECTION // bp=((bp+0xfff)&~0xfff)-sizeof(void*); // GAAAH bp=((bp+0xffff)&~0xffff)-sizeof(void*); //fprintf(stderr,"new RUBY_STACK_END = %08lx\n",bp); return (VALUE *)bp; }
//**************************************************************** // BFObject
struct BFObject : t_object { int32 magic; // paranoia Ruby rself; int nin; // per object settings (not class) int nout; // per object settings (not class) t_outlet **out;
void check_magic () { if (magic != OBJECT_MAGIC) { fprintf(stderr,"Object memory corruption! (ask the debugger)\n"); for (int i=-1; i<=1; i++) { fprintf(stderr,"this[0]=0x%08x\n",((int*)this)[i]); } raise(11); } } };
static t_class *find_bfclass (t_symbol *sym) { t_atom a[1]; SETSYMBOL(a,sym); char buf[4096]; if (sym==&s_list) strcpy(buf,"list"); else atom_string(a,buf,sizeof(buf)); Ruby v = rb_hash_aref(rb_ivar_get(mGridFlow2, SI(@fclasses)), rb_str_new2(buf)); if (v==Qnil) { post("GF: class not found: '%s'",buf); return 0; } if (Qnil==rb_ivar_get(v,SI(@bfclass))) { post("@bfclass missing for '%s'",buf); return 0; } return FIX2PTR(t_class,rb_ivar_get(v,SI(@bfclass))); }
static t_class *BFProxy_class;
struct BFProxy : t_object { BFObject *parent; int inlet; };
static void Bridge_export_value(Ruby arg, t_atom *at) { if (INTEGER_P(arg)) { SETFLOAT(at,NUM2INT(arg)); } else if (SYMBOL_P(arg)) { const char *name = rb_sym_name(arg); SETSYMBOL(at,gensym((char *)name)); } else if (FLOAT_P(arg)) { SETFLOAT(at,RFLOAT(arg)->value); } else if (rb_obj_class(arg)==mPointer) { SETPOINTER(at,(t_gpointer*)Pointer_get(arg)); } else { RAISE("cannot convert argument of class '%s'", rb_str_ptr(rb_funcall(rb_funcall(arg,SI(class),0),SI(inspect),0))); } }
static Ruby Bridge_import_value(const t_atom *at) { t_atomtype t = at->a_type; if (t==A_SYMBOL) { return ID2SYM(rb_intern(at->a_w.w_symbol->s_name)); } else if (t==A_FLOAT) { return rb_float_new(at->a_w.w_float); } else if (t==A_POINTER) { return Pointer_s_new(at->a_w.w_gpointer); } else { return Qnil; /* unknown */ } }
static Ruby BFObject_method_missing_1 (FMessage *fm) { Ruby argv[fm->ac+2]; argv[0] = INT2NUM(fm->winlet); argv[1] = ID2SYM(rb_intern(fm->selector->s_name)); for (int i=0; i<fm->ac; i++) argv[2+i] = Bridge_import_value(fm->at+i); fm->self->check_magic(); rb_funcall2(fm->self->rself,SI(send_in),fm->ac+2,argv); return Qnil; }
static Ruby BFObject_rescue (FMessage *fm) { Ruby error_array = make_error_message(); // for (int i=0; i<rb_ary_len(error_array); i++) // post("%s\n",rb_str_ptr(rb_ary_ptr(error_array)[i])); if (fm->self) pd_error(fm->self,"%s",rb_str_ptr( rb_funcall(error_array,SI(join),1,rb_str_new2("\n")))); if (fm->self && fm->is_init) fm->self = 0; return Qnil; }
static void BFObject_method_missing (BFObject *bself, int winlet, t_symbol *selector, int ac, t_atom *at) { FMessage fm = { bself, winlet, selector, ac, at, false }; if (!bself->rself) { pd_error(bself,"message to a dead object. (supposed to be impossible)"); return; } rb_rescue2( (RMethod)BFObject_method_missing_1,(Ruby)&fm, (RMethod)BFObject_rescue,(Ruby)&fm, rb_eException,0); }
static void BFObject_method_missing0 (BFObject *self, t_symbol *s, int argc, t_atom *argv) { BFObject_method_missing(self,0,s,argc,argv); }
static void BFProxy_method_missing(BFProxy *self, t_symbol *s, int argc, t_atom *argv) { BFObject_method_missing(self->parent,self->inlet,s,argc,argv); } static Ruby BFObject_init_1 (FMessage *fm) { Ruby argv[fm->ac+1]; for (int i=0; i<fm->ac; i++) argv[i+1] = Bridge_import_value(fm->at+i);
if (fm->selector==&s_list) { argv[0] = rb_str_new2("list"); // pd is slightly broken here } else { argv[0] = rb_str_new2(fm->selector->s_name); }
Ruby rself = rb_funcall2(rb_const_get(mGridFlow2,SI(FObject)),SI([]),fm->ac+1,argv); DGS(FObject); self->bself = fm->self; self->bself->rself = rself;
int ninlets = self->bself->nin = ninlets_of(rb_funcall(rself,SI(class),0)); int noutlets = self->bself->nout = noutlets_of(rb_funcall(rself,SI(class),0));
for (int i=1; i<ninlets; i++) { BFProxy *p = (BFProxy *)pd_new(BFProxy_class); p->parent = self->bself; p->inlet = i; inlet_new(self->bself, &p->ob_pd, 0,0); } self->bself->out = new t_outlet*[noutlets]; for (int i=0; i<noutlets; i++) { self->bself->out[i] = outlet_new(self->bself,&s_anything); } rb_funcall(rself,SI(initialize2),0); return rself; }
static void *BFObject_init (t_symbol *classsym, int ac, t_atom *at) { t_class *qlass = find_bfclass(classsym); if (!qlass) return 0; BFObject *bself = (BFObject *)pd_new(qlass); bself->magic = OBJECT_MAGIC; bself->check_magic(); FMessage fm = { self: bself, winlet:-1, selector: classsym, ac: ac, at: at, is_init: true }; long r = rb_rescue2( (RMethod)BFObject_init_1,(Ruby)&fm, (RMethod)BFObject_rescue,(Ruby)&fm, rb_eException,0); return r==Qnil ? 0 : (void *)bself; // return NULL if broken object }
static void BFObject_delete_1 (FMessage *fm) { fm->self->check_magic(); if (fm->self->rself) { rb_funcall(fm->self->rself,SI(delete),0); } else { post("BFObject_delete is NOT handling BROKEN object at %08x",(int)fm); } }
static void BFObject_delete (BFObject *bself) { bself->check_magic(); FMessage fm = { self: bself, winlet:-1, selector: gensym("delete"), ac: 0, at: 0, is_init: false }; rb_rescue2( (RMethod)BFObject_delete_1,(Ruby)&fm, (RMethod)BFObject_rescue,(Ruby)&fm, rb_eException,0); bself->magic = 0xDeadBeef; }
/* **************************************************************** */
struct RMessage { VALUE rself; ID sel; int argc; VALUE *argv; };
// this was called rb_funcall_rescue[...] but recently (ruby 1.8.2) // got a conflict with a new function in ruby.
VALUE rb_funcall_myrescue_1(RMessage *rm) { return rb_funcall2(rm->rself,rm->sel,rm->argc,rm->argv); }
static Ruby rb_funcall_myrescue_2 (RMessage *rm) { Ruby error_array = make_error_message(); // for (int i=0; i<rb_ary_len(error_array); i++) // post("%s\n",rb_str_ptr(rb_ary_ptr(error_array)[i])); post("%s",rb_str_ptr(rb_funcall(error_array,SI(join),1,rb_str_new2("\n")))); return Qnil; }
VALUE rb_funcall_myrescue(VALUE rself, ID sel, int argc, ...) { va_list foo; va_start(foo,argc); VALUE argv[argc]; for (int i=0; i<argc; i++) argv[i] = va_arg(foo,VALUE); RMessage rm = { rself, sel, argc, argv }; va_end(foo); return rb_rescue2( (RMethod)rb_funcall_myrescue_1,(Ruby)&rm, (RMethod)rb_funcall_myrescue_2,(Ruby)&rm, rb_eException,0); }
/* Call this to get a gobj's bounding rectangle in pixels */ void bf_getrectfn(t_gobj *x, struct _glist *glist, int *x1, int *y1, int *x2, int *y2) { BFObject *bself = (BFObject*)x; Ruby can = PTR2FIX(glist_getcanvas(glist)); Ruby a = rb_funcall_myrescue(bself->rself,SI(pd_getrect),1,can); if (TYPE(a)!=T_ARRAY || rb_ary_len(a)<4) { post("bf_getrectfn: return value should be 4-element array"); *x1=*y1=*x2=*y2=0; return; } *x1 = INT(rb_ary_ptr(a)[0]); *y1 = INT(rb_ary_ptr(a)[1]); *x2 = INT(rb_ary_ptr(a)[2]); *y2 = INT(rb_ary_ptr(a)[3]); }
/* and this to displace a gobj: */ void bf_displacefn(t_gobj *x, struct _glist *glist, int dx, int dy) { Ruby can = PTR2FIX(glist_getcanvas(glist)); BFObject *bself = (BFObject *)x; bself->te_xpix+=dx; bself->te_ypix+=dy; rb_funcall_myrescue(bself->rself,SI(pd_displace),3,can,INT2NUM(dx),INT2NUM(dy)); canvas_fixlinesfor(glist, (t_text *)x); }
/* change color to show selection: */ void bf_selectfn(t_gobj *x, struct _glist *glist, int state) { Ruby can = PTR2FIX(glist_getcanvas(glist)); rb_funcall_myrescue(((BFObject*)x)->rself,SI(pd_select),2,can,INT2NUM(state)); }
/* change appearance to show activation/deactivation: */ void bf_activatefn(t_gobj *x, struct _glist *glist, int state) { Ruby can = PTR2FIX(glist_getcanvas(glist)); rb_funcall_myrescue(((BFObject*)x)->rself,SI(pd_activate),2,can,INT2NUM(state)); }
/* warn a gobj it's about to be deleted */ void bf_deletefn(t_gobj *x, struct _glist *glist) { Ruby can = PTR2FIX(glist_getcanvas(glist)); rb_funcall_myrescue(((BFObject*)x)->rself,SI(pd_delete),1,can); canvas_deletelinesfor(glist, (t_text *)x); }
/* making visible or invisible */ void bf_visfn(t_gobj *x, struct _glist *glist, int flag) { Ruby can = PTR2FIX(glist_getcanvas(glist)); Ruby rself = ((BFObject*)x)->rself; DGS(FObject); self->check_magic(); rb_funcall_myrescue(((BFObject*)x)->rself,SI(pd_vis),2,can,INT2NUM(flag)); }
/* field a mouse click (when not in "edit" mode) */ int bf_clickfn(t_gobj *x, struct _glist *glist, int xpix, int ypix, int shift, int alt, int dbl, int doit) { Ruby can = PTR2FIX(glist_getcanvas(glist)); Ruby ret = rb_funcall_myrescue(((BFObject*)x)->rself,SI(pd_click),7,can, INT2NUM(xpix),INT2NUM(ypix), INT2NUM(shift),INT2NUM(alt), INT2NUM(dbl),INT2NUM(doit)); if (TYPE(ret) == T_FIXNUM) return INT(ret); post("bf_clickfn: expected Fixnum"); return 0; }
/* save to a binbuf */ void bf_savefn(t_gobj *x, t_binbuf *b) { rb_funcall_myrescue(((BFObject*)x)->rself,SI(pd_save),1,Qnil); }
/* open properties dialog */ void bf_propertiesfn(t_gobj *x, struct _glist *glist) { Ruby can = PTR2FIX(glist_getcanvas(glist)); rb_funcall_myrescue(((BFObject*)x)->rself,SI(pd_properties),1,can); }
/* get keypresses during focus */ void bf_keyfn(void *x, t_floatarg fkey) { rb_funcall_myrescue(((BFObject*)x)->rself,SI(pd_key),1,INT2NUM((int)fkey)); }
/* get motion diff during focus */ void bf_motionfn(void *x, t_floatarg dx, t_floatarg dy) { rb_funcall_myrescue(((BFObject*)x)->rself,SI(pd_motion),2, INT2NUM((int)dx), INT2NUM((int)dy)); }
/* **************************************************************** */
static void BFObject_class_init_1 (t_class *qlass) { class_addanything(qlass,(t_method)BFObject_method_missing0); }
\class FObject
static Ruby FObject_s_install2(Ruby rself, Ruby name) { if (TYPE(name)!=T_STRING) RAISE("name must be String"); t_class *qlass = class_new(gensym(rb_str_ptr(name)), (t_newmethod)BFObject_init, (t_method)BFObject_delete, sizeof(BFObject), CLASS_DEFAULT, A_GIMME,0); rb_ivar_set(rself, SI(@bfclass), PTR2FIX(qlass)); FMessage fm = {0, -1, 0, 0, 0, false}; rb_rescue2( (RMethod)BFObject_class_init_1,(Ruby)qlass, (RMethod)BFObject_rescue,(Ruby)&fm, rb_eException,0); return Qnil; }
static Ruby FObject_send_out2(int argc, Ruby *argv, Ruby rself) { //\def Ruby send_out2(...) { DGS(FObject); BFObject *bself = self->bself; if (!bself) { //post("FObject#send_out2 : bself is NULL, rself=%08x",rself); return Qnil; } bself->check_magic(); Ruby qlass = rb_funcall(rself,SI(class),0); int outlet = INT(argv[0]); Ruby sym = argv[1]; argc-=2; argv+=2; t_atom sel, at[argc]; Bridge_export_value(sym,&sel); for (int i=0; i<argc; i++) Bridge_export_value(argv[i],at+i); t_outlet *out = bself->te_outlet; outlet_anything(bself->out[outlet],atom_getsymbol(&sel),argc,at); return Qnil; }
static Ruby FObject_s_set_help (Ruby rself, Ruby path) { path = rb_funcall(path,SI(to_s),0); Ruby qlassid = rb_ivar_get(rself,SI(@bfclass)); if (qlassid==Qnil) RAISE("@bfclass==nil ???"); t_class *qlass = FIX2PTR(t_class,qlassid); class_sethelpsymbol(qlass,gensym(rb_str_ptr(path))); return Qnil; }
static Ruby GridFlow_s_gui (int argc, Ruby *argv, Ruby rself) { if (argc!=1) RAISE("bad args"); Ruby command = rb_funcall(argv[0],SI(to_s),0); sys_gui(rb_str_ptr(command)); return Qnil; }
static Ruby GridFlow_s_bind (Ruby rself, Ruby argv0, Ruby argv1) { if (TYPE(argv0)==T_STRING) { #if PD_VERSION_INT < 37 RAISE("requires Pd 0.37"); #else Ruby name = rb_funcall(argv0,SI(to_s),0); Ruby qlassid = rb_ivar_get(rb_hash_aref(rb_ivar_get(mGridFlow2,SI(@fclasses)),name),SI(@bfclass)); if (qlassid==Qnil) RAISE("no such class: %s",rb_str_ptr(name)); pd_typedmess(&pd_objectmaker,gensym(rb_str_ptr(name)),0,0); t_pd *o = pd_newest(); pd_bind(o,gensym(rb_str_ptr(argv1))); #endif } else { Ruby rself = argv0; DGS(FObject); t_symbol *s = gensym(rb_str_ptr(argv1)); t_pd *o = (t_pd *)(self->bself); //fprintf(stderr,"binding %08x to: "%s" (%08x %s)\n",o,rb_str_ptr(argv[1]),s,s->s_name); pd_bind(o,s); } return Qnil; }
static Ruby FObject_s_gui_enable (Ruby rself) { Ruby qlassid = rb_ivar_get(rself,SI(@bfclass)); if (qlassid==Qnil) RAISE("no class id ?"); t_widgetbehavior *wb = new t_widgetbehavior; wb->w_getrectfn = bf_getrectfn; wb->w_displacefn = bf_displacefn; wb->w_selectfn = bf_selectfn; wb->w_activatefn = bf_activatefn; wb->w_deletefn = bf_deletefn; wb->w_visfn = bf_visfn; wb->w_clickfn = bf_clickfn; //wb->w_savefn = bf_savefn; //wb->w_propertiesfn = bf_propertiesfn; class_setwidget(FIX2PTR(t_class,qlassid),wb); return Qnil; }
static Ruby FObject_focus (Ruby rself, Ruby canvas_, Ruby x_, Ruby y_) { DGS(FObject); t_glist *canvas = FIX2PTR(t_glist,canvas_); t_gobj *bself = (t_gobj *)(self->bself); int x = INT(x_); int y = INT(y_); glist_grab(canvas,bself, bf_motionfn, bf_keyfn, x,y); return Qnil; }
// doesn't use rself but still is aside FObject_focus for symmetry reasons. static Ruby FObject_unfocus (Ruby rself, Ruby canvas_) { DGS(FObject); t_glist *canvas = FIX2PTR(t_glist,canvas_); glist_grab(canvas,0,0,0,0,0); return Qnil; }
static Ruby FObject_add_inlets (Ruby rself, Ruby n_) { DGS(FObject); if (!self->bself) RAISE("there is no bself"); int n = INT(n_); for (int i=self->bself->nin; i<self->bself->nin+n; i++) { BFProxy *p = (BFProxy *)pd_new(BFProxy_class); p->parent = self->bself; p->inlet = i; inlet_new(self->bself, &p->ob_pd, 0,0); } self->bself->nin+=n; return Qnil; }
static Ruby FObject_add_outlets (Ruby rself, Ruby n_) { DGS(FObject); if (!self->bself) RAISE("there is no bself"); int n = INT(n_); t_outlet **oldouts = self->bself->out; self->bself->out = new t_outlet*[self->bself->nout+n]; memcpy(self->bself->out,oldouts,self->bself->nout*sizeof(t_outlet*)); for (int i=self->bself->nout; i<self->bself->nout+n; i++) { self->bself->out[i] = outlet_new(self->bself,&s_anything); } self->bself->nout+=n; return Qnil; }
static Ruby bridge_add_to_menu (int argc, Ruby *argv, Ruby rself) { if (argc!=1) RAISE("bad args"); Ruby name = rb_funcall(argv[0],SI(to_s),0); Ruby qlassid = rb_ivar_get(rb_hash_aref(rb_ivar_get(mGridFlow2,SI(@fclasses)),name),SI(@bfclass)); if (qlassid==Qnil) RAISE("no such class: %s",rb_str_ptr(name)); //!@#$ return Qnil; }
static Ruby GridFlow_s_add_creator_2 (Ruby rself, Ruby name_) { t_symbol *name = gensym(rb_str_ptr(rb_funcall(name_,SI(to_s),0))); class_addcreator((t_newmethod)BFObject_init,name,A_GIMME,0); return Qnil; }
static Ruby FObject_get_position (Ruby rself, Ruby canvas) { DGS(FObject); t_text *bself = (t_text *)(self->bself); t_glist *c = FIX2PTR(t_glist,canvas); float x0,y0; if (c->gl_havewindow || !c->gl_isgraph) { x0=bself->te_xpix; y0=bself->te_ypix; } else { // graph-on-parent: have to zoom float zx = float(c->gl_x2 - c->gl_x1) / (c->gl_screenx2 - c->gl_screenx1); float zy = float(c->gl_y2 - c->gl_y1) / (c->gl_screeny2 - c->gl_screeny1); x0 = glist_xtopixels(c, c->gl_x1 + bself->te_xpix*zx); y0 = glist_ytopixels(c, c->gl_y1 + bself->te_ypix*zy); } Ruby a = rb_ary_new(); rb_ary_push(a,INT2NUM((int)x0)); rb_ary_push(a,INT2NUM((int)y0)); return a; }
\classinfo {} \end class FObject
//****************************************************************
\class Clock < CObject struct Clock : CObject { t_clock *serf; Ruby owner; /* copy of ptr that serf already has, for marking */ \decl void set (double systime); \decl void delay(double delaytime); \decl void unset(); };
void Clock_fn (Ruby rself) { rb_funcall_myrescue(rself,SI(call),0); } void Clock_mark (Clock *self) { rb_gc_mark(self->owner); } void Clock_free (Clock *self) { clock_free(self->serf); CObject_freeee(self); }
Ruby Clock_s_new (Ruby qlass, Ruby owner) { Clock *self = new Clock(); self->rself = Data_Wrap_Struct(qlass, Clock_mark, Clock_free, self); self->serf = clock_new((void*)owner,(t_method)Clock_fn); self->owner = owner; return self->rself; }
\def void set (double systime) { clock_set(serf, systime); } \def void delay(double delaytime) { clock_delay(serf,delaytime); } \def void unset() { clock_unset(serf); }
\classinfo {} \end class Clock
//****************************************************************
Ruby GridFlow_s_post_string (Ruby rself, Ruby string) { if (TYPE(string)!=T_STRING) RAISE("not a string!"); post("%s",rb_str_ptr(string)); return Qnil; }
#define SDEF(_name1_,_name2_,_argc_) \ rb_define_singleton_method(mGridFlow2,_name1_,(RMethod)GridFlow_s_##_name2_,_argc_)
Ruby gf_bridge_init (Ruby rself) { Ruby ver = EVAL("GridFlow::GF_VERSION"); if (strcmp(rb_str_ptr(ver), GF_VERSION) != 0) { RAISE("GridFlow version mismatch: " "main library is '%s'; bridge is '%s'", rb_str_ptr(ver), GF_VERSION); } syms = FIX2PTR(BuiltinSymbols,rb_ivar_get(mGridFlow2,SI(@bsym))); Ruby fo = EVAL("GridFlow::FObject"); rb_define_singleton_method(fo,"install2",(RMethod)FObject_s_install2,1); rb_define_singleton_method(fo,"gui_enable", (RMethod)FObject_s_gui_enable, 0); rb_define_singleton_method(fo,"set_help", (RMethod)FObject_s_set_help, 1); rb_define_method(fo,"get_position",(RMethod)FObject_get_position,1); rb_define_method(fo,"send_out2", (RMethod)FObject_send_out2,-1); rb_define_method(fo,"send_out2", (RMethod)FObject_send_out2,-1); rb_define_method(fo,"add_inlets", (RMethod)FObject_add_inlets, 1); rb_define_method(fo,"add_outlets", (RMethod)FObject_add_outlets, 1); rb_define_method(fo,"unfocus", (RMethod)FObject_unfocus, 1); rb_define_method(fo, "focus", (RMethod)FObject_focus, 3);
SDEF("post_string",post_string,1); SDEF("add_creator_2",add_creator_2,1); SDEF("gui",gui,-1); SDEF("bind",bind,2); // SDEF("add_to_menu",add_to_menu,-1);
\startall rb_define_singleton_method(EVAL("GridFlow::Clock" ),"new", (RMethod)Clock_s_new, 1); rb_define_singleton_method(EVAL("GridFlow::Pointer"),"new", (RMethod)Pointer_s_new, 1); mPointer = EVAL("GridFlow::Pointer"); EVAL("class<<GridFlow;attr_accessor :config; end"); EVAL("GridFlow.config = {'PUREDATA_PATH' => %{"PUREDATA_PATH"}}"); return Qnil; }
struct BFGridFlow : t_object {};
t_class *bindpatcher; static void *bindpatcher_init (t_symbol *classsym, int ac, t_atom *at) { t_pd *bself = pd_new(bindpatcher); if (ac!=1 || at->a_type != A_SYMBOL) { post("bindpatcher: oops"); } else { t_symbol *s = atom_getsymbol(at); post("binding patcher to: %s",s->s_name); pd_bind((t_pd *)canvas_getcurrent(),s); } return bself; }
extern "C" void gridflow_setup () { char *foo[] = {"Ruby-for-PureData","-w","-e",";"}; post("setting up Ruby-for-PureData..."); /* post("pd_getfilename() = %s", pd_getfilename()->s_name); post("pd_getdirname() = %s", pd_getdirname()->s_name); post("canvas_getcurrentdir() = %p", canvas_getcurrentdir()); char *dirresult = new char[242]; char *nameresult; int fd = open_via_path("","gridflow",".so",dirresult,&nameresult,242,1); post("open_via_path: fd=%d dirresult="%s" nameresult="%s"",fd,dirresult,nameresult); delete[] dirresult; */ ruby_init(); Init_stack(localize_sysstack()); ruby_options(COUNT(foo),foo); post("we are using Ruby version %s",rb_str_ptr(EVAL("RUBY_VERSION"))); Ruby cData = rb_const_get(rb_cObject,SI(Data)); BFProxy_class = class_new(gensym("ruby_proxy"), NULL,NULL,sizeof(BFProxy),CLASS_PD|CLASS_NOINLET, A_NULL); class_addanything(BFProxy_class,BFProxy_method_missing); rb_define_singleton_method(cData,"gf_bridge_init", (RMethod)gf_bridge_init,0);
mGridFlow2 = EVAL( "module GridFlow; class<<self; attr_reader :bridge_name; end; " "@bridge_name = 'puredata'; self end"); post("(done)"); if (! EVAL("begin require 'gridflow'; true; rescue Exception => e;\ STDERR.puts "[#{e.class}] [#{e.message}]:\n#{e.backtrace.join'\n'}"; false; end")) { post("ERROR: Cannot load GridFlow-for-Ruby (gridflow.so)\n"); return; } bindpatcher = class_new(gensym("bindpatcher"), (t_newmethod)bindpatcher_init, 0, sizeof(t_object),CLASS_DEFAULT,A_GIMME,0); }
--- NEW FILE: placebo.rb --- =begin $Id: placebo.rb,v 1.1 2005/10/04 02:02:13 matju Exp $
GridFlow Copyright (c) 2001,2002,2003,2004,2005 by Mathieu Bouchard
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
See file ../COPYING for further informations on licensing terms.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. =end
class Object def self.dummy(sel) self.module_eval "def #{sel}(*args) GridFlow.post "dummy #{sel}: %s", args.inspect end" end end
module GridFlow class<<self # def add_creator_2(*args) post "dummy add_creator_2: %s", args.inspect end dummy :add_creator_2 def post_string(s) STDERR.puts s end end class Clock def initialize(victim) @victim=victim end dummy :delay end class Pointer dummy :initialize end end
--- NEW FILE: puredata.rb --- =begin $Id: puredata.rb,v 1.1 2005/10/04 02:02:13 matju Exp $
GridFlow Copyright (c) 2001,2002 by Mathieu Bouchard
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
See file ../COPYING for further informations on licensing terms.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. =end
# <matju> alx1: in puredata.rb, just after the header, you have a %w() block, # and in it you write the name of your object, and if your helpfile is not # named like your object, then you add an equal sign and the filename
#!@#$ DON'T PUT ABSTRACTIONS IN THE %w() !!! # @mouse=help_mouse @motion_detection=help_motion_detect @fade=help_fade # @apply_colormap_channelwise @checkers @complex_sq @contrast # @posterize @ravel @greyscale_to_rgb @rgb_to_greyscale @solarize @spread #rgb_to_yuv=#rgb_to_yuv_and_#yuv_to_rgb #yuv_to_rgb=#rgb_to_yuv_and_#yuv_to_rgb #clip #contrast #fade #numop #remap_image
# NEW help files #!@#$ (what's #+-help.pd ? #print-help2.pd ?) %w( # #cast #dim #reverse #pack=#unpack-#pack #unpack=#unpack-#pack renamefile #in plotter_control listelement exec ls #print unix_time ).each {|name| if name =~ /=/ then name,file = name.split(/=/) else file = name end begin x = GridFlow.fclasses[name] x.set_help "gridflow/flow_classes/#{file}-help.pd" rescue Exception => e GridFlow.post "for [#{name}], #{e.class}: #{e}" # + ":\n" + e.backtrace.join("\n") end }
# OLD help files %w( @cast @convolve @downscale_by @draw_polygon @export=@importexport @finished @fold @for @global @grade @import=@importexport @inner=@foldinnerouter @in=@inout @join @layer @outer=@foldinnerouter @out=@inout @! @perspective printargs @print @redim rubyprint @scale_by @scale_to @scan @store ).each {|name| if name =~ /=/ then name,file = name.split(/=/) else file = name end begin GridFlow.fclasses[name].set_help "gridflow/#{file}.pd" rescue Exception => e GridFlow.post "ruby #{e.class}: #{e}:\n" + e.backtrace.join("\n") end }
#GridFlow.gui "frame .controls.gridflow -relief ridge -borderwidth 2\n" #GridFlow.gui "button .controls.gridflow.button -text FOO\n" #GridFlow.gui "pack .controls.gridflow.button -side left\n" #GridFlow.gui "pack .controls.gridflow -side right\n"
GridFlow.gui %q{
if {[catch { # pd 0.37 menu .mbar.gridflow -tearoff $pd_tearoff .mbar add cascade -label "GridFlow" -menu .mbar.gridflow set gfmenu .mbar.gridflow }]} { # pd 0.36 ###the problem is that GridFlow.bind requires 0.37 } catch { $gfmenu add command -label "profiler_dump" -command {pd "gridflow profiler_dump;"} $gfmenu add command -label "profiler_reset" -command {pd "gridflow profiler_reset;"} $gfmenu add command -label "formats" -command {pd "gridflow formats;"} }
if {[string length [info command post]] == 0} { proc post {x} {puts $x} }
# if not running Impd: if {[string length [info command listener_new]] == 0} { # start of part duplicated from Impd proc listener_new {self name} { global _ set _($self:hist) {} set _($self:histi) 0 frame $self label $self.label -text "$name: " entry $self.entry -width 40 # entry $self.count -width 5 pack $self.label -side left pack $self.entry -side left -fill x -expand yes # pack $self.count -side left pack $self -fill x -expand no bind $self.entry <Up> "listener_up $self" bind $self.entry <Down> "listener_down $self" }
proc listener_up {self} { global _ if {$_($self:histi) > 0} {set _($self:histi) [expr -1+$_($self:histi)]} $self.entry delete 0 end $self.entry insert 0 [lindex $_($self:hist) $_($self:histi)] $self.entry icursor end # $self.count delete 0 end # $self.count insert 0 "$_($self:histi)/[llength $_($self:hist)]" }
proc listener_down {self} { global _ if {$_($self:histi) < [llength $_($self:hist)]} {incr _($self:histi)} $self.entry delete 0 end $self.entry insert 0 [lindex $_($self:hist) $_($self:histi)] $self.entry icursor end # $self.count delete 0 end # $self.count insert 0 "$_($self:histi)/[llength $_($self:hist)]" }
proc listener_append {self v} { global _ lappend _($self:hist) $v set _($self:histi) [llength $_($self:hist)] }
proc tcl_eval {} { set l [.tcl.entry get] post "tcl: $l" post "returns: [eval $l]" listener_append .tcl [.tcl.entry get] .tcl.entry delete 0 end
} if {[catch { listener_new .tcl "Tcl" bind .tcl.entry <Return> {tcl_eval} }]} { listener_new .tcl "Tcl" {tcl_eval} }
} # end of part duplicated from Impd
proc ruby_eval {} { set l {} foreach c [split [.ruby.entry get] ""] {lappend l [scan $c %c]} pd "gridflow eval $l;" listener_append .ruby [.ruby.entry get] .ruby.entry delete 0 end }
if {[catch { listener_new .ruby "Ruby" bind .ruby.entry <Return> {ruby_eval} }]} { listener_new .ruby "Ruby" {ruby_eval} }
} # GridFlow.gui
if false GridFlow.gui %q{ catch { if {[file exists ${pd_guidir}/lib/gridflow/icons/peephole.gif]} { global pd_guidir image create photo icon_peephole -file ${pd_guidir}/lib/gridflow/icons/peephole.gif global butt button_bar_add peephole {guiext peephole} } { puts $stderr GAAAH } } } # GridFlow.gui end