aboutsummaryrefslogtreecommitdiff
path: root/externals/grill/py/source
diff options
context:
space:
mode:
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