diff options
Diffstat (limited to 'externals/grill/py/source')
-rw-r--r-- | externals/grill/py/source/bound.cpp | 2 | ||||
-rw-r--r-- | externals/grill/py/source/clmeth.cpp | 30 | ||||
-rw-r--r-- | externals/grill/py/source/main.cpp | 621 | ||||
-rw-r--r-- | externals/grill/py/source/main.h | 197 | ||||
-rw-r--r-- | externals/grill/py/source/modmeth.cpp | 2 | ||||
-rw-r--r-- | externals/grill/py/source/py.cpp | 168 | ||||
-rw-r--r-- | externals/grill/py/source/pyargs.cpp | 146 | ||||
-rw-r--r-- | externals/grill/py/source/pyatom.cpp | 61 | ||||
-rw-r--r-- | externals/grill/py/source/pyatom.h | 19 | ||||
-rw-r--r-- | externals/grill/py/source/pybase.cpp | 672 | ||||
-rw-r--r-- | externals/grill/py/source/pybase.h | 206 | ||||
-rw-r--r-- | externals/grill/py/source/pybuffer.cpp | 2 | ||||
-rw-r--r-- | externals/grill/py/source/pyext.cpp | 141 | ||||
-rw-r--r-- | externals/grill/py/source/pyext.h | 6 | ||||
-rw-r--r-- | externals/grill/py/source/pyprefix.h | 12 | ||||
-rw-r--r-- | externals/grill/py/source/register.cpp | 2 |
16 files changed, 1258 insertions, 1029 deletions
diff --git a/externals/grill/py/source/bound.cpp b/externals/grill/py/source/bound.cpp index a5ace4ee..4c57f65f 100644 --- a/externals/grill/py/source/bound.cpp +++ b/externals/grill/py/source/bound.cpp @@ -66,7 +66,7 @@ bool pyext::boundmeth(flext_base *th,t_symbol *sym,int argc,t_atom *argv,void *d PyThreadState *state = pyth->PyLock(); - PyObject *args = MakePyArgs(sym,argc,argv,-1,obj->self != NULL); + PyObject *args = MakePyArgs(sym,argc,argv); // call all functions bound by this symbol for(FuncSet::iterator it = obj->funcs.begin(); it != obj->funcs.end(); ++it) { diff --git a/externals/grill/py/source/clmeth.cpp b/externals/grill/py/source/clmeth.cpp index a8e1ceb7..303b5888 100644 --- a/externals/grill/py/source/clmeth.cpp +++ b/externals/grill/py/source/clmeth.cpp @@ -177,28 +177,18 @@ PyObject *pyext::pyext_outlet(PyObject *,PyObject *args) if(!tp) val = PySequence_GetSlice(args,2,sz); // new ref - flext::AtomListStatic<16> lst; - if(GetPyArgs(lst,val)) { - int o = PyInt_AsLong(outl); - if(o >= 1 && o <= ext->Outlets()) { - // offset outlet by signal outlets - o += ext->sigoutlets; - - // by using the queue there is no immediate call of the next object - // deadlock would occur if this was another py/pyext object! - if(lst.Count() && IsSymbol(lst[0])) - ext->ToOutAnything(o-1,GetSymbol(lst[0]),lst.Count()-1,lst.Atoms()+1); - else if(lst.Count() > 1) - ext->ToOutList(o-1,lst); - else - ext->ToOutAtom(o-1,*lst.Atoms()); + int o = PyInt_AsLong(outl); + if(o >= 1 && o <= ext->Outlets()) { + // offset outlet by signal outlets + o += ext->sigoutlets; + + if(ext->OutObject(ext,o,val)) ok = true; - } - else - PyErr_SetString(PyExc_ValueError,"pyext - _outlet: index out of range"); + else + PyErr_SetString(PyExc_ValueError,"pyext - _outlet: invalid arguments"); } - else - PyErr_SetString(PyExc_ValueError,"pyext - _outlet: invalid arguments"); + else + PyErr_SetString(PyExc_ValueError,"pyext - _outlet: index out of range"); if(!tp) Py_DECREF(val); } diff --git a/externals/grill/py/source/main.cpp b/externals/grill/py/source/main.cpp index 428afea7..399f35c1 100644 --- a/externals/grill/py/source/main.cpp +++ b/externals/grill/py/source/main.cpp @@ -8,625 +8,6 @@ WARRANTIES, see the file, "license.txt," in this distribution. */ -#include "main.h" -#include <map> +#include "pybase.h" -static PyMethodDef StdOut_Methods[] = -{ - { "write", pybase::StdOut_Write, 1 }, - { NULL, NULL, } -}; -static PyObject *gcollect = NULL; - -#ifdef FLEXT_THREADS - -typedef std::map<flext::thrid_t,PyThreadState *> PyThrMap; - -static PyInterpreterState *pymain = NULL; -static PyThrMap pythrmap; -PyThreadState *pybase::pythrsys = NULL; - -int pybase::lockcount = 0; - -PyThreadState *pybase::FindThreadState() -{ - flext::thrid_t id = flext::GetThreadId(); - PyThrMap::iterator it = pythrmap.find(id); - if(it == pythrmap.end()) { - // Make new thread state - PyThreadState *st = PyThreadState_New(pymain); - pythrmap[id] = st; - return st; - } - else - return it->second; -} - -void pybase::FreeThreadState() -{ - flext::thrid_t id = flext::GetThreadId(); - PyThrMap::iterator it = pythrmap.find(id); - if(it != pythrmap.end()) { - // clear out any cruft from thread state object - PyThreadState_Clear(it->second); - // delete my thread state object - PyThreadState_Delete(it->second); - // delete from map - pythrmap.erase(it); - } -} -#endif - - -PyObject *pybase::module_obj = NULL; -PyObject *pybase::module_dict = NULL; - - -void initsymbol(); -void initsamplebuffer(); - -void pybase::lib_setup() -{ - post(""); - post("------------------------------------------------"); - post("py/pyext %s - python script objects",PY__VERSION); - post("(C)2002-2005 Thomas Grill - http://grrrr.org/ext"); - post(""); - post("using Python %s",Py_GetVersion()); - -#ifdef FLEXT_DEBUG - post(""); - post("DEBUG version compiled on %s %s",__DATE__,__TIME__); -#endif - - // ------------------------------------------------------------- - - Py_Initialize(); - -#ifdef FLEXT_DEBUG -// Py_VerboseFlag = 1; -#endif - -#ifdef FLEXT_THREADS - // enable thread support and acquire the global thread lock - PyEval_InitThreads(); - - // get thread state - pythrsys = PyThreadState_Get(); - // get main interpreter state - pymain = pythrsys->interp; - - // add thread state of main thread to map - pythrmap[GetThreadId()] = pythrsys; -#endif - - // sys.argv must be set to empty tuple - char *nothing = ""; - PySys_SetArgv(0,¬hing); - - // register/initialize pyext module only once! - module_obj = Py_InitModule(PYEXT_MODULE, func_tbl); - module_dict = PyModule_GetDict(module_obj); // borrowed reference - - PyModule_AddStringConstant(module_obj,"__doc__",(char *)py_doc); - - // redirect stdout - PyObject* py_out; - py_out = Py_InitModule("stdout", StdOut_Methods); - PySys_SetObject("stdout", py_out); - py_out = Py_InitModule("stderr", StdOut_Methods); - PySys_SetObject("stderr", py_out); - - // get garbage collector function - PyObject *gcobj = PyImport_ImportModule("gc"); - if(gcobj) { - gcollect = PyObject_GetAttrString(gcobj,"collect"); - Py_DECREF(gcobj); - } - - // add symbol type - initsymbol(); - PyModule_AddObject(module_obj,"Symbol",(PyObject *)&pySymbol_Type); - - // pre-defined symbols - PyModule_AddObject(module_obj,"_s_",(PyObject *)pySymbol__); - PyModule_AddObject(module_obj,"_s_bang",(PyObject *)pySymbol_bang); - PyModule_AddObject(module_obj,"_s_list",(PyObject *)pySymbol_list); - PyModule_AddObject(module_obj,"_s_symbol",(PyObject *)pySymbol_symbol); - PyModule_AddObject(module_obj,"_s_float",(PyObject *)pySymbol_float); - PyModule_AddObject(module_obj,"_s_int",(PyObject *)pySymbol_int); - - // add samplebuffer type - initsamplebuffer(); - PyModule_AddObject(module_obj,"Buffer",(PyObject *)&pySamplebuffer_Type); - - // ------------------------------------------------------------- - - FLEXT_SETUP(pyobj); - FLEXT_SETUP(pyext); - FLEXT_DSP_SETUP(pydsp); - -#ifdef FLEXT_THREADS - // release global lock - PyEval_ReleaseLock(); -#endif - - post("------------------------------------------------"); - post(""); -} - -FLEXT_LIB_SETUP(py,pybase::lib_setup) - - -pybase::pybase() - : module(NULL) -#ifdef FLEXT_THREADS - , shouldexit(false),thrcount(0),stoptick(0) -#endif - , detach(0) -{ - PyThreadState *state = PyLockSys(); - Py_INCREF(module_obj); - PyUnlock(state); -} - -pybase::~pybase() -{ - PyThreadState *state = PyLockSys(); - Py_XDECREF(module_obj); - PyUnlock(state); -} - -void pybase::Exit() -{ -#ifdef FLEXT_THREADS - shouldexit = true; - qucond.Signal(); - if(thrcount) { - // Wait for a certain time - for(int i = 0; i < (PY_STOP_WAIT/PY_STOP_TICK) && thrcount; ++i) - Sleep(PY_STOP_TICK*0.001f); - if(thrcount) { - // Wait forever - post("py/pyext - Waiting for thread termination!"); - while(thrcount) Sleep(PY_STOP_TICK*0.001f); - post("py/pyext - Okay, all threads have terminated"); - } - } -#endif -} - -void pybase::GetDir(PyObject *obj,AtomList &lst) -{ - if(obj) { - PyThreadState *state = PyLock(); - - PyObject *pvar = PyObject_Dir(obj); - if(!pvar) - PyErr_Print(); // no method found - else { - if(!GetPyArgs(lst,pvar)) - post("py/pyext - Argument list could not be created"); - Py_DECREF(pvar); - } - - PyUnlock(state); - } -} - -void pybase::m__dir(PyObject *obj) -{ - AtomList lst; - GetDir(obj,lst); - // dump dir to attribute outlet - DumpOut(NULL,lst.Count(),lst.Atoms()); -} - -void pybase::m__doc(PyObject *obj) -{ - if(obj) { - PyThreadState *state = PyLock(); - - PyObject *docf = PyDict_GetItemString(obj,"__doc__"); // borrowed!!! - if(docf && PyString_Check(docf)) { - post(""); - const char *s = PyString_AS_STRING(docf); - - // FIX: Python doc strings can easily be larger than 1k characters - // -> split into separate lines - for(;;) { - char buf[1024]; - char *nl = strchr((char *)s,'\n'); // the cast is for Borland C++ - if(!nl) { - // no more newline found - post(s); - break; - } - else { - // copy string before newline to temp buffer and post - unsigned int l = nl-s; - if(l >= sizeof(buf)) l = sizeof buf-1; - strncpy(buf,s,l); // copy all but newline - buf[l] = 0; - post(buf); - s = nl+1; // set after newline - } - } - } - - PyUnlock(state); - } -} - -void pybase::OpenEditor() -{ - // this should once open the editor.... -} - -void pybase::SetArgs() -{ - // script arguments - int argc = args.Count(); - const t_atom *argv = args.Atoms(); - char **sargv = new char *[argc+1]; - for(int i = 0; i <= argc; ++i) { - sargv[i] = new char[256]; - if(!i) - strcpy(sargv[i],"py/pyext"); - else - GetAString(argv[i-1],sargv[i],255); - } - - // the arguments to the module are only recognized once! (at first use in a patcher) - PySys_SetArgv(argc+1,sargv); - - for(int j = 0; j <= argc; ++j) delete[] sargv[j]; - delete[] sargv; -} - -bool pybase::ImportModule(const char *name) -{ - if(!name) return false; - if(modname == name) return true; - modname = name; - return ReloadModule(); -} - -void pybase::UnimportModule() -{ - if(!module) return; - - FLEXT_ASSERT(dict && module_obj && module_dict); - - Py_DECREF(module); - - // reference count to module is not 0 here, altough probably the last instance was unloaded - // Python retains one reference to the module all the time - // we don't care - - module = NULL; - dict = NULL; -} - -bool pybase::ReloadModule() -{ - bool ok = false; - - SetArgs(); - PyObject *newmod = module - ?PyImport_ReloadModule(module) - :PyImport_ImportModule((char *)modname.c_str()); - - if(!newmod) { - // unload faulty module - if(module) UnimportModule(); - } - else { - Py_XDECREF(module); - module = newmod; - dict = PyModule_GetDict(module); // borrowed - ok = true; - } - return ok; -} - -void pybase::GetModulePath(const char *mod,char *dir,int len) -{ -#if FLEXT_SYS == FLEXT_SYS_PD - // uarghh... pd doesn't show its path for extra modules - - char *name; - int fd = open_via_path("",mod,".py",dir,&name,len,0); - if(fd > 0) close(fd); - else name = NULL; - - // if dir is current working directory... name points to dir - if(dir == name) strcpy(dir,"."); -#elif FLEXT_SYS == FLEXT_SYS_MAX - // how do i get the path in Max/MSP? - short path; - long type; - char smod[1024]; - strcat(strcpy(smod,mod),".py"); - if(!locatefile_extended(smod,&path,&type,&type,-1)) { -#if FLEXT_OS == FLEXT_OS_WIN - path_topathname(path,NULL,dir); -#else - // convert pathname to unix style - path_topathname(path,NULL,smod); - char *colon = strchr(smod,':'); - if(colon) { - *colon = 0; - strcpy(dir,"/Volumes/"); - strcat(dir,smod); - strcat(dir,colon+1); - } - else - strcpy(dir,smod); -#endif - } - else - // not found - *dir = 0; -#else - *dir = 0; -#endif -} - -void pybase::AddToPath(const char *dir) -{ - if(dir && *dir) { - PyObject *pobj = PySys_GetObject("path"); - if(pobj && PyList_Check(pobj)) { - PyObject *ps = PyString_FromString(dir); - if(!PySequence_Contains(pobj,ps)) - PyList_Append(pobj,ps); // makes new reference - Py_DECREF(ps); - } - PySys_SetObject("path",pobj); // steals reference to pobj - } -} - -static const t_symbol *sym_response = flext::MakeSymbol("response"); - -void pybase::Respond(bool b) -{ - if(respond) { - t_atom a; - SetBool(a,b); - DumpOut(sym_response,1,&a); - } -} - -void pybase::Reload() -{ - PyThreadState *state = PyLockSys(); - - PyObject *reg = GetRegistry(REGNAME); - - if(reg) { - PyObject *key; - int pos = 0; - while(PyDict_Next(reg,&pos,&key,NULL)) { - pybase *th = (pybase *)PyLong_AsLong(key); - FLEXT_ASSERT(th); - th->Unload(); - } - - UnloadModule(); - } - - bool ok = ReloadModule(); - - if(ok) { - LoadModule(); - - if(reg) { - SetRegistry(REGNAME,reg); - - PyObject *key; - int pos = 0; - while(PyDict_Next(reg,&pos,&key,NULL)) { - pybase *th = (pybase *)PyLong_AsLong(key); - FLEXT_ASSERT(th); - th->Load(); - } - } - else - Load(); - } - - Report(); - PyUnlock(state); -} - - - -static PyObject *output = NULL; - -// post to the console -PyObject* pybase::StdOut_Write(PyObject* self, PyObject* args) -{ - // should always be a tuple - FLEXT_ASSERT(PyTuple_Check(args)); - - const int sz = PyTuple_GET_SIZE(args); - - for(int i = 0; i < sz; ++i) { - PyObject *val = PyTuple_GET_ITEM(args,i); // borrowed reference - PyObject *str = PyObject_Str(val); // new reference - char *cstr = PyString_AS_STRING(str); - char *lf = strchr(cstr,'\n'); - - // line feed in string - if(!lf) { - // no -> just append - if(output) - PyString_ConcatAndDel(&output,str); // str is decrefd - else - output = str; // take str reference - } - else { - // yes -> append up to line feed, reset output buffer to string remainder - PyObject *part = PyString_FromStringAndSize(cstr,lf-cstr); // new reference - if(output) - PyString_ConcatAndDel(&output,part); // str is decrefd - else - output = part; // take str reference - - // output concatenated string - post(PyString_AS_STRING(output)); - - Py_DECREF(output); - output = PyString_FromString(lf+1); // new reference - } - } - - Py_INCREF(Py_None); - return Py_None; -} - - -class work_data -{ -public: - work_data(PyObject *f,PyObject *a): fun(f),args(a) {} - ~work_data() { Py_DECREF(fun); Py_DECREF(args); } - - PyObject *fun,*args; -}; - -bool pybase::gencall(PyObject *pmeth,PyObject *pargs) -{ - bool ret = false; - - // Now call method - switch(detach) { - case 0: - ret = callpy(pmeth,pargs); - Py_DECREF(pargs); - Py_DECREF(pmeth); - break; -#ifdef FLEXT_THREADS - case 1: - // put call into queue - ret = qucall(pmeth,pargs); - break; - case 2: - // each call a new thread - if(!shouldexit) { - ret = thrcall(new work_data(pmeth,pargs)); - if(!ret) post("py/pyext - Failed to launch thread!"); - } - break; -#endif - default: - post("py/pyext - Unknown detach mode"); - } - return ret; -} - -void pybase::work_wrapper(void *data) -{ - FLEXT_ASSERT(data); - -#ifdef FLEXT_THREADS - ++thrcount; -#endif - - PyThreadState *state = PyLock(); - - // call worker - work_data *w = (work_data *)data; - callpy(w->fun,w->args); - delete w; - - PyUnlock(state); - -#ifdef FLEXT_THREADS - --thrcount; -#endif -} - -#ifdef FLEXT_THREADS -bool pybase::qucall(PyObject *fun,PyObject *args) -{ - FifoEl *el = qufifo.New(); - el->Set(fun,args); - qufifo.Put(el); - qucond.Signal(); - return true; -} - -void pybase::threadworker() -{ - ++thrcount; - - FifoEl *el; - PyThreadState *my = FindThreadState(),*state; - - for(;;) { - while(el = qufifo.Get()) { - ++thrcount; - state = PyLock(my); - callpy(el->fun,el->args); - Py_XDECREF(el->fun); - Py_XDECREF(el->args); - PyUnlock(state); - qufifo.Free(el); - --thrcount; - } - if(shouldexit) - break; - else - qucond.Wait(); - } - - state = PyLock(my); - // unref remaining Python objects - while(el = qufifo.Get()) { - Py_XDECREF(el->fun); - Py_XDECREF(el->args); - qufifo.Free(el); - } - PyUnlock(state); - - --thrcount; -} -#endif - -#if FLEXT_SYS == FLEXT_SYS_MAX -short pybase::patcher_myvol(t_patcher *x) -{ - t_box *w; - if (x->p_vol) - return x->p_vol; - else if (w = (t_box *)x->p_vnewobj) - return patcher_myvol(w->b_patcher); - else - return 0; -} -#endif - -bool pybase::collect() -{ - if(gcollect) { - PyObject *ret = PyObject_CallObject(gcollect,NULL); - if(ret) { -#ifdef FLEXT_DEBUG - int refs = PyInt_AsLong(ret); - if(refs) post("py/pyext - Garbage collector reports %i unreachable objects",refs); -#endif - Py_DECREF(ret); - return false; - } - } - return true; -} - -/* -PY_EXPORT PyThreadState *py_Lock(PyThreadState *st = NULL) { return pybase::PyLock(st?st:pybase::FindThreadState()); } -PY_EXPORT PyThreadState *py_LockSys() { return pybase::PyLockSys(); } -PY_EXPORT void py_Unlock(PyThreadState *st) { pybase::PyUnlock(st); } -*/ diff --git a/externals/grill/py/source/main.h b/externals/grill/py/source/main.h index 0b94274e..479c082d 100644 --- a/externals/grill/py/source/main.h +++ b/externals/grill/py/source/main.h @@ -12,20 +12,8 @@ WARRANTIES, see the file, "license.txt," in this distribution. #define __MAIN_H #include "pyprefix.h" -#include "pysymbol.h" -#include "pybuffer.h" -#include <flcontainers.h> -#include <string> -#if FLEXT_OS == FLEXT_LINUX || FLEXT_OS == FLEXT_IRIX -#include <unistd.h> -#endif - -#if FLEXT_SYS == FLEXT_SYS_PD && (!defined (PD_MINOR_VERSION) || PD_MINOR_VERSION < 37) -#error PD version >= 0.37 required, please upgrade! -#endif - -#define PY__VERSION "0.2.0" +#define PY__VERSION "0.2.1pre" #define PYEXT_MODULE "pyext" // name for module @@ -37,7 +25,6 @@ WARRANTIES, see the file, "license.txt," in this distribution. #define PY_STOP_TICK 1 // ms - class FifoEl : public Fifo::Cell { @@ -48,186 +35,4 @@ public: typedef PooledFifo<FifoEl> PyFifo; - -class pybase - : public flext -{ -public: - pybase(); - virtual ~pybase(); - - void Exit(); - - static PyObject *MakePyArgs(const t_symbol *s,int argc,const t_atom *argv,int inlet = -1,bool withself = false); - static bool GetPyArgs(AtomList &lst,PyObject *pValue,int offs = 0,PyObject **self = NULL); - - static void lib_setup(); - -protected: - - virtual void DumpOut(const t_symbol *sym,int argc,const t_atom *argv) = 0; - - void m__dir(PyObject *obj); - void m__doc(PyObject *obj); - - void m_dir() { m__dir(module); } - void mg_dir(AtomList &lst) { m__dir(module); } - void m_doc() { m__doc(dict); } - - std::string modname; // module name - PyObject *module,*dict; // object module and associated dictionary - - static const char *py_doc; - - void GetDir(PyObject *obj,AtomList &lst); - - AtomListStatic<16> args; - - void GetModulePath(const char *mod,char *dir,int len); - void AddToPath(const char *dir); - void SetArgs(); - - // reload module and all connected objects - void Reload(); - - bool ImportModule(const char *name); - void UnimportModule(); - bool ReloadModule(); - - // Get module registry - PyObject *GetRegistry(const char *regname); - // Set module registry - void SetRegistry(const char *regname,PyObject *reg); - - // Register object - void Register(PyObject *reg); - // Unregister object - void Unregister(PyObject *reg); - - virtual void LoadModule() = 0; - virtual void UnloadModule() = 0; - - virtual void Load() = 0; - virtual void Unload() = 0; - - void OpenEditor(); - void Respond(bool b); - - void Report() { while(PyErr_Occurred()) PyErr_Print(); } - - static bool IsAnything(const t_symbol *s) { return s && s != sym_float && s != sym_int && s != sym_symbol && s != sym_list && s != sym_pointer; } - - enum retval { nothing,atom,sequ }; - - // --- module stuff ----- - - static PyObject *module_obj,*module_dict; - static PyMethodDef func_tbl[]; - - static PyObject *py__doc__(PyObject *,PyObject *args); - static PyObject *py_send(PyObject *,PyObject *args); -#ifdef FLEXT_THREADS - static PyObject *py_priority(PyObject *,PyObject *args); -#endif - - static PyObject *py_arraysupport(PyObject *,PyObject *args); - static PyObject *py_samplerate(PyObject *,PyObject *args); - static PyObject *py_blocksize(PyObject *,PyObject *args); - -#if FLEXT_SYS == FLEXT_SYS_PD - static PyObject *py_getvalue(PyObject *,PyObject *args); - static PyObject *py_setvalue(PyObject *,PyObject *args); -#endif - -#ifdef PY_NUMARRAY - static void setupNumarray(); - static PyObject *py_import(PyObject *,PyObject *args); - static PyObject *py_export(PyObject *,PyObject *args); -#endif - - // ----thread stuff ------------ - - virtual void m_stop(int argc,const t_atom *argv); - - bool respond; -#ifdef FLEXT_THREADS - bool shouldexit; - int thrcount; - int stoptick; - Timer stoptmr; - - void tick(void *); -#endif - - int detach; - - bool gencall(PyObject *fun,PyObject *args); - virtual bool thrcall(void *data) = 0; - virtual bool callpy(PyObject *fun,PyObject *args) = 0; - -#if FLEXT_SYS == FLEXT_SYS_MAX - static short patcher_myvol(t_patcher *x); -#endif - - static bool collect(); - -protected: - - void work_wrapper(void *data); - -#ifdef FLEXT_THREADS - bool qucall(PyObject *fun,PyObject *args); - void threadworker(); - PyFifo qufifo; - ThrCond qucond; - static PyThreadState *pythrsys; - - static PyThreadState *FindThreadState(); - static void FreeThreadState(); -#else - static PyThreadState *FindThreadState() { return NULL; } -#endif - -public: - -#ifdef FLEXT_THREADS - ThrMutex mutex; - inline void Lock() { mutex.Unlock(); } - inline void Unlock() { mutex.Unlock(); } - - // this is especially needed when one py/pyext object calls another one - // we don't want the message to be queued, but otoh we have to avoid deadlock - // (recursive calls can only happen in the system thread) - static int lockcount; - - static PyThreadState *PyLock(PyThreadState *st = FindThreadState()) - { - if(!IsSystemThread() || !lockcount++) PyEval_AcquireLock(); - return PyThreadState_Swap(st); - } - - static PyThreadState *PyLockSys() - { - if(!lockcount++) PyEval_AcquireLock(); - return PyThreadState_Swap(pythrsys); - } - - static void PyUnlock(PyThreadState *st) - { - PyThreadState *old = PyThreadState_Swap(st); - if(old != pythrsys || !--lockcount) PyEval_ReleaseLock(); - } - -#else - inline void Lock() {} - inline void Unlock() {} - - static PyThreadState *PyLock(PyThreadState * = NULL) { return NULL; } - static PyThreadState *PyLockSys() { return NULL; } - static void PyUnlock(PyThreadState *st) {} -#endif - - static PyObject* StdOut_Write(PyObject* Self, PyObject* Args); -}; - #endif diff --git a/externals/grill/py/source/modmeth.cpp b/externals/grill/py/source/modmeth.cpp index 33f0fc7b..d56441ac 100644 --- a/externals/grill/py/source/modmeth.cpp +++ b/externals/grill/py/source/modmeth.cpp @@ -8,7 +8,7 @@ WARRANTIES, see the file, "license.txt," in this distribution. */ -#include "main.h" +#include "pybase.h" // function table for module diff --git a/externals/grill/py/source/py.cpp b/externals/grill/py/source/py.cpp index f91d13b6..d007f0c3 100644 --- a/externals/grill/py/source/py.cpp +++ b/externals/grill/py/source/py.cpp @@ -8,8 +8,7 @@ WARRANTIES, see the file, "license.txt," in this distribution. */ -#include "main.h" - +#include "pybase.h" class pyobj : public pybase @@ -35,15 +34,6 @@ protected: void m_dir_() { m__dir(function); } void m_doc_() { m__doc(function); } - // methods for python arguments - void callwork(const t_symbol *s,int argc,const t_atom *argv); - - inline void m_bang() { callwork(NULL,0,NULL); } - inline void m_py_list(int argc,const t_atom *argv) { callwork(sym_list,argc,argv); } - inline void m_py_float(int argc,const t_atom *argv) { callwork(sym_float,argc,argv); } - inline void m_py_int(int argc,const t_atom *argv) { callwork(sym_int,argc,argv); } - inline void m_py_any(const t_symbol *s,int argc,const t_atom *argv) { callwork(s,argc,argv); } - const t_symbol *funname; PyObject *function; bool withfunction; @@ -60,6 +50,8 @@ protected: virtual bool thrcall(void *data); virtual void DumpOut(const t_symbol *sym,int argc,const t_atom *argv); + PyObject **objects; + private: virtual bool callpy(PyObject *fun,PyObject *args); @@ -67,21 +59,17 @@ private: static void Setup(t_classid c); FLEXT_CALLBACK(m_help) - FLEXT_CALLBACK(m_bang) FLEXT_CALLBACK(m_reload) FLEXT_CALLBACK_V(m_reload_) FLEXT_CALLBACK_V(m_set) FLEXT_CALLBACK(m_dir_) FLEXT_CALLBACK(m_doc_) - FLEXT_CALLBACK_V(m_py_float) - FLEXT_CALLBACK_V(m_py_list) - FLEXT_CALLBACK_V(m_py_int) - FLEXT_CALLBACK_A(m_py_any) - // callbacks FLEXT_ATTRVAR_I(detach) + FLEXT_ATTRVAR_B(xlate) FLEXT_ATTRVAR_B(respond) + FLEXT_CALLBACK_V(m_stop) FLEXT_CALLBACK(m_dir) FLEXT_CALLGET_V(mg_dir) @@ -114,56 +102,64 @@ void pyobj::Setup(t_classid c) FLEXT_CADDMETHOD_(c,0,"doc+",m_doc_); FLEXT_CADDMETHOD_(c,0,"dir+",m_dir_); - FLEXT_CADDBANG(c,0,m_bang); FLEXT_CADDMETHOD_(c,0,"set",m_set); - FLEXT_CADDMETHOD_(c,1,"float",m_py_float); - FLEXT_CADDMETHOD_(c,1,"int",m_py_int); - FLEXT_CADDMETHOD(c,1,m_py_list); - FLEXT_CADDMETHOD(c,1,m_py_any); - + FLEXT_CADDATTR_VAR1(c,"xlate",xlate); FLEXT_CADDATTR_VAR1(c,"respond",respond); } -pyobj::pyobj(int argc,const t_atom *argv): - funname(NULL),function(NULL),withfunction(false) +pyobj::pyobj(int argc,const t_atom *argv) + : funname(NULL) + , function(NULL) + , withfunction(false) + , objects(NULL) { - AddInAnything(2); - AddOutAnything(); - #ifdef FLEXT_THREADS FLEXT_ADDTIMER(stoptmr,tick); // launch thread worker FLEXT_CALLMETHOD(threadworker); #endif - if(argc > 2) args(argc-2,argv+2); - PyThreadState *state = PyLockSys(); + int inlets = -1; // -1 signals non-explicit definition + if(argc && CanbeInt(*argv)) { + inlets = GetAInt(*argv); + argv++,argc--; + } + + if(inlets >= 1) { + objects = new PyObject *[inlets]; + for(int i = 0; i < inlets; ++i) { objects[i] = Py_None; Py_INCREF(Py_None); } + } + + AddInAnything(1+(inlets < 0?1:inlets)); + AddOutAnything(); + + const char *funnm = NULL; + // init script module - if(argc >= 1) { - const char *sn = GetAString(argv[0]); + if(argc) { + AddCurrentPath(thisCanvas()); + + const char *sn = GetAString(*argv); + argv++,argc--; + if(sn) { - char dir[1024]; - GetModulePath(sn,dir,sizeof(dir)); - // set script path - AddToPath(dir); + char modnm[64]; + strcpy(modnm,sn); -#if FLEXT_SYS == FLEXT_SYS_PD - // add dir of current patch to path - AddToPath(GetString(canvas_getdir(thisCanvas()))); - // add current dir to path - AddToPath(GetString(canvas_getcurrentdir())); -#elif FLEXT_SYS == FLEXT_SYS_MAX - short path = patcher_myvol(thisCanvas()); - path_topathname(path,NULL,dir); - AddToPath(dir); -#else - #pragma message("Adding current dir to path is not implemented") -#endif + char *pt = strrchr(modnm,'.'); // search for last dot + if(pt && *pt) { + funnm = pt+1; + *pt = 0; + } + + char dir[1024]; + GetModulePath(modnm,dir,sizeof(dir)); + AddToPath(dir); - ImportModule(sn); + ImportModule(modnm); } else PyErr_SetString(PyExc_ValueError,"Invalid module name"); @@ -171,14 +167,20 @@ pyobj::pyobj(int argc,const t_atom *argv): Register(GetRegistry(REGNAME)); - if(argc >= 2) { - const char *fn = GetAString(argv[1]); - if(fn) - SetFunction(fn); + if(funnm || argc) { + if(!funnm) { + funnm = GetAString(*argv); + argv++,argc--; + } + + if(funnm) + SetFunction(funnm); else PyErr_SetString(PyExc_ValueError,"Invalid function name"); } + if(argc) args(argc,argv); + Report(); PyUnlock(state); @@ -186,7 +188,12 @@ pyobj::pyobj(int argc,const t_atom *argv): pyobj::~pyobj() { - PyThreadState *state = PyLockSys(); + if(objects) { + for(int i = 0; i < CntIn()-1; ++i) Py_DECREF(objects[i]); + delete[] objects; + } + + PyThreadState *state = PyLockSys(); Unregister(GetRegistry(REGNAME)); Report(); PyUnlock(state); @@ -198,13 +205,6 @@ void pyobj::Exit() flext_base::Exit(); } -bool pyobj::CbMethodResort(int n,const t_symbol *s,int argc,const t_atom *argv) -{ - if(n == 1) - post("%s - no method for type %s",thisName(),GetString(s)); - return false; -} - void pyobj::m_set(int argc,const t_atom *argv) { PyThreadState *state = PyLockSys(); @@ -333,31 +333,52 @@ bool pyobj::callpy(PyObject *fun,PyObject *args) return false; } else { - flext::AtomListStatic<16> rargs; - if(GetPyArgs(rargs,ret)) { - // call to outlet _outside_ the Mutex lock! - // otherwise (if not detached) deadlock will occur - if(rargs.Count()) ToOutList(0,rargs); - } - else if(PyErr_Occurred()) + if(ret != Py_None && !OutObject(this,0,ret) && PyErr_Occurred()) PyErr_Print(); - Py_DECREF(ret); return true; } } -void pyobj::callwork(const t_symbol *s,int argc,const t_atom *argv) +bool pyobj::CbMethodResort(int n,const t_symbol *s,int argc,const t_atom *argv) { bool ret = false; + if(n == 0 && s != sym_bang) goto end; + + if(objects && n >= 1) { + // store args + PyObject *&obj = objects[n-1]; + Py_DECREF(obj); + obj = MakePyArg(s,argc,argv); // steal reference + + if(n > 1) { + ret = true; // just store, don't trigger + goto end; + } + } + PyThreadState *state = PyLock(); if(withfunction) { if(function) { - PyObject *pargs = MakePyArgs(s,argc,argv); Py_INCREF(function); - ret = gencall(function,pargs); + + PyObject *pargs; + + if(objects) { + int inlets = CntIn()-1; + pargs = PyTuple_New(inlets); + for(int i = 0; i < inlets; ++i) { + Py_INCREF(objects[i]); + PyTuple_SET_ITEM(pargs,i,objects[i]); + } + } + else + // construct tuple from args + pargs = MakePyArgs(s,argc,argv); + + ret = gencall(function,pargs); // references are stolen } else PyErr_SetString(PyExc_RuntimeError,"No function set"); @@ -380,6 +401,9 @@ void pyobj::callwork(const t_symbol *s,int argc,const t_atom *argv) PyUnlock(state); Respond(ret); + +end: + return ret || flext_base::CbMethodResort(n,s,argc,argv); } void pyobj::CbClick() { pybase::OpenEditor(); } diff --git a/externals/grill/py/source/pyargs.cpp b/externals/grill/py/source/pyargs.cpp index 5e328975..f08369a7 100644 --- a/externals/grill/py/source/pyargs.cpp +++ b/externals/grill/py/source/pyargs.cpp @@ -8,83 +8,124 @@ WARRANTIES, see the file, "license.txt," in this distribution. */ -#include "main.h" +#include "pybase.h" +#include "pyatom.h" + +static const t_symbol *symatom = flext::MakeSymbol(" py "); static PyObject *MakePyAtom(const t_atom &at) { if(flext::IsSymbol(at)) return pySymbol_FromSymbol(flext::GetSymbol(at)); +/* else if(flext::CanbeInt(at) || flext::CanbeFloat(at)) { - // if a number can be an integer... let at be an integer! + // if a number can be an integer... let it be an integer! int ival = flext::GetAInt(at); double fval = flext::GetAFloat(at); return (double)ival == fval?PyInt_FromLong(ival):PyFloat_FromDouble(fval); } -// else if(flext::IsPointer(at)) return NULL; // not handled -/* - // these following should never happen - else if(flext::IsFloat(at)) return PyFloat_FromDouble((double)flext::GetFloat(at)); - else if(flext::IsInt(at)) return PyInt_FromLong(flext::GetInt(at)); -*/ +*/ + else if(flext::IsFloat(at)) + return PyFloat_FromDouble(flext::GetFloat(at)); + else if(flext::IsInt(at)) + return PyInt_FromLong(flext::GetInt(at)); + return NULL; } -PyObject *pybase::MakePyArgs(const t_symbol *s,int argc,const t_atom *argv,int inlet,bool withself) +static PyObject *MakePyAtom(int argc,const t_atom *argv) { - PyObject *pArgs; + if(argc != sizeof(size_t)/2) return NULL; + + size_t atom = 0; + for(int i = sizeof(size_t)/2-1; i >= 0; --i) + if(!flext::CanbeInt(argv[i])) { + atom = 0; + break; + } + else + atom = (atom<<16)+flext::GetAInt(argv[i]); + + if(atom) { + PyObject *el = PyAtom::Retrieve(atom); + if(!el) el = Py_None; // object already gone.... + Py_INCREF(el); + return el; + } + else + return NULL; +} -/* - if(!s && args.Count() == 1) { - pArgs = MakePyAtom(args[0]); - if(!pArgs) - post("py/pyext: cannot convert argument(s)"); +PyObject *pybase::MakePyArgs(const t_symbol *s,int argc,const t_atom *argv,int inlet) +{ + PyObject *ret,*el; + + if(s == symatom && (el = MakePyAtom(argc,argv)) != NULL) { + ret = PyTuple_New(1); + PyTuple_SET_ITEM(ret,0,el); } - else -*/ - { + else { bool any = IsAnything(s); - pArgs = PyTuple_New(argc+(any?1:0)+(inlet >= 0?1:0)); + ret = PyTuple_New(argc+(any?1:0)+(inlet >= 0?1:0)); int pix = 0; if(inlet >= 0) - PyTuple_SetItem(pArgs, pix++, PyInt_FromLong(inlet)); - - int ix; - PyObject *tmp; -// if(!withself || argc < (any?1:2)) - tmp = pArgs,ix = pix; -// else -// tmp = PyTuple_New(argc+(any?1:0)),ix = 0; + PyTuple_SET_ITEM(ret,pix++,PyInt_FromLong(inlet)); if(any) - PyTuple_SET_ITEM(tmp, ix++, pySymbol_FromSymbol(s)); + PyTuple_SET_ITEM(ret,pix++,pySymbol_FromSymbol(s)); for(int i = 0; i < argc; ++i) { - PyObject *pValue = MakePyAtom(argv[i]); - if(!pValue) { + el = MakePyAtom(argv[i]); + if(!el) { post("py/pyext: cannot convert argument %i",any?i+1:i); - continue; - } - - /* pValue reference stolen here: */ - PyTuple_SET_ITEM(tmp, ix++, pValue); + + el = Py_None; + Py_INCREF(Py_None); + } + + PyTuple_SET_ITEM(ret,pix++,el); // reference stolen } + } + + return ret; +} - if(tmp != pArgs) { - PyTuple_SET_ITEM(pArgs, pix++, tmp); - #if PY_VERSION_HEX >= 0x02020000 - _PyTuple_Resize(&pArgs,pix); - #else - _PyTuple_Resize(&pArgs,pix,0); - #endif +PyObject *pybase::MakePyArg(const t_symbol *s,int argc,const t_atom *argv) +{ + PyObject *ret; + + if(s == symatom && (ret = MakePyAtom(argc,argv)) != NULL) { + // ok! + } + else if(argc == 1 && IsAtom(s)) + ret = MakePyAtom(*argv); + else { + bool any = s != sym_list; + ret = PyTuple_New(argc+(any?1:0)); + + int pix = 0; + if(any) + PyTuple_SET_ITEM(ret,pix++,pySymbol_FromSymbol(s)); + + for(int i = 0; i < argc; ++i) { + PyObject *el = MakePyAtom(argv[i]); + if(!el) { + post("py/pyext: cannot convert argument %i",any?i+1:i); + + el = Py_None; + Py_INCREF(Py_None); + } + + PyTuple_SET_ITEM(ret,pix++,el); // reference stolen } } - return pArgs; + return ret; } -bool pybase::GetPyArgs(AtomList &lst,PyObject *pValue,int offs,PyObject **self) +bool pybase::GetPyArgs(AtomList &lst,PyObject *pValue,int offs) { if(pValue == NULL) return false; @@ -124,11 +165,13 @@ bool pybase::GetPyArgs(AtomList &lst,PyObject *pValue,int offs,PyObject **self) else if(PyFloat_Check(arg)) SetFloat(at,(float)PyFloat_AsDouble(arg)); else if(pySymbol_Check(arg)) SetSymbol(at,pySymbol_AS_SYMBOL(arg)); else if(PyString_Check(arg)) SetString(at,PyString_AS_STRING(arg)); - else if(ix == 0 && self && PyInstance_Check(arg)) { +/* + else if(ix == 0 && self && PyInstance_Check(arg)) { // assumed to be self ... that should be checked _somehow_ !!! Py_INCREF(arg); *self = arg; } +*/ else { PyObject *tp = PyObject_Type(arg); PyObject *stp = tp?PyObject_Str(tp):NULL; @@ -146,3 +189,16 @@ bool pybase::GetPyArgs(AtomList &lst,PyObject *pValue,int offs,PyObject **self) return ok; } + + +bool pybase::GetPyAtom(AtomList &lst,PyObject *obj) +{ + size_t atom = PyAtom::Register(obj); + size_t szat = sizeof(atom)/2; + + lst(1+szat); + SetSymbol(lst[0],symatom); + for(size_t i = 0; i < szat; ++i,atom >>= 16) + flext::SetInt(lst[i+1],(int)(atom&((1<<16)-1))); + return true; +} diff --git a/externals/grill/py/source/pyatom.cpp b/externals/grill/py/source/pyatom.cpp new file mode 100644 index 00000000..07712f30 --- /dev/null +++ b/externals/grill/py/source/pyatom.cpp @@ -0,0 +1,61 @@ +/*
+
+py/pyext - python script object for PD and Max/MSP
+
+Copyright (c)2002-2005 Thomas Grill (gr@grrrr.org)
+For information on usage and redistribution, and for a DISCLAIMER OF ALL
+WARRANTIES, see the file, "license.txt," in this distribution.
+
+*/
+
+#include "pyatom.h"
+#include <map>
+
+#define INTV 0.01
+
+typedef std::map<size_t,PyObject *> ObjMap;
+
+static ObjMap objmap;
+static size_t collix = 0,curix = 0;
+static double last = 0;
+
+size_t PyAtom::Register(PyObject *obj)
+{
+ Collect();
+
+ Py_INCREF(obj);
+ objmap[++curix] = obj;
+
+#ifdef _DEBUG
+// post("REG %p (%i)\n",obj,objmap.size());
+#endif
+ return curix;
+}
+
+PyObject *PyAtom::Retrieve(size_t id)
+{
+ ObjMap::iterator it = objmap.find(id);
+ PyObject *ret = it == objmap.end()?NULL:it->second;
+ Collect();
+ return ret;
+}
+
+void PyAtom::Collect()
+{
+ for(;;) {
+ ObjMap::iterator it = objmap.begin();
+ if(it == objmap.end() || it->first > collix) break;
+
+ PyObject *obj = it->second;
+ Py_DECREF(obj);
+ objmap.erase(it);
+
+#ifdef _DEBUG
+// post("DEL %p\n",obj);
+#endif
+ }
+
+ // schedule next collect time
+ double tm = flext::GetTime();
+ if(tm > last+INTV) last = tm,collix = curix;
+}
diff --git a/externals/grill/py/source/pyatom.h b/externals/grill/py/source/pyatom.h new file mode 100644 index 00000000..e96514c6 --- /dev/null +++ b/externals/grill/py/source/pyatom.h @@ -0,0 +1,19 @@ +/*
+
+py/pyext - python script object for PD and Max/MSP
+
+Copyright (c)2002-2005 Thomas Grill (gr@grrrr.org)
+For information on usage and redistribution, and for a DISCLAIMER OF ALL
+WARRANTIES, see the file, "license.txt," in this distribution.
+
+*/
+
+#include "main.h"
+
+class PyAtom
+{
+public:
+ static size_t Register(PyObject *obj);
+ static PyObject *Retrieve(size_t id);
+ static void Collect();
+};
diff --git a/externals/grill/py/source/pybase.cpp b/externals/grill/py/source/pybase.cpp new file mode 100644 index 00000000..cc51a59e --- /dev/null +++ b/externals/grill/py/source/pybase.cpp @@ -0,0 +1,672 @@ +/*
+
+py/pyext - python external object for PD and MaxMSP
+
+Copyright (c)2002-2005 Thomas Grill (gr@grrrr.org)
+For information on usage and redistribution, and for a DISCLAIMER OF ALL
+WARRANTIES, see the file, "license.txt," in this distribution.
+
+*/
+
+#include "pybase.h"
+#include <map>
+
+static PyMethodDef StdOut_Methods[] =
+{
+ { "write", pybase::StdOut_Write, 1 },
+ { NULL, NULL, }
+};
+
+static PyObject *gcollect = NULL;
+
+#ifdef FLEXT_THREADS
+
+typedef std::map<flext::thrid_t,PyThreadState *> PyThrMap;
+
+static PyInterpreterState *pymain = NULL;
+static PyThrMap pythrmap;
+PyThreadState *pybase::pythrsys = NULL;
+
+int pybase::lockcount = 0;
+
+PyThreadState *pybase::FindThreadState()
+{
+ flext::thrid_t id = flext::GetThreadId();
+ PyThrMap::iterator it = pythrmap.find(id);
+ if(it == pythrmap.end()) {
+ // Make new thread state
+ PyThreadState *st = PyThreadState_New(pymain);
+ pythrmap[id] = st;
+ return st;
+ }
+ else
+ return it->second;
+}
+
+void pybase::FreeThreadState()
+{
+ flext::thrid_t id = flext::GetThreadId();
+ PyThrMap::iterator it = pythrmap.find(id);
+ if(it != pythrmap.end()) {
+ // clear out any cruft from thread state object
+ PyThreadState_Clear(it->second);
+ // delete my thread state object
+ PyThreadState_Delete(it->second);
+ // delete from map
+ pythrmap.erase(it);
+ }
+}
+#endif
+
+
+PyObject *pybase::module_obj = NULL;
+PyObject *pybase::module_dict = NULL;
+
+
+// -----------------------------------------------------------------------------------------------------------
+
+
+void initsymbol();
+void initsamplebuffer();
+
+void pybase::lib_setup()
+{
+ post("");
+ post("------------------------------------------------");
+ post("py/pyext %s - python script objects",PY__VERSION);
+ post("(C)2002-2005 Thomas Grill - http://grrrr.org/ext");
+ post("");
+ post("using Python %s",Py_GetVersion());
+
+#ifdef FLEXT_DEBUG
+ post("");
+ post("DEBUG version compiled on %s %s",__DATE__,__TIME__);
+#endif
+
+ // -------------------------------------------------------------
+
+ Py_Initialize();
+
+#ifdef FLEXT_DEBUG
+// Py_VerboseFlag = 1;
+#endif
+
+#ifdef FLEXT_THREADS
+ // enable thread support and acquire the global thread lock
+ PyEval_InitThreads();
+
+ // get thread state
+ pythrsys = PyThreadState_Get();
+ // get main interpreter state
+ pymain = pythrsys->interp;
+
+ // add thread state of main thread to map
+ pythrmap[GetThreadId()] = pythrsys;
+#endif
+
+ // sys.argv must be set to empty tuple
+ char *nothing = "";
+ PySys_SetArgv(0,¬hing);
+
+ // register/initialize pyext module only once!
+ module_obj = Py_InitModule(PYEXT_MODULE, func_tbl);
+ module_dict = PyModule_GetDict(module_obj); // borrowed reference
+
+ PyModule_AddStringConstant(module_obj,"__doc__",(char *)py_doc);
+
+ // redirect stdout
+ PyObject* py_out;
+ py_out = Py_InitModule("stdout", StdOut_Methods);
+ PySys_SetObject("stdout", py_out);
+ py_out = Py_InitModule("stderr", StdOut_Methods);
+ PySys_SetObject("stderr", py_out);
+
+ // get garbage collector function
+ PyObject *gcobj = PyImport_ImportModule("gc");
+ if(gcobj) {
+ gcollect = PyObject_GetAttrString(gcobj,"collect");
+ Py_DECREF(gcobj);
+ }
+
+ // add symbol type
+ initsymbol();
+ PyModule_AddObject(module_obj,"Symbol",(PyObject *)&pySymbol_Type);
+
+ // pre-defined symbols
+ PyModule_AddObject(module_obj,"_s_",(PyObject *)pySymbol__);
+ PyModule_AddObject(module_obj,"_s_bang",(PyObject *)pySymbol_bang);
+ PyModule_AddObject(module_obj,"_s_list",(PyObject *)pySymbol_list);
+ PyModule_AddObject(module_obj,"_s_symbol",(PyObject *)pySymbol_symbol);
+ PyModule_AddObject(module_obj,"_s_float",(PyObject *)pySymbol_float);
+ PyModule_AddObject(module_obj,"_s_int",(PyObject *)pySymbol_int);
+
+ // add samplebuffer type
+ initsamplebuffer();
+ PyModule_AddObject(module_obj,"Buffer",(PyObject *)&pySamplebuffer_Type);
+
+ // -------------------------------------------------------------
+
+ FLEXT_SETUP(pyobj);
+ FLEXT_SETUP(pyext);
+ FLEXT_DSP_SETUP(pydsp);
+
+#ifdef FLEXT_THREADS
+ // release global lock
+ PyEval_ReleaseLock();
+#endif
+
+ post("------------------------------------------------");
+ post("");
+}
+
+FLEXT_LIB_SETUP(py,pybase::lib_setup)
+
+
+// -----------------------------------------------------------------------------------------------------------
+
+
+pybase::pybase()
+ : module(NULL)
+#ifdef FLEXT_THREADS
+ , shouldexit(false),thrcount(0),stoptick(0)
+#endif
+ , detach(0)
+ , xlate(true)
+{
+ PyThreadState *state = PyLockSys();
+ Py_INCREF(module_obj);
+ PyUnlock(state);
+}
+
+pybase::~pybase()
+{
+ PyThreadState *state = PyLockSys();
+ Py_XDECREF(module_obj);
+ PyUnlock(state);
+}
+
+void pybase::Exit()
+{
+#ifdef FLEXT_THREADS
+ shouldexit = true;
+ qucond.Signal();
+ if(thrcount) {
+ // Wait for a certain time
+ for(int i = 0; i < (PY_STOP_WAIT/PY_STOP_TICK) && thrcount; ++i)
+ Sleep(PY_STOP_TICK*0.001f);
+ if(thrcount) {
+ // Wait forever
+ post("py/pyext - Waiting for thread termination!");
+ while(thrcount) Sleep(PY_STOP_TICK*0.001f);
+ post("py/pyext - Okay, all threads have terminated");
+ }
+ }
+#endif
+}
+
+void pybase::GetDir(PyObject *obj,AtomList &lst)
+{
+ if(obj) {
+ PyThreadState *state = PyLock();
+
+ PyObject *pvar = PyObject_Dir(obj);
+ if(!pvar)
+ PyErr_Print(); // no method found
+ else {
+ if(!GetPyArgs(lst,pvar))
+ post("py/pyext - Argument list could not be created");
+ Py_DECREF(pvar);
+ }
+
+ PyUnlock(state);
+ }
+}
+
+void pybase::m__dir(PyObject *obj)
+{
+ AtomList lst;
+ GetDir(obj,lst);
+ // dump dir to attribute outlet
+ DumpOut(NULL,lst.Count(),lst.Atoms());
+}
+
+void pybase::m__doc(PyObject *obj)
+{
+ if(obj) {
+ PyThreadState *state = PyLock();
+
+ PyObject *docf = PyDict_GetItemString(obj,"__doc__"); // borrowed!!!
+ if(docf && PyString_Check(docf)) {
+ post("");
+ const char *s = PyString_AS_STRING(docf);
+
+ // FIX: Python doc strings can easily be larger than 1k characters
+ // -> split into separate lines
+ for(;;) {
+ char buf[1024];
+ char *nl = strchr((char *)s,'\n'); // the cast is for Borland C++
+ if(!nl) {
+ // no more newline found
+ post(s);
+ break;
+ }
+ else {
+ // copy string before newline to temp buffer and post
+ unsigned int l = nl-s;
+ if(l >= sizeof(buf)) l = sizeof buf-1;
+ strncpy(buf,s,l); // copy all but newline
+ buf[l] = 0;
+ post(buf);
+ s = nl+1; // set after newline
+ }
+ }
+ }
+
+ PyUnlock(state);
+ }
+}
+
+void pybase::OpenEditor()
+{
+ // this should once open the editor....
+}
+
+void pybase::SetArgs()
+{
+ // script arguments
+ int argc = args.Count();
+ const t_atom *argv = args.Atoms();
+ char **sargv = new char *[argc+1];
+ for(int i = 0; i <= argc; ++i) {
+ sargv[i] = new char[256];
+ if(!i)
+ strcpy(sargv[i],"py/pyext");
+ else
+ GetAString(argv[i-1],sargv[i],255);
+ }
+
+ // the arguments to the module are only recognized once! (at first use in a patcher)
+ PySys_SetArgv(argc+1,sargv);
+
+ for(int j = 0; j <= argc; ++j) delete[] sargv[j];
+ delete[] sargv;
+}
+
+bool pybase::ImportModule(const char *name)
+{
+ if(!name) return false;
+ if(modname == name) return true;
+ modname = name;
+ return ReloadModule();
+}
+
+void pybase::UnimportModule()
+{
+ if(!module) return;
+
+ FLEXT_ASSERT(dict && module_obj && module_dict);
+
+ Py_DECREF(module);
+
+ // reference count to module is not 0 here, altough probably the last instance was unloaded
+ // Python retains one reference to the module all the time
+ // we don't care
+
+ module = NULL;
+ dict = NULL;
+}
+
+bool pybase::ReloadModule()
+{
+ bool ok = false;
+
+ SetArgs();
+ PyObject *newmod = module
+ ?PyImport_ReloadModule(module)
+ :PyImport_ImportModule((char *)modname.c_str());
+
+ if(!newmod) {
+ // unload faulty module
+ if(module) UnimportModule();
+ }
+ else {
+ Py_XDECREF(module);
+ module = newmod;
+ dict = PyModule_GetDict(module); // borrowed
+ ok = true;
+ }
+ return ok;
+}
+
+void pybase::GetModulePath(const char *mod,char *dir,int len)
+{
+#if FLEXT_SYS == FLEXT_SYS_PD
+ // uarghh... pd doesn't show its path for extra modules
+
+ char *name;
+ int fd = open_via_path("",mod,".py",dir,&name,len,0);
+ if(fd > 0) close(fd);
+ else name = NULL;
+
+ // if dir is current working directory... name points to dir
+ if(dir == name) strcpy(dir,".");
+#elif FLEXT_SYS == FLEXT_SYS_MAX
+ // how do i get the path in Max/MSP?
+ short path;
+ long type;
+ char smod[1024];
+ strcat(strcpy(smod,mod),".py");
+ if(!locatefile_extended(smod,&path,&type,&type,-1)) {
+#if FLEXT_OS == FLEXT_OS_WIN
+ path_topathname(path,NULL,dir);
+#else
+ // convert pathname to unix style
+ path_topathname(path,NULL,smod);
+ char *colon = strchr(smod,':');
+ if(colon) {
+ *colon = 0;
+ strcpy(dir,"/Volumes/");
+ strcat(dir,smod);
+ strcat(dir,colon+1);
+ }
+ else
+ strcpy(dir,smod);
+#endif
+ }
+ else
+ // not found
+ *dir = 0;
+#else
+ *dir = 0;
+#endif
+}
+
+void pybase::AddToPath(const char *dir)
+{
+ if(dir && *dir) {
+ PyObject *pobj = PySys_GetObject("path");
+ if(pobj && PyList_Check(pobj)) {
+ PyObject *ps = PyString_FromString(dir);
+ if(!PySequence_Contains(pobj,ps))
+ PyList_Append(pobj,ps); // makes new reference
+ Py_DECREF(ps);
+ }
+ PySys_SetObject("path",pobj); // steals reference to pobj
+ }
+}
+
+void pybase::AddCurrentPath(t_canvas *cnv)
+{
+#if FLEXT_SYS == FLEXT_SYS_PD
+ // add dir of current patch to path
+ AddToPath(GetString(canvas_getdir(cnv)));
+ // add current dir to path
+ AddToPath(GetString(canvas_getcurrentdir()));
+#elif FLEXT_SYS == FLEXT_SYS_MAX
+ char dir[1024];
+ short path = patcher_myvol(cnv);
+ path_topathname(path,NULL,dir);
+ AddToPath(dir);
+#else
+ #pragma message("Adding current dir to path is not implemented")
+#endif
+}
+
+bool pybase::OutObject(flext_base *ext,int o,PyObject *obj)
+{
+ flext::AtomListStatic<16> lst;
+ if(xlate?GetPyArgs(lst,obj):GetPyAtom(lst,obj)) {
+ // call to outlet _outside_ the Mutex lock!
+ // otherwise (if not detached) deadlock will occur
+ if(lst.Count() && IsSymbol(lst[0]))
+ ext->ToOutAnything(o,GetSymbol(lst[0]),lst.Count()-1,lst.Atoms()+1);
+ else if(lst.Count() > 1)
+ ext->ToOutList(o,lst);
+ else
+ ext->ToOutAtom(o,lst[0]);
+ return true;
+ }
+ else
+ return false;
+}
+
+static const t_symbol *sym_response = flext::MakeSymbol("response");
+
+void pybase::Respond(bool b)
+{
+ if(respond) {
+ t_atom a;
+ SetBool(a,b);
+ DumpOut(sym_response,1,&a);
+ }
+}
+
+void pybase::Reload()
+{
+ PyThreadState *state = PyLockSys();
+
+ PyObject *reg = GetRegistry(REGNAME);
+
+ if(reg) {
+ PyObject *key;
+ int pos = 0;
+ while(PyDict_Next(reg,&pos,&key,NULL)) {
+ pybase *th = (pybase *)PyLong_AsLong(key);
+ FLEXT_ASSERT(th);
+ th->Unload();
+ }
+
+ UnloadModule();
+ }
+
+ bool ok = ReloadModule();
+
+ if(ok) {
+ LoadModule();
+
+ if(reg) {
+ SetRegistry(REGNAME,reg);
+
+ PyObject *key;
+ int pos = 0;
+ while(PyDict_Next(reg,&pos,&key,NULL)) {
+ pybase *th = (pybase *)PyLong_AsLong(key);
+ FLEXT_ASSERT(th);
+ th->Load();
+ }
+ }
+ else
+ Load();
+ }
+
+ Report();
+ PyUnlock(state);
+}
+
+static PyObject *output = NULL;
+
+// post to the console
+PyObject* pybase::StdOut_Write(PyObject* self, PyObject* args)
+{
+ // should always be a tuple
+ FLEXT_ASSERT(PyTuple_Check(args));
+
+ const int sz = PyTuple_GET_SIZE(args);
+
+ for(int i = 0; i < sz; ++i) {
+ PyObject *val = PyTuple_GET_ITEM(args,i); // borrowed reference
+ PyObject *str = PyObject_Str(val); // new reference
+ char *cstr = PyString_AS_STRING(str);
+ char *lf = strchr(cstr,'\n');
+
+ // line feed in string
+ if(!lf) {
+ // no -> just append
+ if(output)
+ PyString_ConcatAndDel(&output,str); // str is decrefd
+ else
+ output = str; // take str reference
+ }
+ else {
+ // yes -> append up to line feed, reset output buffer to string remainder
+ PyObject *part = PyString_FromStringAndSize(cstr,lf-cstr); // new reference
+ if(output)
+ PyString_ConcatAndDel(&output,part); // str is decrefd
+ else
+ output = part; // take str reference
+
+ // output concatenated string
+ post(PyString_AS_STRING(output));
+
+ Py_DECREF(output);
+ output = PyString_FromString(lf+1); // new reference
+ }
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+class work_data
+{
+public:
+ work_data(PyObject *f,PyObject *a): fun(f),args(a) {}
+ ~work_data() { Py_DECREF(fun); Py_DECREF(args); }
+
+ PyObject *fun,*args;
+};
+
+bool pybase::gencall(PyObject *pmeth,PyObject *pargs)
+{
+ bool ret = false;
+
+ // Now call method
+ switch(detach) {
+ case 0:
+ ret = callpy(pmeth,pargs);
+ Py_DECREF(pargs);
+ Py_DECREF(pmeth);
+ break;
+#ifdef FLEXT_THREADS
+ case 1:
+ // put call into queue
+ ret = qucall(pmeth,pargs);
+ break;
+ case 2:
+ // each call a new thread
+ if(!shouldexit) {
+ ret = thrcall(new work_data(pmeth,pargs));
+ if(!ret) post("py/pyext - Failed to launch thread!");
+ }
+ break;
+#endif
+ default:
+ post("py/pyext - Unknown detach mode");
+ }
+ return ret;
+}
+
+void pybase::work_wrapper(void *data)
+{
+ FLEXT_ASSERT(data);
+
+#ifdef FLEXT_THREADS
+ ++thrcount;
+#endif
+
+ PyThreadState *state = PyLock();
+
+ // call worker
+ work_data *w = (work_data *)data;
+ callpy(w->fun,w->args);
+ delete w;
+
+ PyUnlock(state);
+
+#ifdef FLEXT_THREADS
+ --thrcount;
+#endif
+}
+
+#ifdef FLEXT_THREADS
+bool pybase::qucall(PyObject *fun,PyObject *args)
+{
+ FifoEl *el = qufifo.New();
+ el->Set(fun,args);
+ qufifo.Put(el);
+ qucond.Signal();
+ return true;
+}
+
+void pybase::threadworker()
+{
+ ++thrcount;
+
+ FifoEl *el;
+ PyThreadState *my = FindThreadState(),*state;
+
+ for(;;) {
+ while(el = qufifo.Get()) {
+ ++thrcount;
+ state = PyLock(my);
+ callpy(el->fun,el->args);
+ Py_XDECREF(el->fun);
+ Py_XDECREF(el->args);
+ PyUnlock(state);
+ qufifo.Free(el);
+ --thrcount;
+ }
+ if(shouldexit)
+ break;
+ else
+ qucond.Wait();
+ }
+
+ state = PyLock(my);
+ // unref remaining Python objects
+ while(el = qufifo.Get()) {
+ Py_XDECREF(el->fun);
+ Py_XDECREF(el->args);
+ qufifo.Free(el);
+ }
+ PyUnlock(state);
+
+ --thrcount;
+}
+#endif
+
+#if FLEXT_SYS == FLEXT_SYS_MAX
+short pybase::patcher_myvol(t_patcher *x)
+{
+ t_box *w;
+ if (x->p_vol)
+ return x->p_vol;
+ else if (w = (t_box *)x->p_vnewobj)
+ return patcher_myvol(w->b_patcher);
+ else
+ return 0;
+}
+#endif
+
+bool pybase::collect()
+{
+ if(gcollect) {
+ PyObject *ret = PyObject_CallObject(gcollect,NULL);
+ if(ret) {
+#ifdef FLEXT_DEBUG
+ int refs = PyInt_AsLong(ret);
+ if(refs) post("py/pyext - Garbage collector reports %i unreachable objects",refs);
+#endif
+ Py_DECREF(ret);
+ return false;
+ }
+ }
+ return true;
+}
+
+/*
+PY_EXPORT PyThreadState *py_Lock(PyThreadState *st = NULL) { return pybase::PyLock(st?st:pybase::FindThreadState()); }
+PY_EXPORT PyThreadState *py_LockSys() { return pybase::PyLockSys(); }
+PY_EXPORT void py_Unlock(PyThreadState *st) { pybase::PyUnlock(st); }
+*/
diff --git a/externals/grill/py/source/pybase.h b/externals/grill/py/source/pybase.h new file mode 100644 index 00000000..ea5f6b49 --- /dev/null +++ b/externals/grill/py/source/pybase.h @@ -0,0 +1,206 @@ +/*
+
+py/pyext - python script object for PD and MaxMSP
+
+Copyright (c)2002-2005 Thomas Grill (gr@grrrr.org)
+For information on usage and redistribution, and for a DISCLAIMER OF ALL
+WARRANTIES, see the file, "license.txt," in this distribution.
+
+*/
+
+#ifndef __PYBASE_H
+#define __PYBASE_H
+
+#include "main.h"
+#include "pysymbol.h"
+#include "pybuffer.h"
+
+class pybase
+ : public flext
+{
+public:
+ pybase();
+ virtual ~pybase();
+
+ void Exit();
+
+ static PyObject *MakePyArgs(const t_symbol *s,int argc,const t_atom *argv,int inlet = -1);
+ static PyObject *MakePyArg(const t_symbol *s,int argc,const t_atom *argv);
+ static bool GetPyArgs(AtomList &lst,PyObject *pValue,int offs = 0);
+ static bool GetPyAtom(AtomList &lst,PyObject *pValue);
+
+ static void lib_setup();
+
+protected:
+
+ virtual void DumpOut(const t_symbol *sym,int argc,const t_atom *argv) = 0;
+
+ void m__dir(PyObject *obj);
+ void m__doc(PyObject *obj);
+
+ void m_dir() { m__dir(module); }
+ void mg_dir(AtomList &lst) { m__dir(module); }
+ void m_doc() { m__doc(dict); }
+
+ std::string modname; // module name
+ PyObject *module,*dict; // object module and associated dictionary
+
+ static const char *py_doc;
+
+ void GetDir(PyObject *obj,AtomList &lst);
+
+ AtomList args;
+
+ void AddCurrentPath(t_canvas *cnv);
+ void GetModulePath(const char *mod,char *dir,int len);
+ void AddToPath(const char *dir);
+ void SetArgs();
+
+ bool OutObject(flext_base *ext,int o,PyObject *obj);
+
+ // reload module and all connected objects
+ void Reload();
+
+ bool ImportModule(const char *name);
+ void UnimportModule();
+ bool ReloadModule();
+
+ // Get module registry
+ PyObject *GetRegistry(const char *regname);
+ // Set module registry
+ void SetRegistry(const char *regname,PyObject *reg);
+
+ // Register object
+ void Register(PyObject *reg);
+ // Unregister object
+ void Unregister(PyObject *reg);
+
+ virtual void LoadModule() = 0;
+ virtual void UnloadModule() = 0;
+
+ virtual void Load() = 0;
+ virtual void Unload() = 0;
+
+ void OpenEditor();
+ void Respond(bool b);
+
+ void Report() { while(PyErr_Occurred()) PyErr_Print(); }
+
+ static bool IsAnything(const t_symbol *s) { return s && s != sym_float && s != sym_int && s != sym_symbol && s != sym_list && s != sym_pointer; }
+ static bool IsAtom(const t_symbol *s) { return s == sym_float || s == sym_int || s == sym_symbol || s == sym_pointer; }
+
+ enum retval { nothing,atom,sequ };
+
+ // --- module stuff -----
+
+ static PyObject *module_obj,*module_dict;
+ static PyMethodDef func_tbl[];
+
+ static PyObject *py__doc__(PyObject *,PyObject *args);
+ static PyObject *py_send(PyObject *,PyObject *args);
+#ifdef FLEXT_THREADS
+ static PyObject *py_priority(PyObject *,PyObject *args);
+#endif
+
+ static PyObject *py_arraysupport(PyObject *,PyObject *args);
+ static PyObject *py_samplerate(PyObject *,PyObject *args);
+ static PyObject *py_blocksize(PyObject *,PyObject *args);
+
+#if FLEXT_SYS == FLEXT_SYS_PD
+ static PyObject *py_getvalue(PyObject *,PyObject *args);
+ static PyObject *py_setvalue(PyObject *,PyObject *args);
+#endif
+
+#ifdef PY_NUMARRAY
+ static void setupNumarray();
+ static PyObject *py_import(PyObject *,PyObject *args);
+ static PyObject *py_export(PyObject *,PyObject *args);
+#endif
+
+ // ----thread stuff ------------
+
+ virtual void m_stop(int argc,const t_atom *argv);
+
+ bool respond;
+#ifdef FLEXT_THREADS
+ bool shouldexit;
+ int thrcount;
+ int stoptick;
+ Timer stoptmr;
+
+ void tick(void *);
+#endif
+
+ int detach;
+ bool xlate;
+
+ bool gencall(PyObject *fun,PyObject *args);
+ virtual bool thrcall(void *data) = 0;
+ virtual bool callpy(PyObject *fun,PyObject *args) = 0;
+
+#if FLEXT_SYS == FLEXT_SYS_MAX
+ static short patcher_myvol(t_patcher *x);
+#endif
+
+ static bool collect();
+
+protected:
+
+ void work_wrapper(void *data);
+
+#ifdef FLEXT_THREADS
+ bool qucall(PyObject *fun,PyObject *args);
+ void threadworker();
+ PyFifo qufifo;
+ ThrCond qucond;
+ static PyThreadState *pythrsys;
+
+ static PyThreadState *FindThreadState();
+ static void FreeThreadState();
+#else
+ static PyThreadState *FindThreadState() { return NULL; }
+#endif
+
+public:
+
+#ifdef FLEXT_THREADS
+ ThrMutex mutex;
+ inline void Lock() { mutex.Unlock(); }
+ inline void Unlock() { mutex.Unlock(); }
+
+ // this is especially needed when one py/pyext object calls another one
+ // we don't want the message to be queued, but otoh we have to avoid deadlock
+ // (recursive calls can only happen in the system thread)
+ static int lockcount;
+
+ static PyThreadState *PyLock(PyThreadState *st = FindThreadState())
+ {
+ if(!IsSystemThread() || !lockcount++) PyEval_AcquireLock();
+ return PyThreadState_Swap(st);
+ }
+
+ static PyThreadState *PyLockSys()
+ {
+ if(!lockcount++) PyEval_AcquireLock();
+ return PyThreadState_Swap(pythrsys);
+ }
+
+ static void PyUnlock(PyThreadState *st)
+ {
+ PyThreadState *old = PyThreadState_Swap(st);
+ if(old != pythrsys || !--lockcount) PyEval_ReleaseLock();
+ }
+
+#else
+ inline void Lock() {}
+ inline void Unlock() {}
+
+ static PyThreadState *PyLock(PyThreadState * = NULL) { return NULL; }
+ static PyThreadState *PyLockSys() { return NULL; }
+ static void PyUnlock(PyThreadState *st) {}
+#endif
+
+ static PyObject* StdOut_Write(PyObject* Self, PyObject* Args);
+};
+
+#endif
diff --git a/externals/grill/py/source/pybuffer.cpp b/externals/grill/py/source/pybuffer.cpp index 0893b983..13d428c4 100644 --- a/externals/grill/py/source/pybuffer.cpp +++ b/externals/grill/py/source/pybuffer.cpp @@ -8,7 +8,7 @@ WARRANTIES, see the file, "license.txt," in this distribution. */
-#include "main.h"
+#include "pybase.h"
#undef PY_ARRAYS
diff --git a/externals/grill/py/source/pyext.cpp b/externals/grill/py/source/pyext.cpp index e500e264..88b5de0c 100644 --- a/externals/grill/py/source/pyext.cpp +++ b/externals/grill/py/source/pyext.cpp @@ -41,6 +41,7 @@ void pyext::Setup(t_classid c) FLEXT_CADDMETHOD_(c,0,"get",m_get); FLEXT_CADDMETHOD_(c,0,"set",m_set); + FLEXT_CADDATTR_VAR1(c,"xlate",xlate); FLEXT_CADDATTR_VAR1(c,"respond",respond); // ---------------------------------------------------- @@ -123,71 +124,72 @@ pyext::pyext(int argc,const t_atom *argv,bool sig): FLEXT_CALLMETHOD(threadworker); #endif - int apre = 0; - if(argc >= apre+2 && CanbeInt(argv[apre]) && CanbeInt(argv[apre+1])) { - inlets = GetAInt(argv[apre]); - outlets = GetAInt(argv[apre+1]); - apre += 2; + if(argc >= 2 && CanbeInt(argv[0]) && CanbeInt(argv[1])) { + inlets = GetAInt(argv[0]); + outlets = GetAInt(argv[1]); + argv += 2,argc -= 2; } - if(sig && argc >= apre+2 && CanbeInt(argv[apre]) && CanbeInt(argv[apre+1])) { - siginlets = GetAInt(argv[apre]); - sigoutlets = GetAInt(argv[apre+1]); - apre += 2; + if(sig && argc >= 2 && CanbeInt(argv[0]) && CanbeInt(argv[1])) { + siginlets = GetAInt(argv[0]); + sigoutlets = GetAInt(argv[1]); + argv += 2,argc -= 2; } const t_symbol *clname = NULL; + // check if the object name is pyext. , pyx. or similar + bool dotted = strrchr(thisName(),'.') != NULL; + PyThreadState *state = PyLockSys(); // init script module - if(argc > apre) { - char dir[1024]; - -#if FLEXT_SYS == FLEXT_SYS_PD - // add dir of current patch to path - AddToPath(GetString(canvas_getdir(thisCanvas()))); - // add current dir to path - AddToPath(GetString(canvas_getcurrentdir())); -#elif FLEXT_SYS == FLEXT_SYS_MAX - short path = patcher_myvol(thisCanvas()); - path_topathname(path,NULL,dir); - AddToPath(dir); -#else - #pragma message("Adding current dir to path is not implemented") -#endif - const t_symbol *scr = GetASymbol(argv[apre]); + if(argc) { + AddCurrentPath(thisCanvas()); + + const t_symbol *scr = GetASymbol(*argv); + argv++,argc--; + if(scr) { - GetModulePath(GetString(scr),dir,sizeof(dir)); - // add to path - AddToPath(dir); + char modnm[64]; + strcpy(modnm,GetString(scr)); + + if(!dotted) { + char *pt = strrchr(modnm,'.'); // search for last dot + if(pt && *pt) { + clname = MakeSymbol(pt+1); + *pt = 0; + } + } -// SetArgs(0,NULL); + char dir[1024]; + GetModulePath(modnm,dir,sizeof(dir)); + AddToPath(dir); - ImportModule(GetString(scr)); + ImportModule(modnm); } else - post("%s - script name argument is invalid",thisName()); - - ++apre; + PyErr_SetString(PyExc_ValueError,"Invalid module name"); // check for alias creation names - if(strrchr(thisName(),'.')) clname = scr; + if(dotted) clname = scr; } Register(GetRegistry(REGNAME)); - if(argc > apre || clname) { - if(!clname) clname = GetASymbol(argv[apre++]); + if(argc || clname) { + if(!clname) { + clname = GetASymbol(*argv); + argv++,argc--; + } - // class name - if(!clname) - post("%s - class name argument is invalid",thisName()); - else + if(clname) methname = clname; + else + PyErr_SetString(PyExc_ValueError,"Invalid class name"); } - if(argc > apre) initargs(argc-apre,argv+apre); + if(argc) initargs(argc,argv); Report(); @@ -240,7 +242,7 @@ bool pyext::DoInit() { // call init now, after _this has been set, which is // important for eventual callbacks from __init__ to c - PyObject *pargs = MakePyArgs(NULL,initargs.Count(),initargs.Atoms(),-1,true); + PyObject *pargs = MakePyArgs(NULL,initargs.Count(),initargs.Atoms()); if(pargs) { bool ok = true; @@ -443,7 +445,7 @@ void pyext::m_set(int argc,const t_atom *argv) else { char *ch = const_cast<char *>(GetString(argv[0])); if(PyObject_HasAttrString(pyobj,ch)) { - PyObject *pval = MakePyArgs(NULL,argc-1,argv+1,-1,false); + PyObject *pval = MakePyArgs(NULL,argc-1,argv+1); if(pval) { if(PySequence_Size(pval) == 1) { // reduce lists of one element to element itself @@ -467,10 +469,7 @@ void pyext::m_set(int argc,const t_atom *argv) bool pyext::CbMethodResort(int n,const t_symbol *s,int argc,const t_atom *argv) { - if(pyobj && n >= 1) - return work(n,s,argc,argv); - else - return flext_dsp::CbMethodResort(n,s,argc,argv); + return (pyobj && n >= 1 && work(n,s,argc,argv)) || flext_dsp::CbMethodResort(n,s,argc,argv); } @@ -527,7 +526,7 @@ bool pyext::call(const char *meth,int inlet,const t_symbol *s,int argc,const t_a PyErr_Clear(); // no method found } else { - PyObject *pargs = MakePyArgs(s,argc,argv,inlet?inlet:-1,true); + PyObject *pargs = MakePyArgs(s,argc,argv,inlet?inlet:-1); //,true); if(!pargs) { PyErr_Print(); Py_DECREF(pmeth); @@ -547,29 +546,29 @@ bool pyext::work(int n,const t_symbol *s,int argc,const t_atom *argv) // should be enough... char str[256]; - bool isfloat = s == sym_float && argc == 1; - // offset inlet index by signal inlets // \note first one is shared with messages! if(siginlets) n += siginlets-1; - // if float equals an integer, try int_* method - if(isfloat && GetAFloat(argv[0]) == GetAInt(argv[0])) { - sprintf(str,"int_%i",n); - ret = call(str,0,NULL,1,argv); - } - // try tag/inlet if(!ret) { sprintf(str,"%s_%i",GetString(s),n); ret = call(str,0,NULL,argc,argv); } - // try truncated int - if(!ret && isfloat) { - t_atom at; SetInt(at,GetAInt(argv[0])); - sprintf(str,"int_%i",n); - ret = call(str,0,NULL,1,&at); + if(!ret && argc == 1) { + if(s == sym_float) { + // try truncated float + t_atom at; SetInt(at,GetAInt(argv[0])); + sprintf(str,"int_%i",n); + ret = call(str,0,NULL,1,&at); + } + else if(s == sym_int) { + // try floating int + t_atom at; SetFloat(at,GetAFloat(argv[0])); + sprintf(str,"float_%i",n); + ret = call(str,0,NULL,1,&at); + } } // try anything/inlet @@ -578,21 +577,23 @@ bool pyext::work(int n,const t_symbol *s,int argc,const t_atom *argv) ret = call(str,0,s,argc,argv); } - // try int at any inlet - if(!ret && isfloat && GetAFloat(argv[0]) == GetAInt(argv[0])) { - ret = call("int_",0,NULL,1,argv); - } - // try tag at any inlet if(!ret) { sprintf(str,"%s_",GetString(s)); ret = call(str,n,NULL,argc,argv); } - // try truncated int at any inlet - if(!ret && isfloat) { - t_atom at; SetInt(at,GetAInt(argv[0])); - ret = call("int_",0,NULL,1,&at); + if(!ret && argc == 1) { + if(s == sym_float) { + // try truncated float at any inlet + t_atom at; SetInt(at,GetAInt(argv[0])); + ret = call("int_",0,NULL,1,&at); + } + else if(s == sym_int) { + // try floating int at any inlet + t_atom at; SetFloat(at,GetAFloat(argv[0])); + ret = call("float_",0,NULL,1,&at); + } } if(!ret) { diff --git a/externals/grill/py/source/pyext.h b/externals/grill/py/source/pyext.h index cab0c6a2..7fe0cc68 100644 --- a/externals/grill/py/source/pyext.h +++ b/externals/grill/py/source/pyext.h @@ -11,7 +11,7 @@ WARRANTIES, see the file, "license.txt," in this distribution. #ifndef __PYEXT_H #define __PYEXT_H -#include "main.h" +#include "pybase.h" class pyext : public pybase @@ -76,7 +76,7 @@ protected: int inlets,outlets; int siginlets,sigoutlets; - flext::AtomListStatic<16> initargs; + flext::AtomList initargs; virtual void LoadModule(); virtual void UnloadModule(); @@ -138,7 +138,9 @@ private: // callbacks FLEXT_ATTRVAR_I(detach) + FLEXT_ATTRVAR_B(xlate) FLEXT_ATTRVAR_B(respond) + FLEXT_CALLBACK_V(m_stop) FLEXT_CALLBACK(m_dir) FLEXT_CALLGET_V(mg_dir) diff --git a/externals/grill/py/source/pyprefix.h b/externals/grill/py/source/pyprefix.h index 3f149b61..3841cdce 100644 --- a/externals/grill/py/source/pyprefix.h +++ b/externals/grill/py/source/pyprefix.h @@ -24,4 +24,16 @@ WARRANTIES, see the file, "license.txt," in this distribution. #error You need at least flext version 0.5.0
#endif
+#if FLEXT_OS == FLEXT_LINUX || FLEXT_OS == FLEXT_IRIX
+#include <unistd.h>
+#endif
+
+#if FLEXT_SYS == FLEXT_SYS_PD && (!defined (PD_MINOR_VERSION) || PD_MINOR_VERSION < 37)
+#error PD version >= 0.37 required, please upgrade!
+#endif
+
+#include <flcontainers.h>
+#include <string>
+
+
#endif
diff --git a/externals/grill/py/source/register.cpp b/externals/grill/py/source/register.cpp index d26d5504..b34fa209 100644 --- a/externals/grill/py/source/register.cpp +++ b/externals/grill/py/source/register.cpp @@ -8,7 +8,7 @@ WARRANTIES, see the file, "license.txt," in this distribution. */ -#include "main.h" +#include "pybase.h" #if 1 |