diff options
-rw-r--r-- | externals/grill/py/package.txt | 2 | ||||
-rw-r--r-- | externals/grill/py/pd/script-1.pd | 13 | ||||
-rw-r--r-- | externals/grill/py/pd/sig-1.pd | 28 | ||||
-rw-r--r-- | externals/grill/py/pd/sig-2.pd | 23 | ||||
-rw-r--r-- | externals/grill/py/py.vcproj | 3 | ||||
-rw-r--r-- | externals/grill/py/readme.txt | 1 | ||||
-rw-r--r-- | externals/grill/py/scripts/script.py | 12 | ||||
-rw-r--r-- | externals/grill/py/scripts/sig.py | 64 | ||||
-rw-r--r-- | externals/grill/py/source/bound.cpp | 6 | ||||
-rw-r--r-- | externals/grill/py/source/clmeth.cpp | 59 | ||||
-rw-r--r-- | externals/grill/py/source/main.cpp | 111 | ||||
-rw-r--r-- | externals/grill/py/source/main.h | 47 | ||||
-rw-r--r-- | externals/grill/py/source/modmeth.cpp | 34 | ||||
-rw-r--r-- | externals/grill/py/source/py.cpp | 83 | ||||
-rw-r--r-- | externals/grill/py/source/pyargs.cpp | 4 | ||||
-rw-r--r-- | externals/grill/py/source/pybuffer.cpp | 22 | ||||
-rw-r--r-- | externals/grill/py/source/pydsp.cpp | 179 | ||||
-rw-r--r-- | externals/grill/py/source/pyext.cpp | 104 | ||||
-rw-r--r-- | externals/grill/py/source/pyext.h | 63 | ||||
-rw-r--r-- | externals/grill/py/source/register.cpp | 18 |
20 files changed, 665 insertions, 211 deletions
diff --git a/externals/grill/py/package.txt b/externals/grill/py/package.txt index 208fe827..cad479b6 100644 --- a/externals/grill/py/package.txt +++ b/externals/grill/py/package.txt @@ -10,6 +10,6 @@ SRCS= \ main.cpp \
py.cpp pyext.cpp modmeth.cpp clmeth.cpp \
register.cpp bound.cpp pyargs.cpp \
- pysymbol.cpp pybuffer.cpp
+ pysymbol.cpp pybuffer.cpp pydsp.cpp
HDRS= pyprefix.h main.h pyext.h pysymbol.h pybuffer.h
diff --git a/externals/grill/py/pd/script-1.pd b/externals/grill/py/pd/script-1.pd index b748857d..27b63d43 100644 --- a/externals/grill/py/pd/script-1.pd +++ b/externals/grill/py/pd/script-1.pd @@ -1,4 +1,4 @@ -#N canvas 297 17 688 530 12;
+#N canvas 297 17 692 534 12;
#X obj 39 278 print;
#X obj 345 251 print;
#X msg 499 149 freakhole;
@@ -8,16 +8,16 @@ #X msg 102 367 0 1 2 3 4;
#X msg 197 367 5 67 3;
#X obj 350 456 print;
-#X obj 326 365 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+#X obj 316 358 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
-1;
#X obj 515 455 print;
-#X obj 514 386 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+#X obj 484 381 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
-1;
#X msg 188 204 1 3;
#X msg 345 155 help;
-#X msg 360 327 set ret1;
-#X msg 379 351 set ret2;
-#X text 434 326 functions can be set;
+#X msg 350 320 set ret1;
+#X msg 369 344 set ret2;
+#X text 424 319 functions can be set;
#X msg 421 120 somewhere_past_mars;
#X text 152 101 reload with new arguments;
#X msg 40 104 reload 1 2 3;
@@ -37,6 +37,7 @@ file.; #X text 235 32 http://grrrr.org/ext;
#X msg 509 178 a b c;
#X text 556 181 too many args;
+#X text 505 372 just trigger without arguments;
#X connect 2 0 25 1;
#X connect 3 0 21 1;
#X connect 4 0 21 1;
diff --git a/externals/grill/py/pd/sig-1.pd b/externals/grill/py/pd/sig-1.pd new file mode 100644 index 00000000..aaba2fc7 --- /dev/null +++ b/externals/grill/py/pd/sig-1.pd @@ -0,0 +1,28 @@ +#N canvas 56 67 651 303 12;
+#X obj 56 234 dac~;
+#X msg 523 211 \; pd dsp 1;
+#X obj 524 184 loadbang;
+#X obj 194 114 hsl 128 15 0.01 1 1 1 empty empty gain -2 -6 0 8 -225271
+-1 -1 4400 1;
+#X obj 89 116 noise~;
+#X msg 28 117 reload;
+#X obj 16 13 cnv 15 600 40 empty empty py/pyext 10 22 0 24 -260818
+-1 0;
+#X text 213 32 http://grrrr.org/ext;
+#X text 213 16 Python script objects \, (C)2003-2005 Thomas Grill;
+#X text 17 66 This demonstrates signal support. See the sig.py file.
+;
+#X obj 191 131 nbx 5 14 0.001 1 1 0 empty empty empty 0 -6 0 10 -225271
+-1 -1 0.0493075 256;
+#X obj 67 181 pyext~ 0 0 1 1 sig gain;
+#X msg 192 148 set gain \$1;
+#X text 123 202 message inlets \, outlets;
+#X text 123 217 signal inlets \, outlets;
+#X connect 2 0 1 0;
+#X connect 3 0 10 0;
+#X connect 4 0 11 0;
+#X connect 5 0 11 0;
+#X connect 10 0 12 0;
+#X connect 11 0 0 0;
+#X connect 11 0 0 1;
+#X connect 12 0 11 0;
diff --git a/externals/grill/py/pd/sig-2.pd b/externals/grill/py/pd/sig-2.pd new file mode 100644 index 00000000..0e641600 --- /dev/null +++ b/externals/grill/py/pd/sig-2.pd @@ -0,0 +1,23 @@ +#N canvas 56 67 659 311 12;
+#X obj 121 246 dac~;
+#X msg 523 211 \; pd dsp 1;
+#X obj 524 184 loadbang;
+#X obj 266 134 hsl 128 15 0 1 0 1 empty empty pan -2 -6 0 8 -225271
+-1 -1 6500 1;
+#X obj 92 126 noise~;
+#X msg 31 127 reload;
+#X obj 16 13 cnv 15 600 40 empty empty py/pyext 10 22 0 24 -260818
+-1 0;
+#X text 213 32 http://grrrr.org/ext;
+#X text 213 16 Python script objects \, (C)2003-2005 Thomas Grill;
+#X text 17 66 This demonstrates signal support. See the sig.py file.
+;
+#X obj 92 179 pyext~ 1 0 1 2 sig pan;
+#X text 185 202 message inlets \, outlets;
+#X text 183 218 signal inlets \, outlets;
+#X connect 2 0 1 0;
+#X connect 3 0 10 1;
+#X connect 4 0 10 0;
+#X connect 5 0 10 0;
+#X connect 10 0 0 0;
+#X connect 10 1 0 1;
diff --git a/externals/grill/py/py.vcproj b/externals/grill/py/py.vcproj index 1541f6b0..328c89f0 100644 --- a/externals/grill/py/py.vcproj +++ b/externals/grill/py/py.vcproj @@ -1132,6 +1132,9 @@ RelativePath=".\source\pybuffer.h"> </File> <File + RelativePath=".\source\pydsp.cpp"> + </File> + <File RelativePath="source\pyext.cpp"> <FileConfiguration Name="PD Debug|Win32"> diff --git a/externals/grill/py/readme.txt b/externals/grill/py/readme.txt index 60260706..671be6cf 100644 --- a/externals/grill/py/readme.txt +++ b/externals/grill/py/readme.txt @@ -84,6 +84,7 @@ Version history: - ADD: _del method in pyext-derived class can be used to clean up things on exit - FIX: solved py->py messaging problem with lock count instead of message queuing - ADD: buffer handling with optional numarray support (if present) +- ADD: new objects for dsp processing: pyext~,pyx~,pyext.~,pyx.~ 0.1.4: - ADD: better (and independent) handling of inlet and outlet count (as class variables or dynamically initialized in __init__) diff --git a/externals/grill/py/scripts/script.py b/externals/grill/py/scripts/script.py index 88f7afd2..ff41730f 100644 --- a/externals/grill/py/scripts/script.py +++ b/externals/grill/py/scripts/script.py @@ -28,17 +28,11 @@ def strlen(arg): def strcat(*args): """Concatenate several symbols""" - s = "" - for si in args: - s += str(si) - return s - + return reduce(lambda a,b: a+str(b), args,"") def addall(*args): # variable argument list - s = 0 - for si in args: - s += si - return s + """Add a couple of numbers""" + return reduce(lambda a,b: a+b, args,0) def ret1(): diff --git a/externals/grill/py/scripts/sig.py b/externals/grill/py/scripts/sig.py new file mode 100644 index 00000000..8dccf5fe --- /dev/null +++ b/externals/grill/py/scripts/sig.py @@ -0,0 +1,64 @@ +# py/pyext - python script objects 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.
+#
+
+"""This is an example script for the py/pyext signal support.
+
+For numarray see http://numeric.scipy.org
+It will probably once be replaced by Numeric(3)
+"""
+
+try:
+ import pyext
+except:
+ print "ERROR: This script must be loaded by the PD/Max py/pyext external"
+
+try:
+ import psyco
+ psyco.full()
+ print "Using JIT compilation"
+except:
+ # don't care
+ pass
+
+import sys,math
+
+try:
+ import numarray
+except:
+ print "Failed importing numarray module:",sys.exc_value
+
+
+class gain(pyext._class):
+ """Just a simple gain stage"""
+
+ gain = 0
+
+ def _signal(self):
+ # Multiply input vector by gain and copy to output
+ self._outvec(0)[:] = self._invec(0)*self.gain
+
+
+class pan(pyext._class):
+ """Stereo panning"""
+
+ def __init__(self):
+ self.float_1(0.5)
+
+ def float_1(self,pos):
+ """pos ranges from 0 to 1"""
+ x = pos*math.pi/2
+ self.fl = math.cos(x)
+ self.fr = math.sin(x)
+
+ def _signal(self):
+ # Multiply input vector by gain and copy to output
+ iv = self._invec(0)
+ # first process right output channel because left one could be
+ # identical to input
+ # we could also test with 'self._outvec(1)[:] is iv'
+ self._outvec(1)[:] = iv*self.fr
+ self._outvec(0)[:] = iv*self.fl
diff --git a/externals/grill/py/source/bound.cpp b/externals/grill/py/source/bound.cpp index 5690e0b1..1d10c2d3 100644 --- a/externals/grill/py/source/bound.cpp +++ b/externals/grill/py/source/bound.cpp @@ -62,7 +62,7 @@ struct bounddata bool pyext::boundmeth(flext_base *th,t_symbol *sym,int argc,t_atom *argv,void *data) { bounddata *obj = (bounddata *)data; - py *pyth = static_cast<py *>(th); + pyext *pyth = static_cast<pyext *>(th); PyThreadState *state = pyth->PyLock(); @@ -92,7 +92,7 @@ PyObject *pyext::pyext_bind(PyObject *,PyObject *args) post("py/pyext - Wrong argument types!"); } else { - py *th = GetThis(self); + pyext *th = GetThis(self); FLEXT_ASSERT(th); const t_symbol *recv = pyObject_AsSymbol(name); @@ -134,7 +134,7 @@ PyObject *pyext::pyext_unbind(PyObject *,PyObject *args) post("py/pyext - Wrong argument types!"); } else { - py *th = GetThis(self); + pyext *th = GetThis(self); FLEXT_ASSERT(th); const t_symbol *recv = pyObject_AsSymbol(name); diff --git a/externals/grill/py/source/clmeth.cpp b/externals/grill/py/source/clmeth.cpp index 6062eda9..cfd8604a 100644 --- a/externals/grill/py/source/clmeth.cpp +++ b/externals/grill/py/source/clmeth.cpp @@ -29,6 +29,9 @@ PyMethodDef pyext::meth_tbl[] = { "_stop", pyext::pyext_stop, METH_VARARGS,"Stop running threads" }, #endif { "_isthreaded", pyext::pyext_isthreaded, METH_O,"Query whether threading is enabled" }, + + { "_invec", pyext::pyext_invec, METH_VARARGS,"Get input vector" }, + { "_outvec", pyext::pyext_outvec, METH_VARARGS,"Get output vector" }, {NULL, NULL, 0, NULL} /* Sentinel */ }; @@ -36,7 +39,7 @@ PyMethodDef pyext::attr_tbl[] = { { "__setattr__", pyext::pyext_setattr, METH_VARARGS,"Set class attribute" }, { "__getattr__", pyext::pyext_getattr, METH_VARARGS,"Get class attribute" }, - { NULL, NULL,0,NULL }, + { NULL, NULL,0,NULL }, }; @@ -174,6 +177,9 @@ PyObject *pyext::pyext_outlet(PyObject *,PyObject *args) if(lst) { 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])) @@ -195,7 +201,10 @@ PyObject *pyext::pyext_outlet(PyObject *,PyObject *args) if(!tp) Py_DECREF(val); } - if(!ok) post("pyext - Syntax: _outlet(self,outlet,args...)"); + if(!ok) { + PyErr_SetString(PyExc_SyntaxError,"pyext - Syntax: _outlet(self,outlet,args...)"); + return NULL; + } Py_INCREF(Py_None); return Py_None; @@ -211,7 +220,8 @@ PyObject *pyext::pyext_detach(PyObject *,PyObject *args) int val; if(!PyArg_ParseTuple(args, "Oi:pyext_detach",&self,&val)) { // handle error - post("pyext - Syntax: _detach(self,[0/1])"); + PyErr_SetString(PyExc_SyntaxError,"pyext - Syntax: _detach(self,[0/1])"); + return NULL; } else { pyext *ext = GetThis(self); @@ -229,7 +239,8 @@ PyObject *pyext::pyext_stop(PyObject *,PyObject *args) int val = -1; if(!PyArg_ParseTuple(args, "O|i:pyext_stop",&self,&val)) { // handle error - post("pyext - Syntax: _stop(self,{wait time}"); + PyErr_SetString(PyExc_SyntaxError,"pyext - Syntax: _stop(self,{wait time})"); + return NULL; } else { pyext *ext = GetThis(self); @@ -305,12 +316,50 @@ PyObject *pyext::pyext_tocanvas(PyObject *,PyObject *args) if(!tp) Py_DECREF(val); } - if(!ok) post("pyext - Syntax: _tocanvas(self,args...)"); + if(!ok) { + PyErr_SetString(PyExc_SyntaxError,"pyext - Syntax: _tocanvas(self,args...)"); + return NULL; + } Py_INCREF(Py_None); return Py_None; } #endif +PyObject *pyext::pyext_invec(PyObject *,PyObject *args) +{ + PyObject *self; + int val = -1; + if(!PyArg_ParseTuple(args, "O|i:pyext_invec",&self,&val)) { + // handle error + PyErr_SetString(PyExc_SyntaxError,"pyext - Syntax: _invec(self,inlet)"); + return NULL; + } + else { + pyext *ext = GetThis(self); + PyObject *b = ext->GetSig(val,true); + if(b) return b; + } + Py_INCREF(Py_None); + return Py_None; +} +PyObject *pyext::pyext_outvec(PyObject *,PyObject *args) +{ + PyObject *self; + int val = -1; + if(!PyArg_ParseTuple(args, "O|i:pyext_outvec",&self,&val)) { + // handle error + PyErr_SetString(PyExc_SyntaxError,"pyext - Syntax: _outvec(self,inlet)"); + return NULL; + } + else { + pyext *ext = GetThis(self); + PyObject *b = ext->GetSig(val,false); + if(b) return b; + } + + Py_INCREF(Py_None); + return Py_None; +} diff --git a/externals/grill/py/source/main.cpp b/externals/grill/py/source/main.cpp index e32b9ba8..aa234cc4 100644 --- a/externals/grill/py/source/main.cpp +++ b/externals/grill/py/source/main.cpp @@ -13,7 +13,7 @@ WARRANTIES, see the file, "license.txt," in this distribution. static PyMethodDef StdOut_Methods[] = { - { "write", py::StdOut_Write, 1 }, + { "write", pybase::StdOut_Write, 1 }, { NULL, NULL, } }; @@ -27,9 +27,9 @@ static PyInterpreterState *pymain = NULL; static PyThreadState *pythrmain = NULL; static PyThrMap pythrmap; -int py::lockcount = 0; +int pybase::lockcount = 0; -PyThreadState *py::FindThreadState() +PyThreadState *pybase::FindThreadState() { flext::thrid_t id = flext::GetThreadId(); PyThrMap::iterator it = pythrmap.find(id); @@ -43,7 +43,7 @@ PyThreadState *py::FindThreadState() return it->second; } -void py::FreeThreadState() +void pybase::FreeThreadState() { flext::thrid_t id = flext::GetThreadId(); PyThrMap::iterator it = pythrmap.find(id); @@ -59,10 +59,16 @@ void py::FreeThreadState() #endif +PyObject *pybase::module_obj = NULL; +PyObject *pybase::module_dict = NULL; + +PyObject *pybase::emptytuple = NULL; + + void initsymbol(); void initsamplebuffer(); -void py::lib_setup() +void pybase::lib_setup() { post(""); post("------------------------------------------------"); @@ -137,10 +143,13 @@ void py::lib_setup() initsamplebuffer(); PyModule_AddObject(module_obj,"Buffer",(PyObject *)&pySamplebuffer_Type); + emptytuple = PyTuple_New(0); + // ------------------------------------------------------------- FLEXT_SETUP(pyobj); FLEXT_SETUP(pyext); + FLEXT_DSP_SETUP(pydsp); #ifdef FLEXT_THREADS // release global lock @@ -151,24 +160,10 @@ void py::lib_setup() post(""); } -FLEXT_LIB_SETUP(py,py::lib_setup) +FLEXT_LIB_SETUP(py,pybase::lib_setup) -PyObject *py::module_obj = NULL; -PyObject *py::module_dict = NULL; - - -void py::Setup(t_classid c) -{ - FLEXT_CADDMETHOD_(c,0,"doc",m_doc); - FLEXT_CADDMETHOD_(c,0,"dir",m_dir); -#ifdef FLEXT_THREADS - FLEXT_CADDATTR_VAR1(c,"detach",detach); - FLEXT_CADDMETHOD_(c,0,"stop",m_stop); -#endif -} - -py::py() +pybase::pybase() : module(NULL),detach(0) #ifdef FLEXT_THREADS , shouldexit(false),thrcount(0),stoptick(0) @@ -177,23 +172,16 @@ py::py() PyThreadState *state = PyLock(); Py_INCREF(module_obj); PyUnlock(state); - -#ifdef FLEXT_THREADS - FLEXT_ADDTIMER(stoptmr,tick); - - // launch thread worker - FLEXT_CALLMETHOD(threadworker); -#endif } -py::~py() +pybase::~pybase() { PyThreadState *state = PyLock(); Py_XDECREF(module_obj); PyUnlock(state); } -void py::Exit() +void pybase::Exit() { #ifdef FLEXT_THREADS shouldexit = true; @@ -204,16 +192,15 @@ void py::Exit() Sleep(PY_STOP_TICK*0.001f); if(thrcount) { // Wait forever - post("%s - Waiting for thread termination!",thisName()); + post("py/pyext - Waiting for thread termination!"); while(thrcount) Sleep(PY_STOP_TICK*0.001f); - post("%s - Okay, all threads have terminated",thisName()); + post("py/pyext - Okay, all threads have terminated"); } } #endif - flext_base::Exit(); } -void py::GetDir(PyObject *obj,AtomList &lst) +void pybase::GetDir(PyObject *obj,AtomList &lst) { if(obj) { PyThreadState *state = PyLock(); @@ -227,7 +214,7 @@ void py::GetDir(PyObject *obj,AtomList &lst) lst = *l; delete l; } else - post("%s - %s: List could not be created",thisName(),GetString(thisTag())); + post("py/pyext - Argument list could not be created"); Py_DECREF(pvar); } @@ -235,15 +222,15 @@ void py::GetDir(PyObject *obj,AtomList &lst) } } -void py::m__dir(PyObject *obj) +void pybase::m__dir(PyObject *obj) { AtomList lst; GetDir(obj,lst); // dump dir to attribute outlet - ToOutAnything(GetOutAttr(),thisTag(),lst.Count(),lst.Atoms()); + DumpOut(NULL,lst.Count(),lst.Atoms()); } -void py::m__doc(PyObject *obj) +void pybase::m__doc(PyObject *obj) { if(obj) { PyThreadState *state = PyLock(); @@ -279,19 +266,19 @@ void py::m__doc(PyObject *obj) } } -void py::m_click() +void pybase::OpenEditor() { // this should once open the editor.... } -void py::SetArgs(int argc,const t_atom *argv) +void pybase::SetArgs(int argc,const t_atom *argv) { // script arguments char **sargv = new char *[argc+1]; for(int i = 0; i <= argc; ++i) { sargv[i] = new char[256]; if(!i) - strcpy(sargv[i],thisName()); + strcpy(sargv[i],"py/pyext"); else GetAString(argv[i-1],sargv[i],255); } @@ -303,7 +290,7 @@ void py::SetArgs(int argc,const t_atom *argv) delete[] sargv; } -void py::ImportModule(const char *name) +void pybase::ImportModule(const char *name) { if(!name) return; @@ -316,7 +303,7 @@ void py::ImportModule(const char *name) dict = PyModule_GetDict(module); } -void py::UnimportModule() +void pybase::UnimportModule() { if(!module) return; @@ -332,7 +319,7 @@ void py::UnimportModule() dict = NULL; } -void py::ReloadModule() +void pybase::ReloadModule() { if(module) { PyObject *newmod = PyImport_ReloadModule(module); @@ -348,10 +335,10 @@ void py::ReloadModule() } } else - post("%s - No module to reload",thisName()); + post("py/pyext - No module to reload"); } -void py::GetModulePath(const char *mod,char *dir,int len) +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 @@ -394,7 +381,7 @@ void py::GetModulePath(const char *mod,char *dir,int len) #endif } -void py::AddToPath(const char *dir) +void pybase::AddToPath(const char *dir) { if(dir && *dir) { PyObject *pobj = PySys_GetObject("path"); @@ -410,12 +397,12 @@ void py::AddToPath(const char *dir) static const t_symbol *sym_response = flext::MakeSymbol("response"); -void py::Respond(bool b) +void pybase::Respond(bool b) { if(respond) { t_atom a; SetBool(a,b); - ToOutAnything(GetOutAttr(),sym_response,1,&a); + DumpOut(sym_response,1,&a); } } @@ -424,7 +411,7 @@ void py::Respond(bool b) static PyObject *output = NULL; // post to the console -PyObject* py::StdOut_Write(PyObject* self, PyObject* args) +PyObject* pybase::StdOut_Write(PyObject* self, PyObject* args) { // should always be a tuple FLEXT_ASSERT(PyTuple_Check(args)); @@ -475,7 +462,7 @@ public: PyObject *fun,*args; }; -bool py::gencall(PyObject *pmeth,PyObject *pargs) +bool pybase::gencall(PyObject *pmeth,PyObject *pargs) { bool ret = false; @@ -494,18 +481,18 @@ bool py::gencall(PyObject *pmeth,PyObject *pargs) case 2: // each call a new thread if(!shouldexit) { - ret = FLEXT_CALLMETHOD_X(work_wrapper,new work_data(pmeth,pargs)); - if(!ret) post("%s - Failed to launch thread!",thisName()); + ret = thrcall(new work_data(pmeth,pargs)); + if(!ret) post("py/pyext - Failed to launch thread!"); } break; #endif default: - post("%s - Unknown detach mode",thisName()); + post("py/pyext - Unknown detach mode"); } return ret; } -void py::work_wrapper(void *data) +void pybase::work_wrapper(void *data) { FLEXT_ASSERT(data); @@ -528,7 +515,7 @@ void py::work_wrapper(void *data) } #ifdef FLEXT_THREADS -bool py::qucall(PyObject *fun,PyObject *args) +bool pybase::qucall(PyObject *fun,PyObject *args) { FifoEl *el = qufifo.New(); el->Set(fun,args); @@ -537,7 +524,7 @@ bool py::qucall(PyObject *fun,PyObject *args) return true; } -void py::threadworker() +void pybase::threadworker() { FifoEl *el; PyThreadState *state; @@ -573,7 +560,7 @@ void py::threadworker() #endif #if FLEXT_SYS == FLEXT_SYS_MAX -short py::patcher_myvol(t_patcher *x) +short pybase::patcher_myvol(t_patcher *x) { t_box *w; if (x->p_vol) @@ -585,12 +572,12 @@ short py::patcher_myvol(t_patcher *x) } #endif -bool py::collect() +bool pybase::collect() { if(gcollect) { - PyObject *args = PyTuple_New(0); - PyObject *ret = PyObject_Call(gcollect,args,NULL); - Py_DECREF(args); + Py_INCREF(emptytuple); + PyObject *ret = PyObject_Call(gcollect,emptytuple,NULL); + Py_DECREF(emptytuple); if(ret) { #ifdef FLEXT_DEBUG int refs = PyInt_AsLong(ret); diff --git a/externals/grill/py/source/main.h b/externals/grill/py/source/main.h index 7079dc2f..c76d43fa 100644 --- a/externals/grill/py/source/main.h +++ b/externals/grill/py/source/main.h @@ -41,23 +41,25 @@ public: typedef PooledFifo<FifoEl> PyFifo; -class py: - public flext_base -{ - FLEXT_HEADER_S(py,flext_base,Setup) +class pybase + : public flext +{ public: - py(); - ~py(); - static void lib_setup(); + pybase(); + virtual ~pybase(); - virtual void Exit(); + void Exit(); static PyObject *MakePyArgs(const t_symbol *s,int argc,const t_atom *argv,int inlet = -1,bool withself = false); static AtomList *GetPyArgs(PyObject *pValue,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); @@ -83,12 +85,15 @@ protected: void Reregister(const char *reg); virtual void Reload() = 0; + void OpenEditor(); void Respond(bool b); 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 }; + static PyObject *emptytuple; + // --- module stuff ----- static PyObject *module_obj,*module_dict; @@ -131,6 +136,7 @@ protected: 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 @@ -139,7 +145,7 @@ protected: static bool collect(); -private: +protected: void work_wrapper(void *data); @@ -151,10 +157,6 @@ private: static PyThreadState *FindThreadState(); static void FreeThreadState(); - - FLEXT_THREAD_X(work_wrapper) -#else - FLEXT_CALLBACK_X(work_wrapper) #endif public: @@ -189,25 +191,6 @@ public: #endif static PyObject* StdOut_Write(PyObject* Self, PyObject* Args); - -protected: - - virtual void m_click(); - - static void Setup(t_classid c); - - // callbacks - FLEXT_ATTRVAR_I(detach) - FLEXT_ATTRVAR_B(respond) - FLEXT_CALLBACK_V(m_stop) - FLEXT_CALLBACK(m_dir) - FLEXT_CALLGET_V(mg_dir) - FLEXT_CALLBACK(m_doc) - -#ifdef FLEXT_THREADS - FLEXT_CALLBACK_T(tick) - FLEXT_THREAD(threadworker) -#endif }; #endif diff --git a/externals/grill/py/source/modmeth.cpp b/externals/grill/py/source/modmeth.cpp index 4054d3ce..bbbe64b1 100644 --- a/externals/grill/py/source/modmeth.cpp +++ b/externals/grill/py/source/modmeth.cpp @@ -12,24 +12,24 @@ WARRANTIES, see the file, "license.txt," in this distribution. // function table for module -PyMethodDef py::func_tbl[] = +PyMethodDef pybase::func_tbl[] = { - { "_send", py::py_send, METH_VARARGS,"Send message to a named object" }, + { "_send", pybase::py_send, METH_VARARGS,"Send message to a named object" }, #ifdef FLEXT_THREADS - { "_priority", py::py_priority, METH_VARARGS,"Set priority of current thread" }, + { "_priority", pybase::py_priority, METH_VARARGS,"Set priority of current thread" }, #endif - { "_samplerate", py::py_samplerate, METH_NOARGS,"Get system sample rate" }, - { "_blocksize", py::py_blocksize, METH_NOARGS,"Get system block size" }, + { "_samplerate", pybase::py_samplerate, METH_NOARGS,"Get system sample rate" }, + { "_blocksize", pybase::py_blocksize, METH_NOARGS,"Get system block size" }, #if FLEXT_SYS == FLEXT_SYS_PD - { "_getvalue", py::py_getvalue, METH_VARARGS,"Get value of a 'value' object" }, - { "_setvalue", py::py_setvalue, METH_VARARGS,"Set value of a 'value' object" }, + { "_getvalue", pybase::py_getvalue, METH_VARARGS,"Get value of a 'value' object" }, + { "_setvalue", pybase::py_setvalue, METH_VARARGS,"Set value of a 'value' object" }, #endif {NULL, NULL, 0, NULL} // sentinel }; -const char *py::py_doc = +const char *pybase::py_doc = "py/pyext - python external object for PD and Max/MSP, (C)2002-2005 Thomas Grill\n" "\n" "This is the pyext module. Available function:\n" @@ -45,7 +45,7 @@ const char *py::py_doc = #ifdef FLEXT_THREADS -void py::tick(void *) +void pybase::tick(void *) { Lock(); @@ -57,7 +57,7 @@ void py::tick(void *) else { // still active threads if(!--stoptick) { - post("%s - Threads couldn't be stopped entirely - %i remaining",thisName(),thrcount); + post("py/pyext - Threads couldn't be stopped entirely - %i remaining",thrcount); shouldexit = false; } else @@ -69,7 +69,7 @@ void py::tick(void *) } #endif -void py::m_stop(int argc,const t_atom *argv) +void pybase::m_stop(int argc,const t_atom *argv) { #ifdef FLEXT_THREADS if(thrcount) { @@ -93,17 +93,17 @@ void py::m_stop(int argc,const t_atom *argv) #endif } -PyObject *py::py_samplerate(PyObject *self,PyObject *args) +PyObject *pybase::py_samplerate(PyObject *self,PyObject *args) { return PyFloat_FromDouble(sys_getsr()); } -PyObject *py::py_blocksize(PyObject *self,PyObject *args) +PyObject *pybase::py_blocksize(PyObject *self,PyObject *args) { return PyLong_FromLong(sys_getblksize()); } -PyObject *py::py_send(PyObject *,PyObject *args) +PyObject *pybase::py_send(PyObject *,PyObject *args) { // should always be a tuple FLEXT_ASSERT(PyTuple_Check(args)); @@ -153,7 +153,7 @@ PyObject *py::py_send(PyObject *,PyObject *args) } #ifdef FLEXT_THREADS -PyObject *py::py_priority(PyObject *self,PyObject *args) +PyObject *pybase::py_priority(PyObject *self,PyObject *args) { int val; if(!PyArg_ParseTuple(args, "i:py_priority", &val)) { @@ -168,7 +168,7 @@ PyObject *py::py_priority(PyObject *self,PyObject *args) #endif #if FLEXT_SYS == FLEXT_SYS_PD -PyObject *py::py_getvalue(PyObject *self,PyObject *args) +PyObject *pybase::py_getvalue(PyObject *self,PyObject *args) { FLEXT_ASSERT(PyTuple_Check(args)); @@ -195,7 +195,7 @@ PyObject *py::py_getvalue(PyObject *self,PyObject *args) return ret; } -PyObject *py::py_setvalue(PyObject *self,PyObject *args) +PyObject *pybase::py_setvalue(PyObject *self,PyObject *args) { FLEXT_ASSERT(PyTuple_Check(args)); diff --git a/externals/grill/py/source/py.cpp b/externals/grill/py/source/py.cpp index 3856739e..bf3ff8fb 100644 --- a/externals/grill/py/source/py.cpp +++ b/externals/grill/py/source/py.cpp @@ -11,19 +11,23 @@ WARRANTIES, see the file, "license.txt," in this distribution. #include "main.h" -class pyobj: - public py +class pyobj + : public pybase + , public flext_base { - FLEXT_HEADER_S(pyobj,py,Setup) + FLEXT_HEADER_S(pyobj,flext_base,Setup) public: pyobj(int argc,const t_atom *argv); ~pyobj(); protected: - bool m_method_(int n,const t_symbol *s,int argc,const t_atom *argv); + virtual void Exit(); - bool work(const t_symbol *s,int argc,const t_atom *argv); + virtual bool CbMethodResort(int n,const t_symbol *s,int argc,const t_atom *argv); + virtual void CbClick(); + + void m_help(); void m_reload(); void m_reload_(int argc,const t_atom *argv); @@ -31,16 +35,14 @@ protected: void m_dir_() { m__dir(function); } void m_doc_() { m__doc(function); } - virtual void m_help(); - // methods for python arguments void callwork(const t_symbol *s,int argc,const t_atom *argv); - void m_bang() { callwork(sym_bang,0,NULL); } - void m_py_list(int argc,const t_atom *argv) { callwork(sym_list,argc,argv); } - void m_py_float(int argc,const t_atom *argv) { callwork(sym_float,argc,argv); } - void m_py_int(int argc,const t_atom *argv) { callwork(sym_int,argc,argv); } - void m_py_any(const t_symbol *s,int argc,const t_atom *argv) { callwork(s,argc,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; @@ -51,12 +53,16 @@ protected: void SetFunction(const char *func); void ResetFunction(); + virtual bool thrcall(void *data); + virtual void DumpOut(const t_symbol *sym,int argc,const t_atom *argv); + private: virtual bool callpy(PyObject *fun,PyObject *args); static void Setup(t_classid c); + FLEXT_CALLBACK(m_help) FLEXT_CALLBACK(m_bang) FLEXT_CALLBACK(m_reload) FLEXT_CALLBACK_V(m_reload_) @@ -69,10 +75,20 @@ private: FLEXT_CALLBACK_V(m_py_int) FLEXT_CALLBACK_A(m_py_any) + // callbacks + FLEXT_ATTRVAR_I(detach) + FLEXT_ATTRVAR_B(respond) + FLEXT_CALLBACK_V(m_stop) + FLEXT_CALLBACK(m_dir) + FLEXT_CALLGET_V(mg_dir) + FLEXT_CALLBACK(m_doc) + #ifdef FLEXT_THREADS - FLEXT_THREAD_A(work) + FLEXT_CALLBACK_T(tick) + FLEXT_THREAD(threadworker) + FLEXT_THREAD_X(work_wrapper) #else - FLEXT_CALLBACK_A(work) + FLEXT_CALLBACK_X(work_wrapper) #endif }; @@ -81,6 +97,14 @@ FLEXT_LIB_V("py",pyobj) void pyobj::Setup(t_classid c) { + FLEXT_CADDMETHOD_(c,0,"doc",m_doc); + FLEXT_CADDMETHOD_(c,0,"dir",m_dir); +#ifdef FLEXT_THREADS + FLEXT_CADDATTR_VAR1(c,"detach",detach); + FLEXT_CADDMETHOD_(c,0,"stop",m_stop); +#endif + + FLEXT_CADDMETHOD_(c,0,"help",m_help); FLEXT_CADDMETHOD_(c,0,"reload",m_reload_); FLEXT_CADDMETHOD_(c,0,"reload.",m_reload); FLEXT_CADDMETHOD_(c,0,"doc+",m_doc_); @@ -100,11 +124,17 @@ void pyobj::Setup(t_classid c) pyobj::pyobj(int argc,const t_atom *argv): function(NULL),funname(NULL),withfunction(false) { - PyThreadState *state = PyLock(); - AddInAnything(2); AddOutAnything(); +#ifdef FLEXT_THREADS + FLEXT_ADDTIMER(stoptmr,tick); + // launch thread worker + FLEXT_CALLMETHOD(threadworker); +#endif + + PyThreadState *state = PyLock(); + if(argc > 2) SetArgs(argc-2,argv+2); else @@ -163,10 +193,13 @@ pyobj::~pyobj() PyUnlock(state); } +void pyobj::Exit() +{ + pybase::Exit(); + flext_base::Exit(); +} - - -bool pyobj::m_method_(int n,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) { if(n == 1) post("%s - no method for type %s",thisName(),GetString(s)); @@ -346,3 +379,15 @@ void pyobj::callwork(const t_symbol *s,int argc,const t_atom *argv) Respond(ret); } + +void pyobj::CbClick() { pybase::OpenEditor(); } + +void pyobj::DumpOut(const t_symbol *sym,int argc,const t_atom *argv) +{ + ToOutAnything(GetOutAttr(),sym?sym:thisTag(),argc,argv); +} + +bool pyobj::thrcall(void *data) +{ + return FLEXT_CALLMETHOD_X(work_wrapper,data); +} diff --git a/externals/grill/py/source/pyargs.cpp b/externals/grill/py/source/pyargs.cpp index a040feac..56b0123a 100644 --- a/externals/grill/py/source/pyargs.cpp +++ b/externals/grill/py/source/pyargs.cpp @@ -29,7 +29,7 @@ static PyObject *MakePyAtom(const t_atom &at) return NULL; } -PyObject *py::MakePyArgs(const t_symbol *s,int argc,const t_atom *argv,int inlet,bool withself) +PyObject *pybase::MakePyArgs(const t_symbol *s,int argc,const t_atom *argv,int inlet,bool withself) { PyObject *pArgs; @@ -84,7 +84,7 @@ PyObject *py::MakePyArgs(const t_symbol *s,int argc,const t_atom *argv,int inlet return pArgs; } -flext::AtomList *py::GetPyArgs(PyObject *pValue,PyObject **self) +flext::AtomList *pybase::GetPyArgs(PyObject *pValue,PyObject **self) { if(pValue == NULL) return NULL; AtomList *ret = NULL; diff --git a/externals/grill/py/source/pybuffer.cpp b/externals/grill/py/source/pybuffer.cpp index 96f2efae..6e7e571b 100644 --- a/externals/grill/py/source/pybuffer.cpp +++ b/externals/grill/py/source/pybuffer.cpp @@ -178,6 +178,21 @@ static PyObject *buffer_item(pySamplebuffer *self, int i) return ret;
}
+PyObject *NAFromBuffer(PyObject *buf,int c,int n)
+{
+#ifdef PY_NUMARRAY
+ if(nasupport) {
+ maybelong shape[2];
+ shape[0] = n;
+ shape[1] = c;
+ PyArrayObject *na = NA_NewAllFromBuffer(c == 1?1:2,shape,numtype,buf,0,0,NA_ByteOrder(),1,1);
+ return (PyObject *)na;
+ }
+ else
+#endif
+ return NULL;
+}
+
static PyObject *buffer_slice(pySamplebuffer *self,int ilow = 0,int ihigh = 1<<(sizeof(int)*8-2))
{
PyObject *ret;
@@ -191,10 +206,7 @@ static PyObject *buffer_slice(pySamplebuffer *self,int ilow = 0,int ihigh = 1<<( if(ihigh < 0) ihigh += n;
if(ihigh > n) ihigh = n;
- maybelong shape[2];
- shape[0] = n;
- shape[1] = c;
- PyObject *nobj = (PyObject *)NA_NewAllFromBuffer(c == 1?1:2,shape,numtype,(PyObject *)self,0,0,NA_ByteOrder(),1,1);
+ PyObject *nobj = NAFromBuffer((PyObject *)self,c,n);
if(ilow != 0 || ihigh != n) {
ret = PySequence_GetSlice(nobj,ilow,ihigh);
Py_DECREF(nobj);
@@ -657,7 +669,7 @@ void initsamplebuffer() import_libnumarray();
if(PyErr_Occurred())
// catch import error
- PyErr_Print();
+ PyErr_Clear();
else {
// numarray support ok
nasupport = true;
diff --git a/externals/grill/py/source/pydsp.cpp b/externals/grill/py/source/pydsp.cpp new file mode 100644 index 00000000..b1f50c0d --- /dev/null +++ b/externals/grill/py/source/pydsp.cpp @@ -0,0 +1,179 @@ +/*
+
+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 "pyext.h"
+
+class pydsp
+ : public pyext
+{
+ FLEXT_HEADER(pydsp,pyext)
+public:
+ pydsp(int argc,const t_atom *argv);
+
+protected:
+ virtual bool CbDsp();
+ virtual void CbSignal();
+
+ virtual bool DoInit();
+ virtual void DoExit();
+
+ virtual PyObject *GetSig(int ix,bool in);
+
+ void NewBuffers(bool update = false);
+ void FreeBuffers();
+
+ PyObject *dspfun,*sigfun;
+ PyObject **buffers;
+};
+
+FLEXT_LIB_DSP_V("pyext~ pyext.~ pyx~ pyx.~",pydsp)
+
+pydsp::pydsp(int argc,const t_atom *argv)
+ : pyext(argc,argv,true)
+ , dspfun(NULL),sigfun(NULL)
+{}
+
+bool pydsp::DoInit()
+{
+ if(!pyext::DoInit()) return false;
+
+ if(pyobj)
+ {
+ NewBuffers();
+
+ dspfun = PyObject_GetAttrString(pyobj,"_dsp"); // get ref
+ if(dspfun && !PyMethod_Check(dspfun)) {
+ Py_DECREF(dspfun);
+ dspfun = NULL;
+ }
+ sigfun = PyObject_GetAttrString(pyobj,"_signal"); // get ref
+ if(sigfun && !PyMethod_Check(sigfun)) {
+ Py_DECREF(sigfun);
+ sigfun = NULL;
+ }
+ }
+ return true;
+}
+
+void pydsp::DoExit()
+{
+ if(dspfun) { Py_DECREF(dspfun); dspfun = NULL; }
+ if(sigfun) { Py_DECREF(sigfun); sigfun = NULL; }
+
+ FreeBuffers();
+}
+
+PyObject *NAFromBuffer(PyObject *buf,int c,int n);
+
+void pydsp::NewBuffers(bool update)
+{
+ int i,n = Blocksize();
+ const int ins = CntInSig(),outs = CntOutSig();
+ t_sample *const *insigs = InSig();
+ t_sample *const *outsigs = OutSig();
+
+ if(!buffers) {
+ int cnt = ins+outs;
+ if(cnt) {
+ buffers = new PyObject *[cnt];
+ memset(buffers,0,cnt*sizeof(*buffers));
+ }
+ }
+
+ for(i = 0; i < ins; ++i) {
+ if(update) Py_XDECREF(buffers[i]);
+ PyObject *b = PyBuffer_FromReadWriteMemory(insigs[i],n*sizeof(t_sample));
+ buffers[i] = NAFromBuffer(b,1,n);
+ Py_DECREF(b);
+ }
+ for(i = 0; i < outs; ++i) {
+ if(update) Py_XDECREF(buffers[ins+i]);
+ if(i < ins && outsigs[i] == insigs[i]) {
+ // same vectors - share the objects!
+ buffers[ins+i] = buffers[i];
+ Py_XINCREF(buffers[i]);
+ }
+ else {
+ PyObject *b = PyBuffer_FromReadWriteMemory(outsigs[i],n*sizeof(t_sample));
+ buffers[ins+i] = NAFromBuffer(b,1,n);
+ Py_DECREF(b);
+ }
+ }
+}
+
+void pydsp::FreeBuffers()
+{
+ if(buffers) {
+ int cnt = CntInSig()+CntOutSig();
+ for(int i = 0; i < cnt; ++i) Py_XDECREF(buffers[i]);
+ delete[] buffers;
+ buffers = NULL;
+ }
+}
+
+bool pydsp::CbDsp()
+{
+ if(CntInSig() || CntOutSig())
+ {
+ NewBuffers(true);
+
+ if(dspfun) {
+ PyThreadState *state = PyLock();
+// Py_INCREF(emptytuple);
+ PyObject *ret = PyObject_Call(dspfun,emptytuple,NULL);
+// Py_DECREF(emptytuple);
+ if(ret)
+ Py_DECREF(ret);
+ else {
+#ifdef FLEXT_DEBUG
+ PyErr_Print();
+#else
+ PyErr_Clear();
+#endif
+ }
+ PyUnlock(state);
+ }
+ return true;
+ }
+ else
+ // switch on dsp only if there are signal inlets or outlets
+ return false;
+}
+
+void pydsp::CbSignal()
+{
+ if(sigfun) {
+ PyThreadState *state = PyLock();
+// Py_INCREF(emptytuple);
+ PyObject *ret = PyObject_Call(sigfun,emptytuple,NULL);
+// Py_DECREF(emptytuple);
+
+ if(ret)
+ Py_DECREF(ret);
+ else {
+#ifdef FLEXT_DEBUG
+ PyErr_Print();
+#else
+ PyErr_Clear();
+#endif
+ }
+ PyUnlock(state);
+ }
+ else
+ flext_dsp::CbSignal();
+}
+
+PyObject *pydsp::GetSig(int ix,bool in)
+{
+ PyObject *r = buffers[in?ix:CntInSig()+ix];
+ Py_XINCREF(r);
+ return r;
+}
+
diff --git a/externals/grill/py/source/pyext.cpp b/externals/grill/py/source/pyext.cpp index 72ae41fd..0ebeab68 100644 --- a/externals/grill/py/source/pyext.cpp +++ b/externals/grill/py/source/pyext.cpp @@ -20,6 +20,15 @@ void pyext::Setup(t_classid c) { sym_get = flext::MakeSymbol("get"); + FLEXT_CADDMETHOD_(c,0,"doc",m_doc); + FLEXT_CADDMETHOD_(c,0,"dir",m_dir); +#ifdef FLEXT_THREADS + FLEXT_CADDATTR_VAR1(c,"detach",detach); + FLEXT_CADDMETHOD_(c,0,"stop",m_stop); +#endif + + FLEXT_CADDMETHOD_(c,0,"help",m_help); + FLEXT_CADDMETHOD_(c,0,"reload",m_reload_); FLEXT_CADDMETHOD_(c,0,"reload.",m_reload); FLEXT_CADDMETHOD_(c,0,"doc+",m_doc_); @@ -95,19 +104,31 @@ void pyext::SetThis() PyObject *pyext::class_obj = NULL; PyObject *pyext::class_dict = NULL; -pyext::pyext(int argc,const t_atom *argv): +pyext::pyext(int argc,const t_atom *argv,bool sig): pyobj(NULL),pythr(NULL), inlets(-1),outlets(-1), + siginlets(0),sigoutlets(0), methname(NULL) { - int apre = 0; +#ifdef FLEXT_THREADS + FLEXT_ADDTIMER(stoptmr,tick); + // launch thread worker + 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(sig && argc >= apre+2 && CanbeInt(argv[apre]) && CanbeInt(argv[apre+1])) { + siginlets = GetAInt(argv[apre]); + sigoutlets = GetAInt(argv[apre+1]); + apre += 2; + } + const t_atom *clname = NULL; PyThreadState *state = PyLock(); @@ -162,38 +183,46 @@ pyext::pyext(int argc,const t_atom *argv): if(argc > apre) args(argc-apre,argv+apre); + PyUnlock(state); +} + +bool pyext::Init() +{ + PyThreadState *state = PyLock(); + if(methname) { MakeInstance(); - - if(pyobj) - InitInOut(inlets,outlets); + if(pyobj) InitInOut(inlets,outlets); } - else + else inlets = outlets = 0; - PyUnlock(state); - if(inlets < 0 || outlets < 0) InitProblem(); else { - AddInAnything(1+inlets); + AddInSignal(siginlets); + AddInAnything((siginlets?0:1)+inlets); + AddOutSignal(sigoutlets); AddOutAnything(outlets); } - if(!pyobj) - InitProblem(); + PyUnlock(state); + + return pyobj && flext_dsp::Init(); } -pyext::~pyext() -{ - PyThreadState *state = PyLock(); +void pyext::Exit() +{ + pybase::Exit(); // exit threads + PyThreadState *state = PyLock(); DoExit(); - Unregister("_pyext"); UnimportModule(); PyUnlock(state); + + flext_dsp::Exit(); } bool pyext::DoInit() @@ -230,13 +259,15 @@ void pyext::DoExit() // try to run del to clean up the class instance PyObject *objdel = PyObject_GetAttrString(pyobj,"_del"); if(objdel) { - PyObject *args = PyTuple_New(0); - PyObject *ret = PyObject_Call(objdel,args,NULL); - if(!ret) - post("%s - Could not call _del method",thisName()); - else + Py_INCREF(emptytuple); + PyObject *ret = PyObject_Call(objdel,emptytuple,NULL); + if(ret) Py_DECREF(ret); - Py_DECREF(args); +#ifdef FLEXT_DEBUG + else + post("%s - Could not call _del method",thisName()); +#endif + Py_DECREF(emptytuple); Py_DECREF(objdel); } else @@ -269,7 +300,7 @@ void pyext::InitInOut(int &inl,int &outl) if(inl < 0) { // get number of inlets - inl = 1; + inl = inlets; PyObject *res = PyObject_GetAttrString(pyobj,"_inlets"); // get ref if(res) { if(PyCallable_Check(res)) { @@ -286,7 +317,7 @@ void pyext::InitInOut(int &inl,int &outl) } if(outl < 0) { // get number of outlets - outl = 1; + outl = outlets; PyObject *res = PyObject_GetAttrString(pyobj,"_outlets"); // get ref if(res) { if(PyCallable_Check(res)) { @@ -436,14 +467,12 @@ void pyext::m_set(int argc,const t_atom *argv) } -bool pyext::m_method_(int n,const t_symbol *s,int argc,const t_atom *argv) +bool pyext::CbMethodResort(int n,const t_symbol *s,int argc,const t_atom *argv) { - bool ret = false; if(pyobj && n >= 1) - ret = work(n,s,argc,argv); + return work(n,s,argc,argv); else - post("%s - no method for type '%s' into inlet %i",thisName(),GetString(s),n); - return ret; + return flext_dsp::CbMethodResort(n,s,argc,argv); } @@ -522,6 +551,10 @@ bool pyext::work(int n,const t_symbol *s,int argc,const t_atom *argv) 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); @@ -585,3 +618,18 @@ bool pyext::work(int n,const t_symbol *s,int argc,const t_atom *argv) Respond(ret); return ret; } + +PyObject *pyext::GetSig(int ix,bool in) { return NULL; } + +void pyext::CbClick() { pybase::OpenEditor(); } +bool pyext::CbDsp() { return false; } + +void pyext::DumpOut(const t_symbol *sym,int argc,const t_atom *argv) +{ + ToOutAnything(GetOutAttr(),sym?sym:thisTag(),argc,argv); +} + +bool pyext::thrcall(void *data) +{ + return FLEXT_CALLMETHOD_X(work_wrapper,data); +} diff --git a/externals/grill/py/source/pyext.h b/externals/grill/py/source/pyext.h index f94b2f19..3c6a86b5 100644 --- a/externals/grill/py/source/pyext.h +++ b/externals/grill/py/source/pyext.h @@ -13,14 +13,14 @@ WARRANTIES, see the file, "license.txt," in this distribution. #include "main.h" -class pyext: - public py +class pyext + : public pybase + , public flext_dsp { - FLEXT_HEADER_S(pyext,py,Setup) + FLEXT_HEADER_S(pyext,flext_dsp,Setup) public: - pyext(int argc,const t_atom *argv); - ~pyext(); + pyext(int argc,const t_atom *argv,bool sig = false); static PyObject *pyext__doc__(PyObject *,PyObject *args); static PyObject *pyext__init__(PyObject *,PyObject *args); @@ -38,21 +38,35 @@ public: static PyObject *pyext_stop(PyObject *,PyObject *args); static PyObject *pyext_isthreaded(PyObject *,PyObject *); + static PyObject *pyext_inbuf(PyObject *,PyObject *args); + static PyObject *pyext_invec(PyObject *,PyObject *args); + static PyObject *pyext_outbuf(PyObject *,PyObject *args); + static PyObject *pyext_outvec(PyObject *,PyObject *args); + int Inlets() const { return inlets; } int Outlets() const { return outlets; } protected: - virtual bool m_method_(int n,const t_symbol *s,int argc,const t_atom *argv); + + virtual bool Init(); + virtual void Exit(); + + virtual bool CbMethodResort(int n,const t_symbol *s,int argc,const t_atom *argv); + virtual void CbClick(); + virtual bool CbDsp(); + + virtual void DumpOut(const t_symbol *sym,int argc,const t_atom *argv); bool work(int n,const t_symbol *s,int argc,const t_atom *argv); + void m_help(); + void m_reload(); void m_reload_(int argc,const t_atom *argv); void ms_args(const AtomList &a) { m_reload_(a.Count(),a.Atoms()); } void m_dir_() { m__dir(pyobj); } void mg_dir_(AtomList &lst) { GetDir(pyobj,lst); } void m_doc_() { m__doc(((PyInstanceObject *)pyobj)->in_class->cl_dict); } - virtual void m_help(); void m_get(const t_symbol *s); void m_set(int argc,const t_atom *argv); @@ -60,23 +74,27 @@ protected: const t_symbol *methname; PyObject *pyobj; int inlets,outlets; + int siginlets,sigoutlets; + + virtual void Reload(); + virtual bool DoInit(); + virtual void DoExit(); + + virtual PyObject *GetSig(int ix,bool in); + + static pyext *GetThis(PyObject *self); private: static void Setup(t_classid); - static pyext *GetThis(PyObject *self); void SetThis(); void ClearBinding(); bool MakeInstance(); - bool DoInit(); - void DoExit(); void InitInOut(int &inlets,int &outlets); AtomList args; - virtual void Reload(); - static PyObject *class_obj,*class_dict; static PyMethodDef attr_tbl[],meth_tbl[]; static const char *pyext_doc; @@ -89,6 +107,7 @@ private: bool call(const char *meth,int inlet,const t_symbol *s,int argc,const t_atom *argv); + virtual bool thrcall(void *data); virtual bool callpy(PyObject *fun,PyObject *args); static bool stcallpy(PyObject *fun,PyObject *args); @@ -96,7 +115,9 @@ private: private: static bool boundmeth(flext_base *,t_symbol *sym,int argc,t_atom *argv,void *data); - + + FLEXT_CALLBACK(m_help) + FLEXT_CALLBACK(m_reload) FLEXT_CALLBACK_V(m_reload_) FLEXT_CALLBACK(m_dir_) @@ -108,6 +129,22 @@ private: FLEXT_CALLBACK_S(m_get) FLEXT_CALLBACK_V(m_set) + + // callbacks + FLEXT_ATTRVAR_I(detach) + FLEXT_ATTRVAR_B(respond) + FLEXT_CALLBACK_V(m_stop) + FLEXT_CALLBACK(m_dir) + FLEXT_CALLGET_V(mg_dir) + FLEXT_CALLBACK(m_doc) + +#ifdef FLEXT_THREADS + FLEXT_CALLBACK_T(tick) + FLEXT_THREAD(threadworker) + FLEXT_THREAD_X(work_wrapper) +#else + FLEXT_CALLBACK_X(work_wrapper) +#endif }; #endif diff --git a/externals/grill/py/source/register.cpp b/externals/grill/py/source/register.cpp index ae273955..bc2563ae 100644 --- a/externals/grill/py/source/register.cpp +++ b/externals/grill/py/source/register.cpp @@ -11,7 +11,7 @@ WARRANTIES, see the file, "license.txt," in this distribution. #include "main.h" -void py::Register(const char *regnm) +void pybase::Register(const char *regnm) { if(module) { // add this to module registry @@ -20,7 +20,7 @@ void py::Register(const char *regnm) PyObject *add = Py_BuildValue("[i]",(long)this); if(!reg || !PyList_Check(reg)) { if(PyDict_SetItemString(dict,(char *)regnm,add)) { - post("%s - Could not set registry",thisName()); + post("py/pyext - Could not set registry"); } } else { @@ -29,7 +29,7 @@ void py::Register(const char *regnm) } } -void py::Unregister(const char *regnm) +void pybase::Unregister(const char *regnm) { if(module) { // remove this from module registry @@ -37,11 +37,11 @@ void py::Unregister(const char *regnm) PyObject *reg = PyDict_GetItemString(dict,(char *)regnm); // borrowed!!! PyObject *add = Py_BuildValue("i",(int)this); if(!reg || !PySequence_Check(reg)) - post("%s - Internal error: Registry not found!?",thisName()); + post("py/pyext - Internal error: Registry not found!?"); else { int ix = PySequence_Index(reg,add); if(ix < 0) { - post("%s - Internal error: object not found in registry?!",thisName()); + post("py/pyext - Internal error: object not found in registry?!"); } else { PySequence_DelItem(reg,ix); @@ -51,7 +51,7 @@ void py::Unregister(const char *regnm) } } -void py::Reregister(const char *regnm) +void pybase::Reregister(const char *regnm) { if(module) { // remove this from module registry @@ -59,16 +59,16 @@ void py::Reregister(const char *regnm) PyObject *reg = PyDict_GetItemString(dict,(char *)regnm); // borrowed!!! if(!reg || !PySequence_Check(reg)) - post("%s - Internal error: Registry not found!?",thisName()); + post("py/pyext - Internal error: Registry not found!?"); else { int cnt = PySequence_Size(reg); for(int i = 0; i < cnt; ++i) { PyObject *it = PySequence_GetItem(reg,i); // new reference if(!it || !PyInt_Check(it)) { - post("%s - Internal error: Corrupt registry?!",thisName()); + post("py/pyext - Internal error: Corrupt registry?!"); } else { - py *th = (py *)PyInt_AsLong(it); + pybase *th = (pybase *)PyInt_AsLong(it); th->module = module; th->dict = dict; th->Reload(); |