aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--externals/grill/py/package.txt2
-rw-r--r--externals/grill/py/pd/script-1.pd13
-rw-r--r--externals/grill/py/pd/sig-1.pd28
-rw-r--r--externals/grill/py/pd/sig-2.pd23
-rw-r--r--externals/grill/py/py.vcproj3
-rw-r--r--externals/grill/py/readme.txt1
-rw-r--r--externals/grill/py/scripts/script.py12
-rw-r--r--externals/grill/py/scripts/sig.py64
-rw-r--r--externals/grill/py/source/bound.cpp6
-rw-r--r--externals/grill/py/source/clmeth.cpp59
-rw-r--r--externals/grill/py/source/main.cpp111
-rw-r--r--externals/grill/py/source/main.h47
-rw-r--r--externals/grill/py/source/modmeth.cpp34
-rw-r--r--externals/grill/py/source/py.cpp83
-rw-r--r--externals/grill/py/source/pyargs.cpp4
-rw-r--r--externals/grill/py/source/pybuffer.cpp22
-rw-r--r--externals/grill/py/source/pydsp.cpp179
-rw-r--r--externals/grill/py/source/pyext.cpp104
-rw-r--r--externals/grill/py/source/pyext.h63
-rw-r--r--externals/grill/py/source/register.cpp18
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();