From c2645dc4003b1391aba9b387a79a66cff1e63d3e Mon Sep 17 00:00:00 2001 From: Thomas Grill Date: Tue, 22 Oct 2002 23:16:30 +0000 Subject: 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 --- externals/grill/py/build-pd-bcc.bat | 3 + externals/grill/py/build-pd-cygwin.sh | 10 + externals/grill/py/build-pd-linux.sh | 11 + externals/grill/py/build-pd-msvc.bat | 4 + externals/grill/py/config-pd-bcc.txt | 31 +++ externals/grill/py/config-pd-cygwin.txt | 29 ++ externals/grill/py/config-pd-linux.txt | 33 +++ externals/grill/py/config-pd-msvc.txt | 30 +++ externals/grill/py/gpl.txt | 346 ++++++++++++++++++++++++ externals/grill/py/license.txt | 50 ++++ externals/grill/py/makefile.pd-bcc | 82 ++++++ externals/grill/py/makefile.pd-linux | 75 ++++++ externals/grill/py/pd/script-1.pd | 50 ++++ externals/grill/py/pd/sendrecv-1.pd | 25 ++ externals/grill/py/pd/sendrecv-2.pd | 8 + externals/grill/py/pd/sendrecv-3.pd | 5 + externals/grill/py/pd/simple-1.pd | 41 +++ externals/grill/py/pd/simple-2.pd | 37 +++ externals/grill/py/pd/simple-3.pd | 27 ++ externals/grill/py/pd/tcltk.pd | 18 ++ externals/grill/py/pd/thread-1.pd | 47 ++++ externals/grill/py/py.cw | Bin 0 -> 88197 bytes externals/grill/py/py.dsp | 229 ++++++++++++++++ externals/grill/py/py.mpw | 91 +++++++ externals/grill/py/readme.txt | 106 ++++++++ externals/grill/py/scripts/script.py | 53 ++++ externals/grill/py/scripts/sendrecv.py | 173 ++++++++++++ externals/grill/py/scripts/simple.py | 206 ++++++++++++++ externals/grill/py/scripts/tcltk.py | 77 ++++++ externals/grill/py/scripts/threads.py | 43 +++ externals/grill/py/source/bound.cpp | 143 ++++++++++ externals/grill/py/source/clmeth.cpp | 278 +++++++++++++++++++ externals/grill/py/source/main.cpp | 212 +++++++++++++++ externals/grill/py/source/main.h | 147 ++++++++++ externals/grill/py/source/modmeth.cpp | 183 +++++++++++++ externals/grill/py/source/py.cpp | 327 ++++++++++++++++++++++ externals/grill/py/source/pyargs.cpp | 131 +++++++++ externals/grill/py/source/pyext.cpp | 465 ++++++++++++++++++++++++++++++++ externals/grill/py/source/pyext.h | 127 +++++++++ externals/grill/py/source/register.cpp | 86 ++++++ 40 files changed, 4039 insertions(+) create mode 100644 externals/grill/py/build-pd-bcc.bat create mode 100644 externals/grill/py/build-pd-cygwin.sh create mode 100755 externals/grill/py/build-pd-linux.sh create mode 100644 externals/grill/py/build-pd-msvc.bat create mode 100644 externals/grill/py/config-pd-bcc.txt create mode 100644 externals/grill/py/config-pd-cygwin.txt create mode 100644 externals/grill/py/config-pd-linux.txt create mode 100644 externals/grill/py/config-pd-msvc.txt create mode 100644 externals/grill/py/gpl.txt create mode 100644 externals/grill/py/license.txt create mode 100644 externals/grill/py/makefile.pd-bcc create mode 100644 externals/grill/py/makefile.pd-linux create mode 100644 externals/grill/py/pd/script-1.pd create mode 100644 externals/grill/py/pd/sendrecv-1.pd create mode 100644 externals/grill/py/pd/sendrecv-2.pd create mode 100644 externals/grill/py/pd/sendrecv-3.pd create mode 100644 externals/grill/py/pd/simple-1.pd create mode 100644 externals/grill/py/pd/simple-2.pd create mode 100644 externals/grill/py/pd/simple-3.pd create mode 100644 externals/grill/py/pd/tcltk.pd create mode 100644 externals/grill/py/pd/thread-1.pd create mode 100644 externals/grill/py/py.cw create mode 100644 externals/grill/py/py.dsp create mode 100644 externals/grill/py/py.mpw create mode 100644 externals/grill/py/readme.txt create mode 100644 externals/grill/py/scripts/script.py create mode 100644 externals/grill/py/scripts/sendrecv.py create mode 100644 externals/grill/py/scripts/simple.py create mode 100644 externals/grill/py/scripts/tcltk.py create mode 100644 externals/grill/py/scripts/threads.py create mode 100644 externals/grill/py/source/bound.cpp create mode 100644 externals/grill/py/source/clmeth.cpp create mode 100644 externals/grill/py/source/main.cpp create mode 100644 externals/grill/py/source/main.h create mode 100644 externals/grill/py/source/modmeth.cpp create mode 100644 externals/grill/py/source/py.cpp create mode 100644 externals/grill/py/source/pyargs.cpp create mode 100644 externals/grill/py/source/pyext.cpp create mode 100644 externals/grill/py/source/pyext.h create mode 100644 externals/grill/py/source/register.cpp (limited to 'externals/grill/py') 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. + + + Copyright (C) 19yy + + 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. + + , 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 Binary files /dev/null and b/externals/grill/py/py.cw 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 gltiges Makefile. Zum Erstellen dieses Projekts mit NMAKE +!MESSAGE verwenden Sie den Befehl "Makefile exportieren" und fhren Sie den Befehl +!MESSAGE +!MESSAGE NMAKE /f "py.mak". +!MESSAGE +!MESSAGE Sie knnen beim Ausfhren 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 Fr 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("", 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 +#include +#ifndef NT +#include +#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 + + +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(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(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(); + } + } + } + } + +} + + + -- cgit v1.2.1