aboutsummaryrefslogtreecommitdiff
path: root/externals/grill/py
diff options
context:
space:
mode:
authorThomas Grill <xovo@users.sourceforge.net>2002-10-22 23:16:30 +0000
committerThomas Grill <xovo@users.sourceforge.net>2002-10-22 23:16:30 +0000
commitc2645dc4003b1391aba9b387a79a66cff1e63d3e (patch)
tree1ea6dccb8011a8ff64efb7c2ecf9a22caad860b3 /externals/grill/py
parentd62e56f4df9594f72ce501f5e19c974fd18e7295 (diff)
This commit was generated by cvs2svn to compensate for changes in r189,
which included commits to RCS files with non-trunk default branches. svn path=/trunk/; revision=190
Diffstat (limited to 'externals/grill/py')
-rw-r--r--externals/grill/py/build-pd-bcc.bat3
-rw-r--r--externals/grill/py/build-pd-cygwin.sh10
-rwxr-xr-xexternals/grill/py/build-pd-linux.sh11
-rw-r--r--externals/grill/py/build-pd-msvc.bat4
-rw-r--r--externals/grill/py/config-pd-bcc.txt31
-rw-r--r--externals/grill/py/config-pd-cygwin.txt29
-rw-r--r--externals/grill/py/config-pd-linux.txt33
-rw-r--r--externals/grill/py/config-pd-msvc.txt30
-rw-r--r--externals/grill/py/gpl.txt346
-rw-r--r--externals/grill/py/license.txt50
-rw-r--r--externals/grill/py/makefile.pd-bcc82
-rw-r--r--externals/grill/py/makefile.pd-linux75
-rw-r--r--externals/grill/py/pd/script-1.pd50
-rw-r--r--externals/grill/py/pd/sendrecv-1.pd25
-rw-r--r--externals/grill/py/pd/sendrecv-2.pd8
-rw-r--r--externals/grill/py/pd/sendrecv-3.pd5
-rw-r--r--externals/grill/py/pd/simple-1.pd41
-rw-r--r--externals/grill/py/pd/simple-2.pd37
-rw-r--r--externals/grill/py/pd/simple-3.pd27
-rw-r--r--externals/grill/py/pd/tcltk.pd18
-rw-r--r--externals/grill/py/pd/thread-1.pd47
-rw-r--r--externals/grill/py/py.cwbin0 -> 88197 bytes
-rw-r--r--externals/grill/py/py.dsp229
-rw-r--r--externals/grill/py/py.mpw91
-rw-r--r--externals/grill/py/readme.txt106
-rw-r--r--externals/grill/py/scripts/script.py53
-rw-r--r--externals/grill/py/scripts/sendrecv.py173
-rw-r--r--externals/grill/py/scripts/simple.py206
-rw-r--r--externals/grill/py/scripts/tcltk.py77
-rw-r--r--externals/grill/py/scripts/threads.py43
-rw-r--r--externals/grill/py/source/bound.cpp143
-rw-r--r--externals/grill/py/source/clmeth.cpp278
-rw-r--r--externals/grill/py/source/main.cpp212
-rw-r--r--externals/grill/py/source/main.h147
-rw-r--r--externals/grill/py/source/modmeth.cpp183
-rw-r--r--externals/grill/py/source/py.cpp327
-rw-r--r--externals/grill/py/source/pyargs.cpp131
-rw-r--r--externals/grill/py/source/pyext.cpp465
-rw-r--r--externals/grill/py/source/pyext.h127
-rw-r--r--externals/grill/py/source/register.cpp86
40 files changed, 4039 insertions, 0 deletions
diff --git a/externals/grill/py/build-pd-bcc.bat b/externals/grill/py/build-pd-bcc.bat
new file mode 100644
index 00000000..3dd21329
--- /dev/null
+++ b/externals/grill/py/build-pd-bcc.bat
@@ -0,0 +1,3 @@
+@echo --- Building with BorlandC++ ---
+
+make -f makefile.pd-bcc
diff --git a/externals/grill/py/build-pd-cygwin.sh b/externals/grill/py/build-pd-cygwin.sh
new file mode 100644
index 00000000..8eb7bcab
--- /dev/null
+++ b/externals/grill/py/build-pd-cygwin.sh
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+. config-pd-cygwin.txt
+
+make -f makefile.pd-cygwin &&
+{
+ if [ $INSTALL = "yes" ]; then
+ make -f makefile.pd-cygwin install
+ fi
+}
diff --git a/externals/grill/py/build-pd-linux.sh b/externals/grill/py/build-pd-linux.sh
new file mode 100755
index 00000000..90e4a04a
--- /dev/null
+++ b/externals/grill/py/build-pd-linux.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+. config-pd-linux.txt
+
+make -f makefile.pd-linux &&
+{
+ if [ $INSTALL = "yes" ]; then
+ echo Now install as root
+ su -c "make -f makefile.pd-linux install"
+ fi
+}
diff --git a/externals/grill/py/build-pd-msvc.bat b/externals/grill/py/build-pd-msvc.bat
new file mode 100644
index 00000000..d6187f08
--- /dev/null
+++ b/externals/grill/py/build-pd-msvc.bat
@@ -0,0 +1,4 @@
+@echo --- Building with MS Visual C++ ---
+
+nmake -f makefile.pd-msvc clean
+nmake -f makefile.pd-msvc
diff --git a/externals/grill/py/config-pd-bcc.txt b/externals/grill/py/config-pd-bcc.txt
new file mode 100644
index 00000000..83d23264
--- /dev/null
+++ b/externals/grill/py/config-pd-bcc.txt
@@ -0,0 +1,31 @@
+# py/pyext - python script objects for PD and Max/MSP
+# Copyright (c) 2002 Thomas Grill (xovo@gmx.net)
+#
+
+# where is PD?
+PDPATH=c:\programme\audio\pd
+
+# where do the flext libraries reside?
+FLEXTPATH=$(PDPATH)\flext
+
+# where is BorlandC++?
+BCCPATH=c:\programme\prog\bcc55
+
+# which version of Python?
+PYTHONVER=python22
+
+# where are the python header files?
+PYTHONINCLUDE=c:\programme\prog\$(PYTHONVER)\include
+
+# what is the python library file?
+PYTHONBIN=c:\windows\system32\$(PYTHONVER).dll
+
+# where should the external(s) be built?
+OUTPATH=.\pd-bcc
+
+# should the external be installed? (yes/no)
+INSTALL=yes
+
+# where should the external be installed?
+INSTDIR=$(PDPATH)\extra
+
diff --git a/externals/grill/py/config-pd-cygwin.txt b/externals/grill/py/config-pd-cygwin.txt
new file mode 100644
index 00000000..7c7bebd8
--- /dev/null
+++ b/externals/grill/py/config-pd-cygwin.txt
@@ -0,0 +1,29 @@
+# py/pyext - python script objects for PD and Max/MSP
+# Copyright (c) 2002 Thomas Grill (xovo@gmx.net)
+#
+
+# where is PD?
+PDPATH=/cygdrive/c/programme/audio/pd
+
+# where do the flext libraries reside?
+FLEXTPATH=${PDPATH}/flext
+
+# which version of Python?
+PYTHONVER=python22
+
+# where are the python header files?
+PYTHONINCLUDE=/cygdrive/c/programme/prog/${PYTHONVER}/include
+
+# what is the python library file?
+PYTHONLIB=/cygdrive/c/programme/prog/${PYTHONVER}/libs/${PYTHONVER}.lib
+
+# where should the external(s) be built?
+TARGDIR=./pd-cygwin
+
+# should the external be installed? (yes/no)
+INSTALL=yes
+
+# where should the external be installed?
+INSTDIR=${PDPATH}/extra
+
+
diff --git a/externals/grill/py/config-pd-linux.txt b/externals/grill/py/config-pd-linux.txt
new file mode 100644
index 00000000..bc63be41
--- /dev/null
+++ b/externals/grill/py/config-pd-linux.txt
@@ -0,0 +1,33 @@
+# py/pyext - python script objects for PD and Max/MSP
+# Copyright (c) 2002 Thomas Grill (xovo@gmx.net)
+#
+
+# your c++ compiler (normally g++)
+CXX=g++-3.2
+
+# where are the PD header files?
+# leave it blank if it is a system directory (like /usr/local/include),
+# since gcc 3.2 complains about it
+PDPATH=
+
+# where do the flext libraries reside?
+FLEXTPATH=/usr/local/lib/pd/flext
+
+# what is the python version?
+PYTHONVER=2.2
+# where are the python header files?
+PYTHONINCLUDE=/usr/include/python${PYTHONVER}
+# where is the python library file?
+PYTHONLIB=/usr/lib/python${PYTHONVER}/config
+
+# where should flext libraries be built?
+TARGDIR=./pd-linux
+
+# should the flext stuff be installed? (yes/no)
+INSTALL=yes
+
+# where should py/pyext be installed?
+INSTPATH=/usr/local/lib/pd/extra
+
+
+
diff --git a/externals/grill/py/config-pd-msvc.txt b/externals/grill/py/config-pd-msvc.txt
new file mode 100644
index 00000000..e5c4d044
--- /dev/null
+++ b/externals/grill/py/config-pd-msvc.txt
@@ -0,0 +1,30 @@
+# py/pyext - python script objects for PD and Max/MSP
+# Copyright (c) 2002 Thomas Grill (xovo@gmx.net)
+#
+
+# where is PD?
+PDPATH=c:\programme\audio\pd
+
+# where do the flext libraries reside?
+FLEXTPATH=$(PDPATH)\flext
+
+# where is MS VC++?
+MSVCPATH="c:\programme\prog\microsoft visual studio\VC98"
+
+# which version of Python?
+PYTHONVER=python22
+
+# where are the python header files?
+PYTHONINCLUDE=c:\programme\prog\$(PYTHONVER)\include
+
+# what is the python library file?
+PYTHONLIB=c:\programme\prog\$(PYTHONVER)\libs\$(PYTHONVER).lib
+
+# where should the external be built?
+OUTPATH=pd-msvc
+
+# should the external be installed? (yes/no)
+INSTALL=yes
+
+# where should the external be installed?
+INSTDIR=$(PDPATH)\extra
diff --git a/externals/grill/py/gpl.txt b/externals/grill/py/gpl.txt
new file mode 100644
index 00000000..5ea29a7d
--- /dev/null
+++ b/externals/grill/py/gpl.txt
@@ -0,0 +1,346 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+
diff --git a/externals/grill/py/license.txt b/externals/grill/py/license.txt
new file mode 100644
index 00000000..949207fd
--- /dev/null
+++ b/externals/grill/py/license.txt
@@ -0,0 +1,50 @@
+py/pyext - python script objects for PD and MaxMSP
+Copyright (C) 2002 Thomas Grill
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+In the official py/pyext distribution, the GNU General Public License is
+in the file gpl.txt
+
+---------------------------------------------------------
+
+ OTHER COPYRIGHT NOTICES
+
+---------------------------------------------------------
+This package uses the flext C++ layer - See its license text below:
+
+
+--- flext ----------------------------------------------
+flext - C++ layer for Max/MSP and pd (pure data) externals
+Copyright (C) 2001,2002 Thomas Grill
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+In the official flext distribution, the GNU General Public License is
+in the file gpl.txt
+
+
diff --git a/externals/grill/py/makefile.pd-bcc b/externals/grill/py/makefile.pd-bcc
new file mode 100644
index 00000000..e94abdf4
--- /dev/null
+++ b/externals/grill/py/makefile.pd-bcc
@@ -0,0 +1,82 @@
+# py/pyext - python script object for PD and MaxMSP
+# Copyright (C) 2002 Thomas Grill
+#
+# Makefile for BorlandC++
+#
+# usage: make -f makefile.pd-bcc
+#
+# ... no threads!
+#
+# ---------------------------------------------
+
+!include config-pd-bcc.txt
+
+NAME=py
+SETUPFUNCTION=$(NAME)_setup
+
+# flext stuff
+TARGET=pdwin
+
+# includes, libs
+INCPATH=-I$(BCCPATH)\include -I$(PYTHONINCLUDE) -I$(PDPATH)\src -I$(FLEXTPATH)
+LIBPATH=-L$(BCCPATH)\lib -L$(PDPATH)\lib
+LIBS=cw32.lib import32.lib C0D32.OBJ
+
+# compiler definitions and flags
+DEFS=-DPD -DNT
+CFLAGS=-6 -O2 -OS -ff -tWD
+
+
+# the rest can stay untouched
+# ----------------------------------------------
+
+# all the source files from the package
+SRCS= main.cpp py.cpp pyext.cpp modmeth.cpp clmeth.cpp register.cpp pyargs.cpp bound.cpp
+HDRS= main.h pyext.h
+
+# default target
+all: $(OUTPATH)\$(NAME).dll
+
+# remove build
+clean:
+ -del /s /q $(OUTPATH) > nul
+ rmdir $(OUTPATH)
+
+
+install:
+ cp $(OUTPATH)\$(NAME).dll $(INSTDIR)
+
+# ----------------------------------------------
+
+OBJS= $(SRCS:.cpp=.obj)
+
+#.PATH.OBJ=$(OUTPATH)
+
+#$(SRCS): $(HDRS)
+# -touch $<
+
+{source}.cpp.obj:
+ bcc32 -c $(CFLAGS) $(DEFS) $(INCPATH) -n$(OUTPATH) $<
+
+$(OUTPATH):
+ -@if not exist $< mkdir $<
+
+$(OUTPATH)\pd.lib: $(PDPATH)\bin\pd.dll
+ implib -a $< $**
+
+$(OUTPATH)\python.lib: $(PYTHONBIN)
+ implib -a $< $**
+
+$(OUTPATH)\$(NAME).def:
+ @echo EXPORTS $(SETUPFUNCTION) = _$(SETUPFUNCTION) > $<
+ @echo IMPORTS _Py_Initialize = $(PYTHONVER).Py_Initialize >> $<
+ @echo IMPORTS _Py_Finalize = $(PYTHONVER).Py_Finalize >> $<
+
+$(OUTPATH)\$(NAME).dll :: $(OUTPATH) $(OUTPATH)\$(NAME).def $(OUTPATH)\pd.lib $(OUTPATH)\python.lib
+
+$(OUTPATH)\$(NAME).dll :: $(OBJS)
+ cd $(OUTPATH)
+ ilink32 -C -Tpd $(LIBPATH) $** ,..\$<,,$(LIBS) pd.lib python.lib $(FLEXTPATH)\flext-$(TARGET).lib ,$(NAME).def
+ cd ..
+
+ \ No newline at end of file
diff --git a/externals/grill/py/makefile.pd-linux b/externals/grill/py/makefile.pd-linux
new file mode 100644
index 00000000..af2b58d2
--- /dev/null
+++ b/externals/grill/py/makefile.pd-linux
@@ -0,0 +1,75 @@
+# py/pyext - python script object for PD and Max/MSP
+# Copyright (C) 2002 Thomas Grill (xovo@gmx.net)
+#
+# Makefile for gcc @ linux
+#
+# usage:
+# to build run "make -f makefile.pd-linux"
+# to install (as root), do "make -f makefile.pd-linux install"
+#
+
+CONFIG=config-pd-linux.txt
+
+include $(CONFIG)
+
+FLEXTLIB=$(FLEXTPATH)/flext_t.a
+
+# compiler+linker stuff
+INCLUDES=$(PDPATH) $(PYTHONINCLUDE)
+LIBPATH=$(PYTHONLIB)
+FLAGS=-DPD -DFLEXT_THREADS
+CFLAGS=-O6 -mcpu=pentiumpro
+#CFLAGS=-g
+LIBS=m util python$(PYTHONVER)
+
+
+# ---------------------------------------------
+# the rest can stay untouched
+# ----------------------------------------------
+
+NAME=py
+
+# all the source files from the package
+SRCS=main.cpp py.cpp pyext.cpp bound.cpp clmeth.cpp modmeth.cpp pyargs.cpp register.cpp
+HDRS=main.h pyext.h
+
+TARGET=$(TARGDIR)/$(NAME).pd_linux
+
+# default target
+all: $(TARGDIR) $(TARGET)
+
+$(patsubst %,source/%,$(SRCS)): $(patsubst %,source/%,$(HDRS)) $(FLEXTLIB) $(CONFIG)
+ touch $@
+
+$(TARGDIR):
+ mkdir $(TARGDIR)
+
+$(TARGDIR)/%.o : source/%.cpp
+ $(CXX) -c $(CFLAGS) $(FLAGS) $(patsubst %,-I%,$(INCLUDES) $(FLEXTPATH)) $< -o $@
+
+$(TARGET) : $(patsubst %.cpp,$(TARGDIR)/%.o,$(SRCS)) $(FLEXTLIB)
+ $(CXX) -shared $^ $(patsubst %,-L%,$(LIBPATH)) $(patsubst %,-l%,$(LIBS)) -o $@
+ chmod 755 $@
+
+$(INSTPATH):
+ mkdir $(INSTDIR)
+
+install:: $(INSTDIR)
+
+install:: $(TARGET)
+ cp $^ $(INSTPATH)
+ chown root.root $(patsubst %,$(INSTPATH)/%,$(notdir $^))
+ chmod 755 $(patsubst %,$(INSTPATH)/%,$(notdir $^))
+
+.PHONY: clean
+clean:
+ rm -f $(TARGDIR)/*.o $(TARGET)
+
+
+
+
+
+
+
+
+
diff --git a/externals/grill/py/pd/script-1.pd b/externals/grill/py/pd/script-1.pd
new file mode 100644
index 00000000..e143d5e8
--- /dev/null
+++ b/externals/grill/py/pd/script-1.pd
@@ -0,0 +1,50 @@
+#N canvas 297 17 672 523 12;
+#X obj 39 278 print;
+#X obj 345 251 print;
+#X msg 499 149 freakhole;
+#X msg 148 149 list H e l l o;
+#X msg 166 175 Hello friend;
+#X obj 42 460 print;
+#X msg 102 367 0 1 2 3 4;
+#X msg 197 367 5 67 3;
+#X obj 350 456 print;
+#X obj 326 365 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+-1;
+#X obj 515 455 print;
+#X obj 514 386 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+-1;
+#X msg 188 204 1 3;
+#X msg 345 155 help;
+#X msg 360 327 set ret1;
+#X msg 379 351 set ret2;
+#X text 434 326 functions can be set;
+#X msg 421 120 somewhere_past_mars;
+#X text 152 101 reload with new arguments;
+#X msg 40 104 reload 1 2 3;
+#X text 23 13 py/pyext - Python script objects \, (C)2002 Thomas Grill
+;
+#X text 21 42 This demonstrates simple scripting. See the script.py
+file.;
+#X obj 39 241 py script strcat;
+#X obj 43 424 py script addall;
+#X obj 350 420 py script;
+#X obj 516 419 py script ret3;
+#X obj 346 204 py script strlen;
+#X connect 2 0 26 1;
+#X connect 3 0 22 1;
+#X connect 4 0 22 1;
+#X connect 6 0 23 1;
+#X connect 7 0 23 1;
+#X connect 9 0 24 0;
+#X connect 11 0 25 0;
+#X connect 12 0 22 1;
+#X connect 13 0 26 0;
+#X connect 14 0 24 0;
+#X connect 15 0 24 0;
+#X connect 17 0 26 1;
+#X connect 19 0 22 0;
+#X connect 22 0 0 0;
+#X connect 23 0 5 0;
+#X connect 24 0 8 0;
+#X connect 25 0 10 0;
+#X connect 26 0 1 0;
diff --git a/externals/grill/py/pd/sendrecv-1.pd b/externals/grill/py/pd/sendrecv-1.pd
new file mode 100644
index 00000000..d2d4b50a
--- /dev/null
+++ b/externals/grill/py/pd/sendrecv-1.pd
@@ -0,0 +1,25 @@
+#N canvas 343 246 466 316 12;
+#X msg 125 52 reload mi ma;
+#X floatatom 48 173 5 0 0;
+#X floatatom 181 174 5 0 0;
+#X obj 181 198 s mi;
+#X floatatom 49 265 5 0 0;
+#X floatatom 181 266 5 0 0;
+#X obj 181 239 r ma;
+#X obj 48 197 s he;
+#X obj 49 238 r hu;
+#X text 233 51 reload with different args;
+#X msg 20 17 help;
+#X msg 19 49 doc;
+#X msg 58 49 doc+;
+#X obj 49 100 pyext sendrecv ex1 he hu;
+#X text 28 151 scroll here;
+#X text 176 152 or here;
+#X connect 0 0 13 0;
+#X connect 1 0 7 0;
+#X connect 2 0 3 0;
+#X connect 6 0 5 0;
+#X connect 8 0 4 0;
+#X connect 10 0 13 0;
+#X connect 11 0 13 0;
+#X connect 12 0 13 0;
diff --git a/externals/grill/py/pd/sendrecv-2.pd b/externals/grill/py/pd/sendrecv-2.pd
new file mode 100644
index 00000000..9f015b4c
--- /dev/null
+++ b/externals/grill/py/pd/sendrecv-2.pd
@@ -0,0 +1,8 @@
+#N canvas 133 322 454 304 12;
+#X obj 36 135 pyext sendrecv ex2 huha;
+#X floatatom 36 165 5 0 0;
+#X floatatom 35 38 5 0 0;
+#X obj 34 65 s huha;
+#X text 22 19 scroll here;
+#X connect 0 0 1 0;
+#X connect 2 0 3 0;
diff --git a/externals/grill/py/pd/sendrecv-3.pd b/externals/grill/py/pd/sendrecv-3.pd
new file mode 100644
index 00000000..0f42edfc
--- /dev/null
+++ b/externals/grill/py/pd/sendrecv-3.pd
@@ -0,0 +1,5 @@
+#N canvas 294 237 484 334 12;
+#X obj 283 258 pyext sendrecv ex3;
+#X obj 437 255 bng 25 250 50 0 empty ugh empty 0 -6 64 8 -258699 -1
+-1;
+#X connect 1 0 0 1;
diff --git a/externals/grill/py/pd/simple-1.pd b/externals/grill/py/pd/simple-1.pd
new file mode 100644
index 00000000..2d60db5b
--- /dev/null
+++ b/externals/grill/py/pd/simple-1.pd
@@ -0,0 +1,41 @@
+#N canvas 156 192 650 389 12;
+#X obj 53 123 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X floatatom 52 155 5 0 0;
+#X text 388 337 watch the console output!;
+#X msg 52 186 2 3 4;
+#X msg 277 131 ho;
+#X msg 233 155 lets;
+#X msg 283 190 go;
+#X msg 212 214 !!!;
+#X msg 205 113 hey;
+#X obj 183 301 pyext simple ex1;
+#X msg 434 114 onearg 123;
+#X msg 456 167 threeargs 9 8 7;
+#X msg 463 196 varargs 8 4 2 1;
+#X msg 447 140 twoargs 41 15;
+#X msg 453 239 twoargs 1 2 3;
+#X msg 71 299 help;
+#X text 16 15 py/pyext - Python script objects \, (C)2002 Thomas Grill
+;
+#X text 15 57 This demonstrates message handling. See the simple.py
+file.;
+#X text 232 322 file class;
+#X msg 70 324 doc;
+#X msg 106 325 doc+;
+#X connect 0 0 9 1;
+#X connect 1 0 9 1;
+#X connect 3 0 9 1;
+#X connect 4 0 9 2;
+#X connect 5 0 9 2;
+#X connect 6 0 9 2;
+#X connect 7 0 9 2;
+#X connect 8 0 9 2;
+#X connect 10 0 9 3;
+#X connect 11 0 9 3;
+#X connect 12 0 9 3;
+#X connect 13 0 9 3;
+#X connect 14 0 9 3;
+#X connect 15 0 9 0;
+#X connect 19 0 9 0;
+#X connect 20 0 9 0;
diff --git a/externals/grill/py/pd/simple-2.pd b/externals/grill/py/pd/simple-2.pd
new file mode 100644
index 00000000..e20be506
--- /dev/null
+++ b/externals/grill/py/pd/simple-2.pd
@@ -0,0 +1,37 @@
+#N canvas 225 210 689 411 12;
+#X floatatom 251 106 5 0 0;
+#X text 409 291 watch the console output!;
+#X msg 55 213 help;
+#X text 15 57 This demonstrates message handling. See the simple.py
+file.;
+#X msg 54 238 doc;
+#X msg 90 239 doc+;
+#X floatatom 308 106 5 0 0;
+#X msg 218 228 msg 2;
+#X obj 172 282 pyext simple ex2;
+#X floatatom 172 327 5 0 0;
+#X floatatom 289 328 5 0 0;
+#X text 17 22 py/pyext - Python script objects \, (C)2002 Thomas Grill
+;
+#X msg 149 197 msg 1 3;
+#X msg 283 213 msg a b;
+#X msg 169 167 hello;
+#X msg 242 173 hello;
+#X msg 315 172 msg;
+#X msg 374 147 hello 3;
+#X text 418 172 special case: 'hello' handler doesn't like args \,
+so _anything_ is called!;
+#X connect 0 0 8 1;
+#X connect 2 0 8 0;
+#X connect 4 0 8 0;
+#X connect 5 0 8 0;
+#X connect 6 0 8 2;
+#X connect 7 0 8 2;
+#X connect 8 0 9 0;
+#X connect 8 1 10 0;
+#X connect 12 0 8 1;
+#X connect 13 0 8 3;
+#X connect 14 0 8 1;
+#X connect 15 0 8 3;
+#X connect 16 0 8 2;
+#X connect 17 0 8 3;
diff --git a/externals/grill/py/pd/simple-3.pd b/externals/grill/py/pd/simple-3.pd
new file mode 100644
index 00000000..70416ad0
--- /dev/null
+++ b/externals/grill/py/pd/simple-3.pd
@@ -0,0 +1,27 @@
+#N canvas 307 249 546 386 12;
+#X msg 88 279 help;
+#X text 15 50 This demonstrates message handling. See the simple.py
+file.;
+#X msg 87 304 doc;
+#X msg 123 305 doc+;
+#X floatatom 288 345 5 0 0;
+#X text 17 22 py/pyext - Python script objects \, (C)2002 Thomas Grill
+;
+#X floatatom 316 119 5 0 0;
+#X floatatom 399 119 5 0 0;
+#X obj 225 279 pyext simple ex3 1;
+#X msg 39 195 reload.;
+#X msg 39 223 reload -10;
+#X text 110 194 reload script and keep arguments;
+#X text 128 224 reload script with new arguments;
+#X text 281 140 triggers;
+#X text 340 344 result;
+#X text 410 140 sets argument;
+#X connect 0 0 8 0;
+#X connect 2 0 8 0;
+#X connect 3 0 8 0;
+#X connect 6 0 8 1;
+#X connect 7 0 8 2;
+#X connect 8 0 4 0;
+#X connect 9 0 8 0;
+#X connect 10 0 8 0;
diff --git a/externals/grill/py/pd/tcltk.pd b/externals/grill/py/pd/tcltk.pd
new file mode 100644
index 00000000..c1c3b246
--- /dev/null
+++ b/externals/grill/py/pd/tcltk.pd
@@ -0,0 +1,18 @@
+#N canvas 156 192 610 329 12;
+#X obj 328 118 bng 25 250 50 0 empty empty empty 0 -6 0 8 -258699 -1
+-1;
+#X msg 94 128 help;
+#X text 16 15 py/pyext - Python script objects \, (C)2002 Thomas Grill
+;
+#X msg 139 127 doc;
+#X text 14 49 This demonstrates a tcl/tk dialog. See the tcltk.py file.
+;
+#X text 10 263 Note: When used concurrently with audio \, you will
+notice clicks. This Tk window is NOT called over a net socket \, like
+PD is;
+#X obj 206 169 pyext tcltk myapp;
+#X obj 206 200 print tcltk;
+#X connect 0 0 6 1;
+#X connect 1 0 6 0;
+#X connect 3 0 6 0;
+#X connect 6 0 7 0;
diff --git a/externals/grill/py/pd/thread-1.pd b/externals/grill/py/pd/thread-1.pd
new file mode 100644
index 00000000..892c37ce
--- /dev/null
+++ b/externals/grill/py/pd/thread-1.pd
@@ -0,0 +1,47 @@
+#N canvas 307 249 576 388 12;
+#X msg 38 265 help;
+#X msg 37 290 doc;
+#X msg 73 291 doc+;
+#X floatatom 145 323 5 0 0;
+#X text 16 14 py/pyext - Python script objects \, (C)2002 Thomas Grill
+;
+#X text 14 44 This demonstrates threading. See the threads.py file.
+;
+#X obj 145 279 pyext threads ex1;
+#X obj 140 216 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X msg 140 236 detach \$1;
+#X floatatom 253 324 5 0 0;
+#X obj 275 123 bng 15 250 50 0 empty empty empty 0 -6 0 8 -258699 -1
+-1;
+#X obj 146 127 bng 15 250 50 0 empty empty empty 0 -6 0 8 -258699 -1
+-1;
+#X obj 146 154 t b b b;
+#X obj 275 150 t b b b;
+#X obj 289 179 1;
+#X obj 160 181 0;
+#X text 87 87 without threads;
+#X text 113 105 blocking;
+#X text 251 85 with threads;
+#X text 252 102 non-blocking;
+#X text 178 345 watch that!;
+#X msg 414 127 stop;
+#X text 384 106 you can even stop it;
+#X connect 0 0 6 0;
+#X connect 1 0 6 0;
+#X connect 2 0 6 0;
+#X connect 6 0 3 0;
+#X connect 6 1 9 0;
+#X connect 7 0 8 0;
+#X connect 8 0 6 0;
+#X connect 10 0 13 0;
+#X connect 11 0 12 0;
+#X connect 12 0 6 1;
+#X connect 12 1 6 2;
+#X connect 12 2 15 0;
+#X connect 13 0 6 1;
+#X connect 13 1 6 2;
+#X connect 13 2 14 0;
+#X connect 14 0 7 0;
+#X connect 15 0 7 0;
+#X connect 21 0 6 0;
diff --git a/externals/grill/py/py.cw b/externals/grill/py/py.cw
new file mode 100644
index 00000000..f5f6fc7f
--- /dev/null
+++ b/externals/grill/py/py.cw
Binary files differ
diff --git a/externals/grill/py/py.dsp b/externals/grill/py/py.dsp
new file mode 100644
index 00000000..8171624c
--- /dev/null
+++ b/externals/grill/py/py.dsp
@@ -0,0 +1,229 @@
+# Microsoft Developer Studio Project File - Name="py" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** NICHT BEARBEITEN **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=py - Win32 Threads Debug
+!MESSAGE Dies ist kein gültiges Makefile. Zum Erstellen dieses Projekts mit NMAKE
+!MESSAGE verwenden Sie den Befehl "Makefile exportieren" und führen Sie den Befehl
+!MESSAGE
+!MESSAGE NMAKE /f "py.mak".
+!MESSAGE
+!MESSAGE Sie können beim Ausführen von NMAKE eine Konfiguration angeben
+!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel:
+!MESSAGE
+!MESSAGE NMAKE /f "py.mak" CFG="py - Win32 Threads Debug"
+!MESSAGE
+!MESSAGE Für die Konfiguration stehen zur Auswahl:
+!MESSAGE
+!MESSAGE "py - Win32 Release" (basierend auf "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "py - Win32 Debug" (basierend auf "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "py - Win32 Threads Release" (basierend auf "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "py - Win32 Threads Debug" (basierend auf "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName "py"
+# PROP Scc_LocalPath "."
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "py - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "pd-msvc\r"
+# PROP Intermediate_Dir "pd-msvc\r"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PY_EXPORTS" /YX /FD /c
+# ADD CPP /nologo /W3 /GR- /O2 /I "c:\programme\audio\pd\src" /I "f:\prog\max\flext\source" /I "C:\Programme\prog\Python22\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PD" /D "NT" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0xc07 /d "NDEBUG"
+# ADD RSC /l 0xc07 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib pd.lib flext-pdwin.lib /nologo /dll /machine:I386 /libpath:"c:/programme/audio/pd/bin" /libpath:"..\flext\pd-msvc" /libpath:"C:\Programme\prog\Python22\libs"
+
+!ELSEIF "$(CFG)" == "py - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "pd-msvc\d"
+# PROP Intermediate_Dir "pd-msvc\d"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PY_EXPORTS" /YX /FD /GZ /c
+# ADD CPP /nologo /W3 /Gm /GR /ZI /Od /I "c:\programme\audio\pd\src" /I "f:\prog\max\flext\source" /I "C:\Programme\prog\Python22\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PD" /D "NT" /FR /YX /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0xc07 /d "_DEBUG"
+# ADD RSC /l 0xc07 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib pd.lib flext_d-pdwin.lib /nologo /dll /debug /machine:I386 /pdbtype:sept /libpath:"c:/programme/audio/pd/bin" /libpath:"..\flext\pd-msvc" /libpath:"f:\prog\packs\Python-2.2.1\PCbuild"
+
+!ELSEIF "$(CFG)" == "py - Win32 Threads Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "py___Win32_Threads_Release"
+# PROP BASE Intermediate_Dir "py___Win32_Threads_Release"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "pd-msvc\tr"
+# PROP Intermediate_Dir "pd-msvc\tr"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GR /GX /O2 /I "c:\programme\audio\pd\src" /I "f:\prog\max\flext" /I "C:\Programme\prog\Python22\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PD" /D "NT" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GR /O2 /I "c:\programme\audio\pd\src" /I "f:\prog\max\flext\source" /I "C:\Programme\prog\Python22\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PD" /D "NT" /D "FLEXT_THREADS" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0xc07 /d "NDEBUG"
+# ADD RSC /l 0xc07 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib pd.lib flext-pdwin.lib /nologo /dll /machine:I386 /libpath:"c:/programme/audio/pd/bin" /libpath:"..\flext\msvc" /libpath:"C:\Programme\prog\Python22\libs"
+# ADD LINK32 kernel32.lib user32.lib pd.lib flext_t-pdwin.lib pthreadVC.lib /nologo /dll /machine:I386 /out:"pd-msvc\py.dll" /libpath:"c:/programme/audio/pd/bin" /libpath:"..\flext\pd-msvc" /libpath:"C:\Programme\prog\Python22\libs"
+
+!ELSEIF "$(CFG)" == "py - Win32 Threads Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "py___Win32_Threads_Debug"
+# PROP BASE Intermediate_Dir "py___Win32_Threads_Debug"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "pd-msvc\td"
+# PROP Intermediate_Dir "pd-msvc\td"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GR /GX /ZI /Od /I "c:\programme\audio\pd\src" /I "f:\prog\max\flext" /I "C:\Programme\prog\Python22\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PD" /D "NT" /FR /YX /FD /GZ /c
+# ADD CPP /nologo /MTd /W3 /Gm /GR /GX /ZI /Od /I "c:\programme\audio\pd\src" /I "f:\prog\max\flext\source" /I "C:\Programme\prog\Python22\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PD" /D "NT" /D "FLEXT_THREADS" /FR /YX /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0xc07 /d "_DEBUG"
+# ADD RSC /l 0xc07 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib pd.lib flext-pdwin.lib /nologo /dll /debug /machine:I386 /pdbtype:sept /libpath:"c:/programme/audio/pd/bin" /libpath:"..\flext\msvc-debug" /libpath:"f:\prog\packs\Python-2.2.1\PCbuild"
+# ADD LINK32 kernel32.lib user32.lib pd.lib flext_td-pdwin.lib pthreadVC.lib /nologo /dll /debug /machine:I386 /pdbtype:sept /libpath:"c:/programme/audio/pd/bin" /libpath:"..\flext\pd-msvc" /libpath:"f:\prog\packs\Python-2.2.1\PCbuild"
+
+!ENDIF
+
+# Begin Target
+
+# Name "py - Win32 Release"
+# Name "py - Win32 Debug"
+# Name "py - Win32 Threads Release"
+# Name "py - Win32 Threads Debug"
+# Begin Group "scripts"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\scripts\script.py
+# End Source File
+# Begin Source File
+
+SOURCE=.\scripts\sendrecv.py
+# End Source File
+# Begin Source File
+
+SOURCE=.\scripts\simple.py
+# End Source File
+# Begin Source File
+
+SOURCE=.\scripts\tcltk.py
+# End Source File
+# Begin Source File
+
+SOURCE=.\scripts\threads.py
+# End Source File
+# End Group
+# Begin Group "doc"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\gpl.txt
+# End Source File
+# Begin Source File
+
+SOURCE=.\license.txt
+# End Source File
+# Begin Source File
+
+SOURCE=.\readme.txt
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=.\source\bound.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\source\clmeth.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\source\main.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\source\main.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\source\modmeth.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\source\py.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\source\pyargs.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\source\pyext.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\source\pyext.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\source\register.cpp
+# End Source File
+# End Target
+# End Project
diff --git a/externals/grill/py/py.mpw b/externals/grill/py/py.mpw
new file mode 100644
index 00000000..54c507a0
--- /dev/null
+++ b/externals/grill/py/py.mpw
@@ -0,0 +1,91 @@
+# py - python script object for PD and MaxMSP
+# Copyright (c) 2002 Thomas Grill (xovo@gmx.net)
+#
+# Makefile for Apple MPW-PR
+#
+# usage: make -f py.mpw
+#
+# ---------------------------------------------
+
+MAKEFILE = py.mpw
+€MondoBuild€ = {MAKEFILE} # Make blank to avoid rebuilds when makefile is modified
+
+Name = py
+
+ObjDir = :MPW:
+MaxSDK = HD Daten:Prog Stuff:Max/MSP SDK:SDK Examples
+flext = ::flext:
+Python = HD Daten:Prog Stuff:Packs:Python-2.2
+PythonIncludes = {Python}:Include
+PythonMacIncludes = {Python}:Mac:Include
+PythonCore = HD MacOS:Applications (Mac OS 9):dev:Python 2.2:PythonCore
+
+
+
+Includes = -i :,"{flext}","{MaxSDK}:Max Includes","{MaxSDK}:MSP Includes","{GUSI}include","{PythonIncludes}","{PythonMacIncludes}"
+### MPW Shell - Command "Includes" was not found.
+
+Defines = -d MAXMSP -d USE_GUSI2
+
+Sym-PPC = -sym off
+Flags = -bool on -enum int -includes unix -opt speed,unroll,unswitch
+
+
+PPCCPlusOptions = {Includes} {Sym-PPC} {Defines} {Flags}
+
+
+### Source Files ###
+
+SrcFiles = main.cpp
+Headers =
+
+
+### Object Files ###
+
+Obj-PPC =
+ "{ObjDir}main.cpp.x"
+
+LibFiles-Ext =
+ "{flext}MPW:flext.o"
+ "{MaxSDK}:Max Includes:MaxLib"
+ "{MaxSDK}:MSP Includes:MaxAudioLib"
+ "{PythonCore}"
+
+### Libraries ###
+
+LibFiles-PPC =
+ "{SharedLibraries}StdCLib"
+ "{SharedLibraries}MathLib"
+ "{PPCLibraries}StdCRuntime.o"
+ "{PPCLibraries}PPCCRuntime.o"
+ "{PPCLibraries}MrCPlusLib.o"
+
+
+### Default Rules ###
+
+{ObjDir} Ÿ :
+
+.cpp.x Ÿ .cpp {€MondoBuild€} {Headers}
+ {PPCCPlus} {depDir}{default}.cpp -o {targDir}{default}.cpp.x {PPCCPlusOptions}
+
+
+### Build Rules ###
+
+all Ÿ Folder {€MondoBuild€} {ObjDir}{Name}
+
+Folder ŸŸ
+ if !`Exists {ObjDir}` ; NewFolder {ObjDir} ; end
+
+{ObjDir}{Name} Ÿ {Obj-PPC}
+ PPCLink
+ -o {Targ}
+ {deps}
+ {LibFiles-Ext}
+ {LibFiles-PPC}
+ {Sym-PPC}
+ -mf -d
+ -t 'iLaF'
+ -c 'max2'
+ -xm s
+ -export main
+ -main main
diff --git a/externals/grill/py/readme.txt b/externals/grill/py/readme.txt
new file mode 100644
index 00000000..fc82880b
--- /dev/null
+++ b/externals/grill/py/readme.txt
@@ -0,0 +1,106 @@
+py/pyext - python script objects for PD (and MaxMSP... once, under MacOSX and Windows)
+
+Copyright (c) 2002 Thomas Grill (xovo@gmx.net)
+For information on usage and redistribution, and for a DISCLAIMER OF ALL
+WARRANTIES, see the file, "license.txt," in this distribution.
+
+Donations for further development of the package are highly appreciated.
+
+----------------------------------------------------------------------------
+
+You will need the flext C++ layer for PD and Max/MSP externals to compile this.
+
+Package files:
+- readme.txt: this one
+- gpl.txt,license.txt: GPL license stuff
+- main.cpp, main.h, modmeth.cpp, pyargs.cpp, register.cpp: base class
+- py.cpp: py object
+- pyext.cpp, pyext.h, clmeth.cpp, bound.cpp: pyext object
+
+----------------------------------------------------------------------------
+
+Goals/features of the package:
+
+Access the flexibility of the python language in PD/MaxMSP
+
+
+PD - Load it as i library with e.g. "pd -lib py -path scripts"
+Max/MSP - Wait for Windows or MacOSX version. MacOS9 doesn't want it.
+
+
+Check out the sample patches and scripts
+
+
+Description:
+
+With the py object you can load python modules and execute the functions therein.
+With the pyext you can use python classes to represent full-featured pd/Max message objects.
+Multithreading (detached methods) is supported for both objects.
+You can send messages to named objects or receive (with pyext) with Python methods.
+
+----------------------------------------------------------------------------
+
+The py/pyext package should run with Python version >= 2.1.
+It has been thoroughly tested with version 2.2
+
+
+The package should at least compile (and is tested) with the following compilers:
+
+pd - Windows:
+-------------
+o Borland C++ 5.5 (free): edit "config-pd-bcc.txt" & run "build-pd-bcc.bat"
+
+o Microsoft Visual C++ 6: edit the project file "py.dsp" & build
+
+pd - linux:
+-----------
+Python doesn't provide a shared lib by default - static linking produces huge externals
+Ok, debian is an exception... the precompiled binary is for debian, therefore.
+
+o GCC: edit "config-pd-linux.txt" & run "sh build-pd-linux.sh"
+
+----------------------------------------------------------------------------
+
+Version history:
+
+0.1.1:
+- FIX: crash when module couldn't be loaded
+- FIX: GetBound method (modmeth.cpp, line 138) doesn't exist in flext any more
+- FIX: deadlock occured when connecting to py/pyext boxes in non-detached mode
+- ADD: current path and path of the canvas is added to the python path
+
+0.1.0:
+- completely reworked all code
+- added class functionality for full-featured objects and renamed the merge to pyext
+- enabled threads and made everything thread-safe ... phew!
+- using flext 0.3.2
+- pyext now gets full python path
+- python's argv[0] is now "py" or "pyext"
+- etc.etc.
+
+0.0.2:
+- fixed bug when calling script with no function defined (thanks to Ben Saylor)
+- cleaner gcc makefile
+
+0.0.1:
+- using flext 0.2.1
+
+---------------------------------------------------------------------------
+
+TODO list:
+
+general:
+- Documentation and better example patches
+
+features:
+- enable multiple interpreters?
+- make a pygui object where Tkinter draws to the PD canvas...
+- stop individual threads
+
+tests:
+- check for python threading support
+
+bugs:
+- the python interpreter can't be unloaded due to some bug at re-initialization
+- named (keyword) arguments are not supported
+
diff --git a/externals/grill/py/scripts/script.py b/externals/grill/py/scripts/script.py
new file mode 100644
index 00000000..4796949c
--- /dev/null
+++ b/externals/grill/py/scripts/script.py
@@ -0,0 +1,53 @@
+# py/pyext - python script objects for PD and MaxMSP
+#
+# Copyright (c) 2002 Thomas Grill (xovo@gmx.net)
+# For information on usage and redistribution, and for a DISCLAIMER OF ALL
+# WARRANTIES, see the file, "license.txt," in this distribution.
+#
+
+"""Several functions to show the py script functionality"""
+
+import sys
+
+print "Script initialized"
+
+try:
+ print "Script arguments: ",sys.argv
+except:
+ print
+
+def numargs(*args): # variable argument list
+ """Return the number of arguments"""
+ return len(args)
+
+def strlen(arg):
+ """Return the string length"""
+ return len(arg)
+
+
+def strcat(*args):
+ """Concatenate several symbols"""
+ s = ""
+ for si in args:
+ s += str(si)
+ return s
+
+
+def addall(*args): # variable argument list
+ s = 0
+ for si in args:
+ s += si
+ return s
+
+
+def ret1():
+ return 1,2,3,4
+
+
+def ret2():
+ return "sd","lk","ki"
+
+
+def ret3():
+ return ["sd","lk","ki"]
+
diff --git a/externals/grill/py/scripts/sendrecv.py b/externals/grill/py/scripts/sendrecv.py
new file mode 100644
index 00000000..f31eae2d
--- /dev/null
+++ b/externals/grill/py/scripts/sendrecv.py
@@ -0,0 +1,173 @@
+# py/pyext - python script objects for PD and MaxMSP
+#
+# Copyright (c) 2002 Thomas Grill (xovo@gmx.net)
+# 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 send/receive functionality.
+
+You can:
+- bind
+
+
+There are several classes exposing py/pyext features:
+- ex1: A class receiving messages and sending them out again
+- ex2: A class receiving messages and putting them out to an outlet
+- ex3: Do some PD scripting
+
+"""
+
+import pyext
+from time import sleep
+
+#################################################################
+
+def recv_gl(arg):
+ """This is a global receive function, it has no access to class members."""
+ print "GLOBAL",arg
+
+class ex1(pyext._class):
+ """Example of a class which receives and sends messages
+
+ It has two creation arguments: a receiver and a sender name.
+ There are no inlets and outlets.
+ Python functions (one global function, one class method) are bound to PD's or Max/MSP's receive symbols.
+ The class method sends the received messages out again.
+ """
+
+
+ # no inlets and outlets
+ _inlets=0
+ _outlets=0
+
+ recvname=""
+ sendname=""
+
+ def recv(self,arg):
+ """This is a class-local receive function, which has access to class members."""
+
+ # print some stuff
+ print "CLASS",self.recvname,arg
+
+ # send data to specified send address
+ self._send(self.sendname,arg)
+
+
+ def __init__(self,args):
+ """Class constructor"""
+
+ # store sender/receiver names
+ if len(args) >= 1: self.recvname = args[0]
+ if len(args) >= 2: self.sendname = args[1]
+
+ # bind functions to receiver names
+ # both are called upon message
+ self._bind(self.recvname,self.recv)
+ self._bind(self.recvname,recv_gl)
+
+
+ def __del__(self):
+ """Class destructor"""
+
+ # you can but you don't need to
+ # unbinding is automatically done at destruction
+ # you can also comment the _unbind lines
+ self._unbind(self.recvname,self.recv)
+ self._unbind(self.recvname,recv_gl)
+
+ pass
+
+
+#################################################################
+
+class ex2(pyext._class):
+ """Example of a class which receives a message and forwards it to an outlet
+
+ It has one creation argument: the receiver name.
+ """
+
+
+ # define inlets and outlets
+ _inlets=0
+ _outlets=1
+
+ recvname=""
+
+ def recv(self,arg):
+ """This is a class-local receive function"""
+
+ # send received data to outlet
+ self._outlet(1,arg)
+
+
+ def __init__(self,rname):
+ """Class constructor"""
+
+ # store receiver names
+ self.recvname = rname
+
+ # bind function to receiver name
+ self._bind(self.recvname,self.recv)
+
+
+#################################################################
+
+from math import sin,cos,pi
+from cmath import exp
+from random import random,randint
+
+class ex3(pyext._class):
+ """Example of a class which does some object manipulation by scripting"""
+
+
+ # define inlets and outlets
+ _inlets=1
+ _outlets=0
+
+ def __init__(self):
+ """Class constructor"""
+
+ # called scripting method should run on its own thread
+ self._detach(1)
+
+
+ def bang_1(self):
+ """Do some scripting - PD only!"""
+
+ num = 12 # number of objects
+ ori = complex(150,150) # origin
+ rad = 100 # radius
+ l = range(num) # initialize list
+
+ # make flower
+ self._tocanvas("obj",ori.real,ori.imag,"bng",20,250,50,0,"empty","yeah","empty",0,-6,64,8,-24198,-1,-1)
+ for i in range(num):
+ l[i] = ori+rad*exp(complex(0,i*2*pi/num))
+ self._tocanvas("obj",l[i].real,l[i].imag,"bng",15,250,50,0,"empty","yeah"+str(i),"empty",0,-6,64,8,0,-1,-1)
+ self._tocanvas("connect",2,0,3+i,0)
+
+ # blink
+ for i in range(10):
+ self._send("yeah","bang")
+ sleep(1./(i+1))
+
+ # move objects around
+ for i in range(200):
+ ix = randint(0,num-1)
+ l[ix] = ori+rad*complex(2*random()-1,2*random()-1)
+ self._send("yeah"+str(ix),"pos",l[ix].real,l[ix].imag)
+ sleep(0.02)
+
+ # now delete
+ # this is not well-done... from time to time an object remains
+ self._tocanvas("editmode",1)
+ for i in range(num):
+ self._tocanvas("mouse",l[i].real,l[i].imag,0,0)
+ self._tocanvas("cut")
+
+ self._tocanvas("mouse",ori.real+1,ori.imag+1,0,0)
+ self._tocanvas("cut")
+
+ self._tocanvas("editmode",0)
+
diff --git a/externals/grill/py/scripts/simple.py b/externals/grill/py/scripts/simple.py
new file mode 100644
index 00000000..60cebec7
--- /dev/null
+++ b/externals/grill/py/scripts/simple.py
@@ -0,0 +1,206 @@
+# py/pyext - python script objects for PD and MaxMSP
+#
+# Copyright (c) 2002 Thomas Grill (xovo@gmx.net)
+# 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 basic functionality.
+
+pyext Usage:
+- Import pyext
+
+- Inherit your class from pyext._class
+
+- Specfiy the number of inlets and outlets:
+ Use the class members (variables) _inlets and _outlets
+ If not given they default to 1
+ You can also use class methods with the same names to return the respective number
+
+- Constructors/Destructors
+ You can specify an __init__ constructor and/or an __del__ destructor.
+ The constructor will be called with the object's arguments
+
+ e.g. if your PD or MaxMSP object looks like
+ [pyext script class arg1 arg2 arg3]
+
+ then the __init__(self,args) function will be called with a tuple argument
+ args = (arg1,arg2,arg3)
+ With this syntax, you will have to give at least one argument.
+ By defining the constructor as __init__(self,*args) you can also initialize
+ the class without arguments.
+
+- Methods called by pyext
+ The general format is 'tag_inlet(self,args)' resp. 'tag_inlet(self,*args)':
+ tag is the PD or MaxMSP message header.. either bang, float, list etc.
+ inlet is the inlet (starting from 1) from which messages are received.
+ args is a tuple which corresponds to the content of the message. args can be omitted.
+
+ The inlet index can be omitted. The method name then has the format 'tag_(self,inlet,args)'.
+ Here, the inlet index is a additional parameter to the method
+
+ You can also set up methods which react on any message. These have the special forms
+ _anything_inlet(self,args)
+ or
+ _anything_(self,inlet,args)
+
+ Please see below for examples.
+
+ Any return values are ignored - use _outlet (see below).
+
+ Generally, you should avoid method_, method_xx forms for your non-pyext class methods.
+ Identifiers (variables and functions) with leading underscores are reserved for pyext.
+
+- Send messages to outlets:
+ Use the inherited _outlet method.
+ You can either use the form
+ 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
+
+- Use pyext functions and methods:
+ See the __doc__ strings of the pyext module and the pyext._class base class.
+
+"""
+
+import pyext
+
+#################################################################
+
+class ex1(pyext._class):
+ """Example of a simple class which receives messages and prints to the console"""
+
+ # number of inlets and outlets
+ _inlets=3
+ _outlets=0
+
+
+ # methods for first inlet
+
+ def bang_1(self):
+ print "Bang into first inlet"
+
+ def float_1(self,f):
+ print "Float ",f," into first inlet"
+
+ def list_1(self,s):
+ print "List ",s," into first inlet"
+
+
+ # methods for second inlet
+
+ def hey_2(self):
+ print "Tag 'hey' into second inlet"
+
+ def ho_2(self):
+ print "Tag 'ho' into second inlet"
+
+ def lets_2(self):
+ print "Tag 'lets' into second inlet"
+
+ def go_2(self):
+ print "Tag 'go' into second inlet"
+
+ def _anything_2(self,args):
+ print "Some other message into second inlet:",args
+
+
+ # methods for third inlet
+
+ def onearg_3(self,a):
+ print "Tag 'onearg' into third inlet:",a
+
+ def twoargs_3(self,a):
+ if len(a) == 2:
+ print "Tag 'twoargs' into third inlet:",a[0],a[1]
+ else:
+ print "Tag 'twoargs': wrong number of arguments"
+
+ def threeargs_3(self,a):
+ if len(a) == 3:
+ print "Tag 'threeargs' into third inlet",a[0],a[1],a[2]
+ else:
+ print "Tag 'threeargs': wrong number of arguments"
+
+ def varargs_3(self,*args):
+ # with *args there can be arguments or not
+
+ print "Tag 'varargs' into third inlet",args
+
+
+
+#################################################################
+
+class ex2(pyext._class):
+ """Example of a simple class which receives messages and writes to outlets"""
+
+ # number of inlets and outlets
+ _inlets=3
+ _outlets=2
+
+ # methods for all inlets
+
+ def hello_(self,n):
+ print "Tag 'hello' into inlet",n
+
+ def _anything_(self,n,args):
+ print "Message into inlet",n,":",args
+
+
+ # methods for first inlet
+
+ def float_1(self,f):
+ self._outlet(2,f)
+
+ # methods for second inlet
+
+ def float_2(self,f):
+ self._outlet(1,f)
+
+
+#################################################################
+
+# helper function - determine whether argument is a numeric type
+def isNumber(value):
+ import types
+ if type(value) in (types.FloatType, types.IntType, types.LongType):
+ return 1
+ else:
+ return 0
+
+
+class ex3(pyext._class):
+ """Example of a simple class doing a typical number addition
+
+ It uses a constructor and a class member as temporary storage.
+ """
+
+ # number of inlets and outlets
+ _inlets=2
+ _outlets=1
+
+ # temporary storage
+ tmp=0
+
+ # constructor
+ def __init__(self,*args):
+ if len(args) == 1:
+ if isNumber(args[0]):
+ self.tmp = args[0]
+ else:
+ print "ex3: __init__ has superfluous arguments"
+
+ # methods
+
+ def float_1(self,f):
+ self._outlet(1,self.tmp+f)
+
+ def float_2(self,f):
+ self.tmp = f
+
+ # handlers for MaxMSP int type
+ def int_1(self,f):
+ self.float_1(f)
+
+ def int_2(self,f):
+ self.float_2(f)
diff --git a/externals/grill/py/scripts/tcltk.py b/externals/grill/py/scripts/tcltk.py
new file mode 100644
index 00000000..154a51b1
--- /dev/null
+++ b/externals/grill/py/scripts/tcltk.py
@@ -0,0 +1,77 @@
+# py/pyext - python script objects for PD and MaxMSP
+#
+# Copyright (c) 2002 Thomas Grill (xovo@gmx.net)
+# 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 showing a nonsense tcl/tk application."""
+
+import pyext
+from Tkinter import *
+import random
+
+
+class Application(Frame):
+ """This is the TK application class"""
+
+ # Button pressed
+ def say_hi(self):
+ self.extcl._outlet(1,"hi there, everyone!")
+
+ # Mouse motion over canvas
+ def evfunc(self, ev):
+ x = random.uniform(-3,3)
+ y = random.uniform(-3,3)
+ self.mcanv.move('group',x,y)
+
+ # Create interface stuff
+ def createWidgets(self):
+ self.hi = Button(self)
+ self.hi["text"] = "Hi!"
+ self.hi["fg"] = "red"
+ self.hi["command"] = self.say_hi
+ self.hi.pack({"side": "left"})
+
+ self.mcanv = Canvas(self)
+ self.mcanv.pack({"side": "left"})
+ self.mcanv.bind("<Motion>", self.evfunc)
+ self.mcanv.create_rectangle(50,50,200,200)
+ r = self.mcanv.create_rectangle(50,50,200,200)
+ self.mcanv.addtag_withtag('group',r)
+
+ for i in range(500):
+ x = random.uniform(50,200)
+ y = random.uniform(50,200)
+ l = self.mcanv.create_line(x,y,x+1,y)
+ self.mcanv.addtag_withtag('group',l)
+
+ # Constructor
+ def __init__(self,cl):
+ self.extcl = cl
+ Frame.__init__(self)
+ self.pack()
+ self.createWidgets()
+ pass
+
+
+# derive class from pyext._class
+
+class myapp(pyext._class):
+ """This class demonstrates how a TCL/TK can be openened from within a pyext external"""
+
+ # how many inlets and outlets?
+ _inlets = 1
+ _outlets = 1
+
+ # Constructor
+ def __init__(self):
+ # detach bang method
+ self._detach(1)
+
+ def bang_1(self):
+ self._priority(-3)
+ # display the tcl/tk dialog
+ app = Application(self)
+ app.mainloop()
+
diff --git a/externals/grill/py/scripts/threads.py b/externals/grill/py/scripts/threads.py
new file mode 100644
index 00000000..e8486699
--- /dev/null
+++ b/externals/grill/py/scripts/threads.py
@@ -0,0 +1,43 @@
+# py/pyext - python script objects for PD and MaxMSP
+#
+# Copyright (c) 2002 Thomas Grill (xovo@gmx.net)
+# 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 threading functionality.
+
+For threading support pyext exposes several function and variables
+
+- _detach([0/1]): by enabling thread detaching, threads will run in their own threads
+- _priority(prio+-): you can raise or lower the priority of the current thread
+- _stop({wait time in ms}): stop all running threads (you can additionally specify a wait time in ms)
+- _shouldexit: this is a flag which indicates that the running thread should terminate
+
+"""
+
+import pyext
+from time import sleep
+
+#################################################################
+
+class ex1(pyext._class):
+ """This is a simple class with one method looping over time."""
+
+ # number of inlets and outlets
+ _inlets=2
+ _outlets=2
+
+ sltime=0.2 # sleep time
+ loops=30 # loops to iterate
+
+ # method for bang to any inlet
+ def bang_(self,n):
+ for i in range(30):
+ # if _shouldexit is true, the thread ought to stop
+ if self._shouldexit: break
+
+ self._outlet(n,i)
+ sleep(self.sltime)
+
+
diff --git a/externals/grill/py/source/bound.cpp b/externals/grill/py/source/bound.cpp
new file mode 100644
index 00000000..651bb52b
--- /dev/null
+++ b/externals/grill/py/source/bound.cpp
@@ -0,0 +1,143 @@
+/*
+
+py/pyext - python external object for PD and MaxMSP
+
+Copyright (c) 2002 Thomas Grill (xovo@gmx.net)
+For information on usage and redistribution, and for a DISCLAIMER OF ALL
+WARRANTIES, see the file, "license.txt," in this distribution.
+
+*/
+
+#include "pyext.h"
+#include "flinternal.h"
+
+t_class *pyext::px_class;
+pyext::py_proxy *pyext::px_head,*pyext::px_tail;
+
+void pyext::py_proxy::px_method(py_proxy *obj,const t_symbol *s,int argc,t_atom *argv)
+{
+ PY_LOCK
+
+ PyObject *args = MakePyArgs(s,AtomList(argc,argv),-1,obj->self != NULL);
+ PyObject *ret = PyObject_CallObject(obj->func,args);
+ if(!ret) {
+ PyErr_Print();
+ }
+ Py_XDECREF(ret);
+
+ PY_UNLOCK
+}
+
+
+PyObject *pyext::pyext_bind(PyObject *,PyObject *args)
+{
+ PyObject *self,*meth;
+ C *name;
+ if(!PyArg_ParseTuple(args, "OsO:pyext_bind", &self,&name,&meth))
+ post("py/pyext - Wrong arguments!");
+ else if(!PyInstance_Check(self) || !(PyMethod_Check(meth) || PyFunction_Check(meth))) {
+ post("py/pyext - Wrong argument types!");
+ }
+ else {
+ t_symbol *recv = gensym(name);
+/*
+ if(GetBound(recv))
+ post("py/pyext - Symbol \"%s\" is already hooked",GetString(recv));
+*/
+ // make a proxy object
+ py_proxy *px = (py_proxy *)object_new(px_class);
+ if(PyMethod_Check(meth)) {
+ PyObject *no = PyObject_GetAttrString(meth,"__name__");
+ meth = PyObject_GetAttr(self,no);
+ Py_DECREF(no);
+ }
+ px->init(recv,self,meth);
+
+ // add it to the list
+ if(px_tail) px_tail->nxt = px;
+ else px_head = px;
+ px_tail = px;
+
+ // Do bind
+ pd_bind(&px->obj.ob_pd,recv);
+
+ Py_INCREF(self); // self is borrowed reference
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyObject *pyext::pyext_unbind(PyObject *,PyObject *args)
+{
+ PyObject *self,*meth;
+ C *name;
+ if(!PyArg_ParseTuple(args, "OsO:pyext_bind", &self,&name,&meth))
+ post("py/pyext - Wrong arguments!");
+ else if(!PyInstance_Check(self) || !(PyMethod_Check(meth) || PyFunction_Check(meth))) {
+ post("py/pyext - Wrong argument types!");
+ }
+ else {
+ t_symbol *recv = gensym(name);
+ if(PyMethod_Check(meth)) {
+ PyObject *no = PyObject_GetAttrString(meth,"__name__");
+ meth = PyObject_GetAttr(self,no); // meth is given a new reference!
+ Py_DECREF(no);
+ }
+
+ // search proxy object
+ py_proxy *pp = NULL,*px = px_head;
+ while(px) {
+ py_proxy *pn = px->nxt;
+ if(recv == px->name && self == px->self && meth == px->func) {
+ if(pp)
+ pp->nxt = pn;
+ else
+ px_head = pn;
+ if(!pn) px_tail = pp;
+ break;
+ }
+ else pp = px;
+ px = pn;
+ }
+
+ // do unbind
+ if(px) {
+ pd_unbind(&px->obj.ob_pd,recv);
+ object_free(px->obj);
+
+ Py_DECREF(self);
+ if(PyMethod_Check(meth)) Py_DECREF(meth);
+ }
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+V pyext::ClearBinding()
+{
+ // search proxy object
+ py_proxy *pp = NULL,*px = px_head;
+ while(px) {
+ py_proxy *pn = px->nxt;
+ if(px->self == pyobj) {
+ if(pp)
+ pp->nxt = pn;
+ else
+ px_head = pn;
+ if(!pn) px_tail = pp;
+
+ Py_DECREF(px->self);
+ if(PyMethod_Check(px->func)) Py_DECREF(px->func);
+
+ pd_unbind(&px->obj.ob_pd,px->name);
+ object_free(px->obj);
+ }
+ else pp = px;
+ px = pn;
+ }
+}
+
+
diff --git a/externals/grill/py/source/clmeth.cpp b/externals/grill/py/source/clmeth.cpp
new file mode 100644
index 00000000..0a30d1f7
--- /dev/null
+++ b/externals/grill/py/source/clmeth.cpp
@@ -0,0 +1,278 @@
+/*
+
+py/pyext - python external object for PD and MaxMSP
+
+Copyright (c) 2002 Thomas Grill (xovo@gmx.net)
+For information on usage and redistribution, and for a DISCLAIMER OF ALL
+WARRANTIES, see the file, "license.txt," in this distribution.
+
+*/
+
+#include "pyext.h"
+
+
+PyMethodDef pyext::meth_tbl[] =
+{
+ {"__init__", pyext::pyext__init__, METH_VARARGS, "Constructor"},
+ {"__del__", pyext::pyext__del__, METH_VARARGS, "Destructor"},
+
+ {"_outlet", pyext::pyext_outlet, METH_VARARGS,"Send message to outlet"},
+ {"_tocanvas", pyext::pyext_tocanvas, METH_VARARGS,"Send message to canvas" },
+
+ { "_bind", pyext::pyext_bind, METH_VARARGS,"Bind function to a receiving symbol" },
+ { "_unbind", pyext::pyext_unbind, METH_VARARGS,"Unbind function from a receiving symbol" },
+#ifdef FLEXT_THREADS
+ { "_detach", pyext::pyext_detach, METH_VARARGS,"Set detach flag for called methods" },
+ { "_stop", pyext::pyext_stop, METH_VARARGS,"Stop running threads" },
+#endif
+ {NULL, NULL, 0, NULL} /* Sentinel */
+};
+
+PyMethodDef pyext::attr_tbl[] =
+{
+ { "__setattr__", pyext::pyext_setattr, METH_VARARGS,"Set class attribute" },
+ { "__getattr__", pyext::pyext_getattr, METH_VARARGS,"Get class attribute" },
+ { NULL, NULL,0,NULL },
+};
+
+
+const C *pyext::pyext_doc =
+ "py/pyext - python external object for PD and MaxMSP, (C)2002 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"
+ "_tocanvas(self,args...): Send a message to the parent canvas\n"
+#ifdef FLEXT_THREADS
+ "_detach(self,int): Define whether a called Python method has its own thread\n"
+#endif
+ "_bind(self,name,func): Bind a python function to a symbol\n"
+ "_unbind(self,name,func): Unbind a python function from a symbol\n"
+;
+
+PyObject* pyext::pyext__init__(PyObject *,PyObject *args)
+{
+// post("pyext.__init__ called");
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyObject* pyext::pyext__del__(PyObject *,PyObject *args)
+{
+// post("pyext.__del__ called");
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyObject* pyext::pyext_setattr(PyObject *,PyObject *args)
+{
+ PyObject *self,*name,*val,*ret = NULL;
+ if(!PyArg_ParseTuple(args, "OOO:test_foo", &self,&name,&val)) {
+ // handle error
+ ERRINTERNAL();
+ return NULL;
+ }
+
+ BL handled = false;
+ if(PyString_Check(name)) {
+ char* sname = PyString_AsString(name);
+ if (sname) {
+// post("pyext::setattr %s",sname);
+ }
+ }
+
+ if(!handled) {
+ if(PyInstance_Check(self))
+ PyDict_SetItem(((PyInstanceObject *)self)->in_dict, name,val);
+ else
+ ERRINTERNAL();
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyObject* pyext::pyext_getattr(PyObject *,PyObject *args)
+{
+ PyObject *self,*name,*ret = NULL;
+ if(!PyArg_ParseTuple(args, "OO:test_foo", &self,&name)) {
+ // handle error
+ ERRINTERNAL();
+ }
+
+ if(PyString_Check(name)) {
+ char* sname = PyString_AsString(name);
+ if (sname) {
+ if(!strcmp(sname,"_shouldexit")) {
+ pyext *ext = GetThis(self);
+ if(ext)
+ ret = PyLong_FromLong(ext->shouldexit?1:0);
+ }
+// post("pyext::getattr %s",sname);
+ }
+ }
+
+ if(!ret) {
+#if PY_VERSION_HEX >= 0x02020000
+ ret = PyObject_GenericGetAttr(self,name);
+#else
+ if(PyInstance_Check(self))
+ ret = PyDict_GetItem(((PyInstanceObject *)self)->in_dict,name);
+#endif
+ }
+ return ret;
+}
+
+
+//! Send message to outlet
+PyObject *pyext::pyext_outlet(PyObject *,PyObject *args)
+{
+ BL ok = false;
+ if(PySequence_Check(args)) {
+ PyObject *self = PySequence_GetItem(args,0);
+ PyObject *outl = PySequence_GetItem(args,1);
+ if(
+ self && PyInstance_Check(self) &&
+ outl && PyInt_Check(outl)
+ ) {
+ pyext *ext = GetThis(self);
+
+ I sz = PySequence_Size(args);
+ PyObject *val;
+ BL tp = sz == 3 && PySequence_Check(PySequence_GetItem(args,2));
+
+ if(tp)
+ val = PySequence_GetItem(args,2); // borrowed
+ else
+ val = PySequence_GetSlice(args,2,sz); // new ref
+
+ AtomList *lst = GetPyArgs(val);
+ if(lst) {
+ I o = PyInt_AsLong(outl);
+ if(o >= 1 && o <= ext->Outlets()) {
+ // by using the queue there is no immediate call of the next object
+ // deadlock would occur if this was another py/pyext object!
+ if(lst->Count() && IsSymbol((*lst)[0]))
+ ext->ToQueueAnything(o-1,GetSymbol((*lst)[0]),lst->Count()-1,lst->Atoms()+1);
+ else
+ ext->ToQueueList(o-1,*lst);
+ }
+ else
+ post("pyext: outlet index out of range");
+
+ ok = true;
+ }
+ else
+ post("py/pyext - No data to send");
+ if(lst) delete lst;
+
+ if(!tp) Py_DECREF(val);
+ }
+ }
+
+ if(!ok) post("pyext - Syntax: _outlet(self,outlet,args...)");
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+
+#ifdef FLEXT_THREADS
+//! Detach threads
+PyObject *pyext::pyext_detach(PyObject *,PyObject *args)
+{
+ PyObject *self;
+ int val;
+ if(!PyArg_ParseTuple(args, "Oi:pyext_detach",&self,&val)) {
+ // handle error
+ post("pyext - Syntax: _detach(self,[0/1])");
+ }
+ else {
+ pyext *ext = GetThis(self);
+ ext->m_detach(val != 0);
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+//! Stop running threads
+PyObject *pyext::pyext_stop(PyObject *,PyObject *args)
+{
+ PyObject *self;
+ int val = -1;
+ if(!PyArg_ParseTuple(args, "O|i:pyext_stop",&self,&val)) {
+ // handle error
+ post("pyext - Syntax: _stop(self,{wait time}");
+ }
+ else {
+ pyext *ext = GetThis(self);
+ I cnt = 0;
+ t_atom at;
+ if(val >= 0) flext::SetInt(at,val);
+ ext->m_stop(cnt,&at);
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+#endif
+
+//! Send message to canvas
+PyObject *pyext::pyext_tocanvas(PyObject *,PyObject *args)
+{
+ BL ok = false;
+ if(PySequence_Check(args)) {
+ PyObject *self = PySequence_GetItem(args,0);
+ if(self && PyInstance_Check(self)) {
+ pyext *ext = GetThis(self);
+
+#ifdef PD
+ I sz = PySequence_Size(args);
+ PyObject *val;
+ BL tp = sz == 2 && PySequence_Check(PyTuple_GetItem(args,1));
+
+ if(tp)
+ val = PySequence_GetItem(args,1); // borrowed
+ else
+ val = PySequence_GetSlice(args,1,sz); // new ref
+
+ AtomList *lst = GetPyArgs(val);
+ if(lst) {
+ t_glist *gl = ext->thisCanvas(); //canvas_getcurrent();
+ t_class **cl = (t_pd *)gl;
+ if(cl) {
+#ifdef PD
+ pd_forwardmess(cl,lst->Count(),lst->Atoms());
+#else
+ #pragma message ("Send is not implemented")
+#endif
+ }
+#ifdef _DEBUG
+ else
+ post("pyext - no parent canvas?!");
+#endif
+ ok = true;
+ }
+ else
+ post("py/pyext - No data to send");
+ if(lst) delete lst;
+
+ if(!tp) Py_DECREF(val);
+#else
+#pragma message ("Not implemented for MaxMSP")
+#endif
+ }
+ }
+
+ if(!ok) post("pyext - Syntax: _tocanvas(self,args...)");
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+
diff --git a/externals/grill/py/source/main.cpp b/externals/grill/py/source/main.cpp
new file mode 100644
index 00000000..65e1d274
--- /dev/null
+++ b/externals/grill/py/source/main.cpp
@@ -0,0 +1,212 @@
+/*
+
+py/pyext - python external object for PD and MaxMSP
+
+Copyright (c) 2002 Thomas Grill (xovo@gmx.net)
+For information on usage and redistribution, and for a DISCLAIMER OF ALL
+WARRANTIES, see the file, "license.txt," in this distribution.
+
+*/
+
+#include "main.h"
+
+
+V py::lib_setup()
+{
+ post("");
+ post("py/pyext %s - python script objects, (C)2002 Thomas Grill",PY__VERSION);
+ post("");
+
+ FLEXT_SETUP(pyobj);
+ FLEXT_SETUP(pyext);
+
+ pyref = 0;
+}
+
+FLEXT_LIB_SETUP(py,py::lib_setup)
+
+PyInterpreterState *py::pystate = NULL;
+
+
+I py::pyref = 0;
+PyObject *py::module_obj = NULL;
+PyObject *py::module_dict = NULL;
+
+
+py::py():
+ module(NULL),
+ detach(false),shouldexit(false),thrcount(0),
+ clk(NULL),stoptick(0)
+{
+ Lock();
+ // under Max/MSP: doesn't survive next line.....
+
+ if(!(pyref++)) {
+ Py_Initialize();
+
+ #ifdef FLEXT_THREADS
+ PyEval_InitThreads();
+
+ pystate = PyThreadState_Get()->interp;
+ #endif
+ // register/initialize pyext module only once!
+ module_obj = Py_InitModule(PYEXT_MODULE, func_tbl);
+ module_dict = PyModule_GetDict(module_obj);
+
+ PyModule_AddStringConstant(module_obj,"__doc__",(C *)py_doc);
+
+ #ifdef FLEXT_THREADS
+ pythrmain = PyEval_SaveThread();
+ #endif
+ }
+ else {
+ PY_LOCK
+ Py_INCREF(module_obj);
+ Py_INCREF(module_dict);
+ PY_UNLOCK
+ }
+
+ Unlock();
+
+ clk = clock_new(this,(t_method)tick);
+}
+
+py::~py()
+{
+ if(thrcount) {
+ shouldexit = true;
+
+ // Wait for a certain time
+ for(int i = 0; i < (PY_STOP_WAIT/PY_STOP_TICK) && thrcount; ++i) Sleep((F)(PY_STOP_TICK/1000.));
+
+ // Wait forever
+ post("%s - Waiting for thread termination!",thisName());
+ while(thrcount) Sleep(0.2f);
+ post("%s - Okay, all threads have terminated",thisName());
+ }
+
+/*
+ // don't unregister
+
+ Lock();
+
+ if(!(--pyref)) {
+ Py_DECREF(module_obj);
+ module_obj = NULL;
+ Py_DECREF(module_dict);
+ module_dict = NULL;
+
+ Py_XDECREF(module);
+
+// delete modules; modules = NULL;
+
+ PyEval_AcquireThread(pythrmain);
+ PyThreadState *new_state = PyThreadState_New(pystate); // must have lock
+ PyThreadState *prev_state = PyThreadState_Swap(new_state);
+
+ Py_Finalize();
+ }
+
+ Unlock();
+*/
+ if(clk) clock_free(clk);
+}
+
+
+V py::m_doc()
+{
+ if(dict) {
+ PyObject *docf = PyDict_GetItemString(dict,"__doc__"); // borrowed!!!
+ if(docf && PyString_Check(docf)) {
+ post("");
+ post(PyString_AsString(docf));
+ }
+ }
+}
+
+
+
+
+V py::SetArgs(I argc,t_atom *argv)
+{
+ // script arguments
+ C **sargv = new C *[argc+1];
+ for(int i = 0; i <= argc; ++i) {
+ sargv[i] = new C[256];
+ if(!i)
+ strcpy(sargv[i],thisName());
+ 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;
+}
+
+V py::ImportModule(const C *name)
+{
+ if(!name) return;
+
+ module = PyImport_ImportModule((C *)name);
+ if (!module) {
+ PyErr_Print();
+ dict = NULL;
+ }
+ else
+ dict = PyModule_GetDict(module); // borrowed
+
+}
+
+
+V py::ReloadModule()
+{
+ if(module) {
+ PyObject *newmod = PyImport_ReloadModule(module);
+ if(!newmod) {
+ PyErr_Print();
+ // old module still exists?!
+// dict = NULL;
+ }
+ else {
+ Py_XDECREF(module);
+ module = newmod;
+ dict = PyModule_GetDict(module); // borrowed
+ }
+ }
+ else
+ post("%s - No module to reload",thisName());
+}
+
+V py::GetModulePath(const C *mod,C *dir,I len)
+{
+#ifdef PD
+ // uarghh... pd doesn't show it's path for extra modules
+
+ C *name;
+ I fd = open_via_path("",mod,".py",dir,&name,len,0);
+ if(fd > 0) close(fd);
+ else name = NULL;
+
+ // if dir is current working directory... name points to dir
+ if(dir == name) strcpy(dir,".");
+#elif defined(MAXMSP)
+ *dir = 0;
+#endif
+}
+
+V py::AddToPath(const C *dir)
+{
+ if(dir && *dir) {
+ PyObject *pobj = PySys_GetObject("path");
+ if(pobj && PyList_Check(pobj)) {
+ PyObject *ps = PyString_FromString(dir);
+ PyList_Append(pobj,ps);
+ }
+ PySys_SetObject("path",pobj);
+ }
+}
+
+
diff --git a/externals/grill/py/source/main.h b/externals/grill/py/source/main.h
new file mode 100644
index 00000000..66b332cf
--- /dev/null
+++ b/externals/grill/py/source/main.h
@@ -0,0 +1,147 @@
+/*
+
+py/pyext - python script object for PD and MaxMSP
+
+Copyright (c) 2002 Thomas Grill (xovo@gmx.net)
+For information on usage and redistribution, and for a DISCLAIMER OF ALL
+WARRANTIES, see the file, "license.txt," in this distribution.
+
+*/
+
+#ifndef __MAIN_H
+#define __MAIN_H
+
+#include <flext.h>
+#include <Python.h>
+#ifndef NT
+#include <unistd.h>
+#endif
+
+#if !defined(FLEXT_VERSION) || (FLEXT_VERSION < 400)
+#error You need at least flext version 0.4.0
+#endif
+
+#define PY__VERSION "0.1.1pre3"
+
+
+#define PYEXT_MODULE "pyext" // name for module
+#define PYEXT_CLASS "_class" // name for base class
+
+#define PY_STOP_WAIT 1000 // ms
+#define PY_STOP_TICK 10 // ms
+
+
+
+#define I int
+#define C char
+#define V void
+#define BL bool
+#define F float
+#define D double
+
+
+#include "main.h"
+
+class py:
+ public flext_base
+{
+ FLEXT_HEADER(py,flext_base)
+
+public:
+ py();
+ ~py();
+ static V lib_setup();
+
+ static PyObject *MakePyArgs(const t_symbol *s,const AtomList &args,I inlet = -1,BL withself = false);
+ static AtomList *GetPyArgs(PyObject *pValue,PyObject **self = NULL);
+
+protected:
+
+ V m_doc();
+
+ PyObject *module,*dict; // inherited user class module and associated dictionary
+
+ static I pyref;
+ static const C *py_doc;
+
+ V GetModulePath(const C *mod,C *dir,I len);
+ V AddToPath(const C *dir);
+ V SetArgs(I argc,t_atom *argv);
+ V ImportModule(const C *name);
+ V ReloadModule();
+
+ V Register(const C *reg);
+ V Unregister(const C *reg);
+ V Reregister(const C *reg);
+ virtual V Reload() = 0;
+
+ static BL IsAnything(const t_symbol *s) { return s && s != sym_bang && s != sym_float && s != sym_int && s != sym_symbol && s != sym_list && s != sym_pointer; }
+
+ enum retval { nothing,atom,sequ /*,tuple,list*/ };
+
+ // --- module stuff -----
+
+ static PyObject *module_obj,*module_dict;
+ static PyMethodDef func_tbl[];
+
+ static PyObject *py__doc__(PyObject *,PyObject *args);
+ static PyObject *py_send(PyObject *,PyObject *args);
+#ifdef FLEXT_THREADS
+ static PyObject *py_priority(PyObject *,PyObject *args);
+#endif
+
+ static PyObject *py_samplerate(PyObject *,PyObject *args);
+ static PyObject *py_blocksize(PyObject *,PyObject *args);
+ static PyObject *py_inchannels(PyObject *,PyObject *args);
+ static PyObject *py_outchannels(PyObject *,PyObject *args);
+
+ // ----thread stuff ------------
+
+ V m_detach(BL det) { detach = det; }
+ virtual V m_stop(int argc,t_atom *argv);
+
+ BL detach,shouldexit;
+ I thrcount;
+ t_clock *clk;
+ I stoptick;
+
+ static V tick(py *obj);
+
+public:
+ static PyInterpreterState *pystate;
+ PyThreadState *pythrmain;
+
+#ifdef FLEXT_THREADS
+ ThrMutex mutex;
+ V Lock() { mutex.Unlock(); }
+ V Unlock() { mutex.Unlock(); }
+#else
+ V Lock() {}
+ V Unlock() {}
+#endif
+
+protected:
+ // callbacks
+
+ FLEXT_CALLBACK_B(m_detach)
+ FLEXT_CALLBACK_V(m_stop)
+ FLEXT_CALLBACK(m_doc)
+};
+
+#ifdef FLEXT_THREADS
+#define PY_LOCK \
+ { \
+ PyThreadState *thrst = PyThreadState_New(pystate); \
+ PyEval_AcquireThread(thrst);
+
+#define PY_UNLOCK \
+ PyThreadState_Clear(thrst); /* must have lock */ \
+ PyEval_ReleaseThread(thrst); \
+ PyThreadState_Delete(thrst); /* needn't have lock */ \
+ }
+#else
+#define PY_LOCK
+#define PY_UNLOCK
+#endif
+
+#endif
diff --git a/externals/grill/py/source/modmeth.cpp b/externals/grill/py/source/modmeth.cpp
new file mode 100644
index 00000000..51e103ed
--- /dev/null
+++ b/externals/grill/py/source/modmeth.cpp
@@ -0,0 +1,183 @@
+/*
+
+py/pyext - python external object for PD and MaxMSP
+
+Copyright (c) 2002 Thomas Grill (xovo@gmx.net)
+For information on usage and redistribution, and for a DISCLAIMER OF ALL
+WARRANTIES, see the file, "license.txt," in this distribution.
+
+*/
+
+#include "main.h"
+
+
+// function table for module
+PyMethodDef py::func_tbl[] =
+{
+ { "_send", py::py_send, METH_VARARGS,"Send message to a named object" },
+#ifdef FLEXT_THREADS
+ { "_priority", py::py_priority, METH_VARARGS,"Set priority of current thread" },
+#endif
+
+ { "_samplerate", py::py_samplerate, 0,"Get system sample rate" },
+ { "_blocksize", py::py_blocksize, 0,"Get system block size" },
+ { "_inchannels", py::py_inchannels, 0,"Get number of audio in channels" },
+ { "_outchannels", py::py_outchannels, 0,"Get number of audio out channels" },
+
+ {NULL, NULL, 0, NULL} // sentinel
+};
+
+const C *py::py_doc =
+ "py/pyext - python external object for PD and MaxMSP, (C)2002 Thomas Grill\n"
+ "\n"
+ "This is the pyext module. Available function:\n"
+ "_send(args...): Send a message to a send symbol\n"
+#ifdef FLEXT_THREADS
+ "_priority(int): Raise/lower thread priority\n"
+#endif
+ "_samplerate(): Get system sample rate\n"
+ "_blocksize(): Get current blocksize\n"
+ "_inchannels(): Get number of audio in channels\n"
+ "_outchannels(): Get number of audio out channels\n"
+;
+
+
+
+V py::tick(py *th)
+{
+ th->Lock();
+
+ if(!th->thrcount) {
+ // all threads have stopped
+ th->shouldexit = false;
+ th->stoptick = 0;
+ }
+ else {
+ // still active threads
+ if(!--th->stoptick) {
+ post("%s - Threads couldn't be stopped entirely - %i remaining",th->thisName(),th->thrcount);
+ th->shouldexit = false;
+ }
+ else
+ // continue waiting
+ clock_delay(th->clk,PY_STOP_TICK);
+ }
+
+ th->Unlock();
+}
+
+V py::m_stop(int argc,t_atom *argv)
+{
+ if(thrcount) {
+ Lock();
+
+ I wait = PY_STOP_WAIT;
+ if(argc >= 1 && CanbeInt(argv[0])) wait = GetAInt(argv[0]);
+
+ I ticks = wait/PY_STOP_TICK;
+ if(stoptick) {
+ // already stopping
+ if(ticks < stoptick) stoptick = ticks;
+ }
+ else
+ stoptick = ticks;
+ shouldexit = true;
+ clock_delay(clk,PY_STOP_TICK);
+
+ Unlock();
+ }
+
+}
+
+PyObject *py::py_samplerate(PyObject *self,PyObject *args)
+{
+ return PyFloat_FromDouble(sys_getsr());
+}
+
+PyObject *py::py_blocksize(PyObject *self,PyObject *args)
+{
+ return PyLong_FromLong(sys_getblksize());
+}
+
+PyObject *py::py_inchannels(PyObject *self,PyObject *args)
+{
+#ifdef PD
+ I ch = sys_get_inchannels();
+#else // MAXMSP
+ I ch = sys_getch(); // not functioning
+#endif
+ return PyLong_FromLong(ch);
+}
+
+PyObject *py::py_outchannels(PyObject *self,PyObject *args)
+{
+#ifdef PD
+ I ch = sys_get_outchannels();
+#else // MAXMSP
+ I ch = sys_getch(); // not functioning
+#endif
+ return PyLong_FromLong(ch);
+}
+
+PyObject *py::py_send(PyObject *,PyObject *args)
+{
+ if(PySequence_Check(args)) {
+ PyObject *name = PySequence_GetItem(args,0); // borrowed
+ if(name && PyString_Check(name)) {
+ const t_symbol *recv = MakeSymbol(PyString_AsString(name));
+ I sz = PySequence_Size(args);
+ PyObject *val;
+ BL tp = sz == 2 && PySequence_Check(PySequence_GetItem(args,1));
+
+ if(tp)
+ val = PySequence_GetItem(args,1); // borrowed
+ else
+ val = PySequence_GetSlice(args,1,sz); // new ref
+
+ AtomList *lst = GetPyArgs(val);
+ if(lst) {
+// t_class **cl = (t_class **)GetBound(recv);
+ t_class **cl = (t_class **)recv->s_thing;
+ if(cl) {
+#ifdef PD
+ pd_forwardmess(cl,lst->Count(),lst->Atoms());
+#else
+ #pragma message ("Send is not implemented")
+#endif
+ }
+#ifdef _DEBUG
+ else
+ post("py/pyext - Receiver doesn't exist");
+#endif
+ }
+ else
+ post("py/pyext - No data to send");
+ if(lst) delete lst;
+
+ if(!tp) Py_DECREF(val);
+ }
+ else
+ post("py/pyext - Send name is invalid");
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+#ifdef FLEXT_THREADS
+PyObject *py::py_priority(PyObject *self,PyObject *args)
+{
+ int val;
+ if(!PyArg_ParseTuple(args, "i:py_priority", &val)) {
+ post("py/pyext - Syntax: _priority [int]");
+ }
+ else
+ ChangePriority(val);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+#endif
+
+
+
diff --git a/externals/grill/py/source/py.cpp b/externals/grill/py/source/py.cpp
new file mode 100644
index 00000000..83c5d9b5
--- /dev/null
+++ b/externals/grill/py/source/py.cpp
@@ -0,0 +1,327 @@
+/*
+
+py/pyext - python script object for PD and MaxMSP
+
+Copyright (c) 2002 Thomas Grill (xovo@gmx.net)
+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 pyobj:
+ public py
+{
+ FLEXT_HEADER(pyobj,py)
+
+public:
+ pyobj(I argc,t_atom *argv);
+ ~pyobj();
+
+protected:
+ BL m_method_(I n,const t_symbol *s,I argc,t_atom *argv);
+
+ V work(const t_symbol *s,I argc,t_atom *argv);
+
+ V m_bang() { work(sym_bang,0,NULL); }
+ V m_reload();
+ V m_reload_(I argc,t_atom *argv);
+ V m_set(I argc,t_atom *argv);
+ V m_doc_();
+
+ virtual V m_help();
+
+ // methods for python arguments
+ V callwork(const t_symbol *s,I argc,t_atom *argv);
+
+ V m_py_list(I argc,t_atom *argv) { callwork(sym_list,argc,argv); }
+ V m_py_float(I argc,t_atom *argv) { callwork(sym_float,argc,argv); }
+ V m_py_int(I argc,t_atom *argv) { callwork(sym_int,argc,argv); }
+ V m_py_any(const t_symbol *s,I argc,t_atom *argv) { callwork(s,argc,argv); }
+
+ const t_symbol *funname;
+ PyObject *function;
+
+ virtual V Reload();
+
+ V SetFunction(const C *func);
+ V ResetFunction();
+
+private:
+
+ FLEXT_CALLBACK(m_bang)
+ FLEXT_CALLBACK(m_reload)
+ FLEXT_CALLBACK_V(m_reload_)
+ FLEXT_CALLBACK_V(m_set)
+ FLEXT_CALLBACK(m_doc_)
+
+ FLEXT_CALLBACK_V(m_py_float)
+ FLEXT_CALLBACK_V(m_py_list)
+ FLEXT_CALLBACK_V(m_py_int)
+ FLEXT_CALLBACK_A(m_py_any)
+
+#ifdef FLEXT_THREADS
+ FLEXT_THREAD_A(work)
+#else
+ FLEXT_CALLBACK_A(work)
+#endif
+};
+
+FLEXT_LIB_V("py",pyobj)
+
+
+pyobj::pyobj(I argc,t_atom *argv):
+ function(NULL),funname(NULL)
+{
+ PY_LOCK
+
+ AddInAnything(2);
+ AddOutAnything();
+
+ FLEXT_ADDBANG(0,m_bang);
+ FLEXT_ADDMETHOD_(0,"reload",m_reload_);
+ FLEXT_ADDMETHOD_(0,"reload.",m_reload);
+ FLEXT_ADDMETHOD_(0,"set",m_set);
+ FLEXT_ADDMETHOD_(0,"doc",m_doc);
+ FLEXT_ADDMETHOD_(0,"doc+",m_doc_);
+#ifdef FLEXT_THREADS
+ FLEXT_ADDMETHOD_(0,"detach",m_detach);
+ FLEXT_ADDMETHOD_(0,"stop",m_stop);
+#endif
+
+ FLEXT_ADDMETHOD_(1,"float",m_py_float);
+ FLEXT_ADDMETHOD_(1,"int",m_py_int);
+ FLEXT_ADDMETHOD(1,m_py_list);
+ FLEXT_ADDMETHOD(1,m_py_any);
+
+ if(argc > 2)
+ SetArgs(argc-2,argv+2);
+ else
+ SetArgs(0,NULL);
+
+ // init script module
+ if(argc >= 1) {
+ C dir[1024];
+ GetModulePath(GetString(argv[0]),dir,sizeof(dir));
+ // set script path
+ AddToPath(dir);
+
+ if(!IsString(argv[0]))
+ post("%s - script name argument is invalid",thisName());
+ else
+ ImportModule(GetString(argv[0]));
+ }
+
+ Register("_py");
+
+ if(argc >= 2) {
+ // set function name
+ if(!IsString(argv[1]))
+ post("%s - function name argument is invalid",thisName());
+ else {
+ // Set function
+ SetFunction(GetString(argv[1]));
+ }
+ }
+
+ PY_UNLOCK
+}
+
+pyobj::~pyobj()
+{
+ PY_LOCK
+ Unregister("_py");
+ PY_UNLOCK
+}
+
+
+
+
+BL pyobj::m_method_(I n,const t_symbol *s,I argc,t_atom *argv)
+{
+ if(n == 1)
+ post("%s - no method for type %s",thisName(),GetString(s));
+ return false;
+}
+
+V pyobj::m_reload()
+{
+ PY_LOCK
+
+ Unregister("_py");
+
+ ReloadModule();
+ Reregister("_py");
+ Register("_py");
+ SetFunction(funname?GetString(funname):NULL);
+
+ PY_UNLOCK
+}
+
+V pyobj::m_reload_(I argc,t_atom *argv)
+{
+ PY_LOCK
+ SetArgs(argc,argv);
+ PY_UNLOCK
+
+ m_reload();
+}
+
+V pyobj::m_set(I argc,t_atom *argv)
+{
+ PY_LOCK
+
+ I ix = 0;
+ if(argc >= 2) {
+ if(!IsString(argv[ix])) {
+ post("%s - script name is not valid",thisName());
+ return;
+ }
+ const C *sn = GetString(argv[ix]);
+
+ if(!module || !strcmp(sn,PyModule_GetName(module))) {
+ ImportModule(sn);
+ Register("_py");
+ }
+
+ ++ix;
+ }
+
+ if(!IsString(argv[ix]))
+ post("%s - function name is not valid",thisName());
+ else
+ SetFunction(GetString(argv[ix]));
+
+ PY_UNLOCK
+}
+
+
+V pyobj::m_doc_()
+{
+ PY_LOCK
+
+ if(function) {
+ PyObject *docf = PyObject_GetAttrString(function,"__doc__"); // borrowed!!!
+ if(docf && PyString_Check(docf)) {
+ post("");
+ post(PyString_AsString(docf));
+ }
+ }
+
+ PY_UNLOCK
+}
+
+
+V pyobj::m_help()
+{
+ post("");
+ post("py %s - python script object, (C)2002 Thomas Grill",PY__VERSION);
+#ifdef _DEBUG
+ post("compiled on " __DATE__ " " __TIME__);
+#endif
+
+ post("Arguments: %s [script name] [function 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");
+#ifdef FLEXT_THREADS
+ post("\tdetach 0/1: detach threads");
+ post("\tstop {wait time (ms)}: stop threads");
+#endif
+ post("");
+}
+
+V pyobj::ResetFunction()
+{
+ if(!module || !dict)
+ {
+ post("%s - No module loaded",thisName());
+ function = NULL;
+ return;
+ }
+
+ function = funname?PyDict_GetItemString(dict,(C *)GetString(funname)):NULL; // borrowed!!!
+ if(!function) {
+ PyErr_Clear();
+ if(funname) post("%s - Function %s could not be found",thisName(),GetString(funname));
+ }
+ else if(!PyFunction_Check(function)) {
+ post("%s - Object %s is not a function",thisName(),GetString(funname));
+ function = NULL;
+ }
+}
+
+V pyobj::SetFunction(const C *func)
+{
+ if(func) {
+ funname = MakeSymbol(func);
+ ResetFunction();
+ }
+ else
+ function = NULL,funname = NULL;
+}
+
+
+V pyobj::Reload()
+{
+ ResetFunction();
+}
+
+
+V pyobj::work(const t_symbol *s,I argc,t_atom *argv)
+{
+ AtomList *rargs = NULL;
+
+ ++thrcount;
+ PY_LOCK
+
+ if(function) {
+ PyObject *pArgs = MakePyArgs(s,AtomList(argc,argv));
+ PyObject *pValue = PyObject_CallObject(function, pArgs);
+
+ rargs = GetPyArgs(pValue);
+ if(!rargs) PyErr_Print();
+
+ Py_XDECREF(pArgs);
+ Py_XDECREF(pValue);
+ }
+ else {
+ post("%s: no function defined",thisName());
+ }
+
+ PY_UNLOCK
+ --thrcount;
+
+ if(rargs) {
+ // call to outlet _outside_ the Mutex lock!
+ // otherwise (if not detached) deadlock will occur
+ ToOutList(0,*rargs);
+ delete rargs;
+ }
+}
+
+V pyobj::callwork(const t_symbol *s,I argc,t_atom *argv)
+{
+ if(detach) {
+ if(shouldexit)
+ post("%s - New threads can't be launched now!",thisName());
+ else
+ if(!FLEXT_CALLMETHOD_A(work,s,argc,argv))
+ post("%s - Failed to launch thread!",thisName());
+ }
+ else
+ work(s,argc,argv);
+}
+
+
diff --git a/externals/grill/py/source/pyargs.cpp b/externals/grill/py/source/pyargs.cpp
new file mode 100644
index 00000000..be4adaa1
--- /dev/null
+++ b/externals/grill/py/source/pyargs.cpp
@@ -0,0 +1,131 @@
+/*
+
+py/pyext - python external object for PD and MaxMSP
+
+Copyright (c) 2002 Thomas Grill (xovo@gmx.net)
+For information on usage and redistribution, and for a DISCLAIMER OF ALL
+WARRANTIES, see the file, "license.txt," in this distribution.
+
+*/
+
+#include "main.h"
+
+
+PyObject *py::MakePyArgs(const t_symbol *s,const AtomList &args,I inlet,BL withself)
+{
+ PyObject *pArgs;
+
+ BL any = IsAnything(s);
+ pArgs = PyTuple_New(args.Count()+(any?1:0)+(inlet >= 0?1:0));
+
+ I pix = 0;
+
+ if(inlet >= 0) {
+ PyObject *pValue = PyInt_FromLong(inlet);
+
+ // reference stolen:
+ PyTuple_SetItem(pArgs, pix++, pValue);
+ }
+
+ I ix;
+ PyObject *tmp;
+ if(!withself || args.Count() < (any?1:2)) tmp = pArgs,ix = pix;
+ else tmp = PyTuple_New(args.Count()+(any?1:0)),ix = 0;
+
+ if(any) {
+ PyObject *pValue = PyString_FromString(GetString(s));
+
+ // reference stolen here:
+ PyTuple_SetItem(tmp, ix++, pValue);
+ }
+
+ for(I i = 0; i < args.Count(); ++i) {
+ PyObject *pValue = NULL;
+
+ if(IsFloat(args[i])) pValue = PyFloat_FromDouble((D)GetFloat(args[i]));
+ else if(IsInt(args[i])) pValue = PyInt_FromLong(GetInt(args[i]));
+ else if(IsSymbol(args[i])) pValue = PyString_FromString(GetString(args[i]));
+ else if(IsPointer(args[i])) pValue = NULL; // not handled
+
+ if(!pValue) {
+ post("py/pyext: cannot convert argument %i",any?i+1:i);
+ continue;
+ }
+
+ /* pValue reference stolen here: */
+ PyTuple_SetItem(tmp, ix++, pValue);
+ }
+
+ if(tmp != pArgs) {
+ PyTuple_SetItem(pArgs, pix++, tmp);
+#if PY_VERSION_HEX >= 0x02020000
+ _PyTuple_Resize(&pArgs,pix);
+#else
+ _PyTuple_Resize(&pArgs,pix,0);
+#endif
+ }
+
+ return pArgs;
+}
+
+flext::AtomList *py::GetPyArgs(PyObject *pValue,PyObject **self)
+{
+ if(pValue == NULL) return NULL;
+ AtomList *ret = NULL;
+
+ // analyze return value or tuple
+
+ I rargc = 0;
+ BL ok = true;
+ retval tp = nothing;
+
+ if(PyString_Check(pValue)) {
+ rargc = 1;
+ tp = atom;
+ }
+ else if(PySequence_Check(pValue)) {
+ rargc = PySequence_Size(pValue);
+ tp = sequ;
+ }
+ else {
+ rargc = 1;
+ tp = atom;
+ }
+
+ ret = new AtomList(rargc);
+
+ for(I ix = 0; ix < rargc; ++ix) {
+ PyObject *arg;
+ switch(tp) {
+ case sequ: arg = PySequence_GetItem(pValue,ix); break;
+ default: arg = pValue;
+ }
+
+ if(PyInt_Check(arg)) SetInt((*ret)[ix],PyInt_AsLong(arg));
+ else if(PyLong_Check(arg)) SetInt((*ret)[ix],PyLong_AsLong(arg));
+ else if(PyFloat_Check(arg)) SetFloat((*ret)[ix],(F)PyFloat_AsDouble(arg));
+ else if(PyString_Check(arg)) SetString((*ret)[ix],PyString_AsString(arg));
+ else if(ix == 0 && self && PyInstance_Check(arg)) {
+ // assumed to be self ... that should be checked _somehow_ !!!
+ *self = arg;
+ }
+ else {
+ PyObject *tp = PyObject_Type(arg);
+ PyObject *stp = tp?PyObject_Str(tp):NULL;
+ C *tmp = "";
+ if(stp) tmp = PyString_AsString(stp);
+ post("py/pyext: Could not convert argument %s",tmp);
+ Py_XDECREF(stp);
+ Py_XDECREF(tp);
+ ok = false;
+ }
+ // No DECREF for arg -> borrowed from pValue!
+ }
+
+ if(!ok) {
+ delete ret;
+ ret = NULL;
+ }
+ return ret;
+}
+
diff --git a/externals/grill/py/source/pyext.cpp b/externals/grill/py/source/pyext.cpp
new file mode 100644
index 00000000..8e971873
--- /dev/null
+++ b/externals/grill/py/source/pyext.cpp
@@ -0,0 +1,465 @@
+/*
+
+py/pyext - python script object for PD and MaxMSP
+
+Copyright (c) 2002 Thomas Grill (xovo@gmx.net)
+For information on usage and redistribution, and for a DISCLAIMER OF ALL
+WARRANTIES, see the file, "license.txt," in this distribution.
+
+*/
+
+#include "pyext.h"
+#include <flinternal.h>
+
+
+FLEXT_LIB_V("pyext",pyext)
+
+V pyext::setup(t_class *)
+{
+ px_head = px_tail = NULL;
+
+ px_class = class_new(gensym("pyext proxy"),NULL,NULL,sizeof(py_proxy),CLASS_PD|CLASS_NOINLET, A_NULL);
+ ::add_anything(px_class,py_proxy::px_method); // for other inlets
+}
+
+pyext *pyext::GetThis(PyObject *self)
+{
+ PyObject *th = PyObject_GetAttrString(self,"_this");
+ pyext *ret = th?(pyext *)PyLong_AsVoidPtr(th):NULL;
+ PyErr_Clear();
+ Py_XDECREF(th);
+ return ret;
+}
+
+
+I pyext::pyextref = 0;
+PyObject *pyext::class_obj = NULL;
+PyObject *pyext::class_dict = NULL;
+
+pyext::pyext(I argc,t_atom *argv):
+ pyobj(NULL),pythr(NULL),
+ inlets(0),outlets(0),
+ methname(NULL)
+{
+ PY_LOCK
+
+ if(!pyextref++) {
+ // register/initialize pyext base class along with module
+ class_dict = PyDict_New();
+ PyObject *className = PyString_FromString(PYEXT_CLASS);
+ PyMethodDef *def;
+
+ // add setattr/getattr to class
+ for(def = attr_tbl; def->ml_name; def++) {
+ PyObject *func = PyCFunction_New(def, NULL);
+ PyDict_SetItemString(class_dict, def->ml_name, func);
+ Py_DECREF(func);
+ }
+
+ class_obj = PyClass_New(NULL, class_dict, className);
+ PyDict_SetItemString(module_dict, PYEXT_CLASS,class_obj);
+ Py_DECREF(className);
+
+ // add methods to class
+ for (def = meth_tbl; def->ml_name != NULL; def++) {
+ PyObject *func = PyCFunction_New(def, NULL);
+ PyObject *method = PyMethod_New(func, NULL, class_obj);
+ PyDict_SetItemString(class_dict, def->ml_name, method);
+ Py_DECREF(func);
+ Py_DECREF(method);
+ }
+
+#if PY_VERSION_HEX >= 0x02020000
+ // not absolutely necessary, existent in python 2.2 upwards
+ // make pyext functions available in class scope
+ PyDict_Merge(class_dict,module_dict,0);
+#endif
+
+ PyDict_SetItemString(class_dict,"__doc__",PyString_FromString(pyext_doc));
+ }
+ else {
+ Py_INCREF(class_obj);
+ Py_INCREF(class_dict);
+ }
+
+ // init script module
+ if(argc >= 1) {
+ C dir[1024];
+#ifdef PD
+ // add dir of current patch to path
+ strcpy(dir,GetString(canvas_getdir(thisCanvas())));
+ AddToPath(dir);
+ // add current dir to path
+ strcpy(dir,GetString(canvas_getcurrentdir()));
+ AddToPath(dir);
+#else
+ #pragma message("Adding current dir to path is not implemented")
+#endif
+
+ GetModulePath(GetString(argv[0]),dir,sizeof(dir));
+ // add to path
+ AddToPath(dir);
+
+ if(!IsString(argv[0]))
+ post("%s - script name argument is invalid",thisName());
+ else {
+ SetArgs(0,NULL);
+ ImportModule(GetString(argv[0]));
+ }
+ }
+
+ Register("_pyext");
+
+// t_symbol *sobj = NULL;
+ if(argc >= 2) {
+ // object name
+ if(!IsString(argv[1]))
+ post("%s - object name argument is invalid",thisName());
+ else {
+ methname = GetSymbol(argv[1]);
+ }
+
+ args(argc-2,argv+2);
+ }
+
+ if(methname) {
+ SetClssMeth();
+
+ // now get number of inlets and outlets
+ inlets = 1,outlets = 1;
+
+ if(pyobj) {
+ PyObject *res;
+ res = PyObject_GetAttrString(pyobj,"_inlets"); // get ref
+ if(res) {
+ if(PyCallable_Check(res)) {
+ PyObject *fres = PyEval_CallObject(res,NULL);
+ Py_DECREF(res);
+ res = fres;
+ }
+ if(PyInt_Check(res))
+ inlets = PyInt_AsLong(res);
+ Py_DECREF(res);
+ }
+ else
+ PyErr_Clear();
+
+ res = PyObject_GetAttrString(pyobj,"_outlets"); // get ref
+ if(res) {
+ if(PyCallable_Check(res)) {
+ PyObject *fres = PyEval_CallObject(res,NULL);
+ Py_DECREF(res);
+ res = fres;
+ }
+ if(PyInt_Check(res))
+ outlets = PyInt_AsLong(res);
+ Py_DECREF(res);
+ }
+ else
+ PyErr_Clear();
+ }
+ }
+
+ PY_UNLOCK
+
+ AddInAnything(1+inlets);
+ AddOutAnything(outlets);
+
+ FLEXT_ADDMETHOD_(0,"reload.",m_reload);
+ FLEXT_ADDMETHOD_(0,"reload",m_reload_);
+ FLEXT_ADDMETHOD_(0,"doc",m_doc);
+ FLEXT_ADDMETHOD_(0,"doc+",m_doc_);
+
+#ifdef FLEXT_THREADS
+ FLEXT_ADDMETHOD_(0,"detach",m_detach);
+ FLEXT_ADDMETHOD_(0,"stop",m_stop);
+#endif
+
+ if(!pyobj)
+ InitProblem();
+}
+
+pyext::~pyext()
+{
+ PY_LOCK
+
+ ClearBinding();
+ Unregister("_pyext");
+
+ Py_XDECREF(pyobj);
+
+ Py_XDECREF(class_obj);
+ Py_XDECREF(class_dict);
+/*
+ // Don't unregister
+
+ if(!--pyextref) {
+ class_obj = NULL;
+ class_dict = NULL;
+ }
+*/
+ PY_UNLOCK
+}
+
+BL pyext::SetClssMeth() //I argc,t_atom *argv)
+{
+ // pyobj should already have been decref'd / cleared before getting here!!
+
+ if(module && methname) {
+ PyObject *pref = PyObject_GetAttrString(module,const_cast<C *>(GetString(methname)));
+ if(!pref)
+ PyErr_Print();
+ else if(PyClass_Check(pref)) {
+ // make instance, but don't call __init__
+ pyobj = PyInstance_NewRaw(pref,NULL);
+
+ Py_DECREF(pref);
+ if(pyobj == NULL)
+ PyErr_Print();
+ else {
+ // remember the this pointer
+ PyObject *th = PyLong_FromVoidPtr(this);
+ int ret = PyObject_SetAttrString(pyobj,"_this",th); // ref is taken
+
+ // call init now, after _this has been set, which is
+ // important for eventual callbacks from __init__ to c
+ PyObject *pargs = MakePyArgs(NULL,args,-1,true);
+ if (pargs == NULL) PyErr_Print();
+
+ PyObject *init;
+ init = PyObject_GetAttrString(pyobj,"__init__"); // get ref
+ if(init && PyCallable_Check(init)) {
+ PyObject *res = PyEval_CallObject(init,pargs);
+ if(!res)
+ PyErr_Print();
+ else
+ Py_DECREF(res);
+ }
+
+ Py_XDECREF(pargs);
+ }
+ }
+ else
+ post("%s - Type of \"%s\" is unhandled!",thisName(),GetString(methname));
+ return true;
+ }
+ else
+ return false;
+}
+
+V pyext::Reload()
+{
+ ClearBinding();
+ Py_XDECREF(pyobj);
+ // by here, the Python class destructor should have been called!
+
+ SetArgs(0,NULL);
+ ReloadModule();
+
+ SetClssMeth();
+}
+
+
+V pyext::m_reload()
+{
+ PY_LOCK
+
+ Unregister("_pyext"); // self
+
+ Reload();
+
+ Reregister("_pyext"); // the others
+ Register("_pyext"); // self
+
+ PY_UNLOCK
+}
+
+V pyext::m_reload_(I argc,t_atom *argv)
+{
+ args(argc,argv);
+ m_reload();
+}
+
+V pyext::m_doc_()
+{
+ if(pyobj) {
+ PY_LOCK
+
+ PyObject *docf = PyObject_GetAttrString(pyobj,"__doc__"); // borrowed!!!
+ if(docf && PyString_Check(docf)) {
+ post("");
+ post(PyString_AsString(docf));
+ }
+
+ PY_UNLOCK
+ }
+}
+
+
+
+
+BL pyext::m_method_(I n,const t_symbol *s,I argc,t_atom *argv)
+{
+ if(pyobj && n >= 1) {
+ return callwork(n,s,argc,argv);
+ }
+ else {
+ post("%s - no method for type '%s' into inlet %i",thisName(),GetString(s),n);
+ return false;
+ }
+}
+
+
+V pyext::m_help()
+{
+ post("");
+ post("pyext %s - python script object, (C)2002 Thomas Grill",PY__VERSION);
+#ifdef _DEBUG
+ post("compiled on " __DATE__ " " __TIME__);
+#endif
+
+ post("Arguments: %s [script name] [class name] {args...}",thisName());
+
+ post("Inlet 1: messages to control the pyext object");
+ post(" 2...: python inlets");
+ post("Outlets: python outlets");
+ post("Methods:");
+ post("\thelp: shows this help");
+ post("\treload {args...}: reload python script");
+ post("\treload. : reload with former arguments");
+ post("\tdoc: display module doc string");
+ post("\tdoc+: display class doc string");
+#ifdef FLEXT_THREADS
+ post("\tdetach 0/1: detach threads");
+ post("\tstop {wait time (ms)}: stop threads");
+#endif
+ post("");
+}
+
+PyObject *pyext::call(const C *meth,I inlet,const t_symbol *s,I argc,t_atom *argv)
+{
+ PyObject *ret = NULL;
+
+ PyObject *pmeth = PyObject_GetAttrString(pyobj,const_cast<char *>(meth)); /* fetch bound method */
+ if(pmeth == NULL) {
+ PyErr_Clear(); // no method found
+ }
+ else {
+ PyObject *pargs = MakePyArgs(s,AtomList(argc,argv),inlet?inlet:-1,true);
+ if(!pargs)
+ PyErr_Print();
+ else {
+ ret = PyEval_CallObject(pmeth, pargs);
+ if (ret == NULL) // function not found resp. arguments not matching
+#ifdef _DEBUG
+ PyErr_Print();
+#else
+ PyErr_Clear();
+#endif
+ else {
+// Py_DECREF(pres);
+ }
+
+ Py_DECREF(pargs);
+ }
+ Py_DECREF(pmeth);
+ }
+
+ return ret;
+}
+
+V pyext::work_wrapper(V *data)
+{
+ ++thrcount;
+#ifdef _DEBUG
+ if(!data)
+ post("%s - no data!",thisName());
+ else
+#endif
+ {
+ work_data *w = (work_data *)data;
+ work(w->n,w->Header(),w->Count(),w->Atoms());
+// delete w;
+ }
+ --thrcount;
+}
+
+BL pyext::callwork(I n,const t_symbol *s,I argc,t_atom *argv)
+{
+ if(detach) {
+ if(shouldexit) {
+ post("%s - Stopping.... new threads can't be launched now!",thisName());
+ return true;
+ }
+ else {
+ BL ret = FLEXT_CALLMETHOD_X(work_wrapper,new work_data(n,s,argc,argv));
+ if(!ret) post("%s - Failed to launch thread!",thisName());
+ return true;
+ }
+ }
+ else
+ return work(n,s,argc,argv);
+}
+
+BL pyext::work(I n,const t_symbol *s,I argc,t_atom *argv)
+{
+ BL retv = false;
+
+ PY_LOCK
+
+ PyObject *ret = NULL;
+ char *str = new char[strlen(GetString(s))+10];
+
+ {
+ // try tag/inlet
+ sprintf(str,"%s_%i",GetString(s),n);
+ ret = call(str,0,NULL,argc,argv);
+ }
+
+ if(!ret) {
+ // try anything/inlet
+ sprintf(str,"_anything_%i",n);
+ if(s == sym_bang && !argc) {
+ t_atom argv;
+ SetString(argv,"");
+ ret = call(str,0,s,1,&argv);
+ }
+ else
+ ret = call(str,0,s,argc,argv);
+ }
+ if(!ret) {
+ // try tag at any inlet
+ sprintf(str,"%s_",GetString(s));
+ ret = call(str,n,NULL,argc,argv);
+ }
+ if(!ret) {
+ // try anything at any inlet
+ strcpy(str,"_anything_");
+ if(s == sym_bang && !argc) {
+ t_atom argv;
+ SetString(argv,"");
+ ret = call(str,n,s,1,&argv);
+ }
+ else
+ ret = call(str,n,s,argc,argv);
+ }
+
+ if(!ret)
+ // no matching python method found
+ post("%s - no matching method found for '%s' into inlet %i",thisName(),GetString(s),n);
+
+ if(str) delete[] str;
+
+ if(ret) {
+ if(!PyObject_Not(ret)) post("%s - returned value is ignored",thisName());
+ Py_DECREF(ret);
+ retv = true;
+ }
+
+ PY_UNLOCK
+
+ return retv;
+}
+
+
+
diff --git a/externals/grill/py/source/pyext.h b/externals/grill/py/source/pyext.h
new file mode 100644
index 00000000..2aba0e8e
--- /dev/null
+++ b/externals/grill/py/source/pyext.h
@@ -0,0 +1,127 @@
+/*
+
+py/pyext - python external object for PD and MaxMSP
+
+Copyright (c) 2002 Thomas Grill (xovo@gmx.net)
+For information on usage and redistribution, and for a DISCLAIMER OF ALL
+WARRANTIES, see the file, "license.txt," in this distribution.
+
+*/
+
+#ifndef __PYEXT_H
+#define __PYEXT_H
+
+#include "main.h"
+
+class pyext:
+ public py
+{
+ FLEXT_HEADER_S(pyext,py,setup)
+
+public:
+ pyext(I argc,t_atom *argv);
+ ~pyext();
+
+ static PyObject *pyext__doc__(PyObject *,PyObject *args);
+ static PyObject *pyext__init__(PyObject *,PyObject *args);
+ static PyObject *pyext__del__(PyObject *,PyObject *args);
+
+ static PyObject *pyext_outlet(PyObject *,PyObject *args);
+ static PyObject *pyext_tocanvas(PyObject *,PyObject *args);
+
+ static PyObject *pyext_setattr(PyObject *,PyObject *args);
+ static PyObject *pyext_getattr(PyObject *,PyObject *args);
+
+ static PyObject *pyext_detach(PyObject *,PyObject *args);
+ static PyObject *pyext_stop(PyObject *,PyObject *args);
+
+ I Inlets() const { return inlets; }
+ I Outlets() const { return outlets; }
+
+protected:
+ BL m_method_(I n,const t_symbol *s,I argc,t_atom *argv);
+
+ BL work(I n,const t_symbol *s,I argc,t_atom *argv);
+
+ V m_reload();
+ V m_reload_(I argc,t_atom *argv);
+ V m_doc_();
+ virtual V m_help();
+
+ const t_symbol *methname;
+ PyObject *pyobj;
+ I inlets,outlets;
+
+private:
+ static V setup(t_class *);
+
+ static pyext *GetThis(PyObject *self);
+ V ClearBinding();
+ BL SetClssMeth(); //I argc,t_atom *argv);
+
+ AtomList args;
+
+ virtual V Reload();
+
+ static I pyextref;
+ static PyObject *class_obj,*class_dict;
+ static PyMethodDef attr_tbl[],meth_tbl[];
+ static const C *pyext_doc;
+
+ // -------- bound stuff ------------------
+
+ static t_class *px_class;
+
+ friend class py_proxy;
+
+ class py_proxy // no virtual table!
+ {
+ public:
+ t_object obj; // MUST reside at memory offset 0
+ PyObject *self,*func;
+ t_symbol *name;
+
+ py_proxy *nxt;
+
+ void init(t_symbol *n,PyObject *s,PyObject *f) { name = n,self = s,func = f,nxt = NULL; }
+// bool cmp(PyObject *s,PyObject *f) const { return self == s && func == f; }
+// void init(PyObject *s,char *f) { self = s,func = f,nxt = NULL; }
+// bool cmp(PyObject *s,char *f) const { return self == s && func == f; }
+ static void px_method(py_proxy *c,const t_symbol *s,int argc,t_atom *argv);
+ };
+ static py_proxy *px_head,*px_tail;
+
+ static PyObject *pyext_bind(PyObject *,PyObject *args);
+ static PyObject *pyext_unbind(PyObject *,PyObject *args);
+
+ // ---------------------------
+
+ PyObject *call(const C *meth,I inlet,const t_symbol *s,I argc,t_atom *argv);
+
+ V work_wrapper(void *data);
+ BL callwork(I n,const t_symbol *s,I argc,t_atom *argv);
+
+ class work_data:
+ public flext::AtomAnything
+ {
+ public:
+ work_data(I _n,const t_symbol *_s,I _argc,t_atom *_argv): n(_n),AtomAnything(_s,_argc,_argv) {}
+ I n;
+ };
+
+#ifdef FLEXT_THREADS
+ FLEXT_THREAD_X(work_wrapper)
+#else
+ FLEXT_CALLBACK_X(work_wrapper)
+#endif
+
+ PyThreadState *pythr;
+
+private:
+ FLEXT_CALLBACK(m_reload)
+ FLEXT_CALLBACK_V(m_reload_)
+ FLEXT_CALLBACK(m_doc_)
+};
+
+
+#endif \ No newline at end of file
diff --git a/externals/grill/py/source/register.cpp b/externals/grill/py/source/register.cpp
new file mode 100644
index 00000000..63a9f952
--- /dev/null
+++ b/externals/grill/py/source/register.cpp
@@ -0,0 +1,86 @@
+/*
+
+py/pyext - python external object for PD and MaxMSP
+
+Copyright (c) 2002 Thomas Grill (xovo@gmx.net)
+For information on usage and redistribution, and for a DISCLAIMER OF ALL
+WARRANTIES, see the file, "license.txt," in this distribution.
+
+*/
+
+#include "main.h"
+
+
+V py::Register(const C *regnm)
+{
+ if(module) {
+ // add this to module registry
+
+ PyObject *reg = PyDict_GetItemString(dict,(C *)regnm); // borrowed!!!
+ PyObject *add = Py_BuildValue("[i]",(long)this);
+ if(!reg || !PyList_Check(reg)) {
+ if(PyDict_SetItemString(dict,(C *)regnm,add)) {
+ post("%s - Could not set registry",thisName());
+ }
+ // Py_XDECREF(reg);
+ }
+ else {
+ PySequence_InPlaceConcat(reg,add);
+ }
+ }
+
+}
+
+V py::Unregister(const C *regnm)
+{
+ if(module) {
+ // remove this from module registry
+
+ PyObject *reg = PyDict_GetItemString(dict,(C *)regnm); // borrowed!!!
+ PyObject *add = Py_BuildValue("i",(int)this);
+ if(!reg || !PySequence_Check(reg))
+ post("%s - Registry not found!?",thisName());
+ else {
+ I ix = PySequence_Index(reg,add);
+ if(ix < 0) {
+ post("%s - This object not found in registry?!",thisName());
+ }
+ else {
+ PySequence_DelItem(reg,ix);
+ }
+ }
+ Py_DECREF(add);
+ }
+
+}
+
+V py::Reregister(const C *regnm)
+{
+ if(module) {
+ // remove this from module registry
+
+ PyObject *reg = PyDict_GetItemString(dict,(C *)regnm); // borrowed!!!
+
+ if(!reg || !PySequence_Check(reg))
+ post("%s - Registry not found!?",thisName());
+ else {
+ I cnt = PySequence_Size(reg);
+ for(I i = 0; i < cnt; ++i) {
+ PyObject *it = PySequence_GetItem(reg,i); // borrowed!!
+ if(!it || !PyInt_Check(it)) {
+ post("%s - Corrupt registry?!",thisName());
+ }
+ else {
+ py *th = (py *)PyInt_AsLong(it);
+ th->module = module;
+ th->dict = dict;
+ th->Reload();
+ }
+ }
+ }
+ }
+
+}
+
+
+