aboutsummaryrefslogtreecommitdiff
path: root/externals/grill
diff options
context:
space:
mode:
Diffstat (limited to 'externals/grill')
-rw-r--r--externals/grill/py/build/config-lnx.def3
-rw-r--r--externals/grill/py/build/config-mac.def3
-rw-r--r--externals/grill/py/build/config-win.def3
-rw-r--r--externals/grill/py/build/gnumake-lnx-gcc.inc3
-rw-r--r--externals/grill/py/build/gnumake-mac-gcc.inc3
-rw-r--r--externals/grill/py/build/gnumake-win-cygwin.inc3
-rw-r--r--externals/grill/py/build/nmake-win-msvc.inc3
-rw-r--r--externals/grill/py/package.txt32
-rw-r--r--externals/grill/py/py.vcproj6
-rw-r--r--externals/grill/py/py.xcodeproj/project.pbxproj14
-rw-r--r--externals/grill/py/readme.txt8
-rw-r--r--externals/grill/py/scripts/buffer.py120
-rw-r--r--externals/grill/py/scripts/sig.py200
-rw-r--r--externals/grill/py/scripts/simple.py4
-rw-r--r--externals/grill/py/source/bound.cpp2
-rw-r--r--externals/grill/py/source/clmeth.cpp4
-rw-r--r--externals/grill/py/source/modmeth.cpp4
-rw-r--r--externals/grill/py/source/py.cpp12
-rw-r--r--externals/grill/py/source/pyatom.cpp122
-rw-r--r--externals/grill/py/source/pyatom.h38
-rw-r--r--externals/grill/py/source/pybase.cpp1793
-rw-r--r--externals/grill/py/source/pybase.h479
-rw-r--r--externals/grill/py/source/pybundle.cpp460
-rw-r--r--externals/grill/py/source/pybundle.h66
-rw-r--r--externals/grill/py/source/pydsp.cpp380
-rw-r--r--externals/grill/py/source/pyext.cpp18
-rw-r--r--externals/grill/py/source/pyext.h4
-rw-r--r--externals/grill/py/source/pymeth.cpp856
-rw-r--r--externals/grill/py/source/pyprefix.h86
-rw-r--r--externals/grill/py/source/pysymbol.cpp508
-rw-r--r--externals/grill/py/source/pysymbol.h152
31 files changed, 2741 insertions, 2648 deletions
diff --git a/externals/grill/py/build/config-lnx.def b/externals/grill/py/build/config-lnx.def
index e19f03bc..10e518f5 100644
--- a/externals/grill/py/build/config-lnx.def
+++ b/externals/grill/py/build/config-lnx.def
@@ -9,3 +9,6 @@ PYTHONVERSION=2.4
PY_NUMPY=1
# PY_NUMARRAY=1
# PY_NUMERIC=1
+
+# use thread-safe GIL functionality (do this for python version >= 2.3!)
+PY_USE_GIL=1 \ No newline at end of file
diff --git a/externals/grill/py/build/config-mac.def b/externals/grill/py/build/config-mac.def
index 57f6e3d5..752ee335 100644
--- a/externals/grill/py/build/config-mac.def
+++ b/externals/grill/py/build/config-mac.def
@@ -3,3 +3,6 @@
PY_NUMPY=1
# PY_NUMARRAY=1
# PY_NUMERIC=1
+
+# use thread-safe GIL functionality (do this for python version >= 2.3!)
+PY_USE_GIL=1 \ No newline at end of file
diff --git a/externals/grill/py/build/config-win.def b/externals/grill/py/build/config-win.def
index fee70e7b..98ab5552 100644
--- a/externals/grill/py/build/config-win.def
+++ b/externals/grill/py/build/config-win.def
@@ -9,3 +9,6 @@ PYTHONPATH=%programfiles%/python$(PYTHONVER)
PY_NUMPY=1
# PY_NUMARRAY=1
# PY_NUMERIC=1
+
+# use thread-safe GIL functionality (do this for python version >= 2.3!)
+PY_USE_GIL=1 \ No newline at end of file
diff --git a/externals/grill/py/build/gnumake-lnx-gcc.inc b/externals/grill/py/build/gnumake-lnx-gcc.inc
index 483bb514..2babf197 100644
--- a/externals/grill/py/build/gnumake-lnx-gcc.inc
+++ b/externals/grill/py/build/gnumake-lnx-gcc.inc
@@ -12,3 +12,6 @@ ifdef PY_NUMERIC
DEFS += -DPY_NUMERIC
endif
+ifdef PY_USE_GIL
+DEFS += -DPY_USE_GIL
+endif
diff --git a/externals/grill/py/build/gnumake-mac-gcc.inc b/externals/grill/py/build/gnumake-mac-gcc.inc
index c7080d47..8f8591af 100644
--- a/externals/grill/py/build/gnumake-mac-gcc.inc
+++ b/externals/grill/py/build/gnumake-mac-gcc.inc
@@ -12,3 +12,6 @@ ifdef PY_NUMERIC
DEFS += -DPY_NUMERIC
endif
+ifdef PY_USE_GIL
+DEFS += -DPY_USE_GIL
+endif \ No newline at end of file
diff --git a/externals/grill/py/build/gnumake-win-cygwin.inc b/externals/grill/py/build/gnumake-win-cygwin.inc
index 102c2ecd..d9487833 100644
--- a/externals/grill/py/build/gnumake-win-cygwin.inc
+++ b/externals/grill/py/build/gnumake-win-cygwin.inc
@@ -13,3 +13,6 @@ ifdef PY_NUMERIC
DEFS += -DPY_NUMERIC
endif
+ifdef PY_USE_GIL
+DEFS += -DPY_USE_GIL
+endif \ No newline at end of file
diff --git a/externals/grill/py/build/nmake-win-msvc.inc b/externals/grill/py/build/nmake-win-msvc.inc
index 0820daf9..a23e03ca 100644
--- a/externals/grill/py/build/nmake-win-msvc.inc
+++ b/externals/grill/py/build/nmake-win-msvc.inc
@@ -14,3 +14,6 @@ DEFS = $(DEFS) /DPY_NUMPY
DEFS = $(DEFS) /DPY_NUMERIC
!endif
+!ifdef PY_USE_GIL
+DEFS = $(DEFS) /DPY_USE_GIL
+!endif
diff --git a/externals/grill/py/package.txt b/externals/grill/py/package.txt
index 001023bf..9002aa86 100644
--- a/externals/grill/py/package.txt
+++ b/externals/grill/py/package.txt
@@ -1,16 +1,16 @@
-NAME=py
-
-BUILDTYPE=multi
-BUILDDIR=build
-
-SRCDIR=source
-PRECOMPILE=pyprefix.h
-
-SRCS= \
- main.cpp \
- py.cpp pyext.cpp modmeth.cpp clmeth.cpp \
- register.cpp bound.cpp pyargs.cpp \
- pysymbol.cpp pybuffer.cpp pybundle.cpp pydsp.cpp \
- pyatom.cpp pybase.cpp pymeth.cpp
-
-HDRS= pyprefix.h main.h pyext.h pysymbol.h pybuffer.h pybundle.h pyatom.h pybase.h
+NAME=py
+
+BUILDTYPE=multi
+BUILDDIR=build
+
+SRCDIR=source
+PRECOMPILE=pyprefix.h
+
+SRCS= \
+ main.cpp \
+ py.cpp pyext.cpp modmeth.cpp clmeth.cpp \
+ register.cpp bound.cpp pyargs.cpp \
+ pysymbol.cpp pybuffer.cpp pybundle.cpp pydsp.cpp \
+ pyatom.cpp pybase.cpp pymeth.cpp
+
+HDRS= pyprefix.h main.h pyext.h pysymbol.h pybuffer.h pybundle.h pyatom.h pybase.h
diff --git a/externals/grill/py/py.vcproj b/externals/grill/py/py.vcproj
index 74c3954c..0a42243a 100644
--- a/externals/grill/py/py.vcproj
+++ b/externals/grill/py/py.vcproj
@@ -86,7 +86,7 @@
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="C:\data\prog\packs\pthreads\include;"c:\data\pd\pd-cvs\src";..\flext\source;C:\Programme\prog\Python24\include;"C:\Programme\prog\Python24\Lib\site-packages\numpy\core\include""
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;PY_EXPORTS;FLEXT_SYS=2;FLEXT_THREADS;xPY_NUMPY;xFLEXT_USECMEM"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;PY_EXPORTS;FLEXT_SYS=2;FLEXT_THREADS;PY_NUMPY;FLEXT_USECMEM;PY_USE_GIL"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
RuntimeTypeInfo="TRUE"
@@ -152,7 +152,7 @@
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="c:\programme\audio\pd\src;c:\data\pdmax\flext\source;C:\Programme\prog\Python24\include"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;FLEXT_SYS=2;FLEXT_THREADS;PY_EXPORTS;PY_NUMARRAY"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;FLEXT_SYS=2;FLEXT_THREADS;PY_EXPORTS;PY_NUMARRAY;PY_USE_GIL"
StringPooling="TRUE"
RuntimeLibrary="0"
EnableFunctionLevelLinking="TRUE"
@@ -167,7 +167,7 @@
<Tool
Name="VCLinkerTool"
AdditionalDependencies="pd.lib pthreadVC.lib"
- OutputFile="pd-msvc\py.dll"
+ OutputFile="$(outdir)\py.dll"
LinkIncremental="1"
SuppressStartupBanner="TRUE"
AdditionalLibraryDirectories="c:/programme/audio/pd/bin;&quot;..\flext\pd-msvc&quot;;C:\Programme\prog\Python24\libs"
diff --git a/externals/grill/py/py.xcodeproj/project.pbxproj b/externals/grill/py/py.xcodeproj/project.pbxproj
index ae60f114..30e3c783 100644
--- a/externals/grill/py/py.xcodeproj/project.pbxproj
+++ b/externals/grill/py/py.xcodeproj/project.pbxproj
@@ -578,7 +578,12 @@
isa = XCBuildConfiguration;
buildSettings = {
GCC_OPTIMIZATION_LEVEL = 0;
- GCC_PREPROCESSOR_DEFINITIONS = PY_NUMPY;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ _DEBUG,
+ PY_NUMPY,
+ PY_USE_GIL,
+ );
HEADER_SEARCH_PATHS = "/Library/Python/2.3/site-packages/numpy/core/include/";
};
name = Development;
@@ -591,7 +596,12 @@
ppc,
);
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
- GCC_PREPROCESSOR_DEFINITIONS = PY_NUMPY;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ NDEBUG,
+ PY_NUMPY,
+ PY_USE_GIL,
+ );
HEADER_SEARCH_PATHS = "/Library/Python/2.3/site-packages/numpy/core/include/";
};
name = Deployment;
diff --git a/externals/grill/py/readme.txt b/externals/grill/py/readme.txt
index cba59e07..c10b2b6a 100644
--- a/externals/grill/py/readme.txt
+++ b/externals/grill/py/readme.txt
@@ -1,6 +1,6 @@
py/pyext - python script objects for PD and Max/MSP
-Copyright (c)2002-2006 Thomas Grill (gr@grrrr.org)
+Copyright (c)2002-2007 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.
@@ -16,8 +16,9 @@ For OS X keep things as the are - it has Python installed by default.
The py/pyext package should run with Python version >= 2.1.
-It has been thoroughly tested with versions 2.2 to 2.4
+It has been thoroughly tested with versions 2.2 to 2.5
+The default build setting using PY_USE_GIL requires Python version >= 2.3.
Check out the sample patches and scripts
@@ -47,7 +48,6 @@ Known bugs:
- With standard PD 0.37, threaded py scripts will cause "Stack overflows" under some circumstances
-> use PD 0.38 or the devel_0_37 cvs branch instead
- It has been reported that pyext crashes on AMD64 with SSE enabled (for these CPUs, disable the respective compiler flags)
-- Threading in pyext obviously crashes under linux with Python version 2.4.2 (only)
----------------------------------------------------------------------------
@@ -120,6 +120,8 @@ Version history:
- ADD: py.Bundle class to support flext message bundles
- ADD: enable usage of compiled-only modules (.py[co])
- ADD: enable usage of module packages (with module/__init__.py[co])
+- ADD: make use of the PyGILState_*() functions
+- ADD: always run the Python interpreter in the background (to keep alive Python threads)
0.2.0:
- ADD: handling of Python threads
diff --git a/externals/grill/py/scripts/buffer.py b/externals/grill/py/scripts/buffer.py
index 2bd36203..46c47991 100644
--- a/externals/grill/py/scripts/buffer.py
+++ b/externals/grill/py/scripts/buffer.py
@@ -1,60 +1,60 @@
-# 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 object's buffer support.
-
-PD/Max buffers can be mapped to Python arrays.
-Currently, there are three implementations:
-Numeric, numarray and Numeric3 (for all of them see http://numeric.scipy.org)
-"""
-
-import sys
-
-try:
- import pyext
-except:
- print "ERROR: This script must be loaded by the PD/Max py/pyext external"
-
-try:
- from numarray import *
-except:
- print "Failed importing numarray module:",sys.exc_value
-
-def mul(*args):
- # create buffer objects
- # as long as these variables live the underlying buffers are locked
- c = pyext.Buffer(args[0])
- a = pyext.Buffer(args[1])
- b = pyext.Buffer(args[2])
-
- # slicing causes Python arrays (mapped to buffers) to be created
- # note the c[:] - to assign contents you must assign to a slice of the buffer
- c[:] = a[:]*b[:]
-
-def add(*args):
- c = pyext.Buffer(args[0])
- a = pyext.Buffer(args[1])
- b = pyext.Buffer(args[2])
-
- # this is also possible, but is probably slower
- # the + converts a into a Python array, the argument b is taken as a sequence
- # depending on the implementation this may be as fast
- # as above or not
- c[:] = a+b
-
-def fadein(target):
- a = pyext.Buffer(target)
- # in place operations are ok
- a *= arange(len(a),type=Float32)/len(a)
-
-def neg(target):
- a = pyext.Buffer(target)
- # in place transformation (see Python array ufuncs)
- negative(a[:],a[:])
- # must mark buffer content as dirty to update graph
- # (no explicit assignment occurred)
- a.dirty()
+# 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 object's buffer support.
+
+PD/Max buffers can be mapped to Python arrays.
+Currently, there are three implementations:
+Numeric, numarray and Numeric3 (for all of them see http://numeric.scipy.org)
+"""
+
+import sys
+
+try:
+ import pyext
+except:
+ print "ERROR: This script must be loaded by the PD/Max py/pyext external"
+
+try:
+ from numarray import *
+except:
+ print "Failed importing numarray module:",sys.exc_value
+
+def mul(*args):
+ # create buffer objects
+ # as long as these variables live the underlying buffers are locked
+ c = pyext.Buffer(args[0])
+ a = pyext.Buffer(args[1])
+ b = pyext.Buffer(args[2])
+
+ # slicing causes Python arrays (mapped to buffers) to be created
+ # note the c[:] - to assign contents you must assign to a slice of the buffer
+ c[:] = a[:]*b[:]
+
+def add(*args):
+ c = pyext.Buffer(args[0])
+ a = pyext.Buffer(args[1])
+ b = pyext.Buffer(args[2])
+
+ # this is also possible, but is probably slower
+ # the + converts a into a Python array, the argument b is taken as a sequence
+ # depending on the implementation this may be as fast
+ # as above or not
+ c[:] = a+b
+
+def fadein(target):
+ a = pyext.Buffer(target)
+ # in place operations are ok
+ a *= arange(len(a),type=Float32)/len(a)
+
+def neg(target):
+ a = pyext.Buffer(target)
+ # in place transformation (see Python array ufuncs)
+ negative(a[:],a[:])
+ # must mark buffer content as dirty to update graph
+ # (no explicit assignment occurred)
+ a.dirty()
diff --git a/externals/grill/py/scripts/sig.py b/externals/grill/py/scripts/sig.py
index 8aa1ce65..09be7b66 100644
--- a/externals/grill/py/scripts/sig.py
+++ b/externals/grill/py/scripts/sig.py
@@ -1,100 +1,100 @@
-# 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
- try:
- self._outvec(0)[:] = self._invec(0)*self.gain
- except:
- pass
-
-
-class gain2(pyext._class):
- """More optimized version"""
-
- gain = 0
-
- def _dsp(self):
- if not self._arraysupport():
- print "No DSP support"
- return False
-
- # cache vectors in this scope
- self.invec = self._invec(0)
- self.outvec = self._outvec(0)
- # initialize _signal method here for optimized version
- if self.invec is self.outvec:
- self._signal = self.signal1
- else:
- self._signal = self.signal2
- return True
-
- def signal1(self):
- # Multiply signal vector in place
- self.outvec *= self.gain
-
- def signal2(self):
- # Multiply input vector by gain and copy to output
- self.outvec[:] = self.invec*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 _dsp(self):
- # if _dsp is present it must return True to enable DSP
- return pyext._arraysupport()
-
- 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
+# 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
+ try:
+ self._outvec(0)[:] = self._invec(0)*self.gain
+ except:
+ pass
+
+
+class gain2(pyext._class):
+ """More optimized version"""
+
+ gain = 0
+
+ def _dsp(self):
+ if not self._arraysupport():
+ print "No DSP support"
+ return False
+
+ # cache vectors in this scope
+ self.invec = self._invec(0)
+ self.outvec = self._outvec(0)
+ # initialize _signal method here for optimized version
+ if self.invec is self.outvec:
+ self._signal = self.signal1
+ else:
+ self._signal = self.signal2
+ return True
+
+ def signal1(self):
+ # Multiply signal vector in place
+ self.outvec *= self.gain
+
+ def signal2(self):
+ # Multiply input vector by gain and copy to output
+ self.outvec[:] = self.invec*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 _dsp(self):
+ # if _dsp is present it must return True to enable DSP
+ return pyext._arraysupport()
+
+ 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/scripts/simple.py b/externals/grill/py/scripts/simple.py
index 04bea7ac..1aa211c5 100644
--- a/externals/grill/py/scripts/simple.py
+++ b/externals/grill/py/scripts/simple.py
@@ -1,6 +1,6 @@
# py/pyext - python script objects for PD and MaxMSP
#
-# Copyright (c) 2002-2005 Thomas Grill (gr@grrrr.org)
+# Copyright (c) 2002-2007 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.
#
@@ -57,6 +57,8 @@ pyext Usage:
self._outlet(outlet,arg1,arg2,arg3,arg4) ... where all args are atoms (no sequence types!)
or
self._outlet(outlet,arg) ... where arg is a sequence containing only atoms
+
+ Do not use _outlet inside __init__, since the outlets have not been created at that time.
- Use pyext functions and methods:
See the __doc__ strings of the pyext module and the pyext._class base class.
diff --git a/externals/grill/py/source/bound.cpp b/externals/grill/py/source/bound.cpp
index 3e7bc386..de81bf1c 100644
--- a/externals/grill/py/source/bound.cpp
+++ b/externals/grill/py/source/bound.cpp
@@ -64,7 +64,7 @@ bool pyext::boundmeth(flext_base *th,t_symbol *sym,int argc,t_atom *argv,void *d
bounddata *obj = (bounddata *)data;
pyext *pyth = static_cast<pyext *>(th);
- PyThreadState *state = pyth->PyLock();
+ ThrState state = pyth->PyLock();
PyObject *args = MakePyArgs(sym,argc,argv);
diff --git a/externals/grill/py/source/clmeth.cpp b/externals/grill/py/source/clmeth.cpp
index be003291..e1e01977 100644
--- a/externals/grill/py/source/clmeth.cpp
+++ b/externals/grill/py/source/clmeth.cpp
@@ -2,7 +2,7 @@
py/pyext - python external object for PD and Max/MSP
-Copyright (c)2002-2005 Thomas Grill (gr@grrrr.org)
+Copyright (c)2002-2007 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.
@@ -43,7 +43,7 @@ PyMethodDef pyext::attr_tbl[] =
const char *pyext::pyext_doc =
- "py/pyext - python external object for PD and Max/MSP, (C)2002-2005 Thomas Grill\n"
+ "py/pyext - python external object for PD and Max/MSP, (C)2002-2007 Thomas Grill\n"
"\n"
"This is the pyext base class. Available methods:\n"
"_outlet(self,ix,args...): Send a message to an indexed outlet\n"
diff --git a/externals/grill/py/source/modmeth.cpp b/externals/grill/py/source/modmeth.cpp
index 3d44d99e..52f5b964 100644
--- a/externals/grill/py/source/modmeth.cpp
+++ b/externals/grill/py/source/modmeth.cpp
@@ -2,7 +2,7 @@
py/pyext - python external object for PD and Max/MSP
-Copyright (c)2002-2006 Thomas Grill (gr@grrrr.org)
+Copyright (c)2002-2007 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.
@@ -35,7 +35,7 @@ PyMethodDef pybase::func_tbl[] =
};
const char *pybase::py_doc =
- "py/pyext - python external object for PD and Max/MSP, (C)2002-2006 Thomas Grill\n"
+ "py/pyext - python external object for PD and Max/MSP, (C)2002-2007 Thomas Grill\n"
"\n"
"This is the pyext module. Available function:\n"
"_send(args...): Send a message to a send symbol\n"
diff --git a/externals/grill/py/source/py.cpp b/externals/grill/py/source/py.cpp
index c773ffcb..f19ec36a 100644
--- a/externals/grill/py/source/py.cpp
+++ b/externals/grill/py/source/py.cpp
@@ -2,7 +2,7 @@
py/pyext - python script object for PD and Max/MSP
-Copyright (c)2002-2005 Thomas Grill (gr@grrrr.org)
+Copyright (c)2002-2007 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.
@@ -117,7 +117,7 @@ pyobj::pyobj(int argc,const t_atom *argv)
FLEXT_ADDTIMER(stoptmr,tick);
#endif
- PyThreadState *state = PyLockSys();
+ ThrState state = PyLockSys();
int inlets;
if(argc && CanbeInt(*argv)) {
@@ -193,7 +193,7 @@ pyobj::~pyobj()
delete[] objects;
}
- PyThreadState *state = PyLockSys();
+ ThrState state = PyLockSys();
Unregister(GetRegistry(REGNAME));
Report();
PyUnlock(state);
@@ -207,7 +207,7 @@ void pyobj::Exit()
void pyobj::m_set(int argc,const t_atom *argv)
{
- PyThreadState *state = PyLockSys();
+ ThrState state = PyLockSys();
// function name has precedence
if(argc >= 2) {
@@ -241,7 +241,7 @@ void pyobj::m_set(int argc,const t_atom *argv)
void pyobj::m_help()
{
post("");
- post("%s %s - python script object, (C)2002-2006 Thomas Grill",thisName(),PY__VERSION);
+ post("%s %s - python script object, (C)2002-2007 Thomas Grill",thisName(),PY__VERSION);
#ifdef FLEXT_DEBUG
post("DEBUG VERSION, compiled on " __DATE__ " " __TIME__);
#endif
@@ -346,7 +346,7 @@ bool pyobj::CbMethodResort(int n,const t_symbol *s,int argc,const t_atom *argv)
if(n == 0 && s != sym_bang)
return flext_base::CbMethodResort(n,s,argc,argv);
- PyThreadState *state = PyLockSys();
+ ThrState state = PyLockSys();
bool ret = false;
diff --git a/externals/grill/py/source/pyatom.cpp b/externals/grill/py/source/pyatom.cpp
index 07712f30..0af1b5e0 100644
--- a/externals/grill/py/source/pyatom.cpp
+++ b/externals/grill/py/source/pyatom.cpp
@@ -1,61 +1,61 @@
-/*
-
-py/pyext - python script object for PD and Max/MSP
-
-Copyright (c)2002-2005 Thomas Grill (gr@grrrr.org)
-For information on usage and redistribution, and for a DISCLAIMER OF ALL
-WARRANTIES, see the file, "license.txt," in this distribution.
-
-*/
-
-#include "pyatom.h"
-#include <map>
-
-#define INTV 0.01
-
-typedef std::map<size_t,PyObject *> ObjMap;
-
-static ObjMap objmap;
-static size_t collix = 0,curix = 0;
-static double last = 0;
-
-size_t PyAtom::Register(PyObject *obj)
-{
- Collect();
-
- Py_INCREF(obj);
- objmap[++curix] = obj;
-
-#ifdef _DEBUG
-// post("REG %p (%i)\n",obj,objmap.size());
-#endif
- return curix;
-}
-
-PyObject *PyAtom::Retrieve(size_t id)
-{
- ObjMap::iterator it = objmap.find(id);
- PyObject *ret = it == objmap.end()?NULL:it->second;
- Collect();
- return ret;
-}
-
-void PyAtom::Collect()
-{
- for(;;) {
- ObjMap::iterator it = objmap.begin();
- if(it == objmap.end() || it->first > collix) break;
-
- PyObject *obj = it->second;
- Py_DECREF(obj);
- objmap.erase(it);
-
-#ifdef _DEBUG
-// post("DEL %p\n",obj);
-#endif
- }
-
- // schedule next collect time
- double tm = flext::GetTime();
- if(tm > last+INTV) last = tm,collix = curix;
-}
+/*
+
+py/pyext - python script object for PD and Max/MSP
+
+Copyright (c)2002-2005 Thomas Grill (gr@grrrr.org)
+For information on usage and redistribution, and for a DISCLAIMER OF ALL
+WARRANTIES, see the file, "license.txt," in this distribution.
+
+*/
+
+#include "pyatom.h"
+#include <map>
+
+#define INTV 0.01
+
+typedef std::map<size_t,PyObject *> ObjMap;
+
+static ObjMap objmap;
+static size_t collix = 0,curix = 0;
+static double last = 0;
+
+size_t PyAtom::Register(PyObject *obj)
+{
+ Collect();
+
+ Py_INCREF(obj);
+ objmap[++curix] = obj;
+
+#ifdef _DEBUG
+// post("REG %p (%i)\n",obj,objmap.size());
+#endif
+ return curix;
+}
+
+PyObject *PyAtom::Retrieve(size_t id)
+{
+ ObjMap::iterator it = objmap.find(id);
+ PyObject *ret = it == objmap.end()?NULL:it->second;
+ Collect();
+ return ret;
+}
+
+void PyAtom::Collect()
+{
+ for(;;) {
+ ObjMap::iterator it = objmap.begin();
+ if(it == objmap.end() || it->first > collix) break;
+
+ PyObject *obj = it->second;
+ Py_DECREF(obj);
+ objmap.erase(it);
+
+#ifdef _DEBUG
+// post("DEL %p\n",obj);
+#endif
+ }
+
+ // schedule next collect time
+ double tm = flext::GetTime();
+ if(tm > last+INTV) last = tm,collix = curix;
+}
diff --git a/externals/grill/py/source/pyatom.h b/externals/grill/py/source/pyatom.h
index e96514c6..3c20c66b 100644
--- a/externals/grill/py/source/pyatom.h
+++ b/externals/grill/py/source/pyatom.h
@@ -1,19 +1,19 @@
-/*
-
-py/pyext - python script object for PD and Max/MSP
-
-Copyright (c)2002-2005 Thomas Grill (gr@grrrr.org)
-For information on usage and redistribution, and for a DISCLAIMER OF ALL
-WARRANTIES, see the file, "license.txt," in this distribution.
-
-*/
-
-#include "main.h"
-
-class PyAtom
-{
-public:
- static size_t Register(PyObject *obj);
- static PyObject *Retrieve(size_t id);
- static void Collect();
-};
+/*
+
+py/pyext - python script object for PD and Max/MSP
+
+Copyright (c)2002-2005 Thomas Grill (gr@grrrr.org)
+For information on usage and redistribution, and for a DISCLAIMER OF ALL
+WARRANTIES, see the file, "license.txt," in this distribution.
+
+*/
+
+#include "main.h"
+
+class PyAtom
+{
+public:
+ static size_t Register(PyObject *obj);
+ static PyObject *Retrieve(size_t id);
+ static void Collect();
+};
diff --git a/externals/grill/py/source/pybase.cpp b/externals/grill/py/source/pybase.cpp
index 5c9dd40c..a74df81e 100644
--- a/externals/grill/py/source/pybase.cpp
+++ b/externals/grill/py/source/pybase.cpp
@@ -1,881 +1,912 @@
-/*
-
-py/pyext - python external object for PD and MaxMSP
-
-Copyright (c)2002-2006 Thomas Grill (gr@grrrr.org)
-For information on usage and redistribution, and for a DISCLAIMER OF ALL
-WARRANTIES, see the file, "license.txt," in this distribution.
-
-*/
-
-#include "pybase.h"
-#include <map>
-
-#if FLEXT_OS == FLEXT_OS_WIN
-#include <windows.h>
-#elif FLEXT_OS == FLEXT_OS_MAC
-#include <ApplicationServices/ApplicationServices.h>
-#endif
-
-static PyMethodDef StdOut_Methods[] =
-{
- { "write", pybase::StdOut_Write, 1 },
- { NULL, NULL, }
-};
-
-static PyObject *gcollect = NULL;
-
-#ifdef FLEXT_THREADS
-
-class ThrCmp
-{
-public:
- inline bool operator()(const flext::thrid_t &a,const flext::thrid_t &b) const
- {
- if(sizeof(a) == sizeof(size_t))
- return *(size_t *)&a < *(size_t *)&b;
- else
- return memcmp(&a,&b,sizeof(a)) < 0;
- }
-};
-
-typedef std::map<flext::thrid_t,PyThreadState *,ThrCmp> PyThrMap;
-
-static PyInterpreterState *pymain = NULL;
-static PyThrMap pythrmap;
-PyThreadState *pybase::pythrsys = NULL;
-
-int pybase::lockcount = 0;
-
-PyThreadState *pybase::FindThreadState()
-{
- flext::thrid_t id = flext::GetThreadId();
- PyThrMap::iterator it = pythrmap.find(id);
- if(it == pythrmap.end()) {
- // Make new thread state
- PyThreadState *st = PyThreadState_New(pymain);
- pythrmap[id] = st;
- return st;
- }
- else
- return it->second;
-}
-
-void pybase::FreeThreadState()
-{
- flext::thrid_t id = flext::GetThreadId();
- PyThrMap::iterator it = pythrmap.find(id);
- if(it != pythrmap.end()) {
- // clear out any cruft from thread state object
- PyThreadState_Clear(it->second);
- // delete my thread state object
- PyThreadState_Delete(it->second);
- // delete from map
- pythrmap.erase(it);
- }
-}
-
-PyFifo pybase::qufifo;
-flext::ThrCond pybase::qucond;
-#endif
-
-
-PyObject *pybase::module_obj = NULL;
-PyObject *pybase::module_dict = NULL;
-
-PyObject *pybase::builtins_obj = NULL;
-PyObject *pybase::builtins_dict = NULL;
-
-const t_symbol *pybase::sym_fint = NULL;
-const t_symbol *pybase::sym_response = NULL;
-
-// -----------------------------------------------------------------------------------------------------------
-
-
-void initsymbol();
-void initsamplebuffer();
-void initbundle();
-
-void pybase::lib_setup()
-{
- post("");
- post("------------------------------------------------");
- post("py/pyext %s - python script objects",PY__VERSION);
- post("(C)2002-2006 Thomas Grill - http://grrrr.org/ext");
- post("");
- post("using Python %s",Py_GetVersion());
-
-#ifdef FLEXT_DEBUG
- post("");
- post("DEBUG version compiled on %s %s",__DATE__,__TIME__);
-#endif
-
- // -------------------------------------------------------------
-
- sym_response = flext::MakeSymbol("response");
-
-#if FLEXT_SYS == FLEXT_SYS_PD
- sym_fint = sym_float;
-#else
- sym_fint = sym_int;
-#endif
-
- // -------------------------------------------------------------
-
- Py_Initialize();
-
-#ifdef FLEXT_DEBUG
- Py_DebugFlag = 1;
-// Py_VerboseFlag = 1;
-#else
- Py_OptimizeFlag = 1;
-#endif
-
-#ifdef FLEXT_THREADS
- // enable thread support and acquire the global thread lock
- PyEval_InitThreads();
-
- // get thread state
- pythrsys = PyThreadState_Get();
- // get main interpreter state
- pymain = pythrsys->interp;
-
- // add thread state of main thread to map
- pythrmap[GetThreadId()] = pythrsys;
-#endif
-
- // sys.argv must be set to empty tuple
- char *nothing = "";
- PySys_SetArgv(0,&nothing);
-
- // register/initialize pyext module only once!
- module_obj = Py_InitModule(PYEXT_MODULE, func_tbl);
- module_dict = PyModule_GetDict(module_obj); // borrowed reference
-
- PyModule_AddStringConstant(module_obj,"__doc__",(char *)py_doc);
-
- // redirect stdout
- PyObject* py_out;
- py_out = Py_InitModule("stdout", StdOut_Methods);
- PySys_SetObject("stdout", py_out);
- py_out = Py_InitModule("stderr", StdOut_Methods);
- PySys_SetObject("stderr", py_out);
-
- // get garbage collector function
- PyObject *gcobj = PyImport_ImportModule("gc");
- if(gcobj) {
- gcollect = PyObject_GetAttrString(gcobj,"collect");
- Py_DECREF(gcobj);
- }
-
- builtins_obj = PyImport_ImportModule("__builtin__");
- builtins_dict = PyModule_GetDict(builtins_obj); // borrowed reference
-
- // add symbol type
- initsymbol();
- PyModule_AddObject(module_obj,"Symbol",(PyObject *)&pySymbol_Type);
-
- // pre-defined symbols
- PyModule_AddObject(module_obj,"_s_",(PyObject *)pySymbol__);
- PyModule_AddObject(module_obj,"_s_bang",(PyObject *)pySymbol_bang);
- PyModule_AddObject(module_obj,"_s_list",(PyObject *)pySymbol_list);
- PyModule_AddObject(module_obj,"_s_symbol",(PyObject *)pySymbol_symbol);
- PyModule_AddObject(module_obj,"_s_float",(PyObject *)pySymbol_float);
- PyModule_AddObject(module_obj,"_s_int",(PyObject *)pySymbol_int);
-
- // add samplebuffer type
- initsamplebuffer();
- PyModule_AddObject(module_obj,"Buffer",(PyObject *)&pySamplebuffer_Type);
-
- // add message bundle type
- initbundle();
- PyModule_AddObject(module_obj,"Bundle",(PyObject *)&pyBundle_Type);
-
- // -------------------------------------------------------------
-
- FLEXT_SETUP(pyobj);
- FLEXT_SETUP(pymeth);
- FLEXT_SETUP(pyext);
-#ifndef PY_NODSP
- FLEXT_DSP_SETUP(pydsp);
-#endif
-
-#ifdef FLEXT_THREADS
- // release global lock
- PyEval_ReleaseLock();
-
- // launch thread worker
- LaunchThread(quworker,NULL);
-#endif
-
- post("------------------------------------------------");
- post("");
-}
-
-FLEXT_LIB_SETUP(py,pybase::lib_setup)
-
-
-// -----------------------------------------------------------------------------------------------------------
-
-
-pybase::pybase()
- : module(NULL)
- , dict(NULL)
-#ifdef FLEXT_THREADS
- , thrcount(0)
- , shouldexit(false),stoptick(0)
-#endif
- , detach(0)
- , pymsg(false)
-{
- PyThreadState *state = PyLock();
- Py_INCREF(module_obj);
- PyUnlock(state);
-}
-
-pybase::~pybase()
-{
- PyThreadState *state = PyLock();
- Py_XDECREF(module_obj);
- PyUnlock(state);
-}
-
-void pybase::Exit()
-{
-#ifdef FLEXT_THREADS
- erasethreads();
-
- shouldexit = true;
- qucond.Signal();
-
- if(thrcount) {
- // Wait for a certain time
- for(int i = 0; i < (PY_STOP_WAIT/PY_STOP_TICK) && thrcount; ++i)
- Sleep(PY_STOP_TICK*0.001f);
- if(thrcount) {
- // Wait forever
- post("py/pyext - Waiting for thread termination!");
- while(thrcount) Sleep(PY_STOP_TICK*0.001f);
- post("py/pyext - Okay, all threads have terminated");
- }
- }
-#endif
-}
-
-void pybase::GetDir(PyObject *obj,AtomList &lst)
-{
- if(obj) {
- PyThreadState *state = PyLock();
-
- PyObject *pvar = PyObject_Dir(obj);
- if(!pvar)
- PyErr_Print(); // no method found
- else {
- const t_symbol *sym = GetPyArgs(lst,pvar);
- if(!sym)
- post("py/pyext - Argument list could not be created");
- else
- FLEXT_ASSERT(sym == sym_list);
- Py_DECREF(pvar);
- }
-
- PyUnlock(state);
- }
-}
-
-void pybase::m__dir(PyObject *obj)
-{
- AtomList lst;
- GetDir(obj,lst);
- // dump dir to attribute outlet
- DumpOut(NULL,lst.Count(),lst.Atoms());
-}
-
-void pybase::m__doc(PyObject *obj)
-{
- if(obj) {
- PyThreadState *state = PyLock();
-
- PyObject *docf = PyDict_GetItemString(obj,"__doc__"); // borrowed!!!
- if(docf && PyString_Check(docf)) {
- post("");
- const char *s = PyString_AS_STRING(docf);
-
- // FIX: Python doc strings can easily be larger than 1k characters
- // -> split into separate lines
- for(;;) {
- char buf[1024];
- char *nl = strchr((char *)s,'\n'); // the cast is for Borland C++
- if(!nl) {
- // no more newline found
- post(s);
- break;
- }
- else {
- // copy string before newline to temp buffer and post
- unsigned int l = nl-s;
- if(l >= sizeof(buf)) l = sizeof buf-1;
- strncpy(buf,s,l); // copy all but newline
- buf[l] = 0;
- post(buf);
- s = nl+1; // set after newline
- }
- }
- }
-
- PyUnlock(state);
- }
-}
-
-void pybase::OpenEditor()
-{
- if(!module) return;
- const char *mname = PyModule_GetFilename(module);
- if(!mname) {
- PyErr_Clear();
- return;
- }
-
- char fname[1024];
- strcpy(fname,mname);
-
- // replacing .pyc or .pyo for source file name
- char *dt = strrchr(fname,'.');
- if(dt && !strncmp(dt,".py",2)) strcpy(dt,".py");
-
- // this should open the editor....
-#if FLEXT_OS == FLEXT_OS_WIN
- int err = (int)ShellExecute(NULL,"edit",fname,NULL,NULL,SW_SHOW);
- if(err == SE_ERR_NOASSOC) {
- // no association found - try notepad
- err = (int)ShellExecute(NULL,NULL,"notepad.exe",fname,NULL,SW_SHOW);
- }
- else if(err == ERROR_FILE_NOT_FOUND || err == SE_ERR_FNF)
- post("py/pyext - File not %s found",fname);
- else if(err <= 32)
- post("py/pyext - Unknown error opening %s",fname);
-
-#elif FLEXT_OS == FLEXT_OS_MAC
- FSRef ref;
- OSStatus err = FSPathMakeRef((unsigned char *)fname,&ref,NULL);
- if(err)
- post("py/pyext - Error interpreting path %s",fname);
- else {
- FSRef editor;
- err = LSGetApplicationForItem(&ref,kLSRolesEditor,&editor,NULL);
- if(err) {
- // Can't find associated application... try Textedit
- err = FSPathMakeRef((unsigned char *)"/Applications/TextEdit.app",&editor,NULL);
- if(err)
- post("py/pyext - Can't find Textedit application");
- }
-
- if(!err) {
- LSLaunchFSRefSpec lspec;
- lspec.appRef = &editor;
- lspec.numDocs = 1;
- lspec.itemRefs = &ref;
- lspec.passThruParams = NULL;
- lspec.launchFlags = kLSLaunchDefaults;
- lspec.asyncRefCon = NULL;
- err = LSOpenFromRefSpec(&lspec,NULL);
- if(err)
- post("py/pyext - Couldn't launch editor");
- }
- }
-#else
- // thanks to Tim Blechmann
-
- char *editor = getenv("EDITOR");
-
- if(!editor) { // || !strcmp(editor, "/usr/bin/nano") || !strcmp(editor, "/usr/bin/pico") || !strcmp(editor, "/usr/bin/vi")) {
- // no environment variable or console text editor found ... use idle instead (should have come with Python)
- editor = "idle";
- }
-
- pid_t child = fork();
- if(!child) {
- char cmd[80];
- strcpy(cmd,editor);
- strcat(cmd," ");
- strcat(cmd,fname);
- execl("/bin/sh", "sh", "-c", cmd, (char *) NULL);
- }
-#endif
-}
-
-void pybase::SetArgs()
-{
- // script arguments
- int argc = args.Count();
- const t_atom *argv = args.Atoms();
- char **sargv = new char *[argc+1];
- for(int i = 0; i <= argc; ++i) {
- sargv[i] = new char[256];
- if(!i)
- strcpy(sargv[i],"py/pyext");
- else
- GetAString(argv[i-1],sargv[i],255);
- }
-
- // the arguments to the module are only recognized once! (at first use in a patcher)
- PySys_SetArgv(argc+1,sargv);
-
- for(int j = 0; j <= argc; ++j) delete[] sargv[j];
- delete[] sargv;
-}
-
-static bool getmodulesub(const char *mod,char *dir,int len,char *ext)
-{
-#if FLEXT_SYS == FLEXT_SYS_PD
- char *name;
- int fd = open_via_path("",mod,ext,dir,&name,len,0);
- if(fd > 0) {
- FLEXT_ASSERT(name && *name);
- close(fd);
- }
- else {
- // look for mod/__init__.py
- std::string tmp(mod);
- int l = tmp.size();
- tmp += "/__init__";
- fd = open_via_path("",tmp.c_str(),ext,dir,&name,len,0);
- if(fd > 0) {
- FLEXT_ASSERT(name && *name);
- close(fd);
- // we must remove the module name from dir
- char *t = dir+strlen(dir)-l;
- FLEXT_ASSERT(!strcmp(mod,t) && t[-1] == '/');
- t[-1] = 0;
- }
- else
- name = NULL;
- }
-
- // if dir is current working directory... name points to dir
- if(dir == name) strcpy(dir,".");
- return name != NULL;
-#elif FLEXT_SYS == FLEXT_SYS_MAX
- short path;
- long type;
- char smod[1024];
- strcpy(smod,mod);
- strcat(smod,ext);
- bool ok = !locatefile_extended(smod,&path,&type,&type,0);
- if(ok)
- // convert pathname to unix style
- path_topathname(path,NULL,smod);
- else {
- // do path/file.ext combinations work at all under Max?
- strcpy(smod,mod);
-
- short path;
- type = 'fold';
- ok = !locatefile_extended(smod,&path,&type,&type,1);
- if(ok) {
- // convert pathname to unix style (including trailing slash)
- path_topathname(path,NULL,smod);
- char *end = smod+strlen(smod);
- strcpy(end,mod);
- strcat(end,"/__init__");
- strcat(end,ext);
-
- // check if file is really existing: try to open it
- FILE *f = fopen(smod,"r");
- if(f) {
- *end = 0; // clear module part ... we only need base path
- fclose(f);
- }
- else
- ok = false;
- }
- }
-
- if(ok) {
- // convert path into slash style needed for Python
-#if 0
- // Max API function uses Volume:/Path notation
- path_nameconform(smod,dir,PATH_STYLE_SLASH,PATH_TYPE_ABSOLUTE);
-#else
-#if FLEXT_OS == FLEXT_OS_WIN
- char *colon = NULL;
-#else
- char *colon = strchr(smod,':');
-#endif
- if(colon) {
- *colon = 0;
- strcpy(dir,"/Volumes/");
- strcat(dir,smod);
- strcat(dir,colon+1);
- }
- else
- strcpy(dir,smod);
-#endif
- return true;
- }
- else
- // not found
- return false;
-#else
-#pragma message("Not implemented");
- return false;
-#endif
-}
-
-static bool getmodulepath(const char *mod,char *dir,int len)
-{
- return
- getmodulesub(mod,dir,len,".py") ||
- getmodulesub(mod,dir,len,".pyc") ||
- getmodulesub(mod,dir,len,".pyo");
-}
-
-bool pybase::ImportModule(const char *name)
-{
- if(name) {
- if(modname == name) {
- // module with the same name is already loaded
- if(module) return true;
- }
- else
- modname = name;
- }
- else
- modname.clear();
-
- UnimportModule();
- return ReloadModule();
-}
-
-void pybase::UnimportModule()
-{
- if(module) {
- FLEXT_ASSERT(dict && module_obj && module_dict);
-
- Py_DECREF(module);
-
- // reference count to module is not 0 here, altough probably the last instance was unloaded
- // Python retains one reference to the module all the time
- // we don't care
-
- module = NULL;
- dict = NULL;
- }
-}
-
-bool pybase::ReloadModule()
-{
- SetArgs();
- PyObject *newmod;
-
- if(modname.length()) {
- if(module)
- newmod = PyImport_ReloadModule(module);
- else {
- // search in module path (TODO: check before if module is already present to avoid costly searching)
- char dir[1024];
- if(!getmodulepath(modname.c_str(),dir,sizeof(dir)))
- PyErr_SetString(PyExc_ImportError,"Module not found in path");
- else
- AddToPath(dir);
-
- // module could also be loaded ok, even if it's not in the path (e.g. for internal stuff)
- newmod = PyImport_ImportModule((char *)modname.c_str());
- }
- }
- else {
- // if no module name given, take py module
- newmod = module_obj;
- Py_INCREF(newmod);
- }
-
- if(!newmod) {
- // unload faulty module
- UnimportModule();
- return false;
- }
- else {
- Py_XDECREF(module);
- module = newmod;
- dict = PyModule_GetDict(module); // borrowed
- return true;
- }
-}
-
-void pybase::AddToPath(const char *dir)
-{
- if(dir && *dir) {
- PyObject *pobj = PySys_GetObject("path");
- if(pobj && PyList_Check(pobj)) {
- PyObject *ps = PyString_FromString(dir);
- if(!PySequence_Contains(pobj,ps))
- PyList_Append(pobj,ps); // makes new reference
- Py_DECREF(ps);
- }
- PySys_SetObject("path",pobj); // steals reference to pobj
- }
-}
-
-void pybase::AddCurrentPath(flext_base *o)
-{
- char dir[1024];
-
- // add dir of current patch to path
- o->GetCanvasDir(dir,sizeof(dir));
- if(*dir) AddToPath(dir);
-
- // add current dir to path
-#if FLEXT_SYS == FLEXT_SYS_PD
- AddToPath(GetString(canvas_getcurrentdir()));
-#elif FLEXT_SYS == FLEXT_SYS_MAX
- short path = path_getdefault();
- path_topathname(path,NULL,dir);
- AddToPath(dir);
-#endif
-}
-
-bool pybase::OutObject(flext_base *ext,int o,PyObject *obj)
-{
- flext::AtomListStatic<16> lst;
- const t_symbol *sym = pymsg?GetPyAtom(lst,obj):GetPyArgs(lst,obj);
- if(sym) {
- // call to outlet _outside_ the Mutex lock!
- // otherwise (if not detached) deadlock will occur
- ext->ToOutAnything(o,sym,lst.Count(),lst.Atoms());
- return true;
- }
- else
- return false;
-}
-
-void pybase::Reload()
-{
- PyThreadState *state = PyLock();
-
- PyObject *reg = GetRegistry(REGNAME);
-
- if(reg) {
- PyObject *key;
- int pos = 0;
- while(PyDict_Next(reg,&pos,&key,NULL)) {
- pybase *th = (pybase *)PyLong_AsLong(key);
- FLEXT_ASSERT(th);
- th->Unload();
- }
-
- UnloadModule();
- }
-
- bool ok = ReloadModule();
-
- if(ok) {
- LoadModule();
-
- if(reg) {
- SetRegistry(REGNAME,reg);
-
- PyObject *key;
- int pos = 0;
- while(PyDict_Next(reg,&pos,&key,NULL)) {
- pybase *th = (pybase *)PyLong_AsLong(key);
- FLEXT_ASSERT(th);
- th->Load();
- }
- }
- else
- Load();
- }
-
- Report();
- PyUnlock(state);
-}
-
-static PyObject *output = NULL;
-
-// post to the console
-PyObject* pybase::StdOut_Write(PyObject* self, PyObject* args)
-{
- // should always be a tuple
- FLEXT_ASSERT(PyTuple_Check(args));
-
- const int sz = PyTuple_GET_SIZE(args);
-
- for(int i = 0; i < sz; ++i) {
- PyObject *val = PyTuple_GET_ITEM(args,i); // borrowed reference
- PyObject *str = PyObject_Str(val); // new reference
- char *cstr = PyString_AS_STRING(str);
- char *lf = strchr(cstr,'\n');
-
- // line feed in string
- if(!lf) {
- // no -> just append
- if(output)
- PyString_ConcatAndDel(&output,str); // str is decrefd
- else
- output = str; // take str reference
- }
- else {
- // yes -> append up to line feed, reset output buffer to string remainder
- PyObject *part = PyString_FromStringAndSize(cstr,lf-cstr); // new reference
- if(output)
- PyString_ConcatAndDel(&output,part); // str is decrefd
- else
- output = part; // take str reference
-
- // output concatenated string
- post(PyString_AS_STRING(output));
-
- Py_DECREF(output);
- output = PyString_FromString(lf+1); // new reference
- }
- }
-
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-
-class work_data
-{
-public:
- work_data(PyObject *f,PyObject *a): fun(f),args(a) {}
- ~work_data() { Py_DECREF(fun); Py_DECREF(args); }
-
- PyObject *fun,*args;
-};
-
-bool pybase::gencall(PyObject *pmeth,PyObject *pargs)
-{
- bool ret = false;
-
- // Now call method
- switch(detach) {
- case 0:
- ret = docall(pmeth,pargs);
- Py_DECREF(pargs);
- Py_DECREF(pmeth);
- break;
-#ifdef FLEXT_THREADS
- case 1:
- // put call into queue
- ret = qucall(pmeth,pargs);
- break;
- case 2:
- // each call a new thread
- if(!shouldexit) {
- thr_params *p = new thr_params;
- p->cl = (flext_base *)this;
- p->var->_ext = new work_data(pmeth,pargs);
- ret = LaunchThread(thrworker,p);
- if(!ret) post("py/pyext - Failed to launch thread!");
- }
- break;
-#endif
- default:
- post("py/pyext - Unknown detach mode");
- }
- return ret;
-}
-
-void pybase::exchandle()
-{
-#if 0
- // want to use that, but exception keeps a reference to the object
- // might be a Python bug!
- PyErr_Print();
-#else
- // must use that instead... clear the exception
- PyObject *type,*value,*traceback;
- PyErr_Fetch(&type,&value,&traceback);
- PyErr_NormalizeException(&type,&value,&traceback);
- PyErr_Display(type,value,traceback);
-
- Py_XDECREF(type);
- Py_XDECREF(value);
- Py_XDECREF(traceback);
-#endif
-}
-
-#ifdef FLEXT_THREADS
-void pybase::thrworker(thr_params *p)
-{
- FLEXT_ASSERT(p);
- pybase *th = (pybase *)p->cl;
- work_data *w = (work_data *)p->var->_ext;
-
- ++th->thrcount; // \todo this should be atomic
- PyThreadState *state = PyLock();
-
- // call worker
- th->docall(w->fun,w->args);
- delete w;
-
- PyUnlock(state);
- --th->thrcount; // \todo this should be atomic
-}
-
-void pybase::quworker(thr_params *)
-{
- FifoEl *el;
- PyThreadState *my = FindThreadState(),*state;
-
- for(;;) {
- while(el = qufifo.Get()) {
- ++el->th->thrcount; // \todo this should be atomic
- state = PyLock(my);
- el->th->docall(el->fun,el->args);
- Py_XDECREF(el->fun);
- Py_XDECREF(el->args);
- PyUnlock(state);
- --el->th->thrcount; // \todo this should be atomic
- qufifo.Free(el);
- }
- qucond.Wait();
- }
-
- // we never end
-#if 0
- state = PyLock(my);
- // unref remaining Python objects
- while(el = qufifo.Get()) {
- Py_XDECREF(el->fun);
- Py_XDECREF(el->args);
- qufifo.Free(el);
- }
- PyUnlock(state);
-#endif
-}
-
-void pybase::erasethreads()
-{
- PyFifo tmp;
- FifoEl *el;
- while(el = qufifo.Get()) {
- if(el->th == this) {
- Py_XDECREF(el->fun);
- Py_XDECREF(el->args);
- qufifo.Free(el);
- }
- else
- tmp.Put(el);
- }
- // Push back
- while(el = tmp.Get()) qufifo.Put(el);
-}
-#endif
-
-bool pybase::collect()
-{
- if(gcollect) {
- PyObject *ret = PyObject_CallObject(gcollect,NULL);
- if(ret) {
-#ifdef FLEXT_DEBUG
- int refs = PyInt_AsLong(ret);
- if(refs) post("py/pyext - Garbage collector reports %i unreachable objects",refs);
-#endif
- Py_DECREF(ret);
- return false;
- }
- }
- return true;
-}
+/*
+
+py/pyext - python external object for PD and MaxMSP
+
+Copyright (c)2002-2007 Thomas Grill (gr@grrrr.org)
+For information on usage and redistribution, and for a DISCLAIMER OF ALL
+WARRANTIES, see the file, "license.txt," in this distribution.
+
+*/
+
+#include "pybase.h"
+#include <map>
+
+#if FLEXT_OS == FLEXT_OS_WIN
+#include <windows.h>
+#elif FLEXT_OS == FLEXT_OS_MAC
+#include <ApplicationServices/ApplicationServices.h>
+#endif
+
+static PyMethodDef StdOut_Methods[] =
+{
+ { "write", pybase::StdOut_Write, 1 },
+ { NULL, NULL, }
+};
+
+static PyObject *gcollect = NULL;
+
+#ifdef FLEXT_THREADS
+
+class ThrCmp
+{
+public:
+ inline bool operator()(const flext::thrid_t &a,const flext::thrid_t &b) const
+ {
+ if(sizeof(a) == sizeof(size_t))
+ return *(size_t *)&a < *(size_t *)&b;
+ else
+ return memcmp(&a,&b,sizeof(a)) < 0;
+ }
+};
+
+
+int pybase::lockcount = 0;
+
+#ifndef PY_USE_GIL
+static PyInterpreterState *pymain = NULL;
+
+typedef std::map<flext::thrid_t,ThrState,ThrCmp> PyThrMap;
+
+static PyThrMap pythrmap;
+ThrState pybase::pythrsys = NULL;
+
+ThrState pybase::FindThreadState()
+{
+ flext::thrid_t id = flext::GetThreadId();
+ PyThrMap::iterator it = pythrmap.find(id);
+ if(it == pythrmap.end()) {
+ // Make new thread state
+ ThrState st = PyThreadState_New(pymain);
+ pythrmap[id] = st;
+ return st;
+ }
+ else
+ return it->second;
+}
+
+void pybase::FreeThreadState()
+{
+ flext::thrid_t id = flext::GetThreadId();
+ PyThrMap::iterator it = pythrmap.find(id);
+ if(it != pythrmap.end()) {
+ // clear out any cruft from thread state object
+ PyThreadState_Clear(it->second);
+ // delete my thread state object
+ PyThreadState_Delete(it->second);
+ // delete from map
+ pythrmap.erase(it);
+ }
+}
+#endif // PY_USE_GIL
+
+PyFifo pybase::qufifo;
+flext::ThrCond pybase::qucond;
+#endif
+
+
+PyObject *pybase::module_obj = NULL;
+PyObject *pybase::module_dict = NULL;
+
+PyObject *pybase::builtins_obj = NULL;
+PyObject *pybase::builtins_dict = NULL;
+
+const t_symbol *pybase::sym_fint = NULL;
+const t_symbol *pybase::sym_response = NULL;
+
+// -----------------------------------------------------------------------------------------------------------
+
+
+void initsymbol();
+void initsamplebuffer();
+void initbundle();
+
+void pybase::lib_setup()
+{
+ post("");
+ post("------------------------------------------------");
+ post("py/pyext %s - python script objects",PY__VERSION);
+ post("(C)2002-2007 Thomas Grill - http://grrrr.org/ext");
+ post("");
+ post("using Python %s",Py_GetVersion());
+
+#ifdef FLEXT_DEBUG
+ post("");
+ post("DEBUG version compiled on %s %s",__DATE__,__TIME__);
+#endif
+
+ // -------------------------------------------------------------
+
+ sym_response = flext::MakeSymbol("response");
+
+#if FLEXT_SYS == FLEXT_SYS_PD
+ sym_fint = sym_float;
+#else
+ sym_fint = sym_int;
+#endif
+
+ // -------------------------------------------------------------
+
+ Py_Initialize();
+
+#ifdef FLEXT_DEBUG
+ Py_DebugFlag = 1;
+// Py_VerboseFlag = 1;
+#else
+ Py_OptimizeFlag = 1;
+#endif
+
+#ifdef FLEXT_THREADS
+ // enable thread support and acquire the global thread lock
+ PyEval_InitThreads();
+
+#ifndef PY_USE_GIL
+ // get thread state
+ pythrsys = PyThreadState_Get();
+ // get main interpreter state
+ pymain = pythrsys->interp;
+
+ // add thread state of main thread to map
+ pythrmap[GetThreadId()] = pythrsys;
+#endif // PY_USE_GIL
+
+#endif
+
+ // sys.argv must be set to empty tuple
+ char *nothing = "";
+ PySys_SetArgv(0,&nothing);
+
+ // register/initialize pyext module only once!
+ module_obj = Py_InitModule(PYEXT_MODULE, func_tbl);
+ module_dict = PyModule_GetDict(module_obj); // borrowed reference
+
+ PyModule_AddStringConstant(module_obj,"__doc__",(char *)py_doc);
+
+ // redirect stdout
+ PyObject* py_out;
+ py_out = Py_InitModule("stdout", StdOut_Methods);
+ PySys_SetObject("stdout", py_out);
+ py_out = Py_InitModule("stderr", StdOut_Methods);
+ PySys_SetObject("stderr", py_out);
+
+ // get garbage collector function
+ PyObject *gcobj = PyImport_ImportModule("gc");
+ if(gcobj) {
+ gcollect = PyObject_GetAttrString(gcobj,"collect");
+ Py_DECREF(gcobj);
+ }
+
+ builtins_obj = PyImport_ImportModule("__builtin__");
+ builtins_dict = PyModule_GetDict(builtins_obj); // borrowed reference
+
+ // add symbol type
+ initsymbol();
+ PyModule_AddObject(module_obj,"Symbol",(PyObject *)&pySymbol_Type);
+
+ // pre-defined symbols
+ PyModule_AddObject(module_obj,"_s_",(PyObject *)pySymbol__);
+ PyModule_AddObject(module_obj,"_s_bang",(PyObject *)pySymbol_bang);
+ PyModule_AddObject(module_obj,"_s_list",(PyObject *)pySymbol_list);
+ PyModule_AddObject(module_obj,"_s_symbol",(PyObject *)pySymbol_symbol);
+ PyModule_AddObject(module_obj,"_s_float",(PyObject *)pySymbol_float);
+ PyModule_AddObject(module_obj,"_s_int",(PyObject *)pySymbol_int);
+
+ // add samplebuffer type
+ initsamplebuffer();
+ PyModule_AddObject(module_obj,"Buffer",(PyObject *)&pySamplebuffer_Type);
+
+ // add message bundle type
+ initbundle();
+ PyModule_AddObject(module_obj,"Bundle",(PyObject *)&pyBundle_Type);
+
+ // -------------------------------------------------------------
+
+ FLEXT_SETUP(pyobj);
+ FLEXT_SETUP(pymeth);
+ FLEXT_SETUP(pyext);
+#ifndef PY_NODSP
+ FLEXT_DSP_SETUP(pydsp);
+#endif
+
+#ifdef FLEXT_THREADS
+ // release global lock
+ PyEval_ReleaseLock();
+
+ // launch thread worker
+ LaunchThread(quworker,NULL);
+
+ // launch python worker
+ LaunchThread(pyworker,NULL);
+#endif
+
+ post("------------------------------------------------");
+ post("");
+}
+
+FLEXT_LIB_SETUP(py,pybase::lib_setup)
+
+
+// -----------------------------------------------------------------------------------------------------------
+
+
+pybase::pybase()
+ : module(NULL)
+ , dict(NULL)
+#ifdef FLEXT_THREADS
+ , thrcount(0)
+ , shouldexit(false),stoptick(0)
+#endif
+ , detach(0)
+ , pymsg(false)
+{
+ ThrState state = PyLock();
+ Py_INCREF(module_obj);
+ PyUnlock(state);
+}
+
+pybase::~pybase()
+{
+ ThrState state = PyLock();
+ Py_XDECREF(module_obj);
+ PyUnlock(state);
+}
+
+void pybase::Exit()
+{
+#ifdef FLEXT_THREADS
+ erasethreads();
+
+ shouldexit = true;
+ qucond.Signal();
+
+ if(thrcount) {
+ // Wait for a certain time
+ for(int i = 0; i < (PY_STOP_WAIT/PY_STOP_TICK) && thrcount; ++i)
+ Sleep(PY_STOP_TICK*0.001f);
+ if(thrcount) {
+ // Wait forever
+ post("py/pyext - Waiting for thread termination!");
+ while(thrcount) Sleep(PY_STOP_TICK*0.001f);
+ post("py/pyext - Okay, all threads have terminated");
+ }
+ }
+#endif
+}
+
+void pybase::GetDir(PyObject *obj,AtomList &lst)
+{
+ if(obj) {
+ ThrState state = PyLock();
+
+ PyObject *pvar = PyObject_Dir(obj);
+ if(!pvar)
+ PyErr_Print(); // no method found
+ else {
+ const t_symbol *sym = GetPyArgs(lst,pvar);
+ if(!sym)
+ post("py/pyext - Argument list could not be created");
+ else
+ FLEXT_ASSERT(sym == sym_list);
+ Py_DECREF(pvar);
+ }
+
+ PyUnlock(state);
+ }
+}
+
+void pybase::m__dir(PyObject *obj)
+{
+ AtomList lst;
+ GetDir(obj,lst);
+ // dump dir to attribute outlet
+ DumpOut(NULL,lst.Count(),lst.Atoms());
+}
+
+void pybase::m__doc(PyObject *obj)
+{
+ if(obj) {
+ ThrState state = PyLock();
+
+ PyObject *docf = PyDict_GetItemString(obj,"__doc__"); // borrowed!!!
+ if(docf && PyString_Check(docf)) {
+ post("");
+ const char *s = PyString_AS_STRING(docf);
+
+ // FIX: Python doc strings can easily be larger than 1k characters
+ // -> split into separate lines
+ for(;;) {
+ char buf[1024];
+ char *nl = strchr((char *)s,'\n'); // the cast is for Borland C++
+ if(!nl) {
+ // no more newline found
+ post(s);
+ break;
+ }
+ else {
+ // copy string before newline to temp buffer and post
+ unsigned int l = nl-s;
+ if(l >= sizeof(buf)) l = sizeof buf-1;
+ strncpy(buf,s,l); // copy all but newline
+ buf[l] = 0;
+ post(buf);
+ s = nl+1; // set after newline
+ }
+ }
+ }
+
+ PyUnlock(state);
+ }
+}
+
+void pybase::OpenEditor()
+{
+ if(!module) return;
+ const char *mname = PyModule_GetFilename(module);
+ if(!mname) {
+ PyErr_Clear();
+ return;
+ }
+
+ char fname[1024];
+ strcpy(fname,mname);
+
+ // replacing .pyc or .pyo for source file name
+ char *dt = strrchr(fname,'.');
+ if(dt && !strncmp(dt,".py",2)) strcpy(dt,".py");
+
+ // this should open the editor....
+#if FLEXT_OS == FLEXT_OS_WIN
+ int err = (int)ShellExecute(NULL,"edit",fname,NULL,NULL,SW_SHOW);
+ if(err == SE_ERR_NOASSOC) {
+ // no association found - try notepad
+ err = (int)ShellExecute(NULL,NULL,"notepad.exe",fname,NULL,SW_SHOW);
+ }
+ else if(err == ERROR_FILE_NOT_FOUND || err == SE_ERR_FNF)
+ post("py/pyext - File not %s found",fname);
+ else if(err <= 32)
+ post("py/pyext - Unknown error opening %s",fname);
+
+#elif FLEXT_OS == FLEXT_OS_MAC
+ FSRef ref;
+ OSStatus err = FSPathMakeRef((unsigned char *)fname,&ref,NULL);
+ if(err)
+ post("py/pyext - Error interpreting path %s",fname);
+ else {
+ FSRef editor;
+ err = LSGetApplicationForItem(&ref,kLSRolesEditor,&editor,NULL);
+ if(err) {
+ // Can't find associated application... try Textedit
+ err = FSPathMakeRef((unsigned char *)"/Applications/TextEdit.app",&editor,NULL);
+ if(err)
+ post("py/pyext - Can't find Textedit application");
+ }
+
+ if(!err) {
+ LSLaunchFSRefSpec lspec;
+ lspec.appRef = &editor;
+ lspec.numDocs = 1;
+ lspec.itemRefs = &ref;
+ lspec.passThruParams = NULL;
+ lspec.launchFlags = kLSLaunchDefaults;
+ lspec.asyncRefCon = NULL;
+ err = LSOpenFromRefSpec(&lspec,NULL);
+ if(err)
+ post("py/pyext - Couldn't launch editor");
+ }
+ }
+#else
+ // thanks to Tim Blechmann
+
+ char *editor = getenv("EDITOR");
+
+ if(!editor) { // || !strcmp(editor, "/usr/bin/nano") || !strcmp(editor, "/usr/bin/pico") || !strcmp(editor, "/usr/bin/vi")) {
+ // no environment variable or console text editor found ... use idle instead (should have come with Python)
+ editor = "idle";
+ }
+
+ pid_t child = fork();
+ if(!child) {
+ char cmd[80];
+ strcpy(cmd,editor);
+ strcat(cmd," ");
+ strcat(cmd,fname);
+ execl("/bin/sh", "sh", "-c", cmd, (char *) NULL);
+ }
+#endif
+}
+
+void pybase::SetArgs()
+{
+ // script arguments
+ int argc = args.Count();
+ const t_atom *argv = args.Atoms();
+ char **sargv = new char *[argc+1];
+ for(int i = 0; i <= argc; ++i) {
+ sargv[i] = new char[256];
+ if(!i)
+ strcpy(sargv[i],"py/pyext");
+ else
+ GetAString(argv[i-1],sargv[i],255);
+ }
+
+ // the arguments to the module are only recognized once! (at first use in a patcher)
+ PySys_SetArgv(argc+1,sargv);
+
+ for(int j = 0; j <= argc; ++j) delete[] sargv[j];
+ delete[] sargv;
+}
+
+static bool getmodulesub(const char *mod,char *dir,int len,char *ext)
+{
+#if FLEXT_SYS == FLEXT_SYS_PD
+ char *name;
+ int fd = open_via_path("",mod,ext,dir,&name,len,0);
+ if(fd > 0) {
+ FLEXT_ASSERT(name && *name);
+ close(fd);
+ }
+ else {
+ // look for mod/__init__.py
+ std::string tmp(mod);
+ int l = tmp.size();
+ tmp += "/__init__";
+ fd = open_via_path("",tmp.c_str(),ext,dir,&name,len,0);
+ if(fd > 0) {
+ FLEXT_ASSERT(name && *name);
+ close(fd);
+ // we must remove the module name from dir
+ char *t = dir+strlen(dir)-l;
+ FLEXT_ASSERT(!strcmp(mod,t) && t[-1] == '/');
+ t[-1] = 0;
+ }
+ else
+ name = NULL;
+ }
+
+ // if dir is current working directory... name points to dir
+ if(dir == name) strcpy(dir,".");
+ return name != NULL;
+#elif FLEXT_SYS == FLEXT_SYS_MAX
+ short path;
+ long type;
+ char smod[1024];
+ strcpy(smod,mod);
+ strcat(smod,ext);
+ bool ok = !locatefile_extended(smod,&path,&type,&type,0);
+ if(ok)
+ // convert pathname to unix style
+ path_topathname(path,NULL,smod);
+ else {
+ // do path/file.ext combinations work at all under Max?
+ strcpy(smod,mod);
+
+ short path;
+ type = 'fold';
+ ok = !locatefile_extended(smod,&path,&type,&type,1);
+ if(ok) {
+ // convert pathname to unix style (including trailing slash)
+ path_topathname(path,NULL,smod);
+ char *end = smod+strlen(smod);
+ strcpy(end,mod);
+ strcat(end,"/__init__");
+ strcat(end,ext);
+
+ // check if file is really existing: try to open it
+ FILE *f = fopen(smod,"r");
+ if(f) {
+ *end = 0; // clear module part ... we only need base path
+ fclose(f);
+ }
+ else
+ ok = false;
+ }
+ }
+
+ if(ok) {
+ // convert path into slash style needed for Python
+#if 0
+ // Max API function uses Volume:/Path notation
+ path_nameconform(smod,dir,PATH_STYLE_SLASH,PATH_TYPE_ABSOLUTE);
+#else
+#if FLEXT_OS == FLEXT_OS_WIN
+ char *colon = NULL;
+#else
+ char *colon = strchr(smod,':');
+#endif
+ if(colon) {
+ *colon = 0;
+ strcpy(dir,"/Volumes/");
+ strcat(dir,smod);
+ strcat(dir,colon+1);
+ }
+ else
+ strcpy(dir,smod);
+#endif
+ return true;
+ }
+ else
+ // not found
+ return false;
+#else
+#pragma message("Not implemented");
+ return false;
+#endif
+}
+
+static bool getmodulepath(const char *mod,char *dir,int len)
+{
+ return
+ getmodulesub(mod,dir,len,".py") ||
+ getmodulesub(mod,dir,len,".pyc") ||
+ getmodulesub(mod,dir,len,".pyo");
+}
+
+bool pybase::ImportModule(const char *name)
+{
+ if(name) {
+ if(modname == name) {
+ // module with the same name is already loaded
+ if(module) return true;
+ }
+ else
+ modname = name;
+ }
+ else
+ modname.clear();
+
+ UnimportModule();
+ return ReloadModule();
+}
+
+void pybase::UnimportModule()
+{
+ if(module) {
+ FLEXT_ASSERT(dict && module_obj && module_dict);
+
+ Py_DECREF(module);
+
+ // reference count to module is not 0 here, altough probably the last instance was unloaded
+ // Python retains one reference to the module all the time
+ // we don't care
+
+ module = NULL;
+ dict = NULL;
+ }
+}
+
+bool pybase::ReloadModule()
+{
+ SetArgs();
+ PyObject *newmod;
+
+ if(modname.length()) {
+
+ if(module)
+ newmod = PyImport_ReloadModule(module);
+ else {
+ // search in module path (TODO: check before if module is already present to avoid costly searching)
+ char dir[1024];
+ if(!getmodulepath(modname.c_str(),dir,sizeof(dir)))
+ PyErr_SetString(PyExc_ImportError,"Module not found in path");
+ else
+ AddToPath(dir);
+
+ // module could also be loaded ok, even if it's not in the path (e.g. for internal stuff)
+ newmod = PyImport_ImportModule((char *)modname.c_str());
+ }
+ }
+ else {
+ // if no module name given, take py module
+ newmod = module_obj;
+ Py_INCREF(newmod);
+ }
+
+ if(!newmod) {
+ // unload faulty module
+ UnimportModule();
+ return false;
+ }
+ else {
+ Py_XDECREF(module);
+ module = newmod;
+ dict = PyModule_GetDict(module); // borrowed
+ return true;
+ }
+}
+
+void pybase::AddToPath(const char *dir)
+{
+ if(dir && *dir) {
+ PyObject *pobj = PySys_GetObject("path");
+ if(pobj && PyList_Check(pobj)) {
+ PyObject *ps = PyString_FromString(dir);
+ if(!PySequence_Contains(pobj,ps))
+ PyList_Append(pobj,ps); // makes new reference
+ Py_DECREF(ps);
+ }
+ PySys_SetObject("path",pobj); // steals reference to pobj
+ }
+}
+
+void pybase::AddCurrentPath(flext_base *o)
+{
+ char dir[1024];
+
+ // add dir of current patch to path
+ o->GetCanvasDir(dir,sizeof(dir));
+ if(*dir) AddToPath(dir);
+
+ // add current dir to path
+#if FLEXT_SYS == FLEXT_SYS_PD
+ AddToPath(GetString(canvas_getcurrentdir()));
+#elif FLEXT_SYS == FLEXT_SYS_MAX
+ short path = path_getdefault();
+ path_topathname(path,NULL,dir);
+ AddToPath(dir);
+#endif
+}
+
+bool pybase::OutObject(flext_base *ext,int o,PyObject *obj)
+{
+ flext::AtomListStatic<16> lst;
+ const t_symbol *sym = pymsg?GetPyAtom(lst,obj):GetPyArgs(lst,obj);
+ if(sym) {
+ // call to outlet _outside_ the Mutex lock!
+ // otherwise (if not detached) deadlock will occur
+ ext->ToOutAnything(o,sym,lst.Count(),lst.Atoms());
+ return true;
+ }
+ else
+ return false;
+}
+
+void pybase::Reload()
+{
+ ThrState state = PyLock();
+
+ PyObject *reg = GetRegistry(REGNAME);
+
+ if(reg) {
+ PyObject *key;
+ int pos = 0;
+ while(PyDict_Next(reg,&pos,&key,NULL)) {
+ pybase *th = (pybase *)PyLong_AsLong(key);
+ FLEXT_ASSERT(th);
+ th->Unload();
+ }
+
+ UnloadModule();
+ }
+
+ bool ok = ReloadModule();
+
+ if(ok) {
+ LoadModule();
+
+ if(reg) {
+ SetRegistry(REGNAME,reg);
+
+ PyObject *key;
+ int pos = 0;
+ while(PyDict_Next(reg,&pos,&key,NULL)) {
+ pybase *th = (pybase *)PyLong_AsLong(key);
+ FLEXT_ASSERT(th);
+ th->Load();
+ }
+ }
+ else
+ Load();
+ }
+
+ Report();
+ PyUnlock(state);
+}
+
+static PyObject *output = NULL;
+
+// post to the console
+PyObject* pybase::StdOut_Write(PyObject* self, PyObject* args)
+{
+ // should always be a tuple
+ FLEXT_ASSERT(PyTuple_Check(args));
+
+ const int sz = PyTuple_GET_SIZE(args);
+
+ for(int i = 0; i < sz; ++i) {
+ PyObject *val = PyTuple_GET_ITEM(args,i); // borrowed reference
+ PyObject *str = PyObject_Str(val); // new reference
+ char *cstr = PyString_AS_STRING(str);
+ char *lf = strchr(cstr,'\n');
+
+ // line feed in string
+ if(!lf) {
+ // no -> just append
+ if(output)
+ PyString_ConcatAndDel(&output,str); // str is decrefd
+ else
+ output = str; // take str reference
+ }
+ else {
+ // yes -> append up to line feed, reset output buffer to string remainder
+ PyObject *part = PyString_FromStringAndSize(cstr,lf-cstr); // new reference
+ if(output)
+ PyString_ConcatAndDel(&output,part); // str is decrefd
+ else
+ output = part; // take str reference
+
+ // output concatenated string
+ post(PyString_AS_STRING(output));
+
+ Py_DECREF(output);
+ output = PyString_FromString(lf+1); // new reference
+ }
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+class work_data
+{
+public:
+ work_data(PyObject *f,PyObject *a): fun(f),args(a) {}
+ ~work_data() { Py_DECREF(fun); Py_DECREF(args); }
+
+ PyObject *fun,*args;
+};
+
+bool pybase::gencall(PyObject *pmeth,PyObject *pargs)
+{
+ bool ret = false;
+
+ // Now call method
+ switch(detach) {
+ case 0:
+ ret = docall(pmeth,pargs);
+ Py_DECREF(pargs);
+ Py_DECREF(pmeth);
+ break;
+#ifdef FLEXT_THREADS
+ case 1:
+ // put call into queue
+ ret = qucall(pmeth,pargs);
+ break;
+ case 2:
+ // each call a new thread
+ if(!shouldexit) {
+ thr_params *p = new thr_params;
+ p->cl = (flext_base *)this;
+ p->var->_ext = new work_data(pmeth,pargs);
+ ret = LaunchThread(thrworker,p);
+ if(!ret) post("py/pyext - Failed to launch thread!");
+ }
+ break;
+#endif
+ default:
+ post("py/pyext - Unknown detach mode");
+ }
+ return ret;
+}
+
+void pybase::exchandle()
+{
+#if 0
+ // want to use that, but exception keeps a reference to the object
+ // might be a Python bug!
+ PyErr_Print();
+#else
+ // must use that instead... clear the exception
+ PyObject *type,*value,*traceback;
+ PyErr_Fetch(&type,&value,&traceback);
+ PyErr_NormalizeException(&type,&value,&traceback);
+ PyErr_Display(type,value,traceback);
+
+ Py_XDECREF(type);
+ Py_XDECREF(value);
+ Py_XDECREF(traceback);
+#endif
+}
+
+#ifdef FLEXT_THREADS
+void pybase::thrworker(thr_params *p)
+{
+ FLEXT_ASSERT(p);
+ pybase *th = (pybase *)p->cl;
+ work_data *w = (work_data *)p->var->_ext;
+
+ ++th->thrcount; // \todo this should be atomic
+ ThrState state = PyLock();
+
+ // call worker
+ th->docall(w->fun,w->args);
+ delete w;
+
+ PyUnlock(state);
+ --th->thrcount; // \todo this should be atomic
+}
+
+/*! This thread function basically keeps alive the Python interpreter in the background
+ It's good for threads that have been started from scripted functions
+*/
+void pybase::pyworker(thr_params *)
+{
+ ThrState state = PyLock();
+
+ PyObject *timemod = PyImport_ImportModule("time");
+ PyObject *sleep = PyObject_GetAttrString(timemod,"sleep");
+ PyObject *args = PyTuple_New(1);
+ PyTuple_SET_ITEM(args,0,PyFloat_FromDouble(1000000));
+
+ for(;;) {
+ PyObject *res = PyObject_CallObject(sleep,args);
+ Py_DECREF(res);
+ }
+
+ PyUnlock(state);
+}
+
+void pybase::quworker(thr_params *)
+{
+ FifoEl *el;
+ ThrState my = FindThreadState(),state;
+
+ for(;;) {
+ while(el = qufifo.Get()) {
+ ++el->th->thrcount; // \todo this should be atomic
+ state = PyLock(my);
+ el->th->docall(el->fun,el->args);
+ Py_XDECREF(el->fun);
+ Py_XDECREF(el->args);
+ PyUnlock(state);
+ --el->th->thrcount; // \todo this should be atomic
+ qufifo.Free(el);
+ }
+ qucond.Wait();
+ }
+
+ // we never end
+#if 0
+ state = PyLock(my);
+ // unref remaining Python objects
+ while(el = qufifo.Get()) {
+ Py_XDECREF(el->fun);
+ Py_XDECREF(el->args);
+ qufifo.Free(el);
+ }
+ PyUnlock(state);
+#endif
+}
+
+void pybase::erasethreads()
+{
+ PyFifo tmp;
+ FifoEl *el;
+ while(el = qufifo.Get()) {
+ if(el->th == this) {
+ Py_XDECREF(el->fun);
+ Py_XDECREF(el->args);
+ qufifo.Free(el);
+ }
+ else
+ tmp.Put(el);
+ }
+ // Push back
+ while(el = tmp.Get()) qufifo.Put(el);
+}
+#endif
+
+bool pybase::collect()
+{
+ if(gcollect) {
+ PyObject *ret = PyObject_CallObject(gcollect,NULL);
+ if(ret) {
+#ifdef FLEXT_DEBUG
+ int refs = PyInt_AsLong(ret);
+ if(refs) post("py/pyext - Garbage collector reports %i unreachable objects",refs);
+#endif
+ Py_DECREF(ret);
+ return false;
+ }
+ }
+ return true;
+}
diff --git a/externals/grill/py/source/pybase.h b/externals/grill/py/source/pybase.h
index b5cc8220..61518a2a 100644
--- a/externals/grill/py/source/pybase.h
+++ b/externals/grill/py/source/pybase.h
@@ -1,228 +1,251 @@
-/*
-
-py/pyext - python script object for PD and MaxMSP
-
-Copyright (c)2002-2005 Thomas Grill (gr@grrrr.org)
-For information on usage and redistribution, and for a DISCLAIMER OF ALL
-WARRANTIES, see the file, "license.txt," in this distribution.
-
-*/
-
-#ifndef __PYBASE_H
-#define __PYBASE_H
-
-#include "main.h"
-#include "pysymbol.h"
-#include "pybuffer.h"
-#include "pybundle.h"
-
-class pybase
- : public flext
-{
-public:
- pybase();
- virtual ~pybase();
-
- void Exit();
-
- static PyObject *MakePyArgs(const t_symbol *s,int argc,const t_atom *argv,int inlet = -1);
- static PyObject *MakePyArg(const t_symbol *s,int argc,const t_atom *argv);
- static const t_symbol *GetPyArgs(AtomList &lst,PyObject *pValue,int offs = 0);
- static const t_symbol *GetPyAtom(AtomList &lst,PyObject *pValue);
-
- static void lib_setup();
-
-protected:
-
- virtual void DumpOut(const t_symbol *sym,int argc,const t_atom *argv) = 0;
-
- void m__dir(PyObject *obj);
- void m__doc(PyObject *obj);
-
- void m_dir() { m__dir(module); }
- void mg_dir(AtomList &lst) { m__dir(module); }
- void m_doc() { m__doc(dict); }
-
- std::string modname; // module name
- PyObject *module,*dict; // object module and associated dictionary
-
- static const char *py_doc;
-
- void GetDir(PyObject *obj,AtomList &lst);
-
- AtomList args;
-
- void AddCurrentPath(flext_base *o);
- void SetArgs();
-
- bool OutObject(flext_base *ext,int o,PyObject *obj);
-
- // reload module and all connected objects
- void Reload();
-
- bool ImportModule(const char *name);
- void UnimportModule();
- bool ReloadModule();
-
- // Get module registry
- PyObject *GetRegistry(const char *regname);
- // Set module registry
- void SetRegistry(const char *regname,PyObject *reg);
-
- // Register object
- void Register(PyObject *reg);
- // Unregister object
- void Unregister(PyObject *reg);
-
- virtual void LoadModule() = 0;
- virtual void UnloadModule() = 0;
-
- virtual void Load() = 0;
- virtual void Unload() = 0;
-
- void OpenEditor();
-
- void Respond(bool b)
- {
- if(respond) {
- t_atom a;
- SetBool(a,b);
- DumpOut(sym_response,1,&a);
- }
- }
-
- void Report() { while(PyErr_Occurred()) PyErr_Print(); }
-
- static bool IsAnything(const t_symbol *s) { return s && s != sym_float && s != sym_int && s != sym_symbol && s != sym_list && s != sym_pointer; }
- static bool IsAtom(const t_symbol *s) { return s == sym_float || s == sym_int || s == sym_symbol || s == sym_pointer; }
-
-// enum retval { nothing,atom,sequ };
-
- // --- module stuff -----
-
- static PyObject *module_obj,*module_dict;
- static PyObject *builtins_obj,*builtins_dict;
- static PyMethodDef func_tbl[];
-
- static PyObject *py__doc__(PyObject *,PyObject *args);
- static PyObject *py_send(PyObject *,PyObject *args);
-#ifdef FLEXT_THREADS
- static PyObject *py_priority(PyObject *,PyObject *args);
-#endif
-
- static PyObject *py_arraysupport(PyObject *,PyObject *args);
- static PyObject *py_samplerate(PyObject *,PyObject *args);
- static PyObject *py_blocksize(PyObject *,PyObject *args);
-
-#if FLEXT_SYS == FLEXT_SYS_PD
- static PyObject *py_getvalue(PyObject *,PyObject *args);
- static PyObject *py_setvalue(PyObject *,PyObject *args);
-#endif
-
- static PyObject *py_list(PyObject *,PyObject *args);
- static PyObject *py_tuple(PyObject *,PyObject *args);
-
- // ----thread stuff ------------
-
- virtual void m_stop(int argc,const t_atom *argv);
-
- bool respond;
-#ifdef FLEXT_THREADS
- int thrcount;
- bool shouldexit;
- int stoptick;
- Timer stoptmr;
-
- void tick(void *);
-#endif
-
- int detach;
- bool pymsg;
-
- bool gencall(PyObject *fun,PyObject *args);
-
- bool docall(PyObject *fun,PyObject *args)
- {
- callpy(fun,args);
- if(PyErr_Occurred()) {
- exchandle();
- return false;
- }
- else
- return true;
- }
-
- virtual void callpy(PyObject *fun,PyObject *args) = 0;
-
- void exchandle();
-
- static bool collect();
-
-protected:
-
-#ifdef FLEXT_THREADS
- static void thrworker(thr_params *data);
-
- bool qucall(PyObject *fun,PyObject *args)
- {
- FifoEl *el = qufifo.New();
- el->Set(this,fun,args);
- qufifo.Put(el);
- qucond.Signal();
- return true;
- }
-
- static void quworker(thr_params *);
- void erasethreads();
-
- static PyFifo qufifo;
- static ThrCond qucond;
- static PyThreadState *pythrsys;
-#endif
-
- static const t_symbol *sym_fint; // float or int symbol, depending on native number message type
- static const t_symbol *sym_response;
-
- static const t_symbol *getone(t_atom &at,PyObject *arg);
- static const t_symbol *getlist(t_atom *lst,PyObject *seq,int cnt,int offs = 0);
-
-public:
-
- static void AddToPath(const char *dir);
-
-#ifdef FLEXT_THREADS
- static PyThreadState *FindThreadState();
- static void FreeThreadState();
-
- // this is especially needed when one py/pyext object calls another one
- // we don't want the message to be queued, but otoh we have to avoid deadlock
- // (recursive calls can only happen in the system thread)
- static int lockcount;
-
- static PyThreadState *PyLock(PyThreadState *st = FindThreadState())
- {
- if(!IsSystemThread() || !lockcount++) PyEval_AcquireLock();
- return PyThreadState_Swap(st);
- }
-
- static PyThreadState *PyLockSys()
- {
- if(!lockcount++) PyEval_AcquireLock();
- return PyThreadState_Swap(pythrsys);
- }
-
- static void PyUnlock(PyThreadState *st)
- {
- PyThreadState *old = PyThreadState_Swap(st);
- if(old != pythrsys || !--lockcount) PyEval_ReleaseLock();
- }
-#else
- static PyThreadState *PyLock(PyThreadState * = NULL) { return NULL; }
- static PyThreadState *PyLockSys() { return NULL; }
- static void PyUnlock(PyThreadState *st) {}
-#endif
-
- static PyObject* StdOut_Write(PyObject* Self, PyObject* Args);
-};
-
-#endif
+/*
+
+py/pyext - python script object for PD and MaxMSP
+
+Copyright (c)2002-2007 Thomas Grill (gr@grrrr.org)
+For information on usage and redistribution, and for a DISCLAIMER OF ALL
+WARRANTIES, see the file, "license.txt," in this distribution.
+
+*/
+
+#ifndef __PYBASE_H
+#define __PYBASE_H
+
+#include "main.h"
+#include "pysymbol.h"
+#include "pybuffer.h"
+#include "pybundle.h"
+
+#ifdef PY_USE_GIL
+ typedef PyGILState_STATE ThrState;
+#else
+ typedef PyThreadState *ThrState;
+#endif
+
+class pybase
+ : public flext
+{
+public:
+ pybase();
+ virtual ~pybase();
+
+ void Exit();
+
+ static PyObject *MakePyArgs(const t_symbol *s,int argc,const t_atom *argv,int inlet = -1);
+ static PyObject *MakePyArg(const t_symbol *s,int argc,const t_atom *argv);
+ static const t_symbol *GetPyArgs(AtomList &lst,PyObject *pValue,int offs = 0);
+ static const t_symbol *GetPyAtom(AtomList &lst,PyObject *pValue);
+
+ static void lib_setup();
+
+protected:
+
+ virtual void DumpOut(const t_symbol *sym,int argc,const t_atom *argv) = 0;
+
+ void m__dir(PyObject *obj);
+ void m__doc(PyObject *obj);
+
+ void m_dir() { m__dir(module); }
+ void mg_dir(AtomList &lst) { m__dir(module); }
+ void m_doc() { m__doc(dict); }
+
+ std::string modname; // module name
+ PyObject *module,*dict; // object module and associated dictionary
+
+ static const char *py_doc;
+
+ void GetDir(PyObject *obj,AtomList &lst);
+
+ AtomList args;
+
+ void AddCurrentPath(flext_base *o);
+ void SetArgs();
+
+ bool OutObject(flext_base *ext,int o,PyObject *obj);
+
+ // reload module and all connected objects
+ void Reload();
+
+ bool ImportModule(const char *name);
+ void UnimportModule();
+ bool ReloadModule();
+
+ // Get module registry
+ PyObject *GetRegistry(const char *regname);
+ // Set module registry
+ void SetRegistry(const char *regname,PyObject *reg);
+
+ // Register object
+ void Register(PyObject *reg);
+ // Unregister object
+ void Unregister(PyObject *reg);
+
+ virtual void LoadModule() = 0;
+ virtual void UnloadModule() = 0;
+
+ virtual void Load() = 0;
+ virtual void Unload() = 0;
+
+ void OpenEditor();
+
+ void Respond(bool b)
+ {
+ if(respond) {
+ t_atom a;
+ SetBool(a,b);
+ DumpOut(sym_response,1,&a);
+ }
+ }
+
+ void Report() { while(PyErr_Occurred()) PyErr_Print(); }
+
+ static bool IsAnything(const t_symbol *s) { return s && s != sym_float && s != sym_int && s != sym_symbol && s != sym_list && s != sym_pointer; }
+ static bool IsAtom(const t_symbol *s) { return s == sym_float || s == sym_int || s == sym_symbol || s == sym_pointer; }
+
+// enum retval { nothing,atom,sequ };
+
+ // --- module stuff -----
+
+ static PyObject *module_obj,*module_dict;
+ static PyObject *builtins_obj,*builtins_dict;
+ static PyMethodDef func_tbl[];
+
+ static PyObject *py__doc__(PyObject *,PyObject *args);
+ static PyObject *py_send(PyObject *,PyObject *args);
+#ifdef FLEXT_THREADS
+ static PyObject *py_priority(PyObject *,PyObject *args);
+#endif
+
+ static PyObject *py_arraysupport(PyObject *,PyObject *args);
+ static PyObject *py_samplerate(PyObject *,PyObject *args);
+ static PyObject *py_blocksize(PyObject *,PyObject *args);
+
+#if FLEXT_SYS == FLEXT_SYS_PD
+ static PyObject *py_getvalue(PyObject *,PyObject *args);
+ static PyObject *py_setvalue(PyObject *,PyObject *args);
+#endif
+
+ static PyObject *py_list(PyObject *,PyObject *args);
+ static PyObject *py_tuple(PyObject *,PyObject *args);
+
+ // ----thread stuff ------------
+
+ virtual void m_stop(int argc,const t_atom *argv);
+
+ bool respond;
+#ifdef FLEXT_THREADS
+ int thrcount;
+ bool shouldexit;
+ int stoptick;
+ Timer stoptmr;
+
+ void tick(void *);
+#endif
+
+ int detach;
+ bool pymsg;
+
+ bool gencall(PyObject *fun,PyObject *args);
+
+ bool docall(PyObject *fun,PyObject *args)
+ {
+ callpy(fun,args);
+ if(PyErr_Occurred()) {
+ exchandle();
+ return false;
+ }
+ else
+ return true;
+ }
+
+ virtual void callpy(PyObject *fun,PyObject *args) = 0;
+
+ void exchandle();
+
+ static bool collect();
+
+protected:
+
+#ifdef FLEXT_THREADS
+ static void thrworker(thr_params *data);
+
+ bool qucall(PyObject *fun,PyObject *args)
+ {
+ FifoEl *el = qufifo.New();
+ el->Set(this,fun,args);
+ qufifo.Put(el);
+ qucond.Signal();
+ return true;
+ }
+
+ static void quworker(thr_params *);
+ static void pyworker(thr_params *);
+ void erasethreads();
+
+ static PyFifo qufifo;
+ static ThrCond qucond;
+
+#ifndef PY_USE_GIL
+ static ThrState pythrsys;
+#endif
+#endif
+
+ static const t_symbol *sym_fint; // float or int symbol, depending on native number message type
+ static const t_symbol *sym_response;
+
+ static const t_symbol *getone(t_atom &at,PyObject *arg);
+ static const t_symbol *getlist(t_atom *lst,PyObject *seq,int cnt,int offs = 0);
+
+public:
+
+ static void AddToPath(const char *dir);
+
+#ifdef FLEXT_THREADS
+ // this is especially needed when one py/pyext object calls another one
+ // we don't want the message to be queued, but otoh we have to avoid deadlock
+ // (recursive calls can only happen in the system thread)
+ static int lockcount;
+
+#ifdef PY_USE_GIL
+ static inline ThrState FindThreadState() { return ThrState(); }
+
+ static inline ThrState PyLock(ThrState = ThrState()) { return PyGILState_Ensure(); }
+ static inline ThrState PyLockSys() { return PyLock(); }
+ static inline void PyUnlock(ThrState st) { PyGILState_Release(st); }
+#else // PY_USE_GIL
+ static ThrState FindThreadState();
+ static void FreeThreadState();
+
+ static ThrState PyLock(ThrState st = FindThreadState())
+ {
+ if(!IsSystemThread() || !lockcount++) PyEval_AcquireLock();
+ return PyThreadState_Swap(st);
+ }
+
+#if 1
+ static inline ThrState PyLockSys() { return PyLock(); }
+#else
+ static ThrState PyLockSys()
+ {
+ if(!lockcount++) PyEval_AcquireLock();
+ return PyThreadState_Swap(pythrsys);
+ }
+#endif
+
+ static void PyUnlock(ThrState st)
+ {
+ ThrState old = PyThreadState_Swap(st);
+ if(old != pythrsys || !--lockcount) PyEval_ReleaseLock();
+ }
+#endif // PY_USE_GIL
+
+#else // FLEXT_THREADS
+ static inline ThrState PyLock(ThrState = NULL) { return NULL; }
+ static inline ThrState PyLockSys() { return NULL; }
+ static inline void PyUnlock(ThrState st) {}
+#endif
+
+ static PyObject* StdOut_Write(PyObject* Self, PyObject* Args);
+};
+
+#endif
diff --git a/externals/grill/py/source/pybundle.cpp b/externals/grill/py/source/pybundle.cpp
index 69f5d90c..ee2e16c0 100644
--- a/externals/grill/py/source/pybundle.cpp
+++ b/externals/grill/py/source/pybundle.cpp
@@ -1,232 +1,232 @@
-/*
-
-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 "pyprefix.h"
-#include "pybundle.h"
-#include "pyext.h"
-
-static PyObject *bundle_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-{
- pyBundle *self = (pyBundle *)pyBundle_Type.tp_alloc(&pyBundle_Type, 0);
- if(self) self->bundle = flext::MsgNew();
- return (PyObject *)self;
-}
-
-static int bundle_init(PyObject *self, PyObject *args, PyObject *kwds)
-{
- FLEXT_ASSERT(pyBundle_Check(self));
-
- int len = PySequence_Length(args);
- if(len) {
- PyErr_SetString(PyExc_TypeError,"no arguments expected");
- return -1;
- }
-
- return 0;
-}
-
-static void bundle_dealloc(PyObject *obj)
-{
- pyBundle *self = (pyBundle *)obj;
- if(self->bundle) flext::MsgFree(self->bundle);
- obj->ob_type->tp_free(obj);
-}
-
-static PyObject *bundle_send(PyObject *obj)
-{
- pyBundle *self = (pyBundle *)obj;
- if(self->bundle) {
- flext::ToOutMsg(self->bundle);
- self->bundle = NULL;
-
- Py_INCREF(obj);
- return obj;
- }
- else {
- PyErr_SetString(PyExc_RuntimeError,"already sent");
- return NULL;
- }
-}
-
-static PyObject *bundle_repr(PyObject *self)
-{
- FLEXT_ASSERT(pyBundle_Check(self));
- return (PyObject *)PyString_FromFormat("<Bundle %p>",pyBundle_AS_BUNDLE(self));
-}
-
-static PyObject *bundle_str(PyObject *self)
-{
- return bundle_repr(self);
-}
-
-static PyObject *bundle_richcompare(PyObject *a,PyObject *b,int cmp)
-{
- if(pyBundle_Check(a) && pyBundle_Check(b)) {
- const flext::MsgBundle *abnd = pyBundle_AS_BUNDLE(a);
- const flext::MsgBundle *bbnd = pyBundle_AS_BUNDLE(b);
- bool ret;
- switch(cmp) {
- case Py_LT: ret = abnd < bbnd; break;
- case Py_LE: ret = abnd <= bbnd; break;
- case Py_EQ: ret = abnd == bbnd; break;
- case Py_NE: ret = abnd != bbnd; break;
- case Py_GT: ret = abnd > bbnd; break;
- case Py_GE: ret = abnd >= bbnd; break;
- }
- return PyBool_FromLong(ret);
- }
+/*
+
+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 "pyprefix.h"
+#include "pybundle.h"
+#include "pyext.h"
+
+static PyObject *bundle_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ pyBundle *self = (pyBundle *)pyBundle_Type.tp_alloc(&pyBundle_Type, 0);
+ if(self) self->bundle = flext::MsgNew();
+ return (PyObject *)self;
+}
+
+static int bundle_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ FLEXT_ASSERT(pyBundle_Check(self));
+
+ int len = PySequence_Length(args);
+ if(len) {
+ PyErr_SetString(PyExc_TypeError,"no arguments expected");
+ return -1;
+ }
+
+ return 0;
+}
+
+static void bundle_dealloc(PyObject *obj)
+{
+ pyBundle *self = (pyBundle *)obj;
+ if(self->bundle) flext::MsgFree(self->bundle);
+ obj->ob_type->tp_free(obj);
+}
+
+static PyObject *bundle_send(PyObject *obj)
+{
+ pyBundle *self = (pyBundle *)obj;
+ if(self->bundle) {
+ flext::ToOutMsg(self->bundle);
+ self->bundle = NULL;
+
+ Py_INCREF(obj);
+ return obj;
+ }
+ else {
+ PyErr_SetString(PyExc_RuntimeError,"already sent");
+ return NULL;
+ }
+}
+
+static PyObject *bundle_repr(PyObject *self)
+{
+ FLEXT_ASSERT(pyBundle_Check(self));
+ return (PyObject *)PyString_FromFormat("<Bundle %p>",pyBundle_AS_BUNDLE(self));
+}
+
+static PyObject *bundle_str(PyObject *self)
+{
+ return bundle_repr(self);
+}
+
+static PyObject *bundle_richcompare(PyObject *a,PyObject *b,int cmp)
+{
+ if(pyBundle_Check(a) && pyBundle_Check(b)) {
+ const flext::MsgBundle *abnd = pyBundle_AS_BUNDLE(a);
+ const flext::MsgBundle *bbnd = pyBundle_AS_BUNDLE(b);
+ bool ret;
+ switch(cmp) {
+ case Py_LT: ret = abnd < bbnd; break;
+ case Py_LE: ret = abnd <= bbnd; break;
+ case Py_EQ: ret = abnd == bbnd; break;
+ case Py_NE: ret = abnd != bbnd; break;
+ case Py_GT: ret = abnd > bbnd; break;
+ case Py_GE: ret = abnd >= bbnd; break;
+ }
+ return PyBool_FromLong(ret);
+ }
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
-}
-
-static long bundle_hash(PyObject *self)
-{
- FLEXT_ASSERT(pyBundle_Check(self));
- return (long)pyBundle_AS_BUNDLE(self);
-}
-
-
-static PyObject *bundle_append(PyObject *self,PyObject *args)
-{
- flext::MsgBundle *b = pyBundle_AS_BUNDLE(self);
- if(b) {
- int sz = PyTuple_GET_SIZE(args),offs = 0;
- PyObject *tg,*outl;
- pyext *ext = NULL;
- const t_symbol *recv;
- int o;
-
- if(sz > 2 &&
- (tg = PyTuple_GET_ITEM(args,0)) != NULL && PyInstance_Check(tg) &&
- (outl = PyTuple_GET_ITEM(args,1)) != NULL && PyInt_Check(outl)
- ) {
- // Sending to outlet
- ext = pyext::GetThis(tg);
- o = PyInt_AS_LONG(outl);
-
- if(o < 1 || o > ext->Outlets()) {
- PyErr_SetString(PyExc_ValueError,"Outlet index out of range");
- return NULL;
- }
-
- offs += 2;
- }
- else if(sz > 1 &&
- (tg = PyTuple_GET_ITEM(args,0)) != NULL && (recv = pyObject_AsSymbol(tg)) != NULL
- ) {
- // Sending to receiver
- offs++;
- }
- else {
- // not recognized
- PyErr_SetString(PyExc_SyntaxError,"Unrecognized arguments");
- return NULL;
- }
-
- PyObject *val;
- if(sz-offs == 1) {
- val = PyTuple_GET_ITEM(args,offs); // borrow reference
- Py_INCREF(val);
- }
- else
- val = PyTuple_GetSlice(args,offs,sz); // new ref
-
- flext::AtomListStatic<16> lst;
- const t_symbol *sym = pybase::GetPyArgs(lst,val);
- Py_DECREF(val);
-
- if(sym) {
- if(ext) {
- FLEXT_ASSERT(outl);
- ext->MsgAddAnything(b,o-1,sym,lst.Count(),lst.Atoms());
- }
- else {
- FLEXT_ASSERT(sym);
- if(!flext::MsgForward(b,recv,sym,lst.Count(),lst.Atoms())) {
- PyErr_SetString(PyExc_ValueError,"Receiver not found");
- return NULL;
- }
- }
-
- Py_INCREF(Py_None);
- return Py_None;
- }
- else {
- FLEXT_ASSERT(PyErr_Occurred());
- return NULL;
- }
-
- Py_INCREF(self);
- return self;
- }
- else {
- PyErr_SetString(PyExc_RuntimeError,"Invalid bundle");
- return NULL;
- }
-}
-
-static PyMethodDef bundle_methods[] = {
- {"append", (PyCFunction)bundle_append,METH_VARARGS,"Append message to bundle"},
- {"send", (PyCFunction)bundle_send,METH_NOARGS,"Send bundle"},
- {NULL} /* Sentinel */
-};
-
-
-
-PyTypeObject pyBundle_Type = {
- PyObject_HEAD_INIT(NULL)
- 0, /*ob_size*/
- "Bundle", /*tp_name*/
- sizeof(pyBundle), /*tp_basicsize*/
- 0, /*tp_itemsize*/
- bundle_dealloc, /*tp_dealloc*/
- 0, /*tp_print*/
- 0, /*tp_getattr*/
- 0, /*tp_setattr*/
- 0, /*tp_compare*/
- bundle_repr, /*tp_repr*/
- 0, /*tp_as_number*/
- 0, /*tp_as_sequence*/
- 0, /*tp_as_mapping*/
- bundle_hash, /*tp_hash */
- 0, /*tp_call*/
- bundle_str, /*tp_str*/
- 0, /*tp_getattro*/
- 0, /*tp_setattro*/
- 0, /*tp_as_buffer*/
- Py_TPFLAGS_DEFAULT /*| Py_TPFLAGS_BASETYPE*/, /*tp_flags*/
- "Bundle objects", /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- bundle_richcompare, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- bundle_methods, /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- bundle_init, /* tp_init */
- 0, /* tp_alloc */
- bundle_new, /* tp_new */
-};
-
-
-void initbundle()
-{
- if(PyType_Ready(&pyBundle_Type) < 0)
- FLEXT_ASSERT(false);
- else
- Py_INCREF(&pyBundle_Type);
-}
+}
+
+static long bundle_hash(PyObject *self)
+{
+ FLEXT_ASSERT(pyBundle_Check(self));
+ return (long)pyBundle_AS_BUNDLE(self);
+}
+
+
+static PyObject *bundle_append(PyObject *self,PyObject *args)
+{
+ flext::MsgBundle *b = pyBundle_AS_BUNDLE(self);
+ if(b) {
+ int sz = PyTuple_GET_SIZE(args),offs = 0;
+ PyObject *tg,*outl;
+ pyext *ext = NULL;
+ const t_symbol *recv;
+ int o;
+
+ if(sz > 2 &&
+ (tg = PyTuple_GET_ITEM(args,0)) != NULL && PyInstance_Check(tg) &&
+ (outl = PyTuple_GET_ITEM(args,1)) != NULL && PyInt_Check(outl)
+ ) {
+ // Sending to outlet
+ ext = pyext::GetThis(tg);
+ o = PyInt_AS_LONG(outl);
+
+ if(o < 1 || o > ext->Outlets()) {
+ PyErr_SetString(PyExc_ValueError,"Outlet index out of range");
+ return NULL;
+ }
+
+ offs += 2;
+ }
+ else if(sz > 1 &&
+ (tg = PyTuple_GET_ITEM(args,0)) != NULL && (recv = pyObject_AsSymbol(tg)) != NULL
+ ) {
+ // Sending to receiver
+ offs++;
+ }
+ else {
+ // not recognized
+ PyErr_SetString(PyExc_SyntaxError,"Unrecognized arguments");
+ return NULL;
+ }
+
+ PyObject *val;
+ if(sz-offs == 1) {
+ val = PyTuple_GET_ITEM(args,offs); // borrow reference
+ Py_INCREF(val);
+ }
+ else
+ val = PyTuple_GetSlice(args,offs,sz); // new ref
+
+ flext::AtomListStatic<16> lst;
+ const t_symbol *sym = pybase::GetPyArgs(lst,val);
+ Py_DECREF(val);
+
+ if(sym) {
+ if(ext) {
+ FLEXT_ASSERT(outl);
+ ext->MsgAddAnything(b,o-1,sym,lst.Count(),lst.Atoms());
+ }
+ else {
+ FLEXT_ASSERT(sym);
+ if(!flext::MsgForward(b,recv,sym,lst.Count(),lst.Atoms())) {
+ PyErr_SetString(PyExc_ValueError,"Receiver not found");
+ return NULL;
+ }
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ else {
+ FLEXT_ASSERT(PyErr_Occurred());
+ return NULL;
+ }
+
+ Py_INCREF(self);
+ return self;
+ }
+ else {
+ PyErr_SetString(PyExc_RuntimeError,"Invalid bundle");
+ return NULL;
+ }
+}
+
+static PyMethodDef bundle_methods[] = {
+ {"append", (PyCFunction)bundle_append,METH_VARARGS,"Append message to bundle"},
+ {"send", (PyCFunction)bundle_send,METH_NOARGS,"Send bundle"},
+ {NULL} /* Sentinel */
+};
+
+
+
+PyTypeObject pyBundle_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "Bundle", /*tp_name*/
+ sizeof(pyBundle), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ bundle_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ bundle_repr, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ bundle_hash, /*tp_hash */
+ 0, /*tp_call*/
+ bundle_str, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT /*| Py_TPFLAGS_BASETYPE*/, /*tp_flags*/
+ "Bundle objects", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ bundle_richcompare, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ bundle_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ bundle_init, /* tp_init */
+ 0, /* tp_alloc */
+ bundle_new, /* tp_new */
+};
+
+
+void initbundle()
+{
+ if(PyType_Ready(&pyBundle_Type) < 0)
+ FLEXT_ASSERT(false);
+ else
+ Py_INCREF(&pyBundle_Type);
+}
diff --git a/externals/grill/py/source/pybundle.h b/externals/grill/py/source/pybundle.h
index 5978cc38..1e840eb5 100644
--- a/externals/grill/py/source/pybundle.h
+++ b/externals/grill/py/source/pybundle.h
@@ -1,16 +1,16 @@
-/*
-
-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.
-
-*/
-
-#ifndef __PYBUNDLE_H
-#define __PYBUNDLE_H
-
+/*
+
+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.
+
+*/
+
+#ifndef __PYBUNDLE_H
+#define __PYBUNDLE_H
+
#include <flext.h>
#if !defined(FLEXT_VERSION) || (FLEXT_VERSION < 500)
@@ -33,28 +33,28 @@ WARRANTIES, see the file, "license.txt," in this distribution.
#else
#define PY_EXPORT
#endif
-
-typedef struct {
- PyObject_HEAD
- /* Type-specific fields go here. */
- flext::MsgBundle *bundle;
-} pyBundle;
-
-PY_EXPORT extern PyTypeObject pyBundle_Type;
-
+
+typedef struct {
+ PyObject_HEAD
+ /* Type-specific fields go here. */
+ flext::MsgBundle *bundle;
+} pyBundle;
+
+PY_EXPORT extern PyTypeObject pyBundle_Type;
+
#define pyBundle_Check(op) PyObject_TypeCheck(op, &pyBundle_Type)
#define pyBundle_CheckExact(op) ((op)->ob_type == &pyBundle_Type)
-inline flext::MsgBundle *pyBundle_AS_BUNDLE(PyObject *op)
-{
- return ((pyBundle *)op)->bundle;
-}
-
-inline flext::MsgBundle *pyBundle_AsBundle(PyObject *op)
-{
- return pyBundle_Check(op)?pyBundle_AS_BUNDLE(op):NULL;
-}
-
+inline flext::MsgBundle *pyBundle_AS_BUNDLE(PyObject *op)
+{
+ return ((pyBundle *)op)->bundle;
+}
+
+inline flext::MsgBundle *pyBundle_AsBundle(PyObject *op)
+{
+ return pyBundle_Check(op)?pyBundle_AS_BUNDLE(op):NULL;
+}
-#endif
+
+#endif
diff --git a/externals/grill/py/source/pydsp.cpp b/externals/grill/py/source/pydsp.cpp
index a88a3956..07fa75af 100644
--- a/externals/grill/py/source/pydsp.cpp
+++ b/externals/grill/py/source/pydsp.cpp
@@ -1,190 +1,190 @@
-/*
-
-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.
-
-*/
-
-#ifndef PY_NODSP
-
-#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();
- 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)
- {
- dspfun = PyObject_GetAttrString(pyobj,"_dsp"); // get ref
- if(!dspfun)
- PyErr_Clear();
- else if(!PyMethod_Check(dspfun)) {
- Py_DECREF(dspfun);
- dspfun = NULL;
- }
- }
- return true;
-}
-
-void pydsp::DoExit()
-{
- if(dspfun) { Py_DECREF(dspfun); dspfun = NULL; }
- if(sigfun) { Py_DECREF(sigfun); sigfun = NULL; }
-
- FreeBuffers();
-}
-
-PyObject *arrayfrombuffer(PyObject *buf,int c,int n);
-
-void pydsp::NewBuffers()
-{
- int i,n = Blocksize();
- const int ins = CntInSig(),outs = CntOutSig();
- t_sample *const *insigs = InSig();
- t_sample *const *outsigs = OutSig();
-
- // inlet/outlet count can't change so we don't have to deallocate
- if(!buffers) {
- int cnt = ins+outs;
- buffers = new PyObject *[cnt];
- memset(buffers,0,cnt*sizeof(*buffers));
- }
-
- for(i = 0; i < ins; ++i) {
- Py_XDECREF(buffers[i]);
- PyObject *b = PyBuffer_FromReadWriteMemory(insigs[i],n*sizeof(t_sample));
- buffers[i] = arrayfrombuffer(b,1,n);
- Py_DECREF(b);
- }
- for(i = 0; i < outs; ++i) {
- 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] = arrayfrombuffer(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(pyobj && (CntInSig() || CntOutSig()))
- {
- PyThreadState *state = PyLockSys();
-
- NewBuffers();
-
- bool dodsp = true;
- if(dspfun) {
- PyObject *ret = PyObject_CallObject(dspfun,NULL);
- if(ret) {
- dodsp = PyObject_IsTrue(ret) != 0;
- Py_DECREF(ret);
- }
- else {
-#ifdef FLEXT_DEBUG
- PyErr_Print();
-#else
- PyErr_Clear();
-#endif
- }
- }
-
- // do that here instead of where dspfun is initialized, so that
- // _signal can be assigned in _dsp
- // optimizations may be done there to assign the right _signal version
- Py_XDECREF(sigfun);
-
- if(dodsp) {
- sigfun = PyObject_GetAttrString(pyobj,"_signal"); // get ref
- if(!sigfun)
- PyErr_Clear();
- else if(!PyMethod_Check(sigfun)) {
- Py_DECREF(sigfun);
- sigfun = NULL;
- }
- }
- else
- sigfun = NULL;
-
- PyUnlock(state);
- return sigfun != NULL;
- }
- else
- // switch on dsp only if there are signal inlets or outlets
- return false;
-}
-
-void pydsp::CbSignal()
-{
- PyThreadState *state = PyLockSys();
- PyObject *ret = PyObject_CallObject(sigfun,NULL);
-
- if(ret)
- Py_DECREF(ret);
- else {
-#ifdef FLEXT_DEBUG
- PyErr_Print();
-#else
- PyErr_Clear();
-#endif
- }
- PyUnlock(state);
-}
-
-PyObject *pydsp::GetSig(int ix,bool in)
-{
- PyObject *r = buffers[in?ix:CntInSig()+ix];
- Py_XINCREF(r);
- return r;
-}
-
-#endif
+/*
+
+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.
+
+*/
+
+#ifndef PY_NODSP
+
+#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();
+ 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)
+ {
+ dspfun = PyObject_GetAttrString(pyobj,"_dsp"); // get ref
+ if(!dspfun)
+ PyErr_Clear();
+ else if(!PyMethod_Check(dspfun)) {
+ Py_DECREF(dspfun);
+ dspfun = NULL;
+ }
+ }
+ return true;
+}
+
+void pydsp::DoExit()
+{
+ if(dspfun) { Py_DECREF(dspfun); dspfun = NULL; }
+ if(sigfun) { Py_DECREF(sigfun); sigfun = NULL; }
+
+ FreeBuffers();
+}
+
+PyObject *arrayfrombuffer(PyObject *buf,int c,int n);
+
+void pydsp::NewBuffers()
+{
+ int i,n = Blocksize();
+ const int ins = CntInSig(),outs = CntOutSig();
+ t_sample *const *insigs = InSig();
+ t_sample *const *outsigs = OutSig();
+
+ // inlet/outlet count can't change so we don't have to deallocate
+ if(!buffers) {
+ int cnt = ins+outs;
+ buffers = new PyObject *[cnt];
+ memset(buffers,0,cnt*sizeof(*buffers));
+ }
+
+ for(i = 0; i < ins; ++i) {
+ Py_XDECREF(buffers[i]);
+ PyObject *b = PyBuffer_FromReadWriteMemory(insigs[i],n*sizeof(t_sample));
+ buffers[i] = arrayfrombuffer(b,1,n);
+ Py_DECREF(b);
+ }
+ for(i = 0; i < outs; ++i) {
+ 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] = arrayfrombuffer(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(pyobj && (CntInSig() || CntOutSig()))
+ {
+ ThrState state = PyLockSys();
+
+ NewBuffers();
+
+ bool dodsp = true;
+ if(dspfun) {
+ PyObject *ret = PyObject_CallObject(dspfun,NULL);
+ if(ret) {
+ dodsp = PyObject_IsTrue(ret) != 0;
+ Py_DECREF(ret);
+ }
+ else {
+#ifdef FLEXT_DEBUG
+ PyErr_Print();
+#else
+ PyErr_Clear();
+#endif
+ }
+ }
+
+ // do that here instead of where dspfun is initialized, so that
+ // _signal can be assigned in _dsp
+ // optimizations may be done there to assign the right _signal version
+ Py_XDECREF(sigfun);
+
+ if(dodsp) {
+ sigfun = PyObject_GetAttrString(pyobj,"_signal"); // get ref
+ if(!sigfun)
+ PyErr_Clear();
+ else if(!PyMethod_Check(sigfun)) {
+ Py_DECREF(sigfun);
+ sigfun = NULL;
+ }
+ }
+ else
+ sigfun = NULL;
+
+ PyUnlock(state);
+ return sigfun != NULL;
+ }
+ else
+ // switch on dsp only if there are signal inlets or outlets
+ return false;
+}
+
+void pydsp::CbSignal()
+{
+ ThrState state = PyLockSys();
+ PyObject *ret = PyObject_CallObject(sigfun,NULL);
+
+ if(ret)
+ Py_DECREF(ret);
+ else {
+#ifdef FLEXT_DEBUG
+ PyErr_Print();
+#else
+ PyErr_Clear();
+#endif
+ }
+ PyUnlock(state);
+}
+
+PyObject *pydsp::GetSig(int ix,bool in)
+{
+ PyObject *r = buffers[in?ix:CntInSig()+ix];
+ Py_XINCREF(r);
+ return r;
+}
+
+#endif
diff --git a/externals/grill/py/source/pyext.cpp b/externals/grill/py/source/pyext.cpp
index 5c573bd2..31945277 100644
--- a/externals/grill/py/source/pyext.cpp
+++ b/externals/grill/py/source/pyext.cpp
@@ -117,8 +117,10 @@ pyext::pyext(int argc,const t_atom *argv,bool sig):
methname(NULL),
pyobj(NULL),
inlets(-1),outlets(-1),
- siginlets(0),sigoutlets(0),
- pythr(NULL)
+ siginlets(0),sigoutlets(0)
+#ifndef PY_USE_GIL
+ ,pythr(NULL)
+#endif
{
#ifdef FLEXT_THREADS
FLEXT_ADDTIMER(stoptmr,tick);
@@ -141,7 +143,7 @@ pyext::pyext(int argc,const t_atom *argv,bool sig):
// check if the object name is pyext. , pyx. or similar
bool dotted = strrchr(thisName(),'.') != NULL;
- PyThreadState *state = PyLockSys();
+ ThrState state = PyLockSys();
// init script module
if(argc) {
@@ -194,7 +196,7 @@ pyext::pyext(int argc,const t_atom *argv,bool sig):
bool pyext::Init()
{
- PyThreadState *state = PyLockSys();
+ ThrState state = PyLockSys();
if(methname) {
MakeInstance();
@@ -221,7 +223,7 @@ void pyext::Exit()
{
pybase::Exit(); // exit threads
- PyThreadState *state = PyLockSys();
+ ThrState state = PyLockSys();
DoExit();
Unregister(GetRegistry(REGNAME));
@@ -414,7 +416,7 @@ void pyext::Unload()
void pyext::m_get(const t_symbol *s)
{
- PyThreadState *state = PyLockSys();
+ ThrState state = PyLockSys();
PyObject *pvar = PyObject_GetAttrString(pyobj,const_cast<char *>(GetString(s))); /* fetch bound method */
if(pvar) {
@@ -437,7 +439,7 @@ void pyext::m_get(const t_symbol *s)
void pyext::m_set(int argc,const t_atom *argv)
{
- PyThreadState *state = PyLockSys();
+ ThrState state = PyLockSys();
if(argc < 2 || !IsString(argv[0]))
post("%s - Syntax: set varname arguments...",thisName());
@@ -542,7 +544,7 @@ bool pyext::work(int n,const t_symbol *s,int argc,const t_atom *argv)
{
bool ret = false;
- PyThreadState *state = PyLock();
+ ThrState state = PyLock();
// should be enough...
char str[256];
diff --git a/externals/grill/py/source/pyext.h b/externals/grill/py/source/pyext.h
index 4696c72c..da08aa53 100644
--- a/externals/grill/py/source/pyext.h
+++ b/externals/grill/py/source/pyext.h
@@ -114,7 +114,9 @@ private:
virtual void callpy(PyObject *fun,PyObject *args);
static bool stcallpy(PyObject *fun,PyObject *args);
- PyThreadState *pythr;
+#ifndef PY_USE_GIL
+ ThrState pythr;
+#endif
private:
static bool boundmeth(flext_base *,t_symbol *sym,int argc,t_atom *argv,void *data);
diff --git a/externals/grill/py/source/pymeth.cpp b/externals/grill/py/source/pymeth.cpp
index 3bc90ee2..ff0d6b83 100644
--- a/externals/grill/py/source/pymeth.cpp
+++ b/externals/grill/py/source/pymeth.cpp
@@ -1,428 +1,428 @@
-/*
-
-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 "pybase.h"
-#include <map>
-
-struct xlt { const t_symbol *from,*to; };
-
-static const xlt xtdefs[] = {
- { flext::MakeSymbol("+"),flext::MakeSymbol("__add__") },
- { flext::MakeSymbol("+="),flext::MakeSymbol("__iadd__") },
- { flext::MakeSymbol("!+"),flext::MakeSymbol("__radd__") },
- { flext::MakeSymbol("-"),flext::MakeSymbol("__sub__") },
- { flext::MakeSymbol("-="),flext::MakeSymbol("__isub__") },
- { flext::MakeSymbol("!-"),flext::MakeSymbol("__rsub__") },
- { flext::MakeSymbol("*"),flext::MakeSymbol("__mul__") },
- { flext::MakeSymbol("*="),flext::MakeSymbol("__imul__") },
- { flext::MakeSymbol("!*"),flext::MakeSymbol("__rmul__") },
- { flext::MakeSymbol("/"),flext::MakeSymbol("__div__") },
- { flext::MakeSymbol("/="),flext::MakeSymbol("__idiv__") },
- { flext::MakeSymbol("!/"),flext::MakeSymbol("__rdiv__") },
- { flext::MakeSymbol("//"),flext::MakeSymbol("__floordiv__") },
- { flext::MakeSymbol("//="),flext::MakeSymbol("__ifloordiv__") },
- { flext::MakeSymbol("!//"),flext::MakeSymbol("__rfloordiv__") },
- { flext::MakeSymbol("%"),flext::MakeSymbol("__mod__") },
- { flext::MakeSymbol("%="),flext::MakeSymbol("__imod__") },
- { flext::MakeSymbol("!%"),flext::MakeSymbol("__rmod__") },
- { flext::MakeSymbol("**"),flext::MakeSymbol("__pow__") },
- { flext::MakeSymbol("**="),flext::MakeSymbol("__ipow__") },
- { flext::MakeSymbol("!**"),flext::MakeSymbol("__rpow__") },
- { flext::MakeSymbol("&"),flext::MakeSymbol("__and__") },
- { flext::MakeSymbol("&="),flext::MakeSymbol("__iand__") },
- { flext::MakeSymbol("!&"),flext::MakeSymbol("__rand__") },
- { flext::MakeSymbol("|"),flext::MakeSymbol("__or__") },
- { flext::MakeSymbol("|="),flext::MakeSymbol("__ior__") },
- { flext::MakeSymbol("!|"),flext::MakeSymbol("__ror__") },
- { flext::MakeSymbol("^"),flext::MakeSymbol("__xor__") },
- { flext::MakeSymbol("^="),flext::MakeSymbol("__ixor__") },
- { flext::MakeSymbol("!^"),flext::MakeSymbol("__rxor__") },
- { flext::MakeSymbol("<<"),flext::MakeSymbol("__lshift__") },
- { flext::MakeSymbol("<<="),flext::MakeSymbol("__ilshift__") },
- { flext::MakeSymbol("!<<"),flext::MakeSymbol("__rlshift__") },
- { flext::MakeSymbol(">>"),flext::MakeSymbol("__rshift__") },
- { flext::MakeSymbol(">>="),flext::MakeSymbol("__irshift__") },
- { flext::MakeSymbol("!>>"),flext::MakeSymbol("__rrshift__") },
- { flext::MakeSymbol("=="),flext::MakeSymbol("__eq__") },
- { flext::MakeSymbol("!="),flext::MakeSymbol("__ne__") },
- { flext::MakeSymbol("<"),flext::MakeSymbol("__lt__") },
- { flext::MakeSymbol(">"),flext::MakeSymbol("__gt__") },
- { flext::MakeSymbol("<="),flext::MakeSymbol("__le__") },
- { flext::MakeSymbol(">="),flext::MakeSymbol("__ge__") },
- { flext::MakeSymbol("!"),flext::MakeSymbol("__nonzero__") },
- { flext::MakeSymbol("~"),flext::MakeSymbol("__invert__") },
- { flext::MakeSymbol("[]"),flext::MakeSymbol("__getitem__") },
- { flext::MakeSymbol("[]="),flext::MakeSymbol("__setitem__") },
- { flext::MakeSymbol("[:]"),flext::MakeSymbol("__getslice__") },
- { flext::MakeSymbol("[:]="),flext::MakeSymbol("__setslice__") },
-
- { flext::MakeSymbol(".abs"),flext::MakeSymbol("__abs__") },
- { flext::MakeSymbol(".neg"),flext::MakeSymbol("__neg__") },
- { flext::MakeSymbol(".pos"),flext::MakeSymbol("__pos__") },
- { flext::MakeSymbol(".divmod"),flext::MakeSymbol("__divmod__") },
-
- { flext::MakeSymbol(".int"),flext::MakeSymbol("__int__") },
- { flext::MakeSymbol(".long"),flext::MakeSymbol("__long__") },
- { flext::MakeSymbol(".float"),flext::MakeSymbol("__float__") },
- { flext::MakeSymbol(".complex"),flext::MakeSymbol("__complex__") },
- { flext::MakeSymbol(".str"),flext::MakeSymbol("__str__") },
- { flext::MakeSymbol(".coerce"),flext::MakeSymbol("__coerce__") },
-
- { flext::MakeSymbol(".doc"),flext::MakeSymbol("__doc__") },
- { flext::MakeSymbol(".repr"),flext::MakeSymbol("__repr__") },
-
- { flext::MakeSymbol(".len"),flext::MakeSymbol("__len__") },
- { flext::MakeSymbol(".in"),flext::MakeSymbol("__contains") },
-
- { NULL,NULL } // sentinel
-};
-
-typedef std::map<const t_symbol *,const t_symbol *> XTable;
-static XTable xtable;
-
-
-class pymeth
- : public pybase
- , public flext_base
-{
- FLEXT_HEADER_S(pymeth,flext_base,Setup)
-
-public:
- pymeth(int argc,const t_atom *argv);
- ~pymeth();
-
-protected:
- virtual void Exit();
-
- virtual bool CbMethodResort(int n,const t_symbol *s,int argc,const t_atom *argv);
-
- void m_help();
-
- void m_reload() { Reload(); }
- void m_reload_(int argc,const t_atom *argv) { args(argc,argv); Reload(); }
- void m_set(int argc,const t_atom *argv);
- void m_dir_() { m__dir(function); }
- void m_doc_() { m__doc(function); }
-
- const t_symbol *funname;
- PyObject *function;
-
- virtual void LoadModule();
- virtual void UnloadModule();
-
- virtual void Load();
- virtual void Unload();
-
- void SetFunction(const t_symbol *func);
- void ResetFunction();
-
- virtual void DumpOut(const t_symbol *sym,int argc,const t_atom *argv);
-
- PyObject **objects;
-
-private:
-
- virtual void callpy(PyObject *fun,PyObject *args);
-
- static void Setup(t_classid c);
-
- FLEXT_CALLBACK(m_help)
- FLEXT_CALLBACK(m_reload)
- FLEXT_CALLBACK_V(m_reload_)
- FLEXT_CALLBACK_V(m_set)
- FLEXT_CALLBACK(m_dir_)
- FLEXT_CALLBACK(m_doc_)
-
- // callbacks
- FLEXT_ATTRVAR_I(detach)
- FLEXT_ATTRVAR_B(pymsg)
- 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)
-#endif
-};
-
-FLEXT_LIB_V("pym",pymeth)
-
-
-void pymeth::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_);
- FLEXT_CADDMETHOD_(c,0,"dir+",m_dir_);
-
- FLEXT_CADDMETHOD_(c,0,"set",m_set);
-
- FLEXT_CADDATTR_VAR1(c,"py",pymsg);
- FLEXT_CADDATTR_VAR1(c,"respond",respond);
-
- // init translation map
- for(const xlt *xi = xtdefs; xi->from; ++xi) xtable[xi->from] = xi->to;
-}
-
-pymeth::pymeth(int argc,const t_atom *argv)
- : funname(NULL)
- , function(NULL)
- , objects(NULL)
-{
-#ifdef FLEXT_THREADS
- FLEXT_ADDTIMER(stoptmr,tick);
-#endif
-
- PyThreadState *state = PyLockSys();
-
- int inlets;
- if(argc && CanbeInt(*argv)) {
- inlets = GetAInt(*argv);
- if(inlets < 1) inlets = 1;
- argv++,argc--;
- }
- else inlets = 1;
-
- objects = new PyObject *[inlets];
- for(int i = 0; i < inlets; ++i) { objects[i] = Py_None; Py_INCREF(Py_None); }
-
- if(inlets <= 0) InitProblem();
-
- AddInAnything(1+(inlets < 0?1:inlets));
- AddOutAnything();
-
- Register(GetRegistry(REGNAME));
-
- if(argc) {
- const t_symbol *funnm = GetASymbol(*argv);
- argv++,argc--;
-
- if(funnm)
- SetFunction(funnm);
- else
- PyErr_SetString(PyExc_ValueError,"Invalid function name");
- }
-
- if(argc) args(argc,argv);
-
- Report();
-
- PyUnlock(state);
-}
-
-pymeth::~pymeth()
-{
- if(objects) {
- for(int i = 0; i < CntIn()-1; ++i) Py_DECREF(objects[i]);
- delete[] objects;
- }
-
- PyThreadState *state = PyLockSys();
- Unregister(GetRegistry(REGNAME));
- Report();
- PyUnlock(state);
-}
-
-void pymeth::Exit()
-{
- pybase::Exit();
- flext_base::Exit();
-}
-
-void pymeth::m_set(int argc,const t_atom *argv)
-{
- PyThreadState *state = PyLockSys();
-
- // function name has precedence
- if(argc >= 2) {
- const char *sn = GetAString(*argv);
- ++argv,--argc;
-
- if(sn) {
- if(!module || !strcmp(sn,PyModule_GetName(module))) {
- ImportModule(sn);
- Register(GetRegistry(REGNAME));
- }
- }
- else
- PyErr_SetString(PyExc_ValueError,"Invalid module name");
- }
-
- if(argc) {
- const t_symbol *fn = GetASymbol(*argv);
- if(fn)
- SetFunction(fn);
- else
- PyErr_SetString(PyExc_ValueError,"Invalid function name");
- }
-
- Report();
-
- PyUnlock(state);
-}
-
-void pymeth::m_help()
-{
- post("");
- post("%s %s - python method object, (C)2002-2005 Thomas Grill",thisName(),PY__VERSION);
-#ifdef FLEXT_DEBUG
- post("DEBUG VERSION, compiled on " __DATE__ " " __TIME__);
-#endif
-
- post("Arguments: %s [method name] {args...}",thisName());
-
- post("Inlet 1:messages to control the py object");
- post(" 2:call python function with message as argument(s)");
- post("Outlet: 1:return values from python function");
- post("Methods:");
- post("\thelp: shows this help");
- post("\tbang: call script without arguments");
- post("\tset [script name] [function name]: set (script and) function name");
- post("\treload {args...}: reload python script");
- post("\treload. : reload with former arguments");
- post("\tdoc: display module doc string");
- post("\tdoc+: display function doc string");
- post("\tdir: dump module dictionary");
- post("\tdir+: dump function dictionary");
-#ifdef FLEXT_THREADS
- post("\tdetach 0/1/2: detach threads");
- post("\tstop {wait time (ms)}: stop threads");
-#endif
- post("");
-}
-
-void pymeth::ResetFunction()
-{
- Py_XDECREF(function);
- function = NULL;
-
- if(funname && objects[0] != Py_None) {
- function = PyObject_GetAttrString(objects[0],(char *)GetString(funname)); // new reference
- if(!function)
- PyErr_SetString(PyExc_AttributeError,"Method not found");
- }
-
- // exception could be set here
-}
-
-void pymeth::SetFunction(const t_symbol *func)
-{
- // look for method name in translation table
- XTable::iterator it = xtable.find(func);
- funname = it == xtable.end()?func:it->second;
-
- ResetFunction();
-}
-
-
-void pymeth::LoadModule()
-{
- SetFunction(funname);
-}
-
-void pymeth::UnloadModule()
-{
-}
-
-void pymeth::Load()
-{
- ResetFunction();
-}
-
-void pymeth::Unload()
-{
- SetFunction(NULL);
-}
-
-void pymeth::callpy(PyObject *fun,PyObject *args)
-{
- PyObject *ret = PyObject_CallObject(fun,args);
- if(ret) {
- OutObject(this,0,ret); // exception might be raised here
- Py_DECREF(ret);
- }
-}
-
-bool pymeth::CbMethodResort(int n,const t_symbol *s,int argc,const t_atom *argv)
-{
- if(n == 0 && s != sym_bang)
- return flext_base::CbMethodResort(n,s,argc,argv);
-
- PyThreadState *state = PyLockSys();
-
- bool ret = false;
-
- if(n >= 1) {
- // store args
- PyObject *&obj = objects[n-1];
- Py_DECREF(obj);
- obj = MakePyArg(s,argc,argv); // steal reference
-
- if(n > 1) ret = true; // just store, don't trigger
- }
-
- if(!ret) {
- if(function) {
- PyObject *self = PyMethod_Self(function);
- PyErr_Clear();
- if(!self || self->ob_type != objects[0]->ob_type)
- // type has changed, search for new method
- ResetFunction();
- else if(self != objects[0]) {
- // type hasn't changed, but object has
- PyObject *f = function;
- function = PyMethod_New(PyMethod_GET_FUNCTION(f),objects[0],PyMethod_GET_CLASS(f));
- Py_DECREF(f);
- }
- }
- else
- ResetFunction();
-
- if(function) {
- Py_INCREF(function);
-
- int inlets = CntIn()-1;
- PyObject *pargs = PyTuple_New(inlets-1);
- for(int i = 1; i < inlets; ++i) {
- Py_INCREF(objects[i]);
- PyTuple_SET_ITEM(pargs,i-1,objects[i]);
- }
-
- gencall(function,pargs); // references are stolen
- ret = true;
- }
- else
- PyErr_SetString(PyExc_RuntimeError,"No function set");
-
- Report();
- }
-
- PyUnlock(state);
-
- Respond(ret);
-
- return ret;
-}
-
-void pymeth::DumpOut(const t_symbol *sym,int argc,const t_atom *argv)
-{
- ToOutAnything(GetOutAttr(),sym?sym:thisTag(),argc,argv);
-}
+/*
+
+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 "pybase.h"
+#include <map>
+
+struct xlt { const t_symbol *from,*to; };
+
+static const xlt xtdefs[] = {
+ { flext::MakeSymbol("+"),flext::MakeSymbol("__add__") },
+ { flext::MakeSymbol("+="),flext::MakeSymbol("__iadd__") },
+ { flext::MakeSymbol("!+"),flext::MakeSymbol("__radd__") },
+ { flext::MakeSymbol("-"),flext::MakeSymbol("__sub__") },
+ { flext::MakeSymbol("-="),flext::MakeSymbol("__isub__") },
+ { flext::MakeSymbol("!-"),flext::MakeSymbol("__rsub__") },
+ { flext::MakeSymbol("*"),flext::MakeSymbol("__mul__") },
+ { flext::MakeSymbol("*="),flext::MakeSymbol("__imul__") },
+ { flext::MakeSymbol("!*"),flext::MakeSymbol("__rmul__") },
+ { flext::MakeSymbol("/"),flext::MakeSymbol("__div__") },
+ { flext::MakeSymbol("/="),flext::MakeSymbol("__idiv__") },
+ { flext::MakeSymbol("!/"),flext::MakeSymbol("__rdiv__") },
+ { flext::MakeSymbol("//"),flext::MakeSymbol("__floordiv__") },
+ { flext::MakeSymbol("//="),flext::MakeSymbol("__ifloordiv__") },
+ { flext::MakeSymbol("!//"),flext::MakeSymbol("__rfloordiv__") },
+ { flext::MakeSymbol("%"),flext::MakeSymbol("__mod__") },
+ { flext::MakeSymbol("%="),flext::MakeSymbol("__imod__") },
+ { flext::MakeSymbol("!%"),flext::MakeSymbol("__rmod__") },
+ { flext::MakeSymbol("**"),flext::MakeSymbol("__pow__") },
+ { flext::MakeSymbol("**="),flext::MakeSymbol("__ipow__") },
+ { flext::MakeSymbol("!**"),flext::MakeSymbol("__rpow__") },
+ { flext::MakeSymbol("&"),flext::MakeSymbol("__and__") },
+ { flext::MakeSymbol("&="),flext::MakeSymbol("__iand__") },
+ { flext::MakeSymbol("!&"),flext::MakeSymbol("__rand__") },
+ { flext::MakeSymbol("|"),flext::MakeSymbol("__or__") },
+ { flext::MakeSymbol("|="),flext::MakeSymbol("__ior__") },
+ { flext::MakeSymbol("!|"),flext::MakeSymbol("__ror__") },
+ { flext::MakeSymbol("^"),flext::MakeSymbol("__xor__") },
+ { flext::MakeSymbol("^="),flext::MakeSymbol("__ixor__") },
+ { flext::MakeSymbol("!^"),flext::MakeSymbol("__rxor__") },
+ { flext::MakeSymbol("<<"),flext::MakeSymbol("__lshift__") },
+ { flext::MakeSymbol("<<="),flext::MakeSymbol("__ilshift__") },
+ { flext::MakeSymbol("!<<"),flext::MakeSymbol("__rlshift__") },
+ { flext::MakeSymbol(">>"),flext::MakeSymbol("__rshift__") },
+ { flext::MakeSymbol(">>="),flext::MakeSymbol("__irshift__") },
+ { flext::MakeSymbol("!>>"),flext::MakeSymbol("__rrshift__") },
+ { flext::MakeSymbol("=="),flext::MakeSymbol("__eq__") },
+ { flext::MakeSymbol("!="),flext::MakeSymbol("__ne__") },
+ { flext::MakeSymbol("<"),flext::MakeSymbol("__lt__") },
+ { flext::MakeSymbol(">"),flext::MakeSymbol("__gt__") },
+ { flext::MakeSymbol("<="),flext::MakeSymbol("__le__") },
+ { flext::MakeSymbol(">="),flext::MakeSymbol("__ge__") },
+ { flext::MakeSymbol("!"),flext::MakeSymbol("__nonzero__") },
+ { flext::MakeSymbol("~"),flext::MakeSymbol("__invert__") },
+ { flext::MakeSymbol("[]"),flext::MakeSymbol("__getitem__") },
+ { flext::MakeSymbol("[]="),flext::MakeSymbol("__setitem__") },
+ { flext::MakeSymbol("[:]"),flext::MakeSymbol("__getslice__") },
+ { flext::MakeSymbol("[:]="),flext::MakeSymbol("__setslice__") },
+
+ { flext::MakeSymbol(".abs"),flext::MakeSymbol("__abs__") },
+ { flext::MakeSymbol(".neg"),flext::MakeSymbol("__neg__") },
+ { flext::MakeSymbol(".pos"),flext::MakeSymbol("__pos__") },
+ { flext::MakeSymbol(".divmod"),flext::MakeSymbol("__divmod__") },
+
+ { flext::MakeSymbol(".int"),flext::MakeSymbol("__int__") },
+ { flext::MakeSymbol(".long"),flext::MakeSymbol("__long__") },
+ { flext::MakeSymbol(".float"),flext::MakeSymbol("__float__") },
+ { flext::MakeSymbol(".complex"),flext::MakeSymbol("__complex__") },
+ { flext::MakeSymbol(".str"),flext::MakeSymbol("__str__") },
+ { flext::MakeSymbol(".coerce"),flext::MakeSymbol("__coerce__") },
+
+ { flext::MakeSymbol(".doc"),flext::MakeSymbol("__doc__") },
+ { flext::MakeSymbol(".repr"),flext::MakeSymbol("__repr__") },
+
+ { flext::MakeSymbol(".len"),flext::MakeSymbol("__len__") },
+ { flext::MakeSymbol(".in"),flext::MakeSymbol("__contains") },
+
+ { NULL,NULL } // sentinel
+};
+
+typedef std::map<const t_symbol *,const t_symbol *> XTable;
+static XTable xtable;
+
+
+class pymeth
+ : public pybase
+ , public flext_base
+{
+ FLEXT_HEADER_S(pymeth,flext_base,Setup)
+
+public:
+ pymeth(int argc,const t_atom *argv);
+ ~pymeth();
+
+protected:
+ virtual void Exit();
+
+ virtual bool CbMethodResort(int n,const t_symbol *s,int argc,const t_atom *argv);
+
+ void m_help();
+
+ void m_reload() { Reload(); }
+ void m_reload_(int argc,const t_atom *argv) { args(argc,argv); Reload(); }
+ void m_set(int argc,const t_atom *argv);
+ void m_dir_() { m__dir(function); }
+ void m_doc_() { m__doc(function); }
+
+ const t_symbol *funname;
+ PyObject *function;
+
+ virtual void LoadModule();
+ virtual void UnloadModule();
+
+ virtual void Load();
+ virtual void Unload();
+
+ void SetFunction(const t_symbol *func);
+ void ResetFunction();
+
+ virtual void DumpOut(const t_symbol *sym,int argc,const t_atom *argv);
+
+ PyObject **objects;
+
+private:
+
+ virtual void callpy(PyObject *fun,PyObject *args);
+
+ static void Setup(t_classid c);
+
+ FLEXT_CALLBACK(m_help)
+ FLEXT_CALLBACK(m_reload)
+ FLEXT_CALLBACK_V(m_reload_)
+ FLEXT_CALLBACK_V(m_set)
+ FLEXT_CALLBACK(m_dir_)
+ FLEXT_CALLBACK(m_doc_)
+
+ // callbacks
+ FLEXT_ATTRVAR_I(detach)
+ FLEXT_ATTRVAR_B(pymsg)
+ 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)
+#endif
+};
+
+FLEXT_LIB_V("pym",pymeth)
+
+
+void pymeth::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_);
+ FLEXT_CADDMETHOD_(c,0,"dir+",m_dir_);
+
+ FLEXT_CADDMETHOD_(c,0,"set",m_set);
+
+ FLEXT_CADDATTR_VAR1(c,"py",pymsg);
+ FLEXT_CADDATTR_VAR1(c,"respond",respond);
+
+ // init translation map
+ for(const xlt *xi = xtdefs; xi->from; ++xi) xtable[xi->from] = xi->to;
+}
+
+pymeth::pymeth(int argc,const t_atom *argv)
+ : funname(NULL)
+ , function(NULL)
+ , objects(NULL)
+{
+#ifdef FLEXT_THREADS
+ FLEXT_ADDTIMER(stoptmr,tick);
+#endif
+
+ ThrState state = PyLockSys();
+
+ int inlets;
+ if(argc && CanbeInt(*argv)) {
+ inlets = GetAInt(*argv);
+ if(inlets < 1) inlets = 1;
+ argv++,argc--;
+ }
+ else inlets = 1;
+
+ objects = new PyObject *[inlets];
+ for(int i = 0; i < inlets; ++i) { objects[i] = Py_None; Py_INCREF(Py_None); }
+
+ if(inlets <= 0) InitProblem();
+
+ AddInAnything(1+(inlets < 0?1:inlets));
+ AddOutAnything();
+
+ Register(GetRegistry(REGNAME));
+
+ if(argc) {
+ const t_symbol *funnm = GetASymbol(*argv);
+ argv++,argc--;
+
+ if(funnm)
+ SetFunction(funnm);
+ else
+ PyErr_SetString(PyExc_ValueError,"Invalid function name");
+ }
+
+ if(argc) args(argc,argv);
+
+ Report();
+
+ PyUnlock(state);
+}
+
+pymeth::~pymeth()
+{
+ if(objects) {
+ for(int i = 0; i < CntIn()-1; ++i) Py_DECREF(objects[i]);
+ delete[] objects;
+ }
+
+ ThrState state = PyLockSys();
+ Unregister(GetRegistry(REGNAME));
+ Report();
+ PyUnlock(state);
+}
+
+void pymeth::Exit()
+{
+ pybase::Exit();
+ flext_base::Exit();
+}
+
+void pymeth::m_set(int argc,const t_atom *argv)
+{
+ ThrState state = PyLockSys();
+
+ // function name has precedence
+ if(argc >= 2) {
+ const char *sn = GetAString(*argv);
+ ++argv,--argc;
+
+ if(sn) {
+ if(!module || !strcmp(sn,PyModule_GetName(module))) {
+ ImportModule(sn);
+ Register(GetRegistry(REGNAME));
+ }
+ }
+ else
+ PyErr_SetString(PyExc_ValueError,"Invalid module name");
+ }
+
+ if(argc) {
+ const t_symbol *fn = GetASymbol(*argv);
+ if(fn)
+ SetFunction(fn);
+ else
+ PyErr_SetString(PyExc_ValueError,"Invalid function name");
+ }
+
+ Report();
+
+ PyUnlock(state);
+}
+
+void pymeth::m_help()
+{
+ post("");
+ post("%s %s - python method object, (C)2002-2005 Thomas Grill",thisName(),PY__VERSION);
+#ifdef FLEXT_DEBUG
+ post("DEBUG VERSION, compiled on " __DATE__ " " __TIME__);
+#endif
+
+ post("Arguments: %s [method name] {args...}",thisName());
+
+ post("Inlet 1:messages to control the py object");
+ post(" 2:call python function with message as argument(s)");
+ post("Outlet: 1:return values from python function");
+ post("Methods:");
+ post("\thelp: shows this help");
+ post("\tbang: call script without arguments");
+ post("\tset [script name] [function name]: set (script and) function name");
+ post("\treload {args...}: reload python script");
+ post("\treload. : reload with former arguments");
+ post("\tdoc: display module doc string");
+ post("\tdoc+: display function doc string");
+ post("\tdir: dump module dictionary");
+ post("\tdir+: dump function dictionary");
+#ifdef FLEXT_THREADS
+ post("\tdetach 0/1/2: detach threads");
+ post("\tstop {wait time (ms)}: stop threads");
+#endif
+ post("");
+}
+
+void pymeth::ResetFunction()
+{
+ Py_XDECREF(function);
+ function = NULL;
+
+ if(funname && objects[0] != Py_None) {
+ function = PyObject_GetAttrString(objects[0],(char *)GetString(funname)); // new reference
+ if(!function)
+ PyErr_SetString(PyExc_AttributeError,"Method not found");
+ }
+
+ // exception could be set here
+}
+
+void pymeth::SetFunction(const t_symbol *func)
+{
+ // look for method name in translation table
+ XTable::iterator it = xtable.find(func);
+ funname = it == xtable.end()?func:it->second;
+
+ ResetFunction();
+}
+
+
+void pymeth::LoadModule()
+{
+ SetFunction(funname);
+}
+
+void pymeth::UnloadModule()
+{
+}
+
+void pymeth::Load()
+{
+ ResetFunction();
+}
+
+void pymeth::Unload()
+{
+ SetFunction(NULL);
+}
+
+void pymeth::callpy(PyObject *fun,PyObject *args)
+{
+ PyObject *ret = PyObject_CallObject(fun,args);
+ if(ret) {
+ OutObject(this,0,ret); // exception might be raised here
+ Py_DECREF(ret);
+ }
+}
+
+bool pymeth::CbMethodResort(int n,const t_symbol *s,int argc,const t_atom *argv)
+{
+ if(n == 0 && s != sym_bang)
+ return flext_base::CbMethodResort(n,s,argc,argv);
+
+ ThrState state = PyLockSys();
+
+ bool ret = false;
+
+ if(n >= 1) {
+ // store args
+ PyObject *&obj = objects[n-1];
+ Py_DECREF(obj);
+ obj = MakePyArg(s,argc,argv); // steal reference
+
+ if(n > 1) ret = true; // just store, don't trigger
+ }
+
+ if(!ret) {
+ if(function) {
+ PyObject *self = PyMethod_Self(function);
+ PyErr_Clear();
+ if(!self || self->ob_type != objects[0]->ob_type)
+ // type has changed, search for new method
+ ResetFunction();
+ else if(self != objects[0]) {
+ // type hasn't changed, but object has
+ PyObject *f = function;
+ function = PyMethod_New(PyMethod_GET_FUNCTION(f),objects[0],PyMethod_GET_CLASS(f));
+ Py_DECREF(f);
+ }
+ }
+ else
+ ResetFunction();
+
+ if(function) {
+ Py_INCREF(function);
+
+ int inlets = CntIn()-1;
+ PyObject *pargs = PyTuple_New(inlets-1);
+ for(int i = 1; i < inlets; ++i) {
+ Py_INCREF(objects[i]);
+ PyTuple_SET_ITEM(pargs,i-1,objects[i]);
+ }
+
+ gencall(function,pargs); // references are stolen
+ ret = true;
+ }
+ else
+ PyErr_SetString(PyExc_RuntimeError,"No function set");
+
+ Report();
+ }
+
+ PyUnlock(state);
+
+ Respond(ret);
+
+ return ret;
+}
+
+void pymeth::DumpOut(const t_symbol *sym,int argc,const t_atom *argv)
+{
+ ToOutAnything(GetOutAttr(),sym?sym:thisTag(),argc,argv);
+}
diff --git a/externals/grill/py/source/pyprefix.h b/externals/grill/py/source/pyprefix.h
index de74ca42..9be12e85 100644
--- a/externals/grill/py/source/pyprefix.h
+++ b/externals/grill/py/source/pyprefix.h
@@ -1,43 +1,43 @@
-/*
-
-py/pyext - python script object for PD and MaxMSP
-
-Copyright (c)2002-2005 Thomas Grill (gr@grrrr.org)
-For information on usage and redistribution, and for a DISCLAIMER OF ALL
-WARRANTIES, see the file, "license.txt," in this distribution.
-
-*/
-
-#ifndef __PYPREFIX_H
-#define __PYPREFIX_H
-
-#define FLEXT_ATTRIBUTES 1
-#include <flext.h>
-
-// hack: must include math.h before Python.h (at least on OSX)
-// otherwise some functions don't get defined
-#include <math.h>
-
-#if FLEXT_OS == FLEXT_OS_MAC
-#include <Python/Python.h>
-#else
-#include <Python.h>
-#endif
-
-#if !defined(FLEXT_VERSION) || (FLEXT_VERSION < 501)
-#error You need at least flext version 0.5.1
-#endif
-
-#if FLEXT_OS == FLEXT_LINUX || FLEXT_OS == FLEXT_IRIX
-#include <unistd.h>
-#endif
-
-#if FLEXT_SYS == FLEXT_SYS_PD && (!defined (PD_MINOR_VERSION) || PD_MINOR_VERSION < 37)
-#error PD version >= 0.37 required, please upgrade!
-#endif
-
-#include <flcontainers.h>
-#include <string>
-
-
-#endif
+/*
+
+py/pyext - python script object for PD and MaxMSP
+
+Copyright (c)2002-2005 Thomas Grill (gr@grrrr.org)
+For information on usage and redistribution, and for a DISCLAIMER OF ALL
+WARRANTIES, see the file, "license.txt," in this distribution.
+
+*/
+
+#ifndef __PYPREFIX_H
+#define __PYPREFIX_H
+
+#define FLEXT_ATTRIBUTES 1
+#include <flext.h>
+
+// hack: must include math.h before Python.h (at least on OSX)
+// otherwise some functions don't get defined
+#include <math.h>
+
+#if FLEXT_OS == FLEXT_OS_MAC
+#include <Python/Python.h>
+#else
+#include <Python.h>
+#endif
+
+#if !defined(FLEXT_VERSION) || (FLEXT_VERSION < 501)
+#error You need at least flext version 0.5.1
+#endif
+
+#if FLEXT_OS == FLEXT_LINUX || FLEXT_OS == FLEXT_IRIX
+#include <unistd.h>
+#endif
+
+#if FLEXT_SYS == FLEXT_SYS_PD && (!defined (PD_MINOR_VERSION) || PD_MINOR_VERSION < 37)
+#error PD version >= 0.37 required, please upgrade!
+#endif
+
+#include <flcontainers.h>
+#include <string>
+
+
+#endif
diff --git a/externals/grill/py/source/pysymbol.cpp b/externals/grill/py/source/pysymbol.cpp
index 2f023469..f907cc45 100644
--- a/externals/grill/py/source/pysymbol.cpp
+++ b/externals/grill/py/source/pysymbol.cpp
@@ -1,254 +1,254 @@
-/*
-
-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 "pyprefix.h"
-#include "pysymbol.h"
-
-inline pySymbol *symbol_newsym(const t_symbol *sym)
-{
- pySymbol *self = (pySymbol *)pySymbol_Type.tp_alloc(&pySymbol_Type, 0);
- if(self) self->sym = sym;
- return self;
-}
-
-static PyObject *symbol_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-{
- return (PyObject *)symbol_newsym(flext::sym__);
-}
-
-static int symbol_init(PyObject *self, PyObject *args, PyObject *kwds)
-{
- FLEXT_ASSERT(pySymbol_Check(self));
-
- PyObject *arg = PySequence_GetItem(args,0); // new reference
- if(!arg) return -1;
-
- int ret = 0;
-
- if(pySymbol_Check(arg))
- ((pySymbol *)self)->sym = pySymbol_AS_SYMBOL(arg);
- else if(PyString_Check(arg))
- ((pySymbol *)self)->sym = flext::MakeSymbol(PyString_AS_STRING(arg));
- else {
- PyErr_SetString(PyExc_TypeError,"string or symbol argument expected");
- ret = -1;
- }
- Py_DECREF(arg);
-
- return ret;
-}
-
-static PyObject *symbol_str(PyObject *self)
-{
- FLEXT_ASSERT(pySymbol_Check(self));
- return (PyObject *)PyString_FromString(pySymbol_AS_STRING(self));
-}
-
-static PyObject *symbol_repr(PyObject *self)
-{
- FLEXT_ASSERT(pySymbol_Check(self));
- return (PyObject *)PyString_FromFormat("<Symbol %s>",pySymbol_AS_STRING(self));
-}
-
-static PyObject *symbol_richcompare(PyObject *a,PyObject *b,int cmp)
-{
- if(pySymbol_Check(a) && pySymbol_Check(b)) {
- const t_symbol *asym = pySymbol_AS_SYMBOL(a);
- const t_symbol *bsym = pySymbol_AS_SYMBOL(b);
- bool ret;
- switch(cmp) {
- case Py_LT: ret = asym < bsym; break;
- case Py_LE: ret = asym <= bsym; break;
- case Py_EQ: ret = asym == bsym; break;
- case Py_NE: ret = asym != bsym; break;
- case Py_GT: ret = asym > bsym; break;
- case Py_GE: ret = asym >= bsym; break;
- }
- return PyBool_FromLong(ret);
- }
- Py_INCREF(Py_NotImplemented);
- return Py_NotImplemented;
-}
-
-static long symbol_hash(PyObject *self)
-{
- FLEXT_ASSERT(pySymbol_Check(self));
- return (long)pySymbol_AS_SYMBOL(self);
-}
-
-
-static int symbol_length(pySymbol *self)
-{
- return strlen(flext::GetString(self->sym));
-}
-
-static PyObject *symbol_item(pySymbol *self, int i)
-{
- const char *str = flext::GetString(self->sym);
- int len = strlen(str);
- if(i < 0) i += len;
-
- if(i >= 0 && i < len)
- return PyString_FromStringAndSize(str+i,1);
- else {
- Py_INCREF(Py_None);
- return Py_None;
- }
-}
-
-static PyObject *symbol_slice(pySymbol *self,int ilow = 0,int ihigh = 1<<(sizeof(int)*8-2))
-{
- const char *str = flext::GetString(self->sym);
- int len = strlen(str);
- if(ilow < 0) {
- ilow += len;
- if(ilow < 0) ilow = 0;
- }
- if(ihigh < 0) ihigh += len;
- if(ihigh >= len) ihigh = len-1;
-
- return PyString_FromStringAndSize(str+ilow,ilow <= ihigh?ihigh-ilow+1:0);
-}
-
-static PyObject *symbol_concat(pySymbol *self,PyObject *op)
-{
- PyObject *nobj = symbol_slice(self); // take all
- if(nobj) {
- PyObject *ret = PySequence_Concat(nobj,op);
- Py_DECREF(nobj);
- return ret;
- }
- else
- return NULL;
-}
-
-static PyObject *symbol_repeat(pySymbol *self,int rep)
-{
- PyObject *nobj = symbol_slice(self); // take all
- if(nobj) {
- PyObject *ret = PySequence_Repeat(nobj,rep);
- Py_DECREF(nobj);
- return ret;
- }
- else
- return NULL;
-}
-
-static PySequenceMethods symbol_as_seq = {
- (inquiry)symbol_length, /* inquiry sq_length; __len__ */
- (binaryfunc)symbol_concat, /* __add__ */
- (intargfunc)symbol_repeat, /* __mul__ */
- (intargfunc)symbol_item, /* intargfunc sq_item; __getitem__ */
- (intintargfunc)symbol_slice, /* intintargfunc sq_slice; __getslice__ */
- NULL, /* intobjargproc sq_ass_item; __setitem__ */
- NULL, /* intintobjargproc sq_ass_slice; __setslice__ */
-};
-
-static PyObject *symbol_iter(PyObject *obj)
-{
- pySymbol *self = (pySymbol *)obj;
- PyObject *nobj = symbol_slice(self);
- if(nobj) {
- PyObject *it = PyObject_GetIter(nobj);
- Py_DECREF(nobj);
- return it;
- }
- else
- return NULL;
-}
-
-
-
-PyTypeObject pySymbol_Type = {
- PyObject_HEAD_INIT(NULL)
- 0, /*ob_size*/
- "Symbol", /*tp_name*/
- sizeof(pySymbol), /*tp_basicsize*/
- 0, /*tp_itemsize*/
- 0, /*tp_dealloc*/
- 0, /*tp_print*/
- 0, /*tp_getattr*/
- 0, /*tp_setattr*/
- 0, /*tp_compare*/
- symbol_repr, /*tp_repr*/
- 0, /*tp_as_number*/
- &symbol_as_seq, /*tp_as_sequence*/
- 0, /*tp_as_mapping*/
- symbol_hash, /*tp_hash */
- 0, /*tp_call*/
- symbol_str, /*tp_str*/
- 0, /*tp_getattro*/
- 0, /*tp_setattro*/
- 0, /*tp_as_buffer*/
- Py_TPFLAGS_DEFAULT /*| Py_TPFLAGS_BASETYPE*/, /*tp_flags*/
- "Symbol objects", /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- symbol_richcompare, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- symbol_iter, /* tp_iter */
- 0, /* tp_iternext */
- 0, /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- symbol_init, /* tp_init */
- 0, /* tp_alloc */
- symbol_new, /* tp_new */
-};
-
-pySymbol *pySymbol__;
-pySymbol *pySymbol_bang;
-pySymbol *pySymbol_list;
-pySymbol *pySymbol_symbol;
-pySymbol *pySymbol_float;
-pySymbol *pySymbol_int;
-
-
-void initsymbol()
-{
- if(PyType_Ready(&pySymbol_Type) < 0)
- return;
-
- Py_INCREF(&pySymbol_Type);
-
- // initialize predefined objects
- pySymbol__ = symbol_newsym(flext::sym__);
- pySymbol_bang = symbol_newsym(flext::sym_bang);
- pySymbol_list = symbol_newsym(flext::sym_list);
- pySymbol_symbol = symbol_newsym(flext::sym_symbol);
- pySymbol_float = symbol_newsym(flext::sym_float);
- pySymbol_int = symbol_newsym(flext::sym_int);
-}
-
-
-PyObject *pySymbol_FromSymbol(const t_symbol *sym)
-{
- pySymbol *op;
- if(sym == flext::sym__)
- Py_INCREF(op = pySymbol__);
- else if(sym == flext::sym_bang)
- Py_INCREF(op = pySymbol_bang);
- else if(sym == flext::sym_list)
- Py_INCREF(op = pySymbol_list);
- else if(sym == flext::sym_symbol)
- Py_INCREF(op = pySymbol_symbol);
- else if(sym == flext::sym_float)
- Py_INCREF(op = pySymbol_float);
- else if(sym == flext::sym_int)
- Py_INCREF(op = pySymbol_int);
- else
- op = symbol_newsym(sym);
- return (PyObject *)op;
-}
+/*
+
+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 "pyprefix.h"
+#include "pysymbol.h"
+
+inline pySymbol *symbol_newsym(const t_symbol *sym)
+{
+ pySymbol *self = (pySymbol *)pySymbol_Type.tp_alloc(&pySymbol_Type, 0);
+ if(self) self->sym = sym;
+ return self;
+}
+
+static PyObject *symbol_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ return (PyObject *)symbol_newsym(flext::sym__);
+}
+
+static int symbol_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ FLEXT_ASSERT(pySymbol_Check(self));
+
+ PyObject *arg = PySequence_GetItem(args,0); // new reference
+ if(!arg) return -1;
+
+ int ret = 0;
+
+ if(pySymbol_Check(arg))
+ ((pySymbol *)self)->sym = pySymbol_AS_SYMBOL(arg);
+ else if(PyString_Check(arg))
+ ((pySymbol *)self)->sym = flext::MakeSymbol(PyString_AS_STRING(arg));
+ else {
+ PyErr_SetString(PyExc_TypeError,"string or symbol argument expected");
+ ret = -1;
+ }
+ Py_DECREF(arg);
+
+ return ret;
+}
+
+static PyObject *symbol_str(PyObject *self)
+{
+ FLEXT_ASSERT(pySymbol_Check(self));
+ return (PyObject *)PyString_FromString(pySymbol_AS_STRING(self));
+}
+
+static PyObject *symbol_repr(PyObject *self)
+{
+ FLEXT_ASSERT(pySymbol_Check(self));
+ return (PyObject *)PyString_FromFormat("<Symbol %s>",pySymbol_AS_STRING(self));
+}
+
+static PyObject *symbol_richcompare(PyObject *a,PyObject *b,int cmp)
+{
+ if(pySymbol_Check(a) && pySymbol_Check(b)) {
+ const t_symbol *asym = pySymbol_AS_SYMBOL(a);
+ const t_symbol *bsym = pySymbol_AS_SYMBOL(b);
+ bool ret;
+ switch(cmp) {
+ case Py_LT: ret = asym < bsym; break;
+ case Py_LE: ret = asym <= bsym; break;
+ case Py_EQ: ret = asym == bsym; break;
+ case Py_NE: ret = asym != bsym; break;
+ case Py_GT: ret = asym > bsym; break;
+ case Py_GE: ret = asym >= bsym; break;
+ }
+ return PyBool_FromLong(ret);
+ }
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+}
+
+static long symbol_hash(PyObject *self)
+{
+ FLEXT_ASSERT(pySymbol_Check(self));
+ return (long)pySymbol_AS_SYMBOL(self);
+}
+
+
+static int symbol_length(pySymbol *self)
+{
+ return strlen(flext::GetString(self->sym));
+}
+
+static PyObject *symbol_item(pySymbol *self, int i)
+{
+ const char *str = flext::GetString(self->sym);
+ int len = strlen(str);
+ if(i < 0) i += len;
+
+ if(i >= 0 && i < len)
+ return PyString_FromStringAndSize(str+i,1);
+ else {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+}
+
+static PyObject *symbol_slice(pySymbol *self,int ilow = 0,int ihigh = 1<<(sizeof(int)*8-2))
+{
+ const char *str = flext::GetString(self->sym);
+ int len = strlen(str);
+ if(ilow < 0) {
+ ilow += len;
+ if(ilow < 0) ilow = 0;
+ }
+ if(ihigh < 0) ihigh += len;
+ if(ihigh >= len) ihigh = len-1;
+
+ return PyString_FromStringAndSize(str+ilow,ilow <= ihigh?ihigh-ilow+1:0);
+}
+
+static PyObject *symbol_concat(pySymbol *self,PyObject *op)
+{
+ PyObject *nobj = symbol_slice(self); // take all
+ if(nobj) {
+ PyObject *ret = PySequence_Concat(nobj,op);
+ Py_DECREF(nobj);
+ return ret;
+ }
+ else
+ return NULL;
+}
+
+static PyObject *symbol_repeat(pySymbol *self,int rep)
+{
+ PyObject *nobj = symbol_slice(self); // take all
+ if(nobj) {
+ PyObject *ret = PySequence_Repeat(nobj,rep);
+ Py_DECREF(nobj);
+ return ret;
+ }
+ else
+ return NULL;
+}
+
+static PySequenceMethods symbol_as_seq = {
+ (inquiry)symbol_length, /* inquiry sq_length; __len__ */
+ (binaryfunc)symbol_concat, /* __add__ */
+ (intargfunc)symbol_repeat, /* __mul__ */
+ (intargfunc)symbol_item, /* intargfunc sq_item; __getitem__ */
+ (intintargfunc)symbol_slice, /* intintargfunc sq_slice; __getslice__ */
+ NULL, /* intobjargproc sq_ass_item; __setitem__ */
+ NULL, /* intintobjargproc sq_ass_slice; __setslice__ */
+};
+
+static PyObject *symbol_iter(PyObject *obj)
+{
+ pySymbol *self = (pySymbol *)obj;
+ PyObject *nobj = symbol_slice(self);
+ if(nobj) {
+ PyObject *it = PyObject_GetIter(nobj);
+ Py_DECREF(nobj);
+ return it;
+ }
+ else
+ return NULL;
+}
+
+
+
+PyTypeObject pySymbol_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "Symbol", /*tp_name*/
+ sizeof(pySymbol), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ 0, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ symbol_repr, /*tp_repr*/
+ 0, /*tp_as_number*/
+ &symbol_as_seq, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ symbol_hash, /*tp_hash */
+ 0, /*tp_call*/
+ symbol_str, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT /*| Py_TPFLAGS_BASETYPE*/, /*tp_flags*/
+ "Symbol objects", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ symbol_richcompare, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ symbol_iter, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ symbol_init, /* tp_init */
+ 0, /* tp_alloc */
+ symbol_new, /* tp_new */
+};
+
+pySymbol *pySymbol__;
+pySymbol *pySymbol_bang;
+pySymbol *pySymbol_list;
+pySymbol *pySymbol_symbol;
+pySymbol *pySymbol_float;
+pySymbol *pySymbol_int;
+
+
+void initsymbol()
+{
+ if(PyType_Ready(&pySymbol_Type) < 0)
+ return;
+
+ Py_INCREF(&pySymbol_Type);
+
+ // initialize predefined objects
+ pySymbol__ = symbol_newsym(flext::sym__);
+ pySymbol_bang = symbol_newsym(flext::sym_bang);
+ pySymbol_list = symbol_newsym(flext::sym_list);
+ pySymbol_symbol = symbol_newsym(flext::sym_symbol);
+ pySymbol_float = symbol_newsym(flext::sym_float);
+ pySymbol_int = symbol_newsym(flext::sym_int);
+}
+
+
+PyObject *pySymbol_FromSymbol(const t_symbol *sym)
+{
+ pySymbol *op;
+ if(sym == flext::sym__)
+ Py_INCREF(op = pySymbol__);
+ else if(sym == flext::sym_bang)
+ Py_INCREF(op = pySymbol_bang);
+ else if(sym == flext::sym_list)
+ Py_INCREF(op = pySymbol_list);
+ else if(sym == flext::sym_symbol)
+ Py_INCREF(op = pySymbol_symbol);
+ else if(sym == flext::sym_float)
+ Py_INCREF(op = pySymbol_float);
+ else if(sym == flext::sym_int)
+ Py_INCREF(op = pySymbol_int);
+ else
+ op = symbol_newsym(sym);
+ return (PyObject *)op;
+}
diff --git a/externals/grill/py/source/pysymbol.h b/externals/grill/py/source/pysymbol.h
index 42f6765c..3de4cb00 100644
--- a/externals/grill/py/source/pysymbol.h
+++ b/externals/grill/py/source/pysymbol.h
@@ -1,55 +1,55 @@
-/*
-
-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.
-
-*/
-
-#ifndef __PYSYMBOL_H
-#define __PYSYMBOL_H
-
-#include <flext.h>
-
-#if !defined(FLEXT_VERSION) || (FLEXT_VERSION < 500)
-#error You need at least flext version 0.5.0
-#endif
-
-#if FLEXT_OS == FLEXT_OS_MAC
-#include <Python/Python.h>
-#else
-#include <Python.h>
-#endif
-
-
-#ifdef _MSC_VER
- #ifdef PY_EXPORTS
- #define PY_EXPORT __declspec(dllexport)
- #else
- #define PY_EXPORT __declspec(dllimport)
- #endif
-#else
- #define PY_EXPORT
-#endif
-
-typedef struct {
- PyObject_HEAD
- /* Type-specific fields go here. */
- const t_symbol *sym;
-} pySymbol;
-
-PY_EXPORT extern PyTypeObject pySymbol_Type;
-
-PY_EXPORT extern pySymbol *pySymbol__;
-PY_EXPORT extern pySymbol *pySymbol_bang;
-PY_EXPORT extern pySymbol *pySymbol_list;
-PY_EXPORT extern pySymbol *pySymbol_symbol;
-PY_EXPORT extern pySymbol *pySymbol_float;
-PY_EXPORT extern pySymbol *pySymbol_int;
-
-
+/*
+
+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.
+
+*/
+
+#ifndef __PYSYMBOL_H
+#define __PYSYMBOL_H
+
+#include <flext.h>
+
+#if !defined(FLEXT_VERSION) || (FLEXT_VERSION < 500)
+#error You need at least flext version 0.5.0
+#endif
+
+#if FLEXT_OS == FLEXT_OS_MAC
+#include <Python/Python.h>
+#else
+#include <Python.h>
+#endif
+
+
+#ifdef _MSC_VER
+ #ifdef PY_EXPORTS
+ #define PY_EXPORT __declspec(dllexport)
+ #else
+ #define PY_EXPORT __declspec(dllimport)
+ #endif
+#else
+ #define PY_EXPORT
+#endif
+
+typedef struct {
+ PyObject_HEAD
+ /* Type-specific fields go here. */
+ const t_symbol *sym;
+} pySymbol;
+
+PY_EXPORT extern PyTypeObject pySymbol_Type;
+
+PY_EXPORT extern pySymbol *pySymbol__;
+PY_EXPORT extern pySymbol *pySymbol_bang;
+PY_EXPORT extern pySymbol *pySymbol_list;
+PY_EXPORT extern pySymbol *pySymbol_symbol;
+PY_EXPORT extern pySymbol *pySymbol_float;
+PY_EXPORT extern pySymbol *pySymbol_int;
+
+
#define pySymbol_Check(op) PyObject_TypeCheck(op, &pySymbol_Type)
#define pySymbol_CheckExact(op) ((op)->ob_type == &pySymbol_Type)
@@ -66,27 +66,27 @@ inline PyObject *pySymbol_FromString(PyObject *str)
return pySymbol_FromString(PyString_AsString(str));
}
-inline const t_symbol *pySymbol_AS_SYMBOL(PyObject *op)
-{
- return ((pySymbol *)op)->sym;
-}
-
-inline const t_symbol *pySymbol_AsSymbol(PyObject *op)
-{
- return pySymbol_Check(op)?pySymbol_AS_SYMBOL(op):NULL;
-}
-
-inline const char *pySymbol_AS_STRING(PyObject *op)
-{
- return flext::GetString(pySymbol_AS_SYMBOL(op));
-}
-
-inline const t_symbol *pyObject_AsSymbol(PyObject *op)
-{
- if(PyString_Check(op))
- return flext::MakeSymbol(PyString_AS_STRING(op));
- else
- return pySymbol_AsSymbol(op);
-}
-
-#endif
+inline const t_symbol *pySymbol_AS_SYMBOL(PyObject *op)
+{
+ return ((pySymbol *)op)->sym;
+}
+
+inline const t_symbol *pySymbol_AsSymbol(PyObject *op)
+{
+ return pySymbol_Check(op)?pySymbol_AS_SYMBOL(op):NULL;
+}
+
+inline const char *pySymbol_AS_STRING(PyObject *op)
+{
+ return flext::GetString(pySymbol_AS_SYMBOL(op));
+}
+
+inline const t_symbol *pyObject_AsSymbol(PyObject *op)
+{
+ if(PyString_Check(op))
+ return flext::MakeSymbol(PyString_AS_STRING(op));
+ else
+ return pySymbol_AsSymbol(op);
+}
+
+#endif