aboutsummaryrefslogtreecommitdiff
path: root/externals/grill/py/source
diff options
context:
space:
mode:
authorThomas Grill <xovo@users.sourceforge.net>2005-07-08 14:30:31 +0000
committerThomas Grill <xovo@users.sourceforge.net>2005-07-08 14:30:31 +0000
commit897b80c5585f7c9031ff1aafb504c21a9d3b1606 (patch)
treeeaab38174de9e018827634ed079a885e232097a4 /externals/grill/py/source
parent6efb16b9040f7ba6db8c60559e0c815d54f05c43 (diff)
better reload handling, but still far fom perfect
fixed minor other issues cleaned up float vs. int pyext tags simplifications in py and pyext bumped version number python-like dotted module.function syntax send and receive wrapped PyObjects through inlets/outlets multiply inlets for py (hot and cold inlets) svn path=/trunk/; revision=3308
Diffstat (limited to 'externals/grill/py/source')
-rw-r--r--externals/grill/py/source/bound.cpp2
-rw-r--r--externals/grill/py/source/clmeth.cpp30
-rw-r--r--externals/grill/py/source/main.cpp621
-rw-r--r--externals/grill/py/source/main.h197
-rw-r--r--externals/grill/py/source/modmeth.cpp2
-rw-r--r--externals/grill/py/source/py.cpp168
-rw-r--r--externals/grill/py/source/pyargs.cpp146
-rw-r--r--externals/grill/py/source/pyatom.cpp61
-rw-r--r--externals/grill/py/source/pyatom.h19
-rw-r--r--externals/grill/py/source/pybase.cpp672
-rw-r--r--externals/grill/py/source/pybase.h206
-rw-r--r--externals/grill/py/source/pybuffer.cpp2
-rw-r--r--externals/grill/py/source/pyext.cpp141
-rw-r--r--externals/grill/py/source/pyext.h6
-rw-r--r--externals/grill/py/source/pyprefix.h12
-rw-r--r--externals/grill/py/source/register.cpp2
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,&nothing);
-
- // 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,&nothing);
+
+ // 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