[SCM] pd-moonlib/master: New upstream version 0.3.4~repack

umlaeute at users.alioth.debian.org umlaeute at users.alioth.debian.org
Fri Oct 28 21:50:49 UTC 2016


The following commit has been merged in the master branch:
commit 007fc07f6f019239f09a26f6a083c0a951aacc64
Author: IOhannes m zmölnig <zmoelnig at umlautQ.umlaeute.mur.at>
Date:   Fri Oct 28 23:10:09 2016 +0200

    New upstream version 0.3.4~repack

diff --git a/.directory b/.directory
new file mode 100644
index 0000000..486990f
--- /dev/null
+++ b/.directory
@@ -0,0 +1,47 @@
+[IconPosition::README]
+X=456
+Y=60
+
+[IconPosition::docs]
+X=28
+Y=5
+
+[IconPosition::externs]
+X=113
+Y=5
+
+[IconPosition::externs0.37]
+X=190
+Y=5
+
+[IconPosition::makefile]
+X=287
+Y=60
+
+[IconPosition::nilib_0.1.0]
+X=281
+Y=5
+
+[IconPosition::nilib_0.2.0]
+X=368
+Y=5
+
+[IconPosition::others_0.2]
+X=453
+Y=5
+
+[IconPosition::paths.txt]
+X=370
+Y=60
+
+[IconPosition::sublib_0.1.0]
+X=16
+Y=60
+
+[IconPosition::sublib_0.2.0]
+X=103
+Y=60
+
+[IconPosition::sublib_0.3.0]
+X=190
+Y=60
diff --git a/LICENSE.txt b/LICENSE.txt
index fa0bef4..89e08fb 100644
--- a/LICENSE.txt
+++ b/LICENSE.txt
@@ -1,290 +1,339 @@
-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
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser 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
+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. 
+distribute and/or modify the software.
 
-Also, for each author's protection and ours, we want to make certain
+  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
+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. 
+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. 
+  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. 
+  The precise terms and conditions for copying, distribution and
+modification follow.
 
-TERMS AND CONDITIONS FOR
-COPYING, DISTRIBUTION AND
-MODIFICATION
+                    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"
+  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". 
+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. 
+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
+  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. 
+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. 
+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
+  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
+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,
+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.) 
+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
+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
+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
+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
+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. 
+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
+  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
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/Makefile b/Makefile
index aefc7b4..3e67a7a 100644
--- a/Makefile
+++ b/Makefile
@@ -1,308 +1,39 @@
-## Pd library template version 1.0.5
-# For instructions on how to use this template, see:
-#  http://puredata.info/docs/developer/MakefileTemplate
-LIBRARY_NAME = moonlib
-
-# add your .c source files, one object per file, to the SOURCES
-# variable, help files will be included automatically
-SOURCES = absolutepath.c basedir.c char2f.c comma.c dinlet~.c dispatch.c dripchar.c f2char.c gamme.c image.c mknob.c panvol~.c popen.c relativepath.c s2f.c sarray.c sfread2~.c slist.c ssaw~.c tabdump2.c tabenv.c tabreadl.c tabsort2.c tabsort.c wac.c 
-
-# For objects that only build on certain platforms, add those to the SOURCES
-# line for the right platforms.
-SOURCES_linux = readsfv~.c
-
-# list all pd objects (i.e. myobject.pd) files here, and their helpfiles will
-# be included automatically
-PDOBJECTS = 
-
-# example patches and related files, in the 'examples' subfolder
-EXAMPLES = pause.gif play.gif playy.gif rec.gif saww.gif sin.gif sinw.gif squarew.gif d0.gif d10.gif d11.gif d12.gif d13.gif d14.gif d15.gif d16.gif d17.gif d18.gif d19.gif d1.gif d20.gif d21.gif d22.gif d23.gif d24.gif d25.gif d26.gif d27.gif d28.gif d29.gif d2.gif d30.gif d31.gif d32.gif d33.gif d34.gif d35.gif d36.gif d37.gif d38.gif d39.gif d3.gif d40.gif d41.gif d42.gif d43.gif d44.gif d45.gif d46.gif d47.gif d48.gif d49.gif d4.gif d50.gif d51.gif d52.gif d53.gif d54.gif d55.gif d56.gif d57.gif d58.gif d59.gif d5.gif d60.gif d61.gif d62.gif d63.gif d6.gif d7.gif d8.gif d9.gif
-
-# manuals and related files, in the 'manual' subfolder
-MANUAL = 
-
-# if you want to include any other files in the source and binary tarballs,
-# list them here.  This can be anything from header files, test patches,
-# documentation, etc.  README.txt and LICENSE.txt are required and therefore
-# automatically included
-EXTRA_DIST = XFS.txt
-
-
-
-#------------------------------------------------------------------------------#
-#
-# things you might need to edit if you are using other C libraries
-#
-#------------------------------------------------------------------------------#
-
-CFLAGS = -DPD -I"$(PD_INCLUDE)" -Wall -W -g
-LDFLAGS =  
-LIBS = 
-
-#------------------------------------------------------------------------------#
-#
-# you shouldn't need to edit anything below here, if we did it right :)
-#
-#------------------------------------------------------------------------------#
-
-# get library version from meta file
-LIBRARY_VERSION = $(shell sed -n 's|^\#X text [0-9][0-9]* [0-9][0-9]* VERSION \(.*\);|\1|p' $(LIBRARY_NAME)-meta.pd)
-
-CFLAGS += -DVERSION='"$(LIBRARY_VERSION)"'
-
-PD_INCLUDE = $(PD_PATH)/include
-# where to install the library, overridden below depending on platform
-prefix = /usr/local
-libdir = $(prefix)/lib
-pkglibdir = $(libdir)/pd-externals
-objectsdir = $(pkglibdir)
-
-INSTALL = install
-INSTALL_PROGRAM = $(INSTALL) -p -m 644
-INSTALL_DATA = $(INSTALL) -p -m 644
-INSTALL_DIR     = $(INSTALL) -p -m 755 -d
-
-ALLSOURCES := $(SOURCES) $(SOURCES_android) $(SOURCES_cygwin) $(SOURCES_macosx) \
-	         $(SOURCES_iphoneos) $(SOURCES_linux) $(SOURCES_windows)
-
-DISTDIR=$(LIBRARY_NAME)-$(LIBRARY_VERSION)
-ORIGDIR=pd-$(LIBRARY_NAME:~=)_$(LIBRARY_VERSION)
-
-UNAME := $(shell uname -s)
-ifeq ($(UNAME),Darwin)
-  CPU := $(shell uname -p)
-  ifeq ($(CPU),arm) # iPhone/iPod Touch
-    SOURCES += $(SOURCES_iphoneos)
-    EXTENSION = pd_darwin
-    OS = iphoneos
-    PD_PATH = /Applications/Pd-extended.app/Contents/Resources
-    IPHONE_BASE=/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin
-    CC=$(IPHONE_BASE)/gcc
-    CPP=$(IPHONE_BASE)/cpp
-    CXX=$(IPHONE_BASE)/g++
-    ISYSROOT = -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.0.sdk
-    IPHONE_CFLAGS = -miphoneos-version-min=3.0 $(ISYSROOT) -arch armv6
-    OPT_CFLAGS = -fast -funroll-loops -fomit-frame-pointer
-	CFLAGS := $(IPHONE_CFLAGS) $(OPT_CFLAGS) $(CFLAGS)
-    LDFLAGS += -arch armv6 -bundle -undefined dynamic_lookup $(ISYSROOT)
-    LIBS += -lc 
-    STRIP = strip -x
-    DISTBINDIR=$(DISTDIR)-$(OS)
-  else # Mac OS X
-    SOURCES += $(SOURCES_macosx)
-    EXTENSION = pd_darwin
-    OS = macosx
-    PD_PATH = /Applications/Pd-extended.app/Contents/Resources
-    OPT_CFLAGS = -ftree-vectorize -ftree-vectorizer-verbose=2 -fast
-# build universal 32-bit on 10.4 and 32/64 on newer
-    ifeq ($(shell uname -r | sed 's|\([0-9][0-9]*\)\.[0-9][0-9]*\.[0-9][0-9]*|\1|'), 8)
-      FAT_FLAGS = -arch ppc -arch i386 -mmacosx-version-min=10.4
-    else
-      FAT_FLAGS = -arch ppc -arch i386 -arch x86_64 -mmacosx-version-min=10.4
-      SOURCES += $(SOURCES_iphoneos)
-    endif
-    CFLAGS += $(FAT_FLAGS) -fPIC -I/sw/include
-    LDFLAGS += $(FAT_FLAGS) -bundle -undefined dynamic_lookup -L/sw/lib
-    # if the 'pd' binary exists, check the linking against it to aid with stripping
-    LDFLAGS += $(shell test -e $(PD_PATH)/bin/pd && echo -bundle_loader $(PD_PATH)/bin/pd)
-    LIBS += -lc 
-    STRIP = strip -x
-    DISTBINDIR=$(DISTDIR)-$(OS)
-# install into ~/Library/Pd on Mac OS X since /usr/local isn't used much
-    pkglibdir=$(HOME)/Library/Pd
-  endif
-endif
-ifeq ($(UNAME),Linux)
-  CPU := $(shell uname -m)
-  SOURCES += $(SOURCES_linux)
-  EXTENSION = pd_linux
-  OS = linux
-  PD_PATH = /usr
-  OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer
-  CFLAGS += -fPIC
-  LDFLAGS += -Wl,--export-dynamic  -shared -fPIC
-  LIBS += -lc
-  STRIP = strip --strip-unneeded -R .note -R .comment
-  DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m)
-endif
-ifeq (CYGWIN,$(findstring CYGWIN,$(UNAME)))
-  CPU := $(shell uname -m)
-  SOURCES += $(SOURCES_cygwin)
-  EXTENSION = dll
-  OS = cygwin
-  PD_PATH = $(cygpath $(PROGRAMFILES))/pd
-  OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer
-  CFLAGS += 
-  LDFLAGS += -Wl,--export-dynamic -shared -L"$(PD_PATH)/src" -L"$(PD_PATH)/bin"
-  LIBS += -lc -lpd
-  STRIP = strip --strip-unneeded -R .note -R .comment
-  DISTBINDIR=$(DISTDIR)-$(OS)
-endif
-ifeq (MINGW,$(findstring MINGW,$(UNAME)))
-  CPU := $(shell uname -m)
-  SOURCES += $(SOURCES_windows)
-  EXTENSION = dll
-  OS = windows
-  PD_PATH = $(shell cd "$(PROGRAMFILES)"/pd && pwd)
-  OPT_CFLAGS = -O3 -funroll-loops -fomit-frame-pointer
-  WINDOWS_HACKS = -D'O_NONBLOCK=1'
-  CFLAGS += -mms-bitfields $(WINDOWS_HACKS)
-  LDFLAGS += -s -shared -Wl,--enable-auto-import
-  LIBS += -L"$(PD_PATH)/src" -L"$(PD_PATH)/bin" -L"$(PD_PATH)/obj" -lpd -lwsock32 -lkernel32 -luser32 -lgdi32
-  STRIP = strip --strip-unneeded -R .note -R .comment
-  DISTBINDIR=$(DISTDIR)-$(OS)
-endif
-
-# in case somebody manually set the HELPPATCHES above
-HELPPATCHES ?= $(SOURCES:.c=-help.pd) $(PDOBJECTS:.pd=-help.pd)
-
-CFLAGS += $(OPT_CFLAGS)
-
-
-.PHONY = install libdir_install single_install install-doc install-exec install-examples install-manual clean dist etags $(LIBRARY_NAME)
-
-all: $(SOURCES:.c=.$(EXTENSION))
-
-%.o: %.c
-	$(CC) $(CFLAGS) -o "$*.o" -c "$*.c"
-
-%.$(EXTENSION): %.o
-	$(CC) $(LDFLAGS) -o "$*.$(EXTENSION)" "$*.o"  $(LIBS)
-	chmod a-x "$*.$(EXTENSION)"
-
-# this links everything into a single binary file
-$(LIBRARY_NAME): $(SOURCES:.c=.o) $(LIBRARY_NAME).o
-	$(CC) $(LDFLAGS) -o $(LIBRARY_NAME).$(EXTENSION) $(SOURCES:.c=.o) $(LIBRARY_NAME).o $(LIBS)
-	chmod a-x $(LIBRARY_NAME).$(EXTENSION)
-
-install: libdir_install
-
-# The meta and help files are explicitly installed to make sure they are
-# actually there.  Those files are not optional, then need to be there.
-libdir_install: $(SOURCES:.c=.$(EXTENSION)) install-doc install-examples install-manual
-	$(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
-	$(INSTALL_DATA) $(LIBRARY_NAME)-meta.pd \
-		$(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
-	test -z "$(strip $(SOURCES))" || (\
-		$(INSTALL_PROGRAM) $(SOURCES:.c=.$(EXTENSION)) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) && \
-		$(STRIP) $(addprefix $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/,$(SOURCES:.c=.$(EXTENSION))))
-	test -z "$(strip $(PDOBJECTS))" || \
-		$(INSTALL_DATA) $(PDOBJECTS) \
-			$(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
-
-# install library linked as single binary
-single_install: $(LIBRARY_NAME) install-doc install-exec
-	$(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
-	$(INSTALL_PROGRAM) $(LIBRARY_NAME).$(EXTENSION) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
-	$(STRIP) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/$(LIBRARY_NAME).$(EXTENSION)
-
-install-doc:
-	$(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
-	test -z "$(strip $(SOURCES) $(PDOBJECTS))" || \
-		$(INSTALL_DATA) $(HELPPATCHES) \
-			$(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
-	$(INSTALL_DATA) README.txt $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/README.txt
-	$(INSTALL_DATA) LICENSE.txt $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/LICENSE.txt
-
-install-examples:
-	test -z "$(strip $(EXAMPLES))" || \
-		$(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/examples && \
-		for file in $(EXAMPLES); do \
-			$(INSTALL_DATA) examples/$$file $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/examples; \
-		done
-
-install-manual:
-	test -z "$(strip $(MANUAL))" || \
-		$(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/manual && \
-		for file in $(MANUAL); do \
-			$(INSTALL_DATA) manual/$$file $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/manual; \
-		done
-
-
-clean:
-	-rm -f -- $(SOURCES:.c=.o) $(SOURCES_LIB:.c=.o)
-	-rm -f -- $(SOURCES:.c=.$(EXTENSION))
-	-rm -f -- $(LIBRARY_NAME).o
-	-rm -f -- $(LIBRARY_NAME).$(EXTENSION)
-
-distclean: clean
-	-rm -f -- $(DISTBINDIR).tar.gz
-	-rm -rf -- $(DISTBINDIR)
-	-rm -f -- $(DISTDIR).tar.gz
-	-rm -rf -- $(DISTDIR)
-	-rm -f -- $(ORIGDIR).tar.gz
-	-rm -rf -- $(ORIGDIR)
-
-
-$(DISTBINDIR):
-	$(INSTALL_DIR) $(DISTBINDIR)
-
-libdir: all $(DISTBINDIR)
-	$(INSTALL_DATA) $(LIBRARY_NAME)-meta.pd  $(DISTBINDIR)
-	$(INSTALL_DATA) $(SOURCES)  $(DISTBINDIR)
-	$(INSTALL_DATA) $(HELPPATCHES) $(DISTBINDIR)
-	test -z "$(strip $(EXTRA_DIST))" || \
-		$(INSTALL_DATA) $(EXTRA_DIST)    $(DISTBINDIR)
-#	tar --exclude-vcs -czpf $(DISTBINDIR).tar.gz $(DISTBINDIR)
-
-$(DISTDIR):
-	$(INSTALL_DIR) $(DISTDIR)
-
-$(ORIGDIR):
-	$(INSTALL_DIR) $(ORIGDIR)
-
-dist: $(DISTDIR)
-	$(INSTALL_DATA) Makefile  $(DISTDIR)
-	$(INSTALL_DATA) README.txt $(DISTDIR)
-	$(INSTALL_DATA) LICENSE.txt $(DISTDIR)
-	$(INSTALL_DATA) $(LIBRARY_NAME)-meta.pd  $(DISTDIR)
-	test -z "$(strip $(ALLSOURCES))" || \
-		$(INSTALL_DATA) $(ALLSOURCES)  $(DISTDIR)
-	test -z "$(strip $(PDOBJECTS))" || \
-		$(INSTALL_DATA) $(PDOBJECTS)  $(DISTDIR)
-	test -z "$(strip $(HELPPATCHES))" || \
-		$(INSTALL_DATA) $(HELPPATCHES) $(DISTDIR)
-	test -z "$(strip $(EXTRA_DIST))" || \
-		$(INSTALL_DATA) $(EXTRA_DIST)    $(DISTDIR)
-	test -z "$(strip $(EXAMPLES))" || \
-		$(INSTALL_DIR) $(DISTDIR)/examples && \
-		for file in $(EXAMPLES); do \
-			$(INSTALL_DATA) examples/$$file $(DISTDIR)/examples; \
-		done
-	test -z "$(strip $(MANUAL))" || \
-		$(INSTALL_DIR) $(DISTDIR)/manual && \
-		for file in $(MANUAL); do \
-			$(INSTALL_DATA) manual/$$file $(DISTDIR)/manual; \
-		done
-	tar --exclude-vcs -czpf $(DISTDIR).tar.gz $(DISTDIR)
-
-# make a Debian source package
-dpkg-source:
-	debclean
-	make distclean dist
-	mv $(DISTDIR) $(ORIGDIR)
-	tar --exclude-vcs -czpf ../$(ORIGDIR).orig.tar.gz $(ORIGDIR)
-	rm -f -- $(DISTDIR).tar.gz
-	rm -rf -- $(DISTDIR) $(ORIGDIR)
-	cd .. && dpkg-source -b $(LIBRARY_NAME)
-
-etags:
-	etags *.h $(SOURCES) ../../pd/src/*.[ch] /usr/include/*.h /usr/include/*/*.h
-
-showsetup:
-	@echo "CFLAGS: $(CFLAGS)"
-	@echo "LDFLAGS: $(LDFLAGS)"
-	@echo "LIBS: $(LIBS)"
-	@echo "PD_INCLUDE: $(PD_INCLUDE)"
-	@echo "PD_PATH: $(PD_PATH)"
-	@echo "objectsdir: $(objectsdir)"
-	@echo "LIBRARY_NAME: $(LIBRARY_NAME)"
-	@echo "LIBRARY_VERSION: $(LIBRARY_VERSION)"
-	@echo "SOURCES: $(SOURCES)"
-	@echo "PDOBJECTS: $(PDOBJECTS)"
-	@echo "ALLSOURCES: $(ALLSOURCES)"
-	@echo "UNAME: $(UNAME)"
-	@echo "CPU: $(CPU)"
-	@echo "pkglibdir: $(pkglibdir)"
-	@echo "DISTDIR: $(DISTDIR)"
-	@echo "ORIGDIR: $(ORIGDIR)"
+# Makefile to build class 'moonlib' for Pure Data.
+# Needs Makefile.pdlibbuilder as helper makefile for platform-dependent build
+# settings and rules.
+#
+# use : make pdincludepath=/path/to/pure-data/src/
+#
+# The following command will build the external and install the distributable 
+# files into a subdirectory called build/moonlib :
+#
+# make install pdincludepath=../pure-data/src/ objectsdir=./build
+
+lib.name = moonlib
+
+uname := $(shell uname -s)
+ifeq (MINGW,$(findstring MINGW,$(uname)))
+ldlibs = -lpthread
+endif
+
+objects = char2f comma dispatch dripchar f2char f2s gamme image mknob panvol~ \
+s2f sarray sfread2~ slist ssaw~ tabdump2 tabenv tabreadl tabsort2 tabsort ndmetro
+
+ifneq (MINGW,$(findstring MINGW,$(uname)))
+objects += absolutepath basedir dinlet~ popen readsfv~ relativepath wac
+endif
+
+class.sources = $(addsuffix .c,$(objects))
+
+# all extra files to be included in binary distribution of the library
+datafiles = \
+$(addsuffix -help.pd,$(objects)) \
+moonlib-meta.pd \
+image.tcl \
+LICENSE.txt \
+README.txt
+
+datadirs = img
+cflags = -Wno-unused -Wno-unused-parameter 
+
+include pd-lib-builder/Makefile.pdlibbuilder
diff --git a/README.txt b/README.txt
index e4e5d5a..cfd460e 100644
--- a/README.txt
+++ b/README.txt
@@ -1,113 +1,39 @@
-Here are the libs I've written for Pd.
-They can be splitted in three parts:
-
-   1. the nilib library, which is a kind of wrapper between Pd and Gtk, and its
-    objects:
- 	nifs (a one-click file selector, with some special tricks...), niscope (a 
-	simple oscilloscope), and nileon (a simple drum machine, but it's the 
-	replication of an enormous mechanical one, named Leon Napakatbra, which was 
-	built from a 8 meters diameter merry-go-round...). 
-	 There was also nimouse (giving mouse position/buttons) and nitab (the same 
-	for wacom serial graphire tablet) but i don't use these anymore: it's too 
-	dangerous to access a device file directly from pd. Beter use gtkmouse and 
-	wac/wacusb programs with pdsend/pdreceive.
-
-   2. the sub library, which is a collection of gui control objects (subdial, 
-   	subslider, subbang and subtoggle) that are placed into a subpatch but are 
-	visible in the parent window, into the subpatch's box. The idea was to build 
-	easy-to-use complex subpatchs, or abstractions. I wrote it before 
-	"graph-on-parent" was implemented in Pd, so it's a bit deprecated now, but 
-	it has the advantage that subs values (positions of the buttons) are saved 
-	into the parent patch... very useful in case of abstractions.
-     About of these questions, have a look to my AutoPreset abstractions, which 
-	adds a manner to save the value of regular gui objects (hslider etc...) into 
-	either a file or the parent patch, even those nested in abstractions (and 
-	recursively in abstractions of abstractions...). It works also with tables, 
-	symbols and symbol arrays.
-
-   3. some other objects, such as:
-
-    tabenv : like env~, an enveloppe follower, but computing on a table, so 
-	 possibly much speeder than real-time env~'s computation.
-    tabsort and tabsort2 : returns the indices of the sorted table (tabsort2 
-	 is bidimentionnal).
-    gamme : one octave of a piano keyboard used to filter/choose notes in a 
-	 selected scale.
-    absolutepath/relativepath : to use datas (sounds, texts, presets, images, 
-	 programs...) nested in the patch's directory (and in subdirs).
-    sarray and slist : to creates shared dynamic arrays or lists with symbols.
-    sfread2~ and readsfv~ : to pitch the direct-from-disk reading of sound files.
-    dinlet~ : an inlet~ with a default value (when nothing is connected to it).
-    mknob : a round knob ala iemgui vslider (with its "properties" window).
-    dispatch : creates one bus name for many buttons' buses: from the N pairs  
-	 (slider1-snd/slider1-rcv) ... (sliderN-snd/sliderN-rcv), creates only 
-	 one pair of buses named (slider-snd/slider-rcv) , in which datas are 
-	 prepended by the number of the "sub-bus".
-    joystik : an improvment of Joseph A. Sarlo's joystick.
-    image :  an improvment  of Guenter Geiger's one. Same name, but it's 
-	 compatible. Here you can share images through different objects, preload 
-	 a list of images, and animate this list.
-
-    and some others...
-
-CAUTION:
-
-    This stuff was written with Pd v0.34-4 to v0.37 on a PC under Linux. It 
-	hasn't be tested under other conditions; nilib will only work under Linux 
-	(but I think it will be OK on other machines than PC), because of use of 
-	multithreading and GTK .
-    Anyway makefiles are only working for Linux for the moment...
-    Moreover I think sub library is potentially very sensible to possible 
-	modifications of Pd sources.
-
-
-
-To install:
-
-sublib_0.1.0 is for Pd 0.33
-sublib_0.2.0 is for Pd 0.35
-sublib_0.3.0 is for Pd 0.37
-
-nilib_0.1.0 is for Pd 0.35
-nilib_0.2.0 is for Pd 0.37
-
-others_0.1.0 is for Pd 0.35 
-others_0.2.0 is for Pd 0.37
-
-
-
-Edit paths.txt to tune install paths and pure-data's location.
-Edit this makefile if you want to select older versions of externals (if you
- are using pd0.37 it should be ok).
-
-Then:
-
-make
-make install
-
-
-
-If you keep externals locally inside moonlibs directory, then you should add it
-to your pdrc file:
-
--path moonlibs-0.2/externs
--helppath moonlibs-0.2/docs
-
-
-CAUTION : 
-	1)	(pd 0.35) You MUST fix a bug pd sources and recompile them in order to have 
-	dinlet~ working !! 
-	You have to replace the function obj_findsignalscalar() in file m_obj.c 
-	by the one written in dinlet~.c .
-	
-	(dinlet~ is a signal inlet where you can choose the default float value it
-	outputs when no signal is connected into.)
-
-
-	2) In order to have sfread~ working with big files in direct-from-disk 
-	mode you have to hack pd sources: change 
-		mlockall(MCL_FUTURE) 
-	with 
-		mlockall(MCL_CURRENT)
-	in s_linux.c (pd0.35) or s_inter.c (pd0.37). If not the whole file will be loaded in memory when
-	opening it.
+MOONLIB puredata externals
+
+    tabenv : like env~, an enveloppe follower, but computing on a table, so 
+	 possibly much speeder than real-time env~'s computation.
+    tabsort and tabsort2 : returns the indices of the sorted table (tabsort2 
+	 is bidimentionnal).
+    gamme : one octave of a piano keyboard used to filter/choose notes in a 
+	 selected scale.
+    absolutepath/relativepath : to use datas (sounds, texts, presets, images, 
+	 programs...) nested in the patch's directory (and in subdirs).
+    sarray and slist : to creates shared dynamic arrays or lists with symbols.
+    sfread2~ and readsfv~ : to pitch the direct-from-disk reading of sound files.
+    dinlet~ : an inlet~ with a default value (when nothing is connected to it).
+    mknob : a round knob ala iemgui vslider (with its "properties" window).
+    dispatch : creates one bus name for many buttons' buses: from the N pairs  
+	 (slider1-snd/slider1-rcv) ... (sliderN-snd/sliderN-rcv), creates only 
+	 one pair of buses named (slider-snd/slider-rcv) , in which datas are 
+	 prepended by the number of the "sub-bus".
+    joystik : an improvment of Joseph A. Sarlo's joystick.
+    image :  an improvment  of Guenter Geiger's one. Same name, but it's 
+	 compatible. Here you can share images through different objects, preload 
+	 a list of images, and animate this list.
+    ndmetro : a metronome/counter allowing continuous tempo change and other features.
+    
+    and some others...
+
+
+  In order to have sfread2~ working with big files in direct-from-disk 
+mode you have to hack pd sources: change 
+	mlockall(MCL_FUTURE) 
+with 
+	mlockall(MCL_CURRENT)
+in s_inter.c . If not the whole file will be loaded in memory when opening it.
+
+Latest source can be found (and issues can be reported) at: 
+https://github.com/MetaluNet/moonlib
+
+Antoine Rousseau
+
diff --git a/XFS.txt b/XFS.txt
deleted file mode 100644
index d50aece..0000000
--- a/XFS.txt
+++ /dev/null
@@ -1 +0,0 @@
-xfs -port -1 -daemon -droppriv -user xfs
diff --git a/absolutepath-help.pd b/absolutepath-help.pd
index b056f4a..6a6b8e2 100644
--- a/absolutepath-help.pd
+++ b/absolutepath-help.pd
@@ -1,13 +1,24 @@
-#N canvas 14 323 660 379 10;
-#X text 17 352 (c) Antoine Rousseau 2004;
-#X obj 33 108 absolutepath;
-#X symbolatom 33 131 0 0 0;
-#X msg 33 51 symbol absolutepath.pd;
-#X obj 33 220 relativepath;
-#X symbolatom 33 245 0 0 0;
-#X text 14 6 absolutepath / relativepath : use filenames relatively
-to the patch's path.;
-#X connect 1 0 2 0;
-#X connect 2 0 4 0;
-#X connect 3 0 1 0;
-#X connect 4 0 5 0;
+#N canvas 0 31 482 379 10;
+#X text 17 352 (c) Antoine Rousseau 2004;
+#X obj 33 108 absolutepath;
+#X symbolatom 33 131 0 0 0 0 - - -;
+#X obj 33 220 relativepath;
+#X symbolatom 33 245 0 0 0 0 - - -;
+#X text 14 6 absolutepath / relativepath : use filenames relatively
+to the patch's path.;
+#N canvas 380 146 494 344 META 0;
+#X text 12 25 LICENSE GPL v2;
+#X text 12 5 KEYWORDS control patchfile_op;
+#X text 12 45 DESCRIPTION use filenames relatively to the patch's path
+;
+#X text 12 65 INLET_0 symbol;
+#X text 12 85 OUTLET_0 symbol;
+#X text 12 105 AUTHOR Antoine Rousseau;
+#X text 12 125 HELP_PATCH_AUTHORS Antoine Rousseau. "pd meta" information
+added by Jonathan Wilkes for Pd version 0.42.;
+#X restore 421 350 pd META;
+#X msg 33 51 symbol absolutepath-help.pd;
+#X connect 1 0 2 0;
+#X connect 2 0 3 0;
+#X connect 3 0 4 0;
+#X connect 7 0 1 0;
diff --git a/absolutepath.c b/absolutepath.c
index 0b44dcb..772d05b 100644
--- a/absolutepath.c
+++ b/absolutepath.c
@@ -1,142 +1,154 @@
-#ifndef _WIN32
-/*
-Copyright (C) 2002 Antoine Rousseau 
-
-This library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation; either
-version 2.1 of the License, or (at your option) any later version.
-
-This library 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
-Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with this library; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  
-
-*/
-
-/*#include <m_imp.h>*/
-#include "m_pd.h"
-#include "g_canvas.h"
-
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
-#include <libgen.h>
-#include <string.h>
-
-extern t_canvas *canvas_list;	    	    /* list of all root canvases */
-extern int canvas_getdollarzero( void);
-
-struct _canvasenvironment
-{
-    t_symbol *ce_dir;	/* directory patch lives in */
-    int ce_argc;    	/* number of "$" arguments */
-    t_atom *ce_argv;	/* array of "$" arguments */
-    int ce_dollarzero;	/* value of "$0" */
-};
-
-typedef struct _absolutepath
-{
-    t_object x_obj;
-    t_canvas *x_canvas;
-	int x_dolzero;
-	int x_realized;
-}t_absolutepath;
-
-t_class *absolutepath_class;
-
-void absolutepath_setup(void);
-
-static t_glist *getcanvas(t_glist *can,int d0)
-{
-	t_canvas *retcan=0;
-	t_gobj *ob;
-	
-	if((can->gl_env)&&(can->gl_env->ce_dollarzero==d0)){
-		return can;
-	}
-	
-	ob=can->gl_list;
-	while(ob&&(retcan==0)) {
-		if (pd_class(&ob->g_pd) == canvas_class)
-			retcan=getcanvas((t_glist *)ob,d0);
-		ob=ob->g_next;
-	} 
-
-	if((!retcan)&&(can->gl_next)) retcan=getcanvas((t_glist *)can->gl_next,d0);
-	return retcan;
-}
-
-
-static void absolutepath_symbol(t_absolutepath *x,t_symbol *sym)
-{
-	t_canvas *can=0;
-    char buf[MAXPDSTRING], *bufptr,
-		*instr=sym->s_name,
-		canname[MAXPDSTRING],totaldir[MAXPDSTRING],
-		*cnamedir,
-		*candir;
-	unsigned int n,i=0;
-	int fd;
-
-	if(!x->x_realized) can=(t_canvas*)getcanvas(canvas_list,x->x_dolzero);
-	if(can) {
-		x->x_canvas = can;
-		x->x_realized = 1;
-		//post("found $0 canvas : %x %d ",x->x_canvas, x->x_canvas->gl_env->ce_dollarzero );
-	}
-
-	if(!instr) return;
-
-	candir=canvas_getdir(x->x_canvas)->s_name;
-	if(!candir) candir="";
-	
-	//post("input= %s   candir= %s   glname=%s",instr,candir,x->x_canvas->gl_name->s_name);
-	
-	strcpy(canname,x->x_canvas->gl_name->s_name);
-	cnamedir=dirname(canname);
-	
-	if (strcmp(cnamedir,".")) {
-		sprintf(totaldir,"%s/%s",candir,cnamedir);
-		fd=open_via_path(totaldir,instr ,"",buf, &bufptr, MAXPDSTRING, 1);
-	}
-	else 
-		fd=open_via_path(candir, instr, "",buf, &bufptr, MAXPDSTRING, 1);
-
-	if (fd>=0) {
-		close(fd);
-		buf[strlen(buf)]='/';
-		outlet_symbol(x->x_obj.ob_outlet,gensym(buf));
-	}
-	return;
-}
-
-
-static void *absolutepath_new(t_float dolzero)
-{
-	t_absolutepath *x = (t_absolutepath *)pd_new(absolutepath_class);
-	t_canvas *can=canvas_list;
-	int d0;
-	
-	outlet_new(&x->x_obj, 0);
-    x->x_canvas = canvas_getcurrent();
-	x->x_dolzero = dolzero;
-	x->x_realized=dolzero?0:1;
-
-	return (void *)x;
-}
-
-void absolutepath_setup(void)
-{
-	absolutepath_class = class_new(gensym("absolutepath"),(t_newmethod)absolutepath_new,
-		0, sizeof(t_absolutepath), 0,A_DEFFLOAT, 0);
-
-	class_addsymbol(absolutepath_class, absolutepath_symbol);
-}
-
-#endif /* NOT _WIN32 */
+#ifndef _WIN32
+/*
+Copyright (C) 2002 Antoine Rousseau
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+*/
+
+/*#include <m_imp.h>*/
+#include "m_pd.h"
+#include "m_imp.h"
+#include "g_canvas.h"
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <libgen.h>
+#include <string.h>
+
+#if ((PD_MAJOR_VERSION == 0) && (PD_MINOR_VERSION < 46))
+extern t_canvas *canvas_list;
+#else
+#define canvas_list pd_this->pd_canvaslist
+#endif
+
+extern int canvas_getdollarzero( void);
+
+struct _canvasenvironment
+{
+    t_symbol *ce_dir;	/* directory patch lives in */
+    int ce_argc;    	/* number of "$" arguments */
+    t_atom *ce_argv;	/* array of "$" arguments */
+    int ce_dollarzero;	/* value of "$0" */
+};
+
+typedef struct _absolutepath
+{
+    t_object x_obj;
+    t_canvas *x_canvas;
+    int x_dolzero;
+    int x_realized;
+} t_absolutepath;
+
+t_class *absolutepath_class;
+
+void absolutepath_setup(void);
+
+static t_glist *getcanvas(t_glist *can,int d0)
+{
+    t_canvas *retcan=0;
+    t_gobj *ob;
+
+    if((can->gl_env)&&(can->gl_env->ce_dollarzero==d0))
+    {
+        return can;
+    }
+
+    ob=can->gl_list;
+    while(ob&&(retcan==0))
+    {
+        if (pd_class(&ob->g_pd) == canvas_class)
+            retcan=getcanvas((t_glist *)ob,d0);
+        ob=ob->g_next;
+    }
+
+    if((!retcan)&&(can->gl_next)) retcan=getcanvas((t_glist *)can->gl_next,d0);
+    return retcan;
+}
+
+
+static void absolutepath_symbol(t_absolutepath *x,t_symbol *sym)
+{
+    t_canvas *can=0;
+    char buf[MAXPDSTRING], *bufptr,
+         *instr=sym->s_name,
+          canname[MAXPDSTRING],totaldir[MAXPDSTRING],
+          *cnamedir,
+          *candir;
+    unsigned int n,i=0;
+    int fd;
+
+    if(!x->x_realized) can=(t_canvas *)getcanvas(canvas_list,x->x_dolzero);
+    if(can)
+    {
+        x->x_canvas = can;
+        x->x_realized = 1;
+    }
+
+    if(!instr) return;
+
+    candir=canvas_getdir(x->x_canvas)->s_name;
+    if(!candir) candir="";
+
+    strcpy(canname,x->x_canvas->gl_name->s_name);
+    cnamedir=dirname(canname);
+
+    if (strcmp(cnamedir,"."))
+    {
+        sprintf(totaldir,"%s/%s",candir,cnamedir);
+        fd=open_via_path(totaldir,instr ,"",buf, &bufptr, MAXPDSTRING, 1);
+    }
+    else
+        fd=open_via_path(candir, instr, "",buf, &bufptr, MAXPDSTRING, 1);
+
+    if (fd>=0)
+    {
+        close(fd);
+        buf[strlen(buf)]='/';
+        outlet_symbol(x->x_obj.ob_outlet,gensym(buf));
+    }
+    return;
+}
+
+
+static void *absolutepath_new(t_symbol *s,int argc,t_atom *argv)
+{
+    t_absolutepath *x = (t_absolutepath *)pd_new(absolutepath_class);
+    t_canvas *can=canvas_list;
+
+    outlet_new(&x->x_obj, 0);
+    x->x_canvas = canvas_getcurrent();
+	x->x_dolzero = 0;
+    if(argc>0){
+        if(argv->a_type==A_FLOAT) x->x_dolzero=atom_getint(argv);
+        else if(argv->a_type==A_SYMBOL)
+            x->x_dolzero=atoi(atom_getsymbol(argv)->s_name);
+    }
+    x->x_realized = x->x_dolzero?0:1;
+
+    return (void *)x;
+}
+
+void absolutepath_setup(void)
+{
+    absolutepath_class = class_new(gensym("absolutepath"),(t_newmethod)absolutepath_new,
+                                   0, sizeof(t_absolutepath), 0,A_GIMME, 0);
+
+    class_addsymbol(absolutepath_class, absolutepath_symbol);
+}
+
+#endif /* NOT _WIN32 */
diff --git a/basedir-help.pd b/basedir-help.pd
index cbf9c9e..b933bd4 100644
--- a/basedir-help.pd
+++ b/basedir-help.pd
@@ -1,18 +1,28 @@
-#N canvas 136 196 430 247 10;
-#X obj 0 0 cnv 8 100 60 empty empty basedir 20 20 1 18 -262144 -1109
-0;
-#X text 7 221 (c) Moonix: Antoine Rousseau 2003;
-#X text 135 12 basename/dirname functions;
-#X obj 124 102 basedir;
-#X obj 124 136 unpack s s;
-#X symbolatom 124 158 0 0 0;
-#X symbolatom 189 158 0 0 0;
-#X msg 124 62 symbol /usr/local/bin/pd;
-#X obj 124 42 loadbang;
-#X text 108 175 basename;
-#X text 212 175 dirname;
-#X connect 3 0 4 0;
-#X connect 4 0 5 0;
-#X connect 4 1 6 0;
-#X connect 7 0 3 0;
-#X connect 8 0 7 0;
+#N canvas 0 31 430 247 10;
+#X obj 0 0 cnv 8 100 60 empty empty basedir 20 20 1 18 -262144 -1109
+0;
+#X text 7 221 (c) Moonix: Antoine Rousseau 2003;
+#X text 135 12 basename/dirname functions;
+#X obj 124 102 basedir;
+#X obj 124 136 unpack s s;
+#X symbolatom 124 158 0 0 0 0 - - -;
+#X symbolatom 189 158 0 0 0 0 - - -;
+#X msg 124 62 symbol /usr/local/bin/pd;
+#X obj 124 42 loadbang;
+#X text 108 175 basename;
+#X text 212 175 dirname;
+#N canvas 380 146 494 344 META 0;
+#X text 12 25 LICENSE GPL v2;
+#X text 12 65 INLET_0 symbol;
+#X text 12 105 AUTHOR Antoine Rousseau;
+#X text 12 125 HELP_PATCH_AUTHORS Antoine Rousseau. "pd meta" information
+added by Jonathan Wilkes for Pd version 0.42.;
+#X text 12 5 KEYWORDS control symbol_op filesystem;
+#X text 12 45 DESCRIPTION basename/dirname functions;
+#X text 12 85 OUTLET_0 list;
+#X restore 373 217 pd META;
+#X connect 3 0 4 0;
+#X connect 4 0 5 0;
+#X connect 4 1 6 0;
+#X connect 7 0 3 0;
+#X connect 8 0 7 0;
diff --git a/basedir.c b/basedir.c
index 61ebcf4..abdda5c 100644
--- a/basedir.c
+++ b/basedir.c
@@ -1,75 +1,75 @@
-#ifndef _WIN32
-/*
-Copyright (C) 2002 Antoine Rousseau 
-
-This library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation; either
-version 2.1 of the License, or (at your option) any later version.
-
-This library 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
-Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with this library; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  
-
-*/
-
-/*#include <m_imp.h>*/
-#include "m_pd.h"
-
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
-#include <libgen.h>
-#include <string.h>
-
-typedef struct _basedir
-{
-    t_object x_obj;
-}t_basedir;
-
-t_class *basedir_class;
-
-void basedir_setup(void);
-
-static void basedir_symbol(t_basedir *x,t_symbol *sym)
-{
-	static t_binbuf *binbuf=0;
-	t_atom at[2];
-	char *b,*d;
-	int l;
-
-	if(!sym->s_name) return;
-
-	b=strdup(sym->s_name);
-	d=strdup(sym->s_name);
-
-	SETSYMBOL(&at[0],gensym(basename(b)));
-	SETSYMBOL(&at[1],gensym(dirname(d)));
-
-	outlet_list(x->x_obj.ob_outlet,0,2,at);
-}
-
-
-static void *basedir_new(void)
-{
-	t_basedir *x = (t_basedir *)pd_new(basedir_class);
-	outlet_new(&x->x_obj, 0);
-	return (void *)x;
-}
-
-void basedir_setup(void)
-{
-	basedir_class = class_new(gensym("basedir"),(t_newmethod)basedir_new,
-		0, sizeof(t_basedir), 0, 0);
-
-	class_addsymbol(basedir_class, basedir_symbol);
-}
-
-
-#endif /* NOT _WIN32 */
+#ifndef _WIN32
+/*
+Copyright (C) 2002 Antoine Rousseau
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+*/
+
+/*#include <m_imp.h>*/
+#include "m_pd.h"
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <libgen.h>
+#include <string.h>
+
+typedef struct _basedir
+{
+    t_object x_obj;
+} t_basedir;
+
+t_class *basedir_class;
+
+void basedir_setup(void);
+
+static void basedir_symbol(t_basedir *x,t_symbol *sym)
+{
+    static t_binbuf *binbuf=0;
+    t_atom at[2];
+    char *b,*d;
+    int l;
+
+    if(!sym->s_name) return;
+
+    b=strdup(sym->s_name);
+    d=strdup(sym->s_name);
+
+    SETSYMBOL(&at[0],gensym(basename(b)));
+    SETSYMBOL(&at[1],gensym(dirname(d)));
+
+    outlet_list(x->x_obj.ob_outlet,0,2,at);
+}
+
+
+static void *basedir_new(void)
+{
+    t_basedir *x = (t_basedir *)pd_new(basedir_class);
+    outlet_new(&x->x_obj, 0);
+    return (void *)x;
+}
+
+void basedir_setup(void)
+{
+    basedir_class = class_new(gensym("basedir"),(t_newmethod)basedir_new,
+                              0, sizeof(t_basedir), 0, 0);
+
+    class_addsymbol(basedir_class, basedir_symbol);
+}
+
+
+#endif /* NOT _WIN32 */
diff --git a/char2f-help.pd b/char2f-help.pd
index f133288..730e5a3 100644
--- a/char2f-help.pd
+++ b/char2f-help.pd
@@ -1,18 +1,28 @@
-#N canvas 134 318 430 247 10;
-#X obj 0 0 cnv 8 100 60 empty empty char2f_f2char 10 20 1 18 -262144
--1109 0;
-#X text 7 221 (c) Moonix: Antoine Rousseau 2003;
-#X text 160 14 ascii utilities;
-#X obj 131 115 char2f;
-#X floatatom 131 136 5 0 0;
-#X msg 131 69 symbol A;
-#X obj 131 173 f2char;
-#X symbolatom 131 194 2 0 0;
-#X obj 131 49 loadbang;
-#X msg 216 70 symbol a;
-#X connect 3 0 4 0;
-#X connect 4 0 6 0;
-#X connect 5 0 3 0;
-#X connect 6 0 7 0;
-#X connect 8 0 5 0;
-#X connect 9 0 3 0;
+#N canvas 0 31 430 247 10;
+#X obj 0 0 cnv 8 100 60 empty empty char2f_f2char 10 20 1 18 -262144
+-1109 0;
+#X text 7 221 (c) Moonix: Antoine Rousseau 2003;
+#X text 160 14 ascii utilities;
+#X obj 131 115 char2f;
+#X floatatom 131 136 5 0 0 0 - - -;
+#X msg 131 69 symbol A;
+#X obj 131 173 f2char;
+#X symbolatom 131 194 2 0 0 0 - - -;
+#X obj 131 49 loadbang;
+#X msg 216 70 symbol a;
+#N canvas 380 146 494 344 META 0;
+#X text 12 25 LICENSE GPL v2;
+#X text 12 65 INLET_0 symbol;
+#X text 12 105 AUTHOR Antoine Rousseau;
+#X text 12 125 HELP_PATCH_AUTHORS Antoine Rousseau. "pd meta" information
+added by Jonathan Wilkes for Pd version 0.42.;
+#X text 12 45 DESCRIPTION ascii utility;
+#X text 12 5 KEYWORDS control conversion symbol_op;
+#X text 12 85 OUTLET_0 float;
+#X restore 373 217 pd META;
+#X connect 3 0 4 0;
+#X connect 4 0 6 0;
+#X connect 5 0 3 0;
+#X connect 6 0 7 0;
+#X connect 8 0 5 0;
+#X connect 9 0 3 0;
diff --git a/char2f.c b/char2f.c
index ef8af99..f5097e5 100644
--- a/char2f.c
+++ b/char2f.c
@@ -1,53 +1,53 @@
-/*
-Copyright (C) 2002 Antoine Rousseau 
-
-This library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation; either
-version 2.1 of the License, or (at your option) any later version.
-
-This library 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
-Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with this library; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  
-
-*/
-
-#include "m_pd.h"
-
-
-typedef struct _char2f
-{
-    t_object x_obj;
-}t_char2f;
-
-t_class *char2f_class;
-
-void char2f_setup(void);
-
-static void char2f_symbol(t_char2f *x,t_symbol *sym)
-{
-	if(!sym->s_name) return;
-
-	outlet_float(x->x_obj.ob_outlet,(float)sym->s_name[0]);
-}
-
-static void *char2f_new(void)
-{  
-	t_char2f *x = (t_char2f *)pd_new(char2f_class);
-	outlet_new(&x->x_obj, &s_float);
-	return (void *)x;
-}
-
-void char2f_setup(void)
-{
-	char2f_class = class_new(gensym("char2f"),(t_newmethod)char2f_new, 
-		0, sizeof(t_char2f), 0, 0);
-
-	class_addsymbol(char2f_class, char2f_symbol);
-}
-
+/*
+Copyright (C) 2002 Antoine Rousseau
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+*/
+
+#include "m_pd.h"
+
+
+typedef struct _char2f
+{
+    t_object x_obj;
+} t_char2f;
+
+t_class *char2f_class;
+
+void char2f_setup(void);
+
+static void char2f_symbol(t_char2f *x,t_symbol *sym)
+{
+    if(!sym->s_name) return;
+
+    outlet_float(x->x_obj.ob_outlet,(t_float)sym->s_name[0]);
+}
+
+static void *char2f_new(void)
+{
+    t_char2f *x = (t_char2f *)pd_new(char2f_class);
+    outlet_new(&x->x_obj, &s_float);
+    return (void *)x;
+}
+
+void char2f_setup(void)
+{
+    char2f_class = class_new(gensym("char2f"),(t_newmethod)char2f_new,
+                             0, sizeof(t_char2f), 0, 0);
+
+    class_addsymbol(char2f_class, char2f_symbol);
+}
+
diff --git a/comma-help.pd b/comma-help.pd
index b8a8e63..6a36ea8 100644
--- a/comma-help.pd
+++ b/comma-help.pd
@@ -1,40 +1,25 @@
-#N canvas 172 316 715 428 10;
-#X obj 0 0 cnv 8 100 60 empty empty comma 10 20 1 18 -262144 -1109
-0;
-#X text 109 12 how to write " \, " in a message...;
-#X text 2 388 (c) Moonix: Antoine Rousseau 2004;
-#X msg 71 101 foo 1 \, bar 2;
-#X floatatom 70 340 5 0 0 0 - - -;
-#X floatatom 113 341 5 0 0 0 - - -;
-#X obj 70 318 route foo bar;
-#X text 59 85 build a message like this:;
-#X text 106 118 | notice the comma...;
-#X text 106 116 ^;
-#X obj 437 192 drip;
-#X obj 396 192 comma;
-#X msg 417 222 add2 \$1;
-#X msg 372 110 foo 10;
-#X obj 407 171 t b a;
-#X msg 331 82 set;
-#X msg 427 110 bar 20;
-#X msg 417 249 foo 10 \, bar 20 \,;
-#X obj 517 171 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
--1;
-#X text 39 72 0: what we want to do is to;
-#X text 299 64 1: reset the message;
-#X text 375 92 2: add parts;
-#X text 467 153 (or click the message directly);
-#X text 453 142 3: send the message;
-#X connect 3 0 6 0;
-#X connect 6 0 4 0;
-#X connect 6 1 5 0;
-#X connect 10 0 12 0;
-#X connect 11 0 12 0;
-#X connect 12 0 17 0;
-#X connect 13 0 14 0;
-#X connect 14 0 11 0;
-#X connect 14 1 10 0;
-#X connect 15 0 17 0;
-#X connect 16 0 14 0;
-#X connect 17 0 6 0;
-#X connect 18 0 17 0;
+#N canvas 529 154 292 237 10;
+#X obj 0 0 cnv 8 100 60 empty empty comma 10 20 1 18 -262144 -1109
+0;
+#X text 7 206 (c) Moonix: Antoine Rousseau 2004;
+#N canvas 378 151 494 344 META 0;
+#X text 12 25 LICENSE GPL v2;
+#X text 12 105 AUTHOR Antoine Rousseau;
+#X text 12 125 HELP_PATCH_AUTHORS Antoine Rousseau. "pd meta" information
+added by Jonathan Wilkes for Pd version 0.42.;
+#X text 12 5 KEYWORDS control deprecated;
+#X text 12 65 INLET_0 bang;
+#X text 12 85 OUTLET_0 comma;
+#X text 12 45 DESCRIPTION the ' \, ' message (deprecated);
+#X restore 225 203 pd META;
+#X obj 78 107 comma;
+#X obj 78 81 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1
+-1;
+#X msg 78 129 set \$1;
+#X msg 78 154 \,;
+#X obj 78 58 loadbang;
+#X text 95 16 the ' \, 'symbol;
+#X connect 3 0 5 0;
+#X connect 4 0 3 0;
+#X connect 5 0 6 0;
+#X connect 7 0 4 0;
diff --git a/comma.c b/comma.c
index 737d2b7..11cfca2 100644
--- a/comma.c
+++ b/comma.c
@@ -1,53 +1,53 @@
-/*
-Copyright (C) 2002 Antoine Rousseau 
-
-This library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation; either
-version 2.1 of the License, or (at your option) any later version.
-
-This library 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
-Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with this library; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  
-
-*/
-
-#include "m_pd.h"
-
-static t_atom _commaatom_;
-
-typedef struct _comma
-{
-    t_object x_obj;
-}t_comma;
-
-t_class *comma_class;
-
-void comma_setup(void);
-
-static void comma_bang(t_comma *x)
-{
-	outlet_list(x->x_obj.ob_outlet, &s_list, 1, &_commaatom_);
-}
-
-static void *comma_new(void)
-{  
-	t_comma *x = (t_comma *)pd_new(comma_class);
-	outlet_new(&x->x_obj,&s_symbol);
-	return (void *)x;
-}
-
-void comma_setup(void)
-{
-	comma_class = class_new(gensym("comma"),(t_newmethod)comma_new, 
-		0, sizeof(t_comma), 0, 0);
-
-	class_addbang(comma_class, comma_bang);
-	SETCOMMA(&_commaatom_);
-}
-
+/*
+Copyright (C) 2002 Antoine Rousseau
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+*/
+
+#include "m_pd.h"
+
+static t_atom _commaatom_;
+
+typedef struct _comma
+{
+    t_object x_obj;
+} t_comma;
+
+t_class *comma_class;
+
+void comma_setup(void);
+
+static void comma_bang(t_comma *x)
+{
+    outlet_list(x->x_obj.ob_outlet, &s_list, 1, &_commaatom_);
+}
+
+static void *comma_new(void)
+{
+    t_comma *x = (t_comma *)pd_new(comma_class);
+    outlet_new(&x->x_obj,&s_symbol);
+    return (void *)x;
+}
+
+void comma_setup(void)
+{
+    comma_class = class_new(gensym("comma"),(t_newmethod)comma_new,
+                            0, sizeof(t_comma), 0, 0);
+
+    class_addbang(comma_class, comma_bang);
+    SETCOMMA(&_commaatom_);
+}
+
diff --git a/dinlet~-help.pd b/dinlet~-help.pd
index 8033afe..baf54da 100644
--- a/dinlet~-help.pd
+++ b/dinlet~-help.pd
@@ -1,37 +1,52 @@
-#N canvas 196 161 422 282 10;
-#X text 6 248 (c) Antoine Rousseau 2001;
-#X obj 9 5 dinlet~;
-#X text 66 6 A signal inlet with a default value.;
-#N canvas 178 154 300 161 --- 0;
-#X obj 108 70 unsig~ 50;
-#X obj 108 96 outlet;
-#X obj 196 71 unsig~ 50;
-#X obj 196 97 outlet;
-#X obj 108 43 dinlet~ 1;
-#X obj 196 44 dinlet~ 2;
-#X obj 29 70 unsig~ 50;
-#X obj 29 96 outlet;
-#X obj 29 43 inlet~;
-#X connect 0 0 1 0;
-#X connect 2 0 3 0;
-#X connect 4 0 0 0;
-#X connect 5 0 2 0;
-#X connect 6 0 7 0;
-#X connect 8 0 6 0;
-#X restore 112 100 pd ---;
-#X floatatom 130 158 5 0 0;
-#X floatatom 33 159 5 0 0;
-#X floatatom 242 157 5 0 0;
-#X obj 129 56 sig~ 5;
-#X text 3 180 normal inlet~;
-#X text 129 177 dinlet~ with;
-#X text 128 192 default 1;
-#X text 242 177 dinlet~ with;
-#X text 241 192 default 2;
-#X text 199 61 try connect and deconnect;
-#X text 198 77 sig~ object to each of;
-#X text 198 93 the subpatch inlets.;
-#X connect 3 0 5 0;
-#X connect 3 1 4 0;
-#X connect 3 2 6 0;
-#X connect 7 0 3 2;
+#N canvas 956 331 422 282 10;
+#X text 6 248 (c) Antoine Rousseau 2001;
+#X obj 9 5 dinlet~;
+#X text 66 6 A signal inlet with a default value.;
+#N canvas 176 159 438 278 --- 0;
+#X obj 107 165 outlet;
+#X obj 195 166 outlet;
+#X obj 108 43 dinlet~ 1;
+#X obj 196 44 dinlet~ 2;
+#X obj 28 165 outlet;
+#X obj 29 43 inlet~;
+#X obj 28 116 snapshot~;
+#X obj 284 65 metro 300;
+#X obj 284 41 loadbang;
+#X obj 107 115 snapshot~;
+#X obj 195 117 snapshot~;
+#X connect 2 0 9 0;
+#X connect 3 0 10 0;
+#X connect 5 0 6 0;
+#X connect 6 0 4 0;
+#X connect 7 0 6 0;
+#X connect 7 0 9 0;
+#X connect 7 0 10 0;
+#X connect 8 0 7 0;
+#X connect 9 0 0 0;
+#X connect 10 0 1 0;
+#X restore 112 100 pd ---;
+#X floatatom 128 158 5 0 0 0 - - -, f 5;
+#X floatatom 33 159 5 0 0 0 - - -, f 5;
+#X floatatom 242 157 5 0 0 0 - - -, f 5;
+#X obj 129 56 sig~ 5;
+#X text 3 180 normal inlet~;
+#X text 127 177 dinlet~ with;
+#X text 126 192 default 1;
+#X text 242 177 dinlet~ with;
+#X text 241 192 default 2;
+#X text 198 93 the subpatch inlets.;
+#N canvas 380 146 494 344 META 0;
+#X text 12 25 LICENSE GPL v2;
+#X text 12 85 AUTHOR Antoine Rousseau;
+#X text 12 105 HELP_PATCH_AUTHORS Antoine Rousseau. "pd meta" information
+added by Jonathan Wilkes for Pd version 0.42.;
+#X text 12 5 KEYWORDS signal canvas_op;
+#X text 12 45 DESCRIPTION signal inlet with a default value;
+#X text 12 65 OUTLET_0 signal;
+#X restore 363 247 pd META;
+#X text 199 61 try connect and disconnect;
+#X text 198 77 sig~ object to/from each of;
+#X connect 3 0 5 0;
+#X connect 3 1 4 0;
+#X connect 3 2 6 0;
+#X connect 7 0 3 2;
diff --git a/dinlet~.c b/dinlet~.c
index 7933eac..313d268 100644
--- a/dinlet~.c
+++ b/dinlet~.c
@@ -1,136 +1,136 @@
-/*
-Copyright (C) 2002 Antoine Rousseau 
-
-This library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation; either
-version 2.1 of the License, or (at your option) any later version.
-
-This library 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
-Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with this library; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  
-
-*/
-
-/* this file is made from parts of m_object.c and g_io.c
-* 	it defines a signal inlet named dinlet~ which is the same as inlet~
-*  exepts you can give a default float value for the case none signal 
-*  is connected to this inlet~. */
-
-/***********************************************************************/
-/* CAUTION : 
-		You MUST fix a bug pd sources and recompile them in order to have 
-	dinlet~ working !!
-
-	this function must be fixed in pd/m_obj.c:								  */
-#if 0
-t_sample *obj_findsignalscalar(t_object *x, int m)
-{
-    int n = 0,mbak=m;
-    t_inlet *i;
-	 post("my obj_findsignalscalar");
-    if (x->ob_pd->c_firstin && x->ob_pd->c_floatsignalin)
-    {
-    	if (!m--)
-	    return (x->ob_pd->c_floatsignalin > 0 ?
-	    	(t_sample *)(((char *)x) + x->ob_pd->c_floatsignalin) : 0);
-    	n++;
-    }
-    for (i = x->ob_inlet; i; i = i->i_next, m--)
-    	if (i->i_symfrom == &s_signal)
-    {
-    	/*if (m == 0)*/
-		if(n==mbak)
-	    return (&i->i_un.iu_floatsignalvalue);
-    	n++;
-    }
-    return (0);
-}
-#endif
-/***********************************************************************/
-
-#include "m_pd.h"
-#include "m_imp.h"
-#include "g_canvas.h"
-#include <string.h>
-
-/******************** from m_obj.c: **************************/
-/* only because inlet_float() is not public... */
-union inletunion
-{
-    t_symbol *iu_symto;
-    t_gpointer *iu_pointerslot;
-    t_float *iu_floatslot;
-    t_symbol **iu_symslot;
-    t_sample iu_floatsignalvalue;
-};
-
-struct _inlet
-{
-    t_pd i_pd;
-    struct _inlet *i_next;
-    t_object *i_owner;
-    t_pd *i_dest;
-    t_symbol *i_symfrom;
-    union inletunion i_un;
-};
-
-#define i_symto i_un.iu_symto
-
-static void dinlet_float(t_inlet *x, t_float f)
-{
-    if (x->i_symfrom == &s_float)
-    	pd_vmess(x->i_dest, x->i_symto, "f", (t_floatarg)f);
-    else if (x->i_symfrom == &s_signal)
-    	x->i_un.iu_floatsignalvalue = f;
-    else if (!x->i_symfrom)
-    	pd_float(x->i_dest, f);
-    /*else inlet_wrong(x, &s_float);*/
-}
-/**************** from g_io.c : *********************************/
-
-void signal_setborrowed(t_signal *sig, t_signal *sig2);
-void signal_makereusable(t_signal *sig);
-
-/* ------------------------- vinlet -------------------------- */
-t_class *vinlet_class;
-
-typedef struct _vinlet
-{
-    t_object x_obj;
-    t_canvas *x_canvas;
-    t_inlet *x_inlet;
-    int x_bufsize;
-    t_float *x_buf; 	    /* signal buffer; zero if not a signal */
-    t_float *x_endbuf;
-    t_float *x_fill;
-    t_float *x_read;
-    int x_hop;
-    	/* if not reblocking, the next slot communicates the parent's inlet
-	signal from the prolog to the DSP routine: */
-    t_signal *x_directsignal;
-} t_vinlet;
-
-
-static void *dinlet_newsig(t_floatarg f)
-{
-    t_vinlet *x = (t_vinlet *)pd_new(vinlet_class);
-    x->x_canvas = canvas_getcurrent();
-    x->x_inlet = canvas_addinlet(x->x_canvas, &x->x_obj.ob_pd, &s_signal);
-    x->x_endbuf = x->x_buf = (t_float *)getbytes(0);
-    x->x_bufsize = 0;
-    x->x_directsignal = 0;
-	 x->x_inlet->i_un.iu_floatsignalvalue=f;
-    outlet_new(&x->x_obj, &s_signal);
-    return (x);
-}
-
-void dinlet_tilde_setup(void)
-{
-    class_addcreator((t_newmethod)dinlet_newsig, gensym("dinlet~"), A_DEFFLOAT,0);
-}
+/*
+Copyright (C) 2002 Antoine Rousseau
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+*/
+
+/* this file is made from parts of m_object.c and g_io.c
+* 	it defines a signal inlet named dinlet~ which is the same as inlet~
+*  exepts you can give a default float value for the case none signal
+*  is connected to this inlet~. */
+
+/***********************************************************************/
+/* CAUTION :
+		You MUST fix a bug pd sources and recompile them in order to have
+	dinlet~ working !!
+
+	this function must be fixed in pd/m_obj.c:								  */
+#if 0
+t_sample *obj_findsignalscalar(t_object *x, int m)
+{
+    int n = 0,mbak=m;
+    t_inlet *i;
+    post("my obj_findsignalscalar");
+    if (x->ob_pd->c_firstin && x->ob_pd->c_floatsignalin)
+    {
+        if (!m--)
+            return (x->ob_pd->c_floatsignalin > 0 ?
+                    (t_sample *)(((char *)x) + x->ob_pd->c_floatsignalin) : 0);
+        n++;
+    }
+    for (i = x->ob_inlet; i; i = i->i_next, m--)
+        if (i->i_symfrom == &s_signal)
+        {
+            /*if (m == 0)*/
+            if(n==mbak)
+                return (&i->i_un.iu_floatsignalvalue);
+            n++;
+        }
+    return (0);
+}
+#endif
+/***********************************************************************/
+
+#include "m_pd.h"
+#include "m_imp.h"
+#include "g_canvas.h"
+#include <string.h>
+
+/******************** from m_obj.c: **************************/
+/* only because inlet_float() is not public... */
+union inletunion
+{
+    t_symbol *iu_symto;
+    t_gpointer *iu_pointerslot;
+    t_float *iu_floatslot;
+    t_symbol **iu_symslot;
+    t_sample iu_floatsignalvalue;
+};
+
+struct _inlet
+{
+    t_pd i_pd;
+    struct _inlet *i_next;
+    t_object *i_owner;
+    t_pd *i_dest;
+    t_symbol *i_symfrom;
+    union inletunion i_un;
+};
+
+#define i_symto i_un.iu_symto
+
+static void dinlet_float(t_inlet *x, t_float f)
+{
+    if (x->i_symfrom == &s_float)
+        pd_vmess(x->i_dest, x->i_symto, "f", (t_floatarg)f);
+    else if (x->i_symfrom == &s_signal)
+        x->i_un.iu_floatsignalvalue = f;
+    else if (!x->i_symfrom)
+        pd_float(x->i_dest, f);
+    /*else inlet_wrong(x, &s_float);*/
+}
+/**************** from g_io.c : *********************************/
+
+void signal_setborrowed(t_signal *sig, t_signal *sig2);
+void signal_makereusable(t_signal *sig);
+
+/* ------------------------- vinlet -------------------------- */
+t_class *vinlet_class;
+
+typedef struct _vinlet
+{
+    t_object x_obj;
+    t_canvas *x_canvas;
+    t_inlet *x_inlet;
+    int x_bufsize;
+    t_float *x_buf; 	    /* signal buffer; zero if not a signal */
+    t_float *x_endbuf;
+    t_float *x_fill;
+    t_float *x_read;
+    int x_hop;
+    /* if not reblocking, the next slot communicates the parent's inlet
+    signal from the prolog to the DSP routine: */
+    t_signal *x_directsignal;
+} t_vinlet;
+
+
+static void *dinlet_newsig(t_floatarg f)
+{
+    t_vinlet *x = (t_vinlet *)pd_new(vinlet_class);
+    x->x_canvas = canvas_getcurrent();
+    x->x_inlet = canvas_addinlet(x->x_canvas, &x->x_obj.ob_pd, &s_signal);
+    x->x_endbuf = x->x_buf = (t_float *)getbytes(0);
+    x->x_bufsize = 0;
+    x->x_directsignal = 0;
+    x->x_inlet->i_un.iu_floatsignalvalue=f;
+    outlet_new(&x->x_obj, &s_signal);
+    return (x);
+}
+
+void dinlet_tilde_setup(void)
+{
+    class_addcreator((t_newmethod)dinlet_newsig, gensym("dinlet~"), A_DEFFLOAT,0);
+}
diff --git a/dispatch-help.pd b/dispatch-help.pd
index 16231ef..d695fc0 100644
--- a/dispatch-help.pd
+++ b/dispatch-help.pd
@@ -1,65 +1,75 @@
-#N canvas 479 347 565 404 10;
-#X obj 0 0 cnv 8 100 60 empty empty dispatch 10 20 1 18 -262144 -1109
-0;
-#X obj 40 131 r foo1-rcv;
-#X obj 40 151 print foo1;
-#X obj 121 131 r foo2-rcv;
-#X obj 121 151 print foo2;
-#X obj 198 132 r foo3-rcv;
-#X obj 198 152 print foo3;
-#X obj 293 78 dispatch foo 1 3;
-#X text 291 60 args: name min-index max-index;
-#X msg 310 102 2 truc;
-#X text 132 12 link several pairs of send/receive addresses to;
-#X msg 39 82 f1snd;
-#X msg 119 83 f2snd;
-#X msg 197 83 f3snd;
-#X obj 39 102 s foo1-snd;
-#X obj 119 103 s foo2-snd;
-#X obj 197 103 s foo3-snd;
-#X obj 310 154 r foo-snd;
-#X obj 310 122 s foo-rcv;
-#X obj 310 175 print foo-snd;
-#X text 406 162 one "send" from all;
-#X text 382 110 one "receive" to all;
-#X obj 35 208 cnv 15 300 150 empty empty empty 20 12 0 14 -261681 -66577
-0;
-#X obj 77 223 tgl 15 0 \$0-bar1-snd \$0-bar1-rcv bar1 0 -6 1 8 -262144
--1 -1 0 1;
-#X obj 104 223 tgl 15 0 \$0-bar2-snd \$0-bar2-rcv bar2 0 -6 1 8 -262144
--1 -1 0 1;
-#X obj 132 223 tgl 15 0 \$0-bar3-snd \$0-bar3-rcv bar3 0 -6 1 8 -262144
--1 -1 0 1;
-#X obj 49 223 tgl 15 0 \$0-bar0-snd \$0-bar0-rcv bar0 0 -6 1 8 -262144
--1 -1 0 1;
-#X obj 173 321 s \$0-bar-rcv;
-#X obj 49 276 r \$0-bar-snd;
-#X obj 173 276 hdl 15 0 0 4 empty empty empty 0 -6 0 8 -262144 -1 -1
-1;
-#X obj 185 221 dispatch \$0-bar 0 3;
-#X msg 173 297 \$1 bang;
-#X obj 49 298 unpack f f;
-#X floatatom 49 319 2 0 0 0 - - -;
-#X floatatom 114 320 2 0 0 0 - - -;
-#X text 5 383 (c) Moonix: Antoine Rousseau 2004;
-#X text 362 238 Warning: you HAVE to name;
-#X text 343 254 your boutton buses like this:;
-#X text 362 241 _______;
-#X text 351 280 (notice the -snd and -rcv);
-#X text 351 268 skeletonX-snd skeletonX-rcv;
-#X text 134 24 a single one \, in which datas are prepended by the
-number;
-#X text 134 37 of the receiver/sender.;
-#X connect 1 0 2 0;
-#X connect 3 0 4 0;
-#X connect 5 0 6 0;
-#X connect 9 0 18 0;
-#X connect 11 0 14 0;
-#X connect 12 0 15 0;
-#X connect 13 0 16 0;
-#X connect 17 0 19 0;
-#X connect 28 0 32 0;
-#X connect 29 0 31 0;
-#X connect 31 0 27 0;
-#X connect 32 0 33 0;
-#X connect 32 1 34 0;
+#N canvas 1 93 565 421 10;
+#X obj 0 0 cnv 8 100 60 empty empty dispatch 10 20 1 18 -262144 -1109
+0;
+#X obj 40 131 r foo1-rcv;
+#X obj 40 151 print foo1;
+#X obj 121 131 r foo2-rcv;
+#X obj 121 151 print foo2;
+#X obj 198 132 r foo3-rcv;
+#X obj 198 152 print foo3;
+#X obj 293 78 dispatch foo 1 3;
+#X text 291 60 args: name min-index max-index;
+#X msg 310 102 2 truc;
+#X text 132 12 link several pairs of send/receive addresses to;
+#X msg 39 82 f1snd;
+#X msg 119 83 f2snd;
+#X msg 197 83 f3snd;
+#X obj 39 102 s foo1-snd;
+#X obj 119 103 s foo2-snd;
+#X obj 197 103 s foo3-snd;
+#X obj 310 154 r foo-snd;
+#X obj 310 122 s foo-rcv;
+#X obj 310 175 print foo-snd;
+#X text 406 162 one "send" from all;
+#X text 382 110 one "receive" to all;
+#X obj 35 208 cnv 15 300 150 empty empty empty 20 12 0 14 -261681 -66577
+0;
+#X obj 77 223 tgl 15 0 \$0-bar1-snd \$0-bar1-rcv bar1 0 -6 1 8 -262144
+-1 -1 1 1;
+#X obj 104 223 tgl 15 0 \$0-bar2-snd \$0-bar2-rcv bar2 0 -6 1 8 -262144
+-1 -1 1 1;
+#X obj 132 223 tgl 15 0 \$0-bar3-snd \$0-bar3-rcv bar3 0 -6 1 8 -262144
+-1 -1 0 1;
+#X obj 49 223 tgl 15 0 \$0-bar0-snd \$0-bar0-rcv bar0 0 -6 1 8 -262144
+-1 -1 1 1;
+#X obj 173 321 s \$0-bar-rcv;
+#X obj 49 276 r \$0-bar-snd;
+#X obj 173 276 hdl 15 0 0 4 empty empty empty 0 -6 0 8 -262144 -1 -1
+1;
+#X obj 183 221 dispatch \$0-bar 0 3;
+#X msg 173 297 \$1 bang;
+#X obj 49 298 unpack f f;
+#X floatatom 49 319 2 0 0 0 - - -, f 2;
+#X floatatom 114 320 2 0 0 0 - - -, f 2;
+#X text 5 383 (c) Moonix: Antoine Rousseau 2004;
+#X text 362 238 Warning: you HAVE to name;
+#X text 343 254 your boutton buses like this:;
+#X text 362 241 _______;
+#X text 351 280 (notice the -snd and -rcv);
+#X text 351 268 skeletonX-snd skeletonX-rcv;
+#X text 134 37 of the receiver/sender.;
+#N canvas 529 242 494 344 META 0;
+#X text 12 25 LICENSE GPL v2;
+#X text 12 95 AUTHOR Antoine Rousseau;
+#X text 12 115 HELP_PATCH_AUTHORS Antoine Rousseau. "pd meta" information
+added by Jonathan Wilkes for Pd version 0.42.;
+#X text 12 45 DESCRIPTION link several pairs of send/receive addresses
+to a single one;
+#X text 12 75 INLET_0;
+#X text 12 5 KEYWORDS control nonlocal;
+#X restore 508 371 pd META;
+#X text 134 24 a single one \, in which data is prepended by the number
+;
+#X connect 1 0 2 0;
+#X connect 3 0 4 0;
+#X connect 5 0 6 0;
+#X connect 9 0 18 0;
+#X connect 11 0 14 0;
+#X connect 12 0 15 0;
+#X connect 13 0 16 0;
+#X connect 17 0 19 0;
+#X connect 28 0 32 0;
+#X connect 29 0 31 0;
+#X connect 31 0 27 0;
+#X connect 32 0 33 0;
+#X connect 32 1 34 0;
diff --git a/dispatch.c b/dispatch.c
index f8a937a..4cf6006 100644
--- a/dispatch.c
+++ b/dispatch.c
@@ -1,194 +1,200 @@
-/*
-Copyright (C) 2003 Antoine Rousseau 
-
-This library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation; either
-version 2.1 of the License, or (at your option) any later version.
-
-This library 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
-Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with this library; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  
-
-*/
-
-/* a shared symbol array, ala "value" .*/
-
-#include "m_pd.h"
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-
-static t_class *dispatch_class, *dispsnd_class;
-static t_symbol *s__;
-
-typedef struct _dispatch t_dispatch;
-
-typedef struct dispsnd
-{
-    t_pd d_pd;
-    t_symbol *d_eachsnd;
-    t_symbol *d_allsnd;
-    t_int d_num;
-} t_dispsnd;
-
-struct _dispatch
-{
-    t_object x_obj;
-    t_symbol *x_sym;
-    int x_from;
-    int x_to;
-
-    t_dispsnd **x_snds;
-
-    t_symbol *x_allrcv;
-    t_symbol **x_eachrcvs;
-};
-
-/*--------------------- dispsnd ------------------------------------*/
-
-static void dispsnd_ff(t_dispsnd *x)
-{
-	pd_unbind((t_pd*)x, x->d_eachsnd);
-}
-
-static void *dispsnd_new(t_symbol *eachsnd,t_symbol *allsnd,int num)
-{
-    t_dispsnd *x = (t_dispsnd *)pd_new(dispsnd_class);
-	
-	//post("new dispsnd: num=%d rcv=%s snd=%s",num,eachsnd->s_name,allsnd->s_name);
-	x->d_eachsnd=eachsnd;
-	x->d_allsnd=allsnd;
-	x->d_num=num;
-
-	pd_bind((t_pd*)x, x->d_eachsnd);
-	
-    return (x);
-}
-
-static void dispsnd_float(t_dispsnd *x, t_float f)
-{
-	t_atom out[2];
-
-	if (x->d_allsnd->s_thing) {
-		SETFLOAT(&out[0],x->d_num);
-		SETFLOAT(&out[1],f);
-	
-		typedmess(x->d_allsnd->s_thing, &s_list, 2, out);
-	}
-}
-
-static void dispsnd_anything(t_dispsnd *x, t_symbol *s, int argc, t_atom *argv)
-{
-	t_atom *out;
-
-	if (x->d_allsnd->s_thing) {
-		out = (t_atom*)getbytes(sizeof(t_atom)*(argc+2));
-		memcpy(&out[2], argv, argc*sizeof(t_atom));
-		SETFLOAT(&out[0],x->d_num);
-		SETSYMBOL(&out[1],s);
-	
-		typedmess(x->d_allsnd->s_thing, &s_list, argc+2, out);
-
-		freebytes(out, sizeof(t_atom)*(argc+2));
-	}
-}
-
-
-
-/*--------------------- dispatch ------------------------------------*/
- 
-static void *dispatch_new(t_symbol *s,t_float from,t_float to)
-{
-    int i,len;
-	t_dispatch *x = (t_dispatch *)pd_new(dispatch_class);
-	char str[512];
-	t_symbol *allsnd,*eachsnd;
- 
-	x->x_snds=0;
-    x->x_sym = s;
-    x->x_from = from;
-    x->x_to = to;
-	len=x->x_to-x->x_from+1;
-	
-	if(len>0){
-		sprintf(str,"%s-snd",x->x_sym->s_name);
-		allsnd=gensym(str);
-
-		sprintf(str,"%s-rcv",x->x_sym->s_name);
-		x->x_allrcv=gensym(str);
-		pd_bind((t_pd*)x, x->x_allrcv);
-		
-		x->x_snds=getbytes(len*sizeof(t_dispsnd *));
-		x->x_eachrcvs=getbytes(len*sizeof(t_symbol *));
-
-		for(i=0;i<len;i++){
-			sprintf(str,"%s%d-snd",x->x_sym->s_name,i+x->x_from);
-			eachsnd=gensym(str);
-			x->x_snds[i]=dispsnd_new(eachsnd,allsnd,i+x->x_from);
-
-			sprintf(str,"%s%d-rcv",x->x_sym->s_name,i+x->x_from);
-			x->x_eachrcvs[i]=gensym(str);
-		}
-	}		
-    return (x);
-}
-
-static void dispatch_ff(t_dispatch *x)
-{
-	int i,len=x->x_to-x->x_from+1;
-
-	if(len<=0) return;
-	
-	pd_unbind((t_pd*)x, x->x_allrcv);
-
-	for(i=0;i<len;i++) pd_free((t_pd*)x->x_snds[i]);
-
-	freebytes(x->x_snds,len*sizeof(t_dispsnd *));
-	freebytes(x->x_eachrcvs,len*sizeof(t_symbol *));
-}
-
-
-static void dispatch_list(t_dispatch *x, t_symbol *s, int argc, t_atom *argv)
-{
-	int num;
-
-    if((!argc)|(argv[0].a_type!=A_FLOAT)) {
-		error("dispatch: bad list format");
-		return;
-	}
-	
-	num=atom_getint(&argv[0]);
-	
-	if((num<x->x_from)|(num>x->x_to)) {
-		//error("dispatch: bad num");
-		return;
-	}
-	
-	if (x->x_eachrcvs[num-x->x_from]->s_thing) 
-		pd_forwardmess(x->x_eachrcvs[num-x->x_from]->s_thing, argc-1, argv+1);
-}
-
-
-
-
-/*--------------------------------------------------------------*/
-
-void dispatch_setup(void)
-{
-	dispatch_class = class_new(gensym("dispatch"), (t_newmethod)dispatch_new,
-    	(t_method)dispatch_ff,
-    	sizeof(t_dispatch), 0, A_SYMBOL, A_FLOAT, A_FLOAT,0);
-
-    class_addlist(dispatch_class, dispatch_list);
-	dispsnd_class = class_new(gensym("dispatch"), 0, (t_method)dispsnd_ff,
-    	sizeof(t_dispsnd), CLASS_PD, 0);
-    class_addanything(dispsnd_class, dispsnd_anything);
-    class_addfloat(dispsnd_class, dispsnd_float);
-}
-
+/*
+Copyright (C) 2003 Antoine Rousseau
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+*/
+
+/* a shared symbol array, ala "value" .*/
+
+#include "m_pd.h"
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+static t_class *dispatch_class, *dispsnd_class;
+static t_symbol *s__;
+
+typedef struct _dispatch t_dispatch;
+
+typedef struct dispsnd
+{
+    t_pd d_pd;
+    t_symbol *d_eachsnd;
+    t_symbol *d_allsnd;
+    t_int d_num;
+} t_dispsnd;
+
+struct _dispatch
+{
+    t_object x_obj;
+    t_symbol *x_sym;
+    int x_from;
+    int x_to;
+
+    t_dispsnd **x_snds;
+
+    t_symbol *x_allrcv;
+    t_symbol **x_eachrcvs;
+};
+
+/*--------------------- dispsnd ------------------------------------*/
+
+static void dispsnd_ff(t_dispsnd *x)
+{
+    pd_unbind((t_pd *)x, x->d_eachsnd);
+}
+
+static void *dispsnd_new(t_symbol *eachsnd,t_symbol *allsnd,int num)
+{
+    t_dispsnd *x = (t_dispsnd *)pd_new(dispsnd_class);
+
+    //post("new dispsnd: num=%d rcv=%s snd=%s",num,eachsnd->s_name,allsnd->s_name);
+    x->d_eachsnd=eachsnd;
+    x->d_allsnd=allsnd;
+    x->d_num=num;
+
+    pd_bind((t_pd *)x, x->d_eachsnd);
+
+    return (x);
+}
+
+static void dispsnd_float(t_dispsnd *x, t_float f)
+{
+    t_atom out[2];
+
+    if (x->d_allsnd->s_thing)
+    {
+        SETFLOAT(&out[0],x->d_num);
+        SETFLOAT(&out[1],f);
+
+        typedmess(x->d_allsnd->s_thing, &s_list, 2, out);
+    }
+}
+
+static void dispsnd_anything(t_dispsnd *x, t_symbol *s, int argc, t_atom *argv)
+{
+    t_atom *out;
+
+    if (x->d_allsnd->s_thing)
+    {
+        out = (t_atom *)getbytes(sizeof(t_atom)*(argc+2));
+        memcpy(&out[2], argv, argc*sizeof(t_atom));
+        SETFLOAT(&out[0],x->d_num);
+        SETSYMBOL(&out[1],s);
+
+        typedmess(x->d_allsnd->s_thing, &s_list, argc+2, out);
+
+        freebytes(out, sizeof(t_atom)*(argc+2));
+    }
+}
+
+
+
+/*--------------------- dispatch ------------------------------------*/
+
+static void *dispatch_new(t_symbol *s,t_float from,t_float to)
+{
+    int i,len;
+    t_dispatch *x = (t_dispatch *)pd_new(dispatch_class);
+    char str[512];
+    t_symbol *allsnd,*eachsnd;
+
+    x->x_snds=0;
+    x->x_sym = s;
+    x->x_from = from;
+    x->x_to = to;
+    len=x->x_to-x->x_from+1;
+
+    if(len>0)
+    {
+        sprintf(str,"%s-snd",x->x_sym->s_name);
+        allsnd=gensym(str);
+
+        sprintf(str,"%s-rcv",x->x_sym->s_name);
+        x->x_allrcv=gensym(str);
+        pd_bind((t_pd *)x, x->x_allrcv);
+
+        x->x_snds=getbytes(len*sizeof(t_dispsnd *));
+        x->x_eachrcvs=getbytes(len*sizeof(t_symbol *));
+
+        for(i=0; i<len; i++)
+        {
+            sprintf(str,"%s%d-snd",x->x_sym->s_name,i+x->x_from);
+            eachsnd=gensym(str);
+            x->x_snds[i]=dispsnd_new(eachsnd,allsnd,i+x->x_from);
+
+            sprintf(str,"%s%d-rcv",x->x_sym->s_name,i+x->x_from);
+            x->x_eachrcvs[i]=gensym(str);
+        }
+    }
+    return (x);
+}
+
+static void dispatch_ff(t_dispatch *x)
+{
+    int i,len=x->x_to-x->x_from+1;
+
+    if(len<=0) return;
+
+    pd_unbind((t_pd *)x, x->x_allrcv);
+
+    for(i=0; i<len; i++) pd_free((t_pd *)x->x_snds[i]);
+
+    freebytes(x->x_snds,len*sizeof(t_dispsnd *));
+    freebytes(x->x_eachrcvs,len*sizeof(t_symbol *));
+}
+
+
+static void dispatch_list(t_dispatch *x, t_symbol *s, int argc, t_atom *argv)
+{
+    int num;
+
+    if((!argc)|(argv[0].a_type!=A_FLOAT))
+    {
+        error("dispatch: bad list format");
+        return;
+    }
+
+    num=atom_getint(&argv[0]);
+
+    if((num<x->x_from)|(num>x->x_to))
+    {
+        //error("dispatch: bad num");
+        return;
+    }
+
+    if (x->x_eachrcvs[num-x->x_from]->s_thing)
+        pd_forwardmess(x->x_eachrcvs[num-x->x_from]->s_thing, argc-1, argv+1);
+}
+
+
+
+
+/*--------------------------------------------------------------*/
+
+void dispatch_setup(void)
+{
+    dispatch_class = class_new(gensym("dispatch"), (t_newmethod)dispatch_new,
+                               (t_method)dispatch_ff,
+                               sizeof(t_dispatch), 0, A_SYMBOL, A_FLOAT, A_FLOAT,0);
+
+    class_addlist(dispatch_class, dispatch_list);
+    dispsnd_class = class_new(gensym("dispatch"), 0, (t_method)dispsnd_ff,
+                              sizeof(t_dispsnd), CLASS_PD, 0);
+    class_addanything(dispsnd_class, dispsnd_anything);
+    class_addfloat(dispsnd_class, dispsnd_float);
+}
+
diff --git a/dripchar-help.pd b/dripchar-help.pd
index 6318f36..c34fec9 100644
--- a/dripchar-help.pd
+++ b/dripchar-help.pd
@@ -1,28 +1,38 @@
-#N canvas 117 153 430 247 10;
-#X obj 0 0 cnv 8 100 60 empty empty dripchar 10 20 1 18 -262144 -1109
-0;
-#X text 7 221 (c) Moonix: Antoine Rousseau 2003;
-#X obj 131 49 loadbang;
-#X obj 131 95 dripchar;
-#X msg 131 69 symbol Antoine;
-#X text 132 12 drip characters from a symbol to a list;
-#X obj 131 117 unpack s s s s s s s;
-#X symbolatom 131 142 1 0 0;
-#X symbolatom 153 142 1 0 0;
-#X symbolatom 176 142 1 0 0;
-#X symbolatom 198 142 1 0 0;
-#X symbolatom 221 142 1 0 0;
-#X symbolatom 243 142 1 0 0;
-#X symbolatom 266 142 1 0 0;
-#X msg 245 69 symbol moonix_;
-#X connect 2 0 4 0;
-#X connect 3 0 6 0;
-#X connect 4 0 3 0;
-#X connect 6 0 7 0;
-#X connect 6 1 8 0;
-#X connect 6 2 9 0;
-#X connect 6 3 10 0;
-#X connect 6 4 11 0;
-#X connect 6 5 12 0;
-#X connect 6 6 13 0;
-#X connect 14 0 3 0;
+#N canvas 1 82 430 259 10;
+#X obj 0 0 cnv 8 100 60 empty empty dripchar 10 20 1 18 -262144 -1109
+0;
+#X text 7 221 (c) Moonix: Antoine Rousseau 2003;
+#X obj 131 49 loadbang;
+#X obj 131 95 dripchar;
+#X msg 131 69 symbol Antoine;
+#X text 132 12 drip characters from a symbol to a list;
+#X obj 131 117 unpack s s s s s s s;
+#X symbolatom 131 142 1 0 0 0 - - -, f 1;
+#X symbolatom 153 142 1 0 0 0 - - -, f 1;
+#X symbolatom 176 142 1 0 0 0 - - -, f 1;
+#X symbolatom 198 142 1 0 0 0 - - -, f 1;
+#X symbolatom 221 142 1 0 0 0 - - -, f 1;
+#X symbolatom 243 142 1 0 0 0 - - -, f 1;
+#X symbolatom 266 142 1 0 0 0 - - -, f 1;
+#X msg 245 69 symbol moonix_;
+#N canvas 380 146 494 344 META 0;
+#X text 12 25 LICENSE GPL v2;
+#X text 12 105 AUTHOR Antoine Rousseau;
+#X text 12 125 HELP_PATCH_AUTHORS Antoine Rousseau. "pd meta" information
+added by Jonathan Wilkes for Pd version 0.42.;
+#X text 12 5 KEYWORDS control conversion symbol_op;
+#X text 12 45 DESCRIPTION drip characters from a symbol to a list;
+#X text 12 65 INLET_0 symbol;
+#X text 12 85 OUTLET_0 list;
+#X restore 363 207 pd META;
+#X connect 2 0 4 0;
+#X connect 3 0 6 0;
+#X connect 4 0 3 0;
+#X connect 6 0 7 0;
+#X connect 6 1 8 0;
+#X connect 6 2 9 0;
+#X connect 6 3 10 0;
+#X connect 6 4 11 0;
+#X connect 6 5 12 0;
+#X connect 6 6 13 0;
+#X connect 14 0 3 0;
diff --git a/dripchar.c b/dripchar.c
index 184e204..bc5a104 100644
--- a/dripchar.c
+++ b/dripchar.c
@@ -1,82 +1,83 @@
-/*
-Copyright (C) 2002 Antoine Rousseau 
-
-This library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation; either
-version 2.1 of the License, or (at your option) any later version.
-
-This library 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
-Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with this library; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  
-
-*/
-
-/*#include <m_imp.h>*/
-#include "m_pd.h"
-
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
-
-typedef struct _dripchar
-{
-    t_object x_obj;
-}t_dripchar;
-
-t_class *dripchar_class;
-
-void dripchar_setup(void);
-
-static void dripchar_symbol(t_dripchar *x,t_symbol *sym)
-{
-	static t_binbuf *binbuf=0;
-	t_atom at;
-	char *c,s[2]={0};
-	int l;
-	
-	if(!binbuf) binbuf=binbuf_new();
-	/*post("dripchar_symbol");*/
-	if(!sym->s_name) return;
-
-	c=sym->s_name;
-	while(*c) {
-		s[0]=*c++;
-		SETSYMBOL(&at,gensym(s));
-		binbuf_add(binbuf,1,&at);
-	}
-
-	
-	outlet_list(x->x_obj.ob_outlet,0,
-		binbuf_getnatom(binbuf),binbuf_getvec(binbuf));
-	binbuf_clear(binbuf);
-}
-
-static void dripchar_float(t_dripchar *x,t_floatarg f)
-{
-	post("dripchar_float");
-	/*outlet_symbol(x->x_obj.ob_outlet,*/
-}
-
-static void *dripchar_new(void)
-{  
-	t_dripchar *x = (t_dripchar *)pd_new(dripchar_class);
-	outlet_new(&x->x_obj, 0);
-	return (void *)x;
-}
-
-void dripchar_setup(void)
-{
-	dripchar_class = class_new(gensym("dripchar"),(t_newmethod)dripchar_new, 
-		0, sizeof(t_dripchar), 0, 0);
-
-	class_addsymbol(dripchar_class, dripchar_symbol);
-	class_addfloat(dripchar_class, dripchar_float);
-}
-
+/*
+Copyright (C) 2002 Antoine Rousseau
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+*/
+
+/*#include <m_imp.h>*/
+#include "m_pd.h"
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+typedef struct _dripchar
+{
+    t_object x_obj;
+} t_dripchar;
+
+t_class *dripchar_class;
+
+void dripchar_setup(void);
+
+static void dripchar_symbol(t_dripchar *x,t_symbol *sym)
+{
+    static t_binbuf *binbuf=0;
+    t_atom at;
+    char *c,s[2]= {0};
+    int l;
+
+    if(!binbuf) binbuf=binbuf_new();
+    /*post("dripchar_symbol");*/
+    if(!sym->s_name) return;
+
+    c=sym->s_name;
+    while(*c)
+    {
+        s[0]=*c++;
+        SETSYMBOL(&at,gensym(s));
+        binbuf_add(binbuf,1,&at);
+    }
+
+
+    outlet_list(x->x_obj.ob_outlet,0,
+                binbuf_getnatom(binbuf),binbuf_getvec(binbuf));
+    binbuf_clear(binbuf);
+}
+
+static void dripchar_float(t_dripchar *x,t_floatarg f)
+{
+    post("dripchar_float");
+    /*outlet_symbol(x->x_obj.ob_outlet,*/
+}
+
+static void *dripchar_new(void)
+{
+    t_dripchar *x = (t_dripchar *)pd_new(dripchar_class);
+    outlet_new(&x->x_obj, 0);
+    return (void *)x;
+}
+
+void dripchar_setup(void)
+{
+    dripchar_class = class_new(gensym("dripchar"),(t_newmethod)dripchar_new,
+                               0, sizeof(t_dripchar), 0, 0);
+
+    class_addsymbol(dripchar_class, dripchar_symbol);
+    class_addfloat(dripchar_class, dripchar_float);
+}
+
diff --git a/f2char-help.pd b/f2char-help.pd
index f133288..7c0a0d8 100644
--- a/f2char-help.pd
+++ b/f2char-help.pd
@@ -1,18 +1,28 @@
-#N canvas 134 318 430 247 10;
-#X obj 0 0 cnv 8 100 60 empty empty char2f_f2char 10 20 1 18 -262144
--1109 0;
-#X text 7 221 (c) Moonix: Antoine Rousseau 2003;
-#X text 160 14 ascii utilities;
-#X obj 131 115 char2f;
-#X floatatom 131 136 5 0 0;
-#X msg 131 69 symbol A;
-#X obj 131 173 f2char;
-#X symbolatom 131 194 2 0 0;
-#X obj 131 49 loadbang;
-#X msg 216 70 symbol a;
-#X connect 3 0 4 0;
-#X connect 4 0 6 0;
-#X connect 5 0 3 0;
-#X connect 6 0 7 0;
-#X connect 8 0 5 0;
-#X connect 9 0 3 0;
+#N canvas 1 58 445 259 10;
+#X obj 0 0 cnv 8 100 60 empty empty char2f_f2char 10 20 1 18 -262144
+-1109 0;
+#X text 7 221 (c) Moonix: Antoine Rousseau 2003;
+#X text 160 14 ascii utilities;
+#X obj 131 115 char2f;
+#X floatatom 131 136 5 0 0 0 - - -, f 5;
+#X msg 131 69 symbol A;
+#X obj 131 173 f2char;
+#X symbolatom 131 194 2 0 0 0 - - -, f 2;
+#X obj 131 49 loadbang;
+#X msg 216 70 symbol a;
+#N canvas 380 146 494 344 META 0;
+#X text 12 25 LICENSE GPL v2;
+#X text 12 105 AUTHOR Antoine Rousseau;
+#X text 12 125 HELP_PATCH_AUTHORS Antoine Rousseau. "pd meta" information
+added by Jonathan Wilkes for Pd version 0.42.;
+#X text 12 5 KEYWORDS control conversion symbol_op;
+#X text 12 45 DESCRIPTION ascii utility;
+#X text 12 65 INLET_0 float;
+#X text 12 85 OUTLET_0 symbol;
+#X restore 373 217 pd META;
+#X connect 3 0 4 0;
+#X connect 4 0 6 0;
+#X connect 5 0 3 0;
+#X connect 6 0 7 0;
+#X connect 8 0 5 0;
+#X connect 9 0 3 0;
diff --git a/f2char.c b/f2char.c
index e14c5cf..7462f66 100644
--- a/f2char.c
+++ b/f2char.c
@@ -1,53 +1,53 @@
-/*
-Copyright (C) 2002 Antoine Rousseau 
-
-This library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation; either
-version 2.1 of the License, or (at your option) any later version.
-
-This library 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
-Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with this library; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  
-
-*/
-
-#include "m_pd.h"
-
-typedef struct _f2char
-{
-    t_object x_obj;
-}t_f2char;
-
-t_class *f2char_class;
-
-void f2char_setup(void);
-
-static void f2char_float(t_f2char *x,t_floatarg f)
-{
-	char s[2]={0};
-	
-	s[0]=(char)f;
-	outlet_symbol(x->x_obj.ob_outlet,gensym(s));
-}
-
-static void *f2char_new(void)
-{  
-	t_f2char *x = (t_f2char *)pd_new(f2char_class);
-	outlet_new(&x->x_obj,&s_symbol);
-	return (void *)x;
-}
-
-void f2char_setup(void)
-{
-	f2char_class = class_new(gensym("f2char"),(t_newmethod)f2char_new, 
-		0, sizeof(t_f2char), 0, 0);
-
-	class_addfloat(f2char_class, f2char_float);
-}
-
+/*
+Copyright (C) 2002 Antoine Rousseau
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+*/
+
+#include "m_pd.h"
+
+typedef struct _f2char
+{
+    t_object x_obj;
+} t_f2char;
+
+t_class *f2char_class;
+
+void f2char_setup(void);
+
+static void f2char_float(t_f2char *x,t_floatarg f)
+{
+    char s[2]= {0};
+
+    s[0]=(char)f;
+    outlet_symbol(x->x_obj.ob_outlet,gensym(s));
+}
+
+static void *f2char_new(void)
+{
+    t_f2char *x = (t_f2char *)pd_new(f2char_class);
+    outlet_new(&x->x_obj,&s_symbol);
+    return (void *)x;
+}
+
+void f2char_setup(void)
+{
+    f2char_class = class_new(gensym("f2char"),(t_newmethod)f2char_new,
+                             0, sizeof(t_f2char), 0, 0);
+
+    class_addfloat(f2char_class, f2char_float);
+}
+
diff --git a/f2s-help.pd b/f2s-help.pd
new file mode 100644
index 0000000..68362ab
--- /dev/null
+++ b/f2s-help.pd
@@ -0,0 +1,29 @@
+#N canvas 0 31 527 298 10;
+#X text 27 268 (c) Antoine Rousseau 2001;
+#X floatatom 196 85 5 0 300 0 - - -;
+#X obj 163 136 f2s;
+#X obj 196 106 dbtorms;
+#X symbolatom 163 158 4 0 0 0 - - -;
+#X floatatom 207 158 0 0 0 0 - - -;
+#X text 244 85 Touch this;
+#X text 57 196 The idea: many decades in an always 4 characters long
+symbol...;
+#X obj 44 31 f2s;
+#X text 80 32 A float-to-symbol converter \, with scientific-mode writing.
+;
+#N canvas 380 146 494 344 META 0;
+#X text 12 35 LICENSE GPL v2;
+#X text 12 125 AUTHOR Antoine Rousseau;
+#X text 12 145 HELP_PATCH_AUTHORS Antoine Rousseau. "pd meta" information
+added by Jonathan Wilkes for Pd version 0.42.;
+#X text 12 85 INLET_0 float;
+#X text 12 105 OUTLET_0 symbol;
+#X text 12 55 DESCRIPTION a float-to-symbol converter \, with scientific-mode
+writing;
+#X text 12 5 KEYWORDS control conversion symbol_op needs_work (object
+won't create);
+#X restore 461 260 pd META;
+#X connect 1 0 3 0;
+#X connect 2 0 4 0;
+#X connect 3 0 2 0;
+#X connect 3 0 5 0;
diff --git a/f2s.c b/f2s.c
new file mode 100644
index 0000000..cc82fd5
--- /dev/null
+++ b/f2s.c
@@ -0,0 +1,118 @@
+/*
+Copyright (C) 2002 Antoine Rousseau 
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  
+
+*/
+
+#include <m_pd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h> 
+
+#define IS_A_FLOAT(atom,index) ((atom+index)->a_type == A_FLOAT)
+#define IS_A_SYMBOL(atom,index) ((atom+index)->a_type == A_SYMBOL)
+
+static t_class *f2s_class;
+
+typedef struct _f2s
+{
+   t_object x_ob;
+	t_float x_f;
+	int x_type; /*0: p/n/µ/m/./k/M/G with n digits */
+	int x_n;
+} t_f2s;
+
+static void f2s_bang(t_f2s *x)
+{
+	char buf[256],delim;
+	float f=x->x_f,fnorm;
+	int ilogf,ilogf3,fh,fl=0,subdigits;
+	
+	if(!f) {
+		sprintf(buf,"0");
+		goto end;
+	}
+	ilogf=(int)floor(log10(fabs(f)));
+	ilogf3=(int)floor(log10(fabs(f))/3);
+	
+	subdigits=2-ilogf+ilogf3*3;
+	
+	fnorm=f*pow(10,-ilogf3*3);
+	fh=(int)(fnorm);
+	fl=(int)(fabs((fnorm-fh)*pow(10,subdigits))+0.00001);
+
+	switch(ilogf3){
+		case -4: delim='p'; break;
+		case -3: delim='n'; break;
+		case -2: delim='u'; break;
+		case -1: delim='m'; break;
+		case 0: delim=subdigits?'.':0; break;
+		case 1: delim='k'; break;
+		case 2: delim='M'; break;
+		case 3: delim='G'; break;
+		case 4: delim='T'; break;
+		default:delim='?';
+	}
+	
+	if(subdigits)
+		sprintf(buf,"%i%c%0*i",fh,delim,subdigits,fl);
+	else {
+		if(delim=='m')
+			sprintf(buf,"%s%03i",fh<0?"-.":".",abs(fh));
+		else sprintf(buf,"%i%c",fh,delim);
+	}
+	
+	end:
+	outlet_symbol(((t_object *)x)->ob_outlet,gensym(buf));
+}
+
+static void f2s_float(t_f2s *x,t_float val)
+{
+	x->x_f=val;
+	f2s_bang(x);
+}
+
+static void *f2s_new( t_symbol *s, int argc, t_atom *argv)
+{
+	t_atom *at;
+
+	t_f2s *x=(t_f2s*)pd_new(f2s_class);	
+
+	x->x_f=0;
+	x->x_type=0;
+	x->x_n=3;
+	
+	outlet_new(&x->x_ob, &s_symbol);
+	
+	if(argc&&IS_A_FLOAT(argv,0)) {
+		x->x_n=atom_getfloat(argv++);
+		argc--;
+	}
+	
+	return (void *)x;
+}
+
+void f2s_setup(void)
+{
+	f2s_class = class_new(gensym("f2s"),(t_newmethod)f2s_new, 
+		0, sizeof(t_f2s),0,A_GIMME ,0);
+
+	class_addfloat(f2s_class, (t_method)f2s_float);
+	class_addbang(f2s_class, (t_method)f2s_bang);
+	class_sethelpsymbol(f2s_class, gensym("moonlibs/f2s"));
+}
+
diff --git a/gamme-help.pd b/gamme-help.pd
index 8f87eb0..bdd67ec 100644
--- a/gamme-help.pd
+++ b/gamme-help.pd
@@ -1,171 +1,212 @@
-#N canvas 246 348 520 515 10;
-#X text 10 491 (c) Antoine Rousseau 2001;
-#X text 85 3 gamme: a musical scale selector.;
-#X obj 113 187 gamme 90 40 1 0 0 0 1 0 0 1 0 0 0 0;
-#X floatatom 51 244 6 0 0 0 - - -;
-#X floatatom 134 71 4 0 0 0 - - -;
-#X floatatom 33 78 4 0 0 0 - - -;
-#X floatatom 154 244 4 0 0 0 - - -;
-#X msg 280 256 set \$1 \$2;
-#X obj 280 288 gamme 90 40 1 0 0 0 1 0 0 1 0 0 0 0;
-#X msg 401 177 getall;
-#X floatatom 322 336 4 0 0 0 - - -;
-#X floatatom 282 72 6 0 0 0 - - -;
-#X msg 282 138 round \$1 \$2;
-#X obj 282 116 pack f f;
-#X floatatom 363 71 4 0 200 0 - - -;
-#X obj 281 227 print changed;
-#X obj 134 119 pack f f;
-#X floatatom 190 71 4 0 0 0 - - -;
-#X obj 156 99 t b f;
-#X msg 134 141 get \$1 \$2;
-#X text 126 53 octave;
-#X text 188 53 note;
-#X text 271 56 semitone;
-#X text 344 55 rounding strength;
-#X obj 303 93 t b f;
-#X text 19 59 semitone;
-#X text 152 33 ARPEGE;
-#X text 28 39 FILTER;
-#X text 324 36 ROUNDING;
-#X text 51 263 Result;
-#X text 139 261 Number of;
-#X text 127 273 selected notes;
-#X text 377 238 in the key set.;
-#X text 383 225 Last change;
-#X text 371 158 get all the key set.;
-#N canvas 483 118 375 520 audio 0;
-#X obj 4 356 gamme 90 40 1 0 1 0 1 0 0 1 0 1 0 0;
-#X obj 28 464 *~;
-#X obj 4 419 mtof;
-#X obj 4 442 osc~;
-#N canvas 394 93 600 400 env 0;
-#X obj 19 122 inlet;
-#X obj 105 121 inlet;
-#X msg 19 143 bang;
-#X obj 89 280 line~;
-#X obj 114 329 outlet~;
-#X obj 114 307 *~;
-#X obj 130 280 +~ 1;
-#X obj 130 258 *~ 0.6;
-#X obj 130 237 osc~ 12;
-#X msg 89 228 0 \$1;
-#X obj 89 206 200;
-#X obj 48 206 0.2;
-#X obj 64 121 inlet;
-#X text 18 101 trig;
-#X text 62 101 vol;
-#X text 103 102 sustain;
-#X text 133 219 lfo...;
-#X msg 48 228 \$1 2;
-#X obj 89 183 delay 2;
-#X connect 0 0 2 0;
-#X connect 1 0 10 1;
-#X connect 2 0 11 0;
-#X connect 2 0 18 0;
-#X connect 3 0 5 0;
-#X connect 5 0 4 0;
-#X connect 6 0 5 1;
-#X connect 7 0 6 0;
-#X connect 8 0 7 0;
-#X connect 9 0 3 0;
-#X connect 10 0 9 0;
-#X connect 11 0 17 0;
-#X connect 12 0 11 1;
-#X connect 17 0 3 0;
-#X connect 18 0 10 0;
-#X restore 44 441 pd env;
-#X floatatom 51 236 5 0 0 0 - - -;
-#X obj 17 499 dac~;
-#X obj 62 421 pow 4;
-#X obj 4 189 metro 180;
-#X obj 4 211 i;
-#X obj 4 162 tgl 20 0 empty empty play 0 -8 1 10 -262144 -1 -1 1 1
-;
-#X obj 29 211 + 1;
-#X obj 4 286 spigot;
-#X obj 49 286 == 0;
-#X obj 54 211 mod 16;
-#X obj 91 287 spigot;
-#X obj 136 287 == 1;
-#X msg 91 309 get 4 \$1;
-#X obj 233 251 unpack f;
-#X obj 188 279 spigot;
-#X msg 188 345 round \$1 \$2;
-#X obj 188 323 pack f f;
-#X obj 233 279 == 2;
-#X obj 4 306 + 60;
-#X obj 188 301 + 60.05;
-#X obj 191 375 hsl 50 10 0 500 0 1 empty empty Sustain -2 -6 1 10 -262144
--1 -1 1700 1;
-#X obj 52 165 hsl 50 10 5 500 0 1 empty empty Metro(ms) -2 -6 1 10
--262144 -1 -1 1200 1;
-#X obj 318 165 vsl 10 40 0 100 0 1 empty empty Round 0 -8 1 10 -262144
--1 -1 600 1;
-#X obj 191 486 hsl 60 15 0 1 0 1 empty empty Volume -2 -6 1 10 -258699
--1 -1 4300 1;
-#X obj 149 88 cnv 15 90 47 empty empty filter/arpeg/round 2 8 1 10
--233017 -1 0;
-#X obj 149 162 hdl 30 0 1 3 empty empty empty 20 8 0 8 -262144 -1 -1
-0;
-#X obj 13 328 inlet;
-#X connect 0 0 4 0;
-#X connect 0 0 2 0;
-#X connect 1 0 6 0;
-#X connect 1 0 6 1;
-#X connect 2 0 3 0;
-#X connect 3 0 1 0;
-#X connect 4 0 1 1;
-#X connect 5 0 15 0;
-#X connect 5 0 12 0;
-#X connect 5 0 19 0;
-#X connect 7 0 4 1;
-#X connect 8 0 9 0;
-#X connect 9 0 5 0;
-#X connect 9 0 11 0;
-#X connect 10 0 8 0;
-#X connect 11 0 14 0;
-#X connect 12 0 23 0;
-#X connect 13 0 12 1;
-#X connect 14 0 9 1;
-#X connect 15 0 17 0;
-#X connect 16 0 15 1;
-#X connect 17 0 0 0;
-#X connect 18 0 16 0;
-#X connect 18 0 22 0;
-#X connect 18 0 13 0;
-#X connect 19 0 24 0;
-#X connect 20 0 0 0;
-#X connect 21 0 20 0;
-#X connect 22 0 19 1;
-#X connect 23 0 0 0;
-#X connect 24 0 21 0;
-#X connect 25 0 4 2;
-#X connect 26 0 8 1;
-#X connect 27 0 21 1;
-#X connect 28 0 7 0;
-#X connect 30 0 18 0;
-#X connect 31 0 0 0;
-#X coords 0 0 1 1 210 110 1;
-#X restore 33 325 pd audio demo;
-#X connect 2 0 3 0;
-#X connect 2 1 6 0;
-#X connect 2 2 7 0;
-#X connect 2 2 15 0;
-#X connect 4 0 16 0;
-#X connect 5 0 2 0;
-#X connect 7 0 8 0;
-#X connect 7 0 35 0;
-#X connect 8 1 10 0;
-#X connect 9 0 2 0;
-#X connect 11 0 13 0;
-#X connect 12 0 2 0;
-#X connect 13 0 12 0;
-#X connect 14 0 24 0;
-#X connect 16 0 19 0;
-#X connect 17 0 18 0;
-#X connect 18 0 16 0;
-#X connect 18 1 16 1;
-#X connect 19 0 2 0;
-#X connect 24 0 13 0;
-#X connect 24 1 13 1;
+#N canvas 65 329 649 515 10;
+#X text 10 491 (c) Antoine Rousseau 2001;
+#X text 85 3 gamme: a musical scale selector.;
+#X obj 113 187 gamme 90 40 1 0 0 0 1 0 0 1 0 0 0 1;
+#X floatatom 51 244 6 0 0 0 - - -, f 6;
+#X floatatom 134 71 4 0 0 0 - - -, f 4;
+#X floatatom 33 78 4 0 0 0 - - -, f 4;
+#X floatatom 140 241 4 0 0 0 - - -, f 4;
+#X msg 276 286 set \$1 \$2;
+#X obj 276 318 gamme 90 40 1 0 0 0 1 0 0 1 0 0 0 1;
+#X msg 406 141 getall;
+#X floatatom 303 367 4 0 0 0 - - -, f 4;
+#X floatatom 282 72 6 0 0 0 - - -, f 6;
+#X msg 282 138 round \$1 \$2;
+#X obj 282 116 pack f f;
+#X floatatom 363 71 4 0 200 0 - - -, f 4;
+#X obj 354 285 print changed;
+#X obj 134 119 pack f f;
+#X floatatom 190 71 4 0 0 0 - - -, f 4;
+#X obj 156 99 t b f;
+#X msg 134 141 get \$1 \$2;
+#X text 126 53 octave;
+#X text 188 53 note;
+#X text 271 56 semitone;
+#X text 344 55 rounding strength;
+#X obj 303 93 t b f;
+#X text 19 59 semitone;
+#X text 152 33 ARPEGE;
+#X text 28 39 FILTER;
+#X text 324 36 ROUNDING;
+#X text 51 263 Result;
+#X text 125 258 Number of;
+#X text 113 270 selected notes;
+#X text 357 269 in the key set.;
+#X text 363 256 Last change;
+#X text 376 122 get all the key set.;
+#N canvas 138 153 463 732 audio 0;
+#X obj 59 109 gamme 90 40 1 0 0 0 1 0 0 1 0 0 0 1;
+#X obj 85 639 *~;
+#X obj 86 569 mtof;
+#N canvas 384 118 600 400 env 0;
+#X obj 19 122 inlet;
+#X obj 105 121 inlet;
+#X msg 19 143 bang;
+#X obj 89 280 line~;
+#X obj 114 329 outlet~;
+#X obj 114 307 *~;
+#X obj 130 280 +~ 1;
+#X msg 89 228 0 \$1;
+#X obj 89 206 200;
+#X obj 48 206 0.2;
+#X obj 64 121 inlet;
+#X text 18 101 trig;
+#X text 62 101 vol;
+#X text 103 102 sustain;
+#X text 133 219 lfo...;
+#X msg 48 228 \$1 2;
+#X obj 89 183 delay 2;
+#X obj 130 237 osc~ 10;
+#X obj 130 258 *~ 0.5;
+#X connect 0 0 2 0;
+#X connect 1 0 8 1;
+#X connect 2 0 9 0;
+#X connect 2 0 16 0;
+#X connect 3 0 5 0;
+#X connect 5 0 4 0;
+#X connect 6 0 5 1;
+#X connect 7 0 3 0;
+#X connect 8 0 7 0;
+#X connect 9 0 15 0;
+#X connect 10 0 9 1;
+#X connect 15 0 3 0;
+#X connect 16 0 8 0;
+#X connect 17 0 18 0;
+#X connect 18 0 6 0;
+#X restore 152 611 pd env;
+#X floatatom 63 272 5 0 0 0 - - -, f 5;
+#X obj 85 673 dac~;
+#X obj 63 224 metro 180;
+#X obj 63 246 i;
+#X obj 68 81 tgl 20 0 \$0-play empty play 0 -8 1 10 -262144 -1 -1 1
+1;
+#X obj 88 246 + 1;
+#X obj 105 396 == 0;
+#X obj 113 246 mod 16;
+#X obj 136 397 spigot;
+#X obj 181 397 == 1;
+#X msg 136 419 get 4 \$1;
+#X obj 233 389 spigot;
+#X msg 233 454 round \$1 \$2;
+#X obj 233 433 pack f f;
+#X obj 278 389 == 2;
+#X obj 49 416 + 60;
+#X obj 233 411 + 60.05;
+#X obj 160 114 hsl 50 10 1 500 0 1 \$0-sustain empty Sustain -2 -6
+1 10 -262144 -1 -1 4200 1;
+#X obj 108 79 hsl 50 10 5 500 0 1 \$0-metroMs empty Metro(ms) -2 -6
+1 10 -262144 -1 -1 2900 1;
+#X obj 226 113 vsl 10 40 0.1 100 1 1 \$0-round empty Round 0 -8 1 10
+-262144 -1 -1 2100 1;
+#X obj 158 141 hsl 60 15 0 1 0 1 \$0-volume empty Volume -2 -6 1 10
+-258699 -1 -1 4800 1;
+#X obj 169 52 cnv 15 90 15 empty empty filter/arpeg/round 2 8 1 10
+-233017 -1 0;
+#X obj 282 56 inlet;
+#X floatatom 105 91 5 0 0 0 - #0-step -, f 5;
+#X obj 49 492 s \$0-2gamme;
+#X obj 59 173 s \$0-gamme;
+#X obj 13 28 r \$0-2gamme;
+#X obj 86 530 r \$0-gamme;
+#X obj 63 202 r \$0-play;
+#X obj 123 201 r \$0-metroMs;
+#X obj 168 550 r \$0-volume;
+#X obj 168 571 pow 3;
+#X obj 185 590 r \$0-sustain;
+#X obj 169 68 hradio 30 1 0 3 \$0-mode empty empty 0 -8 0 10 -262144
+-1 -1 0;
+#X obj 105 311 r \$0-mode;
+#X obj 284 411 r \$0-round;
+#X obj 111 270 s \$0-step;
+#X obj 49 374 r \$0-step;
+#X obj 136 374 r \$0-step;
+#X obj 233 367 r \$0-step;
+#X obj 282 76 s \$0-2gamme;
+#X obj 86 592 ssaw~;
+#X obj 86 614 lop~ 800;
+#X obj 49 396 spigot 1;
+#X connect 0 0 29 0;
+#X connect 1 0 5 0;
+#X connect 1 0 5 1;
+#X connect 2 0 45 0;
+#X connect 3 0 1 1;
+#X connect 4 0 40 0;
+#X connect 6 0 7 0;
+#X connect 7 0 4 0;
+#X connect 7 0 9 0;
+#X connect 9 0 11 0;
+#X connect 10 0 47 1;
+#X connect 11 0 7 1;
+#X connect 12 0 14 0;
+#X connect 13 0 12 1;
+#X connect 14 0 28 0;
+#X connect 15 0 20 0;
+#X connect 16 0 28 0;
+#X connect 17 0 16 0;
+#X connect 18 0 15 1;
+#X connect 19 0 28 0;
+#X connect 20 0 17 0;
+#X connect 26 0 44 0;
+#X connect 30 0 0 0;
+#X connect 31 0 3 0;
+#X connect 31 0 2 0;
+#X connect 32 0 6 0;
+#X connect 33 0 6 1;
+#X connect 34 0 35 0;
+#X connect 35 0 3 1;
+#X connect 36 0 3 2;
+#X connect 38 0 13 0;
+#X connect 38 0 18 0;
+#X connect 38 0 10 0;
+#X connect 39 0 17 1;
+#X connect 41 0 47 0;
+#X connect 42 0 12 0;
+#X connect 43 0 15 0;
+#X connect 45 0 46 0;
+#X connect 46 0 1 0;
+#X connect 47 0 19 0;
+#X coords 0 0 1 1 210 110 1 50 50;
+#X restore 33 325 pd audio demo;
+#X obj 295 213 print binary_out;
+#X text 298 197 12bits=12notes;
+#X obj 480 309 gamme 90 40 1 0 0 0 1 0 0 1 0 0 0 1;
+#X obj 480 262 f;
+#X obj 480 221 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 480 283 setb \$1;
+#X floatatom 563 371 5 0 0 0 - - -, f 5;
+#X msg 530 236 0;
+#X text 538 283 binary input;
+#X msg 600 234 2741;
+#X msg 562 235 145;
+#X text 304 184 binary output:;
+#X connect 2 0 3 0;
+#X connect 2 1 6 0;
+#X connect 2 2 7 0;
+#X connect 2 2 15 0;
+#X connect 2 3 36 0;
+#X connect 2 3 39 1;
+#X connect 4 0 16 0;
+#X connect 5 0 2 0;
+#X connect 7 0 8 0;
+#X connect 7 0 35 0;
+#X connect 8 1 10 0;
+#X connect 9 0 2 0;
+#X connect 11 0 13 0;
+#X connect 12 0 2 0;
+#X connect 13 0 12 0;
+#X connect 14 0 24 0;
+#X connect 16 0 19 0;
+#X connect 17 0 18 0;
+#X connect 18 0 16 0;
+#X connect 18 1 16 1;
+#X connect 19 0 2 0;
+#X connect 24 0 13 0;
+#X connect 24 1 13 1;
+#X connect 38 3 42 0;
+#X connect 39 0 41 0;
+#X connect 40 0 39 0;
+#X connect 41 0 38 0;
+#X connect 43 0 41 0;
+#X connect 45 0 41 0;
+#X connect 46 0 41 0;
diff --git a/gamme.c b/gamme.c
index 8545a78..786432a 100644
--- a/gamme.c
+++ b/gamme.c
@@ -1,558 +1,613 @@
-/*
-Copyright (C) 2002 Antoine Rousseau 
-
-This library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation; either
-version 2.1 of the License, or (at your option) any later version.
-
-This library 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
-Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with this library; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  
-
-*/
-#include <math.h>
-#include <stdlib.h>
-#include <m_pd.h>
-#include "g_canvas.h"
-
-#ifdef _MSC_VER
-#pragma warning( disable : 4244 )
-#pragma warning( disable : 4305 )
-#endif
-
-/* ------------------------ gamme ----------------------------- */
-#define BACKGROUND "-fill grey"
-#define BACKGROUNDCOLOR "grey"
-
-#ifndef  PD_VERSION_MINOR
-#define PD_VERSION_MINOR 32
-#endif
-
-#define IS_A_POINTER(atom,index) ((atom+index)->a_type == A_POINTER)
-#define IS_A_FLOAT(atom,index) ((atom+index)->a_type == A_FLOAT)
-#define IS_A_SYMBOL(atom,index) ((atom+index)->a_type == A_SYMBOL)
-
-
-#define DEFAULTSIZE 15
-#define DEFAULTWIDTH 90
-#define DEFAULTHEIGHT 40
-
-#define DEFAULTCOLOR "black"
-#define BLACKCOLOR "black"
-#define WHITECOLOR "white"
-#define SELBLACKCOLOR "gold"
-#define SELWHITECOLOR "yellow"
-
-
-static t_class *gamme_class;
-
-static char *NoteNames[]=
-	{ "C","C#","D","D#","E","F","F#","G","G#","A","A#","B" };
-static char NoteColPos[]=
-	{ 1,-1,2,-2,3,4,-4,5,-5,6,-6,7 };
-static char Whites[]={0,2,4,5,7,9,11};
-static char Blacks[]={1,3,6,8,10};
-static char BlacksWhites[]={1,3,6,8,10,0,2,4,5,7,9,11};
-static char WhitesBlacks[]={0,2,4,5,7,9,11,1,3,6,8,10};
-
-#define ISWHITE(x) (NoteColPos[x]>0)
-#define ISBLACK(x) (!ISWHITE(x))
-
-#define te_xpos te_xpix
-#define te_ypos te_ypix
-
-typedef struct _gamme
-{
-     t_object x_obj;
-	  t_outlet *x_out_n; /*gives the number of selected notes when change occurs*/
-	  t_outlet *x_out_note; /*gives the number and new value of the changed notes when change occurs*/
-     t_glist * x_glist;
-     int x_width;
-     int x_height;
- 	  char x_n;
- 	  char x_notes[12];
- 	  char x_on_notes[12];
-} t_gamme;
-
-/* widget helper functions */
-
-
-#define INTERSPACE 0.02
-#define NOTEWIDTH ((1-INTERSPACE*6.0)/7.0)
-#define BLACK1st ((NOTEWIDTH+INTERSPACE)/2.0)
-#define BLACKH 0.6
-static void note_get_rel_rect(int x, float *xp1, float *yp1, float *xp2, float *yp2)
-{
-	int cp=NoteColPos[x];
-	
-	*xp1=(abs(cp)-1)*(NOTEWIDTH+INTERSPACE) + (cp<0)*BLACK1st;
-	*xp2=*xp1+NOTEWIDTH;
-	
-	*yp1=0;
-	*yp2=cp<0?BLACKH:1;
-}
-
-static int get_touched_note(float x, float y)
-{
-	int i,j;
-	float xp1,xp2,yp1,yp2;
-	
-	for(j=0;j<12;j++) {
-		i=BlacksWhites[j];
-		note_get_rel_rect(i,&xp1,&yp1,&xp2,&yp2);
-		if((x>=xp1)&&(x<=xp2)&&(y>=yp1)&&(y<=yp2))
-			return i;
-	}
-	/*post("gamme::get_touched_note note not found: x=%f y=%f",x,y);*/
-	return -1;
-}
-
-static void draw_inlets(t_gamme *x, t_glist *glist, int firsttime, int nin, int nout)
-{
-     int n = nout;
-     int nplus, i;
-    int xpos=text_xpix(&x->x_obj, glist);
-    int ypos=text_ypix(&x->x_obj, glist);
-
-     nplus = (n == 1 ? 1 : n-1);
-     for (i = 0; i < n; i++)
-     {
-	  int onset = xpos + (x->x_width - IOWIDTH) * i / nplus;
-	  if (firsttime)
-	       sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xo%d\n",
-			glist_getcanvas(glist),
-			onset, ypos + x->x_height - 1,
-			onset + IOWIDTH, ypos + x->x_height,
-			x, i);
-	  else
-	       sys_vgui(".x%x.c coords %xo%d %d %d %d %d\n",
-			glist_getcanvas(glist), x, i,
-			onset, ypos + x->x_height - 1,
-			onset + IOWIDTH, ypos + x->x_height);
-     }
-     n = nin; 
-     nplus = (n == 1 ? 1 : n-1);
-     for (i = 0; i < n; i++)
-     {
-	  int onset = xpos + (x->x_width - IOWIDTH) * i / nplus;
-	  if (firsttime)
-	       sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xi%d\n",
-			glist_getcanvas(glist),
-			onset, ypos,
-			onset + IOWIDTH, ypos + 1,
-			x, i);
-	  else
-	       sys_vgui(".x%x.c coords %xi%d %d %d %d %d\n",
-			glist_getcanvas(glist), x, i,
-			onset, ypos,
-			onset + IOWIDTH, ypos + 1);
-	  
-     }
-}
-
-void gamme_drawme(t_gamme *x, t_glist *glist, int firsttime)
-{
-     int i,j;
-	  float x1,y1,x2,y2;
-	  int xi1,yi1,xi2,yi2;
-	  char *color;
-    int xpos=text_xpix(&x->x_obj, glist);
-    int ypos=text_ypix(&x->x_obj, glist);
-	  
-	  if (firsttime) {
-	  sys_vgui(".x%x.c create rectangle \
-%d %d %d %d -tags %xS "BACKGROUND"\n",
-		   glist_getcanvas(glist),
-		   xpos, ypos,
-		   xpos + x->x_width, ypos + x->x_height,
-		   x);
-	  
-     }     
-     else {
-	  sys_vgui(".x%x.c coords %xS \
-%d %d %d %d\n",
-		   glist_getcanvas(glist), x,
-		   xpos, ypos,
-		   xpos + x->x_width, ypos + x->x_height);
-     }
-	
-	for(j=0;j<12;j++){
-		i=WhitesBlacks[j];
-		note_get_rel_rect(i,&x1,&y1,&x2,&y2);
-		xi1=xpos + x->x_width*x1;
-		xi2=xpos + x->x_width*x2;
-		yi1=ypos + x->x_height*y1;
-		yi2=ypos + x->x_height*y2;
-		
-	  if (firsttime) {
-		color=x->x_notes[i]?	(ISWHITE(i)?SELWHITECOLOR:SELBLACKCOLOR):
-							(ISWHITE(i)?WHITECOLOR:BLACKCOLOR);
-	  sys_vgui(".x%x.c create rectangle \
-%d %d %d %d -tags %x%s -fill %s\n",
-			glist_getcanvas(glist),xi1,yi1,xi2,yi2,
-			x,NoteNames[i],color);
-    }     
-     else {
-	  sys_vgui(".x%x.c coords %x%s \
-%d %d %d %d\n",
-			glist_getcanvas(glist),x,NoteNames[i],xi1,yi1,xi2,yi2);
-     }
-	}	
-	
-	draw_inlets(x, glist, firsttime, 1,3);
-
-}
-
-void gamme_erase(t_gamme* x,t_glist* glist)
-{
-     int n;
-    t_canvas *canvas=glist_getcanvas(glist);
-
-	 sys_vgui(".x%x.c delete %xS\n",canvas, x);
-
-	for(n=0;n<12;n++)
-		sys_vgui(".x%x.c delete %x%s\n",canvas,x,NoteNames[n]);
-
-     n = 1;
-     while (n--) {
-	  sys_vgui(".x%x.c delete %xi%d\n",canvas,x,n);
-     }
-     n = 3;
-     while (n--) {
-	  sys_vgui(".x%x.c delete %xo%d\n",canvas,x,n);
-     }
-}
-	
-
-
-/* ------------------------ gamme widgetbehaviour----------------------------- */
-
-
-static void gamme_getrect(t_gobj *z, t_glist *glist,
-    int *xp1, int *yp1, int *xp2, int *yp2)
-{
-    t_gamme *x = (t_gamme *)z;
-    int width, height;
-    t_gamme* s = (t_gamme*)z;
-
-
-    width = s->x_width;
-    height = s->x_height;
-    *xp1 = text_xpix(&x->x_obj, glist);
-    *yp1 = text_ypix(&x->x_obj, glist);
-    *xp2 = *xp1 + width;
-    *yp2 = *yp1 + height;
-}
-
-static void gamme_displace(t_gobj *z, t_glist *glist,
-    int dx, int dy)
-{
-    t_gamme *x = (t_gamme *)z;
-    x->x_obj.te_xpos += dx;
-    x->x_obj.te_ypos += dy;
-    gamme_drawme(x, glist, 0);
-    canvas_fixlinesfor(glist,(t_text*) x);
-}
-
-static void gamme_select(t_gobj *z, t_glist *glist, int state)
-{
-     t_gamme *x = (t_gamme *)z;
-     sys_vgui(".x%x.c itemconfigure %xS -fill %s\n", glist, 
-	     x, (state? "blue" : BACKGROUNDCOLOR));
-}
-
-
-static void gamme_activate(t_gobj *z, t_glist *glist, int state)
-{
-/*    t_text *x = (t_text *)z;
-    t_rtext *y = glist_findrtext(glist, x);
-    if (z->g_pd != gatom_class) rtext_activate(y, state);*/
-}
-
-static void gamme_delete(t_gobj *z, t_glist *glist)
-{
-    t_text *x = (t_text *)z;
-    canvas_deletelinesfor(glist, x);
-}
-
-       
-static void gamme_vis(t_gobj *z, t_glist *glist, int vis)
-{
-    t_gamme* s = (t_gamme*)z;
-    if (vis)
-	 gamme_drawme(s, glist, 1);
-    else
-	 gamme_erase(s,glist);
-}
-
-/* can we use the normal text save function ?? */
-
-static void gamme_save(t_gobj *z, t_binbuf *b)
-{
-    t_gamme *x = (t_gamme *)z;
-	 char *c=x->x_notes;
-	 
-    binbuf_addv(b, "ssiisiiiiiiiiiiiiii", gensym("#X"),gensym("obj"),
-		(t_int)x->x_obj.te_xpos, (t_int)x->x_obj.te_ypos,  
-        atom_getsymbol(binbuf_getvec(x->x_obj.te_binbuf)),
-		x->x_width,x->x_height,
-		c[0],c[1],c[2],c[3],c[4],c[5],c[6],c[7],c[8],c[9],c[10],c[11]);
-    binbuf_addv(b, ";");
-}
-
-void gamme_getn(t_gamme *x)
-{
-	outlet_float(x->x_out_n,x->x_n);
-}
-
-void gamme_out_changed(t_gamme *x,int note)
-{
-	t_atom ats[2];
-	SETFLOAT(&ats[0],note);
-	SETFLOAT(&ats[1],x->x_notes[note]);
-
-	outlet_list(x->x_out_note,0,2,ats);
-}
-
-inline float my_mod(float x,int n)
-{
-	float y=fmod(x,n);
-	return y<0?y+n:y;
-}
-
-#define my_div(x,y) (floor(x/y))
-#define tonotei(x) (my_mod(rint(x),12U))
-
-void gamme_set(t_gamme *x,t_floatarg note,t_floatarg on)
-{
-	unsigned int i,notei=tonotei(note),changed=0;
-	char *color;
-    t_canvas *canvas=glist_getcanvas(x->x_glist);
-	
-	
-	if(x->x_notes[notei]!=on) changed=1;
-	if(on<0) x->x_notes[notei]=!(x->x_notes[notei]);
-	else x->x_notes[notei]=on;
-	if(changed) gamme_out_changed(x,notei);
-
-	color=x->x_notes[notei]?(ISWHITE(notei)?SELWHITECOLOR:SELBLACKCOLOR):
-									(ISWHITE(notei)?WHITECOLOR:BLACKCOLOR);
-	
-	if(glist_isvisible(x->x_glist))
-		sys_vgui(".x%x.c itemconfigure %x%s -fill %s\n", canvas, 
-	     x, NoteNames[notei],color);
-	
-	x->x_n=0;
-	for(i=0;i<12;i++) if(x->x_notes[i]) x->x_on_notes[(int)(x->x_n++)]=i;
-	gamme_getn(x);
-}
-
-#define getnote(n) \
-	(my_div(n,(int)x->x_n)*12+x->x_on_notes[(int)my_mod(n,x->x_n)])
-void gamme_get(t_gamme *x,t_floatarg ref_octave,t_floatarg note)
-{
-	int no0,no1,ni0,ni1,n0,n1,n;
-	float xn,xx,nn;
-
-	if(!x->x_n) return;
-	no0=floor(note);
-	no1=ceil(note);
-	xx=note-no0;
-
-	nn=getnote((float)no0)*(1-xx)+getnote((float)(no0+1))*xx+ref_octave*12;
-	n=getnote((float)no0)+ref_octave*12;
-	outlet_float(x->x_obj.ob_outlet,nn);
-}
-
-static void gamme_click(t_gamme *x, t_floatarg xpos, t_floatarg ypos,
-			  t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
-{
-	int note;    
-    int x0=text_xpix(&x->x_obj, x->x_glist);
-    int y0=text_ypix(&x->x_obj, x->x_glist);
-	
-	note=get_touched_note(
-		(xpos-x0)/x->x_width,
-		(ypos-y0)/x->x_height);
-			
-	if(note>=0) gamme_set(x,note,!x->x_notes[note]);
-}
-
-static int gamme_newclick(t_gobj *z, struct _glist *glist,
-			    int xpix, int ypix, int shift, int alt, int dbl, int doit)
-{
-    t_gamme* x = (t_gamme *)z;
-
-    if(doit)
-    {
-		gamme_click( x, (t_floatarg)xpix, (t_floatarg)ypix, (t_floatarg)shift,
-			0, (t_floatarg)alt);
-    }
-    return (1);
-}
-
-void gamme_float(t_gamme *x,t_floatarg f)
-{
- 	unsigned int notei=tonotei(f);
-
-   /*post("notei=%d",notei);*/
-	if(x->x_notes[notei])
-		outlet_float(x->x_obj.ob_outlet,f);
-}
-
-void gamme_round(t_gamme *x,t_floatarg f,t_floatarg round)
-{
- 	unsigned int notei=tonotei(f);
-	int imin=floor(f),imax=ceil(f);
-	float norm;
-	
-	if(!x->x_n) return;
-
-	while(!x->x_notes[(int)my_mod((imin),12U)]) imin--;
-	while(!x->x_notes[(int)my_mod((imax),12U)]) imax++;
-	
-	/*post("min: %d  max: %d",imin,imax);*/
-
-	if((imin!=imax)&&round) {
-		round*=round;
-		norm=(f-imin)/(imax-imin)*2-1;
-		norm=norm/sqrt(1+round*norm*norm)*sqrt(1+round)/2+.5;
-		f=norm*(imax-imin)+imin;
-	}
-	outlet_float(x->x_obj.ob_outlet,f);
-}
-
-void gamme_setall(t_gamme *x,t_symbol *s, int argc, t_atom *argv)
-{
-	int i=0,err=0;
-	
-	if(argc==12)
-	{
-		for(i=0;i<12;i++) err+=!IS_A_FLOAT(argv,i);
-		if(!err) for(i=0;i<12;i++) gamme_set(x,i,atom_getfloat(&argv[i]));
-	}
-}
-
-void gamme_getall(t_gamme *x)
-{
-	int i=0;
-
-	for(i=0;i<12;i++) gamme_out_changed(x,i);
-	gamme_getn(x);
-}
-
-extern int sys_noloadbang;
-static void gamme_loadbang(t_gamme *x)
-{
-	int i;
-	
-	if(sys_noloadbang) return;
-	for(i=0;i<12;i++) gamme_out_changed(x,i);
-	gamme_getn(x);
-}
-
-void gamme_size(t_gamme* x,t_floatarg w,t_floatarg h) {
-     x->x_width = w;
-     x->x_height = h;
-     gamme_drawme(x, x->x_glist, 0);
-}
-
-t_widgetbehavior   gamme_widgetbehavior;
-
-static void gamme_setwidget(void)
-{
-    gamme_widgetbehavior.w_getrectfn =		gamme_getrect;
-    gamme_widgetbehavior.w_displacefn =	gamme_displace;
-    gamme_widgetbehavior.w_selectfn =		gamme_select;
-    gamme_widgetbehavior.w_activatefn =	gamme_activate;
-    gamme_widgetbehavior.w_deletefn =		gamme_delete;
-    gamme_widgetbehavior.w_visfn =			gamme_vis;
-    gamme_widgetbehavior.w_clickfn =		gamme_newclick;
-    //gamme_widgetbehavior.w_propertiesfn =	NULL; 
-    //gamme_widgetbehavior.w_savefn =			gamme_save;
-}
-
-
-static void *gamme_new(t_symbol *s, int argc, t_atom *argv)
-{
-	int i=0,err=0;
-	
-	t_gamme *x = (t_gamme *)pd_new(gamme_class);
-
-	x->x_glist = (t_glist*) canvas_getcurrent();
-	x->x_width = DEFAULTWIDTH;
-	x->x_height = DEFAULTHEIGHT;
-	outlet_new(&x->x_obj, &s_float);
-	x->x_out_n=outlet_new(&x->x_obj, &s_float);
-	x->x_out_note=outlet_new(&x->x_obj, &s_float);
-	
-	x->x_n=0;
-	for(i=0;i<12;i++) x->x_notes[i]=0;
-	for(i=0;i<12;i++) x->x_on_notes[i]=0;
-
-	if((argc>1)&&IS_A_FLOAT(argv,0)&&IS_A_FLOAT(argv,1))
-	{
-		if(atom_getfloat(&argv[0])) x->x_width = atom_getfloat(&argv[0]);
-		if(atom_getfloat(&argv[1])) x->x_height = atom_getfloat(&argv[1]);
-		
-		if(argc==14)
-		{
-			for(i=0;i<12;i++) err+=(!IS_A_FLOAT(argv,i+2));
-			if(!err) {
-				for(i=0;i<12;i++) if(x->x_notes[i]=atom_getfloat(&argv[i+2]))
-					x->x_on_notes[(int)(x->x_n++)]=i;
-				/*gamme_set(x,i,atom_getfloat(&argv[i+2]));gamme_getn(x);*/
-			}
-			else post("gamme_new : error in creation arguments");
-		}
-		/*if(argc==14) gamme_setall(x,s,argc-2,&argv[2]);*/
-	}
-
-	return (x);
-}
-
-void gamme_setup(void)
-{
-	 gamme_class = class_new(gensym("gamme"), (t_newmethod)gamme_new, 0,
-				sizeof(t_gamme),0, A_GIMME,0);
-
-    class_addfloat(gamme_class,gamme_float);
-
-    class_addmethod(gamme_class, (t_method)gamme_click, gensym("click"),
-    	A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
-
-    class_addmethod(gamme_class, (t_method)gamme_size, gensym("size"),
-    	A_FLOAT, A_FLOAT, 0);
-
-    class_addmethod(gamme_class, (t_method)gamme_set, gensym("set"),
-    	A_FLOAT, A_FLOAT, 0);
-
-    class_addmethod(gamme_class, (t_method)gamme_get, gensym("get"),
-    	A_FLOAT, A_FLOAT, 0);
-
-    class_addmethod(gamme_class, (t_method)gamme_round, gensym("round"),
-    	A_FLOAT, A_FLOAT, 0);
-
-    class_addmethod(gamme_class, (t_method)gamme_setall, gensym("setall"),
-    	A_GIMME, 0);
-
-    class_addmethod(gamme_class, (t_method)gamme_getall, gensym("getall"), 0);
-
-    class_addmethod(gamme_class, (t_method)gamme_getn, gensym("getn"), 0);
-
-    /*class_addmethod(gamme_class, (t_method)gamme_loadbang, gensym("loadbang"), 0);*/
-
-
-    gamme_setwidget();
-    class_setwidget(gamme_class,&gamme_widgetbehavior);
-    class_setsavefn(gamme_class, gamme_save);
-
-}
-
-
+/*
+Copyright (C) 2002 Antoine Rousseau
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+*/
+#include <math.h>
+#include <stdlib.h>
+#include <m_pd.h>
+#include "g_canvas.h"
+
+#ifdef _MSC_VER
+#pragma warning( disable : 4244 )
+#pragma warning( disable : 4305 )
+#endif
+
+/* ------------------------ gamme ----------------------------- */
+#define BACKGROUND "-fill grey"
+#define BACKGROUNDCOLOR "grey"
+
+#ifndef  PD_VERSION_MINOR
+#define PD_VERSION_MINOR 32
+#endif
+
+#define IS_A_POINTER(atom,index) ((atom+index)->a_type == A_POINTER)
+#define IS_A_FLOAT(atom,index) ((atom+index)->a_type == A_FLOAT)
+#define IS_A_SYMBOL(atom,index) ((atom+index)->a_type == A_SYMBOL)
+
+
+#define DEFAULTSIZE 15
+#define DEFAULTWIDTH 90
+#define DEFAULTHEIGHT 40
+
+#define DEFAULTCOLOR "black"
+#define BLACKCOLOR "black"
+#define WHITECOLOR "white"
+#define SELBLACKCOLOR "gold"
+#define SELWHITECOLOR "yellow"
+
+
+static t_class *gamme_class;
+
+static char *NoteNames[]=
+{ "C","C#","D","D#","E","F","F#","G","G#","A","A#","B" };
+static char NoteColPos[]=
+{ 1,-1,2,-2,3,4,-4,5,-5,6,-6,7 };
+static char Whites[]= {0,2,4,5,7,9,11};
+static char Blacks[]= {1,3,6,8,10};
+static char BlacksWhites[]= {1,3,6,8,10,0,2,4,5,7,9,11};
+static char WhitesBlacks[]= {0,2,4,5,7,9,11,1,3,6,8,10};
+
+#define ISWHITE(x) (NoteColPos[x]>0)
+#define ISBLACK(x) (!ISWHITE(x))
+
+#define te_xpos te_xpix
+#define te_ypos te_ypix
+
+typedef struct _gamme
+{
+    t_object x_obj;
+    t_outlet *x_out_n; /*gives the number of selected notes when change occurs*/
+    t_outlet *x_out_note; /*gives the number and new value of the changed notes when change occurs*/
+	t_outlet *x_out_b; /*binary output: 12bits-integer=1bit/note */
+    t_glist *x_glist;
+    int x_width;
+    int x_height;
+    unsigned char x_n;
+    unsigned char x_notes[12];
+    unsigned char x_on_notes[12];
+} t_gamme;
+
+/* widget helper functions */
+
+
+#define INTERSPACE 0.02
+#define NOTEWIDTH ((1-INTERSPACE*6.0)/7.0)
+#define BLACK1st ((NOTEWIDTH+INTERSPACE)/2.0)
+#define BLACKH 0.6
+static void note_get_rel_rect(int x, float *xp1, float *yp1, float *xp2, float *yp2)
+{
+    int cp=NoteColPos[x];
+
+    *xp1=(abs(cp)-1)*(NOTEWIDTH+INTERSPACE) + (cp<0)*BLACK1st;
+    *xp2=*xp1+NOTEWIDTH;
+
+    *yp1=0;
+    *yp2=cp<0?BLACKH:1;
+}
+
+static int get_touched_note(float x, float y)
+{
+    int i,j;
+    float xp1,xp2,yp1,yp2;
+
+    for(j=0; j<12; j++)
+    {
+        i=BlacksWhites[j];
+        note_get_rel_rect(i,&xp1,&yp1,&xp2,&yp2);
+        if((x>=xp1)&&(x<=xp2)&&(y>=yp1)&&(y<=yp2))
+            return i;
+    }
+    /*post("gamme::get_touched_note note not found: x=%f y=%f",x,y);*/
+    return -1;
+}
+
+static void draw_inlets(t_gamme *x, t_glist *glist, int firsttime, int nin, int nout)
+{
+    int n = nout;
+    int nplus, i;
+    int xpos=text_xpix(&x->x_obj, glist);
+    int ypos=text_ypix(&x->x_obj, glist);
+
+    nplus = (n == 1 ? 1 : n-1);
+    for (i = 0; i < n; i++)
+    {
+        int onset = xpos + (x->x_width - IOWIDTH) * i / nplus;
+        if (firsttime)
+            sys_vgui(".x%lx.c create rectangle %d %d %d %d -tags %xo%d\n",
+                     glist_getcanvas(glist),
+                     onset, ypos + x->x_height - 1,
+                     onset + IOWIDTH, ypos + x->x_height,
+                     x, i);
+        else
+            sys_vgui(".x%lx.c coords %xo%d %d %d %d %d\n",
+                     glist_getcanvas(glist), x, i,
+                     onset, ypos + x->x_height - 1,
+                     onset + IOWIDTH, ypos + x->x_height);
+    }
+    n = nin;
+    nplus = (n == 1 ? 1 : n-1);
+    for (i = 0; i < n; i++)
+    {
+        int onset = xpos + (x->x_width - IOWIDTH) * i / nplus;
+        if (firsttime)
+            sys_vgui(".x%lx.c create rectangle %d %d %d %d -tags %xi%d\n",
+                     glist_getcanvas(glist),
+                     onset, ypos,
+                     onset + IOWIDTH, ypos + 1,
+                     x, i);
+        else
+            sys_vgui(".x%lx.c coords %xi%d %d %d %d %d\n",
+                     glist_getcanvas(glist), x, i,
+                     onset, ypos,
+                     onset + IOWIDTH, ypos + 1);
+
+    }
+}
+
+void gamme_drawme(t_gamme *x, t_glist *glist, int firsttime)
+{
+    int i,j;
+    float x1,y1,x2,y2;
+    int xi1,yi1,xi2,yi2;
+    char *color;
+    int xpos=text_xpix(&x->x_obj, glist);
+    int ypos=text_ypix(&x->x_obj, glist);
+
+    if (firsttime)
+    {
+        sys_vgui(".x%lx.c create rectangle \
+%d %d %d %d -tags %xS "BACKGROUND"\n",
+                 glist_getcanvas(glist),
+                 xpos, ypos,
+                 xpos + x->x_width, ypos + x->x_height,
+                 x);
+
+    }
+    else
+    {
+        sys_vgui(".x%lx.c coords %xS \
+%d %d %d %d\n",
+                 glist_getcanvas(glist), x,
+                 xpos, ypos,
+                 xpos + x->x_width, ypos + x->x_height);
+    }
+
+    for(j=0; j<12; j++)
+    {
+        i=WhitesBlacks[j];
+        note_get_rel_rect(i,&x1,&y1,&x2,&y2);
+        xi1=xpos + x->x_width*x1;
+        xi2=xpos + x->x_width*x2;
+        yi1=ypos + x->x_height*y1;
+        yi2=ypos + x->x_height*y2;
+
+        if (firsttime)
+        {
+            color=x->x_notes[i]? (ISWHITE(i)?SELWHITECOLOR:SELBLACKCOLOR):
+                      (ISWHITE(i)?WHITECOLOR:BLACKCOLOR);
+            sys_vgui(".x%lx.c create rectangle \
+%d %d %d %d -tags %x%s -fill %s\n",
+                     glist_getcanvas(glist),xi1,yi1,xi2,yi2,
+                     x,NoteNames[i],color);
+        }
+        else
+    {
+            sys_vgui(".x%lx.c coords %x%s \
+%d %d %d %d\n",
+                     glist_getcanvas(glist),x,NoteNames[i],xi1,yi1,xi2,yi2);
+        }
+    }
+
+    draw_inlets(x, glist, firsttime, 1,4);
+
+}
+
+void gamme_erase(t_gamme *x,t_glist *glist)
+{
+    int n;
+    t_canvas *canvas=glist_getcanvas(glist);
+
+    sys_vgui(".x%lx.c delete %xS\n",canvas, x);
+
+    for(n=0; n<12; n++)
+        sys_vgui(".x%lx.c delete %x%s\n",canvas,x,NoteNames[n]);
+
+    n = 1;
+    while (n--)
+    {
+        sys_vgui(".x%lx.c delete %xi%d\n",canvas,x,n);
+    }
+    n = 4;
+    while (n--)
+    {
+        sys_vgui(".x%lx.c delete %xo%d\n",canvas,x,n);
+    }
+}
+
+
+
+/* ------------------------ gamme widgetbehaviour----------------------------- */
+
+
+static void gamme_getrect(t_gobj *z, t_glist *glist,
+                          int *xp1, int *yp1, int *xp2, int *yp2)
+{
+    t_gamme *x = (t_gamme *)z;
+    int width, height;
+    t_gamme *s = (t_gamme *)z;
+
+
+    width = s->x_width;
+    height = s->x_height;
+    *xp1 = text_xpix(&x->x_obj, glist);
+    *yp1 = text_ypix(&x->x_obj, glist);
+    *xp2 = *xp1 + width;
+    *yp2 = *yp1 + height;
+}
+
+static void gamme_displace(t_gobj *z, t_glist *glist,
+                           int dx, int dy)
+{
+    t_gamme *x = (t_gamme *)z;
+    x->x_obj.te_xpos += dx;
+    x->x_obj.te_ypos += dy;
+    gamme_drawme(x, glist, 0);
+    canvas_fixlinesfor(glist,(t_text *) x);
+}
+
+static void gamme_select(t_gobj *z, t_glist *glist, int state)
+{
+    t_gamme *x = (t_gamme *)z;
+    sys_vgui(".x%lx.c itemconfigure %xS -fill %s\n", glist,
+             x, (state? "blue" : BACKGROUNDCOLOR));
+}
+
+
+static void gamme_activate(t_gobj *z, t_glist *glist, int state)
+{
+    /*    t_text *x = (t_text *)z;
+        t_rtext *y = glist_findrtext(glist, x);
+        if (z->g_pd != gatom_class) rtext_activate(y, state);*/
+}
+
+static void gamme_delete(t_gobj *z, t_glist *glist)
+{
+    t_text *x = (t_text *)z;
+    canvas_deletelinesfor(glist, x);
+}
+
+
+static void gamme_vis(t_gobj *z, t_glist *glist, int vis)
+{
+    t_gamme *s = (t_gamme *)z;
+    if (vis)
+        gamme_drawme(s, glist, 1);
+    else
+        gamme_erase(s,glist);
+}
+
+/* can we use the normal text save function ?? */
+
+static void gamme_save(t_gobj *z, t_binbuf *b)
+{
+    t_gamme *x = (t_gamme *)z;
+    char *c=x->x_notes;
+
+    binbuf_addv(b, "ssiisiiiiiiiiiiiiii", gensym("#X"),gensym("obj"),
+                (t_int)x->x_obj.te_xpos, (t_int)x->x_obj.te_ypos,
+                atom_getsymbol(binbuf_getvec(x->x_obj.te_binbuf)),
+                x->x_width,x->x_height,
+                c[0],c[1],c[2],c[3],c[4],c[5],c[6],c[7],c[8],c[9],c[10],c[11]);
+    binbuf_addv(b, ";");
+}
+
+void gamme_getn(t_gamme *x)
+{
+    outlet_float(x->x_out_n,x->x_n);
+}
+
+void gamme_out_changed(t_gamme *x,int note)
+{
+    t_atom ats[2];
+    SETFLOAT(&ats[0],note);
+    SETFLOAT(&ats[1],x->x_notes[note]);
+
+    outlet_list(x->x_out_note,0,2,ats);
+}
+
+void gamme_out_b(t_gamme *x)
+{
+	int i,out_b=0;
+	
+	for(i=0;i<12;i++) out_b+=(x->x_notes[i]!=0)<<i;
+	
+	outlet_float(x->x_out_b,out_b);
+}
+
+inline float my_mod(float x,int n)
+{
+    float y=fmod(x,n);
+    return y<0?y+n:y;
+}
+
+#define my_div(x,y) (floor(x/y))
+#define tonotei(x) (my_mod(rint(x),12U))
+
+void gamme_draw_note(t_gamme *x,t_floatarg note)
+{
+    t_canvas *canvas=glist_getcanvas(x->x_glist);
+    char *color;
+    int notei=note;
+	
+    if(glist_isvisible(x->x_glist)) {
+        color=x->x_notes[(int)notei]?(ISWHITE(notei)?SELWHITECOLOR:SELBLACKCOLOR):
+                    (ISWHITE(notei)?WHITECOLOR:BLACKCOLOR);
+        sys_vgui(".x%x.c itemconfigure %x%s -fill %s\n", canvas, 
+        x, NoteNames[notei],color);
+    }
+}
+
+void gamme_set(t_gamme *x,t_floatarg note,t_floatarg on)
+{
+    unsigned int i,notei=tonotei(note),changed=0;
+    char *color;
+    t_canvas *canvas=glist_getcanvas(x->x_glist);
+
+
+    if(x->x_notes[notei]!=on) changed=1;
+    if(on<0) x->x_notes[notei]=!(x->x_notes[notei]);
+    else x->x_notes[notei]=on;
+
+    if(changed) {
+        gamme_out_changed(x,notei);
+        gamme_out_b(x);
+        gamme_draw_note(x,notei);
+    }
+
+    x->x_n=0;
+    for(i=0; i<12; i++) if(x->x_notes[i]) x->x_on_notes[(int)(x->x_n++)]=i;
+    gamme_getn(x);
+}
+
+void gamme_set_b(t_gamme *x,t_floatarg in_byte)
+{
+    unsigned int i,changed=0,on,in_b=in_byte;
+
+    x->x_n=0;	
+    for(i=0;i<12;i++){
+        on=((in_b&(1<<i))!=0);
+        if(x->x_notes[i]!=on) {
+            x->x_notes[i]=on;
+            gamme_out_changed(x,i);
+            gamme_draw_note(x,i);
+        }
+        if(on) x->x_on_notes[(int)(x->x_n++)]=i;
+    }	
+    gamme_out_b(x);
+    gamme_getn(x);
+}
+
+#define getnote(n) \
+	(my_div(n,(int)x->x_n)*12+x->x_on_notes[(int)my_mod(n,x->x_n)])
+void gamme_get(t_gamme *x,t_floatarg ref_octave,t_floatarg note)
+{
+    int no0,no1,ni0,ni1,n0,n1,n;
+    float xn,xx,nn;
+
+    if(!x->x_n) return;
+    no0=floor(note);
+    no1=ceil(note);
+    xx=note-no0;
+
+    nn=getnote((float)no0)*(1-xx)+getnote((float)(no0+1))*xx+ref_octave*12;
+    n=getnote((float)no0)+ref_octave*12;
+    outlet_float(x->x_obj.ob_outlet,nn);
+}
+
+static void gamme_click(t_gamme *x, t_floatarg xpos, t_floatarg ypos,
+                        t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
+{
+    int note;
+    int x0=text_xpix(&x->x_obj, x->x_glist);
+    int y0=text_ypix(&x->x_obj, x->x_glist);
+
+    note=get_touched_note(
+             (xpos-x0)/x->x_width,
+             (ypos-y0)/x->x_height);
+
+    if(note>=0) gamme_set(x,note,!x->x_notes[note]);
+}
+
+static int gamme_newclick(t_gobj *z, struct _glist *glist,
+                          int xpix, int ypix, int shift, int alt, int dbl, int doit)
+{
+    t_gamme *x = (t_gamme *)z;
+
+    if(doit)
+    {
+        gamme_click( x, (t_floatarg)xpix, (t_floatarg)ypix, (t_floatarg)shift,
+                     0, (t_floatarg)alt);
+    }
+    return (1);
+}
+
+void gamme_float(t_gamme *x,t_floatarg f)
+{
+    unsigned int notei=tonotei(f);
+
+    /*post("notei=%d",notei);*/
+    if(x->x_notes[notei])
+        outlet_float(x->x_obj.ob_outlet,f);
+}
+
+void gamme_round(t_gamme *x,t_floatarg f,t_floatarg round)
+{
+    unsigned int notei=tonotei(f);
+    int imin=floor(f),imax=ceil(f);
+    float norm;
+
+    if(!x->x_n) return;
+
+    while(!x->x_notes[(int)my_mod((imin),12U)]) imin--;
+    while(!x->x_notes[(int)my_mod((imax),12U)]) imax++;
+
+    /*post("min: %d  max: %d",imin,imax);*/
+
+    if((imin!=imax)&&round)
+    {
+        round*=round;
+        norm=(f-imin)/(imax-imin)*2-1;
+        norm=norm/sqrt(1+round*norm*norm)*sqrt(1+round)/2+.5;
+        f=norm*(imax-imin)+imin;
+    }
+    outlet_float(x->x_obj.ob_outlet,f);
+}
+
+void gamme_setall(t_gamme *x,t_symbol *s, int argc, t_atom *argv)
+{
+    int i=0,err=0;
+
+    if(argc==12)
+    {
+        for(i=0; i<12; i++) err+=!IS_A_FLOAT(argv,i);
+        if(!err) for(i=0; i<12; i++) gamme_set(x,i,atom_getfloat(&argv[i]));
+    }
+}
+
+void gamme_getall(t_gamme *x)
+{
+    int i=0;
+
+    for(i=0; i<12; i++) gamme_out_changed(x,i);
+    gamme_getn(x);
+}
+
+extern int sys_noloadbang;
+static void gamme_loadbang(t_gamme *x)
+{
+    int i;
+
+    if(sys_noloadbang) return;
+    for(i=0; i<12; i++) gamme_out_changed(x,i);
+    gamme_getn(x);
+}
+
+void gamme_size(t_gamme *x,t_floatarg w,t_floatarg h)
+{
+    x->x_width = w;
+    x->x_height = h;
+    gamme_drawme(x, x->x_glist, 0);
+}
+
+t_widgetbehavior   gamme_widgetbehavior;
+
+static void gamme_setwidget(void)
+{
+    gamme_widgetbehavior.w_getrectfn =		gamme_getrect;
+    gamme_widgetbehavior.w_displacefn =	gamme_displace;
+    gamme_widgetbehavior.w_selectfn =		gamme_select;
+    gamme_widgetbehavior.w_activatefn =	gamme_activate;
+    gamme_widgetbehavior.w_deletefn =		gamme_delete;
+    gamme_widgetbehavior.w_visfn =			gamme_vis;
+    gamme_widgetbehavior.w_clickfn =		gamme_newclick;
+    //gamme_widgetbehavior.w_propertiesfn =	NULL;
+    //gamme_widgetbehavior.w_savefn =			gamme_save;
+}
+
+
+static void *gamme_new(t_symbol *s, int argc, t_atom *argv)
+{
+    int i=0,err=0;
+
+    t_gamme *x = (t_gamme *)pd_new(gamme_class);
+
+    x->x_glist = (t_glist *) canvas_getcurrent();
+    x->x_width = DEFAULTWIDTH;
+    x->x_height = DEFAULTHEIGHT;
+    outlet_new(&x->x_obj, &s_float);
+    x->x_out_n=outlet_new(&x->x_obj, &s_float);
+    x->x_out_note=outlet_new(&x->x_obj, &s_float);
+	x->x_out_b=outlet_new(&x->x_obj, &s_float);
+
+    x->x_n=0;
+    for(i=0; i<12; i++) x->x_notes[i]=0;
+    for(i=0; i<12; i++) x->x_on_notes[i]=0;
+
+    if((argc>1)&&IS_A_FLOAT(argv,0)&&IS_A_FLOAT(argv,1))
+    {
+        if(atom_getfloat(&argv[0])) x->x_width = atom_getfloat(&argv[0]);
+        if(atom_getfloat(&argv[1])) x->x_height = atom_getfloat(&argv[1]);
+
+        if(argc==14)
+        {
+            for(i=0; i<12; i++) err+=(!IS_A_FLOAT(argv,i+2));
+            if(!err)
+            {
+                for(i=0; i<12; i++) if(x->x_notes[i]=atom_getfloat(&argv[i+2]))
+                        x->x_on_notes[(int)(x->x_n++)]=i;
+                /*gamme_set(x,i,atom_getfloat(&argv[i+2]));gamme_getn(x);*/
+            }
+            else post("gamme_new : error in creation arguments");
+        }
+        /*if(argc==14) gamme_setall(x,s,argc-2,&argv[2]);*/
+    }
+
+    return (x);
+}
+
+void gamme_setup(void)
+{
+    gamme_class = class_new(gensym("gamme"), (t_newmethod)gamme_new, 0,
+                            sizeof(t_gamme),0, A_GIMME,0);
+
+    class_addfloat(gamme_class,gamme_float);
+
+    class_addmethod(gamme_class, (t_method)gamme_click, gensym("click"),
+                    A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
+
+    class_addmethod(gamme_class, (t_method)gamme_size, gensym("size"),
+                    A_FLOAT, A_FLOAT, 0);
+
+    class_addmethod(gamme_class, (t_method)gamme_set, gensym("set"),
+                    A_FLOAT, A_FLOAT, 0);
+
+    class_addmethod(gamme_class, (t_method)gamme_set_b, gensym("setb"),
+                    A_FLOAT, 0);
+
+    class_addmethod(gamme_class, (t_method)gamme_get, gensym("get"),
+                    A_FLOAT, A_FLOAT, 0);
+
+    class_addmethod(gamme_class, (t_method)gamme_round, gensym("round"),
+                    A_FLOAT, A_FLOAT, 0);
+
+    class_addmethod(gamme_class, (t_method)gamme_setall, gensym("setall"),
+                    A_GIMME, 0);
+
+    class_addmethod(gamme_class, (t_method)gamme_getall, gensym("getall"), 0);
+
+    class_addmethod(gamme_class, (t_method)gamme_getn, gensym("getn"), 0);
+
+    /*class_addmethod(gamme_class, (t_method)gamme_loadbang, gensym("loadbang"), 0);*/
+
+
+    gamme_setwidget();
+    class_setwidget(gamme_class,&gamme_widgetbehavior);
+    class_setsavefn(gamme_class, gamme_save);
+
+}
+
+
diff --git a/image-help.pd b/image-help.pd
index ec5b649..c06ec41 100644
--- a/image-help.pd
+++ b/image-help.pd
@@ -1,108 +1,126 @@
-#N canvas 152 192 585 548 10;
-#X obj 0 0 cnv 8 100 60 empty empty image 20 20 1 18 -262144 -1109
-0;
-#X text 14 510 (c) moonix: Antoine Rousseau 2004;
-#X text 118 15 image viewer;
-#X text 79 33 usage: image image_symbol [type];
-#X text 97 48 if type=0 (or absent) \, image_symbol is a file.;
-#X text 444 63 see "load" and "set";
-#X text 98 63 if type=1 \, image_symbol means a pre-loaded image \;
-;
-#X text 248 510 \, but it's a hack of Gunter Geiger's image...;
-#X obj 112 134 cnv 15 80 40 empty empty empty 20 12 0 14 -1 -66577
-0;
-#X obj 122 148 image examples/play.gif 0;
-#X obj 348 216 cnv 15 20 20 empty empty empty 20 12 0 14 -1 -66577
-0;
-#X obj 372 197 t a;
-#X msg 424 105 open examples/play.gif;
-#X msg 425 125 open examples/playy.gif;
-#X msg 424 144 open examples/rec.gif;
-#X msg 424 162 open examples/pause.gif;
-#X msg 424 180 open examples/sinw.gif;
-#X msg 425 198 open examples/squarew.gif;
-#X msg 425 215 open examples/saww.gif;
-#X obj 360 227 image examples/saww.gif 0;
-#X obj 136 148 image examples/rec.gif 0;
-#X obj 152 148 image examples/pause.gif 0;
-#X obj 185 144 image examples/sinw.gif 0;
-#X obj 185 156 image examples/squarew.gif 0;
-#X obj 185 168 image examples/saww.gif 0;
-#N canvas 183 192 77 40 (subpatch) 0;
-#X obj 87 205 t a;
-#X msg 127 127 open examples/sinw.gif;
-#X msg 146 150 open examples/squarew.gif;
-#X msg 165 171 open examples/saww.gif;
-#X obj -1 0 tgl 40 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1;
-#X obj 0 1 cnv 15 40 40 empty empty empty 20 12 0 14 -1 -66577 0;
-#X obj 26 20 image examples/sinw.gif 0;
-#X obj 127 84 i;
-#X obj 153 85 + 1;
-#X obj 179 85 mod 3;
-#X obj 127 105 sel 0 1 2;
-#X obj 127 63 b;
-#X connect 1 0 0 0;
-#X connect 2 0 0 0;
-#X connect 3 0 0 0;
-#X connect 4 0 11 0;
-#X connect 7 0 8 0;
-#X connect 7 0 10 0;
-#X connect 8 0 9 0;
-#X connect 9 0 7 1;
-#X connect 10 0 1 0;
-#X connect 10 1 2 0;
-#X connect 10 2 3 0;
-#X connect 11 0 7 0;
-#X coords 0 0 1 1 40 40 1;
-#X restore 246 133 pd;
-#X text 241 118 click !;
-#X obj 65 348 t f f;
-#X obj 65 410 pack s s;
-#X msg 65 430 load \$1 \$2;
-#X msg 295 397 set \$1;
-#X obj 298 304 hsl 128 15 0 63 0 0 empty empty empty -2 -6 0 8 -262144
--1 -1 0 1;
-#X obj 295 326 i;
-#X obj 202 446 image d0 1;
-#X obj 295 349 change;
-#X text 6 253 For animations \, it's beter to preload images:;
-#X obj 402 377 loadbang;
-#X msg 402 397 open examples/rec.gif;
-#X text 95 274 1: load img_sym file;
-#X text 291 287 2: set img_sym;
-#X text 270 463 rem: when a img_symbol is loaded \, it;
-#X text 305 475 can be used in any image object.;
-#X text 17 94 ONLY GIF FILES ACCEPTED !! (because of Tk...);
-#X msg 62 276 64;
-#X obj 63 299 until;
-#X obj 64 325 float;
-#X obj 101 325 + 1;
-#X obj 65 370 makefilename d%d;
-#X obj 295 376 makefilename d%d;
-#X obj 95 390 makefilename examples/d%d.gif;
-#X connect 11 0 19 0;
-#X connect 12 0 11 0;
-#X connect 13 0 11 0;
-#X connect 14 0 11 0;
-#X connect 15 0 11 0;
-#X connect 16 0 11 0;
-#X connect 17 0 11 0;
-#X connect 18 0 11 0;
-#X connect 27 0 47 0;
-#X connect 27 1 49 0;
-#X connect 28 0 29 0;
-#X connect 29 0 33 0;
-#X connect 30 0 33 0;
-#X connect 31 0 32 0;
-#X connect 32 0 34 0;
-#X connect 34 0 48 0;
-#X connect 36 0 37 0;
-#X connect 37 0 33 0;
-#X connect 43 0 44 0;
-#X connect 44 0 45 0;
-#X connect 45 0 27 0;
-#X connect 45 0 46 0;
-#X connect 46 0 45 1;
-#X connect 47 0 28 0;
-#X connect 48 0 30 0;
-#X connect 49 0 28 1;
+#N canvas 373 92 631 561 10;
+#X obj 0 0 cnv 8 100 60 empty empty image 20 20 1 18 -262144 -1109
+0;
+#X text 14 510 (c) moonix: Antoine Rousseau 2004;
+#X text 118 15 image viewer;
+#X text 79 33 usage: image image_symbol [type];
+#X text 97 48 if type=0 (or absent) \, image_symbol is a file.;
+#X text 444 63 see "load" and "set";
+#X text 98 63 if type=1 \, image_symbol means a pre-loaded image \;
+;
+#X text 248 510 \, but it's a hack of Gunter Geiger's image...;
+#X obj 112 134 cnv 15 80 40 empty empty empty 20 12 0 14 -1 -66577
+0;
+#X obj 122 148 image img/play.gif 0;
+#X obj 348 216 cnv 15 20 20 empty empty empty 20 12 0 14 -1 -66577
+0;
+#X obj 372 197 t a;
+#X msg 424 105 open img/play.gif;
+#X msg 425 125 open img/playy.gif;
+#X msg 424 144 open img/rec.gif;
+#X msg 424 162 open img/pause.gif;
+#X msg 424 180 open img/sinw.gif;
+#X msg 425 198 open img/squarew.gif;
+#X msg 425 215 open img/saww.gif;
+#X obj 360 227 image img/saww.gif 0;
+#X obj 136 148 image img/rec.gif 0;
+#X obj 152 148 image img/pause.gif 0;
+#X obj 185 144 image img/sinw.gif 0;
+#X obj 185 156 image img/squarew.gif 0;
+#X obj 185 168 image img/saww.gif 0;
+#N canvas 461 287 393 295 (subpatch) 0;
+#X obj 87 204 t a;
+#X msg 127 126 open img/sinw.gif;
+#X msg 146 149 open img/squarew.gif;
+#X msg 165 170 open img/saww.gif;
+#X obj 0 0 tgl 40 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1;
+#X obj 0 0 cnv 15 40 40 empty empty empty 20 12 0 14 -1 -66577 0;
+#X obj 21 19 image img/sinw.gif 0;
+#X obj 127 83 i;
+#X obj 153 84 + 1;
+#X obj 179 84 mod 3;
+#X obj 127 104 sel 0 1 2;
+#X obj 127 62 b;
+#X connect 0 0 6 0;
+#X connect 1 0 0 0;
+#X connect 2 0 0 0;
+#X connect 3 0 0 0;
+#X connect 4 0 11 0;
+#X connect 7 0 8 0;
+#X connect 7 0 10 0;
+#X connect 8 0 9 0;
+#X connect 9 0 7 1;
+#X connect 10 0 1 0;
+#X connect 10 1 2 0;
+#X connect 10 2 3 0;
+#X connect 11 0 7 0;
+#X coords 0 0 1 1 40 40 1 0 0;
+#X restore 266 147 pd;
+#X text 241 118 click !;
+#X obj 298 304 hsl 128 15 0 63 0 0 empty empty empty -2 -6 0 8 -262144
+-1 -1 202 1;
+#X obj 295 326 i;
+#X obj 202 446 image d1 1;
+#X obj 295 349 change;
+#X obj 402 377 loadbang;
+#X msg 402 397 open img/rec.gif;
+#X text 95 274 1: load img_sym file;
+#X text 291 287 2: set img_sym;
+#X text 270 463 rem: when a img_symbol is loaded \, it;
+#X text 305 475 can be used in any image object.;
+#X text 17 94 ONLY GIF FILES ACCEPTED !! (because of Tk...);
+#X msg 95 313 64;
+#X obj 95 359 until;
+#X obj 132 381 + 1;
+#N canvas 518 217 494 344 META 0;
+#X text 12 25 LICENSE GPL v2;
+#X text 12 85 AUTHOR Antoine Rousseau;
+#X text 12 105 HELP_PATCH_AUTHORS Antoine Rousseau. "pd meta" information
+added by Jonathan Wilkes for Pd version 0.42.;
+#X text 12 65 INLET_0 load set open;
+#X text 12 5 KEYWORDS control GUI;
+#X text 12 45 DESCRIPTION image viewer;
+#X restore 574 531 pd META;
+#X msg 295 397 set d\$1;
+#X obj 95 381 f;
+#X msg 95 404 load d\$1 img/d\$1.gif;
+#X obj 95 335 t f b;
+#X msg 134 359 0;
+#X obj 95 293 loadbang;
+#X text 6 253 For animations \, it's faster to preload images:;
+#X obj 479 333 + 1;
+#X obj 451 333 f;
+#X obj 507 333 mod 64;
+#X obj 451 289 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 1
+1;
+#X obj 451 310 metro 15;
+#X connect 11 0 19 0;
+#X connect 12 0 11 0;
+#X connect 13 0 11 0;
+#X connect 14 0 11 0;
+#X connect 15 0 11 0;
+#X connect 16 0 11 0;
+#X connect 17 0 11 0;
+#X connect 18 0 11 0;
+#X connect 27 0 28 0;
+#X connect 28 0 30 0;
+#X connect 30 0 42 0;
+#X connect 31 0 32 0;
+#X connect 32 0 29 0;
+#X connect 38 0 45 0;
+#X connect 39 0 43 0;
+#X connect 40 0 43 1;
+#X connect 42 0 29 0;
+#X connect 43 0 40 0;
+#X connect 43 0 44 0;
+#X connect 44 0 29 0;
+#X connect 45 0 39 0;
+#X connect 45 1 46 0;
+#X connect 46 0 43 1;
+#X connect 47 0 38 0;
+#X connect 49 0 51 0;
+#X connect 50 0 49 0;
+#X connect 50 0 27 0;
+#X connect 51 0 50 1;
+#X connect 52 0 53 0;
+#X connect 53 0 50 0;
diff --git a/image.c b/image.c
index c019c21..e535ebb 100644
--- a/image.c
+++ b/image.c
@@ -1,306 +1,328 @@
-#include <m_pd.h>
-#include "g_canvas.h"
-#include <unistd.h>
-#include <string.h>
-#include <stdio.h>
-
-#ifdef _MSC_VER
-#pragma warning( disable : 4244 )
-#pragma warning( disable : 4305 )
-#endif
-
-/* ------------------------ image ----------------------------- */
-
-static t_class *image_class;
-
-typedef struct _image
-{
-     t_object x_obj;
-     t_glist * x_glist;
-     int x_width;
-     int x_height;
-    t_symbol*  x_image;
-	 int x_type; //0=file 1=tk_image
-     t_int  x_localimage; //localimage "img%x" done 
-} t_image;
-
-/* widget helper functions */
-
-const char* image_get_filename(t_image *x,char *file)
-{
-	static char fname[MAXPDSTRING];
-	char *bufptr;
-	int fd;
-	
-	fd=open_via_path(canvas_getdir(glist_getcanvas(x->x_glist))->s_name, 
-	    file, "",fname, &bufptr, MAXPDSTRING, 1);
-	if(fd>0){
-	  	fname[strlen(fname)]='/';
-	  	//post("image file: %s",fname);
-	  	close(fd);
-	  	return fname;
-	}
-	else return 0;
-}
-
-void image_drawme(t_image *x, t_glist *glist, int firsttime)
-{
-     if (firsttime) {
-	  if(x->x_type) {
-	  	sys_vgui(".x%x.c create image %d %d -tags %xS\n", 
-			glist_getcanvas(glist),
-			text_xpix(&x->x_obj, glist), text_ypix(&x->x_obj, glist),x);
-	  	sys_vgui(".x%x.c itemconfigure %xS -image %s\n", 
-			glist_getcanvas(glist),x,x->x_image->s_name);
-	  }
-	  else {
-		const char *fname=image_get_filename(x,x->x_image->s_name);
-		if(!x->x_localimage) {
-			sys_vgui("image create photo img%x\n",x);
-			x->x_localimage=1;
-		}
-	  	if(fname) sys_vgui("img%x configure -file %s\n",x,fname);	  		
-		sys_vgui(".x%x.c create image %d %d -image img%x -tags %xS\n", 
-			glist_getcanvas(glist),
-			text_xpix(&x->x_obj, glist), text_ypix(&x->x_obj, glist),x,x);
-	  }
-	  /* TODO callback from gui
-	    sys_vgui("image_size logo");
-	  */
-     }     
-     else {
-	  sys_vgui(".x%x.c coords %xS \
-%d %d\n",
-		   glist_getcanvas(glist), x,
-		   text_xpix(&x->x_obj, glist), text_ypix(&x->x_obj, glist));
-     }
-
-}
-
-
-void image_erase(t_image* x,t_glist* glist)
-{
-     int n;
-     sys_vgui(".x%x.c delete %xS\n",
-	      glist_getcanvas(glist), x);
-
-}
-	
-
-
-/* ------------------------ image widgetbehaviour----------------------------- */
-
-
-static void image_getrect(t_gobj *z, t_glist *glist,
-    int *xp1, int *yp1, int *xp2, int *yp2)
-{
-    int width, height;
-    t_image* x = (t_image*)z;
-
-
-    width = x->x_width;
-    height = x->x_height;
-    *xp1 = text_xpix(&x->x_obj, glist);
-    *yp1 = text_ypix(&x->x_obj, glist);
-    *xp2 = text_xpix(&x->x_obj, glist) + width;
-    *yp2 = text_ypix(&x->x_obj, glist) + height;
-}
-
-static void image_displace(t_gobj *z, t_glist *glist,
-    int dx, int dy)
-{
-    t_image *x = (t_image *)z;
-    x->x_obj.te_xpix += dx;
-    x->x_obj.te_ypix += dy;
-    sys_vgui(".x%x.c coords %xSEL %d %d %d %d\n",
-		   glist_getcanvas(glist), x,
-		   text_xpix(&x->x_obj, glist), text_ypix(&x->x_obj, glist),
-		   text_xpix(&x->x_obj, glist) + x->x_width, text_ypix(&x->x_obj, glist) + x->x_height);
-
-    image_drawme(x, glist, 0);
-    canvas_fixlinesfor(glist,(t_text*) x);
-}
-
-static void image_select(t_gobj *z, t_glist *glist, int state)
-{
-     t_image *x = (t_image *)z;
-     if (state) {
-	  sys_vgui(".x%x.c create rectangle \
-%d %d %d %d -tags %xSEL -outline blue\n",
-		   glist_getcanvas(glist),
-		   text_xpix(&x->x_obj, glist), text_ypix(&x->x_obj, glist),
-		   text_xpix(&x->x_obj, glist) + x->x_width, text_ypix(&x->x_obj, glist) + x->x_height,
-		   x);
-     }
-     else {
-	  sys_vgui(".x%x.c delete %xSEL\n",
-		   glist_getcanvas(glist), x);
-     }
-
-
-
-}
-
-
-static void image_activate(t_gobj *z, t_glist *glist, int state)
-{
-/*    t_text *x = (t_text *)z;
-    t_rtext *y = glist_findrtext(glist, x);
-    if (z->g_pd != gatom_class) rtext_activate(y, state);*/
-}
-
-static void image_delete(t_gobj *z, t_glist *glist)
-{
-    t_text *x = (t_text *)z;
-    canvas_deletelinesfor(glist, x);
-}
-
-       
-static void image_vis(t_gobj *z, t_glist *glist, int vis)
-{
-    t_image* s = (t_image*)z;
-    if (vis)
-	 image_drawme(s, glist, 1);
-    else
-	 image_erase(s,glist);
-}
-
-/* can we use the normal text save function ?? */
-
-static void image_save(t_gobj *z, t_binbuf *b)
-{
-    t_image *x = (t_image *)z;
-    binbuf_addv(b, "ssiissi", gensym("#X"),gensym("obj"),
-		x->x_obj.te_xpix, x->x_obj.te_ypix,   
-        atom_getsymbol(binbuf_getvec(x->x_obj.te_binbuf)),
-		x->x_image,x->x_type);
-    binbuf_addv(b, ";");
-}
-
-
-t_widgetbehavior   image_widgetbehavior;
-
-void image_size(t_image* x,t_floatarg w,t_floatarg h) {
-     x->x_width = w;
-     x->x_height = h;
-}
-
-void image_color(t_image* x,t_symbol* col)
-{
-/*     outlet_bang(x->x_obj.ob_outlet); only bang if there was a bang .. 
-       so color black does the same as bang, but doesn't forward the bang 
-*/
-}
-
-void image_open(t_gobj *z,t_symbol* file)
-{
-    t_image* x = (t_image*)z;
-	const char *fname;
-	int oldtype=x->x_type;
-	
-
-	fname=image_get_filename(x,file->s_name);
-	if(fname){
-		x->x_image=file;
-		x->x_type=0;
-	 	if(glist_isvisible(x->x_glist)) {
-			if(!x->x_localimage) {
-				sys_vgui("image create photo img%x\n",x);
-				x->x_localimage=1;
-			}
-			sys_vgui("img%x blank\n",x);
-			sys_vgui("img%x configure -file %s\n",x,fname);
-			if(oldtype) sys_vgui(".x%x.c itemconfigure %xS -image img%x\n",
-							glist_getcanvas(x->x_glist),x,x);
-		}
-	}
-}
-	
-void image_load(t_gobj *z,t_symbol* image,t_symbol* file)
-{
-    t_image* x = (t_image*)z;
-	const char *fname;
-
-	fname=image_get_filename(x,file->s_name);
-	if(fname){
-			sys_vgui("image create photo %s -file %s\n",image->s_name,fname);
-	}
-}
-	
-void image_set(t_gobj *z,t_symbol* image)
-{
-    t_image* x = (t_image*)z;
-	
-	x->x_image=image;
-	x->x_type=1;
-	
-	if(glist_isvisible(x->x_glist)) {
-	  	sys_vgui(".x%x.c itemconfigure %xS -image %s\n", 
-			glist_getcanvas(x->x_glist),x,x->x_image->s_name);
-	}
-}
-	
-
-static void image_setwidget(void)
-{
-    image_widgetbehavior.w_getrectfn =     image_getrect;
-    image_widgetbehavior.w_displacefn =    image_displace;
-    image_widgetbehavior.w_selectfn =   image_select;
-    image_widgetbehavior.w_activatefn =   image_activate;
-    image_widgetbehavior.w_deletefn =   image_delete;
-    image_widgetbehavior.w_visfn =   image_vis;
-#if (PD_VERSION_MINOR > 31) 
-    image_widgetbehavior.w_clickfn = NULL;
-    image_widgetbehavior.w_propertiesfn = NULL; 
-#endif
-#if PD_MINOR_VERSION < 37
-    image_widgetbehavior.w_savefn =   image_save;
-#endif
-}
-
-
-static void *image_new(t_symbol* image,int type)
-{
-    t_image *x = (t_image *)pd_new(image_class);
-
-    x->x_glist = (t_glist*) canvas_getcurrent();
-
-    x->x_width = 15;
-    x->x_height = 15;
-	x->x_type=type;
-	x->x_localimage=0;
-	x->x_image = image;
-
-   outlet_new(&x->x_obj, &s_float);
-    return (x);
-}
-
-void image_setup(void)
-{
-    image_class = class_new(gensym("image"), (t_newmethod)image_new, 0,
-				sizeof(t_image),0, A_DEFSYM,A_DEFFLOAT,0);
-
-/*
-    class_addmethod(image_class, (t_method)image_size, gensym("size"),
-    	A_FLOAT, A_FLOAT, 0);
-
-    class_addmethod(image_class, (t_method)image_color, gensym("color"),
-    	A_SYMBOL, 0);
-*/
-
-    class_addmethod(image_class, (t_method)image_open, gensym("open"),
-    	A_SYMBOL, 0);
-    class_addmethod(image_class, (t_method)image_set, gensym("set"),
-    	A_SYMBOL, 0);
-    class_addmethod(image_class, (t_method)image_load, gensym("load"),
-    	A_SYMBOL, A_SYMBOL, 0);
-
-    image_setwidget();
-    class_setwidget(image_class,&image_widgetbehavior);
-#if PD_MINOR_VERSION >= 37
-    class_setsavefn(image_class,&image_save);
-#endif
-
-}
-
-
+#include "m_pd.h"
+#include "m_imp.h"
+#include "g_canvas.h"
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifdef _MSC_VER
+#pragma warning( disable : 4244 )
+#pragma warning( disable : 4305 )
+#endif
+
+/* ------------------------ image ----------------------------- */
+
+static t_class *image_class;
+
+typedef struct _image
+{
+    t_object x_obj;
+    t_glist *x_glist;
+    int x_width;
+    int x_height;
+    t_symbol  *x_image;
+    int x_type; //0=file 1=tk_image
+    t_int  x_localimage; //localimage "img%x" done
+} t_image;
+
+/* widget helper functions */
+
+const char *image_get_filename(t_image *x,char *file)
+{
+    static char fname[MAXPDSTRING];
+    char *bufptr;
+    int fd;
+
+    fd=open_via_path(canvas_getdir(glist_getcanvas(x->x_glist))->s_name,
+                     file, "",fname, &bufptr, MAXPDSTRING, 1);
+    if(fd>0)
+    {
+        fname[strlen(fname)]='/';
+        close(fd);
+        return fname;
+    }
+    else return 0;
+}
+
+void image_drawme(t_image *x, t_glist *glist, int firsttime)
+{
+    if (firsttime)
+    {
+        if (x->x_image == &s_) // if we have a blank image name, use the included filler
+        {
+            x->x_image = gensym("::moonlib::image::noimage");
+            x->x_type = 1;
+            pd_error(x, "[image]: no image found");
+        }
+        if(x->x_type)
+        {
+            sys_vgui(".x%lx.c create image %d %d -tags %xS\n",
+                     glist_getcanvas(glist),
+                     text_xpix(&x->x_obj, glist), text_ypix(&x->x_obj, glist),x);
+            sys_vgui(".x%lx.c itemconfigure %xS -image %s\n",
+                     glist_getcanvas(glist),x,x->x_image->s_name);
+        }
+        else
+        {
+            const char *fname=image_get_filename(x,x->x_image->s_name);
+            if(!x->x_localimage)
+            {
+                sys_vgui("image create photo img%x\n",x);
+                x->x_localimage=1;
+            }
+            if(fname)
+                sys_vgui("::moonlib::image::configure .x%lx img%x {%s}\n",x,x,fname);
+            sys_vgui(".x%lx.c create image %d %d -image img%x -tags %xS\n",
+                     glist_getcanvas(glist),
+                     text_xpix(&x->x_obj, glist), text_ypix(&x->x_obj, glist),x,x);
+        }
+        /* TODO callback from gui
+          sys_vgui("image_size logo");
+        */
+    }
+    else
+    {
+        sys_vgui(".x%lx.c coords %xS \
+%d %d\n",
+                 glist_getcanvas(glist), x,
+                 text_xpix(&x->x_obj, glist), text_ypix(&x->x_obj, glist));
+    }
+
+}
+
+
+void image_erase(t_image *x,t_glist *glist)
+{
+    sys_vgui(".x%lx.c delete %xS\n", glist_getcanvas(glist), x);
+}
+
+
+
+/* ------------------------ image widgetbehaviour----------------------------- */
+
+
+static void image_getrect(t_gobj *z, t_glist *glist,
+                          int *xp1, int *yp1, int *xp2, int *yp2)
+{
+    int width, height;
+    t_image *x = (t_image *)z;
+
+
+    width = x->x_width;
+    height = x->x_height;
+    *xp1 = text_xpix(&x->x_obj, glist);
+    *yp1 = text_ypix(&x->x_obj, glist);
+    *xp2 = text_xpix(&x->x_obj, glist) + width;
+    *yp2 = text_ypix(&x->x_obj, glist) + height;
+}
+
+static void image_displace(t_gobj *z, t_glist *glist,
+                           int dx, int dy)
+{
+    t_image *x = (t_image *)z;
+    x->x_obj.te_xpix += dx;
+    x->x_obj.te_ypix += dy;
+    sys_vgui(".x%lx.c coords %xSEL %d %d %d %d\n",
+             glist_getcanvas(glist), x,
+             text_xpix(&x->x_obj, glist), text_ypix(&x->x_obj, glist),
+             text_xpix(&x->x_obj, glist) + x->x_width, text_ypix(&x->x_obj, glist) + x->x_height);
+
+    image_drawme(x, glist, 0);
+    canvas_fixlinesfor(glist,(t_text *) x);
+}
+
+static void image_select(t_gobj *z, t_glist *glist, int state)
+{
+    t_image *x = (t_image *)z;
+    if (state)
+    {
+        sys_vgui(".x%lx.c create rectangle \
+%d %d %d %d -tags %xSEL -outline blue\n",
+                 glist_getcanvas(glist),
+                 text_xpix(&x->x_obj, glist), text_ypix(&x->x_obj, glist),
+                 text_xpix(&x->x_obj, glist) + x->x_width, text_ypix(&x->x_obj, glist) + x->x_height,
+                 x);
+    }
+    else
+    {
+        sys_vgui(".x%lx.c delete %xSEL\n",
+                 glist_getcanvas(glist), x);
+    }
+
+
+
+}
+
+
+static void image_activate(t_gobj *z, t_glist *glist, int state)
+{
+    /*    t_text *x = (t_text *)z;
+        t_rtext *y = glist_findrtext(glist, x);
+        if (z->g_pd != gatom_class) rtext_activate(y, state);*/
+}
+
+static void image_delete(t_gobj *z, t_glist *glist)
+{
+    t_text *x = (t_text *)z;
+    canvas_deletelinesfor(glist, x);
+}
+
+
+static void image_vis(t_gobj *z, t_glist *glist, int vis)
+{
+    t_image *s = (t_image *)z;
+    if (vis)
+        image_drawme(s, glist, 1);
+    else
+        image_erase(s,glist);
+}
+
+/* can we use the normal text save function ?? */
+
+static void image_save(t_gobj *z, t_binbuf *b)
+{
+    t_image *x = (t_image *)z;
+    binbuf_addv(b, "ssiissi", gensym("#X"),gensym("obj"),
+                x->x_obj.te_xpix, x->x_obj.te_ypix,
+                atom_getsymbol(binbuf_getvec(x->x_obj.te_binbuf)),
+                x->x_image,x->x_type);
+    binbuf_addv(b, ";");
+}
+
+
+t_widgetbehavior   image_widgetbehavior;
+
+void image_size(t_image *x,t_floatarg w,t_floatarg h)
+{
+    x->x_width = w;
+    x->x_height = h;
+}
+
+void image_color(t_image *x,t_symbol *col)
+{
+    /*     outlet_bang(x->x_obj.ob_outlet); only bang if there was a bang ..
+           so color black does the same as bang, but doesn't forward the bang
+    */
+}
+
+void image_open(t_gobj *z,t_symbol *file)
+{
+    t_image *x = (t_image *)z;
+    const char *fname;
+    int oldtype=x->x_type;
+
+
+    fname=image_get_filename(x,file->s_name);
+    if(fname)
+    {
+        x->x_image=file;
+        x->x_type=0;
+        if(glist_isvisible(x->x_glist))
+        {
+            if(!x->x_localimage)
+            {
+                sys_vgui("image create photo img%x\n",x);
+                x->x_localimage=1;
+            }
+            sys_vgui("img%x blank\n",x);
+            sys_vgui("::moonlib::image::configure .x%lx img%x {%s}\n",x,x,fname);
+            if(oldtype) sys_vgui(".x%lx.c itemconfigure %xS -image img%x\n",
+                                     glist_getcanvas(x->x_glist),x,x);
+        }
+    }
+    else
+        pd_error(x, "[image]: error opening file '%s'", file->s_name);
+}
+
+void image_load(t_gobj *z,t_symbol *image,t_symbol *file)
+{
+    t_image *x = (t_image *)z;
+    const char *fname;
+
+    fname=image_get_filename(x,file->s_name);
+    if(fname)
+        sys_vgui("::moonlib::image::create_photo .x%lx %s {%s}\n",x,image->s_name,fname);
+}
+
+void image_set(t_gobj *z,t_symbol *image)
+{
+    t_image *x = (t_image *)z;
+
+    x->x_image=image;
+    x->x_type=1;
+
+    if(glist_isvisible(x->x_glist))
+        sys_vgui(".x%lx.c itemconfigure %xS -image %s\n",
+                 glist_getcanvas(x->x_glist),x,x->x_image->s_name);
+}
+
+
+static void image_setwidget(void)
+{
+    image_widgetbehavior.w_getrectfn =     image_getrect;
+    image_widgetbehavior.w_displacefn =    image_displace;
+    image_widgetbehavior.w_selectfn =   image_select;
+    image_widgetbehavior.w_activatefn =   image_activate;
+    image_widgetbehavior.w_deletefn =   image_delete;
+    image_widgetbehavior.w_visfn =   image_vis;
+#if (PD_VERSION_MINOR > 31)
+    image_widgetbehavior.w_clickfn = NULL;
+    image_widgetbehavior.w_propertiesfn = NULL;
+#endif
+#if PD_MINOR_VERSION < 37
+    image_widgetbehavior.w_savefn =   image_save;
+#endif
+}
+
+
+static void *image_new(t_symbol *image, t_float type)
+{
+    t_image *x = (t_image *)pd_new(image_class);
+
+    x->x_glist = (t_glist *) canvas_getcurrent();
+
+    x->x_width = 15;
+    x->x_height = 15;
+    if (type != 0)
+        x->x_type= 1;
+    else
+        x->x_type= 0;
+    x->x_localimage=0;
+    x->x_image = image;
+
+    outlet_new(&x->x_obj, &s_float);
+    return (x);
+}
+
+void image_setup(void)
+{
+    image_class = class_new(gensym("image"), (t_newmethod)image_new, 0,
+                            sizeof(t_image),0, A_DEFSYM,A_DEFFLOAT,0);
+
+    /*
+        class_addmethod(image_class, (t_method)image_size, gensym("size"),
+        	A_FLOAT, A_FLOAT, 0);
+
+        class_addmethod(image_class, (t_method)image_color, gensym("color"),
+        	A_SYMBOL, 0);
+    */
+
+    class_addmethod(image_class, (t_method)image_open, gensym("open"),
+                    A_SYMBOL, 0);
+    class_addmethod(image_class, (t_method)image_set, gensym("set"),
+                    A_SYMBOL, 0);
+    class_addmethod(image_class, (t_method)image_load, gensym("load"),
+                    A_SYMBOL, A_SYMBOL, 0);
+
+    image_setwidget();
+    class_setwidget(image_class,&image_widgetbehavior);
+#if PD_MINOR_VERSION >= 37
+    class_setsavefn(image_class,&image_save);
+#endif
+
+    sys_vgui("eval [read [open {%s/%s.tcl}]]\n",
+             image_class->c_externdir->s_name,
+             image_class->c_name->s_name);
+}
+
+
diff --git a/image.tcl b/image.tcl
new file mode 100644
index 0000000..788e24c
--- /dev/null
+++ b/image.tcl
@@ -0,0 +1,26 @@
+
+namespace eval ::moonlib::image:: {
+}
+
+proc ::moonlib::image::configure {obj_id img filename} {
+    if { [catch {$img configure -file $filename} fid]} {
+        ::pdwindow::logpost $obj_id 1 "[image]: error reading '$filename':\n$fid\n"
+    }
+}
+
+proc ::moonlib::image::create_photo {obj_id img filename} {
+    if { [catch {image create photo $img -file $filename} fid]} {
+        ::pdwindow::logpost $obj_id 1 "[image]: error reading '$filename':\n$fid\n"
+    }
+}
+
+image create photo ::moonlib::image::noimage -data {
+    R0lGODlhDwARANU8AAAAAP6xDv/yHP6kDP6oCv7FEP/pGUY6J/7KEP7CD//tG/6sCurp6FVLM+/v
+    7vzhGP7SE/61DtfW05pwG/7ZFXFjOmNWM31yXv65Dv69D/nuIu+9Em5hRmlcO1FELv///1tILLWW
+    I/b29v/kGOubD/7cFteMEYBdJoiAbpKMeJuYjWNXQF9UOrq4stmYEui/FoqEc3VoRZWQfMCBEtbG
+    MO3VHe6qEObUOZiDQ+2wEcJ/EnluWf///wAAAAAAAAAAACH5BAEAADwALAAAAAAPABEAQAa1QJ5Q
+    JIt1Kh1OSiTkNSAQgBRRSEgBgcChKWxdOLsWl5eiKQRoheFBQSQKExjvMsFErtLBYHIRqnAaaAIG
+    axQvFio8Fg94ACWNGB4oIQWVCRFZCwQEeyhCDAcumpwDJgcMXBIVN4FqNSErEkIOCoGCBiNtCBsH
+    DiwPhApqIyUQVRk5HhUUVx8AUVLOASAKGwhUx1mZJAoSFhgZAJgBmgCcILIOBzaYo3okvVwMKycz
+    JjonLKhCQQA7
+}
diff --git a/examples/d0.gif b/img/d0.gif
similarity index 100%
rename from examples/d0.gif
rename to img/d0.gif
diff --git a/examples/d1.gif b/img/d1.gif
similarity index 100%
rename from examples/d1.gif
rename to img/d1.gif
diff --git a/examples/d10.gif b/img/d10.gif
similarity index 100%
rename from examples/d10.gif
rename to img/d10.gif
diff --git a/examples/d11.gif b/img/d11.gif
similarity index 100%
rename from examples/d11.gif
rename to img/d11.gif
diff --git a/examples/d12.gif b/img/d12.gif
similarity index 100%
rename from examples/d12.gif
rename to img/d12.gif
diff --git a/examples/d13.gif b/img/d13.gif
similarity index 100%
rename from examples/d13.gif
rename to img/d13.gif
diff --git a/examples/d14.gif b/img/d14.gif
similarity index 100%
rename from examples/d14.gif
rename to img/d14.gif
diff --git a/examples/d15.gif b/img/d15.gif
similarity index 100%
rename from examples/d15.gif
rename to img/d15.gif
diff --git a/examples/d16.gif b/img/d16.gif
similarity index 100%
rename from examples/d16.gif
rename to img/d16.gif
diff --git a/examples/d17.gif b/img/d17.gif
similarity index 100%
rename from examples/d17.gif
rename to img/d17.gif
diff --git a/examples/d18.gif b/img/d18.gif
similarity index 100%
rename from examples/d18.gif
rename to img/d18.gif
diff --git a/examples/d19.gif b/img/d19.gif
similarity index 100%
rename from examples/d19.gif
rename to img/d19.gif
diff --git a/examples/d2.gif b/img/d2.gif
similarity index 100%
rename from examples/d2.gif
rename to img/d2.gif
diff --git a/examples/d20.gif b/img/d20.gif
similarity index 100%
rename from examples/d20.gif
rename to img/d20.gif
diff --git a/examples/d21.gif b/img/d21.gif
similarity index 100%
rename from examples/d21.gif
rename to img/d21.gif
diff --git a/examples/d22.gif b/img/d22.gif
similarity index 100%
rename from examples/d22.gif
rename to img/d22.gif
diff --git a/examples/d23.gif b/img/d23.gif
similarity index 100%
rename from examples/d23.gif
rename to img/d23.gif
diff --git a/examples/d24.gif b/img/d24.gif
similarity index 100%
rename from examples/d24.gif
rename to img/d24.gif
diff --git a/examples/d25.gif b/img/d25.gif
similarity index 100%
rename from examples/d25.gif
rename to img/d25.gif
diff --git a/examples/d26.gif b/img/d26.gif
similarity index 100%
rename from examples/d26.gif
rename to img/d26.gif
diff --git a/examples/d27.gif b/img/d27.gif
similarity index 100%
rename from examples/d27.gif
rename to img/d27.gif
diff --git a/examples/d28.gif b/img/d28.gif
similarity index 100%
rename from examples/d28.gif
rename to img/d28.gif
diff --git a/examples/d29.gif b/img/d29.gif
similarity index 100%
rename from examples/d29.gif
rename to img/d29.gif
diff --git a/examples/d3.gif b/img/d3.gif
similarity index 100%
rename from examples/d3.gif
rename to img/d3.gif
diff --git a/examples/d30.gif b/img/d30.gif
similarity index 100%
rename from examples/d30.gif
rename to img/d30.gif
diff --git a/examples/d31.gif b/img/d31.gif
similarity index 100%
rename from examples/d31.gif
rename to img/d31.gif
diff --git a/examples/d32.gif b/img/d32.gif
similarity index 100%
rename from examples/d32.gif
rename to img/d32.gif
diff --git a/examples/d33.gif b/img/d33.gif
similarity index 100%
rename from examples/d33.gif
rename to img/d33.gif
diff --git a/examples/d34.gif b/img/d34.gif
similarity index 100%
rename from examples/d34.gif
rename to img/d34.gif
diff --git a/examples/d35.gif b/img/d35.gif
similarity index 100%
rename from examples/d35.gif
rename to img/d35.gif
diff --git a/examples/d36.gif b/img/d36.gif
similarity index 100%
rename from examples/d36.gif
rename to img/d36.gif
diff --git a/examples/d37.gif b/img/d37.gif
similarity index 100%
rename from examples/d37.gif
rename to img/d37.gif
diff --git a/examples/d38.gif b/img/d38.gif
similarity index 100%
rename from examples/d38.gif
rename to img/d38.gif
diff --git a/examples/d39.gif b/img/d39.gif
similarity index 100%
rename from examples/d39.gif
rename to img/d39.gif
diff --git a/examples/d4.gif b/img/d4.gif
similarity index 100%
rename from examples/d4.gif
rename to img/d4.gif
diff --git a/examples/d40.gif b/img/d40.gif
similarity index 100%
rename from examples/d40.gif
rename to img/d40.gif
diff --git a/examples/d41.gif b/img/d41.gif
similarity index 100%
rename from examples/d41.gif
rename to img/d41.gif
diff --git a/examples/d42.gif b/img/d42.gif
similarity index 100%
rename from examples/d42.gif
rename to img/d42.gif
diff --git a/examples/d43.gif b/img/d43.gif
similarity index 100%
rename from examples/d43.gif
rename to img/d43.gif
diff --git a/examples/d44.gif b/img/d44.gif
similarity index 100%
rename from examples/d44.gif
rename to img/d44.gif
diff --git a/examples/d45.gif b/img/d45.gif
similarity index 100%
rename from examples/d45.gif
rename to img/d45.gif
diff --git a/examples/d46.gif b/img/d46.gif
similarity index 100%
rename from examples/d46.gif
rename to img/d46.gif
diff --git a/examples/d47.gif b/img/d47.gif
similarity index 100%
rename from examples/d47.gif
rename to img/d47.gif
diff --git a/examples/d48.gif b/img/d48.gif
similarity index 100%
rename from examples/d48.gif
rename to img/d48.gif
diff --git a/examples/d49.gif b/img/d49.gif
similarity index 100%
rename from examples/d49.gif
rename to img/d49.gif
diff --git a/examples/d5.gif b/img/d5.gif
similarity index 100%
rename from examples/d5.gif
rename to img/d5.gif
diff --git a/examples/d50.gif b/img/d50.gif
similarity index 100%
rename from examples/d50.gif
rename to img/d50.gif
diff --git a/examples/d51.gif b/img/d51.gif
similarity index 100%
rename from examples/d51.gif
rename to img/d51.gif
diff --git a/examples/d52.gif b/img/d52.gif
similarity index 100%
rename from examples/d52.gif
rename to img/d52.gif
diff --git a/examples/d53.gif b/img/d53.gif
similarity index 100%
rename from examples/d53.gif
rename to img/d53.gif
diff --git a/examples/d54.gif b/img/d54.gif
similarity index 100%
rename from examples/d54.gif
rename to img/d54.gif
diff --git a/examples/d55.gif b/img/d55.gif
similarity index 100%
rename from examples/d55.gif
rename to img/d55.gif
diff --git a/examples/d56.gif b/img/d56.gif
similarity index 100%
rename from examples/d56.gif
rename to img/d56.gif
diff --git a/examples/d57.gif b/img/d57.gif
similarity index 100%
rename from examples/d57.gif
rename to img/d57.gif
diff --git a/examples/d58.gif b/img/d58.gif
similarity index 100%
rename from examples/d58.gif
rename to img/d58.gif
diff --git a/examples/d59.gif b/img/d59.gif
similarity index 100%
rename from examples/d59.gif
rename to img/d59.gif
diff --git a/examples/d6.gif b/img/d6.gif
similarity index 100%
rename from examples/d6.gif
rename to img/d6.gif
diff --git a/examples/d60.gif b/img/d60.gif
similarity index 100%
rename from examples/d60.gif
rename to img/d60.gif
diff --git a/examples/d61.gif b/img/d61.gif
similarity index 100%
rename from examples/d61.gif
rename to img/d61.gif
diff --git a/examples/d62.gif b/img/d62.gif
similarity index 100%
rename from examples/d62.gif
rename to img/d62.gif
diff --git a/examples/d63.gif b/img/d63.gif
similarity index 100%
rename from examples/d63.gif
rename to img/d63.gif
diff --git a/examples/d7.gif b/img/d7.gif
similarity index 100%
rename from examples/d7.gif
rename to img/d7.gif
diff --git a/examples/d8.gif b/img/d8.gif
similarity index 100%
rename from examples/d8.gif
rename to img/d8.gif
diff --git a/examples/d9.gif b/img/d9.gif
similarity index 100%
rename from examples/d9.gif
rename to img/d9.gif
diff --git a/examples/pause.gif b/img/pause.gif
similarity index 100%
rename from examples/pause.gif
rename to img/pause.gif
diff --git a/examples/play.gif b/img/play.gif
similarity index 100%
rename from examples/play.gif
rename to img/play.gif
diff --git a/examples/playy.gif b/img/playy.gif
similarity index 100%
rename from examples/playy.gif
rename to img/playy.gif
diff --git a/examples/rec.gif b/img/rec.gif
similarity index 100%
rename from examples/rec.gif
rename to img/rec.gif
diff --git a/examples/saww.gif b/img/saww.gif
similarity index 100%
rename from examples/saww.gif
rename to img/saww.gif
diff --git a/examples/sin.gif b/img/sin.gif
similarity index 100%
rename from examples/sin.gif
rename to img/sin.gif
diff --git a/examples/sinw.gif b/img/sinw.gif
similarity index 100%
rename from examples/sinw.gif
rename to img/sinw.gif
diff --git a/examples/squarew.gif b/img/squarew.gif
similarity index 100%
rename from examples/squarew.gif
rename to img/squarew.gif
diff --git a/mknob-help.pd b/mknob-help.pd
index 90f4fb2..8bcd84b 100644
--- a/mknob-help.pd
+++ b/mknob-help.pd
@@ -1,53 +1,61 @@
-#N canvas 19 167 677 325 10;
-#X obj 0 0 cnv 8 100 60 empty empty mknob 20 20 1 18 -262144 -1109
-0;
-#X floatatom 55 149 5 0 0 0 - - -;
-#X floatatom 55 68 5 0 0 0 - - -;
-#X text 104 208 Just an adaptation of musil's slider.;
-#X obj 138 224 hsl 128 15 0 127 0 0 empty empty empty -2 -6 0 8 -262144
--1 -1 0 1;
-#X text 103 222 See:;
-#X msg 3 107 set \$1;
-#X floatatom 190 114 5 0 0 0 - - -;
-#X obj 190 95 r foo-snd;
-#X floatatom 190 60 5 0 0 0 - - -;
-#X obj 190 76 s foo-rcv;
-#X text 135 12 gui-round-knob;
-#X text 2 302 (c) moonix: Antoine Rousseau 2003;
-#X obj 149 57 mknob 25 100 0 100 0 0 foo-snd foo-rcv empty -2 -6 192
-8 -225271 -1 -1 0 1;
-#X obj 55 85 mknob 30 100 0 127 0 0 empty empty empty -2 -6 0 8 -241291
--24198 -1 0 1;
-#X obj 55 126 mknob 15 100 127 0 0 0 empty empty empty -2 -6 0 8 -258699
--24198 -1 0 1;
-#X text 306 40 "mouse" parameter sets mouse;
-#X text 309 50 excursion for full range.;
-#X text 309 62 Set it with "size" parameter:;
-#X obj 398 201 mknob 25 -1 0 127 0 0 empty empty empty -2 -6 0 8 -262144
--1 -1 0 1;
-#X msg 369 96 size 25 300;
-#X msg 398 119 size 25 10;
-#X text 452 96 low sensibility;
-#X text 474 120 high sens;
-#X text 494 142 default;
-#X msg 413 141 size 25 100;
-#X text 497 164 angular control;
-#X msg 427 165 size 25 0;
-#X text 518 187 full angular control;
-#X msg 443 188 size 25 -1;
-#X text 273 253 Note: there is in the sources a patch named mknob.pd.tk.diff
-to add (in pd.tk) mknob in the Pd "Put" menu \, and to give the hotkey
-"Alt-k" to it. It will only work for Pd0.37 \, but it can help to do
-the modif by hand for another version.;
-#X connect 2 0 14 0;
-#X connect 6 0 14 0;
-#X connect 8 0 7 0;
-#X connect 9 0 10 0;
-#X connect 14 0 15 0;
-#X connect 15 0 6 0;
-#X connect 15 0 1 0;
-#X connect 20 0 19 0;
-#X connect 21 0 19 0;
-#X connect 25 0 19 0;
-#X connect 27 0 19 0;
-#X connect 29 0 19 0;
+#N canvas 1 82 669 272 10;
+#X obj 0 0 cnv 8 100 60 empty empty mknob 20 20 1 18 -262144 -1109
+0;
+#X floatatom 55 149 5 0 0 0 - - -, f 5;
+#X floatatom 55 68 5 0 0 0 - - -, f 5;
+#X text 108 188 Just an adaptation of musil's slider.;
+#X obj 142 204 hsl 128 15 0 127 0 0 empty empty empty -2 -6 0 8 -262144
+-1 -1 5100 1;
+#X text 106 204 See:;
+#X msg 3 107 set \$1;
+#X floatatom 183 141 5 0 0 0 - - -, f 5;
+#X obj 183 122 r foo-snd;
+#X floatatom 183 87 5 0 0 0 - - -, f 5;
+#X obj 183 103 s foo-rcv;
+#X text 135 12 gui-round-knob;
+#X text 4 233 (c) moonix: Antoine Rousseau 2003;
+#X obj 142 84 mknob 25 100 0 100 0 0 foo-snd foo-rcv empty -2 -6 0
+8 -225271 -1 -1 0 1;
+#X obj 55 85 mknob 30 100 0 127 0 0 empty empty empty -2 -6 0 8 -241291
+-24198 -1 9900 1;
+#X obj 55 126 mknob 15 100 127 0 0 0 empty empty empty -2 -6 0 8 -258699
+-24198 -1 0 1;
+#X text 306 40 "mouse" parameter sets mouse;
+#X text 309 50 excursion for full range.;
+#X text 309 62 Set it with "size" parameter:;
+#X obj 398 201 mknob 25 0 0 127 0 0 empty empty empty -2 -6 0 8 -262144
+-1 -1 1078 1;
+#X msg 369 96 size 25 300;
+#X msg 398 119 size 25 10;
+#X text 452 96 low sensibility;
+#X text 474 120 high sens;
+#X text 494 142 default;
+#X msg 413 141 size 25 100;
+#X text 497 164 angular control;
+#X msg 427 165 size 25 0;
+#X text 518 187 full angular control;
+#X msg 443 188 size 25 -1;
+#N canvas 512 232 494 344 META 0;
+#X text 12 25 LICENSE GPL v2;
+#X text 12 105 AUTHOR Antoine Rousseau;
+#X text 12 125 HELP_PATCH_AUTHORS Antoine Rousseau. "pd meta" information
+added by Jonathan Wilkes for Pd version 0.42.;
+#X text 12 45 DESCRIPTION round gui knob;
+#X text 12 5 KEYWORDS control GUI;
+#X text 12 65 INLET_0 float size;
+#X text 12 85 OUTLET_0 float;
+#X restore 616 239 pd META;
+#X text 120 41 click properties to;
+#X text 108 52 modify geometry \, colors \, etc.;
+#X connect 2 0 14 0;
+#X connect 6 0 14 0;
+#X connect 8 0 7 0;
+#X connect 9 0 10 0;
+#X connect 14 0 15 0;
+#X connect 15 0 6 0;
+#X connect 15 0 1 0;
+#X connect 20 0 19 0;
+#X connect 21 0 19 0;
+#X connect 25 0 19 0;
+#X connect 27 0 19 0;
+#X connect 29 0 19 0;
diff --git a/mknob.c b/mknob.c
index b4a3a88..8e91bde 100644
--- a/mknob.c
+++ b/mknob.c
@@ -1,871 +1,1016 @@
-/* Copyright (c) 1997-1999 Miller Puckette.
- * For information on usage and redistribution, and for a DISCLAIMER OF ALL
- * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
-
-/* mknob.c written by Antoine Rousseau from g_vslider.c.*/
-/* g_7_guis.c written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */
-/* thanks to Miller Puckette, Guenther Geiger and Krzystof Czaja */
-
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <ctype.h>
-#include "m_pd.h"
-#include "g_canvas.h"
-
-#include "g_all_guis.h"
-#include <math.h>
-
-#ifdef _WIN32
-#include <io.h>
-#else
-#include <unistd.h>
-#endif
-
-
-#define MKNOB_TANGLE 100
-#define MKNOB_DEFAULTH 100
-#define MKNOB_DEFAULTSIZE 25
-#define MKNOB_MINSIZE 12
-#define MKNOB_THICK 3
-/* ------------ mknob  ----------------------- */
-typedef struct _mknob
-{
-    t_iemgui x_gui;
-    int      x_pos;
-    int      x_val;
-    int      x_center;
-    int      x_thick;
-    int      x_lin0_log1;
-    int      x_steady;
-    double   x_min;
-    double   x_max;
-    int   	 x_H;
-    double   x_k;
-} t_mknob;
-
-t_widgetbehavior mknob_widgetbehavior;
-static t_class *mknob_class;
-
-/* widget helper functions */
-static void mknob_update_knob(t_mknob *x, t_glist *glist)
-{
-    t_canvas *canvas=glist_getcanvas(glist);
-//	float val=(x->x_val + 50.0)/100.0/MKNOB_TANGLE;
-	float val=(x->x_val + 50.0)/100.0/x->x_H;
-	float 	angle,
-			radius=x->x_gui.x_w/2.0,
-			miniradius=MKNOB_THICK;
-	int x0,y0,x1,y1,xc,yc,xp,yp,xpc,ypc;
-    x0=text_xpix(&x->x_gui.x_obj, glist);
-    y0=text_ypix(&x->x_gui.x_obj, glist);
-	x1=x0+x->x_gui.x_w;
-	y1=y0+x->x_gui.x_w;
-	xc=(x0+x1)/2;
-	yc=(y0+y1)/2;
-	
-	if(x->x_gui.x_h<0)
-		angle=val*(M_PI*2)+M_PI/2.0;
-	else 
-		angle=val*(M_PI*1.5)+3.0*M_PI/4.0;
-		
-	xp=xc+radius*cos(angle);
-	yp=yc+radius*sin(angle);
-	xpc=miniradius*cos(angle-M_PI/2);
-	ypc=miniradius*sin(angle-M_PI/2);
-	
-	sys_vgui(".x%x.c coords %xKNOB %d %d %d %d %d %d\n",
-		canvas,x,xp,yp,xc+xpc,yc+ypc,xc-xpc,yc-ypc);
-}
-
-static void mknob_draw_update(t_mknob *x, t_glist *glist)
-{
-    if (glist_isvisible(glist))
-    {
-		mknob_update_knob(x,glist);
-		
-	/*if(x->x_val == x->x_center)
-	{
-	    if(!x->x_thick)
-	    {
-		sys_vgui(".x%x.c itemconfigure %xKNOB -width 7\n", canvas, x);
-		x->x_thick = 1;
-	    }
-	}
-	else
-	{
-	    if(x->x_thick)
-	    {
-		sys_vgui(".x%x.c itemconfigure %xKNOB -width 3\n", canvas, x);
-		x->x_thick = 0;
-	    }
-	}*/
-    }
-}
-
-static void mknob_draw_new(t_mknob *x, t_glist *glist)
-{
-    int xpos=text_xpix(&x->x_gui.x_obj, glist);
-    int ypos=text_ypix(&x->x_gui.x_obj, glist);
-    int r = xpos + (x->x_val + 50)/100;
-	int xc=xpos+x->x_gui.x_w/2;
-	int yc=ypos+x->x_gui.x_w/2;
-    t_canvas *canvas=glist_getcanvas(glist);
-
-	sys_vgui(".x%x.c create oval %d %d %d %d -fill #%6.6x -tags %xBASE\n",
-		canvas,xpos,ypos,xpos + x->x_gui.x_w, ypos + x->x_gui.x_w,
-		x->x_gui.x_bcol,x); 
-	sys_vgui(".x%x.c create polygon %d %d %d %d %d %d -fill #%6.6x -tags %xKNOB\n",
-		glist_getcanvas(glist),
-		xc,ypos,xc-4,yc,xc+4,yc,x->x_gui.x_fcol,x);
-	mknob_update_knob(x,glist);
-    sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
-	     -font {%s %d bold} -fill #%6.6x -tags %xLABEL\n",
-	     canvas, xpos+x->x_gui.x_ldx,
-	     ypos+x->x_gui.x_ldy,
-	     strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"",
-	     x->x_gui.x_font, x->x_gui.x_fontsize, x->x_gui.x_lcol, x);
-    /*if(!x->x_gui.x_fsf.x_snd_able)
-        sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
-	     canvas, xpos+ x->x_gui.x_w/2-3, ypos + x->x_gui.x_w-1,
-	     xpos+ x->x_gui.x_w/2+4, ypos + x->x_gui.x_w, x, 0);
-    if(!x->x_gui.x_fsf.x_rcv_able)
-	sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
-	     canvas, xpos+ x->x_gui.x_w/2-3, ypos,
-	     xpos+ x->x_gui.x_w/2+4, ypos+1, x, 0);*/
-}
-
-static void mknob_draw_move(t_mknob *x, t_glist *glist)
-{
-    int xpos=text_xpix(&x->x_gui.x_obj, glist);
-    int ypos=text_ypix(&x->x_gui.x_obj, glist);
-    int r = xpos + (x->x_val + 50)/100;
-    t_canvas *canvas=glist_getcanvas(glist);
-
-    sys_vgui(".x%x.c coords %xBASE %d %d %d %d\n",
-	     canvas, x,
-	     xpos, ypos,
-	     xpos + x->x_gui.x_w, ypos + x->x_gui.x_w);
-    mknob_update_knob(x,glist);
-    sys_vgui(".x%x.c coords %xLABEL %d %d\n",
-	     canvas, x, xpos+x->x_gui.x_ldx, ypos+x->x_gui.x_ldy);
-    /*if(!x->x_gui.x_fsf.x_snd_able)
-        sys_vgui(".x%x.c coords %xOUT%d %d %d %d %d\n",
-	     canvas, x, 0,
-	     xpos+ x->x_gui.x_w/2-3, ypos + x->x_gui.x_w-1,
-	     xpos+ x->x_gui.x_w/2+4, ypos + x->x_gui.x_w);
-    if(!x->x_gui.x_fsf.x_rcv_able)
-	sys_vgui(".x%x.c coords %xIN%d %d %d %d %d\n",
-	     canvas, x, 0,
-	     xpos+ x->x_gui.x_w/2-3, ypos,
-	     xpos+ x->x_gui.x_w/2+4, ypos+1);*/
-}
-
-static void mknob_draw_erase(t_mknob* x,t_glist* glist)
-{
-    t_canvas *canvas=glist_getcanvas(glist);
-
-    sys_vgui(".x%x.c delete %xBASE\n", canvas, x);
-    sys_vgui(".x%x.c delete %xKNOB\n", canvas, x);
-    sys_vgui(".x%x.c delete %xLABEL\n", canvas, x);
-    /*if(!x->x_gui.x_fsf.x_snd_able)
-        sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
-    if(!x->x_gui.x_fsf.x_rcv_able)
-        sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);*/
-}
-
-static void mknob_draw_config(t_mknob* x,t_glist* glist)
-{
-    t_canvas *canvas=glist_getcanvas(glist);
-
-    sys_vgui(".x%x.c itemconfigure %xLABEL -font {%s %d bold} -fill #%6.6x -text {%s} \n",
-	     canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize,
-	     x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol,
-	     strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"");
-    sys_vgui(".x%x.c itemconfigure %xKNOB -fill #%6.6x\n", canvas, x, x->x_gui.x_fcol);
-    sys_vgui(".x%x.c itemconfigure %xBASE -fill #%6.6x\n", canvas, x, x->x_gui.x_bcol);
-}
-
-static void mknob_draw_io(t_mknob* x,t_glist* glist, int old_snd_rcv_flags)
-{
-    int xpos=text_xpix(&x->x_gui.x_obj, glist);
-    int ypos=text_ypix(&x->x_gui.x_obj, glist);
-    t_canvas *canvas=glist_getcanvas(glist);
-
-    /*if((old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && !x->x_gui.x_fsf.x_snd_able)
-        sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
-	     canvas, xpos+ x->x_gui.x_w/2-3, ypos + x->x_gui.x_w-1,
-	     xpos+ x->x_gui.x_w/2+4, ypos + x->x_gui.x_w, x, 0);
-    if(!(old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && x->x_gui.x_fsf.x_snd_able)
-        sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
-    if((old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && !x->x_gui.x_fsf.x_rcv_able)
-        sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
-	     canvas, xpos+ x->x_gui.x_w/2-3, ypos,
-	     xpos+ x->x_gui.x_w/2+4, ypos+1, x, 0);
-    if(!(old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && x->x_gui.x_fsf.x_rcv_able)
-	sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);*/
-}
-
-static void mknob_draw_select(t_mknob* x,t_glist* glist)
-{
-    t_canvas *canvas=glist_getcanvas(glist);
-
-    if(x->x_gui.x_fsf.x_selected)
-    {
-	//pd_bind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);
-	sys_vgui(".x%x.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
-	sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
-    }
-    else
-    {
-	//pd_unbind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);
-	sys_vgui(".x%x.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_NORMAL);
-	sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, x->x_gui.x_lcol);
-    }
-}
-
-void mknob_draw(t_mknob *x, t_glist *glist, int mode)
-{
-    if(mode == IEM_GUI_DRAW_MODE_UPDATE)
-	mknob_draw_update(x, glist);
-    else if(mode == IEM_GUI_DRAW_MODE_MOVE)
-	mknob_draw_move(x, glist);
-    else if(mode == IEM_GUI_DRAW_MODE_NEW)
-	mknob_draw_new(x, glist);
-    else if(mode == IEM_GUI_DRAW_MODE_SELECT)
-	mknob_draw_select(x, glist);
-    else if(mode == IEM_GUI_DRAW_MODE_ERASE)
-	mknob_draw_erase(x, glist);
-    else if(mode == IEM_GUI_DRAW_MODE_CONFIG)
-	mknob_draw_config(x, glist);
-    /*else if(mode >= IEM_GUI_DRAW_MODE_IO)
-	mknob_draw_io(x, glist, mode - IEM_GUI_DRAW_MODE_IO);*/
-}
-
-/* ------------------------ mknob widgetbehaviour----------------------------- */
-
-
-static void mknob_getrect(t_gobj *z, t_glist *glist,
-			    int *xp1, int *yp1, int *xp2, int *yp2)
-{
-    t_mknob* x = (t_mknob*)z;
-
-    *xp1 = text_xpix(&x->x_gui.x_obj, glist);
-    *yp1 = text_ypix(&x->x_gui.x_obj, glist);
-    *xp2 = *xp1 + x->x_gui.x_w;
-    *yp2 = *yp1 + x->x_gui.x_w;
-}
-
-static void mknob_save(t_gobj *z, t_binbuf *b)
-{
-    t_mknob *x = (t_mknob *)z;
-    int bflcol[3], *ip1, *ip2;
-    t_symbol *srl[3];
-
-    iemgui_save(&x->x_gui, srl, bflcol);
-    ip1 = (int *)(&x->x_gui.x_isa);
-    ip2 = (int *)(&x->x_gui.x_fsf);
-    binbuf_addv(b, "ssiisiiffiisssiiiiiiiii", gensym("#X"),gensym("obj"),
-		(t_int)x->x_gui.x_obj.te_xpix, (t_int)x->x_gui.x_obj.te_ypix,
-        atom_getsymbol(binbuf_getvec(x->x_gui.x_obj.te_binbuf)),
-        x->x_gui.x_w, x->x_gui.x_h,
-		(float)x->x_min, (float)x->x_max,
-		x->x_lin0_log1, (*ip1)&IEM_INIT_ARGS_ALL,
-		srl[0], srl[1], srl[2],
-		x->x_gui.x_ldx, x->x_gui.x_ldy,
-		(*ip2)&IEM_FSTYLE_FLAGS_ALL, x->x_gui.x_fontsize,
-		bflcol[0], bflcol[1], bflcol[2],
-		x->x_val, x->x_steady);
-    binbuf_addv(b, ";");
-}
-
-void mknob_check_wh(t_mknob *x, int w, int h)
-{
-    int H;
-	
-	if(w < MKNOB_MINSIZE) w = MKNOB_MINSIZE;
-    x->x_gui.x_w = w;
-	
-    if(h < -1) h=-1;
-    if((h>0)&&(h<20)) h=20;
-    x->x_gui.x_h = h;
-	
-	H=x->x_gui.x_h;
-	if(H<0) H=360;
-	if(H==0) H=270;
-	x->x_H=H;
-	
-    if(x->x_lin0_log1)
-	x->x_k = log(x->x_max/x->x_min)/(double)(x->x_H - 1);
-    else
-	x->x_k = (x->x_max - x->x_min)/(double)(x->x_H - 1);
-
-    /*x->x_center = (x->x_gui.x_w-1)*50;
-    if(x->x_val > (x->x_gui.x_w*100 - 100))
-    {
-	x->x_pos = x->x_gui.x_w*100 - 100;
-	x->x_val = x->x_pos;
-    }
-    if(x->x_lin0_log1)
-	x->x_k = log(x->x_max/x->x_min)/(double)(x->x_gui.x_w - 1);
-    else
-	x->x_k = (x->x_max - x->x_min)/(double)(x->x_gui.x_w - 1);*/
-}
-
-void mknob_check_minmax(t_mknob *x, double min, double max)
-{
-    int H;
-	
-	if(x->x_lin0_log1)
-    {
-	if((min == 0.0)&&(max == 0.0))
-	    max = 1.0;
-	if(max > 0.0)
-	{
-	    if(min <= 0.0)
-		min = 0.01*max;
-	}
-	else
-	{
-	    if(min > 0.0)
-		max = 0.01*min;
-	}
-    }
-    x->x_min = min;
-    x->x_max = max;
-    if(x->x_min > x->x_max)                /* bugfix */
-		x->x_gui.x_isa.x_reverse = 1;
-    else
-        x->x_gui.x_isa.x_reverse = 0;
-
-    if(x->x_lin0_log1)
-	x->x_k = log(x->x_max/x->x_min)/(double)(x->x_H - 1);
-    else
-	x->x_k = (x->x_max - x->x_min)/(double)(x->x_H - 1);
-    /*if(x->x_lin0_log1)
-		x->x_k = log(x->x_max/x->x_min)/(double)(MKNOB_TANGLE - 1);
-    else
-		x->x_k = (x->x_max - x->x_min)/(double)(MKNOB_TANGLE - 1);*/
-}
-
-static void mknob_properties(t_gobj *z, t_glist *owner)
-{
-    t_mknob *x = (t_mknob *)z;
-    char buf[800];
-    t_symbol *srl[3];
-
-    iemgui_properties(&x->x_gui, srl);
-    sprintf(buf, "pdtk_iemgui_dialog %%s mknob \
-	    --------dimension(pix):-------- %d %d width: %d %d mouse: \
-	    -----------output-range:----------- %g left: %g right: %g \
-	    %d lin log %d %d empty %d \
-	    %s %s \
-	    %s %d %d \
-	    %d %d \
-	    %d %d %d\n",
-	    x->x_gui.x_w, MKNOB_MINSIZE, x->x_gui.x_h, -1,
-	    x->x_min, x->x_max, 0.0,/*no_schedule*/
-	    x->x_lin0_log1, x->x_gui.x_isa.x_loadinit, x->x_steady, -1,/*no multi, but iem-characteristic*/
-	    srl[0]->s_name, srl[1]->s_name,
-	    srl[2]->s_name, x->x_gui.x_ldx, x->x_gui.x_ldy,
-	    x->x_gui.x_fsf.x_font_style, x->x_gui.x_fontsize,
-	    0xffffff & x->x_gui.x_bcol, 0xffffff & x->x_gui.x_fcol, 0xffffff & x->x_gui.x_lcol);
-    gfxstub_new(&x->x_gui.x_obj.ob_pd, x, buf);
-}
-
-static void mknob_set(t_mknob *x, t_floatarg f)    /* bugfix */
-{
-    double g;
-
-    if(x->x_gui.x_isa.x_reverse)    /* bugfix */
-    {
-	if(f > x->x_min)
-	    f = x->x_min;
-	if(f < x->x_max)
-	    f = x->x_max;
-    }
-    else
-    {
-	if(f > x->x_max)
-	    f = x->x_max;
-	if(f < x->x_min)
-	    f = x->x_min;
-    }
-    if(x->x_lin0_log1)
-	g = log(f/x->x_min)/x->x_k;
-    else
-	g = (f - x->x_min) / x->x_k;
-    x->x_val = (int)(100.0*g + 0.49999);
-    x->x_pos = x->x_val;
-    (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
-}
-
-static void mknob_bang(t_mknob *x)
-{
-    double out;
-
-    if(x->x_lin0_log1)
-	out = x->x_min*exp(x->x_k*(double)(x->x_val)*0.01);
-    else
-	out = (double)(x->x_val)*0.01*x->x_k + x->x_min;
-    if((out < 1.0e-10)&&(out > -1.0e-10))
-	out = 0.0;
-    outlet_float(x->x_gui.x_obj.ob_outlet, out);
-    if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
-        pd_float(x->x_gui.x_snd->s_thing, out);
-}
-
-static void mknob_dialog(t_mknob *x, t_symbol *s, int argc, t_atom *argv)
-{
-    t_symbol *srl[3];
-    int w = (int)atom_getintarg(0, argc, argv);
-    int h = (int)atom_getintarg(1, argc, argv);
-    double min = (double)atom_getfloatarg(2, argc, argv);
-    double max = (double)atom_getfloatarg(3, argc, argv);
-    int lilo = (int)atom_getintarg(4, argc, argv);
-    int steady = (int)atom_getintarg(17, argc, argv);
-    int sr_flags;
-
-    if(lilo != 0) lilo = 1;
-    x->x_lin0_log1 = lilo;
-    if(steady)
-	x->x_steady = 1;
-    else
-	x->x_steady = 0;
-    sr_flags = iemgui_dialog(&x->x_gui, srl, argc, argv);
-    //x->x_gui.x_h = iemgui_clip_size(h);
-    //x->x_gui.x_w = iemgui_clip_size(w);
-    mknob_check_wh(x, w, h);
-    mknob_check_minmax(x, min, max);
-    (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_CONFIG);
-    (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_IO + sr_flags);
-    (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
-    canvas_fixlinesfor(x->x_gui.x_glist, (t_text*)x);
-}
-
-static int xm0,ym0,xm,ym;
-
-static void mknob_motion(t_mknob *x, t_floatarg dx, t_floatarg dy)
-{
-    int old = x->x_val;
-	float d=-dy;
-	
-	if (abs(dx)>abs(dy)) d=dx;
-
-    if(x->x_gui.x_fsf.x_finemoved)
-	x->x_pos += (int)d;
-    else
-	x->x_pos += 100*(int)d;
-    x->x_val = x->x_pos;
-    if(x->x_val > (100*x->x_H - 100))
-    {
-	x->x_val = 100*x->x_H - 100;
-	x->x_pos += 50;
-	x->x_pos -= x->x_pos%100;
-    }
-    if(x->x_val < 0)
-    {
-	x->x_val = 0;
-	x->x_pos -= 50;
-	x->x_pos -= x->x_pos%100;
-    }
-    if(old != x->x_val)
-    {
-	(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
-	mknob_bang(x);
-    }
-}
-
-static void mknob_motion_circular(t_mknob *x, t_floatarg dx, t_floatarg dy)
-{
-    int xc=text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist)+x->x_gui.x_w/2;
-    int yc=text_ypix(&x->x_gui.x_obj, x->x_gui.x_glist)+x->x_gui.x_w/2;
-    int old = x->x_val;
-	float alpha;
-	
-	xm+=dx;
-	ym+=dy;
-	
-	alpha=atan2(xm-xc,ym-yc)*180.0/M_PI;
-	
-	x->x_pos=(int)(31500-alpha*100.0)%36000;
-	if(x->x_pos>31500) x->x_pos=0; 
-	else if(x->x_pos>(27000-100)) x->x_pos=(27000-100); 
-
-    x->x_val=x->x_pos;
-	
-	if(old != x->x_val)
-    {
-	(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
-	mknob_bang(x);
-    }
-}
-
-static void mknob_motion_fullcircular(t_mknob *x, t_floatarg dx, t_floatarg dy)
-{
-    int xc=text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist)+x->x_gui.x_w/2;
-    int yc=text_ypix(&x->x_gui.x_obj, x->x_gui.x_glist)+x->x_gui.x_w/2;
-    int old = x->x_val;
-	float alpha;
-	
-	xm+=dx;
-	ym+=dy;
-	
-	alpha=atan2(xm-xc,ym-yc)*180.0/M_PI;
-	
-	x->x_pos=(int)(36000-alpha*100.0)%36000;
-	/*if(x->x_pos>31500) x->x_pos=0; 
-	else if(x->x_pos>(27000-100)) x->x_pos=(27000-100);*/ 
-
-	if(x->x_pos>(36000-100)) x->x_pos=(36000-100);
-    x->x_val=x->x_pos;
-	
-	if(old != x->x_val)
-    {
-	(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
-	mknob_bang(x);
-    }
-}
-
-static void mknob_click(t_mknob *x, t_floatarg xpos, t_floatarg ypos,
-			  t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
-{
-    xm0=xm=xpos;
-    ym0=ym=ypos;
-	//if(!x->x_steady)
-	//x->x_val = (int)(100.0 * (xpos - text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist)));
-    if(x->x_val > (100*x->x_H - 100))
-	x->x_val = 100*x->x_H - 100;
-    if(x->x_val < 0)
-	x->x_val = 0;
-    x->x_pos = x->x_val;
-    (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
-    mknob_bang(x);
-
-	if(x->x_gui.x_h<0)
-    	glist_grab(x->x_gui.x_glist, &x->x_gui.x_obj.te_g, 
-			(t_glistmotionfn)mknob_motion_fullcircular, 0, xpos, ypos);
-	else if(x->x_gui.x_h==0)
-    	glist_grab(x->x_gui.x_glist, &x->x_gui.x_obj.te_g,
-			(t_glistmotionfn)mknob_motion_circular, 0, xpos, ypos);
-	else 
-    	glist_grab(x->x_gui.x_glist, &x->x_gui.x_obj.te_g, 
-			(t_glistmotionfn)mknob_motion, 0, xpos, ypos);
-
-}
-
-static int mknob_newclick(t_gobj *z, struct _glist *glist,
-			    int xpix, int ypix, int shift, int alt, int dbl, int doit)
-{
-    t_mknob* x = (t_mknob *)z;
-
-    if(doit)
-    {
-	mknob_click( x, (t_floatarg)xpix, (t_floatarg)ypix, (t_floatarg)shift,
-		       0, (t_floatarg)alt);
-	if(shift)
-	    x->x_gui.x_fsf.x_finemoved = 1;
-	else
-	    x->x_gui.x_fsf.x_finemoved = 0;
-    }
-    return (1);
-}
-
-static void mknob_size(t_mknob *x, t_symbol *s, int ac, t_atom *av)
-{
-	int w=(int)atom_getintarg(0, ac, av),
-		h=x->x_gui.x_h;
-
-    if(ac > 1) h=(int)atom_getintarg(1, ac, av);
-	
-	mknob_check_wh(x, w, h);
-    iemgui_size((void *)x, &x->x_gui);
-}
-
-static void mknob_delta(t_mknob *x, t_symbol *s, int ac, t_atom *av)
-{iemgui_delta((void *)x, &x->x_gui, s, ac, av);}
-
-static void mknob_pos(t_mknob *x, t_symbol *s, int ac, t_atom *av)
-{iemgui_pos((void *)x, &x->x_gui, s, ac, av);}
-
-static void mknob_range(t_mknob *x, t_symbol *s, int ac, t_atom *av)
-{
-    mknob_check_minmax(x, (double)atom_getfloatarg(0, ac, av),
-			 (double)atom_getfloatarg(1, ac, av));
-}
-
-static void mknob_color(t_mknob *x, t_symbol *s, int ac, t_atom *av)
-{iemgui_color((void *)x, &x->x_gui, s, ac, av);}
-
-static void mknob_send(t_mknob *x, t_symbol *s)
-{iemgui_send(x, &x->x_gui, s);}
-
-static void mknob_receive(t_mknob *x, t_symbol *s)
-{iemgui_receive(x, &x->x_gui, s);}
-
-static void mknob_label(t_mknob *x, t_symbol *s)
-{iemgui_label((void *)x, &x->x_gui, s);}
-
-static void mknob_label_pos(t_mknob *x, t_symbol *s, int ac, t_atom *av)
-{iemgui_label_pos((void *)x, &x->x_gui, s, ac, av);}
-
-static void mknob_label_font(t_mknob *x, t_symbol *s, int ac, t_atom *av)
-{iemgui_label_font((void *)x, &x->x_gui, s, ac, av);}
-
-static void mknob_log(t_mknob *x)
-{
-    x->x_lin0_log1 = 1;
-    mknob_check_minmax(x, x->x_min, x->x_max);
-}
-
-static void mknob_lin(t_mknob *x)
-{
-    x->x_lin0_log1 = 0;
-    x->x_k = (x->x_max - x->x_min)/(double)(x->x_gui.x_w - 1);
-}
-
-static void mknob_init(t_mknob *x, t_floatarg f)
-{
-    x->x_gui.x_isa.x_loadinit = (f==0.0)?0:1;
-}
-
-static void mknob_steady(t_mknob *x, t_floatarg f)
-{
-    x->x_steady = (f==0.0)?0:1;
-}
-
-static void mknob_float(t_mknob *x, t_floatarg f)
-{
-    double out;
-
-    mknob_set(x, f);
-    if(x->x_lin0_log1)
-	out = x->x_min*exp(x->x_k*(double)(x->x_val)*0.01);
-    else
-	out = (double)(x->x_val)*0.01*x->x_k + x->x_min;
-    if((out < 1.0e-10)&&(out > -1.0e-10))
-	out = 0.0;
-    if(x->x_gui.x_fsf.x_put_in2out)
-    {
-	outlet_float(x->x_gui.x_obj.ob_outlet, out);
-	if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
-	    pd_float(x->x_gui.x_snd->s_thing, out);
-    }
-}
-
-static void mknob_loadbang(t_mknob *x)
-{
-    if(!sys_noloadbang && x->x_gui.x_isa.x_loadinit)
-    {
-	(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
-	mknob_bang(x);
-    }
-}
-
-/*static void mknob_list(t_mknob *x, t_symbol *s, int ac, t_atom *av)
-{
-    int l=iemgui_list((void *)x, &x->x_gui, s, ac, av);
-
-    if(l < 0)
-    {
-	if(IS_A_FLOAT(av,0))
-	    mknob_float(x, atom_getfloatarg(0, ac, av));
-    }
-    else if(l > 0)
-    {
-	(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
-	canvas_fixlinesfor(x->x_gui.x_glist, (t_text*)x);
-    }
-}*/
-
-static void *mknob_new(t_symbol *s, int argc, t_atom *argv)
-{
-    t_mknob *x = (t_mknob *)pd_new(mknob_class);
-    int bflcol[]={-262144, -1, -1};
-    //t_symbol *srl[3];
-    int w=MKNOB_DEFAULTSIZE, h=MKNOB_DEFAULTH;
-    int fs=8 ,lilo=0, ldx=-2, ldy=-6, f=0, v=0, steady=1;
-    //int  iinit=0, ifstyle=0;
-    double min=0.0, max=(double)(IEM_SL_DEFAULTSIZE-1);
-    //t_iem_init_symargs *init=(t_iem_init_symargs *)(&iinit);
-    //t_iem_fstyle_flags *fstyle=(t_iem_fstyle_flags *)(&ifstyle);
-    char str[144];
-
-    /*srl[0] = gensym("empty");
-    srl[1] = gensym("empty");
-    srl[2] = gensym("empty");*/
-
-    if(((argc == 17)||(argc == 18))&&IS_A_FLOAT(argv,0)&&IS_A_FLOAT(argv,1)
-       &&IS_A_FLOAT(argv,2)&&IS_A_FLOAT(argv,3)
-       &&IS_A_FLOAT(argv,4)&&IS_A_FLOAT(argv,5)
-       &&(IS_A_SYMBOL(argv,6)||IS_A_FLOAT(argv,6))
-       &&(IS_A_SYMBOL(argv,7)||IS_A_FLOAT(argv,7))
-       &&(IS_A_SYMBOL(argv,8)||IS_A_FLOAT(argv,8))
-       &&IS_A_FLOAT(argv,9)&&IS_A_FLOAT(argv,10)
-       &&IS_A_FLOAT(argv,11)&&IS_A_FLOAT(argv,12)&&IS_A_FLOAT(argv,13)
-       &&IS_A_FLOAT(argv,14)&&IS_A_FLOAT(argv,15)&&IS_A_FLOAT(argv,16))
-    {
-	w = (int)atom_getintarg(0, argc, argv);
-	h = (int)atom_getintarg(1, argc, argv);
-	min = (double)atom_getfloatarg(2, argc, argv);
-	max = (double)atom_getfloatarg(3, argc, argv);
-	lilo = (int)atom_getintarg(4, argc, argv);
-	iem_inttosymargs(&x->x_gui.x_isa, atom_getintarg(5, argc, argv));
-	iemgui_new_getnames(&x->x_gui, 6, argv);
-	ldx = (int)atom_getintarg(9, argc, argv);
-	ldy = (int)atom_getintarg(10, argc, argv);
-	iem_inttofstyle(&x->x_gui.x_fsf, atom_getintarg(11, argc, argv));
-	fs = (int)atom_getintarg(12, argc, argv);
-	bflcol[0] = (int)atom_getintarg(13, argc, argv);
-	bflcol[1] = (int)atom_getintarg(14, argc, argv);
-	bflcol[2] = (int)atom_getintarg(15, argc, argv);
-	v = (int)atom_getintarg(16, argc, argv);
-	/*iinit = (int)atom_getintarg(5, argc, argv);
-	if(IS_A_SYMBOL(argv,6))
-	    srl[0] = atom_getsymbolarg(6, argc, argv);
-	else if(IS_A_FLOAT(argv,6))
-	{
-	    sprintf(str, "%d", (int)atom_getintarg(6, argc, argv));
-	    srl[0] = gensym(str);
-	}
-	if(IS_A_SYMBOL(argv,7))
-	    srl[1] = atom_getsymbolarg(7, argc, argv);
-	else if(IS_A_FLOAT(argv,7))
-	{
-	    sprintf(str, "%d", (int)atom_getintarg(7, argc, argv));
-	    srl[1] = gensym(str);
-	}
-	if(IS_A_SYMBOL(argv,8))
-	    srl[2] = atom_getsymbolarg(8, argc, argv);
-	else if(IS_A_FLOAT(argv,8))
-	{
-	    sprintf(str, "%d", (int)atom_getintarg(8, argc, argv));
-	    srl[2] = gensym(str);
-	}*/
-	//ifstyle = (int)atom_getintarg(11, argc, argv);
-    }
-    else iemgui_new_getnames(&x->x_gui, 6, 0);
-
-    if((argc == 18)&&IS_A_FLOAT(argv,17))
-	steady = (int)atom_getintarg(17, argc, argv);
-
-    /*iinit &= IEM_INIT_ARGS_ALL;
-    ifstyle &= IEM_FSTYLE_FLAGS_ALL;
-    fstyle->x_snd_able = 1;
-    fstyle->x_rcv_able = 1;*/
-    x->x_gui.x_draw = (t_iemfunptr)mknob_draw;
-    x->x_gui.x_fsf.x_snd_able = 1;
-    x->x_gui.x_fsf.x_rcv_able = 1;
-    x->x_gui.x_glist = (t_glist *)canvas_getcurrent();
-    //x->x_gui.x_isa = *init;
-    if(x->x_gui.x_isa.x_loadinit)
-	x->x_val = v;
-    else
-	x->x_val = 0;
-    x->x_pos = x->x_val;
-    if(lilo != 0) lilo = 1;
-    x->x_lin0_log1 = lilo;
-    if(steady != 0) steady = 1;
-    x->x_steady = steady;
-	if(!strcmp(x->x_gui.x_snd->s_name, "empty")) x->x_gui.x_fsf.x_snd_able = 0;
-    if(!strcmp(x->x_gui.x_rcv->s_name, "empty")) x->x_gui.x_fsf.x_rcv_able = 0;
-    //if(!strcmp(srl[0]->s_name, "empty")) fstyle->x_snd_able = 0;
-    //if(!strcmp(srl[1]->s_name, "empty")) fstyle->x_rcv_able = 0;
-    //x->x_gui.x_unique_num = 0;
-    if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica");
-    else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times");
-    else { x->x_gui.x_fsf.x_font_style = 0;
-    /*if(fstyle->x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica");
-    else if(fstyle->x_font_style == 2) strcpy(x->x_gui.x_font, "times");
-    else { fstyle->x_font_style = 0;*/
-	strcpy(x->x_gui.x_font, "courier"); }
-    //x->x_gui.x_fsf = *fstyle;
-    //iemgui_first_dollararg2sym(&x->x_gui, srl);
-    //if(x->x_gui.x_fsf.x_rcv_able) pd_bind(&x->x_gui.x_obj.ob_pd, srl[1]);
-    /*x->x_gui.x_snd = srl[0];
-    x->x_gui.x_rcv = srl[1];
-    x->x_gui.x_lab = srl[2];*/
-    if(x->x_gui.x_fsf.x_rcv_able) pd_bind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
-    x->x_gui.x_ldx = ldx;
-    x->x_gui.x_ldy = ldy;
-    if(fs < 4)
-	fs = 4;
-    x->x_gui.x_fontsize = fs;
-    //x->x_gui.x_h = iemgui_clip_size(h);
-    //x->x_gui.x_w = iemgui_clip_size(w);
-    mknob_check_wh(x, w, h);
-    //mknob_check_width(x, w);
-    mknob_check_minmax(x, min, max);
-    iemgui_all_colfromload(&x->x_gui, bflcol);
-    x->x_thick = 0;
-    iemgui_verify_snd_ne_rcv(&x->x_gui);
-    outlet_new(&x->x_gui.x_obj, &s_float);
-    return (x);
-}
-
-static void mknob_free(t_mknob *x)
-{
-    /*if(x->x_gui.x_fsf.x_selected)
-	pd_unbind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);*/
-    if(x->x_gui.x_fsf.x_rcv_able)
-	pd_unbind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
-    gfxstub_deleteforkey(x);
-}
-
-extern void canvas_iemguis(t_glist *gl, t_symbol *guiobjname);
-
-void canvas_mknob(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
-{
-    canvas_iemguis(gl, gensym("mknob"));
-}
-
-void mknob_setup(void)
-{
-    mknob_class = class_new(gensym("mknob"), (t_newmethod)mknob_new,
-			      (t_method)mknob_free, sizeof(t_mknob), 0, A_GIMME, 0);
-#ifndef GGEE_mknob_COMPATIBLE
-//    class_addcreator((t_newmethod)mknob_new, gensym("mknob"), A_GIMME, 0);
-#endif
-    class_addbang(mknob_class,mknob_bang);
-    class_addfloat(mknob_class,mknob_float);
-    //class_addlist(mknob_class, mknob_list);
-    class_addmethod(mknob_class, (t_method)mknob_click, gensym("click"),
-		    A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
-    class_addmethod(mknob_class, (t_method)mknob_motion, gensym("motion"),
-		    A_FLOAT, A_FLOAT, 0);
-    class_addmethod(mknob_class, (t_method)mknob_dialog, gensym("dialog"), A_GIMME, 0);
-    class_addmethod(mknob_class, (t_method)mknob_loadbang, gensym("loadbang"), 0);
-    class_addmethod(mknob_class, (t_method)mknob_set, gensym("set"), A_FLOAT, 0);
-    class_addmethod(mknob_class, (t_method)mknob_size, gensym("size"), A_GIMME, 0);
-    class_addmethod(mknob_class, (t_method)mknob_delta, gensym("delta"), A_GIMME, 0);
-    class_addmethod(mknob_class, (t_method)mknob_pos, gensym("pos"), A_GIMME, 0);
-    class_addmethod(mknob_class, (t_method)mknob_range, gensym("range"), A_GIMME, 0);
-    class_addmethod(mknob_class, (t_method)mknob_color, gensym("color"), A_GIMME, 0);
-    class_addmethod(mknob_class, (t_method)mknob_send, gensym("send"), A_DEFSYM, 0);
-    class_addmethod(mknob_class, (t_method)mknob_receive, gensym("receive"), A_DEFSYM, 0);
-    class_addmethod(mknob_class, (t_method)mknob_label, gensym("label"), A_DEFSYM, 0);
-    class_addmethod(mknob_class, (t_method)mknob_label_pos, gensym("label_pos"), A_GIMME, 0);
-    class_addmethod(mknob_class, (t_method)mknob_label_font, gensym("label_font"), A_GIMME, 0);
-    class_addmethod(mknob_class, (t_method)mknob_log, gensym("log"), 0);
-    class_addmethod(mknob_class, (t_method)mknob_lin, gensym("lin"), 0);
-    class_addmethod(mknob_class, (t_method)mknob_init, gensym("init"), A_FLOAT, 0);
-    class_addmethod(mknob_class, (t_method)mknob_steady, gensym("steady"), A_FLOAT, 0);
-    /*if(!iemgui_key_sym)
-	iemgui_key_sym = gensym("#keyname");*/
-    mknob_widgetbehavior.w_getrectfn =    mknob_getrect;
-    mknob_widgetbehavior.w_displacefn =   iemgui_displace;
-    mknob_widgetbehavior.w_selectfn =     iemgui_select;
-    mknob_widgetbehavior.w_activatefn =   NULL;
-    mknob_widgetbehavior.w_deletefn =     iemgui_delete;
-    mknob_widgetbehavior.w_visfn =        iemgui_vis;
-    mknob_widgetbehavior.w_clickfn =      mknob_newclick;
-    //mknob_widgetbehavior.w_propertiesfn = mknob_properties;
-    //mknob_widgetbehavior.w_savefn =       mknob_save;
-    class_setwidget(mknob_class, &mknob_widgetbehavior);
-
-    class_setsavefn(mknob_class, mknob_save);
-    class_setpropertiesfn(mknob_class, mknob_properties);
-    class_addmethod(canvas_class, (t_method)canvas_mknob, gensym("mknob"),
-		    A_GIMME, A_NULL);
-}
+/* Copyright (c) 1997-1999 Miller Puckette.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* mknob.c written by Antoine Rousseau from g_vslider.c.*/
+/* g_7_guis.c written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */
+/* thanks to Miller Puckette, Guenther Geiger and Krzystof Czaja */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include "m_pd.h"
+#include "g_canvas.h"
+
+#include "g_all_guis.h"
+#include <math.h>
+
+#ifdef _WIN32
+#include <io.h>
+#include <Windows.h>
+#else
+#include <unistd.h>
+#include <dlfcn.h>
+#endif
+
+#define MKNOB_TANGLE 100
+#define MKNOB_DEFAULTH 100
+#define MKNOB_DEFAULTSIZE 25
+#define MKNOB_MINSIZE 12
+#define MKNOB_THICK 3
+/* ------------ mknob  ----------------------- */
+typedef struct _mknob
+{
+    t_iemgui x_gui;
+    int      x_prev_h;
+    int      x_prev_w;
+    int      x_pos;
+    int      x_val;
+    int      x_prev_val;
+    int      x_center;
+    int      x_thick;
+    int      x_lin0_log1;
+    int      x_steady;
+    double   x_min;
+    double   x_max;
+    int   	 x_H;
+    int   	 x_prev_H;
+    double   x_k;
+    int      x_reverse;
+} t_mknob;
+
+t_widgetbehavior mknob_widgetbehavior;
+static t_class *mknob_class;
+
+static int compat = 0; // current running pd version < 0.47
+
+/* widget helper functions */
+static void mknob_update_knob(t_mknob *x, t_glist *glist)
+{
+	  
+    /* only draw if something changed */
+    /*if(!(x->x_val != x->x_prev_val || x->x_gui.x_h != x->x_prev_h ||
+       x->x_gui.x_w != x->x_prev_w || x->x_H != x->x_prev_H))
+        return;*/ /* actually seems not needed since value changed is already done ;
+	             and moving the knob was bugged because of that test.
+	          */
+
+    x->x_prev_val = x->x_val;
+    x->x_prev_h = x->x_gui.x_h;
+    x->x_prev_w = x->x_gui.x_w;
+    x->x_prev_H = x->x_H;
+    t_canvas *canvas=glist_getcanvas(glist);
+//	float val=(x->x_val + 50.0)/100.0/MKNOB_TANGLE;
+    float val=(x->x_val + 50.0)/100.0/x->x_H;
+    float 	angle,
+            radius=x->x_gui.x_w/2.0,
+            miniradius=MKNOB_THICK;
+    int x0,y0,x1,y1,xc,yc,xp,yp,xpc,ypc;
+    x0=text_xpix(&x->x_gui.x_obj, glist);
+    y0=text_ypix(&x->x_gui.x_obj, glist);
+    x1=x0+x->x_gui.x_w;
+    y1=y0+x->x_gui.x_w;
+    xc=(x0+x1)/2;
+    yc=(y0+y1)/2;
+
+    if(x->x_gui.x_h<0)
+        angle=val*(M_PI*2)+M_PI/2.0;
+    else
+        angle=val*(M_PI*1.5)+3.0*M_PI/4.0;
+
+    xp=xc+radius*cos(angle);
+    yp=yc+radius*sin(angle);
+    xpc=miniradius*cos(angle-M_PI/2);
+    ypc=miniradius*sin(angle-M_PI/2);
+
+    sys_vgui(".x%lx.c coords %xKNOB %d %d %d %d %d %d\n",
+             canvas,x,xp,yp,xc+xpc,yc+ypc,xc-xpc,yc-ypc);
+}
+
+static void mknob_draw_update(t_mknob *x, t_glist *glist)
+{
+    if (glist_isvisible(glist))
+    {
+        mknob_update_knob(x,glist);
+
+        /*if(x->x_val == x->x_center)
+        {
+            if(!x->x_thick)
+            {
+        	sys_vgui(".x%lx.c itemconfigure %xKNOB -width 7\n", canvas, x);
+        	x->x_thick = 1;
+            }
+        }
+        else
+        {
+            if(x->x_thick)
+            {
+        	sys_vgui(".x%lx.c itemconfigure %xKNOB -width 3\n", canvas, x);
+        	x->x_thick = 0;
+            }
+        }*/
+    }
+}
+
+static void mknob_draw_new(t_mknob *x, t_glist *glist)
+{
+    int xpos=text_xpix(&x->x_gui.x_obj, glist);
+    int ypos=text_ypix(&x->x_gui.x_obj, glist);
+    int r = xpos + (x->x_val + 50)/100;
+    int xc=xpos+x->x_gui.x_w/2;
+    int yc=ypos+x->x_gui.x_w/2;
+    t_canvas *canvas=glist_getcanvas(glist);
+
+    if(compat) {
+        sys_vgui(".x%lx.c create oval %d %d %d %d -fill #%6.6x -tags %xBASE\n",
+                 canvas,xpos,ypos,xpos + x->x_gui.x_w, ypos + x->x_gui.x_w,
+                 x->x_gui.x_bcol,x);
+        sys_vgui(".x%lx.c create polygon %d %d %d %d %d %d -fill #%6.6x -tags %xKNOB\n",
+                 glist_getcanvas(glist),
+                 xc,ypos,xc-4,yc,xc+4,yc,x->x_gui.x_fcol,x);
+        mknob_update_knob(x,glist);
+        sys_vgui(".x%lx.c create text %d %d -text {%s} -anchor w \
+	         -font {{%s} -%d %s} -fill #%6.6x -tags %xLABEL\n",
+                 canvas, xpos+x->x_gui.x_ldx,
+                 ypos+x->x_gui.x_ldy,
+                 strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"",
+                 x->x_gui.x_font, x->x_gui.x_fontsize, sys_fontweight, x->x_gui.x_lcol, x);
+    } else {
+        sys_vgui(".x%lx.c create oval %d %d %d %d -fill #%06x -tags %xBASE\n",
+                 canvas,xpos,ypos,xpos + x->x_gui.x_w, ypos + x->x_gui.x_w,
+                 x->x_gui.x_bcol,x);
+        sys_vgui(".x%lx.c create polygon %d %d %d %d %d %d -fill #%06x -tags %xKNOB\n",
+                 glist_getcanvas(glist),
+                 xc,ypos,xc-4,yc,xc+4,yc,x->x_gui.x_fcol,x);
+        mknob_update_knob(x,glist);
+        sys_vgui(".x%lx.c create text %d %d -text {%s} -anchor w \
+	     -font {{%s} -%d %s} -fill #%06x -tags %xLABEL\n",
+             canvas, xpos+x->x_gui.x_ldx,
+             ypos+x->x_gui.x_ldy,
+             strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"",
+             x->x_gui.x_font, x->x_gui.x_fontsize, sys_fontweight, x->x_gui.x_lcol, x);
+    }
+    /*if(!x->x_gui.x_fsf.x_snd_able)
+        sys_vgui(".x%lx.c create rectangle %d %d %d %d -tags %xOUT%d\n",
+         canvas, xpos+ x->x_gui.x_w/2-3, ypos + x->x_gui.x_w-1,
+         xpos+ x->x_gui.x_w/2+4, ypos + x->x_gui.x_w, x, 0);
+    if(!x->x_gui.x_fsf.x_rcv_able)
+    sys_vgui(".x%lx.c create rectangle %d %d %d %d -tags %xIN%d\n",
+         canvas, xpos+ x->x_gui.x_w/2-3, ypos,
+         xpos+ x->x_gui.x_w/2+4, ypos+1, x, 0);*/
+}
+
+static void mknob_draw_move(t_mknob *x, t_glist *glist)
+{
+    int xpos=text_xpix(&x->x_gui.x_obj, glist);
+    int ypos=text_ypix(&x->x_gui.x_obj, glist);
+    int r = xpos + (x->x_val + 50)/100;
+    t_canvas *canvas=glist_getcanvas(glist);
+
+    sys_vgui(".x%lx.c coords %xBASE %d %d %d %d\n",
+             canvas, x,
+             xpos, ypos,
+             xpos + x->x_gui.x_w, ypos + x->x_gui.x_w);
+    mknob_update_knob(x,glist);
+    sys_vgui(".x%lx.c coords %xLABEL %d %d\n",
+             canvas, x, xpos+x->x_gui.x_ldx, ypos+x->x_gui.x_ldy);
+    /*if(!x->x_gui.x_fsf.x_snd_able)
+        sys_vgui(".x%lx.c coords %xOUT%d %d %d %d %d\n",
+         canvas, x, 0,
+         xpos+ x->x_gui.x_w/2-3, ypos + x->x_gui.x_w-1,
+         xpos+ x->x_gui.x_w/2+4, ypos + x->x_gui.x_w);
+    if(!x->x_gui.x_fsf.x_rcv_able)
+    sys_vgui(".x%lx.c coords %xIN%d %d %d %d %d\n",
+         canvas, x, 0,
+         xpos+ x->x_gui.x_w/2-3, ypos,
+         xpos+ x->x_gui.x_w/2+4, ypos+1);*/
+}
+
+static void mknob_draw_erase(t_mknob *x,t_glist *glist)
+{
+    t_canvas *canvas=glist_getcanvas(glist);
+
+    sys_vgui(".x%lx.c delete %xBASE\n", canvas, x);
+    sys_vgui(".x%lx.c delete %xKNOB\n", canvas, x);
+    sys_vgui(".x%lx.c delete %xLABEL\n", canvas, x);
+    /*if(!x->x_gui.x_fsf.x_snd_able)
+        sys_vgui(".x%lx.c delete %xOUT%d\n", canvas, x, 0);
+    if(!x->x_gui.x_fsf.x_rcv_able)
+        sys_vgui(".x%lx.c delete %xIN%d\n", canvas, x, 0);*/
+}
+
+static void mknob_draw_config(t_mknob *x,t_glist *glist)
+{
+    t_canvas *canvas=glist_getcanvas(glist);
+
+    if(compat) {
+        sys_vgui(".x%lx.c itemconfigure %xLABEL -font {{%s} -%d %s} -fill #%6.6x -text {%s} \n",
+                 canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize, sys_fontweight,
+                 x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol,
+                 strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"");
+        sys_vgui(".x%lx.c itemconfigure %xKNOB -fill #%6.6x\n", canvas, x, x->x_gui.x_fcol);
+        sys_vgui(".x%lx.c itemconfigure %xBASE -fill #%6.6x\n", canvas, x, x->x_gui.x_bcol);
+    } else {
+        sys_vgui(".x%lx.c itemconfigure %xLABEL -font {{%s} -%d %s} -fill #%06x -text {%s} \n",
+                 canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize, sys_fontweight,
+                 x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol,
+                 strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"");
+        sys_vgui(".x%lx.c itemconfigure %xKNOB -fill #%06x\n", canvas, x, x->x_gui.x_fcol);
+        sys_vgui(".x%lx.c itemconfigure %xBASE -fill #%06x\n", canvas, x, x->x_gui.x_bcol);
+    }
+}
+
+/*static void mknob_draw_io(t_mknob *x,t_glist *glist, int old_snd_rcv_flags)
+{
+    int xpos=text_xpix(&x->x_gui.x_obj, glist);
+    int ypos=text_ypix(&x->x_gui.x_obj, glist);
+    t_canvas *canvas=glist_getcanvas(glist);*/
+
+    /*if((old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && !x->x_gui.x_fsf.x_snd_able)
+        sys_vgui(".x%lx.c create rectangle %d %d %d %d -tags %xOUT%d\n",
+         canvas, xpos+ x->x_gui.x_w/2-3, ypos + x->x_gui.x_w-1,
+         xpos+ x->x_gui.x_w/2+4, ypos + x->x_gui.x_w, x, 0);
+    if(!(old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && x->x_gui.x_fsf.x_snd_able)
+        sys_vgui(".x%lx.c delete %xOUT%d\n", canvas, x, 0);
+    if((old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && !x->x_gui.x_fsf.x_rcv_able)
+        sys_vgui(".x%lx.c create rectangle %d %d %d %d -tags %xIN%d\n",
+         canvas, xpos+ x->x_gui.x_w/2-3, ypos,
+         xpos+ x->x_gui.x_w/2+4, ypos+1, x, 0);
+    if(!(old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && x->x_gui.x_fsf.x_rcv_able)
+    sys_vgui(".x%lx.c delete %xIN%d\n", canvas, x, 0);*/
+//}
+
+static void mknob_draw_select(t_mknob *x,t_glist *glist)
+{
+    t_canvas *canvas=glist_getcanvas(glist);
+
+    if(compat) {
+        if(x->x_gui.x_fsf.x_selected)
+        {
+            //pd_bind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);
+            sys_vgui(".x%lx.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
+            sys_vgui(".x%lx.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
+        }
+        else
+        {
+            //pd_unbind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);
+            sys_vgui(".x%lx.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_NORMAL);
+            sys_vgui(".x%lx.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, x->x_gui.x_lcol);
+        }
+    } else  {
+        if(x->x_gui.x_fsf.x_selected)
+        {
+            //pd_bind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);
+            sys_vgui(".x%lx.c itemconfigure %xBASE -outline #%06x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
+            sys_vgui(".x%lx.c itemconfigure %xLABEL -fill #%06x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
+        }
+        else
+        {
+            //pd_unbind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);
+            sys_vgui(".x%lx.c itemconfigure %xBASE -outline #%06x\n", canvas, x, IEM_GUI_COLOR_NORMAL);
+            sys_vgui(".x%lx.c itemconfigure %xLABEL -fill #%06x\n", canvas, x, x->x_gui.x_lcol);
+        }
+    }
+}
+
+void mknob_draw(t_mknob *x, t_glist *glist, int mode)
+{
+    if(mode == IEM_GUI_DRAW_MODE_UPDATE)
+        mknob_draw_update(x, glist);
+    else if(mode == IEM_GUI_DRAW_MODE_MOVE)
+        mknob_draw_move(x, glist);
+    else if(mode == IEM_GUI_DRAW_MODE_NEW)
+        mknob_draw_new(x, glist);
+    else if(mode == IEM_GUI_DRAW_MODE_SELECT)
+        mknob_draw_select(x, glist);
+    else if(mode == IEM_GUI_DRAW_MODE_ERASE)
+        mknob_draw_erase(x, glist);
+    else if(mode == IEM_GUI_DRAW_MODE_CONFIG)
+        mknob_draw_config(x, glist);
+    /*else if(mode >= IEM_GUI_DRAW_MODE_IO)
+    mknob_draw_io(x, glist, mode - IEM_GUI_DRAW_MODE_IO);*/
+}
+
+/* ------------------------ mknob widgetbehaviour----------------------------- */
+
+
+static void mknob_getrect(t_gobj *z, t_glist *glist,
+                          int *xp1, int *yp1, int *xp2, int *yp2)
+{
+    t_mknob *x = (t_mknob *)z;
+
+    *xp1 = text_xpix(&x->x_gui.x_obj, glist);
+    *yp1 = text_ypix(&x->x_gui.x_obj, glist);
+    *xp2 = *xp1 + x->x_gui.x_w;
+    *yp2 = *yp1 + x->x_gui.x_w;
+}
+
+static void mknob_save(t_gobj *z, t_binbuf *b)
+{
+    t_mknob *x = (t_mknob *)z;
+    int bflcol_compat[3];
+    t_symbol *bflcol[3];
+    t_symbol *srl[3];
+
+    if(compat) {
+        ((void (*)(t_iemgui *iemgui, t_symbol **srl, int* bflcol))&iemgui_save)(&x->x_gui, srl, bflcol_compat);
+        binbuf_addv(b, "ssiisiiffiisssiiiiiiiii", gensym("#X"),gensym("obj"),
+            (t_int)x->x_gui.x_obj.te_xpix, (t_int)x->x_gui.x_obj.te_ypix,
+            atom_getsymbol(binbuf_getvec(x->x_gui.x_obj.te_binbuf)),
+            x->x_gui.x_w, x->x_gui.x_h,
+            (float)x->x_min, (float)x->x_max,
+            x->x_lin0_log1, iem_symargstoint(&x->x_gui.x_isa),
+            srl[0], srl[1], srl[2],
+            x->x_gui.x_ldx, x->x_gui.x_ldy,
+            iem_fstyletoint(&x->x_gui.x_fsf), x->x_gui.x_fontsize,
+            bflcol_compat[0], bflcol_compat[1], bflcol_compat[2],
+            x->x_val, x->x_steady);
+    }
+    else {
+        ((void (*)(t_iemgui *iemgui, t_symbol **srl, t_symbol **bflcol))&iemgui_save)(&x->x_gui, srl, bflcol);
+        binbuf_addv(b, "ssiisiiffiisssiiiisssii", gensym("#X"),gensym("obj"),
+            (t_int)x->x_gui.x_obj.te_xpix, (t_int)x->x_gui.x_obj.te_ypix,
+            atom_getsymbol(binbuf_getvec(x->x_gui.x_obj.te_binbuf)),
+            x->x_gui.x_w, x->x_gui.x_h,
+            (float)x->x_min, (float)x->x_max,
+            x->x_lin0_log1, iem_symargstoint(&x->x_gui.x_isa),
+            srl[0], srl[1], srl[2],
+            x->x_gui.x_ldx, x->x_gui.x_ldy,
+            iem_fstyletoint(&x->x_gui.x_fsf), x->x_gui.x_fontsize,
+            bflcol[0], bflcol[1], bflcol[2],
+            x->x_val, x->x_steady);
+        
+    }
+    binbuf_addv(b, ";");
+}
+
+void mknob_check_wh(t_mknob *x, int w, int h)
+{
+    int H;
+
+    if(w < MKNOB_MINSIZE) w = MKNOB_MINSIZE;
+    x->x_gui.x_w = w;
+
+    if(h < -1) h=-1;
+    if((h>0)&&(h<20)) h=20;
+    x->x_gui.x_h = h;
+
+    H=x->x_gui.x_h;
+    if(H<0) H=360;
+    if(H==0) H=270;
+    x->x_H=H;
+
+    if(x->x_lin0_log1)
+        x->x_k = log(x->x_max/x->x_min)/(double)(x->x_H - 1);
+    else
+        x->x_k = (x->x_max - x->x_min)/(double)(x->x_H - 1);
+
+    /*x->x_center = (x->x_gui.x_w-1)*50;
+    if(x->x_val > (x->x_gui.x_w*100 - 100))
+    {
+    x->x_pos = x->x_gui.x_w*100 - 100;
+    x->x_val = x->x_pos;
+    }
+    if(x->x_lin0_log1)
+    x->x_k = log(x->x_max/x->x_min)/(double)(x->x_gui.x_w - 1);
+    else
+    x->x_k = (x->x_max - x->x_min)/(double)(x->x_gui.x_w - 1);*/
+}
+
+void mknob_check_minmax(t_mknob *x, double min, double max)
+{
+    int H;
+
+    if(x->x_lin0_log1)
+    {
+        if((min == 0.0)&&(max == 0.0))
+            max = 1.0;
+        if(max > 0.0)
+        {
+            if(min <= 0.0)
+                min = 0.01*max;
+        }
+        else
+        {
+            if(min > 0.0)
+                max = 0.01*min;
+        }
+    }
+    x->x_min = min;
+    x->x_max = max;
+    if(x->x_min > x->x_max)                /* bugfix */
+        x->x_reverse = 1;
+    else
+        x->x_reverse = 0;
+
+    if(x->x_lin0_log1)
+        x->x_k = log(x->x_max/x->x_min)/(double)(x->x_H - 1);
+    else
+        x->x_k = (x->x_max - x->x_min)/(double)(x->x_H - 1);
+    /*if(x->x_lin0_log1)
+    	x->x_k = log(x->x_max/x->x_min)/(double)(MKNOB_TANGLE - 1);
+    else
+    	x->x_k = (x->x_max - x->x_min)/(double)(MKNOB_TANGLE - 1);*/
+}
+
+static void mknob_properties(t_gobj *z, t_glist *owner)
+{
+    t_mknob *x = (t_mknob *)z;
+    char buf[800];
+    t_symbol *srl[3];
+
+    iemgui_properties(&x->x_gui, srl);
+    if(compat) sprintf(buf, "pdtk_iemgui_dialog %%s mknob \
+	    --------dimension(pix):-------- %d %d width: %d %d mouse: \
+	    -----------output-range:----------- %g left: %g right: %g \
+	    %d lin log %d %d empty %d \
+	    %s %s \
+	    %s %d %d \
+	    %d %d \
+	    %d %d %d\n",
+            x->x_gui.x_w, MKNOB_MINSIZE, x->x_gui.x_h, -1,
+            x->x_min, x->x_max, 0.0,/*no_schedule*/
+            x->x_lin0_log1, x->x_gui.x_isa.x_loadinit, x->x_steady, -1,/*no multi, but iem-characteristic*/
+            srl[0]->s_name, srl[1]->s_name,
+            srl[2]->s_name, x->x_gui.x_ldx, x->x_gui.x_ldy,
+            x->x_gui.x_fsf.x_font_style, x->x_gui.x_fontsize,
+            0xffffff & x->x_gui.x_bcol, 0xffffff & x->x_gui.x_fcol, 0xffffff & x->x_gui.x_lcol);
+    else sprintf(buf, "pdtk_iemgui_dialog %%s mknob \
+	    --------dimension(pix):-------- %d %d width: %d %d mouse: \
+	    -----------output-range:----------- %g left: %g right: %g \
+	    %d lin log %d %d empty %d \
+	    %s %s \
+	    %s %d %d \
+	    %d %d \
+	   #%06x #%06x #%06x\n",
+            x->x_gui.x_w, MKNOB_MINSIZE, x->x_gui.x_h, -1,
+            x->x_min, x->x_max, 0.0,/*no_schedule*/
+            x->x_lin0_log1, x->x_gui.x_isa.x_loadinit, x->x_steady, -1,/*no multi, but iem-characteristic*/
+            srl[0]->s_name, srl[1]->s_name,
+            srl[2]->s_name, x->x_gui.x_ldx, x->x_gui.x_ldy,
+            x->x_gui.x_fsf.x_font_style, x->x_gui.x_fontsize,
+            0xffffff & x->x_gui.x_bcol, 0xffffff & x->x_gui.x_fcol, 0xffffff & x->x_gui.x_lcol);
+    gfxstub_new(&x->x_gui.x_obj.ob_pd, x, buf);
+}
+
+static void mknob_set(t_mknob *x, t_floatarg f)    /* bugfix */
+{
+    double g;
+
+    if(x->x_reverse)    /* bugfix */
+    {
+        if(f > x->x_min)
+            f = x->x_min;
+        if(f < x->x_max)
+            f = x->x_max;
+    }
+    else
+    {
+        if(f > x->x_max)
+            f = x->x_max;
+        if(f < x->x_min)
+            f = x->x_min;
+    }
+    if(x->x_lin0_log1)
+        g = log(f/x->x_min)/x->x_k;
+    else
+        g = (f - x->x_min) / x->x_k;
+    x->x_val = (int)(100.0*g + 0.49999);
+    x->x_pos = x->x_val;
+    (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+}
+
+static void mknob_bang(t_mknob *x)
+{
+    double out;
+
+    if(x->x_lin0_log1)
+        out = x->x_min*exp(x->x_k*(double)(x->x_val)*0.01);
+    else
+        out = (double)(x->x_val)*0.01*x->x_k + x->x_min;
+    if((out < 1.0e-10)&&(out > -1.0e-10))
+        out = 0.0;
+    outlet_float(x->x_gui.x_obj.ob_outlet, out);
+    if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
+        pd_float(x->x_gui.x_snd->s_thing, out);
+}
+
+static void mknob_dialog(t_mknob *x, t_symbol *s, int argc, t_atom *argv)
+{
+    t_symbol *srl[3];
+    int w = (int)atom_getintarg(0, argc, argv);
+    int h = (int)atom_getintarg(1, argc, argv);
+    double min = (double)atom_getfloatarg(2, argc, argv);
+    double max = (double)atom_getfloatarg(3, argc, argv);
+    int lilo = (int)atom_getintarg(4, argc, argv);
+    int steady = (int)atom_getintarg(17, argc, argv);
+    int sr_flags;
+
+    if(lilo != 0) lilo = 1;
+    x->x_lin0_log1 = lilo;
+    if(steady)
+        x->x_steady = 1;
+    else
+        x->x_steady = 0;
+    sr_flags = iemgui_dialog(&x->x_gui, srl, argc, argv);
+    //x->x_gui.x_h = iemgui_clip_size(h);
+    //x->x_gui.x_w = iemgui_clip_size(w);
+    mknob_check_wh(x, w, h);
+    mknob_check_minmax(x, min, max);
+    (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_CONFIG);
+    (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_IO + sr_flags);
+    (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
+    canvas_fixlinesfor(x->x_gui.x_glist, (t_text *)x);
+}
+
+static int xm0,ym0,xm,ym;
+
+static void mknob_motion(t_mknob *x, t_floatarg dx, t_floatarg dy)
+{
+    int old = x->x_val;
+    float d=-dy;
+
+    if (abs(dx)>abs(dy)) d=dx;
+
+    if(x->x_gui.x_fsf.x_finemoved)
+        x->x_pos += (int)d;
+    else
+        x->x_pos += 100*(int)d;
+    x->x_val = x->x_pos;
+    if(x->x_val > (100*x->x_H - 100))
+    {
+        x->x_val = 100*x->x_H - 100;
+        x->x_pos += 50;
+        x->x_pos -= x->x_pos%100;
+    }
+    if(x->x_val < 0)
+    {
+        x->x_val = 0;
+        x->x_pos -= 50;
+        x->x_pos -= x->x_pos%100;
+    }
+    if(old != x->x_val)
+    {
+        (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+        mknob_bang(x);
+    }
+}
+
+static void mknob_motion_circular(t_mknob *x, t_floatarg dx, t_floatarg dy)
+{
+    int xc=text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist)+x->x_gui.x_w/2;
+    int yc=text_ypix(&x->x_gui.x_obj, x->x_gui.x_glist)+x->x_gui.x_w/2;
+    int old = x->x_val;
+    float alpha;
+
+    xm+=dx;
+    ym+=dy;
+
+    alpha=atan2(xm-xc,ym-yc)*180.0/M_PI;
+
+    x->x_pos=(int)(31500-alpha*100.0)%36000;
+    if(x->x_pos>31500) x->x_pos=0;
+    else if(x->x_pos>(27000-100)) x->x_pos=(27000-100);
+
+    x->x_val=x->x_pos;
+
+    if(old != x->x_val)
+    {
+        (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+        mknob_bang(x);
+    }
+}
+
+static void mknob_motion_fullcircular(t_mknob *x, t_floatarg dx, t_floatarg dy)
+{
+    int xc=text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist)+x->x_gui.x_w/2;
+    int yc=text_ypix(&x->x_gui.x_obj, x->x_gui.x_glist)+x->x_gui.x_w/2;
+    int old = x->x_val;
+    float alpha;
+
+    xm+=dx;
+    ym+=dy;
+
+    alpha=atan2(xm-xc,ym-yc)*180.0/M_PI;
+
+    x->x_pos=(int)(36000-alpha*100.0)%36000;
+    /*if(x->x_pos>31500) x->x_pos=0;
+    else if(x->x_pos>(27000-100)) x->x_pos=(27000-100);*/
+
+    if(x->x_pos>(36000-100)) x->x_pos=(36000-100);
+    x->x_val=x->x_pos;
+
+    if(old != x->x_val)
+    {
+        (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+        mknob_bang(x);
+    }
+}
+
+static void mknob_click(t_mknob *x, t_floatarg xpos, t_floatarg ypos,
+                        t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
+{
+    xm0=xm=xpos;
+    ym0=ym=ypos;
+    //if(!x->x_steady)
+    //x->x_val = (int)(100.0 * (xpos - text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist)));
+    if(x->x_val > (100*x->x_H - 100))
+        x->x_val = 100*x->x_H - 100;
+    if(x->x_val < 0)
+        x->x_val = 0;
+    x->x_pos = x->x_val;
+    (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+    mknob_bang(x);
+
+    if(x->x_gui.x_h<0)
+        glist_grab(x->x_gui.x_glist, &x->x_gui.x_obj.te_g,
+                   (t_glistmotionfn)mknob_motion_fullcircular, 0, xpos, ypos);
+    else if(x->x_gui.x_h==0)
+        glist_grab(x->x_gui.x_glist, &x->x_gui.x_obj.te_g,
+                   (t_glistmotionfn)mknob_motion_circular, 0, xpos, ypos);
+    else
+        glist_grab(x->x_gui.x_glist, &x->x_gui.x_obj.te_g,
+                   (t_glistmotionfn)mknob_motion, 0, xpos, ypos);
+
+}
+
+static int mknob_newclick(t_gobj *z, struct _glist *glist,
+                          int xpix, int ypix, int shift, int alt, int dbl, int doit)
+{
+    t_mknob *x = (t_mknob *)z;
+
+    if(doit)
+    {
+        mknob_click( x, (t_floatarg)xpix, (t_floatarg)ypix, (t_floatarg)shift,
+                     0, (t_floatarg)alt);
+        if(shift)
+            x->x_gui.x_fsf.x_finemoved = 1;
+        else
+            x->x_gui.x_fsf.x_finemoved = 0;
+    }
+    return (1);
+}
+
+static void mknob_size(t_mknob *x, t_symbol *s, int ac, t_atom *av)
+{
+    int w=(int)atom_getintarg(0, ac, av),
+        h=x->x_gui.x_h;
+
+    if(ac > 1) h=(int)atom_getintarg(1, ac, av);
+
+    mknob_check_wh(x, w, h);
+    iemgui_size((void *)x, &x->x_gui);
+}
+
+static void mknob_delta(t_mknob *x, t_symbol *s, int ac, t_atom *av)
+{
+    iemgui_delta((void *)x, &x->x_gui, s, ac, av);
+}
+
+static void mknob_pos(t_mknob *x, t_symbol *s, int ac, t_atom *av)
+{
+    iemgui_pos((void *)x, &x->x_gui, s, ac, av);
+}
+
+static void mknob_range(t_mknob *x, t_symbol *s, int ac, t_atom *av)
+{
+    mknob_check_minmax(x, (double)atom_getfloatarg(0, ac, av),
+                       (double)atom_getfloatarg(1, ac, av));
+}
+
+static void mknob_color(t_mknob *x, t_symbol *s, int ac, t_atom *av)
+{
+    iemgui_color((void *)x, &x->x_gui, s, ac, av);
+}
+
+static void mknob_send(t_mknob *x, t_symbol *s)
+{
+    iemgui_send(x, &x->x_gui, s);
+}
+
+static void mknob_receive(t_mknob *x, t_symbol *s)
+{
+    iemgui_receive(x, &x->x_gui, s);
+}
+
+static void mknob_label(t_mknob *x, t_symbol *s)
+{
+    iemgui_label((void *)x, &x->x_gui, s);
+}
+
+static void mknob_label_pos(t_mknob *x, t_symbol *s, int ac, t_atom *av)
+{
+    iemgui_label_pos((void *)x, &x->x_gui, s, ac, av);
+}
+
+static void mknob_label_font(t_mknob *x, t_symbol *s, int ac, t_atom *av)
+{
+    iemgui_label_font((void *)x, &x->x_gui, s, ac, av);
+}
+
+static void mknob_log(t_mknob *x)
+{
+    x->x_lin0_log1 = 1;
+    mknob_check_minmax(x, x->x_min, x->x_max);
+}
+
+static void mknob_lin(t_mknob *x)
+{
+    x->x_lin0_log1 = 0;
+    x->x_k = (x->x_max - x->x_min)/(double)(x->x_gui.x_w - 1);
+}
+
+static void mknob_init(t_mknob *x, t_floatarg f)
+{
+    x->x_gui.x_isa.x_loadinit = (f==0.0)?0:1;
+}
+
+static void mknob_steady(t_mknob *x, t_floatarg f)
+{
+    x->x_steady = (f==0.0)?0:1;
+}
+
+static void mknob_float(t_mknob *x, t_floatarg f)
+{
+    double out;
+
+    mknob_set(x, f);
+    if(x->x_lin0_log1)
+        out = x->x_min*exp(x->x_k*(double)(x->x_val)*0.01);
+    else
+        out = (double)(x->x_val)*0.01*x->x_k + x->x_min;
+    if((out < 1.0e-10)&&(out > -1.0e-10))
+        out = 0.0;
+    if(x->x_gui.x_fsf.x_put_in2out)
+    {
+        outlet_float(x->x_gui.x_obj.ob_outlet, out);
+        if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
+            pd_float(x->x_gui.x_snd->s_thing, out);
+    }
+}
+
+static void mknob_loadbang(t_mknob *x, t_floatarg action)
+{
+    /*if(!sys_noloadbang && x->x_gui.x_isa.x_loadinit)
+    {
+        (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+        mknob_bang(x);
+    }*/
+    if (action == LB_LOAD && x->x_gui.x_isa.x_loadinit)
+        mknob_bang(x);
+}
+
+/*static void mknob_list(t_mknob *x, t_symbol *s, int ac, t_atom *av)
+{
+    int l=iemgui_list((void *)x, &x->x_gui, s, ac, av);
+
+    if(l < 0)
+    {
+	if(IS_A_FLOAT(av,0))
+	    mknob_float(x, atom_getfloatarg(0, ac, av));
+    }
+    else if(l > 0)
+    {
+	(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
+	canvas_fixlinesfor(x->x_gui.x_glist, (t_text*)x);
+    }
+}*/
+
+extern void iemgui_all_colfromload(t_iemgui *iemgui, int *bflcol);
+//extern void iemgui_all_loadcolors(t_iemgui *iemgui, t_atom*bcol, t_atom*fcol, t_atom*lcol);
+//static void (*iemgui_all_loadcolors_p)(t_iemgui *iemgui, t_atom*bcol, t_atom*fcol, t_atom*lcol) = NULL;
+
+typedef void (iemgui_all_loadcolors_t)(t_iemgui *iemgui, t_atom*bcol, t_atom*fcol, t_atom*lcol);
+static iemgui_all_loadcolors_t *iemgui_all_loadcolors_p = NULL;
+
+static void check_compat()
+{
+    compat = 1;
+	// Christof Ressi: the compatibility check below doesn't work yet on Windows, so we just skip it. now the code only works with Pd >= 0.47!
+	/*
+#ifdef MSW
+    HINSTANCE ntdll= GetModuleHandle(NULL);
+    if (ntdll) 
+        iemgui_all_loadcolors_p = (iemgui_all_loadcolors_t *)GetProcAddress(ntdll, "iemgui_all_loadcolors");
+#elif defined(UNIX)
+    void *handle = dlopen(NULL, RTLD_NOW);
+    if(handle) 
+        iemgui_all_loadcolors_p = (iemgui_all_loadcolors_t *)dlsym(handle, "iemgui_all_loadcolors");
+#else
+// No dynamic loading mechanism specified, rely to version of Pd used for compilation :
+    #if PD_MINOR_VERSION >= 47
+    iemgui_all_loadcolors_p = &iemgui_all_loadcolors;
+    #endif
+#endif
+	*/
+	iemgui_all_loadcolors_p = &iemgui_all_loadcolors;
+	
+    if(iemgui_all_loadcolors_p) compat = 0;
+}
+
+static void *mknob_new(t_symbol *s, int argc, t_atom *argv)
+{
+    t_mknob *x = (t_mknob *)pd_new(mknob_class);
+    int w=MKNOB_DEFAULTSIZE, h=MKNOB_DEFAULTH;
+    int fs=8 ,lilo=0, ldx=-2, ldy=-6, f=0, v=0, steady=1;
+    double min=0.0, max=(double)(IEM_SL_DEFAULTSIZE-1);
+    char str[144];
+
+    if(compat) {
+        int bflcol[]= {-262144, -1, -1};
+
+        if(((argc == 17)||(argc == 18))&&IS_A_FLOAT(argv,0)&&IS_A_FLOAT(argv,1)
+                &&IS_A_FLOAT(argv,2)&&IS_A_FLOAT(argv,3)
+                &&IS_A_FLOAT(argv,4)&&IS_A_FLOAT(argv,5)
+                &&(IS_A_SYMBOL(argv,6)||IS_A_FLOAT(argv,6))
+                &&(IS_A_SYMBOL(argv,7)||IS_A_FLOAT(argv,7))
+                &&(IS_A_SYMBOL(argv,8)||IS_A_FLOAT(argv,8))
+                &&IS_A_FLOAT(argv,9)&&IS_A_FLOAT(argv,10)
+                &&IS_A_FLOAT(argv,11)&&IS_A_FLOAT(argv,12)&&IS_A_FLOAT(argv,13)
+                &&IS_A_FLOAT(argv,14)&&IS_A_FLOAT(argv,15)&&IS_A_FLOAT(argv,16))
+        {
+            w = (int)atom_getintarg(0, argc, argv);
+            h = (int)atom_getintarg(1, argc, argv);
+            min = (double)atom_getfloatarg(2, argc, argv);
+            max = (double)atom_getfloatarg(3, argc, argv);
+            lilo = (int)atom_getintarg(4, argc, argv);
+            iem_inttosymargs(&x->x_gui.x_isa, atom_getintarg(5, argc, argv));
+            iemgui_new_getnames(&x->x_gui, 6, argv);
+            ldx = (int)atom_getintarg(9, argc, argv);
+            ldy = (int)atom_getintarg(10, argc, argv);
+            iem_inttofstyle(&x->x_gui.x_fsf, atom_getintarg(11, argc, argv));
+            fs = (int)atom_getintarg(12, argc, argv);
+            bflcol[0] = (int)atom_getintarg(13, argc, argv);
+            bflcol[1] = (int)atom_getintarg(14, argc, argv);
+            bflcol[2] = (int)atom_getintarg(15, argc, argv);
+            v = (int)atom_getintarg(16, argc, argv);
+        }
+        else iemgui_new_getnames(&x->x_gui, 6, 0);
+
+        iemgui_all_colfromload(&x->x_gui, bflcol);
+    } else {
+        x->x_gui.x_bcol = 0xFCFCFC;
+        x->x_gui.x_fcol = 0x00;
+        x->x_gui.x_lcol = 0x00;
+        
+        if(((argc == 17)||(argc == 18))&&IS_A_FLOAT(argv,0)&&IS_A_FLOAT(argv,1)
+                &&IS_A_FLOAT(argv,2)&&IS_A_FLOAT(argv,3)
+                &&IS_A_FLOAT(argv,4)&&IS_A_FLOAT(argv,5)
+                &&(IS_A_SYMBOL(argv,6)||IS_A_FLOAT(argv,6))
+                &&(IS_A_SYMBOL(argv,7)||IS_A_FLOAT(argv,7))
+                &&(IS_A_SYMBOL(argv,8)||IS_A_FLOAT(argv,8))
+                &&IS_A_FLOAT(argv,9)&&IS_A_FLOAT(argv,10)
+                &&IS_A_FLOAT(argv,11)&&IS_A_FLOAT(argv,12)&&IS_A_FLOAT(argv,16))
+        {
+            w = (int)atom_getintarg(0, argc, argv);
+            h = (int)atom_getintarg(1, argc, argv);
+            min = (double)atom_getfloatarg(2, argc, argv);
+            max = (double)atom_getfloatarg(3, argc, argv);
+            lilo = (int)atom_getintarg(4, argc, argv);
+            iem_inttosymargs(&x->x_gui.x_isa, atom_getintarg(5, argc, argv));
+            iemgui_new_getnames(&x->x_gui, 6, argv);
+            ldx = (int)atom_getintarg(9, argc, argv);
+            ldy = (int)atom_getintarg(10, argc, argv);
+            iem_inttofstyle(&x->x_gui.x_fsf, atom_getintarg(11, argc, argv));
+            fs = (int)atom_getintarg(12, argc, argv);
+            
+            //iemgui_all_loadcolors(&x->x_gui, argv+13, argv+14, argv+15);
+            if(iemgui_all_loadcolors_p != NULL)
+                iemgui_all_loadcolors_p(&x->x_gui, argv+13, argv+14, argv+15);
+                
+            v = (int)atom_getintarg(16, argc, argv);
+        }
+        else iemgui_new_getnames(&x->x_gui, 6, 0);
+    }
+
+    if((argc == 18)&&IS_A_FLOAT(argv,17))
+        steady = (int)atom_getintarg(17, argc, argv);
+
+    x->x_gui.x_draw = (t_iemfunptr)mknob_draw;
+    x->x_gui.x_fsf.x_snd_able = 1;
+    x->x_gui.x_fsf.x_rcv_able = 1;
+    x->x_gui.x_glist = (t_glist *)canvas_getcurrent();
+
+    if(x->x_gui.x_isa.x_loadinit)
+        x->x_val = v;
+    else
+        x->x_val = 0;
+
+    x->x_pos = x->x_val;
+
+    if(lilo != 0) lilo = 1;
+    x->x_lin0_log1 = lilo;
+
+    if(steady != 0) steady = 1;
+    x->x_steady = steady;
+
+    if(!strcmp(x->x_gui.x_snd->s_name, "empty")) x->x_gui.x_fsf.x_snd_able = 0;
+    if(!strcmp(x->x_gui.x_rcv->s_name, "empty")) x->x_gui.x_fsf.x_rcv_able = 0;
+
+    if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica");
+    else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times");
+    else
+    {
+        x->x_gui.x_fsf.x_font_style = 0;
+        strcpy(x->x_gui.x_font, sys_font);
+    }
+
+    if(x->x_gui.x_fsf.x_rcv_able) pd_bind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
+
+    x->x_gui.x_ldx = ldx;
+    x->x_gui.x_ldy = ldy;
+
+    if(fs < 4) fs = 4;
+    x->x_gui.x_fontsize = fs;
+
+    mknob_check_wh(x, w, h);
+
+    mknob_check_minmax(x, min, max);
+
+    x->x_thick = 0;
+    iemgui_verify_snd_ne_rcv(&x->x_gui);
+    outlet_new(&x->x_gui.x_obj, &s_float);
+    return (x);
+}
+
+static void mknob_free(t_mknob *x)
+{
+    /*if(x->x_gui.x_fsf.x_selected)
+    pd_unbind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);*/
+    if(x->x_gui.x_fsf.x_rcv_able)
+        pd_unbind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
+    gfxstub_deleteforkey(x);
+}
+
+extern void canvas_iemguis(t_glist *gl, t_symbol *guiobjname);
+
+void canvas_mknob(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
+{
+    canvas_iemguis(gl, gensym("mknob"));
+}
+
+
+
+void mknob_setup(void)
+{
+    check_compat();
+    
+    mknob_class = class_new(gensym("mknob"), (t_newmethod)mknob_new,
+                            (t_method)mknob_free, sizeof(t_mknob), 0, A_GIMME, 0);
+#ifndef GGEE_mknob_COMPATIBLE
+//    class_addcreator((t_newmethod)mknob_new, gensym("mknob"), A_GIMME, 0);
+#endif
+    class_addbang(mknob_class,mknob_bang);
+    class_addfloat(mknob_class,mknob_float);
+    //class_addlist(mknob_class, mknob_list);
+    class_addmethod(mknob_class, (t_method)mknob_click, gensym("click"),
+                    A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
+    class_addmethod(mknob_class, (t_method)mknob_motion, gensym("motion"),
+                    A_FLOAT, A_FLOAT, 0);
+    class_addmethod(mknob_class, (t_method)mknob_dialog, gensym("dialog"), A_GIMME, 0);
+    class_addmethod(mknob_class, (t_method)mknob_loadbang, gensym("loadbang"), 0);
+    class_addmethod(mknob_class, (t_method)mknob_set, gensym("set"), A_FLOAT, 0);
+    class_addmethod(mknob_class, (t_method)mknob_size, gensym("size"), A_GIMME, 0);
+    class_addmethod(mknob_class, (t_method)mknob_delta, gensym("delta"), A_GIMME, 0);
+    class_addmethod(mknob_class, (t_method)mknob_pos, gensym("pos"), A_GIMME, 0);
+    class_addmethod(mknob_class, (t_method)mknob_range, gensym("range"), A_GIMME, 0);
+    class_addmethod(mknob_class, (t_method)mknob_color, gensym("color"), A_GIMME, 0);
+    class_addmethod(mknob_class, (t_method)mknob_send, gensym("send"), A_DEFSYM, 0);
+    class_addmethod(mknob_class, (t_method)mknob_receive, gensym("receive"), A_DEFSYM, 0);
+    class_addmethod(mknob_class, (t_method)mknob_label, gensym("label"), A_DEFSYM, 0);
+    class_addmethod(mknob_class, (t_method)mknob_label_pos, gensym("label_pos"), A_GIMME, 0);
+    class_addmethod(mknob_class, (t_method)mknob_label_font, gensym("label_font"), A_GIMME, 0);
+    class_addmethod(mknob_class, (t_method)mknob_log, gensym("log"), 0);
+    class_addmethod(mknob_class, (t_method)mknob_lin, gensym("lin"), 0);
+    class_addmethod(mknob_class, (t_method)mknob_init, gensym("init"), A_FLOAT, 0);
+    class_addmethod(mknob_class, (t_method)mknob_steady, gensym("steady"), A_FLOAT, 0);
+    /*if(!iemgui_key_sym)
+    iemgui_key_sym = gensym("#keyname");*/
+    mknob_widgetbehavior.w_getrectfn =    mknob_getrect;
+    mknob_widgetbehavior.w_displacefn =   iemgui_displace;
+    mknob_widgetbehavior.w_selectfn =     iemgui_select;
+    mknob_widgetbehavior.w_activatefn =   NULL;
+    mknob_widgetbehavior.w_deletefn =     iemgui_delete;
+    mknob_widgetbehavior.w_visfn =        iemgui_vis;
+    mknob_widgetbehavior.w_clickfn =      mknob_newclick;
+    //mknob_widgetbehavior.w_propertiesfn = mknob_properties;
+    //mknob_widgetbehavior.w_savefn =       mknob_save;
+    class_setwidget(mknob_class, &mknob_widgetbehavior);
+
+    class_setsavefn(mknob_class, mknob_save);
+    class_setpropertiesfn(mknob_class, mknob_properties);
+    class_addmethod(canvas_class, (t_method)canvas_mknob, gensym("mknob"),
+                    A_GIMME, A_NULL);
+}
diff --git a/moonlib-meta.pd b/moonlib-meta.pd
index b065669..51b5189 100644
--- a/moonlib-meta.pd
+++ b/moonlib-meta.pd
@@ -1,7 +1,7 @@
-#N canvas 10 10 200 200 10;
-#N canvas 20 20 420 300 META 0;
-#X text 10 10 META this is a prototype of a libdir meta file;
-#X text 10 30 NAME moonlib;
-#X text 10 50 AUTHOR Antoine Rousseau;
-#X text 10 70 VERSION 0.2;
-#X restore 10 10 pd META;
+#N canvas 10 10 200 200 10;
+#N canvas 20 20 420 300 META 0;
+#X text 10 10 META this is a prototype of a libdir meta file;
+#X text 10 30 NAME moonlib;
+#X text 10 50 AUTHOR Antoine Rousseau;
+#X text 10 70 VERSION 0.3.4;
+#X restore 10 10 pd META;
diff --git a/ndmetro-help.pd b/ndmetro-help.pd
new file mode 100644
index 0000000..d32396a
--- /dev/null
+++ b/ndmetro-help.pd
@@ -0,0 +1,89 @@
+#N canvas 195 138 845 545 10;
+#X obj 0 0 cnv 8 100 60 empty empty ndmetro 10 20 1 18 -262144 -1109
+0;
+#X msg 61 57 0 1000;
+#X floatatom 62 438 5 0 0 0 - - -, f 5;
+#X floatatom 153 239 5 0 0 0 - - -, f 5;
+#X msg 149 173 -1;
+#X floatatom 131 427 5 0 0 0 - - -, f 5;
+#X msg 223 213 700;
+#X msg 188 214 1700;
+#X msg 153 215 4000;
+#X obj 62 462 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1
+-1;
+#X text 16 498 (c) Moonix: Antoine Rousseau 2005-2016;
+#X msg 91 125 0;
+#X floatatom 243 439 5 0 0 0 - - -, f 5;
+#X floatatom 312 427 5 0 0 0 - - -, f 5;
+#X obj 243 463 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144
+-1 -1;
+#X msg 81 101 0 300;
+#X msg 71 80 0 2000;
+#X obj 62 401 ndmetro 64 1;
+#X obj 243 402 ndmetro 64 1;
+#X msg 476 187 4 2;
+#X msg 441 187 64 1;
+#X msg 504 187 6 3;
+#X msg 535 186 16 16;
+#X msg 596 186 64.13 0.97;
+#X obj 131 444 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144
+-1 -1;
+#X obj 312 445 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144
+-1 -1;
+#X msg 153 299 bang;
+#X obj 62 349 t a a;
+#X msg 153 258 tempo \$1;
+#X msg 441 238 nd \$1 \$2;
+#X text 127 81 goto step STEP immediately \, and start counting at
+period MS., f 33;
+#X msg 119 125 10;
+#X msg 148 125 5.5;
+#X text 178 124 floating point STEP is accepted.;
+#X text 180 172 -1 stops.;
+#X text 440 111 nd NUM DENUM : set the decomposition of the counting.
+;
+#X text 441 132 ndmetro will count from 0 to NUM at tempo MS/DENUM.
+;
+#X text 131 60 START : STEP [MS];
+#X text 441 147 ndmetro is always in sync with an imaginary master
+clock only governed by START and tempo commands.;
+#X text 578 206 floating point NUM and DENUM accepted...;
+#X text 579 218 (who really knows what this does ?...);
+#X text 350 400 arguments : initial NUM DENUM;
+#X text 311 464 right outlet sends phase when tempo or nd change (useful
+for example to link ndmetros).;
+#X obj 61 37 loadbang;
+#X text 189 299 bang sends the current phase to right outlet.;
+#X text 210 257 tempo : set the tempo in ms.;
+#X text 109 12 num/denum metronome \, allowing continuous tempo change.
+;
+#X connect 1 0 27 0;
+#X connect 2 0 9 0;
+#X connect 3 0 28 0;
+#X connect 4 0 27 0;
+#X connect 5 0 24 0;
+#X connect 6 0 3 0;
+#X connect 7 0 3 0;
+#X connect 8 0 3 0;
+#X connect 11 0 27 0;
+#X connect 12 0 14 0;
+#X connect 13 0 25 0;
+#X connect 15 0 27 0;
+#X connect 16 0 27 0;
+#X connect 17 0 2 0;
+#X connect 17 1 5 0;
+#X connect 18 0 12 0;
+#X connect 18 1 13 0;
+#X connect 19 0 29 0;
+#X connect 20 0 29 0;
+#X connect 21 0 29 0;
+#X connect 22 0 29 0;
+#X connect 23 0 29 0;
+#X connect 26 0 27 0;
+#X connect 27 0 17 0;
+#X connect 27 1 18 0;
+#X connect 28 0 27 0;
+#X connect 29 0 18 0;
+#X connect 31 0 27 0;
+#X connect 32 0 27 0;
+#X connect 43 0 1 0;
diff --git a/ndmetro.c b/ndmetro.c
new file mode 100644
index 0000000..6be4f33
--- /dev/null
+++ b/ndmetro.c
@@ -0,0 +1,199 @@
+/* ------------------------- ndndmetro   -----------------------------------------*/
+/*                                                                              */
+/*  Antoine Rousseau 2005-2016                                                       */
+/*                                                                              */
+/* 
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+*/
+/* ---------------------------------------------------------------------------- */
+
+#include "m_pd.h"
+#include <stdio.h>
+#include <string.h>
+#ifdef UNIX
+#include <stdlib.h>
+#endif
+#include <math.h>
+
+static t_class *ndmetro_class;
+
+
+typedef struct _ndmetro
+{
+    t_object x_obj;
+    t_clock *x_clock;
+    double x_tempo;
+    double x_newtempo;
+    double x_num;
+    double x_denum;
+    int x_tick;
+    int x_hit;
+    int x_on;
+    double x_lasttime;
+    double x_lastbeat;
+    t_outlet *x_floatoutlet;
+} t_ndmetro;
+
+static void ndmetro_tick(t_ndmetro *x)
+{
+    double dtime,nextime,beat,tick=x->x_tick,tickk,fracpart=0; 
+    double intpart;
+    
+    x->x_hit = 0;
+
+    if(tick>=0){
+	outlet_float(x->x_obj.ob_outlet,fmod(tick,x->x_num));
+	if (!x->x_hit) {
+		clock_delay(x->x_clock, x->x_tempo/x->x_denum);
+    		x->x_tick=tick+1;
+	}
+    }
+    else{
+    	dtime=clock_gettimesince(x->x_lasttime);
+    	beat=x->x_lastbeat+dtime/x->x_tempo;
+    	tick=beat*x->x_denum;
+    	if(fabs((tickk=rint(tick))-tick)<1e-6) tick=tickk;
+    
+    	fracpart=modf(tick,&intpart);
+    
+   //fprintf(stderr,"metro_tick; beat=%.15g tick=%.15g fracpart=%.15g\n",beat,tick,fracpart);
+    	if(!fracpart) outlet_float(x->x_obj.ob_outlet,fmod(tick,x->x_num));
+	else  outlet_float(x->x_floatoutlet,fmod(tick,x->x_num));
+    
+    	if (!x->x_hit) {
+    		x->x_tempo=x->x_newtempo;
+    		x->x_lastbeat=beat;
+    		x->x_lasttime=clock_getsystime();
+    		nextime=x->x_tempo*(1.0-fracpart)/x->x_denum;
+    		if(nextime<0.01) nextime=0.01;
+		clock_delay(x->x_clock, nextime);
+    		x->x_tick=floor(tick)+1;
+	}
+    }
+}
+
+static void ndmetro_bang(t_ndmetro *x)
+{
+    //post("metro_bang");
+    x->x_tick=-1;
+    if(x->x_on) ndmetro_tick(x);
+    x->x_hit = 1;
+}
+
+static void ndmetro_list(t_ndmetro *x, t_symbol *s,  int ac, t_atom *av)
+{
+    double beat,tempo;
+    t_atom *ap=av;
+    
+    //post("metro_list");
+    
+    if(ac<1) {
+	ndmetro_bang(x);
+	return;
+    }
+
+    if(ap->a_type!=A_FLOAT) {
+	ndmetro_bang(x);
+	return;
+    }
+
+    beat=atom_getfloat(ap);ap++;
+    
+    
+    //fprintf(stderr,"beat=%g\n",beat);
+    if(beat==-1) {
+    	clock_unset(x->x_clock);
+	x->x_on=0;
+	x->x_hit = 1;
+	//x->x_tick=0;
+	return;
+    }
+    
+    if((ac>1)&&(ap->a_type==A_FLOAT)) {
+    	tempo=atom_getfloat(ap);
+    	if(tempo<1) tempo=1;
+    	x->x_newtempo=tempo;
+    //fprintf(stderr,"tempo=%f\n",tempo);
+    }
+    
+    x->x_lastbeat=beat;
+    x->x_lasttime=clock_getsystime();
+    x->x_on=1;
+        
+    ndmetro_bang(x);
+}
+
+
+static void ndmetro_nd(t_ndmetro *x, t_floatarg n,t_floatarg d)
+{
+    if(d<0.01) d=0.01;
+    if(n<0.01) n=0.01;
+    x->x_num=n;
+    x->x_denum=d;
+    x->x_tick=-1;
+    //if(x->x_on) ndmetro_tick(x);
+    ndmetro_bang(x);
+
+}
+
+static void ndmetro_tempo(t_ndmetro *x, t_floatarg t)
+{
+    if(t<1) t=1;
+    x->x_newtempo=t;
+    x->x_tick=-1;
+    //if(x->x_on) ndmetro_tick(x);
+    ndmetro_bang(x);
+}
+
+static void ndmetro_free(t_ndmetro *x)
+{
+    clock_free(x->x_clock);
+}
+
+static void *ndmetro_new(t_floatarg n, t_floatarg d)
+{
+    t_ndmetro *x = (t_ndmetro *)pd_new(ndmetro_class);
+    
+    if(d==0) d=1;
+    if(n==0) n=1;
+    if(d<0.01) d=0.01;
+    if(n<0.01) n=0.01;
+    x->x_num=n;
+    x->x_denum=d;
+    x->x_hit = 0;
+    x->x_on = 0;
+    x->x_clock = clock_new(x, (t_method)ndmetro_tick);
+    x->x_tempo=x->x_newtempo=1000;
+    x->x_lasttime=clock_getsystime();
+    x->x_lastbeat=0;
+    outlet_new(&x->x_obj, gensym("float"));
+    x->x_floatoutlet=outlet_new(&x->x_obj, gensym("float"));
+    //inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1"));
+    return (x);
+}
+
+void ndmetro_setup(void)
+{
+    ndmetro_class = class_new(gensym("ndmetro"), (t_newmethod)ndmetro_new,
+        (t_method)ndmetro_free, sizeof(t_ndmetro), 0, A_DEFFLOAT,  A_DEFFLOAT, 0);
+    class_addbang(ndmetro_class, (t_method)ndmetro_bang);
+    class_addlist(ndmetro_class, (t_method)ndmetro_list);
+    class_addmethod(ndmetro_class, (t_method)ndmetro_nd, gensym("nd"),
+        A_FLOAT,A_FLOAT, 0);
+    class_addmethod(ndmetro_class, (t_method)ndmetro_tempo, gensym("tempo"),
+        A_FLOAT, 0);
+}
+
diff --git a/panvol~-help.pd b/panvol~-help.pd
index f7ad351..7d3c4c7 100644
--- a/panvol~-help.pd
+++ b/panvol~-help.pd
@@ -1,34 +1,43 @@
-#N canvas 117 381 340 290 10;
-#X obj 0 0 cnv 8 100 60 empty empty panvol~ 10 20 1 18 -262144 -1109
-0;
-#X text 3 269 (c) Moonix: Antoine Rousseau 2003;
-#X text 132 12 pan & volume;
-#X obj 138 69 hsl 60 10 -45 45 0 0 empty empty pan -2 -6 0 8 -262144
--1 -1 2950 1;
-#X obj 238 61 vsl 10 60 0 1 0 0 empty empty vol 0 -8 0 8 -262144 -1
--1 5900 1;
-#X floatatom 135 85 5 0 0;
-#X floatatom 238 127 5 0 0;
-#X obj 113 141 panvol~;
-#X obj 94 190 unsig~ 100;
-#X floatatom 94 210 5 0 0;
-#X obj 60 85 osc~ 440;
-#X obj 173 190 unsig~ 100;
-#X floatatom 173 210 5 0 0;
-#X obj 94 170 envrms~;
-#X obj 173 170 envrms~;
-#X obj 60 104 *~ 2;
-#X msg 174 49 0;
-#X connect 3 0 5 0;
-#X connect 4 0 6 0;
-#X connect 5 0 7 1;
-#X connect 6 0 7 2;
-#X connect 7 0 13 0;
-#X connect 7 1 14 0;
-#X connect 8 0 9 0;
-#X connect 10 0 15 0;
-#X connect 11 0 12 0;
-#X connect 13 0 8 0;
-#X connect 14 0 11 0;
-#X connect 15 0 7 0;
-#X connect 16 0 3 0;
+#N canvas 619 134 312 305 10;
+#X obj 0 0 cnv 8 100 60 empty empty panvol~ 10 20 1 18 -262144 -1109
+0;
+#X text 3 269 (c) Moonix: Antoine Rousseau 2003;
+#X text 132 12 pan & volume;
+#X obj 135 69 hsl 60 10 -45 45 0 0 empty empty pan -2 -6 0 8 -262144
+-1 -1 0 1;
+#X obj 238 41 vsl 10 60 0 1 0 0 empty empty vol 0 -8 0 8 -262144 -1
+-1 3600 1;
+#X floatatom 132 85 5 0 0 0 - - -, f 5;
+#X floatatom 238 107 5 0 0 0 - - -, f 5;
+#X obj 113 141 panvol~;
+#X floatatom 94 210 5 0 0 0 - - -, f 5;
+#X obj 60 85 osc~ 440;
+#X floatatom 173 210 5 0 0 0 - - -, f 5;
+#X obj 60 104 *~ 2;
+#X msg 171 46 0;
+#N canvas 348 58 494 344 META 0;
+#X text 12 25 LICENSE GPL v2;
+#X text 12 165 AUTHOR Antoine Rousseau;
+#X text 12 185 HELP_PATCH_AUTHORS Antoine Rousseau. "pd meta" information
+added by Jonathan Wilkes for Pd version 0.42.;
+#X text 12 45 DESCRIPTION pan & volume;
+#X text 12 5 KEYWORDS signal;
+#X text 12 65 INLET_0 signal;
+#X text 12 85 INLET_1 float;
+#X text 12 105 INLET_2 float;
+#X text 12 125 OUTLET_0 signal;
+#X text 12 145 OUTLET_1 signal;
+#X restore 241 265 pd META;
+#X obj 94 169 env~;
+#X obj 173 170 env~;
+#X connect 3 0 5 0;
+#X connect 4 0 6 0;
+#X connect 5 0 7 1;
+#X connect 6 0 7 2;
+#X connect 7 0 14 0;
+#X connect 7 1 15 0;
+#X connect 9 0 11 0;
+#X connect 11 0 7 0;
+#X connect 12 0 3 0;
+#X connect 14 0 8 0;
+#X connect 15 0 10 0;
diff --git a/panvol~.c b/panvol~.c
index 2e302c6..625d9aa 100644
--- a/panvol~.c
+++ b/panvol~.c
@@ -1,119 +1,119 @@
-/*************************************************************************** 
- * File: pan~.c 
- * Auth: Iain Mott [iain.mott at bigpond.com] 
- * Maintainer: Iain Mott [iain.mott at bigpond.com] 
- * Version: Part of motex_1.1.2 
- * Date: January 2001
- * 
- * Description: Pd signal external. Equal-power stereo panning
- * Angle input specified in degrees. -45 left, 0 centre, 45 right. 
- * See supporting Pd patch: pan~.pd
- * 
- * Copyright (C) 2001 by Iain Mott [iain.mott at bigpond.com] 
- * 
- * 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, 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, which should be included with this 
- * program, for more details. 
- * 
- ****************************************************************************/ 
-
-/* I've only add a global volume... Antoine Rousseau 2003*/
-
-#include "m_pd.h"
-#include <math.h>
-
-static t_class *pan_class;
-#define RADCONST 0.017453293
-#define ROOT2DIV2 0.707106781
-
-typedef struct _pan
-{
-  t_object x_obj;
-  float x_f;
-  float pan;
-  float left;
-  float right;
-  float vol;
-} t_pan;
-
-static void *pan_new(t_symbol *s, int argc, t_atom *argv)
-{
-  t_pan *x = (t_pan *)pd_new(pan_class);
-  outlet_new(&x->x_obj, gensym("signal"));
-  outlet_new(&x->x_obj, gensym("signal"));
-  inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("panf"));
-  inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("volf"));
-
-  x->x_f = 0;
-  x->left = ROOT2DIV2;
-  x->right = ROOT2DIV2;
-  x->vol = 1;
-  return (x);
-}
-
-static t_int *pan_perform(t_int *w)
-{
-  float *in1 = (t_float *)(w[1]);
-  float *out1 = (t_float *)(w[2]);
-  float *out2 = (t_float *)(w[3]);
-  int n = (int)(w[4]);
-  t_pan *x = (t_pan *)(w[5]);
-  float left=x->left*x->vol;
-  float right=x->right*x->vol;
-  float value;
-  
-  while  (n--) 
-    {
-      value = *in1++;
-      *out1++ = value * left;
-      *out2++ = value * right; 
-    }
-  return (w+6);
-}
-
-static void pan_dsp(t_pan *x, t_signal **sp)
-{
-  int n = sp[0]->s_n;
-  float *in1 = sp[0]->s_vec;
-  float *out1 = sp[1]->s_vec;
-  float *out2 = sp[2]->s_vec;
-
-  dsp_add(pan_perform, 5,
-	  in1, out1, out2, n, x);
-}
-
-static void pan_f(t_pan *x, t_floatarg f)
-{
-  double angle;
-  f = f < -45 ? -45 : f;
-  f = f > 45 ? 45 : f;
-  angle = f * RADCONST; // convert degrees to radians
-  x->right  = ROOT2DIV2 * (cos(angle) + sin(angle));
-  x->left  = ROOT2DIV2 * (cos(angle) - sin(angle));
-/*    post("left = %f : right = %f", x->left, x->right); */
-}
-
-static void vol_f(t_pan *x, t_floatarg f)
-{
-  f = f < 0 ? 0 : f;
-  x->vol=f;
-}
-
-void panvol_tilde_setup(void)
-{
-  pan_class = class_new(gensym("panvol~"), (t_newmethod)pan_new, 0,
-			sizeof(t_pan), 0, A_GIMME, 0);
-
-  class_addmethod(pan_class, nullfn, gensym("signal"), 0);
-
-  class_addmethod(pan_class, (t_method)pan_dsp, gensym("dsp"), 0);
-  class_addmethod(pan_class, (t_method)pan_f, gensym("panf"), A_FLOAT, 0);  
-  class_addmethod(pan_class, (t_method)vol_f, gensym("volf"), A_FLOAT, 0);  
-}
+/***************************************************************************
+ * File: pan~.c
+ * Auth: Iain Mott [iain.mott at bigpond.com]
+ * Maintainer: Iain Mott [iain.mott at bigpond.com]
+ * Version: Part of motex_1.1.2
+ * Date: January 2001
+ *
+ * Description: Pd signal external. Equal-power stereo panning
+ * Angle input specified in degrees. -45 left, 0 centre, 45 right.
+ * See supporting Pd patch: pan~.pd
+ *
+ * Copyright (C) 2001 by Iain Mott [iain.mott at bigpond.com]
+ *
+ * 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, 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, which should be included with this
+ * program, for more details.
+ *
+ ****************************************************************************/
+
+/* I've only add a global volume... Antoine Rousseau 2003*/
+
+#include "m_pd.h"
+#include <math.h>
+
+static t_class *pan_class;
+#define RADCONST 0.017453293
+#define ROOT2DIV2 0.707106781
+
+typedef struct _pan
+{
+    t_object x_obj;
+    float x_f;
+    float pan;
+    float left;
+    float right;
+    float vol;
+} t_pan;
+
+static void *pan_new(t_symbol *s, int argc, t_atom *argv)
+{
+    t_pan *x = (t_pan *)pd_new(pan_class);
+    outlet_new(&x->x_obj, gensym("signal"));
+    outlet_new(&x->x_obj, gensym("signal"));
+    inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("panf"));
+    inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("volf"));
+
+    x->x_f = 0;
+    x->left = ROOT2DIV2;
+    x->right = ROOT2DIV2;
+    x->vol = 1;
+    return (x);
+}
+
+static t_int *pan_perform(t_int *w)
+{
+    float *in1 = (t_float *)(w[1]);
+    float *out1 = (t_float *)(w[2]);
+    float *out2 = (t_float *)(w[3]);
+    int n = (int)(w[4]);
+    t_pan *x = (t_pan *)(w[5]);
+    float left=x->left*x->vol;
+    float right=x->right*x->vol;
+    float value;
+
+    while  (n--)
+    {
+        value = *in1++;
+        *out1++ = value * left;
+        *out2++ = value * right;
+    }
+    return (w+6);
+}
+
+static void pan_dsp(t_pan *x, t_signal **sp)
+{
+    int n = sp[0]->s_n;
+    float *in1 = sp[0]->s_vec;
+    float *out1 = sp[1]->s_vec;
+    float *out2 = sp[2]->s_vec;
+
+    dsp_add(pan_perform, 5,
+            in1, out1, out2, n, x);
+}
+
+static void pan_f(t_pan *x, t_floatarg f)
+{
+    double angle;
+    f = f < -45 ? -45 : f;
+    f = f > 45 ? 45 : f;
+    angle = f * RADCONST; // convert degrees to radians
+    x->right  = ROOT2DIV2 * (cos(angle) + sin(angle));
+    x->left  = ROOT2DIV2 * (cos(angle) - sin(angle));
+    /*    post("left = %f : right = %f", x->left, x->right); */
+}
+
+static void vol_f(t_pan *x, t_floatarg f)
+{
+    f = f < 0 ? 0 : f;
+    x->vol=f;
+}
+
+void panvol_tilde_setup(void)
+{
+    pan_class = class_new(gensym("panvol~"), (t_newmethod)pan_new, 0,
+                          sizeof(t_pan), 0, A_GIMME, 0);
+
+    class_addmethod(pan_class, nullfn, gensym("signal"), 0);
+
+    class_addmethod(pan_class, (t_method)pan_dsp, gensym("dsp"), 0);
+    class_addmethod(pan_class, (t_method)pan_f, gensym("panf"), A_FLOAT, 0);
+    class_addmethod(pan_class, (t_method)vol_f, gensym("volf"), A_FLOAT, 0);
+}
diff --git a/pd-lib-builder/Makefile.pdlibbuilder b/pd-lib-builder/Makefile.pdlibbuilder
new file mode 100644
index 0000000..7082767
--- /dev/null
+++ b/pd-lib-builder/Makefile.pdlibbuilder
@@ -0,0 +1,1164 @@
+# Makefile.pdlibbuilder version 0.1.0, dated 2015-12-08
+#
+# Helper makefile for Pure Data external libraries.
+# Written by Katja Vetter March-June 2015 for the public domain. No warranties.
+# Inspired by Hans Christoph Steiner's Makefile Template and Stephan Beal's
+# ShakeNMake.
+#
+# GNU make version >= 3.81 required.
+#
+#
+#=== characteristics ===========================================================
+#
+#
+# - defines build settings based on autodetected OS and architecture
+# - defines rules to build Pd class- or lib executables from C or C++ sources
+# - defines rules for libdir installation
+# - defines convenience targets for developer and user
+# - evaluates implicit dependencies for non-clean builds
+#
+#
+#=== basic usage ===============================================================
+#
+#
+# In your Makefile, define your Pd lib name and class files, and include
+# Makefile.pdlibbuilder at the end of the Makefile. Like so:
+#
+#    ________________________________________________________________________
+#
+#     # Makefile for mylib
+#
+#     lib.name = mylib
+#
+#     class.sources = myclass1.c myclass2.c
+#
+#     datafiles = myclass1-help.pd myclass2-help.pd README.txt LICENSE.txt
+#
+#     include Makefile.pdlibbuilder
+#    ________________________________________________________________________
+#
+#
+# For files in class.sources it is assumed that class basename == source file
+# basename. The default target builds all classes as individual executables
+# with Pd's default extension for the platform. For anything more than the
+# most basic usage, continue reading.
+#
+#
+#=== list of Makefile.pdlibbuilder API variables ===============================
+#
+#
+# Variables available for definition in your library Makefile:
+#
+# - lib.name
+# - lib.setup.sources
+# - class.sources
+# - common.sources
+# - shared.sources
+# - <classname>.class.sources
+# - <classname>.class.ldflags
+# - <classname>.class.ldlibs
+# - cflags
+# - ldflags
+# - ldlibs
+# - datafiles
+# - datadirs
+# - makefiles
+# - makefiledirs
+# - externalsdir
+#
+# Variables avaialable for (re)definition via command arguments:
+#
+# - pdbinpath (Windows only)
+# - pdincludepath
+# - DESTDIR
+# - prefix
+# - libdir
+# - pkglibdir
+# - CFLAGS
+# - CC
+# - CXX
+# - INSTALL
+# - INSTALL_PROGRAM
+# - INSTALL_DATA
+# - INSTALL_DIR
+#
+# Variables available for your makefile or as command argument:
+#
+# - objectsdir
+# - make-lib-executable
+# - suppress-wunused
+#
+#
+#=== descriptions of Makefile.pdlibbuilder API variables =======================
+#
+#
+# lib.name: 
+# Name of the library directory as it will be installed / distributed. Also the
+# name of the lib executable in the case where all classes are linked into
+# a single binary.
+#
+# lib.setup.sources:
+# Source file(s) (C or C++) which must be compiled only when linking all classes
+# into a single lib binary.
+#
+# class.sources:
+# All sources files (C or C++) for which the condition holds that 
+# class name == source file basename.
+#
+# <classname>.class.sources:
+# Source file(s) (C or C++) specific to class <classname>. Use this for
+# multiple-source classes or when class name != source file basename.
+#
+# common.sources:
+# Source file(s) which must be statically linked to each class in the library.
+#
+# shared.sources:
+# Source file(s) (C or C++) to build a shared dynamic link lib, to be linked
+# with all class executables.
+#
+# cflags, ldflags, ldlibs:
+# Define cflags (preprocessor&compiler), ldflags (linker) and ldlibs (dynamic
+# link libs) for the whole library. These flags are added to platform-specific
+# flags defined by Makefile.pdlibbuilder.
+#
+# <classname>.class.ldflags and <classname>.class.ldlibs: 
+# Define ldflags resp. ldlibs specific to class <classname>. These flags are
+# added to platform-specific flags defined by Makefile.pdlibbuilder, and flags
+# defined in your Makefile for the whole library. Note: cflags can not be
+# defined per class in the current implementation.
+#
+# datafiles and datadirs: 
+# All extra files you want to include in binary distributions of the
+# library: abstractions and help patches, example patches, meta patch, readme
+# and license texts, manuals, sound files, etcetera. Use 'datafiles' for all
+# files that should go into your lib rootdir and 'datadirs' for complete
+# directories you want to copy from source to distribution.
+#
+# externalsdir: 
+# Relative path to directory 'externals' in the context of pd-extended SVN, or
+# any other centralized build layout for multiple libraries. Default value
+# is '..', meaning the direct parent. The value is used in search paths for 
+# pd core components (header files, and executable in the case of Windows).
+#
+# makefiles and makefiledirs: 
+# Extra makefiles or directories with makefiles that should be made in sub-make
+# processes.
+#
+# pdbinpath:
+# For Windows only. Directory where pd.dll can be found for linking.
+#
+# pdincludepath:
+# Directory where Pd API m_pd.h can be found, and other Pd header files.
+#
+# DESTDIR, prefix, libdir:
+# Components of the path for installation as conventionally used on Linux.
+#
+# pkglibdir:
+# Base path for installation of Pd library directories. Default is specified
+# per OS, see section about paths below.
+#
+# objectsdir:
+# Alias of pkglibdir. Can be defined in your makefile to enable project-
+# dependent relative install locations.
+#
+# CFLAGS:
+# Compiler (notably optimization) flags which are defined by 
+# Makefile.pdlibbuilder, but may be overriden via command argument.
+#
+# CC and CXX:
+# C and C++ compiler programs as defined in your build environment.
+#
+# INSTALL, INSTALL_PROGRAM, INSTALL_DATA, INSTALL_DIR:
+# Definitions of install program, may be overriden via command argument.
+#
+# make-lib-executable:
+# When this variable is defined 'yes' in your makefile or as command argument,
+# Makefile.pdlibbuilder will try to build all classes into a single library
+# executable (but it will force exit if lib.setup.sources is undefined).
+# If your makefile defines 'make-lib-executable=yes' as the library default,
+# this can still be overriden with 'make-lib-executable=no' as command argument 
+# to build individual class executables (the Makefile.pdlibbuilder default.)
+#
+# suppress-wunused:
+# When this variable is defined ('yes' or any other value), -Wunused-variable,
+# -Wunused-parameter, -Wunused-value and -Wunused-function are suppressed,
+# but the other warnings from -Wall are retained.
+#
+#
+#=== paths =====================================================================
+#
+#
+# Source files in directories other than current working directory must be
+# prefixed with their relative path. Do not rely on VPATH or vpath.
+# Object (.o) files are built in the directory of their source files.
+# Executables are built in current working directory. 
+#
+# Variable 'pdincludepath' stores a location where m_pd.h is expected to reside.
+# Locations where Makefile.pdlibbuilder tries to find it, in order of priority:
+#
+# any OS:   $(externalsdir)../pd/src
+#
+# Linux:    /usr/include/pdextended
+#           /usr/include/pd
+#
+# OSX:      /Applications/Pd-extended.app/Contents/Resources/include/pdextended
+#           /Applications/Pd.app/Contents/Resources/src
+#
+# Windows:  %PROGRAMFILES%/pd/include/pdextended
+#           %PROGRAMFILES%/pd/src
+#
+# The path for installation of all library components is constructed as:
+#
+# installpath := $(DESTDIR)$(objectsdir)/$(lib.name)
+#
+# Default for 'objectsdir' is defined per platform and follows this convention:
+# https://puredata.info/docs/faq/how-do-i-install-externals-and-help-files
+#
+# Linux:    /usr/local/lib/pd-externals
+# OSX:      ~/Library/Pd
+# Windows:  %APPDATA%/Pd
+#
+# The rationale for not installing to ~/pd-externals by default on Linux
+# is that some people share the home dir between 32 and 64 bit installations.
+#
+#
+#=== targets ===================================================================
+#
+#
+# all: build $(executables) plus optional pre and post targets
+# pre: target to build before $(executables)
+# post: target to build after $(executables)
+# alldebug: build all with -g option turned on for debug symbols
+# <classname>: force clean build of an individual class
+# <sourcefile>.pre: make preprocessor output file in current working directory
+# <sourcefile>.lst: make asm/source output file in current working directory
+#
+# install: install executables and data files
+# clean: remove build products from source tree
+#
+# help: print help text
+# vars: print makefile variables
+# allvars: print all variables
+# depend: print generated prerequisites
+# coffee: dummy target
+#
+# Variable $(executables) expands to class executables plus optional shared lib,
+# or alternatively to single lib executable when make-lib-executable=true.
+# Targets pre and post can be defined by library makefile. Make sure to include
+# Makefile.pdlibbuilder first so default target all will not be redefined.
+#
+#
+#=== Pd-extended libdir concept ================================================
+#
+#
+# For libdir layout as conceived by Hans-Christoph Steiner, see:
+#
+# https://puredata.info/docs/developer/Libdir
+#
+# Files README.txt, LICENSE.txt and <lib.name>-meta.pd are part of the libdir
+# convention. Help patches for each class and abstraction are supposed to be
+# available. Makefile.pdlibbuilder does not force the presence of these files
+# however. It does not automatically include such files in libdir installations.
+# Data files you want to include in distributions must be defined explicitly in
+# your Makefile.
+#
+#
+#=== Makefile.pdlibbuilder syntax conventions ==================================
+#
+#
+# Makefile.pdlibbuilder variable names are lower case. Default make variables,
+# environment variables, and standard user variables (CC, CXX, CFLAGS, DESTDIR)
+# are upper case. Use target 'allvars' to print all variables and their values.
+#
+# 'Fields' in data variables are separated by dots, like in 'foo.class.sources'.
+# Words in variables expressing a function or command are separated by dashes, 
+# like in 'make-lib-executable'.
+#
+#
+#=== useful make options =======================================================
+#
+#
+# Use 'make -d <target>' to print debug details of the make process.
+# Use 'make -p <target>' to print make's database.
+#
+#
+#=== TODO ======================================================================
+#
+#
+# - decide whether to use -static-libgcc or shared dll in MinGW
+# - cygwin support
+# - android support
+# - Windows 64 bit support
+# - figure out how to handle '$' in filenames
+# - add makefile template targets dpkg-source dist libdir distclean tags?
+#
+#
+#=== end of documentation sections =============================================
+#
+# 
+################################################################################
+################################################################################
+################################################################################
+
+
+# GNU make version 3.81 (2006) or higher is required because of the following:
+# - function 'info'
+# - variable '.DEFAULT_GOAL'
+
+# force exit when make version is < 3.81
+ifneq ($(firstword $(sort 3.81 $(MAKE_VERSION))), 3.81)
+  $(error GNU make version 3.81 or higher is required)
+endif
+
+# Relative path to externals root dir in multi-lib source tree like 
+# pd-extended SVN. Default is parent of current working directory. May be
+# defined differently in including makefile. This variable is used to probe for
+# paths.
+externalsdir ?= ..
+
+# variable you can use to check if Makefile.pdlibbuilder is already included
+Makefile.pdlibbuilder = true
+
+
+################################################################################
+### variables: library name and version ########################################
+################################################################################
+
+
+# strip possibles spaces from lib.name, they mess up calculated file names
+lib.name := $(strip $(lib.name))
+
+# if meta file exists, check library version 
+metafile := $(wildcard $(lib.name)-meta.pd)
+
+ifdef metafile
+  lib.version := $(shell sed -n \
+    's|^\#X text [0-9][0-9]* [0-9][0-9]* VERSION \(.*\);|\1|p' \
+    $(metafile))
+endif
+
+
+################################################################################
+### variables: files ###########################################################
+################################################################################
+
+
+#=== sources ===================================================================
+
+
+# (re)define <classname>.class.sources using file names in class.sources
+
+define add-class-source
+$(notdir $(basename $v)).class.sources += $v
+endef
+
+$(foreach v, $(class.sources), $(eval $(add-class-source)))
+
+# derive class names from <classname>.class.sources variables
+sourcevariables := $(filter %.class.sources, $(.VARIABLES))
+classes := $(basename $(basename $(sourcevariables)))
+
+# accumulate all source files specified in makefile
+classes.sources := $(sort $(foreach v, $(sourcevariables), $($v)))
+all.sources := $(classes.sources) $(lib.setup.sources) \
+  $(shared.sources) $(common.sources)
+
+
+#=== object files ==============================================================
+
+
+# construct object filenames from all C and C++ source file names
+classes.objects := $(addsuffix .o, $(basename $(classes.sources)))
+common.objects := $(addsuffix .o, $(basename $(common.sources)))
+shared.objects := $(addsuffix .o, $(basename $(shared.sources)))
+lib.setup.objects := $(addsuffix .o, $(basename $(lib.setup.sources)))
+all.objects = $(classes.objects) $(common.objects) $(shared.objects) \
+  $(lib.setup.objects)
+
+
+#=== executables ===============================================================
+
+
+# use recursive variables here because executable extension is not yet known
+
+# construct class executable names from class names
+classes.executables = $(addsuffix .$(extension), $(classes))
+
+# construct shared lib executable name if shared sources are defined
+ifdef shared.sources
+  shared.lib = lib$(lib.name).$(shared.extension)
+else
+  shared.lib =
+endif
+
+
+################################################################################
+### variables per platform #####################################################
+################################################################################
+
+
+#=== flags per architecture ====================================================
+
+
+# Set architecture-dependent flags, mainly for Linux. For Mac and Windows, 
+# arch.flags are overriden below.
+
+machine := $(shell uname -m)
+
+# Raspberry Pi 1st generation
+ifeq ($(machine), armv6l)
+  arch.flags = -march=armv6 -mfpu=vfp -mfloat-abi=hard
+endif
+
+# Beagle, Udoo, RPi2 etc.
+ifeq ($(machine), armv7l)
+  arch.flags = -march=armv7-a -mfpu=vfpv3 -mfloat-abi=hard
+endif
+
+# Intel 32 bit, build with SSE and SSE2 instructions
+ifeq ($(findstring $(machine), i386 i686), $(machine))
+  arch.flags = -march=pentium4 -mfpmath=sse -msse -msse2
+endif
+
+# Intel/AMD 64 bit, build with SSE, SSE2 and SSE3 instructions
+ifeq ($(findstring $(machine), ia64 x86_64), $(machine))
+  arch.flags = -march=core2 -mfpmath=sse -msse -msse2 -msse3 
+endif
+
+
+#=== operating system ==========================================================
+
+
+# The following systems are defined: Linux, Darwin, Windows. GNU and
+# GNU/kFreeBSD are treated as Linux to get the same options. 
+
+uname := $(shell uname)
+
+ifeq ($(findstring $(uname), Linux GNU GNU/kFreeBSD), $(uname))
+  system = Linux
+endif
+
+ifeq ($(uname), Darwin)
+  system = Darwin
+endif
+
+ifeq ($(findstring MINGW, $(uname)), MINGW)
+  system = Windows
+endif
+
+# TODO: Cygwin, Android
+
+
+#=== flags and paths for Linux =================================================
+
+
+ifeq ($(system), Linux)
+  prefix = /usr/local
+  libdir := $(prefix)/lib
+  pkglibdir = $(libdir)/pd-externals
+  pdincludepath := $(firstword $(wildcard \
+    $(externalsdir)/../pd/src \
+    /usr/include/pdextended \
+    /usr/include/pd))
+  extension = pd_linux
+  cpp.flags := -DUNIX
+  c.flags := -fpic
+  c.ldflags := -rdynamic -shared -fpic -Wl,-rpath,"\$$ORIGIN",--enable-new-dtags
+  c.ldlibs := -lc -lm
+  cxx.flags := -fpic -fcheck-new
+  cxx.ldflags := -rdynamic -shared -fpic -Wl,-rpath,"\$$ORIGIN",--enable-new-dtags
+  cxx.ldlibs := -lc -lm -lstdc++
+  shared.extension = so
+  shared.ldflags := -rdynamic -fpic -shared -Wl,-soname,$(shared.lib)
+  stripflags = --strip-unneeded -R .note -R .comment
+endif
+
+
+#=== flags and paths for Darwin ================================================
+
+
+# On OSX we try to build fat binaries by default. It is assumed that OSX i386
+# can build for ppc and OSX x86_64 can't. TODO: try to refine this condition.
+# LLVM-clang doesn't support -fcheck-new, therefore this flag is omitted for
+# OSX x86_64.
+
+ifeq ($(system), Darwin)
+  pkglibdir = $(HOME)/Library/Pd
+  pdincludepath := $(firstword $(wildcard \
+    $(externalsdir)/../pd/src \
+    /Applications/Pd-extended*.app/Contents/Resources/include/pdextended \
+    /Applications/Pd*.app/Contents/Resources/src))
+  extension = pd_darwin
+  arch.flags =
+  cpp.flags := -DUNIX -DMACOSX -I /sw/include
+  c.flags := 
+  c.ldflags := -undefined suppress -flat_namespace -bundle
+  c.ldlibs := -lc
+  cxx.ldflags := -undefined suppress -flat_namespace -bundle
+  cxx.ldlibs := -lc
+  shared.extension = dylib
+  shared.ldflags = -dynamiclib -undefined dynamic_lookup \
+    -install_name @loader_path/$(shared.lib) \
+    -compatibility_version 1 -current_version 1.0
+  stripflags = -x
+  ifeq ($(machine), i386)
+    cxx.flags := -fcheck-new
+    arch.flags := -arch ppc -arch i386 -arch x86_64 -mmacosx-version-min=10.4
+  endif
+  ifeq ($(machine), x86_64)
+    arch.flags := -arch i386 -arch x86_64 -mmacosx-version-min=10.5
+  endif
+endif
+
+
+#=== flags and paths for Windows ===============================================
+
+
+# Standard paths on Windows contain spaces, and GNU make functions treat such
+# paths as lists, with unintended effects. Therefore we must use shell function
+# ls instead of make's wildcard, and probe for each standard path individually.
+# Using double quotes around paths with spaces is obligatory. Since some path
+# variables are assembled or re-expanded later, great care must be taken to put
+# quotes at appropriate points throughout the makefile. Thanks, Bill.
+
+# paths for 32-bit executables on 64-bit Windows aren't yet defined here (TODO)
+ifeq ($(system), Windows)
+  pkglibdir := $(APPDATA)/Pd
+  pdbinpath := $(wildcard $(externalsdir)/../pd/bin)
+  pdincludepath := $(wildcard $(externalsdir)/../pd/src)
+  ifndef pdbinpath
+    pdbinpath := $(shell ls -d "$(PROGRAMFILES)/pd/bin")
+  endif
+  ifndef pdincludepath
+    pdincludepath := $(shell ls -d "$(PROGRAMFILES)/pd/include/pdextended")
+  endif
+  ifndef pdincludepath
+    pdincludepath := $(shell ls -d "$(PROGRAMFILES)/pd/src")
+  endif
+endif
+
+# On Windows we build 32 bit by default to match Pd(-extended) binary 
+# distributions. This may change in the future.
+# TODO: decide whether -mms-bitfields should be specified.
+ifeq ($(system), Windows)
+  extension = dll
+  CC = gcc
+  CXX = g++
+  arch.flags := -march=pentium4 -msse -msse2 -mfpmath=sse
+  cpp.flags := -DMSW -DNT
+  c.flags :=
+  c.ldflags := -static-libgcc -shared \
+    -Wl,--enable-auto-import "$(pdbinpath)/pd.dll"
+  c.ldlibs :=
+  cxx.flags := -fcheck-new
+  cxx.ldflags := -static-libstdc++ -shared \
+    -Wl,--enable-auto-import "$(pdbinpath)/pd.dll"
+  cxx.ldlibs :=
+  shared.extension = dll
+  shared.ldflags := -static-libgcc -shared "$(pdbinpath)/pd.dll"
+  stripflags = --strip-unneeded -R .note -R .comment
+endif
+
+
+#=== paths =====================================================================
+
+
+# Default pkglibdir is specified above per operating system. It is aliased as 
+# 'objectsdir' to retain compatibility with pd-extended template. Assignment
+# operator '?=' is used to enable a project-relative path definition in the
+# including makefile.
+objectsdir ?= $(pkglibdir)
+
+# base path where all components of the lib will be installed by default
+installpath := $(DESTDIR)$(objectsdir)/$(lib.name)
+
+# check if pdincludepath contains spaces (as is often the case on Windows)
+# if so, store the path so we can later do checks with it
+pdincludepathwithspaces := $(if $(word 2, $(pdincludepath)), $(pdincludepath))
+
+
+#=== accumulated build flags ===================================================
+
+
+# From GNU make docs: 'Users expect to be able to specify CFLAGS freely
+# themselves.' So we use CFLAGS to define platform-independent options which 
+# are not strictly required for compilation: optimizations and warnings. CFLAGS
+# can be safely overriden using a make command argument.
+# Variables cflags, ldflags and ldlibs may be defined in including makefile.
+
+optimization.flags = -O3 -ffast-math -funroll-loops -fomit-frame-pointer
+warn.flags = -Wall -Wextra -Wshadow -Winline -Wstrict-aliasing
+
+# suppress -Wunused-variable & Co if you don't want to clutter a build log
+ifdef suppress-wunused
+  warn.flags += $(addprefix -Wno-unused-, function parameter value variable)
+endif
+
+CFLAGS = $(warn.flags) $(optimization.flags)
+
+# preprocessor flags
+cpp.flags += -DPD -I "$(pdincludepath)"
+
+# flags for C compiler / linker
+c.flags := $(cpp.flags) $(c.flags) $(cflags) $(CFLAGS)
+c.ldflags := $(c.ldflags) $(ldflags)
+c.ldlibs := $(c.ldlibs) $(ldlibs)
+
+# flags for C++ compiler / linker
+cxx.flags := $(cpp.flags) $(cxx.flags) $(cflags) $(CFLAGS)
+cxx.ldflags := $(cxx.ldflags) $(ldflags)
+cxx.ldlibs := $(cxx.ldlibs) $(ldlibs)
+
+
+################################################################################
+### variables: tools ###########################################################
+################################################################################
+
+
+# aliases so we can later define 'compile-$1' and set 'c' or 'cxx' as argument
+compile-c := $(CC)
+compile-cxx := $(CXX)
+
+
+################################################################################
+### checks #####################################################################
+################################################################################
+
+
+# At this point most variables are defined. Now do some checks and info's
+# before rules begin.
+
+# 'forward declaration' of default target, needed to do checks
+all:
+
+# To avoid unpredictable results, make sure the default target is not redefined
+# by including makefile. 
+ifneq ($(.DEFAULT_GOAL), all)
+  $(error Default target must be 'all'.)
+endif
+
+# find out which target(s) will be made
+ifdef MAKECMDGOALS
+  goals := $(MAKECMDGOALS)
+else
+  goals := all
+endif
+
+# store path to Pd API m_pd.h if it is found
+ifdef pdincludepath
+  mpdh := $(shell ls "$(pdincludepath)/m_pd.h")
+endif
+
+# when making target all, check if m_pd.h is found and print info about it
+ifeq ($(goals), all)
+  $(if $(mpdh), \
+    $(info ++++ info: using Pd API $(mpdh)), \
+    $(warning Where is Pd API m_pd.h? Do 'make help' for info.))
+endif
+
+# print target info
+$(info ++++ info: making target $(goals) $(if $(lib.name),in lib $(lib.name)))
+
+# when installing, print installpath info
+$(if $(filter install install-lib, $(goals)), $(info ++++ info: \
+  installpath is '$(installpath)'))
+
+
+#=== define executables ========================================================
+
+
+# By default we build class executables, and optionally a shared dynamic link
+# lib. When make-lib-executable=yes we build all classes into a single lib
+# executable, on the condition that variable lib.setup.sources is defined.
+
+ifeq ($(make-lib-executable),yes)
+  $(if $(lib.setup.sources), ,\
+    $(error Can not build library blob because lib.setup.sources is undefined))
+  executables := $(lib.name).$(extension)
+else
+  executables := $(classes.executables) $(shared.lib)
+endif
+
+
+################################################################################
+### rules: special targets #####################################################
+################################################################################
+
+
+# Disable built-in rules. If some target can't be built with the specified
+# rules, it should not be built at all.
+MAKEFLAGS += --no-builtin-rules
+
+.PRECIOUS:
+.SUFFIXES:
+.PHONY: all pre post build-classes build-lib \
+        $(classes) $(makefiledirs) $(makefiles) \
+        install install-executables install-datafiles install-datadirs \
+        force clean vars allvars depend help
+
+
+################################################################################
+### rules: build targets #######################################################
+################################################################################
+
+
+# Target all forces the build of targets [pre $(executables) post] in
+# deterministic order. Target $(executables) builds class executables plus 
+# optional shared lib or alternatively a single lib executable when 
+# make-lib-executable=true. Targets pre and post are optionally defined by
+# library makefile.
+
+all: post
+post: $(executables)
+$(executables): pre
+pre:
+
+all:
+	$(info ++++info: target all in lib $(lib.name) completed)
+
+# build all with -g option turned on for debug symbols
+alldebug: c.flags += -g
+alldebug: cxx.flags += -g
+alldebug: all
+
+
+#=== class executable ==========================================================
+
+
+# recipe for linking objects in class executable
+# argument $1 = compiler type (c or cxx)
+# argument $2 = class basename
+define link-class
+  $(compile-$1) \
+  $(arch.flags) \
+  $($1.ldflags) $($2.class.ldflags) \
+  -o $2.$(extension) \
+  $(addsuffix .o, $(basename $($2.class.sources))) \
+  $(addsuffix .o, $(basename $(common.sources))) \
+  $($1.ldlibs) $($2.class.ldlibs) $(shared.lib)
+endef
+
+# general rule for linking object files in class executable
+%.$(extension): $(shared.lib)
+	$(info ++++ info: linking objects in $@ for lib $(lib.name))
+	$(if $(filter %.cc %.cpp, $($*.class.sources)), \
+        $(call link-class,cxx,$*), \
+        $(call link-class,c,$*))
+
+
+#=== library blob ==============================================================
+
+
+# build all classes into single executable
+build-lib: $(lib.name).$(extension)
+	$(info ++++ info: library blob $(lib.name).$(extension) completed)
+
+# recipe for linking objects in lib executable
+# argument $1 = compiler type (c or cxx)
+define link-lib
+  $(compile-$1) \
+  $(arch.flags) \
+  $($1.ldflags) $(lib.ldflags) \
+  -o $(lib.name).$(extension) $(all.objects) \
+  $($1.ldlibs) $(lib.ldlibs)
+endef
+
+# rule for linking objects in lib executable
+# declared conditionally to avoid name clashes
+ifeq ($(make-lib-executable),yes)
+$(lib.name).$(extension): $(all.objects)
+	$(if $(filter %.cc %.cpp, $(all.sources)), \
+        $(call link-lib,cxx), \
+        $(call link-lib,c))
+endif
+
+
+#=== shared dynamic lib ========================================================
+
+
+# recipe for linking objects in shared executable
+# argument $1 = compiler type (c or cxx)
+define link-shared
+  $(compile-$1) \
+  $(arch.flags) \
+  $(shared.ldflags) \
+  -o lib$(lib.name).$(shared.extension) $(shared.objects) \
+  $($1.ldlibs) $(shared.ldlibs)
+endef
+
+# rule for linking objects in shared executable
+# build recipe is in macro 'link-shared'
+lib$(lib.name).$(shared.extension): $(shared.objects)
+	$(info ++++ info: linking objects in shared lib $@)
+	$(if $(filter %.cc %.cpp, $(shared.sources)), \
+        $(call link-shared,cxx), \
+        $(call link-shared,c))
+
+
+#=== object files ==============================================================
+
+
+# recipe to make .o file from source
+# argument $1 is compiler type (c or cxx)
+define make-object-file
+  $(info ++++ info: making $@ in lib $(lib.name))
+  $(compile-$1) \
+  $($1.flags) \
+  $(arch.flags) -o $@ -c $<
+endef
+
+# Three rules to create .o files. These are double colon 'terminal' rules,
+# meaning they are the last in a rules chain.
+
+%.o:: %.c
+	$(call make-object-file,c)
+
+%.o:: %.cc
+	$(call make-object-file,cxx)
+
+%.o:: %.cpp
+	$(call make-object-file,cxx)
+
+
+#=== explicit prerequisites for class executables ==============================
+
+
+# For class executables, prerequisite rules are declared in run time. Target
+# 'depend' prints these rules for debugging purposes.
+
+# declare explicit prerequisites rule like 'class: class.extension'
+# argument $v is class basename
+define declare-class-target
+$v: $v.$(extension)
+endef
+
+# declare explicit prerequisites rule like 'class.extension: object1.o object2.o'
+# argument $v is class basename
+define declare-class-executable-target
+$v.$(extension): $(addsuffix .o, $(basename $($v.class.sources))) \
+  $(addsuffix .o, $(basename $(common.sources)))
+endef
+
+# evaluate explicit prerequisite rules for all classes
+$(foreach v, $(classes), $(eval $(declare-class-target)))
+$(foreach v, $(classes), $(eval $(declare-class-executable-target)))
+
+
+#=== implicit prerequisites for class executables ==============================
+
+
+# Evaluating implicit prerequisites (header files) with help from the
+# preprocessor is 'expensive' so this is done conditionally and selectively.
+# Note that it is also possible to trigger a build via install targets, in
+# which case implicit prerequisites are not checked.
+
+# When the Pd include path contains spaces it will mess up the implicit
+# prerequisites rules so we do not evaluate them in that case.
+
+ifndef pdincludepathwithspaces
+  must-build-everything := $(filter all default lib, $(goals))
+  must-build-class := $(filter $(classes), $(goals))
+  must-build-sources := $(foreach v, $(must-build-class), $($v.class.sources))
+endif
+
+# declare implicit prerequisites rule like 'object.o: header1.h header2.h ...'
+# argument $1 is input source file(s)
+define declare-object-target
+$(filter %.o: %.h, $(shell $(CPP) $(c.flags) -MM $1)) $(MAKEFILE_LIST)
+endef
+
+# evaluate implicit prerequisite rules when rebuilding everything
+ifdef must-build-everything
+  $(if $(wildcard $(all.objects)), \
+  $(info ++++ info: evaluating implicit prerequisites in lib $(lib.name).....) \
+  $(foreach v, $(all.sources), $(eval $(call declare-object-target, $v))))
+endif
+
+# evaluate implicit prerequisite rules when selectively building classes
+ifdef must-build-class
+  $(foreach v, $(must-build-sources), \
+  $(eval $(call declare-object-target, $v)))
+  $(foreach v, $(shared.sources), \
+  $(eval $(call declare-object-target, $v)))
+endif
+
+
+################################################################################
+### rules: preprocessor and assembly files #####################################
+################################################################################
+
+
+# Preprocessor and assembly output files for bug tracing etc. They are not part
+# of the build processes for executables. By default these files are created in
+# the current working directory. Dependency tracking is not performed, the build
+# is forced instead to make sure it's up to date.
+
+force:
+
+
+#=== preprocessor file =========================================================
+
+
+# make preprocessor output file with extension .pre
+# argument $1 = compiler type (c or cxx)
+define make-preprocessor-file
+  $(info ++++ info: making preprocessor output file $(notdir $*.pre) \
+  in current working directory)
+  $(compile-$1) -E $< $(c.flags) $($1.flags) -o $(notdir $*.pre)
+endef
+
+%.pre:: %.c force
+	$(call make-preprocessor-file,c)
+
+%.pre:: %.cc force
+	$(call make-preprocessor-file,cxx)
+
+%.pre:: %.cpp force 
+	$(call make-preprocessor-file,cxx)
+
+
+#=== assembly file =============================================================
+
+
+# make C / assembly interleaved output file with extension .lst
+# argument $1 = compiler type (c or cxx)
+define make-assembly-file
+  $(info ++++ info: making assembly output file $(notdir $*.lst) \
+  in current working directory)
+  $(compile-$1) \
+  -c -Wa,-a,-ad -fverbose-asm \
+  $($1.flags) \
+  $(arch.flags) \
+  $< > $(notdir $*.lst)
+endef
+
+%.lst:: %.c force
+	$(call make-assembly-file,c)
+
+%.lst:: %.cc force
+	$(call make-assembly-file,cxx)
+
+%.lst:: %.cpp force
+	$(call make-assembly-file,cxx)
+
+
+################################################################################
+### rules: installation targets ################################################
+################################################################################
+
+
+# Install targets depend on successful exit status of target all because nothing
+# must be installed in case of a build error.
+
+
+# -p = preserve time stamps
+# -m = set permission mode (as in chmod)
+# -d = create all components of specified directories
+INSTALL = install
+INSTALL_PROGRAM := $(INSTALL) -p -m 644
+INSTALL_DATA := $(INSTALL) -p -m 644
+INSTALL_DIR := $(INSTALL) -m 755 -d
+
+# strip spaces from file names
+executables := $(strip $(executables))
+datafiles := $(strip $(datafiles))
+datadirs := $(strip $(datadirs))
+
+# Do not make any install sub-target with empty variable definition because the
+# install program would exit with an error.
+install: $(if $(executables), install-executables)
+install: $(if $(datafiles), install-datafiles)
+install: $(if $(datadirs), install-datadirs)
+
+install-executables: all
+	$(INSTALL_DIR) -v "$(installpath)"
+	$(INSTALL_PROGRAM) $(executables) "$(installpath)"
+	$(info ++++ info: executables of lib $(lib.name) installed \
+        from $(CURDIR) to $(installpath))
+
+install-datafiles: all
+	$(INSTALL_DIR) -v "$(installpath)"
+	$(INSTALL_DATA) $(datafiles) "$(installpath)"
+	$(info ++++ info: data files of lib $(lib.name) installed \
+        from $(CURDIR) to $(installpath))
+
+install-datadirs: all
+	$(foreach v, $(datadirs), $(INSTALL_DIR) "$(installpath)/$v";)
+	$(foreach v, $(datadirs), \
+        $(INSTALL_DATA) $(wildcard $v/*) "$(installpath)/$v";)
+	$(info ++++ info: data directories of lib $(lib.name) installed \
+        from $(CURDIR) to $(installpath))
+
+
+################################################################################
+### rules: distribution targets ################################################
+################################################################################
+
+
+# TODO
+# These targets are implemented in Makefile Template, but I have to figure out
+# how to do it under the not-so-strict conditions of Makefile.pdlibbuilder.
+
+# make source package
+dist:
+	@echo "target dist not yet implemented"
+
+# make Debian source package
+dpkg-source:
+	@echo "target dpkg-source not yet implemented"
+
+$(ORIGDIR):
+
+$(DISTDIR):
+
+
+################################################################################
+### rules: clean targets #######################################################
+################################################################################
+
+
+# delete build products from build tree
+clean:
+	rm -f $(all.objects)
+	rm -f $(classes.executables) $(lib.name).$(extension) $(shared.lib)
+	rm -f *.pre *.lst
+
+# remove distribution directories and tarballs from build tree
+distclean: clean
+	@echo "target distclean not yet implemented"
+
+
+################################################################################
+### rules: submake targets #####################################################
+################################################################################
+
+
+# Iterate over sub-makefiles or makefiles in other directories.
+
+# When 'continue-make=yes' is set, sub-makes will report 'true' to the parent
+# process regardless of their real exit status. This prevents the parent make
+# from being aborted by a sub-make error. Useful when you want to quickly find
+# out which sub-makes from a large set will succeed.
+ifeq ($(continue-make),yes)
+  continue = || true
+endif
+
+# These targets will trigger sub-make processes for entries in 'makefiledirs'
+# and 'makefiles'.
+all alldebug install clean distclean dist dkpg-source: \
+        $(makefiledirs) $(makefiles)
+
+# this expands to identical rules for each entry in 'makefiledirs'
+$(makefiledirs):
+	$(MAKE) --directory=$@ $(MAKECMDGOALS) $(continue)
+
+# this expands to identical rules for each entry in 'makefiles'
+$(makefiles):
+	$(MAKE) --directory=$(dir $@) --makefile=$(notdir $@) $(MAKECMDGOALS) $(continue)
+
+
+################################################################################
+### rules: convenience targets #################################################
+################################################################################
+
+
+#=== show variables ============================================================
+
+
+# Several 'function' macro's cause errors when expanded within a rule or without
+# proper arguments. Variables which are set with the define directive are only
+# shown by name for that reason.
+functions = \
+add-class-source \
+declare-class-target \
+declare-class-executable-target \
+declare-object-target \
+link-class \
+link-lib \
+link-shared \
+make-object-file \
+make-preprocessor-file \
+make-assembly-file
+
+
+# show variables from makefiles
+vars:
+	$(info ++++ info: showing makefile variables:)
+	$(foreach v,\
+        $(sort $(filter-out $(functions) functions, $(.VARIABLES))),\
+        $(if $(filter file, $(origin $v)),\
+        $(info variable $v = $($v))))
+	$(foreach v, $(functions), $(info 'function' name: $v))
+	@echo
+
+# show all variables
+allvars:
+	$(info ++++ info: showing default, automatic and makefile variables:)
+	$(foreach v, \
+        $(sort $(filter-out $(functions) functions, $(.VARIABLES))), \
+        $(info variable ($(origin $v)) $v = $($v)))
+	$(foreach v, $(functions), $(info 'function' name: $v))
+	@echo
+
+
+#=== show dependencies =========================================================
+
+
+# show generated prerequisites rules
+depend:
+	$(info ++++ info: generated prerequisite rules)
+	$(foreach v, $(classes), $(info $(declare-class-target)))
+	$(foreach v, $(classes), $(info $(declare-class-executable-target)))
+	$(foreach v, $(all.sources), $(info $(call declare-object-target, $v)))
+	@echo
+
+
+#=== show help text ============================================================
+
+
+# brief info about targets and paths
+
+ifdef mpdh
+  mpdhinfo := $(mpdh)
+else
+  mpdhinfo := m_pd.h was not found. Is Pd(-extended) installed?
+endif
+
+help:
+	@echo
+	@echo "  Main targets:"
+	@echo "    all:     build executables (default target)"
+	@echo "    install: install all components of the library"
+	@echo "    vars:    print makefile variables for troubleshooting"
+	@echo "    allvars: print all variables for troubleshooting"
+	@echo "    help:    print this help text"
+	@echo
+	@echo "  Pd API m_pd.h:"
+	@echo "    $(mpdhinfo)"
+	@echo "  You may specify your preferred Pd include path as argument to"
+	@echo "  the make command, like 'pdincludepath=path/to/pd/src'."
+	@echo
+	@echo "  Path for installation of your libdir(s):"
+	@echo "    $(objectsdir)"
+	@echo "  Alternatively you may specify your path for installation as argument"
+	@echo "  to the make command, like 'objectsdir=path/to/pd-externals'."
+	@echo
+	@echo "  Default paths are listed in the doc sections in Makefile.pdlibbuilder."
+	@echo
+
+
+#=== dummy target ==============================================================
+
+
+coffee:
+	@echo "Makefile.pdlibbuilder: Can not make coffee. Sorry."
+
+
+################################################################################
+### end of rules sections ######################################################
+################################################################################
+
+
+# for syntax highlighting in vim and github
+# vim: set filetype=make:
+
diff --git a/pd-lib-builder/README.md b/pd-lib-builder/README.md
new file mode 100644
index 0000000..9c28603
--- /dev/null
+++ b/pd-lib-builder/README.md
@@ -0,0 +1,58 @@
+
+
+### Makefile.pdlibbuilder ###
+
+Helper makefile for Pure Data external libraries.
+Written by Katja Vetter March-June 2015 for the public domain. No warranties.
+Inspired by Hans Christoph Steiner's Makefile Template and Stephan Beal's
+ShakeNMake.
+
+GNU make version >= 3.81 required.
+
+
+### characteristics ###
+
+
+* defines build settings based on autodetected OS and architecture
+* defines rules to build Pd class- or lib executables from C or C++ sources
+* defines rules for libdir installation
+* defines convenience targets for developer and user
+* evaluates implicit dependencies for non-clean builds
+
+
+### basic usage ###
+
+
+In your Makefile, define your Pd lib name and class files, and include
+Makefile.pdlibbuilder at the end of the Makefile. Like so:
+
+
+      # Makefile for mylib
+
+      lib.name = mylib
+
+      class.sources = myclass1.c myclass2.c
+
+      datafiles = myclass1-help.pd myclass2-help.pd README.txt LICENSE.txt
+
+      include Makefile.pdlibbuilder
+
+
+For files in class.sources it is assumed that class name == source file
+basename. The default target builds all classes as individual executables
+with Pd's default extension for the platform. For anything more than the
+most basic usage, read the documentation sections in Makefile.pdlibbuilder.
+
+
+### examples ###
+
+
+Here are three projects using the Makefile.pdlibbuilder approach:
+
+https://github.com/pure-data/helloworld
+
+http://sourceforge.net/p/pure-data/svn/HEAD/tree/trunk/externals/miXed/cyclone/Makefile.cyclone
+
+https://github.com/pure-data/xeq
+
+More examples will be referenced here when they are available. 
diff --git a/popen-help.pd b/popen-help.pd
index e37d8e9..08120d0 100644
--- a/popen-help.pd
+++ b/popen-help.pd
@@ -1,68 +1,79 @@
-#N canvas 0 195 644 383 10;
-#X obj 0 0 cnv 8 100 60 empty empty popen 10 20 1 18 -262144 -1109
-0;
-#X text 13 362 (c) Moonix: Antoine Rousseau 2003;
-#X msg 31 74 open process;
-#X text 12 57 open: popen for writing;
-#X msg 240 76 ropen process;
-#X text 221 59 ropen: popen for reading;
-#X msg 466 76 close;
-#X text 428 60 close (quit) current process;
-#X text 108 13 processus in/out (linux only);
-#X text 108 26 DANGEROUS: deadlocks are easy!!!!;
-#N canvas 0 0 850 359 example 0;
-#X obj 458 194 popen;
-#X msg 516 167 close;
-#X obj 82 311 popen;
-#X msg 151 261 close;
-#X msg 76 190 list cat to where you want;
-#X msg 24 145 open cat > /tmp/tmp_fifo;
-#X msg 431 138 ropen cat /tmp/tmp_fifo;
-#X obj 38 89 system;
-#X msg 38 67 mkfifo /tmp/tmp_fifo;
-#X obj 76 258 symbol \;;
-#X obj 76 236 t b a;
-#X symbolatom 433 284 0 0 0 0 - - -;
-#X text 10 17 example: fifo read/write. RESPECT THE NUMBERS for commands
-!;
-#X text 430 120 3: open for reading;
-#X msg 92 213 list Caution not to lock your computer...;
-#X text 517 183 6: close reading process;
-#X obj 433 260 l2s;
-#X obj 458 227 print ropen;
-#X text 76 173 4: write to fifo (as many times you want);
-#X text 36 46 1: create the fifo (if not done);
-#X text 147 244 5: close writing process FIRST;
-#X text 23 125 2: open the fifo for writing FIRST;
-#X text 503 248 Caution: popen/ropen waits for a " \; ";
-#X text 565 260 to send its buffer (pd style).;
-#X connect 0 0 17 0;
-#X connect 0 0 16 0;
-#X connect 1 0 0 0;
-#X connect 3 0 2 0;
-#X connect 4 0 10 0;
-#X connect 5 0 2 0;
-#X connect 6 0 0 0;
-#X connect 8 0 7 0;
-#X connect 9 0 2 0;
-#X connect 10 0 9 0;
-#X connect 10 1 2 0;
-#X connect 14 0 10 0;
-#X connect 16 0 11 0;
-#X restore 19 161 pd example;
-#X obj 31 109 popen;
-#X text 20 191 Remarks:;
-#X text 46 204 The danger here comes from the fact processes lauched
-by;
-#X text 47 215 popen runs concurrently with pd: if they are blocking
-\, pd;
-#X text 46 228 is blocking too. Very dangerous if pd has real-time
-priority: it blocks all the sytem. You have to switch off the computer...
-;
-#X text 47 267 It's much safer to use netsend/netreceive in conjonction
-with pdsend/pdreceive.;
-#X obj 206 333 system;
-#X text 46 297 You can use "at now" to lauch programs totally independantly
-from Pd:;
-#X msg 206 313 echo xclock -display 0:0 | at now;
-#X connect 19 0 17 0;
+#N canvas 1 88 644 383 10;
+#X obj 0 0 cnv 8 100 60 empty empty popen 10 20 1 18 -262144 -1109
+0;
+#X text 13 362 (c) Moonix: Antoine Rousseau 2003;
+#X msg 31 74 open process;
+#X text 12 57 open: popen for writing;
+#X msg 240 76 ropen process;
+#X text 221 59 ropen: popen for reading;
+#X msg 466 76 close;
+#X text 428 60 close (quit) current process;
+#X text 108 13 processus in/out (linux only);
+#X text 108 26 DANGEROUS: deadlocks are easy!!!!;
+#N canvas 0 0 850 359 example 0;
+#X obj 458 194 popen;
+#X msg 516 167 close;
+#X obj 82 311 popen;
+#X msg 151 261 close;
+#X msg 76 190 list cat to where you want;
+#X msg 24 145 open cat > /tmp/tmp_fifo;
+#X msg 431 138 ropen cat /tmp/tmp_fifo;
+#X obj 38 89 system;
+#X msg 38 67 mkfifo /tmp/tmp_fifo;
+#X obj 76 258 symbol \;;
+#X obj 76 236 t b a;
+#X symbolatom 433 284 0 0 0 0 - - -;
+#X text 10 17 example: fifo read/write. RESPECT THE NUMBERS for commands
+!;
+#X text 430 120 3: open for reading;
+#X msg 92 213 list Caution not to lock your computer...;
+#X text 517 183 6: close reading process;
+#X obj 433 260 l2s;
+#X obj 458 227 print ropen;
+#X text 76 173 4: write to fifo (as many times you want);
+#X text 36 46 1: create the fifo (if not done);
+#X text 147 244 5: close writing process FIRST;
+#X text 23 125 2: open the fifo for writing FIRST;
+#X text 503 248 Caution: popen/ropen waits for a " \; ";
+#X text 565 260 to send its buffer (pd style).;
+#X connect 0 0 17 0;
+#X connect 0 0 16 0;
+#X connect 1 0 0 0;
+#X connect 3 0 2 0;
+#X connect 4 0 10 0;
+#X connect 5 0 2 0;
+#X connect 6 0 0 0;
+#X connect 8 0 7 0;
+#X connect 9 0 2 0;
+#X connect 10 0 9 0;
+#X connect 10 1 2 0;
+#X connect 14 0 10 0;
+#X connect 16 0 11 0;
+#X restore 19 161 pd example;
+#X obj 31 109 popen;
+#X text 20 191 Remarks:;
+#X text 46 204 The danger here comes from the fact processes lauched
+by;
+#X text 47 215 popen runs concurrently with pd: if they are blocking
+\, pd;
+#X text 46 228 is blocking too. Very dangerous if pd has real-time
+priority: it blocks all the sytem. You have to switch off the computer...
+;
+#X text 47 267 It's much safer to use netsend/netreceive in conjonction
+with pdsend/pdreceive.;
+#X obj 206 333 system;
+#X text 46 297 You can use "at now" to lauch programs totally independantly
+from Pd:;
+#X msg 206 313 echo xclock -display 0:0 | at now;
+#N canvas 370 189 494 344 META 0;
+#X text 12 25 LICENSE GPL v2;
+#X text 12 125 AUTHOR Antoine Rousseau;
+#X text 12 145 HELP_PATCH_AUTHORS Antoine Rousseau. "pd meta" information
+added by Jonathan Wilkes for Pd version 0.42.;
+#X text 12 45 DESCRIPTION processes in/out (linux only);
+#X text 12 65 INLET_0 anything;
+#X text 12 85 OUTLET_0;
+#X text 12 105 OUTLET_1;
+#X text 12 5 KEYWORDS control filesystem;
+#X restore 587 353 pd META;
+#X connect 19 0 17 0;
diff --git a/popen.c b/popen.c
index c97a17c..35f9fbc 100644
--- a/popen.c
+++ b/popen.c
@@ -1,211 +1,216 @@
-/*
-Copyright (C) 2002 Antoine Rousseau 
-
-This library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation; either
-version 2.1 of the License, or (at your option) any later version.
-
-This library 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
-Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with this library; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  
-
-*/
-
-#include "m_pd.h"
-#include "s_stuff.h"
-#include <stdio.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <string.h>
-#define BUFSIZE 4096
-
-typedef struct popen
-{
-    t_object x_obj;
-    FILE *x_file;
-	char x_data[BUFSIZE];
-	int x_count;
-	int x_ropened;
-    t_outlet *x_msgout;
-} t_popen;
-
-t_class *popen_class;
-static t_binbuf *inbinbuf;
-
-
-static void *popen_new(t_symbol *s, int argc, t_atom *argv)
-{
-    t_popen *x;
-
-    x = (t_popen *)pd_new(popen_class);
-
-	x->x_file = NULL;
-	x->x_count=0;
-	x->x_msgout = outlet_new(&x->x_obj, &s_anything);
-	x->x_ropened=0;
-    return (x);
-}
-
-static void popen_close(t_popen *x)
-{
-	if(x->x_ropened) {
-		sys_rmpollfn(fileno(x->x_file));
-		//fflush(x->x_file);
-	}
-	if(x->x_file) pclose(x->x_file);
-	x->x_file=0;
-	x->x_ropened=0;
-}
-
-static void popen_ff(t_popen *x)
-{
-
-}
-
-static void popen_open(t_popen *x, t_symbol *s,int argc, t_atom *argv)
-{
-    char cmd[512],*text;
-    int cmd_len;
-
-    t_binbuf *bb=binbuf_new();
-
-    popen_close(x);
-
-    //post("argc=%d",argc);
-    //post("argv[0]=%s",atom_getsymbol(&argv[0])->s_name);
-
-    binbuf_add(bb,argc,argv);
-    binbuf_gettext(bb, &text,&cmd_len);
-    binbuf_free(bb);
-
-    strncpy(cmd,text,cmd_len);
-    cmd[cmd_len]=0;
-    //post("cmd=%s",cmd);
-
-    x->x_file=popen(cmd,"w");
-
-}
-
-static void popen_list(t_popen *x, t_symbol *s,
-    int argc, t_atom *argv)
-{
-	t_binbuf *bb;
-	char *buf;
-	int l;
-
-	if(!x->x_file) return;
-
-	bb=binbuf_new();
-	binbuf_add(bb,argc,argv);
-	//binbuf_print(bb);
-	binbuf_gettext(bb, &buf,&l);
-	buf[l]=0;
-
-	//printf("popen list: %s\n",buf);
-	fprintf(x->x_file,"%s\n",buf);fflush(x->x_file);
-
-	freebytes(buf,l);
-	binbuf_free(bb);
-}
-
-static void popen_out(t_popen *x, t_binbuf *b)
-{
-    t_atom messbuf[1024];
-    int msg, natom = binbuf_getnatom(b);
-    t_atom *at = binbuf_getvec(b);
-    for (msg = 0; msg < natom;)
-    {
-    	int emsg;
-	for (emsg = msg; emsg < natom && at[emsg].a_type != A_COMMA
-	    && at[emsg].a_type != A_SEMI; emsg++)
-	    	;
-	if (emsg > msg)
-	{
-	    int i;
-	    for (i = msg; i < emsg; i++)
-	    	if (at[i].a_type == A_DOLLAR || at[i].a_type == A_DOLLSYM)
-	    {
-	    	pd_error(x, "popen: got dollar sign in message");
-		goto nodice;
-	    }
-	    if (at[msg].a_type == A_FLOAT)
-	    {
-	    	if (emsg > msg + 1)
-		    outlet_list(x->x_msgout, 0, emsg-msg, at + msg);
-		else outlet_float(x->x_msgout, at[msg].a_w.w_float);
-	    }
-	    else if (at[msg].a_type == A_SYMBOL)
-	    	outlet_anything(x->x_msgout, at[msg].a_w.w_symbol,
-		    emsg-msg-1, at + msg + 1);
-	}
-    nodice:
-    	msg = emsg + 1;
-    }
-}
-
-static void popen_read(t_popen *x,int fd)
-{
-	int len,i=0;
-	unsigned char b;  
-	unsigned char buffer[BUFSIZE];
-	
- 	if((len=read(fd,buffer,BUFSIZE))> 0){	
-
-		for(i=0;i<len;i++){
-			if(x->x_count>=BUFSIZE) x->x_count=0;
-			x->x_data[x->x_count++]=buffer[i];
-			if(buffer[i]==';') {
-				binbuf_text(inbinbuf, x->x_data, x->x_count);
-				x->x_count=0;
-				popen_out(x,inbinbuf);
-			}
-		}		
-	}	
-}
-
-static void popen_ropen(t_popen *x, t_symbol *s,int argc, t_atom *argv)
-{
-    char cmd[512],*text;
-    int cmd_len;
-
-    t_binbuf *bb=binbuf_new();
-
-    popen_close(x);
-
-    //post("argc=%d",argc);
-    //post("argv[0]=%s",atom_getsymbol(&argv[0])->s_name);
-
-    binbuf_add(bb,argc,argv);
-    binbuf_gettext(bb, &text,&cmd_len);
-    binbuf_free(bb);
-
-    strncpy(cmd,text,cmd_len);
-    cmd[cmd_len]=0;
-    //post("cmd=%s",cmd);
-
-    x->x_file=popen(cmd,"r");
-	sys_addpollfn(fileno(x->x_file),(t_fdpollfn)popen_read,(void*)x);
-	x->x_ropened=1;
-}
-
-void popen_setup(void )
-{
-	inbinbuf = binbuf_new();
-    popen_class = class_new(gensym("popen"), (t_newmethod)popen_new,
-    (t_method)popen_close,sizeof(t_popen), 0, A_GIMME, 0);
-    class_addmethod(popen_class, (t_method)popen_close,
-    	gensym("close"), 0);
-    class_addmethod(popen_class, (t_method)popen_open,
-    	gensym("open"), A_GIMME, 0);
-    class_addmethod(popen_class, (t_method)popen_ropen,
-    	gensym("ropen"), A_GIMME, 0);
-    class_addlist(popen_class, popen_list);
-
-}
-
+/*
+Copyright (C) 2002 Antoine Rousseau
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+*/
+
+#include "m_pd.h"
+#include "s_stuff.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <string.h>
+#define BUFSIZE 4096
+
+typedef struct popen
+{
+    t_object x_obj;
+    FILE *x_file;
+    char x_data[BUFSIZE];
+    int x_count;
+    int x_ropened;
+    t_outlet *x_msgout;
+} t_popen;
+
+t_class *popen_class;
+static t_binbuf *inbinbuf;
+
+
+static void *popen_new(t_symbol *s, int argc, t_atom *argv)
+{
+    t_popen *x;
+
+    x = (t_popen *)pd_new(popen_class);
+
+    x->x_file = NULL;
+    x->x_count=0;
+    x->x_msgout = outlet_new(&x->x_obj, &s_anything);
+    x->x_ropened=0;
+    return (x);
+}
+
+static void popen_close(t_popen *x)
+{
+    if(x->x_ropened)
+    {
+        sys_rmpollfn(fileno(x->x_file));
+        //fflush(x->x_file);
+    }
+    if(x->x_file) pclose(x->x_file);
+    x->x_file=0;
+    x->x_ropened=0;
+}
+
+static void popen_ff(t_popen *x)
+{
+
+}
+
+static void popen_open(t_popen *x, t_symbol *s,int argc, t_atom *argv)
+{
+    char cmd[512],*text;
+    int cmd_len;
+
+    t_binbuf *bb=binbuf_new();
+
+    popen_close(x);
+
+    //post("argc=%d",argc);
+    //post("argv[0]=%s",atom_getsymbol(&argv[0])->s_name);
+
+    binbuf_add(bb,argc,argv);
+    binbuf_gettext(bb, &text,&cmd_len);
+    binbuf_free(bb);
+
+    strncpy(cmd,text,cmd_len);
+    cmd[cmd_len]=0;
+    //post("cmd=%s",cmd);
+
+    x->x_file=popen(cmd,"w");
+
+}
+
+static void popen_list(t_popen *x, t_symbol *s,
+                       int argc, t_atom *argv)
+{
+    t_binbuf *bb;
+    char *buf;
+    int l;
+
+    if(!x->x_file) return;
+
+    bb=binbuf_new();
+    binbuf_add(bb,argc,argv);
+    //binbuf_print(bb);
+    binbuf_gettext(bb, &buf,&l);
+    buf[l]=0;
+
+    //printf("popen list: %s\n",buf);
+    fprintf(x->x_file,"%s\n",buf);
+    fflush(x->x_file);
+
+    freebytes(buf,l);
+    binbuf_free(bb);
+}
+
+static void popen_out(t_popen *x, t_binbuf *b)
+{
+    t_atom messbuf[1024];
+    int msg, natom = binbuf_getnatom(b);
+    t_atom *at = binbuf_getvec(b);
+    for (msg = 0; msg < natom;)
+    {
+        int emsg;
+        for (emsg = msg; emsg < natom && at[emsg].a_type != A_COMMA
+                && at[emsg].a_type != A_SEMI; emsg++)
+            ;
+        if (emsg > msg)
+        {
+            int i;
+            for (i = msg; i < emsg; i++)
+                if (at[i].a_type == A_DOLLAR || at[i].a_type == A_DOLLSYM)
+                {
+                    pd_error(x, "popen: got dollar sign in message");
+                    goto nodice;
+                }
+            if (at[msg].a_type == A_FLOAT)
+            {
+                if (emsg > msg + 1)
+                    outlet_list(x->x_msgout, 0, emsg-msg, at + msg);
+                else outlet_float(x->x_msgout, at[msg].a_w.w_float);
+            }
+            else if (at[msg].a_type == A_SYMBOL)
+                outlet_anything(x->x_msgout, at[msg].a_w.w_symbol,
+                                emsg-msg-1, at + msg + 1);
+        }
+nodice:
+        msg = emsg + 1;
+    }
+}
+
+static void popen_read(t_popen *x,int fd)
+{
+    int len,i=0;
+    unsigned char b;
+    unsigned char buffer[BUFSIZE];
+
+    if((len=read(fd,buffer,BUFSIZE))> 0)
+    {
+
+        for(i=0; i<len; i++)
+        {
+            if(x->x_count>=BUFSIZE) x->x_count=0;
+            x->x_data[x->x_count++]=buffer[i];
+            if(buffer[i]==';')
+            {
+                binbuf_text(inbinbuf, x->x_data, x->x_count);
+                x->x_count=0;
+                popen_out(x,inbinbuf);
+            }
+        }
+    }
+}
+
+static void popen_ropen(t_popen *x, t_symbol *s,int argc, t_atom *argv)
+{
+    char cmd[512],*text;
+    int cmd_len;
+
+    t_binbuf *bb=binbuf_new();
+
+    popen_close(x);
+
+    //post("argc=%d",argc);
+    //post("argv[0]=%s",atom_getsymbol(&argv[0])->s_name);
+
+    binbuf_add(bb,argc,argv);
+    binbuf_gettext(bb, &text,&cmd_len);
+    binbuf_free(bb);
+
+    strncpy(cmd,text,cmd_len);
+    cmd[cmd_len]=0;
+    //post("cmd=%s",cmd);
+
+    x->x_file=popen(cmd,"r");
+    sys_addpollfn(fileno(x->x_file),(t_fdpollfn)popen_read,(void *)x);
+    x->x_ropened=1;
+}
+
+void popen_setup(void )
+{
+    inbinbuf = binbuf_new();
+    popen_class = class_new(gensym("popen"), (t_newmethod)popen_new,
+                            (t_method)popen_close,sizeof(t_popen), 0, A_GIMME, 0);
+    class_addmethod(popen_class, (t_method)popen_close,
+                    gensym("close"), 0);
+    class_addmethod(popen_class, (t_method)popen_open,
+                    gensym("open"), A_GIMME, 0);
+    class_addmethod(popen_class, (t_method)popen_ropen,
+                    gensym("ropen"), A_GIMME, 0);
+    class_addlist(popen_class, popen_list);
+
+}
+
diff --git a/readsfv~-help.pd b/readsfv~-help.pd
index 5870912..952a8a1 100644
--- a/readsfv~-help.pd
+++ b/readsfv~-help.pd
@@ -1,60 +1,74 @@
-#N canvas 117 77 546 422 10;
-#X obj 0 0 cnv 8 100 60 empty empty readsfv~ 10 20 1 18 -262144 -1109
-0;
-#X text 4 400 (c) Moonix: Antoine Rousseau 2003;
-#X obj 124 367 dac~;
-#X obj 132 331 readsfv~;
-#X obj 132 188 delay 20;
-#X msg 132 207 start;
-#X msg 193 207 1;
-#X obj 132 158 bng 15 250 50 0 empty empty play -25 4 0 8 -24198 -1
--1;
-#X obj 183 351 s replay;
-#X obj 132 60 r replay;
-#X obj 159 284 symbol;
-#X msg 159 304 open \$1;
-#X msg 229 283 symbol /usr/local/lib/pd/doc/sound/bell.aiff;
-#X msg 229 262 symbol ../../sound/bell.aiff;
-#X msg 47 298 speed \$1;
-#X obj 266 239 openpanel;
-#X obj 266 220 bng 15 250 50 0 empty empty open 0 -6 1 8 -195568 -1
--1;
-#X obj 132 126 spigot;
-#X obj 169 109 tgl 15 1 empty empty loop 0 -6 1 8 -241291 -1 -1 1 1
-;
-#X obj 47 58 vsl 15 128 0.08 8 1 0 empty empty speed 0 -8 1 8 -260818
--1 -1 6965 1;
-#X obj 1 57 init 1;
-#X obj 47 278 f;
-#X text 171 207 (or;
-#X text 220 207 );
-#X obj 57 253 b;
-#X obj 113 106 del 100;
-#X text 129 8 read a big soundfile in direct-to-disk mode;
-#X text 131 20 at variable speed.;
-#X text 230 104 read manual of;
-#X text 390 103 for more details...;
-#X obj 335 102 readsf~;
-#X connect 3 0 2 0;
-#X connect 3 0 2 1;
-#X connect 3 1 8 0;
-#X connect 4 0 5 0;
-#X connect 5 0 3 0;
-#X connect 5 0 24 0;
-#X connect 7 0 4 0;
-#X connect 7 0 10 0;
-#X connect 9 0 25 0;
-#X connect 10 0 11 0;
-#X connect 11 0 3 0;
-#X connect 12 0 10 1;
-#X connect 13 0 10 1;
-#X connect 14 0 3 0;
-#X connect 15 0 10 1;
-#X connect 16 0 15 0;
-#X connect 17 0 7 0;
-#X connect 18 0 17 1;
-#X connect 19 0 21 0;
-#X connect 20 0 19 0;
-#X connect 21 0 14 0;
-#X connect 24 0 21 0;
-#X connect 25 0 17 0;
+#N canvas 363 195 546 422 10;
+#X obj 0 0 cnv 8 100 60 empty empty readsfv~ 10 20 1 18 -262144 -1109
+0;
+#X text 4 400 (c) Moonix: Antoine Rousseau 2003;
+#X obj 124 367 dac~;
+#X obj 132 331 readsfv~;
+#X obj 132 188 delay 20;
+#X msg 132 207 start;
+#X msg 193 207 1;
+#X obj 132 158 bng 15 250 50 0 empty empty play -25 4 0 8 -24198 -1
+-1;
+#X obj 183 351 s replay;
+#X obj 132 51 r replay;
+#X obj 159 284 symbol;
+#X msg 159 304 open \$1;
+#X msg 229 283 symbol /usr/local/lib/pd/doc/sound/bell.aiff;
+#X msg 229 262 symbol ../../doc/sound/bell.aiff;
+#X msg 47 298 speed \$1;
+#X obj 266 239 openpanel;
+#X obj 266 220 bng 15 250 50 0 empty empty open 0 -6 1 8 -195568 -1
+-1;
+#X obj 132 126 spigot;
+#X obj 165 106 tgl 15 1 empty empty loop 0 -10 1 12 -241291 -1 -1 1
+1;
+#X obj 47 118 vsl 15 128 0.08 8 1 0 empty empty speed 0 -12 1 12 -260818
+-1 -1 0 1;
+#X obj 47 278 f;
+#X text 171 207 (or;
+#X text 220 207 );
+#X obj 57 253 b;
+#X obj 132 72 del 100;
+#X text 129 8 read a big soundfile in direct-to-disk mode;
+#X text 131 20 at variable speed.;
+#X text 230 104 read manual of;
+#X text 390 103 for more details...;
+#X obj 335 102 readsf~;
+#N canvas 524 187 494 344 META 0;
+#X text 12 25 LICENSE GPL v2;
+#X text 12 135 AUTHOR Antoine Rousseau;
+#X text 12 155 HELP_PATCH_AUTHORS Antoine Rousseau. "pd meta" information
+added by Jonathan Wilkes for Pd version 0.42.;
+#X text 12 5 KEYWORDS signal soundfile;
+#X text 12 45 DESCRIPTION read a big soundfile in direct-to-disk mode
+at variable speed;
+#X text 12 75 INLET_0 float start speed stop open print;
+#X text 12 95 OUTLET_0 signal;
+#X text 12 115 OUTLET_1 signal;
+#X restore 487 387 pd META;
+#X obj 22 53 loadbang;
+#X msg 22 76 1;
+#X connect 3 0 2 0;
+#X connect 3 0 2 1;
+#X connect 3 1 8 0;
+#X connect 4 0 5 0;
+#X connect 5 0 3 0;
+#X connect 5 0 23 0;
+#X connect 7 0 4 0;
+#X connect 7 0 10 0;
+#X connect 9 0 24 0;
+#X connect 10 0 11 0;
+#X connect 11 0 3 0;
+#X connect 12 0 10 1;
+#X connect 13 0 10 1;
+#X connect 14 0 3 0;
+#X connect 15 0 10 1;
+#X connect 16 0 15 0;
+#X connect 17 0 7 0;
+#X connect 18 0 17 1;
+#X connect 19 0 20 0;
+#X connect 20 0 14 0;
+#X connect 23 0 20 0;
+#X connect 24 0 17 0;
+#X connect 31 0 32 0;
+#X connect 32 0 19 0;
diff --git a/readsfv~.c b/readsfv~.c
index fc9c54f..fe9fcea 100644
--- a/readsfv~.c
+++ b/readsfv~.c
@@ -1,1683 +1,1707 @@
-#ifndef _WIN32
-/* Copyright (c) 1997-1999 Miller Puckette.
-* For information on usage and redistribution, and for a DISCLAIMER OF ALL
-* WARRANTIES, see the file, "LICENSE.txt," in this distribution.  */
-
-/* this file contains, first, a collection of soundfile access routines, a
-sort of soundfile library.  Second, the "soundfiler" object is defined which
-uses the routines to read or write soundfiles, synchronously, from garrays.
-These operations are not to be done in "real time" as they may have to wait
-for disk accesses (even the write routine.)  Finally, the realtime objects
-readsf~ and writesf~ are defined which confine disk operations to a separate
-thread so that they can be used in real time.  The real-time disk access
-objects are available for linux only so far, although they could be compiled
-for Windows if someone were willing to find a Pthreads package for it. */
-
-/* this is a partial copy of d_soundfile, with some hacking:
-	1: a fix in soundfiler to compute the normalization factor only on 
-		the samples we want to write on the disk...
-	2: a version of readsf~ that works with a (positive) speed parameter.
-	
-	Antoine Rousseau
-*/
-
-#include <pthread.h>
-#ifdef _WIN32
-#include <io.h>
-#else
-#include <unistd.h>
-#include <fcntl.h>
-#endif
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-
-#include "m_pd.h"
-
-#define MAXSFCHANS 4
-
-
-/***************** soundfile header structures ************************/
-
-typedef unsigned short uint16;
-typedef unsigned long uint32;
-
-#define FORMAT_WAVE 0
-#define FORMAT_AIFF 1
-#define FORMAT_NEXT 2
-
-/* the NeXTStep sound header structure; can be big or little endian  */
-
-typedef struct _nextstep
-{
-    char ns_fileid[4]; 	    /* magic number '.snd' if file is big-endian */
-    uint32 ns_onset; 	    /* byte offset of first sample */
-    uint32 ns_length;	    /* length of sound in bytes */
-    uint32 ns_format;        /* format; see below */
-    uint32 ns_sr;    	    /* sample rate */
-    uint32 ns_nchans;	    /* number of channels */
-    char ns_info[4];   	    /* comment */
-} t_nextstep;
-
-#define NS_FORMAT_LINEAR_16	3
-#define NS_FORMAT_LINEAR_24	4
-#define NS_FORMAT_FLOAT         6
-#define SCALE (1./(1024. * 1024. * 1024. * 2.))
-
-/* the WAVE header.  All Wave files are little endian.  We assume
-    the "fmt" chunk comes first which is usually the case but perhaps not
-    always; same for AIFF and the "COMM" chunk.   */
-
-typedef unsigned word;
-typedef unsigned long dword;
-
-typedef struct _wave
-{
-    char  w_fileid[4];	    	    /* chunk id 'RIFF'            */
-    uint32 w_chunksize;     	    /* chunk size                 */
-    char  w_waveid[4];	    	    /* wave chunk id 'WAVE'       */
-    char  w_fmtid[4];	    	    /* format chunk id 'fmt '     */
-    uint32 w_fmtchunksize;   	    /* format chunk size          */
-    uint16  w_fmttag;	    	    /* format tag, 1 for PCM      */
-    uint16  w_nchannels;    	    /* number of channels         */
-    uint32 w_samplespersec;  	    /* sample rate in hz          */
-    uint32 w_navgbytespersec; 	    /* average bytes per second   */
-    uint16  w_nblockalign;    	    /* number of bytes per sample */
-    uint16  w_nbitspersample; 	    /* number of bits in a sample */
-    char  w_datachunkid[4]; 	    /* data chunk id 'data'       */
-    uint32 w_datachunksize;         /* length of data chunk       */
-} t_wave;
-
-typedef struct _fmt	    /* format chunk */
-{
-    uint16 f_fmttag;	    	    /* format tag, 1 for PCM      */
-    uint16 f_nchannels;    	    /* number of channels         */
-    uint32 f_samplespersec;  	    /* sample rate in hz          */
-    uint32 f_navgbytespersec; 	    /* average bytes per second   */
-    uint16 f_nblockalign;    	    /* number of bytes per frame  */
-    uint16 f_nbitspersample; 	    /* number of bits in a sample */
-} t_fmt;
-
-typedef struct _wavechunk	    /* ... and the last two items */
-{
-    char  wc_id[4]; 	    	    /* data chunk id, e.g., 'data' or 'fmt ' */
-    uint32 wc_size;         	    /* length of data chunk       */
-} t_wavechunk;
-
-/* the AIFF header.  I'm assuming AIFC is compatible but don't really know
-    that. */
-
-typedef struct _datachunk
-{
-    char  dc_id[4]; 	    	    /* data chunk id 'SSND'       */
-    uint32 dc_size;         	    /* length of data chunk       */
-} t_datachunk;
-
-//#define CHUNKHDRSIZE sizeof(t_datachunk)
-
-typedef struct _comm
-{
-    uint16 c_nchannels;	            /* number of channels         */
-    uint16 c_nframeshi;    	    /* # of sample frames (hi)    */
-    uint16 c_nframeslo;    	    /* # of sample frames (lo)    */
-    uint16 c_bitspersamp;  	    /* bits per sample            */
-    unsigned char c_samprate[10];   /* sample rate, 80-bit float! */
-} t_comm;
-
-    /* this version is more convenient for writing them out: */
-typedef struct _aiff
-{
-    char  a_fileid[4];	    	    /* chunk id 'FORM'            */
-    uint32 a_chunksize;     	    /* chunk size                 */
-    char  a_aiffid[4];	    	    /* aiff chunk id 'AIFF'       */
-    char  a_fmtid[4];	    	    /* format chunk id 'COMM'     */
-    uint32 a_fmtchunksize;   	    /* format chunk size, 18      */
-    uint16 a_nchannels;	            /* number of channels         */
-    uint16 a_nframeshi;    	    /* # of sample frames (hi)    */
-    uint16 a_nframeslo;    	    /* # of sample frames (lo)    */
-    uint16 a_bitspersamp;  	    /* bits per sample            */
-    unsigned char a_samprate[10];   /* sample rate, 80-bit float! */
-} t_aiff;
-
-#define AIFFHDRSIZE 38	    /* probably not what sizeof() gives */
-
-
-#define AIFFPLUS (AIFFHDRSIZE + 8)  /* header size including first chunk hdr */
-
-#define WHDR1 sizeof(t_nextstep)
-#define WHDR2 (sizeof(t_wave) > WHDR1 ? sizeof (t_wave) : WHDR1)
-#define WRITEHDRSIZE (AIFFPLUS > WHDR2 ? AIFFPLUS : WHDR2)
-
-#define READHDRSIZE (16 > WHDR2 ? 16 : WHDR2)
-
-#define OBUFSIZE MAXPDSTRING  /* assume MAXPDSTRING is bigger than headers */
-
-#ifdef _WIN32
-#include <fcntl.h>
-#define BINCREATE _O_WRONLY | _O_CREAT | _O_BINARY | _O_TRUNC |
-#else
-#define BINCREATE O_WRONLY|O_CREAT|O_TRUNC
-#endif
-
-/* this routine returns 1 if the high order byte comes at the lower
-address on our architecture (big-endianness.).  It's 1 for Motorola,
-0 for Intel: */
-
-extern int garray_ambigendian(void);
-
-/* byte swappers */
-
-static uint32 swap4(uint32 n, int doit)
-{
-    if (doit)
-    	return (((n & 0xff) << 24) | ((n & 0xff00) << 8) |
-    	    ((n & 0xff0000) >> 8) | ((n & 0xff000000) >> 24));
-    else return (n);
-}
-
-static uint16 swap2(uint32 n, int doit)
-{
-    if (doit)
-    	return (((n & 0xff) << 8) | ((n & 0xff00) >> 8));
-    else return (n);
-}
-
-static void swapstring(char *foo, int doit)
-{
-    if (doit)
-    {
-    	char a = foo[0], b = foo[1], c = foo[2], d = foo[3];
-	foo[0] = d; foo[1] = c; foo[2] = b; foo[3] = a;
-    }
-}
-
-/******************** soundfile access routines **********************/
-
-void readsf_banana( void);    /* debugging */
-
-/* This routine opens a file, looks for either a nextstep or "wave" header,
-* seeks to end of it, and fills in bytes per sample and number of channels.
-* Only 2- and 3-byte fixed-point samples and 4-byte floating point samples
-* are supported.  If "headersize" is nonzero, the
-* caller should supply the number of channels, endinanness, and bytes per
-* sample; the header is ignored.  Otherwise, the routine tries to read the
-* header and fill in the properties.
-*/
-
-extern int open_soundfile(const char *dirname, const char *filename, int headersize,
-    int *p_bytespersamp, int *p_bigendian, int *p_nchannels, long *p_bytelimit,
-    long skipframes);
-
-
-static void soundfile_xferin(int sfchannels, int nvecs, float **vecs,
-    long itemsread, unsigned char *buf, int nitems, int bytespersamp,
-    int bigendian)
-{
-    int i, j;
-    unsigned char *sp, *sp2;
-    float *fp;
-    int nchannels = (sfchannels < nvecs ? sfchannels : nvecs);
-    int bytesperframe = bytespersamp * sfchannels;
-    for (i = 0, sp = buf; i < nchannels; i++, sp += bytespersamp)
-    {
-	if (bytespersamp == 2)
-	{
-	    if (bigendian)
-	    {
-	    	for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
-		    j < nitems; j++, sp2 += bytesperframe, fp++)
-		    	*fp = SCALE * ((sp2[0] << 24) | (sp2[1] << 16));
-	    }
-	    else
-	    {
-	    	for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
-		    j < nitems; j++, sp2 += bytesperframe, fp++)
-		    	*fp = SCALE * ((sp2[1] << 24) | (sp2[0] << 16));
-	    }
-	}
-	else if (bytespersamp == 3)
-	{
-	    if (bigendian)
-	    {
-	    	for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
-		    j < nitems; j++, sp2 += bytesperframe, fp++)
-		    	*fp = SCALE * ((sp2[0] << 24) | (sp2[1] << 16)
-			    | (sp2[2] << 8));
-	    }
-	    else
-	    {
-	    	for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
-		    j < nitems; j++, sp2 += bytesperframe, fp++)
-		    	*fp = SCALE * ((sp2[2] << 24) | (sp2[1] << 16)
-			    | (sp2[0] << 8));
-	    }
-	}
-	else if (bytespersamp == 4)
-	{
-	    if (bigendian)
-	    {
-	    	for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
-		    j < nitems; j++, sp2 += bytesperframe, fp++)
-		    	*(long *)fp = ((sp2[0] << 24) | (sp2[1] << 16)
-			    | (sp2[2] << 8) | sp2[3]);
-	    }
-	    else
-	    {
-	    	for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
-		    j < nitems; j++, sp2 += bytesperframe, fp++)
-		    	*(long *)fp = ((sp2[3] << 24) | (sp2[2] << 16)
-			    | (sp2[1] << 8) | sp2[0]);
-	    }
-	}
-    }
-	/* zero out other outputs */
-    for (i = sfchannels; i < nvecs; i++)
-	for (j = nitems, fp = vecs[i]; j--; )
-	    *fp++ = 0;
-
-}
-
-static void interpolate(int nvec,float **invec,int nin,
-			float **outvec,int nout)
-{
-
-	float r=nin/(float)nout;
-	int i,j;
-
-
-	for(i=0;i<nout;i++)
-	for(j=0;j<nvec;j++)
-		outvec[j][i]=invec[j][(int)(i*r)];
-
-}
-    /* soundfiler2_write ...
-
-    usage: write [flags] filename table ...
-    flags:
-	-nframes <frames>
-	-skip <frames>
-	-bytes <bytes per sample>
-	-normalize
-	-nextstep
-	-wave
-	-big
-	-little
-    */
-
-    /* the routine which actually does the work should LATER also be called
-    from garray_write16. */
-
-
-    /* Parse arguments for writing.  The "obj" argument is only for flagging
-    errors.  For streaming to a file the "normalize", "onset" and "nframes"
-    arguments shouldn't be set but the calling routine flags this. */
-
-static int soundfiler2_writeargparse(void *obj, int *p_argc, t_atom **p_argv,
-    t_symbol **p_filesym,
-    int *p_filetype, int *p_bytespersamp, int *p_swap, int *p_bigendian,
-    int *p_normalize, long *p_onset, long *p_nframes,float *p_amp)
-{
-    int argc = *p_argc;
-    t_atom *argv = *p_argv;
-    int bytespersamp = 2, bigendian = 0,
-    	endianness = -1, swap, filetype = FORMAT_WAVE, normalize = 0;
-    long onset = 0, nframes = 0x7fffffff;
-	float amp=1;
-    t_symbol *filesym;
-    while (argc > 0 && argv->a_type == A_SYMBOL &&
-    	*argv->a_w.w_symbol->s_name == '-')
-    {
-    	char *flag = argv->a_w.w_symbol->s_name + 1;
-	if (!strcmp(flag, "skip"))
-	{
-	    if (argc < 2 || argv[1].a_type != A_FLOAT ||
-	    	((onset = argv[1].a_w.w_float) < 0))
-	    	    goto usage;
-	    argc -= 2; argv += 2;
-	}
-	else if (!strcmp(flag, "nframes"))
-	{
-	    if (argc < 2 || argv[1].a_type != A_FLOAT ||
-	    	((nframes = argv[1].a_w.w_float) < 0))
-	    	    goto usage;
-	    argc -= 2; argv += 2;
-	}
-	else if (!strcmp(flag, "bytes"))
-	{
-	    if (argc < 2 || argv[1].a_type != A_FLOAT ||
-	    	((bytespersamp = argv[1].a_w.w_float) < 2) ||
-		    bytespersamp > 4)
-	    	    	goto usage;
-	    argc -= 2; argv += 2;
-	}
-	else if (!strcmp(flag, "normalize"))
-	{
-	    normalize = 1;
-	    argc -= 1; argv += 1;
-	}
-	else if (!strcmp(flag, "amp"))
-	{
-	    if (argc < 2 || argv[1].a_type != A_FLOAT)
-	    	    	goto usage;
-	    amp = argv[1].a_w.w_float;
-	    argc -= 2; argv += 2;
-	}
-	else if (!strcmp(flag, "wave"))
-	{
-	    filetype = FORMAT_WAVE;
-	    argc -= 1; argv += 1;
-	}
-	else if (!strcmp(flag, "nextstep"))
-	{
-	    filetype = FORMAT_NEXT;
-	    argc -= 1; argv += 1;
-	}
-	else if (!strcmp(flag, "aiff"))
-	{
-	    filetype = FORMAT_AIFF;
-	    argc -= 1; argv += 1;
-	}
-	else if (!strcmp(flag, "big"))
-	{
-	    endianness = 1;
-	    argc -= 1; argv += 1;
-	}
-	else if (!strcmp(flag, "little"))
-	{
-	    endianness = 1;
-	    argc -= 1; argv += 1;
-	}
-	else goto usage;
-    }
-    	/* only NextStep handles floating point samples */
-    if (bytespersamp == 4)
-    	filetype = FORMAT_NEXT;
-
-    	/* for WAVE force little endian; for nextstep use machine native */
-    if (filetype == FORMAT_WAVE)
-    {
-    	bigendian = 0;
-    	if (endianness == 1)
-	    pd_error(obj, "WAVE file forced to little endian");
-    }
-    else if (filetype == FORMAT_AIFF)
-    {
-    	bigendian = 1;
-    	if (endianness == 0)
-	    pd_error(obj, "AIFF file forced to big endian");
-    }
-    else if (endianness == -1)
-    {
-    	bigendian = garray_ambigendian();
-    }
-    swap = (bigendian != garray_ambigendian());
-    if (!argc || argv->a_type != A_SYMBOL)
-    	goto usage;
-    filesym = argv->a_w.w_symbol;
-    argc--; argv++;
-    
-    *p_argc = argc;
-    *p_argv = argv;
-    *p_filesym = filesym;
-    *p_filetype = filetype;
-    *p_bytespersamp = bytespersamp;
-    *p_swap = swap;
-    *p_normalize = normalize;
-    *p_onset = onset;
-    *p_nframes = nframes;
-    *p_bigendian = bigendian;
-    *p_amp = amp;
-    return (0);
-usage:
-    return (-1);
-}
-
-static int create_soundfile2(t_canvas *canvas, const char *filename,
-    int filetype, int nframes, int bytespersamp,
-    int bigendian, int nchannels, int swap)
-{
-    char filenamebuf[MAXPDSTRING], buf2[MAXPDSTRING];
-    char headerbuf[WRITEHDRSIZE];
-    t_wave *wavehdr = (t_wave *)headerbuf;
-    t_nextstep *nexthdr = (t_nextstep *)headerbuf;
-    t_aiff *aiffhdr = (t_aiff *)headerbuf;
-    int fd, headersize = 0;
-    
-    strncpy(filenamebuf, filename, MAXPDSTRING-10);
-    filenamebuf[MAXPDSTRING-10] = 0;
-
-    if (filetype == FORMAT_NEXT)
-    {
-    	if (strcmp(filenamebuf + strlen(filenamebuf)-4, ".snd"))
-    	    strcat(filenamebuf, ".snd");
-	if (bigendian)
-	    strncpy(nexthdr->ns_fileid, ".snd", 4);
-    	else strncpy(nexthdr->ns_fileid, "dns.", 4);
-	nexthdr->ns_onset = swap4(sizeof(*nexthdr), swap);
-    	nexthdr->ns_length = 0;
-    	nexthdr->ns_format = swap4((bytespersamp == 3 ? NS_FORMAT_LINEAR_24 :
-	    (bytespersamp == 4 ? NS_FORMAT_FLOAT : NS_FORMAT_LINEAR_16)), swap);;
-    	nexthdr->ns_sr = swap4(44100, swap);     /* lie */
-    	nexthdr->ns_nchans = swap4(nchannels, swap);
-    	strcpy(nexthdr->ns_info, "Pd ");
-    	swapstring(nexthdr->ns_info, swap);
-	headersize = sizeof(t_nextstep);
-    }
-    else if (filetype == FORMAT_AIFF)
-    {
-    	long datasize = nframes * nchannels * bytespersamp;
-	long longtmp;
-	static unsigned char dogdoo[] =
-	    {0x40, 0x0e, 0xac, 0x44, 0, 0, 0, 0, 0, 0, 'S', 'S', 'N', 'D'};
-    	if (strcmp(filenamebuf + strlen(filenamebuf)-4, ".aif") &&
-	    strcmp(filenamebuf + strlen(filenamebuf)-5, ".aiff"))
-    	    	strcat(filenamebuf, ".aif");
-    	strncpy(aiffhdr->a_fileid, "FORM", 4);
-    	aiffhdr->a_chunksize = swap4(datasize + sizeof(*aiffhdr) + 4, swap);
-    	strncpy(aiffhdr->a_aiffid, "AIFF", 4);
-    	strncpy(aiffhdr->a_fmtid, "COMM", 4);
-    	aiffhdr->a_fmtchunksize = swap4(18, swap);
-    	aiffhdr->a_nchannels = swap2(nchannels, swap);
-	longtmp = swap4(nframes, swap);
-	memcpy(&aiffhdr->a_nframeshi, &longtmp, 4);
-    	aiffhdr->a_bitspersamp = swap2(8 * bytespersamp, swap);
-    	memcpy(aiffhdr->a_samprate, dogdoo, sizeof(dogdoo));
-	longtmp = swap4(datasize, swap);
-	memcpy(aiffhdr->a_samprate + sizeof(dogdoo), &longtmp, 4);
-	headersize = AIFFPLUS;
-    }
-    else    /* WAVE format */
-    {
-    	long datasize = nframes * nchannels * bytespersamp;
-    	if (strcmp(filenamebuf + strlen(filenamebuf)-4, ".wav"))
-    	    strcat(filenamebuf, ".wav");
-    	strncpy(wavehdr->w_fileid, "RIFF", 4);
-    	wavehdr->w_chunksize = swap4(datasize + sizeof(*wavehdr) - 8, swap);
-    	strncpy(wavehdr->w_waveid, "WAVE", 4);
-    	strncpy(wavehdr->w_fmtid, "fmt ", 4);
-    	wavehdr->w_fmtchunksize = swap4(16, swap);
-    	wavehdr->w_fmttag = swap2(1, swap);
-    	wavehdr->w_nchannels = swap2(nchannels, swap);
-    	wavehdr->w_samplespersec = swap4(44100, swap);
-    	wavehdr->w_navgbytespersec = swap4(44100 * nchannels * bytespersamp, swap);
-    	wavehdr->w_nblockalign = swap2(bytespersamp, swap);
-    	wavehdr->w_nbitspersample = swap2(8 * bytespersamp, swap);
-    	strncpy(wavehdr->w_datachunkid, "data", 4);
-    	wavehdr->w_datachunksize = swap4(datasize, swap);
-	headersize = sizeof(t_wave);
-    }
-
-    canvas_makefilename(canvas, filenamebuf, buf2, MAXPDSTRING);
-    sys_bashfilename(buf2, buf2);
-    if ((fd = open(buf2, BINCREATE, 0666)) < 0)
-    	return (-1);
-
-    if (write(fd, headerbuf, headersize) < headersize)
-    {
-	close (fd);
-    	return (-1);
-    }
-    return (fd);
-}
-
-static void soundfile_finishwrite(void *obj, char *filename, int fd,
-    int filetype, long nframes, long itemswritten, int bytesperframe, int swap)
-{
-    if (itemswritten < nframes)
-    {
-    	if (nframes < 0x7fffffff)
-	    pd_error(obj, "soundfiler2_write: %d out of %d bytes written",
-	    	itemswritten, nframes);
-	    /* try to fix size fields in header */
-	if (filetype == FORMAT_WAVE)
-	{
-    	    long datasize = itemswritten * bytesperframe, mofo;
-	    
-	    if (lseek(fd,
-	    	((char *)(&((t_wave *)0)->w_chunksize)) - (char *)0,
-		    SEEK_SET) == 0)
-		    	goto baddonewrite;
-	    mofo = swap4(datasize + sizeof(t_wave) - 8, swap);
-    	    if (write(fd, (char *)(&mofo), 4) < 4)
-    	    	goto baddonewrite;
-	    if (lseek(fd,
-	    	((char *)(&((t_wave *)0)->w_datachunksize)) - (char *)0,
-		    SEEK_SET) == 0)
-		    	goto baddonewrite;
-    	    mofo = swap4(datasize, swap);
-    	    if (write(fd, (char *)(&mofo), 4) < 4)
-    	    	goto baddonewrite;
-	}
-	if (filetype == FORMAT_AIFF)
-	{
-    	    long mofo;
-    	    if (lseek(fd,
-	    	((char *)(&((t_aiff *)0)->a_nframeshi)) - (char *)0,
-		    SEEK_SET) == 0)
-		    	goto baddonewrite;
-	    mofo = swap4(nframes, swap);
-    	    if (write(fd, (char *)(&mofo), 4) < 4)
-    	    	goto baddonewrite;
-	}
-    }
-    return;
-baddonewrite:
-    post("%s: %s", filename, strerror(errno));
-}
-
-static void soundfile_xferout(int nchannels, float **vecs,
-    unsigned char *buf, int nitems, long onset, int bytespersamp,
-    int bigendian, float normalfactor)
-{
-    int i, j;
-    unsigned char *sp, *sp2;
-    float *fp;
-    int bytesperframe = bytespersamp * nchannels;
-    long xx;
-    for (i = 0, sp = buf; i < nchannels; i++, sp += bytespersamp)
-    {
-	if (bytespersamp == 2)
-	{
-	    float ff = normalfactor * 32768.;
-	    if (bigendian)
-	    {
-	    	for (j = 0, sp2 = sp, fp = vecs[i] + onset;
-		    j < nitems; j++, sp2 += bytesperframe, fp++)
-		{
-		    int xx = 32768. + (*fp * ff);
-		    xx -= 32768;
-		    if (xx < -32767)
-			xx = -32767;
-		    if (xx > 32767)
-			xx = 32767;
-		    sp2[0] = (xx >> 8);
-		    sp2[1] = xx;
-	    	}
-	    }
-	    else
-	    {
-	    	for (j = 0, sp2 = sp, fp=vecs[i] + onset;
-		    j < nitems; j++, sp2 += bytesperframe, fp++)
-		{
-		    int xx = 32768. + (*fp * ff);
-		    xx -= 32768;
-		    if (xx < -32767)
-			xx = -32767;
-		    if (xx > 32767)
-			xx = 32767;
-		    sp2[1] = (xx >> 8);
-		    sp2[0] = xx;
-		}
-	    }
-	}
-	else if (bytespersamp == 3)
-	{
-	    float ff = normalfactor * 8388608.;
-	    if (bigendian)
-	    {
-	    	for (j = 0, sp2 = sp, fp=vecs[i] + onset;
-		    j < nitems; j++, sp2 += bytesperframe, fp++)
-		{
-		    int xx = 8388608. + (*fp * ff);
-		    xx -= 8388608;
-		    if (xx < -8388607)
-			xx = -8388607;
-		    if (xx > 8388607)
-			xx = 8388607;
-		    sp2[0] = (xx >> 16);
-		    sp2[1] = (xx >> 8);
-		    sp2[2] = xx;
-		}
-	    }
-	    else
-	    {
-	    	for (j = 0, sp2 = sp, fp=vecs[i] + onset;
-		    j < nitems; j++, sp2 += bytesperframe, fp++)
-		{
-		    int xx = 8388608. + (*fp * ff);
-		    xx -= 8388608;
-		    if (xx < -8388607)
-			xx = -8388607;
-		    if (xx > 8388607)
-			xx = 8388607;
-		    sp2[2] = (xx >> 16);
-		    sp2[1] = (xx >> 8);
-		    sp2[0] = xx;
-		}
-	    }
-	}
-	else if (bytespersamp == 4)
-	{
-	    if (bigendian)
-	    {
-	    	for (j = 0, sp2 = sp, fp=vecs[i] + onset;
-		    j < nitems; j++, sp2 += bytesperframe, fp++)
-		{
-		    float f2 = *fp * normalfactor;
-		    xx = *(long *)&f2;
-		    sp2[0] = (xx >> 24); sp2[1] = (xx >> 24);
-		    sp2[2] = (xx >> 24); sp2[3] = xx;
-	    	}
-	    }
-	    else
-	    {
-	    	for (j = 0, sp2 = sp, fp=vecs[i] + onset;
-		    j < nitems; j++, sp2 += bytesperframe, fp++)
-		{
-		    float f2 = *fp * normalfactor;
-		    xx = *(long *)&f2;
-		    sp2[3] = (xx >> 24); sp2[2] = (xx >> 24);
-		    sp2[1] = (xx >> 24); sp2[0] = xx;
-	    	}
-	    }
-	}
-    }
-}
-
-
-/* ------- soundfiler - reads and writes soundfiles to/from "garrays" ---- */
-#define DEFMAXSIZE 4000000 	/* default maximum 16 MB per channel */
-#define SAMPBUFSIZE 1024
-
-
-static t_class *soundfiler2_class;
-
-typedef struct _soundfiler2
-{
-    t_object x_obj;
-    t_canvas *x_canvas;
-} t_soundfiler2;
-
-static t_soundfiler2 *soundfiler2_new(void)
-{
-    t_soundfiler2 *x = (t_soundfiler2 *)pd_new(soundfiler2_class);
-    x->x_canvas = canvas_getcurrent();
-    outlet_new(&x->x_obj, &s_float);
-    return (x);
-}
-
-    /* soundfiler2_read ...
-
-    usage: read [flags] filename table ...
-    flags:
-    	-skip <frames> ... frames to skip in file
-	-nframes <frames>
-	-onset <frames> ... onset in table to read into (NOT DONE YET)
-	-raw <headersize channels bytes endian>
-	-resize
-	-maxsize <max-size>
-    */
-
-static void soundfiler2_read(t_soundfiler2 *x, t_symbol *s,
-    int argc, t_atom *argv)
-{
-    int headersize = -1, channels = 0, bytespersamp = 0, bigendian = 0,
-	resize = 0, i, j;
-    long skipframes = 0, nframes = 0, finalsize = 0, itemsleft,
-    	maxsize = DEFMAXSIZE, itemsread = 0, bytelimit  = 0x7fffffff;
-    int fd = -1;
-    char endianness, *filename;
-    t_garray *garrays[MAXSFCHANS];
-    t_float *vecs[MAXSFCHANS];
-    char sampbuf[SAMPBUFSIZE];
-    int bufframes, nitems;
-    FILE *fp;
-    while (argc > 0 && argv->a_type == A_SYMBOL &&
-    	*argv->a_w.w_symbol->s_name == '-')
-    {
-    	char *flag = argv->a_w.w_symbol->s_name + 1;
-	if (!strcmp(flag, "skip"))
-	{
-	    if (argc < 2 || argv[1].a_type != A_FLOAT ||
-	    	((skipframes = argv[1].a_w.w_float) < 0))
-	    	    goto usage;
-	    argc -= 2; argv += 2;
-	}
-	else if (!strcmp(flag, "nframes"))
-	{
-	    if (argc < 2 || argv[1].a_type != A_FLOAT ||
-	    	((nframes = argv[1].a_w.w_float) < 0))
-	    	    goto usage;
-	    argc -= 2; argv += 2;
-	}
-	else if (!strcmp(flag, "raw"))
-	{
-	    if (argc < 5 ||
-	    	argv[1].a_type != A_FLOAT ||
-	    	((headersize = argv[1].a_w.w_float) < 0) ||
-	    	argv[2].a_type != A_FLOAT ||
-	    	((channels = argv[2].a_w.w_float) < 1) ||
-		(channels > MAXSFCHANS) ||
-	    	argv[3].a_type != A_FLOAT ||
-	    	((bytespersamp = argv[3].a_w.w_float) < 2) ||
-		    (bytespersamp > 4) ||
-	    	argv[4].a_type != A_SYMBOL ||
-		    ((endianness = argv[4].a_w.w_symbol->s_name[0]) != 'b'
-		    && endianness != 'l' && endianness != 'n'))
-	    	    	goto usage;
-	    if (endianness == 'b')
-	    	bigendian = 1;
-	    else if (endianness == 'l')
-	    	bigendian = 0;
-	    else
-	    	bigendian = garray_ambigendian();
-	    argc -= 5; argv += 5;
-	}
-	else if (!strcmp(flag, "resize"))
-	{
-	    resize = 1;
-	    argc -= 1; argv += 1;
-	}
-	else if (!strcmp(flag, "maxsize"))
-	{
-	    if (argc < 2 || argv[1].a_type != A_FLOAT ||
-	    	((maxsize = argv[1].a_w.w_float) < 0))
-	    	    goto usage;
-	    resize = 1;     /* maxsize implies resize. */
-	    argc -= 2; argv += 2;
-	}
-	else goto usage;
-    }
-    if (argc < 2 || argc > MAXSFCHANS + 1 || argv[0].a_type != A_SYMBOL)
-    	goto usage;
-    filename = argv[0].a_w.w_symbol->s_name;
-    argc--; argv++;
-    
-    for (i = 0; i < argc; i++)
-    {
-    	int vecsize;
-    	if (argv[i].a_type != A_SYMBOL)
-	    goto usage;
-	if (!(garrays[i] =
-	    (t_garray *)pd_findbyclass(argv[i].a_w.w_symbol, garray_class)))
-	{
-	    pd_error(x, "%s: no such table", argv[i].a_w.w_symbol->s_name);
-	    goto done;
-	}
-    	else if (!garray_getfloatarray(garrays[i], &vecsize, &vecs[i]))
-    	    error("%s: bad template for tabwrite",
-	    	argv[i].a_w.w_symbol->s_name);
-    	if (finalsize && finalsize != vecsize && !resize)
-	{
-	    post("soundfiler2_read: arrays have different lengths; resizing...");
-	    resize = 1;
-	}
-	finalsize = vecsize;
-    }
-    fd = open_soundfile(canvas_getdir(x->x_canvas)->s_name, filename,
-    	headersize, &bytespersamp, &bigendian, &channels, &bytelimit,
-	    skipframes);
-
-    if (fd < 0)
-    {
-	pd_error(x, "soundfiler2_read: %s: %s", filename, (errno == EIO ?
-	    "unknown or bad header format" : strerror(errno)));
-    	goto done;
-    }
-
-    if (resize)
-    {
-    	    /* figure out what to resize to */
-    	long poswas, eofis, framesinfile;
-
-	poswas = lseek(fd, 0, SEEK_CUR);
-	eofis = lseek(fd, 0, SEEK_END);
-	if (poswas < 0 || eofis < 0)
-	{
-	    pd_error(x, "lseek failed");
-	    goto done;
-	}
-	lseek(fd, poswas, SEEK_SET);
-	framesinfile = (eofis - poswas) / (channels * bytespersamp);
-	if (framesinfile > maxsize)
-	{
-	    pd_error(x, "soundfiler2_read: truncated to %d elements", maxsize);
-	    framesinfile = maxsize;
-	}
-	if (framesinfile > bytelimit / bytespersamp)
-	    framesinfile = bytelimit / bytespersamp;
-	finalsize = framesinfile;
-	for (i = 0; i < argc; i++)
-	{
-	    int vecsize;
-
-    	garray_resize(garrays[i], finalsize);
-	    	/* for sanity's sake let's clear the save-in-patch flag here */
-	    garray_setsaveit(garrays[i], 0);
-	    garray_getfloatarray(garrays[i], &vecsize, &vecs[i]);
-	    	/* if the resize failed, garray_resize reported the error */
-	    if (vecsize != framesinfile)
-	    {
-	    	pd_error(x, "resize failed");
-	     	goto done;
-		}
-	}
-    }
-    if (!finalsize) finalsize = 0x7fffffff;
-    if (finalsize > bytelimit / bytespersamp)
-    	finalsize = bytelimit / bytespersamp;
-    fp = fdopen(fd, "rb");
-    bufframes = SAMPBUFSIZE / (channels * bytespersamp);
-
-    for (itemsread = 0; itemsread < finalsize; )
-    {
-    	int thisread = finalsize - itemsread;
-    	thisread = (thisread > bufframes ? bufframes : thisread);
-    	nitems = fread(sampbuf, channels * bytespersamp, thisread, fp);
-	if (nitems <= 0) break;
-	soundfile_xferin(channels, argc, vecs, itemsread,
-	    (unsigned char *)sampbuf, nitems, bytespersamp, bigendian);
-	itemsread += nitems;
-    }
-    	/* zero out remaining elements of vectors */
-	
-    for (i = 0; i < argc; i++)
-    {
-	int nzero, vecsize;
-	garray_getfloatarray(garrays[i], &vecsize, &vecs[i]);
-	for (j = itemsread; j < vecsize; j++)
-	    vecs[i][j] = 0;
-    }
-    	/* zero out vectors in excess of number of channels */
-    for (i = channels; i < argc; i++)
-    {
-	int vecsize;
-	float *foo;
-	garray_getfloatarray(garrays[i], &vecsize, &foo);
-	for (j = 0; j < vecsize; j++)
-	    foo[j] = 0;
-    }
-    	/* do all graphics updates */
-    for (i = 0; i < argc; i++)
-    	garray_redraw(garrays[i]);
-    fclose(fp);
-    fd = -1;
-    goto done;
-usage:
-    pd_error(x, "usage: read [flags] filename tablename...");
-    post("flags: -skip <n> -nframes <n> -resize -maxsize <n> ...");
-    post("-raw <headerbytes> <channels> <bytespersamp> <endian (b, l, or n)>.");
-done:
-    if (fd >= 0)
-    	close (fd);
-    outlet_float(x->x_obj.ob_outlet, (float)itemsread); 
-}
-
-    /* this is broken out from soundfiler2_write below so garray_write can
-    call it too... not done yet though. */
-
-static long soundfiler2_dowrite(void *obj, t_canvas *canvas,
-    int argc, t_atom *argv)
-{
-    int headersize, bytespersamp, bigendian,
-    	endianness, swap, filetype, normalize, i, j, nchannels;
-    long onset, nframes, itemsleft,
-    	maxsize = DEFMAXSIZE, itemswritten = 0;
-    t_garray *garrays[MAXSFCHANS];
-    t_float *vecs[MAXSFCHANS];
-    char sampbuf[SAMPBUFSIZE];
-    int bufframes, nitems;
-    int fd = -1;
-    float normfactor, biggest = 0,ftmp,amp;
-    t_symbol *filesym;
-
-    if (soundfiler2_writeargparse(obj, &argc, &argv, &filesym, &filetype,
-    	&bytespersamp, &swap, &bigendian, &normalize, &onset, &nframes,&amp))
-    	    goto usage;
-    nchannels = argc;
-    if (nchannels < 1 || nchannels > MAXSFCHANS)
-    	goto usage;
-
-    for (i = 0; i < nchannels; i++)
-    {
-    	int vecsize;
-		
-    	if (argv[i].a_type != A_SYMBOL) goto usage;
-	
-		if (!(garrays[i] =
-	    (t_garray *)pd_findbyclass(argv[i].a_w.w_symbol, garray_class)))
-		{
-			pd_error(obj, "%s: no such table", argv[i].a_w.w_symbol->s_name);
-			goto fail;
-		}
-    	else if (!garray_getfloatarray(garrays[i], &vecsize, &vecs[i]))
-    	    error("%s: bad template for tabwrite",argv[i].a_w.w_symbol->s_name);
-    	if (nframes > vecsize - onset)
-	    	nframes = vecsize - onset;
-
-		for (j = 0; j < nframes; j++) /* FIXED (Antoine Rousseau)*/
-		{
-			ftmp=vecs[i][j+onset];
-			if (ftmp > biggest) biggest = ftmp;
-			else if (-ftmp > biggest) biggest = -ftmp;
-    	}
-    }
-	
-    if (nframes <= 0)
-    {
-	pd_error(obj, "soundfiler2_write: no samples at onset %ld", onset);
-    	goto fail;
-    }
-
-    if ((fd = create_soundfile2(canvas, filesym->s_name, filetype,
-     	nframes, bytespersamp, bigendian, nchannels,
-	    swap)) < 0)
-    {
-    	post("%s: %s\n", filesym->s_name, strerror(errno));
-    	goto fail;
-    }
-    if (!normalize)
-    {
-    	if ((bytespersamp != 4) && (biggest > 1))
-		{
-    	    //post("%s: normalizing max amplitude %f to 1", filesym->s_name, biggest);
-    	    normalize = 1;
-    	}
-		//else post("%s: biggest amplitude = %f", filesym->s_name, biggest);
-    }
-    if (normalize)
-		normfactor = (biggest > 0 ? 32767./(32768. * biggest) : 1);
-    else normfactor = amp;
-
-	/*post("%s: biggest amplitude = %f , normfactor = %f", 
-		filesym->s_name, biggest,normfactor);*/
-
-    bufframes = SAMPBUFSIZE / (nchannels * bytespersamp);
-
-    for (itemswritten = 0; itemswritten < nframes; )
-    {
-    	int thiswrite = nframes - itemswritten, nitems, nbytes;
-    	thiswrite = (thiswrite > bufframes ? bufframes : thiswrite);
-	soundfile_xferout(argc, vecs, (unsigned char *)sampbuf, thiswrite,
-	    onset, bytespersamp, bigendian, normfactor);
-    	nbytes = write(fd, sampbuf, nchannels * bytespersamp * thiswrite);
-	if (nbytes < nchannels * bytespersamp * thiswrite)
-	{
-	    post("%s: %s", filesym->s_name, strerror(errno));
-	    if (nbytes > 0)
-	    	itemswritten += nbytes / (nchannels * bytespersamp);
-	    break;
-	}
-	itemswritten += thiswrite;
-	onset += thiswrite;
-    }
-    if (fd >= 0)
-    {
-    	soundfile_finishwrite(obj, filesym->s_name, fd,
-    	    filetype, nframes, itemswritten, nchannels * bytespersamp, swap);
-    	close (fd);
-    }
-    return ((float)itemswritten); 
-usage:
-    pd_error(obj, "usage: write [flags] filename tablename...");
-    post("flags: -skip <n> -nframes <n> -bytes <n> -wave -aiff -nextstep ...");
-    post("-big -little -normalize -amp <n>");
-    post("(defaults to a 16-bit wave file).");
-fail:
-    if (fd >= 0)
-    	close (fd);
-    return (0);
-}
-
-static void soundfiler2_write(t_soundfiler2 *x, t_symbol *s,
-    int argc, t_atom *argv)
-{
-    long bozo = soundfiler2_dowrite(x, x->x_canvas,
-    	argc, argv);
-    outlet_float(x->x_obj.ob_outlet, (float)bozo);
-}
-
-void soundfiler2_setup(void)
-{
-    soundfiler2_class = class_new(gensym("soundfiler2"), (t_newmethod)soundfiler2_new, 
-    	0, sizeof(t_soundfiler2), 0, 0);
-    class_addmethod(soundfiler2_class, (t_method)soundfiler2_read, gensym("read"), 
-    	A_GIMME, 0);
-    class_addmethod(soundfiler2_class, (t_method)soundfiler2_write,
-    	gensym("write"), A_GIMME, 0);
-}
-
-/************************* readsf object ******************************/
-
-/* READSF uses the Posix threads package; for the moment we're Linux
-only although this should be portable to the other platforms.
-
-Each instance of readsf~ owns a "child" thread for doing the UNIX (NT?) file
-reading.  The parent thread signals the child each time:
-    (1) a file wants opening or closing;
-    (2) we've eaten another 1/16 of the shared buffer (so that the
-    	child thread should check if it's time to read some more.)
-The child signals the parent whenever a read has completed.  Signalling
-is done by setting "conditions" and putting data in mutex-controlled common
-areas.
-*/
-
-#ifdef __linux__
-
-#define MAXBYTESPERSAMPLE 4
-#define MAXVECSIZE 128
-
-#define READSIZE 65536
-#define WRITESIZE 65536
-#define DEFBUFPERCHAN 262144
-#define MINBUFSIZE (4 * READSIZE)
-#define MAXBUFSIZE 16777216 	/* arbitrary; just don't want to hang malloc */
-
-#define REQUEST_NOTHING 0
-#define REQUEST_OPEN 1
-#define REQUEST_CLOSE 2
-#define REQUEST_QUIT 3
-#define REQUEST_BUSY 4
-
-#define STATE_IDLE 0
-#define STATE_STARTUP 1
-#define STATE_STREAM 2
-
-static t_class *readsfv_class;
-
-static t_sample *(tmpvec[MAXSFCHANS]);
-
-typedef struct _readsf
-{
-    t_object x_obj;
-    t_canvas *x_canvas;
-    t_clock *x_clock;
-    char *x_buf;    	    	    	    /* soundfile buffer */
-    int x_bufsize;  	    	    	    /* buffer size in bytes */
-    int x_noutlets; 	    	    	    /* number of audio outlets */
-    t_sample *(x_outvec[MAXSFCHANS]);	    /* audio vectors */
-    int x_vecsize;  	    	    	    /* vector size for transfers */
-    t_outlet *x_bangout;  	    	    /* bang-on-done outlet */
-    int x_state;    	    	    	    /* opened, running, or idle */
-    	/* parameters to communicate with subthread */
-    int x_requestcode;	    /* pending request from parent to I/O thread */
-    char *x_filename;	    /* file to open (string is permanently allocated) */
-    int x_fileerror;	    /* slot for "errno" return */
-    int x_skipheaderbytes;  /* size of header we'll skip */
-    int x_bytespersample;   /* bytes per sample (2 or 3) */
-    int x_bigendian;        /* true if file is big-endian */
-    int x_sfchannels;	    /* number of channels in soundfile */
-    long x_onsetframes;	    /* number of sample frames to skip */
-    long x_bytelimit;	    /* max number of data bytes to read */
-    int x_fd;	    	    /* filedesc */
-    int x_fifosize; 	    /* buffer size appropriately rounded down */	    
-    int x_fifohead; 	    /* index of next byte to get from file */
-    int x_fifotail; 	    /* index of next byte the ugen will read */
-    int x_eof;   	    /* true if fifohead has stopped changing */
-    int x_sigcountdown;     /* counter for signalling child for more data */
-    int x_sigperiod;	    /* number of ticks per signal */
-    int x_filetype; 	    /* writesf~ only; type of file to create */
-    int x_itemswritten;     /* writesf~ only; items writen */
-    int x_swap; 	    /* writesf~ only; true if byte swapping */
-    float x_f; 	    	    /* writesf~ only; scalar for signal inlet */
-	/*----HACK------*/
-    float x_speed;    /*speed of reading*/
-    float x_frac;    /*fractionnal part of sample to play next buffer*/
-
-    pthread_mutex_t x_mutex;
-    pthread_cond_t x_requestcondition;
-    pthread_cond_t x_answercondition;
-    pthread_t x_childthread;
-} t_readsf;
-
-
-/************** the child thread which performs file I/O ***********/
-
-#if 0
-static void pute(char *s)   /* debug routine */
-{
-    write(2, s, strlen(s));
-}
-#else
-#define pute(x)
-#endif
-
-#if 1
-#define sfread_cond_wait pthread_cond_wait
-#define sfread_cond_signal pthread_cond_signal
-#else
-#include <sys/time.h>    /* debugging version... */
-#include <sys/types.h>
-static void readsf_fakewait(pthread_mutex_t *b)
-{
-    struct timeval timout;
-    timout.tv_sec = 0;
-    timout.tv_usec = 1000000;
-    pthread_mutex_unlock(b);
-    select(0, 0, 0, 0, &timout);
-    pthread_mutex_lock(b);
-}
-
-static void readsf_banana( void)
-{
-    struct timeval timout;
-    timout.tv_sec = 0;
-    timout.tv_usec = 200000;
-    pute("banana1\n");
-    select(0, 0, 0, 0, &timout);
-    pute("banana2\n");
-}
-
-
-#define sfread_cond_wait(a,b) readsf_fakewait(b)
-#define sfread_cond_signal(a) 
-#endif
-
-static void *readsf_child_main(void *zz)
-{
-    t_readsf *x = zz;
-    pute("1\n");
-    pthread_mutex_lock(&x->x_mutex);
-    while (1)
-    {
-    	int fd, fifohead;
-	char *buf;
-	pute("0\n");
-	if (x->x_requestcode == REQUEST_NOTHING)
-	{
-    	    pute("wait 2\n");
-	    sfread_cond_signal(&x->x_answercondition);
-	    sfread_cond_wait(&x->x_requestcondition, &x->x_mutex);
-    	    pute("3\n");
-	}
-	else if (x->x_requestcode == REQUEST_OPEN)
-	{
-    	    char boo[80];
-	    int sysrtn, wantbytes;
-	    
-	    	/* copy file stuff out of the data structure so we can
-		relinquish the mutex while we're in open_soundfile(). */
-	    long onsetframes = x->x_onsetframes;
-	    long bytelimit = 0x7fffffff;
-	    int skipheaderbytes = x->x_skipheaderbytes;
-	    int bytespersample = x->x_bytespersample;
-	    int sfchannels = x->x_sfchannels;
-	    int bigendian = x->x_bigendian;
-	    char *filename = x->x_filename;
-	    char *dirname = canvas_getdir(x->x_canvas)->s_name;
-	    	/* alter the request code so that an ensuing "open" will get
-		noticed. */
-    	    pute("4\n");
-	    x->x_requestcode = REQUEST_BUSY;
-	    x->x_fileerror = 0;
-
-	    	/* if there's already a file open, close it */
-	    if (x->x_fd >= 0)
-	    {
-	    	fd = x->x_fd;
-	    	pthread_mutex_unlock(&x->x_mutex);
-    	    	close (fd);
-    	    	pthread_mutex_lock(&x->x_mutex);
-	    	x->x_fd = -1;
-		if (x->x_requestcode != REQUEST_BUSY)
-		    goto lost;
-	    }
-    	    	/* open the soundfile with the mutex unlocked */
-	    pthread_mutex_unlock(&x->x_mutex);
-	    fd = open_soundfile(dirname, filename,
-	    	skipheaderbytes, &bytespersample, &bigendian,
-		&sfchannels, &bytelimit, onsetframes);	    
-	    pthread_mutex_lock(&x->x_mutex);
-
-    	    pute("5\n");
-    	    	/* copy back into the instance structure. */
-	    x->x_bytespersample = bytespersample;
-	    x->x_sfchannels = sfchannels;
-	    x->x_bigendian = bigendian;
-	    x->x_fd = fd;
-	    x->x_bytelimit = bytelimit;
-	    if (fd < 0)
-	    {
-    	    	x->x_fileerror = errno;
-		x->x_eof = 1;
-    	    	pute("open failed\n");
-    	    	pute(filename);
-    	    	pute(dirname);
-		goto lost;
-	    }
-	    	/* check if another request has been made; if so, field it */
-	    if (x->x_requestcode != REQUEST_BUSY)
-	    	goto lost;
-    	    pute("6\n");
-    	    x->x_fifohead = 0;
-	    	    /* set fifosize from bufsize.  fifosize must be a
-		    multiple of the number of bytes eaten for each DSP
-		    tick.  We pessimistically assume MAXVECSIZE samples
-		    per tick since that could change.  There could be a
-		    problem here if the vector size increases while a
-		    soundfile is being played...  */
-	    x->x_fifosize = x->x_bufsize - (x->x_bufsize %
-	    	(x->x_bytespersample * x->x_sfchannels * MAXVECSIZE));
-		    /* arrange for the "request" condition to be signalled 16
-		    times per buffer */
-    	    sprintf(boo, "fifosize %d\n", 
-    	    	x->x_fifosize);
-    	    pute(boo);
-	    x->x_sigcountdown = x->x_sigperiod =
-	    	(x->x_fifosize /
-		    (16 * x->x_bytespersample * x->x_sfchannels *
-		    	x->x_vecsize));
-    	    	/* in a loop, wait for the fifo to get hungry and feed it */
-
-	    while (x->x_requestcode == REQUEST_BUSY)
-	    {
-	    	int fifosize = x->x_fifosize;
-    	    	pute("77\n");
-		if (x->x_eof)
-		    break;
-		if (x->x_fifohead >= x->x_fifotail)
-		{
-		    	/* if the head is >= the tail, we can immediately read
-		    	to the end of the fifo.  Unless, that is, we would
-			read all the way to the end of the buffer and the 
-			"tail" is zero; this would fill the buffer completely
-			which isn't allowed because you can't tell a completely
-			full buffer from an empty one. */
-		    if (x->x_fifotail || (fifosize - x->x_fifohead > READSIZE))
-		    {
-		    	wantbytes = fifosize - x->x_fifohead;
-			if (wantbytes > READSIZE)
-			    wantbytes = READSIZE;
-			if (wantbytes > x->x_bytelimit)
-			    wantbytes = x->x_bytelimit;
-		    	sprintf(boo, "head %d, tail %d, size %d\n", 
-			    x->x_fifohead, x->x_fifotail, wantbytes);
-			pute(boo);
-		    }
-		    else
-		    {
-    	    	    	pute("wait 7a ...\n");
-	    	    	sfread_cond_signal(&x->x_answercondition);
-			pute("signalled\n");
-		    	sfread_cond_wait(&x->x_requestcondition,
-			    &x->x_mutex);
-    	    	    	pute("7a done\n");
-		    	continue;
-		    }
-		}
-		else
-		{
-		    	/* otherwise check if there are at least READSIZE
-			bytes to read.  If not, wait and loop back. */
-		    wantbytes =  x->x_fifotail - x->x_fifohead - 1;
-		    if (wantbytes < READSIZE)
-		    {
-    	    	    	pute("wait 7...\n");
-	    	    	sfread_cond_signal(&x->x_answercondition);
-		    	sfread_cond_wait(&x->x_requestcondition,
-			    &x->x_mutex);
-    	    	    	pute("7 done\n");
-			continue;
-		    }
-		    else wantbytes = READSIZE;
-		}
-    	    	pute("8\n");
-		fd = x->x_fd;
-		buf = x->x_buf;
-		fifohead = x->x_fifohead;
-	    	pthread_mutex_unlock(&x->x_mutex);
-		sysrtn = read(fd, buf + fifohead, wantbytes);
-	    	pthread_mutex_lock(&x->x_mutex);
-		if (x->x_requestcode != REQUEST_BUSY)
-		    break;
-		if (sysrtn < 0)
-		{
-		    pute("fileerror\n");
-	    	    x->x_fileerror = errno;
-		    break;
-		}
-    	    	else if (sysrtn == 0)
-		{
-		    x->x_eof = 1;
-		    break;
-		}
-		else
-		{
-		    x->x_fifohead += sysrtn;
-		    x->x_bytelimit -= sysrtn;
-		    if (x->x_bytelimit <= 0)
-		    {
-		    	x->x_eof = 1;
-		    	break;
-		    }
-		    if (x->x_fifohead == fifosize)
-    	    	    	x->x_fifohead = 0;
-    	    	}
-    	    	sprintf(boo, "after: head %d, tail %d\n", 
-    	    	    x->x_fifohead, x->x_fifotail);
-    	    	pute(boo);
-		    /* signal parent in case it's waiting for data */
-		sfread_cond_signal(&x->x_answercondition);
-	    }
-    	lost:
-
-    	    if (x->x_requestcode == REQUEST_BUSY)
-	    	x->x_requestcode = REQUEST_NOTHING;
-    	    	/* fell out of read loop: close file if necessary,
-		set EOF and signal once more */
-	    if (x->x_fd >= 0)
-	    {
-	    	fd = x->x_fd;
-    	    	pthread_mutex_unlock(&x->x_mutex);
-    	    	close (fd);
-    	    	pthread_mutex_lock(&x->x_mutex);
-	    	x->x_fd = -1;
-    	    }
-	    sfread_cond_signal(&x->x_answercondition);
-
-	}
-	else if (x->x_requestcode == REQUEST_CLOSE)
-	{
-	    if (x->x_fd >= 0)
-	    {
-	    	fd = x->x_fd;
-	    	pthread_mutex_unlock(&x->x_mutex);
-    	    	close (fd);
-    	    	pthread_mutex_lock(&x->x_mutex);
-	    	x->x_fd = -1;
-	    }
-	    if (x->x_requestcode == REQUEST_CLOSE)
-	    	x->x_requestcode = REQUEST_NOTHING;
-	    sfread_cond_signal(&x->x_answercondition);
-	}
-	else if (x->x_requestcode == REQUEST_QUIT)
-	{
-	    if (x->x_fd >= 0)
-	    {
-	    	fd = x->x_fd;
-	    	pthread_mutex_unlock(&x->x_mutex);
-    	    	close (fd);
-    	    	pthread_mutex_lock(&x->x_mutex);
-		x->x_fd = -1;
-	    }
-	    x->x_requestcode = REQUEST_NOTHING;
-	    sfread_cond_signal(&x->x_answercondition);
-	    break;
-	}
-	else
-	{
-	    pute("13\n");
-	}
-    }
-    pute("thread exit\n");
-    pthread_mutex_unlock(&x->x_mutex);
-    return (0);
-}
-
-/******** the object proper runs in the calling (parent) thread ****/
-
-static void readsf_tick(t_readsf *x);
-
-static void *readsf_new(t_floatarg fnchannels, t_floatarg fbufsize)
-{
-    t_readsf *x;
-    int nchannels = fnchannels, bufsize = fbufsize, i;
-    char *buf;
-    
-    if (nchannels < 1)
-    	nchannels = 1;
-    else if (nchannels > MAXSFCHANS)
-    	nchannels = MAXSFCHANS;
-    if (bufsize <= 0) bufsize = DEFBUFPERCHAN * nchannels;
-    else if (bufsize < MINBUFSIZE)
-    	bufsize = MINBUFSIZE;
-    else if (bufsize > MAXBUFSIZE)
-    	bufsize = MAXBUFSIZE;
-    buf = getbytes(bufsize);
-    if (!buf) return (0);
-    
-    x = (t_readsf *)pd_new(readsfv_class);
-
-    for (i = 0; i < nchannels; i++)
-    	outlet_new(&x->x_obj, gensym("signal"));
-    x->x_noutlets = nchannels;
-    x->x_bangout = outlet_new(&x->x_obj, &s_bang);
-    pthread_mutex_init(&x->x_mutex, 0);
-    pthread_cond_init(&x->x_requestcondition, 0);
-    pthread_cond_init(&x->x_answercondition, 0);
-    x->x_vecsize = MAXVECSIZE;
-    x->x_state = STATE_IDLE;
-    x->x_clock = clock_new(x, (t_method)readsf_tick);
-    x->x_canvas = canvas_getcurrent();
-    x->x_bytespersample = 2;
-    x->x_sfchannels = 1;
-    x->x_fd = -1;
-    x->x_buf = buf;
-    x->x_bufsize = bufsize;
-    x->x_fifosize = x->x_fifohead = x->x_fifotail = x->x_requestcode = 0;
-    pthread_create(&x->x_childthread, 0, readsf_child_main, x);
-    return (x);
-}
-
-static void readsf_tick(t_readsf *x)
-{
-    outlet_bang(x->x_bangout);
-}
-
-static t_int *readsf_perform(t_int *w)
-{
-    t_readsf *x = (t_readsf *)(w[1]);
-    int vecsize = x->x_vecsize, noutlets = x->x_noutlets, i, j,
-    	bytespersample = x->x_bytespersample,
-	bigendian = x->x_bigendian,wantsamples;
-    float *fp,tmp,speed=x->x_speed;
-    if (x->x_state == STATE_STREAM)
-    {
-    	int wantbytes, nchannels, sfchannels = x->x_sfchannels;
-    	pthread_mutex_lock(&x->x_mutex);
-	tmp=vecsize *speed+x->x_frac;
-	wantsamples=(int)tmp;
-	x->x_frac=tmp-wantsamples;
-
-	if(!speed) goto idle;
-
-	wantbytes = sfchannels * wantsamples * bytespersample;
-
-	while (
-	    !x->x_eof && x->x_fifohead >= x->x_fifotail &&
-	    	x->x_fifohead < x->x_fifotail + wantbytes-1)
-	{
-	    pute("wait...\n");
-	    sfread_cond_signal(&x->x_requestcondition);
-	    sfread_cond_wait(&x->x_answercondition, &x->x_mutex);
-	    pute("done\n");
-	}
-	if (x->x_eof && x->x_fifohead >= x->x_fifotail &&
-	    x->x_fifohead < x->x_fifotail + wantbytes-1)
-	{
-	    if (x->x_fileerror)
-	    {
-	    	pd_error(x, "dsp: %s: %s", x->x_filename,
-		    (x->x_fileerror == EIO ?
-		    	"unknown or bad header format" :
-		    	    strerror(x->x_fileerror)));
-	    }
-	    clock_delay(x->x_clock, 0);
-	    x->x_state = STATE_IDLE;
-	    sfread_cond_signal(&x->x_requestcondition);
-	    pthread_mutex_unlock(&x->x_mutex);
-	    goto idle;
-	}
-
-	if(speed==1)
-		soundfile_xferin(sfchannels, noutlets, x->x_outvec, 0,
-    	    (unsigned char *)(x->x_buf + x->x_fifotail), vecsize,
-	    	bytespersample, bigendian);
-	else {
-		soundfile_xferin(sfchannels, noutlets, tmpvec, 0,
-    	    (unsigned char *)(x->x_buf + x->x_fifotail), wantsamples,
-	    	bytespersample, bigendian);
-		interpolate(noutlets,tmpvec,wantsamples,x->x_outvec,vecsize);
-	}
-
-	x->x_fifotail += wantbytes;
-	if (x->x_fifotail >= x->x_fifosize)
-	    x->x_fifotail = 0;
-	if ((--x->x_sigcountdown) <= 0)
-	{
-    	    sfread_cond_signal(&x->x_requestcondition);
-	    x->x_sigcountdown = x->x_sigperiod;
-	}
-	pthread_mutex_unlock(&x->x_mutex);
-    }
-    else
-    {
-    idle:
-    	for (i = 0; i < noutlets; i++)
-	    for (j = vecsize, fp = x->x_outvec[i]; j--; )
-	    	*fp++ = 0;
-    }
-    return (w+2);
-}
-
-static void readsf_start(t_readsf *x)
-{
-    /* start making output.  If we're in the "startup" state change
-    to the "running" state. */
-    if (x->x_state == STATE_STARTUP)
-	x->x_state = STATE_STREAM;
-    else pd_error(x, "readsf: start requested with no prior 'open'");
-}
-
-static void readsf_stop(t_readsf *x)
-{
-    	/* LATER rethink whether you need the mutex just to set a variable? */
-    pthread_mutex_lock(&x->x_mutex);
-    x->x_state = STATE_IDLE;
-    x->x_requestcode = REQUEST_CLOSE;
-    sfread_cond_signal(&x->x_requestcondition);
-    pthread_mutex_unlock(&x->x_mutex);
-}
-
-static void readsf_float(t_readsf *x, t_floatarg f)
-{
-    if (f != 0)
-    	readsf_start(x);
-    else readsf_stop(x);
-}
-
-static void readsf_speed(t_readsf *x, t_floatarg f)
-{
-    if((f>=0)&&(f<=8))
-    	x->x_speed=f;
-}
-
-    /* open method.  Called as:
-    open filename [skipframes headersize channels bytespersamp endianness]
-    	(if headersize is zero, header is taken to be automatically
-	detected; thus, use the special "-1" to mean a truly headerless file.)
-    */
-
-static void readsf_open(t_readsf *x, t_symbol *s, int argc, t_atom *argv)
-{
-    t_symbol *filesym = atom_getsymbolarg(0, argc, argv);
-    t_float onsetframes = atom_getfloatarg(1, argc, argv);
-    t_float headerbytes = atom_getfloatarg(2, argc, argv);
-    t_float channels = atom_getfloatarg(3, argc, argv);
-    t_float bytespersamp = atom_getfloatarg(4, argc, argv);
-    t_symbol *endian = atom_getsymbolarg(5, argc, argv);
-    if (!*filesym->s_name)
-    	return;
-    pthread_mutex_lock(&x->x_mutex);
-    x->x_requestcode = REQUEST_OPEN;
-    x->x_filename = filesym->s_name;
-    x->x_fifotail = 0;
-    x->x_fifohead = 0;
-    if (*endian->s_name == 'b')
-    	 x->x_bigendian = 1;
-    else if (*endian->s_name == 'l')
-    	 x->x_bigendian = 0;
-    else if (*endian->s_name)
-    	pd_error(x, "endianness neither 'b' nor 'l'");
-    else x->x_bigendian = garray_ambigendian();
-    x->x_onsetframes = (onsetframes > 0 ? onsetframes : 0);
-    x->x_skipheaderbytes = (headerbytes > 0 ? headerbytes : 
-    	(headerbytes == 0 ? -1 : 0));
-    x->x_sfchannels = (channels >= 1 ? channels : 1);
-    x->x_bytespersample = (bytespersamp > 2 ? bytespersamp : 2);
-    x->x_eof = 0;
-    x->x_fileerror = 0;
-    x->x_state = STATE_STARTUP;
-    x->x_speed=1;
-    x->x_frac=0;
-    sfread_cond_signal(&x->x_requestcondition);
-    pthread_mutex_unlock(&x->x_mutex);
-}
-
-static void readsf_dsp(t_readsf *x, t_signal **sp)
-{
-    int i, noutlets = x->x_noutlets;
-    pthread_mutex_lock(&x->x_mutex);
-    x->x_vecsize = sp[0]->s_n;
-    
-    x->x_sigperiod = (x->x_fifosize /
-    	(x->x_bytespersample * x->x_sfchannels * x->x_vecsize));
-    for (i = 0; i < noutlets; i++)
-    	x->x_outvec[i] = sp[i]->s_vec;
-    pthread_mutex_unlock(&x->x_mutex);
-    dsp_add(readsf_perform, 1, x);
-}
-
-static void readsf_print(t_readsf *x)
-{
-    post("state %d", x->x_state);
-    post("fifo head %d", x->x_fifohead);
-    post("fifo tail %d", x->x_fifotail);
-    post("fifo size %d", x->x_fifosize);
-    post("fd %d", x->x_fd);
-    post("eof %d", x->x_eof);
-}
-
-static void readsf_free(t_readsf *x)
-{
-    	/* request QUIT and wait for acknowledge */
-    void *threadrtn;
-    pthread_mutex_lock(&x->x_mutex);
-    x->x_requestcode = REQUEST_QUIT;
-    post("stopping readsf thread...");
-    sfread_cond_signal(&x->x_requestcondition);
-    while (x->x_requestcode != REQUEST_NOTHING)
-    {
-    	post("signalling...");
-	sfread_cond_signal(&x->x_requestcondition);
-    	sfread_cond_wait(&x->x_answercondition, &x->x_mutex);
-    }
-    pthread_mutex_unlock(&x->x_mutex);
-    if (pthread_join(x->x_childthread, &threadrtn))
-    	error("readsf_free: join failed");
-    post("... done.");
-    
-    pthread_cond_destroy(&x->x_requestcondition);
-    pthread_cond_destroy(&x->x_answercondition);
-    pthread_mutex_destroy(&x->x_mutex);
-    freebytes(x->x_buf, x->x_bufsize);
-    clock_free(x->x_clock);
-}
-
-#endif /* __linux__ */
-
-void readsfv_tilde_setup(void)
-{
-#ifdef __linux__
-    int i;
-
-    readsfv_class = class_new(gensym("readsfv~"), (t_newmethod)readsf_new,
-    	(t_method)readsf_free, sizeof(t_readsf), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
-
-    class_addfloat(readsfv_class, (t_method)readsf_float);
-    class_addmethod(readsfv_class, (t_method)readsf_speed, gensym("speed"), A_FLOAT,0);
-    class_addmethod(readsfv_class, (t_method)readsf_start, gensym("start"), 0);
-    class_addmethod(readsfv_class, (t_method)readsf_stop, gensym("stop"), 0);
-    class_addmethod(readsfv_class, (t_method)readsf_dsp, gensym("dsp"), 0);
-    class_addmethod(readsfv_class, (t_method)readsf_open, gensym("open"),
-    	A_GIMME, 0);
-    class_addmethod(readsfv_class, (t_method)readsf_print, gensym("print"), 0);
-
-    for(i=0;i<MAXSFCHANS;i++)
-    	tmpvec[i]=getbytes(sizeof(t_sample)*8*1024);
-#endif /* __linux__ */
-}
-
-
-
-#endif /* NOT _WIN32 */
+#ifndef _WIN32
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution.  */
+
+/* this file contains, first, a collection of soundfile access routines, a
+sort of soundfile library.  Second, the "soundfiler" object is defined which
+uses the routines to read or write soundfiles, synchronously, from garrays.
+These operations are not to be done in "real time" as they may have to wait
+for disk accesses (even the write routine.)  Finally, the realtime objects
+readsf~ and writesf~ are defined which confine disk operations to a separate
+thread so that they can be used in real time.  The real-time disk access
+objects are available for linux only so far, although they could be compiled
+for Windows if someone were willing to find a Pthreads package for it. */
+
+/* this is a partial copy of d_soundfile, with some hacking:
+	1: a fix in soundfiler to compute the normalization factor only on
+		the samples we want to write on the disk...
+	2: a version of readsf~ that works with a (positive) speed parameter.
+
+	Antoine Rousseau
+*/
+
+#include <pthread.h>
+#ifdef _WIN32
+#include <io.h>
+#else
+#include <unistd.h>
+#include <fcntl.h>
+#endif
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "m_pd.h"
+
+#define MAXSFCHANS 4
+
+
+/***************** soundfile header structures ************************/
+
+typedef unsigned short uint16;
+typedef unsigned long uint32;
+
+#define FORMAT_WAVE 0
+#define FORMAT_AIFF 1
+#define FORMAT_NEXT 2
+
+/* the NeXTStep sound header structure; can be big or little endian  */
+
+typedef struct _nextstep
+{
+    char ns_fileid[4]; 	    /* magic number '.snd' if file is big-endian */
+    uint32 ns_onset; 	    /* byte offset of first sample */
+    uint32 ns_length;	    /* length of sound in bytes */
+    uint32 ns_format;        /* format; see below */
+    uint32 ns_sr;    	    /* sample rate */
+    uint32 ns_nchans;	    /* number of channels */
+    char ns_info[4];   	    /* comment */
+} t_nextstep;
+
+#define NS_FORMAT_LINEAR_16	3
+#define NS_FORMAT_LINEAR_24	4
+#define NS_FORMAT_FLOAT         6
+#define SCALE (1./(1024. * 1024. * 1024. * 2.))
+
+/* the WAVE header.  All Wave files are little endian.  We assume
+    the "fmt" chunk comes first which is usually the case but perhaps not
+    always; same for AIFF and the "COMM" chunk.   */
+
+typedef unsigned word;
+typedef unsigned long dword;
+
+typedef struct _wave
+{
+    char  w_fileid[4];	    	    /* chunk id 'RIFF'            */
+    uint32 w_chunksize;     	    /* chunk size                 */
+    char  w_waveid[4];	    	    /* wave chunk id 'WAVE'       */
+    char  w_fmtid[4];	    	    /* format chunk id 'fmt '     */
+    uint32 w_fmtchunksize;   	    /* format chunk size          */
+    uint16  w_fmttag;	    	    /* format tag, 1 for PCM      */
+    uint16  w_nchannels;    	    /* number of channels         */
+    uint32 w_samplespersec;  	    /* sample rate in hz          */
+    uint32 w_navgbytespersec; 	    /* average bytes per second   */
+    uint16  w_nblockalign;    	    /* number of bytes per sample */
+    uint16  w_nbitspersample; 	    /* number of bits in a sample */
+    char  w_datachunkid[4]; 	    /* data chunk id 'data'       */
+    uint32 w_datachunksize;         /* length of data chunk       */
+} t_wave;
+
+typedef struct _fmt	    /* format chunk */
+{
+    uint16 f_fmttag;	    	    /* format tag, 1 for PCM      */
+    uint16 f_nchannels;    	    /* number of channels         */
+    uint32 f_samplespersec;  	    /* sample rate in hz          */
+    uint32 f_navgbytespersec; 	    /* average bytes per second   */
+    uint16 f_nblockalign;    	    /* number of bytes per frame  */
+    uint16 f_nbitspersample; 	    /* number of bits in a sample */
+} t_fmt;
+
+typedef struct _wavechunk	    /* ... and the last two items */
+{
+    char  wc_id[4]; 	    	    /* data chunk id, e.g., 'data' or 'fmt ' */
+    uint32 wc_size;         	    /* length of data chunk       */
+} t_wavechunk;
+
+/* the AIFF header.  I'm assuming AIFC is compatible but don't really know
+    that. */
+
+typedef struct _datachunk
+{
+    char  dc_id[4]; 	    	    /* data chunk id 'SSND'       */
+    uint32 dc_size;         	    /* length of data chunk       */
+} t_datachunk;
+
+//#define CHUNKHDRSIZE sizeof(t_datachunk)
+
+typedef struct _comm
+{
+    uint16 c_nchannels;	            /* number of channels         */
+    uint16 c_nframeshi;    	    /* # of sample frames (hi)    */
+    uint16 c_nframeslo;    	    /* # of sample frames (lo)    */
+    uint16 c_bitspersamp;  	    /* bits per sample            */
+    unsigned char c_samprate[10];   /* sample rate, 80-bit float! */
+} t_comm;
+
+/* this version is more convenient for writing them out: */
+typedef struct _aiff
+{
+    char  a_fileid[4];	    	    /* chunk id 'FORM'            */
+    uint32 a_chunksize;     	    /* chunk size                 */
+    char  a_aiffid[4];	    	    /* aiff chunk id 'AIFF'       */
+    char  a_fmtid[4];	    	    /* format chunk id 'COMM'     */
+    uint32 a_fmtchunksize;   	    /* format chunk size, 18      */
+    uint16 a_nchannels;	            /* number of channels         */
+    uint16 a_nframeshi;    	    /* # of sample frames (hi)    */
+    uint16 a_nframeslo;    	    /* # of sample frames (lo)    */
+    uint16 a_bitspersamp;  	    /* bits per sample            */
+    unsigned char a_samprate[10];   /* sample rate, 80-bit float! */
+} t_aiff;
+
+#define AIFFHDRSIZE 38	    /* probably not what sizeof() gives */
+
+
+#define AIFFPLUS (AIFFHDRSIZE + 8)  /* header size including first chunk hdr */
+
+#define WHDR1 sizeof(t_nextstep)
+#define WHDR2 (sizeof(t_wave) > WHDR1 ? sizeof (t_wave) : WHDR1)
+#define WRITEHDRSIZE (AIFFPLUS > WHDR2 ? AIFFPLUS : WHDR2)
+
+#define READHDRSIZE (16 > WHDR2 ? 16 : WHDR2)
+
+#define OBUFSIZE MAXPDSTRING  /* assume MAXPDSTRING is bigger than headers */
+
+#ifdef _WIN32
+#include <fcntl.h>
+#define BINCREATE _O_WRONLY | _O_CREAT | _O_BINARY | _O_TRUNC |
+#else
+#define BINCREATE O_WRONLY|O_CREAT|O_TRUNC
+#endif
+
+/* this routine returns 1 if the high order byte comes at the lower
+address on our architecture (big-endianness.).  It's 1 for Motorola,
+0 for Intel: */
+
+extern int garray_ambigendian(void);
+
+/* byte swappers */
+
+static uint32 swap4(uint32 n, int doit)
+{
+    if (doit)
+        return (((n & 0xff) << 24) | ((n & 0xff00) << 8) |
+                ((n & 0xff0000) >> 8) | ((n & 0xff000000) >> 24));
+    else return (n);
+}
+
+static uint16 swap2(uint32 n, int doit)
+{
+    if (doit)
+        return (((n & 0xff) << 8) | ((n & 0xff00) >> 8));
+    else return (n);
+}
+
+static void swapstring(char *foo, int doit)
+{
+    if (doit)
+    {
+        char a = foo[0], b = foo[1], c = foo[2], d = foo[3];
+        foo[0] = d;
+        foo[1] = c;
+        foo[2] = b;
+        foo[3] = a;
+    }
+}
+
+/******************** soundfile access routines **********************/
+
+void readsf_banana( void);    /* debugging */
+
+/* This routine opens a file, looks for either a nextstep or "wave" header,
+* seeks to end of it, and fills in bytes per sample and number of channels.
+* Only 2- and 3-byte fixed-point samples and 4-byte floating point samples
+* are supported.  If "headersize" is nonzero, the
+* caller should supply the number of channels, endinanness, and bytes per
+* sample; the header is ignored.  Otherwise, the routine tries to read the
+* header and fill in the properties.
+*/
+
+extern int open_soundfile(const char *dirname, const char *filename, int headersize,
+                          int *p_bytespersamp, int *p_bigendian, int *p_nchannels, long *p_bytelimit,
+                          long skipframes);
+
+
+static void soundfile_xferin(int sfchannels, int nvecs, float **vecs,
+                             long itemsread, unsigned char *buf, int nitems, int bytespersamp,
+                             int bigendian)
+{
+    int i, j;
+    unsigned char *sp, *sp2;
+    float *fp;
+    int nchannels = (sfchannels < nvecs ? sfchannels : nvecs);
+    int bytesperframe = bytespersamp * sfchannels;
+    for (i = 0, sp = buf; i < nchannels; i++, sp += bytespersamp)
+    {
+        if (bytespersamp == 2)
+        {
+            if (bigendian)
+            {
+                for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
+                        j < nitems; j++, sp2 += bytesperframe, fp++)
+                    *fp = SCALE * ((sp2[0] << 24) | (sp2[1] << 16));
+            }
+            else
+            {
+                for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
+                        j < nitems; j++, sp2 += bytesperframe, fp++)
+                    *fp = SCALE * ((sp2[1] << 24) | (sp2[0] << 16));
+            }
+        }
+        else if (bytespersamp == 3)
+        {
+            if (bigendian)
+            {
+                for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
+                        j < nitems; j++, sp2 += bytesperframe, fp++)
+                    *fp = SCALE * ((sp2[0] << 24) | (sp2[1] << 16)
+                                   | (sp2[2] << 8));
+            }
+            else
+            {
+                for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
+                        j < nitems; j++, sp2 += bytesperframe, fp++)
+                    *fp = SCALE * ((sp2[2] << 24) | (sp2[1] << 16)
+                                   | (sp2[0] << 8));
+            }
+        }
+        else if (bytespersamp == 4)
+        {
+            if (bigendian)
+            {
+                for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
+                        j < nitems; j++, sp2 += bytesperframe, fp++)
+                    *(long *)fp = ((sp2[0] << 24) | (sp2[1] << 16)
+                                   | (sp2[2] << 8) | sp2[3]);
+            }
+            else
+            {
+                for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
+                        j < nitems; j++, sp2 += bytesperframe, fp++)
+                    *(long *)fp = ((sp2[3] << 24) | (sp2[2] << 16)
+                                   | (sp2[1] << 8) | sp2[0]);
+            }
+        }
+    }
+    /* zero out other outputs */
+    for (i = sfchannels; i < nvecs; i++)
+        for (j = nitems, fp = vecs[i]; j--; )
+            *fp++ = 0;
+
+}
+
+static void interpolate(int nvec,float **invec,int nin,
+                        float **outvec,int nout)
+{
+
+    float r=nin/(float)nout;
+    int i,j;
+
+
+    for(i=0; i<nout; i++)
+        for(j=0; j<nvec; j++)
+            outvec[j][i]=invec[j][(int)(i*r)];
+
+}
+/* soundfiler2_write ...
+
+usage: write [flags] filename table ...
+flags:
+-nframes <frames>
+-skip <frames>
+-bytes <bytes per sample>
+-normalize
+-nextstep
+-wave
+-big
+-little
+*/
+
+/* the routine which actually does the work should LATER also be called
+from garray_write16. */
+
+
+/* Parse arguments for writing.  The "obj" argument is only for flagging
+errors.  For streaming to a file the "normalize", "onset" and "nframes"
+arguments shouldn't be set but the calling routine flags this. */
+
+static int soundfiler2_writeargparse(void *obj, int *p_argc, t_atom **p_argv,
+                                     t_symbol **p_filesym,
+                                     int *p_filetype, int *p_bytespersamp, int *p_swap, int *p_bigendian,
+                                     int *p_normalize, long *p_onset, long *p_nframes,float *p_amp)
+{
+    int argc = *p_argc;
+    t_atom *argv = *p_argv;
+    int bytespersamp = 2, bigendian = 0,
+        endianness = -1, swap, filetype = FORMAT_WAVE, normalize = 0;
+    long onset = 0, nframes = 0x7fffffff;
+    float amp=1;
+    t_symbol *filesym;
+    while (argc > 0 && argv->a_type == A_SYMBOL &&
+            *argv->a_w.w_symbol->s_name == '-')
+    {
+        char *flag = argv->a_w.w_symbol->s_name + 1;
+        if (!strcmp(flag, "skip"))
+        {
+            if (argc < 2 || argv[1].a_type != A_FLOAT ||
+                    ((onset = argv[1].a_w.w_float) < 0))
+                goto usage;
+            argc -= 2;
+            argv += 2;
+        }
+        else if (!strcmp(flag, "nframes"))
+        {
+            if (argc < 2 || argv[1].a_type != A_FLOAT ||
+                    ((nframes = argv[1].a_w.w_float) < 0))
+                goto usage;
+            argc -= 2;
+            argv += 2;
+        }
+        else if (!strcmp(flag, "bytes"))
+        {
+            if (argc < 2 || argv[1].a_type != A_FLOAT ||
+                    ((bytespersamp = argv[1].a_w.w_float) < 2) ||
+                    bytespersamp > 4)
+                goto usage;
+            argc -= 2;
+            argv += 2;
+        }
+        else if (!strcmp(flag, "normalize"))
+        {
+            normalize = 1;
+            argc -= 1;
+            argv += 1;
+        }
+        else if (!strcmp(flag, "amp"))
+        {
+            if (argc < 2 || argv[1].a_type != A_FLOAT)
+                goto usage;
+            amp = argv[1].a_w.w_float;
+            argc -= 2;
+            argv += 2;
+        }
+        else if (!strcmp(flag, "wave"))
+        {
+            filetype = FORMAT_WAVE;
+            argc -= 1;
+            argv += 1;
+        }
+        else if (!strcmp(flag, "nextstep"))
+        {
+            filetype = FORMAT_NEXT;
+            argc -= 1;
+            argv += 1;
+        }
+        else if (!strcmp(flag, "aiff"))
+        {
+            filetype = FORMAT_AIFF;
+            argc -= 1;
+            argv += 1;
+        }
+        else if (!strcmp(flag, "big"))
+        {
+            endianness = 1;
+            argc -= 1;
+            argv += 1;
+        }
+        else if (!strcmp(flag, "little"))
+        {
+            endianness = 1;
+            argc -= 1;
+            argv += 1;
+        }
+        else goto usage;
+    }
+    /* only NextStep handles floating point samples */
+    if (bytespersamp == 4)
+        filetype = FORMAT_NEXT;
+
+    /* for WAVE force little endian; for nextstep use machine native */
+    if (filetype == FORMAT_WAVE)
+    {
+        bigendian = 0;
+        if (endianness == 1)
+            pd_error(obj, "WAVE file forced to little endian");
+    }
+    else if (filetype == FORMAT_AIFF)
+    {
+        bigendian = 1;
+        if (endianness == 0)
+            pd_error(obj, "AIFF file forced to big endian");
+    }
+    else if (endianness == -1)
+    {
+        bigendian = garray_ambigendian();
+    }
+    swap = (bigendian != garray_ambigendian());
+    if (!argc || argv->a_type != A_SYMBOL)
+        goto usage;
+    filesym = argv->a_w.w_symbol;
+    argc--;
+    argv++;
+
+    *p_argc = argc;
+    *p_argv = argv;
+    *p_filesym = filesym;
+    *p_filetype = filetype;
+    *p_bytespersamp = bytespersamp;
+    *p_swap = swap;
+    *p_normalize = normalize;
+    *p_onset = onset;
+    *p_nframes = nframes;
+    *p_bigendian = bigendian;
+    *p_amp = amp;
+    return (0);
+usage:
+    return (-1);
+}
+
+static int create_soundfile2(t_canvas *canvas, const char *filename,
+                             int filetype, int nframes, int bytespersamp,
+                             int bigendian, int nchannels, int swap)
+{
+    char filenamebuf[MAXPDSTRING], buf2[MAXPDSTRING];
+    char headerbuf[WRITEHDRSIZE];
+    t_wave *wavehdr = (t_wave *)headerbuf;
+    t_nextstep *nexthdr = (t_nextstep *)headerbuf;
+    t_aiff *aiffhdr = (t_aiff *)headerbuf;
+    int fd, headersize = 0;
+
+    strncpy(filenamebuf, filename, MAXPDSTRING-10);
+    filenamebuf[MAXPDSTRING-10] = 0;
+
+    if (filetype == FORMAT_NEXT)
+    {
+        if (strcmp(filenamebuf + strlen(filenamebuf)-4, ".snd"))
+            strcat(filenamebuf, ".snd");
+        if (bigendian)
+            strncpy(nexthdr->ns_fileid, ".snd", 4);
+        else strncpy(nexthdr->ns_fileid, "dns.", 4);
+        nexthdr->ns_onset = swap4(sizeof(*nexthdr), swap);
+        nexthdr->ns_length = 0;
+        nexthdr->ns_format = swap4((bytespersamp == 3 ? NS_FORMAT_LINEAR_24 :
+                                    (bytespersamp == 4 ? NS_FORMAT_FLOAT : NS_FORMAT_LINEAR_16)), swap);;
+        nexthdr->ns_sr = swap4(44100, swap);     /* lie */
+        nexthdr->ns_nchans = swap4(nchannels, swap);
+        strcpy(nexthdr->ns_info, "Pd ");
+        swapstring(nexthdr->ns_info, swap);
+        headersize = sizeof(t_nextstep);
+    }
+    else if (filetype == FORMAT_AIFF)
+    {
+        long datasize = nframes * nchannels * bytespersamp;
+        long longtmp;
+        static unsigned char dogdoo[] =
+        {0x40, 0x0e, 0xac, 0x44, 0, 0, 0, 0, 0, 0, 'S', 'S', 'N', 'D'};
+        if (strcmp(filenamebuf + strlen(filenamebuf)-4, ".aif") &&
+                strcmp(filenamebuf + strlen(filenamebuf)-5, ".aiff"))
+            strcat(filenamebuf, ".aif");
+        strncpy(aiffhdr->a_fileid, "FORM", 4);
+        aiffhdr->a_chunksize = swap4(datasize + sizeof(*aiffhdr) + 4, swap);
+        strncpy(aiffhdr->a_aiffid, "AIFF", 4);
+        strncpy(aiffhdr->a_fmtid, "COMM", 4);
+        aiffhdr->a_fmtchunksize = swap4(18, swap);
+        aiffhdr->a_nchannels = swap2(nchannels, swap);
+        longtmp = swap4(nframes, swap);
+        memcpy(&aiffhdr->a_nframeshi, &longtmp, 4);
+        aiffhdr->a_bitspersamp = swap2(8 * bytespersamp, swap);
+        memcpy(aiffhdr->a_samprate, dogdoo, sizeof(dogdoo));
+        longtmp = swap4(datasize, swap);
+        memcpy(aiffhdr->a_samprate + sizeof(dogdoo), &longtmp, 4);
+        headersize = AIFFPLUS;
+    }
+    else    /* WAVE format */
+    {
+        long datasize = nframes * nchannels * bytespersamp;
+        if (strcmp(filenamebuf + strlen(filenamebuf)-4, ".wav"))
+            strcat(filenamebuf, ".wav");
+        strncpy(wavehdr->w_fileid, "RIFF", 4);
+        wavehdr->w_chunksize = swap4(datasize + sizeof(*wavehdr) - 8, swap);
+        strncpy(wavehdr->w_waveid, "WAVE", 4);
+        strncpy(wavehdr->w_fmtid, "fmt ", 4);
+        wavehdr->w_fmtchunksize = swap4(16, swap);
+        wavehdr->w_fmttag = swap2(1, swap);
+        wavehdr->w_nchannels = swap2(nchannels, swap);
+        wavehdr->w_samplespersec = swap4(44100, swap);
+        wavehdr->w_navgbytespersec = swap4(44100 * nchannels * bytespersamp, swap);
+        wavehdr->w_nblockalign = swap2(bytespersamp, swap);
+        wavehdr->w_nbitspersample = swap2(8 * bytespersamp, swap);
+        strncpy(wavehdr->w_datachunkid, "data", 4);
+        wavehdr->w_datachunksize = swap4(datasize, swap);
+        headersize = sizeof(t_wave);
+    }
+
+    canvas_makefilename(canvas, filenamebuf, buf2, MAXPDSTRING);
+    if ((fd = sys_open(buf2, BINCREATE, 0666)) < 0)
+        return (-1);
+
+    if (write(fd, headerbuf, headersize) < headersize)
+    {
+        close (fd);
+        return (-1);
+    }
+    return (fd);
+}
+
+static void soundfile_finishwrite(void *obj, char *filename, int fd,
+                                  int filetype, long nframes, long itemswritten, int bytesperframe, int swap)
+{
+    if (itemswritten < nframes)
+    {
+        if (nframes < 0x7fffffff)
+            pd_error(obj, "soundfiler2_write: %d out of %d bytes written",
+                     itemswritten, nframes);
+        /* try to fix size fields in header */
+        if (filetype == FORMAT_WAVE)
+        {
+            long datasize = itemswritten * bytesperframe, mofo;
+
+            if (lseek(fd,
+                      ((char *)(&((t_wave *)0)->w_chunksize)) - (char *)0,
+                      SEEK_SET) == 0)
+                goto baddonewrite;
+            mofo = swap4(datasize + sizeof(t_wave) - 8, swap);
+            if (write(fd, (char *)(&mofo), 4) < 4)
+                goto baddonewrite;
+            if (lseek(fd,
+                      ((char *)(&((t_wave *)0)->w_datachunksize)) - (char *)0,
+                      SEEK_SET) == 0)
+                goto baddonewrite;
+            mofo = swap4(datasize, swap);
+            if (write(fd, (char *)(&mofo), 4) < 4)
+                goto baddonewrite;
+        }
+        if (filetype == FORMAT_AIFF)
+        {
+            long mofo;
+            if (lseek(fd,
+                      ((char *)(&((t_aiff *)0)->a_nframeshi)) - (char *)0,
+                      SEEK_SET) == 0)
+                goto baddonewrite;
+            mofo = swap4(nframes, swap);
+            if (write(fd, (char *)(&mofo), 4) < 4)
+                goto baddonewrite;
+        }
+    }
+    return;
+baddonewrite:
+    post("%s: %s", filename, strerror(errno));
+}
+
+static void soundfile_xferout(int nchannels, float **vecs,
+                              unsigned char *buf, int nitems, long onset, int bytespersamp,
+                              int bigendian, float normalfactor)
+{
+    int i, j;
+    unsigned char *sp, *sp2;
+    float *fp;
+    int bytesperframe = bytespersamp * nchannels;
+    long xx;
+    for (i = 0, sp = buf; i < nchannels; i++, sp += bytespersamp)
+    {
+        if (bytespersamp == 2)
+        {
+            float ff = normalfactor * 32768.;
+            if (bigendian)
+            {
+                for (j = 0, sp2 = sp, fp = vecs[i] + onset;
+                        j < nitems; j++, sp2 += bytesperframe, fp++)
+                {
+                    int xx = 32768. + (*fp * ff);
+                    xx -= 32768;
+                    if (xx < -32767)
+                        xx = -32767;
+                    if (xx > 32767)
+                        xx = 32767;
+                    sp2[0] = (xx >> 8);
+                    sp2[1] = xx;
+                }
+            }
+            else
+            {
+                for (j = 0, sp2 = sp, fp=vecs[i] + onset;
+                        j < nitems; j++, sp2 += bytesperframe, fp++)
+                {
+                    int xx = 32768. + (*fp * ff);
+                    xx -= 32768;
+                    if (xx < -32767)
+                        xx = -32767;
+                    if (xx > 32767)
+                        xx = 32767;
+                    sp2[1] = (xx >> 8);
+                    sp2[0] = xx;
+                }
+            }
+        }
+        else if (bytespersamp == 3)
+        {
+            float ff = normalfactor * 8388608.;
+            if (bigendian)
+            {
+                for (j = 0, sp2 = sp, fp=vecs[i] + onset;
+                        j < nitems; j++, sp2 += bytesperframe, fp++)
+                {
+                    int xx = 8388608. + (*fp * ff);
+                    xx -= 8388608;
+                    if (xx < -8388607)
+                        xx = -8388607;
+                    if (xx > 8388607)
+                        xx = 8388607;
+                    sp2[0] = (xx >> 16);
+                    sp2[1] = (xx >> 8);
+                    sp2[2] = xx;
+                }
+            }
+            else
+            {
+                for (j = 0, sp2 = sp, fp=vecs[i] + onset;
+                        j < nitems; j++, sp2 += bytesperframe, fp++)
+                {
+                    int xx = 8388608. + (*fp * ff);
+                    xx -= 8388608;
+                    if (xx < -8388607)
+                        xx = -8388607;
+                    if (xx > 8388607)
+                        xx = 8388607;
+                    sp2[2] = (xx >> 16);
+                    sp2[1] = (xx >> 8);
+                    sp2[0] = xx;
+                }
+            }
+        }
+        else if (bytespersamp == 4)
+        {
+            if (bigendian)
+            {
+                for (j = 0, sp2 = sp, fp=vecs[i] + onset;
+                        j < nitems; j++, sp2 += bytesperframe, fp++)
+                {
+                    float f2 = *fp * normalfactor;
+                    xx = *(long *)&f2;
+                    sp2[0] = (xx >> 24);
+                    sp2[1] = (xx >> 24);
+                    sp2[2] = (xx >> 24);
+                    sp2[3] = xx;
+                }
+            }
+            else
+            {
+                for (j = 0, sp2 = sp, fp=vecs[i] + onset;
+                        j < nitems; j++, sp2 += bytesperframe, fp++)
+                {
+                    float f2 = *fp * normalfactor;
+                    xx = *(long *)&f2;
+                    sp2[3] = (xx >> 24);
+                    sp2[2] = (xx >> 24);
+                    sp2[1] = (xx >> 24);
+                    sp2[0] = xx;
+                }
+            }
+        }
+    }
+}
+
+
+/* ------- soundfiler - reads and writes soundfiles to/from "garrays" ---- */
+#define DEFMAXSIZE 4000000 	/* default maximum 16 MB per channel */
+#define SAMPBUFSIZE 1024
+
+
+static t_class *soundfiler2_class;
+
+typedef struct _soundfiler2
+{
+    t_object x_obj;
+    t_canvas *x_canvas;
+} t_soundfiler2;
+
+static t_soundfiler2 *soundfiler2_new(void)
+{
+    t_soundfiler2 *x = (t_soundfiler2 *)pd_new(soundfiler2_class);
+    x->x_canvas = canvas_getcurrent();
+    outlet_new(&x->x_obj, &s_float);
+    return (x);
+}
+
+/* soundfiler2_read ...
+
+usage: read [flags] filename table ...
+flags:
+	-skip <frames> ... frames to skip in file
+-nframes <frames>
+-onset <frames> ... onset in table to read into (NOT DONE YET)
+-raw <headersize channels bytes endian>
+-resize
+-maxsize <max-size>
+*/
+
+static void soundfiler2_read(t_soundfiler2 *x, t_symbol *s,
+                             int argc, t_atom *argv)
+{
+    int headersize = -1, channels = 0, bytespersamp = 0, bigendian = 0,
+        resize = 0, i, j;
+    long skipframes = 0, nframes = 0, finalsize = 0, itemsleft,
+         maxsize = DEFMAXSIZE, itemsread = 0, bytelimit  = 0x7fffffff;
+    int fd = -1;
+    char endianness, *filename;
+    t_garray *garrays[MAXSFCHANS];
+    t_float *vecs[MAXSFCHANS];
+    char sampbuf[SAMPBUFSIZE];
+    int bufframes, nitems;
+    FILE *fp;
+    while (argc > 0 && argv->a_type == A_SYMBOL &&
+            *argv->a_w.w_symbol->s_name == '-')
+    {
+        char *flag = argv->a_w.w_symbol->s_name + 1;
+        if (!strcmp(flag, "skip"))
+        {
+            if (argc < 2 || argv[1].a_type != A_FLOAT ||
+                    ((skipframes = argv[1].a_w.w_float) < 0))
+                goto usage;
+            argc -= 2;
+            argv += 2;
+        }
+        else if (!strcmp(flag, "nframes"))
+        {
+            if (argc < 2 || argv[1].a_type != A_FLOAT ||
+                    ((nframes = argv[1].a_w.w_float) < 0))
+                goto usage;
+            argc -= 2;
+            argv += 2;
+        }
+        else if (!strcmp(flag, "raw"))
+        {
+            if (argc < 5 ||
+                    argv[1].a_type != A_FLOAT ||
+                    ((headersize = argv[1].a_w.w_float) < 0) ||
+                    argv[2].a_type != A_FLOAT ||
+                    ((channels = argv[2].a_w.w_float) < 1) ||
+                    (channels > MAXSFCHANS) ||
+                    argv[3].a_type != A_FLOAT ||
+                    ((bytespersamp = argv[3].a_w.w_float) < 2) ||
+                    (bytespersamp > 4) ||
+                    argv[4].a_type != A_SYMBOL ||
+                    ((endianness = argv[4].a_w.w_symbol->s_name[0]) != 'b'
+                     && endianness != 'l' && endianness != 'n'))
+                goto usage;
+            if (endianness == 'b')
+                bigendian = 1;
+            else if (endianness == 'l')
+                bigendian = 0;
+            else
+                bigendian = garray_ambigendian();
+            argc -= 5;
+            argv += 5;
+        }
+        else if (!strcmp(flag, "resize"))
+        {
+            resize = 1;
+            argc -= 1;
+            argv += 1;
+        }
+        else if (!strcmp(flag, "maxsize"))
+        {
+            if (argc < 2 || argv[1].a_type != A_FLOAT ||
+                    ((maxsize = argv[1].a_w.w_float) < 0))
+                goto usage;
+            resize = 1;     /* maxsize implies resize. */
+            argc -= 2;
+            argv += 2;
+        }
+        else goto usage;
+    }
+    if (argc < 2 || argc > MAXSFCHANS + 1 || argv[0].a_type != A_SYMBOL)
+        goto usage;
+    filename = argv[0].a_w.w_symbol->s_name;
+    argc--;
+    argv++;
+
+    for (i = 0; i < argc; i++)
+    {
+        int vecsize;
+        if (argv[i].a_type != A_SYMBOL)
+            goto usage;
+        if (!(garrays[i] =
+                    (t_garray *)pd_findbyclass(argv[i].a_w.w_symbol, garray_class)))
+        {
+            pd_error(x, "%s: no such table", argv[i].a_w.w_symbol->s_name);
+            goto done;
+        }
+        else if (!garray_getfloatarray(garrays[i], &vecsize, &vecs[i]))
+            error("%s: bad template for tabwrite",
+                  argv[i].a_w.w_symbol->s_name);
+        if (finalsize && finalsize != vecsize && !resize)
+        {
+            post("soundfiler2_read: arrays have different lengths; resizing...");
+            resize = 1;
+        }
+        finalsize = vecsize;
+    }
+    fd = open_soundfile(canvas_getdir(x->x_canvas)->s_name, filename,
+                        headersize, &bytespersamp, &bigendian, &channels, &bytelimit,
+                        skipframes);
+
+    if (fd < 0)
+    {
+        pd_error(x, "soundfiler2_read: %s: %s", filename, (errno == EIO ?
+                 "unknown or bad header format" : strerror(errno)));
+        goto done;
+    }
+
+    if (resize)
+    {
+        /* figure out what to resize to */
+        long poswas, eofis, framesinfile;
+
+        poswas = lseek(fd, 0, SEEK_CUR);
+        eofis = lseek(fd, 0, SEEK_END);
+        if (poswas < 0 || eofis < 0)
+        {
+            pd_error(x, "lseek failed");
+            goto done;
+        }
+        lseek(fd, poswas, SEEK_SET);
+        framesinfile = (eofis - poswas) / (channels * bytespersamp);
+        if (framesinfile > maxsize)
+        {
+            pd_error(x, "soundfiler2_read: truncated to %d elements", maxsize);
+            framesinfile = maxsize;
+        }
+        if (framesinfile > bytelimit / bytespersamp)
+            framesinfile = bytelimit / bytespersamp;
+        finalsize = framesinfile;
+        for (i = 0; i < argc; i++)
+        {
+            int vecsize;
+
+            garray_resize(garrays[i], finalsize);
+            /* for sanity's sake let's clear the save-in-patch flag here */
+            garray_setsaveit(garrays[i], 0);
+            garray_getfloatarray(garrays[i], &vecsize, &vecs[i]);
+            /* if the resize failed, garray_resize reported the error */
+            if (vecsize != framesinfile)
+            {
+                pd_error(x, "resize failed");
+                goto done;
+            }
+        }
+    }
+    if (!finalsize) finalsize = 0x7fffffff;
+    if (finalsize > bytelimit / bytespersamp)
+        finalsize = bytelimit / bytespersamp;
+    fp = fdopen(fd, "rb");
+    bufframes = SAMPBUFSIZE / (channels * bytespersamp);
+
+    for (itemsread = 0; itemsread < finalsize; )
+    {
+        int thisread = finalsize - itemsread;
+        thisread = (thisread > bufframes ? bufframes : thisread);
+        nitems = fread(sampbuf, channels * bytespersamp, thisread, fp);
+        if (nitems <= 0) break;
+        soundfile_xferin(channels, argc, vecs, itemsread,
+                         (unsigned char *)sampbuf, nitems, bytespersamp, bigendian);
+        itemsread += nitems;
+    }
+    /* zero out remaining elements of vectors */
+
+    for (i = 0; i < argc; i++)
+    {
+        int nzero, vecsize;
+        garray_getfloatarray(garrays[i], &vecsize, &vecs[i]);
+        for (j = itemsread; j < vecsize; j++)
+            vecs[i][j] = 0;
+    }
+    /* zero out vectors in excess of number of channels */
+    for (i = channels; i < argc; i++)
+    {
+        int vecsize;
+        float *foo;
+        garray_getfloatarray(garrays[i], &vecsize, &foo);
+        for (j = 0; j < vecsize; j++)
+            foo[j] = 0;
+    }
+    /* do all graphics updates */
+    for (i = 0; i < argc; i++)
+        garray_redraw(garrays[i]);
+    fclose(fp);
+    fd = -1;
+    goto done;
+usage:
+    pd_error(x, "usage: read [flags] filename tablename...");
+    post("flags: -skip <n> -nframes <n> -resize -maxsize <n> ...");
+    post("-raw <headerbytes> <channels> <bytespersamp> <endian (b, l, or n)>.");
+done:
+    if (fd >= 0)
+        close (fd);
+    outlet_float(x->x_obj.ob_outlet, (float)itemsread);
+}
+
+/* this is broken out from soundfiler2_write below so garray_write can
+call it too... not done yet though. */
+
+static long soundfiler2_dowrite(void *obj, t_canvas *canvas,
+                                int argc, t_atom *argv)
+{
+    int headersize, bytespersamp, bigendian,
+        endianness, swap, filetype, normalize, i, j, nchannels;
+    long onset, nframes, itemsleft,
+         maxsize = DEFMAXSIZE, itemswritten = 0;
+    t_garray *garrays[MAXSFCHANS];
+    t_float *vecs[MAXSFCHANS];
+    char sampbuf[SAMPBUFSIZE];
+    int bufframes, nitems;
+    int fd = -1;
+    float normfactor, biggest = 0,ftmp,amp;
+    t_symbol *filesym;
+
+    if (soundfiler2_writeargparse(obj, &argc, &argv, &filesym, &filetype,
+                                  &bytespersamp, &swap, &bigendian, &normalize, &onset, &nframes,&amp))
+        goto usage;
+    nchannels = argc;
+    if (nchannels < 1 || nchannels > MAXSFCHANS)
+        goto usage;
+
+    for (i = 0; i < nchannels; i++)
+    {
+        int vecsize;
+
+        if (argv[i].a_type != A_SYMBOL) goto usage;
+
+        if (!(garrays[i] =
+                    (t_garray *)pd_findbyclass(argv[i].a_w.w_symbol, garray_class)))
+        {
+            pd_error(obj, "%s: no such table", argv[i].a_w.w_symbol->s_name);
+            goto fail;
+        }
+        else if (!garray_getfloatarray(garrays[i], &vecsize, &vecs[i]))
+            error("%s: bad template for tabwrite",argv[i].a_w.w_symbol->s_name);
+        if (nframes > vecsize - onset)
+            nframes = vecsize - onset;
+
+        for (j = 0; j < nframes; j++) /* FIXED (Antoine Rousseau)*/
+        {
+            ftmp=vecs[i][j+onset];
+            if (ftmp > biggest) biggest = ftmp;
+            else if (-ftmp > biggest) biggest = -ftmp;
+        }
+    }
+
+    if (nframes <= 0)
+    {
+        pd_error(obj, "soundfiler2_write: no samples at onset %ld", onset);
+        goto fail;
+    }
+
+    if ((fd = create_soundfile2(canvas, filesym->s_name, filetype,
+                                nframes, bytespersamp, bigendian, nchannels,
+                                swap)) < 0)
+    {
+        post("%s: %s\n", filesym->s_name, strerror(errno));
+        goto fail;
+    }
+    if (!normalize)
+    {
+        if ((bytespersamp != 4) && (biggest > 1))
+        {
+            //post("%s: normalizing max amplitude %f to 1", filesym->s_name, biggest);
+            normalize = 1;
+        }
+        //else post("%s: biggest amplitude = %f", filesym->s_name, biggest);
+    }
+    if (normalize)
+        normfactor = (biggest > 0 ? 32767./(32768. * biggest) : 1);
+    else normfactor = amp;
+
+    /*post("%s: biggest amplitude = %f , normfactor = %f",
+    	filesym->s_name, biggest,normfactor);*/
+
+    bufframes = SAMPBUFSIZE / (nchannels * bytespersamp);
+
+    for (itemswritten = 0; itemswritten < nframes; )
+    {
+        int thiswrite = nframes - itemswritten, nitems, nbytes;
+        thiswrite = (thiswrite > bufframes ? bufframes : thiswrite);
+        soundfile_xferout(argc, vecs, (unsigned char *)sampbuf, thiswrite,
+                          onset, bytespersamp, bigendian, normfactor);
+        nbytes = write(fd, sampbuf, nchannels * bytespersamp * thiswrite);
+        if (nbytes < nchannels * bytespersamp * thiswrite)
+        {
+            post("%s: %s", filesym->s_name, strerror(errno));
+            if (nbytes > 0)
+                itemswritten += nbytes / (nchannels * bytespersamp);
+            break;
+        }
+        itemswritten += thiswrite;
+        onset += thiswrite;
+    }
+    if (fd >= 0)
+    {
+        soundfile_finishwrite(obj, filesym->s_name, fd,
+                              filetype, nframes, itemswritten, nchannels * bytespersamp, swap);
+        close (fd);
+    }
+    return ((float)itemswritten);
+usage:
+    pd_error(obj, "usage: write [flags] filename tablename...");
+    post("flags: -skip <n> -nframes <n> -bytes <n> -wave -aiff -nextstep ...");
+    post("-big -little -normalize -amp <n>");
+    post("(defaults to a 16-bit wave file).");
+fail:
+    if (fd >= 0)
+        close (fd);
+    return (0);
+}
+
+static void soundfiler2_write(t_soundfiler2 *x, t_symbol *s,
+                              int argc, t_atom *argv)
+{
+    long bozo = soundfiler2_dowrite(x, x->x_canvas,
+                                    argc, argv);
+    outlet_float(x->x_obj.ob_outlet, (float)bozo);
+}
+
+void soundfiler2_setup(void)
+{
+    soundfiler2_class = class_new(gensym("soundfiler2"), (t_newmethod)soundfiler2_new,
+                                  0, sizeof(t_soundfiler2), 0, 0);
+    class_addmethod(soundfiler2_class, (t_method)soundfiler2_read, gensym("read"),
+                    A_GIMME, 0);
+    class_addmethod(soundfiler2_class, (t_method)soundfiler2_write,
+                    gensym("write"), A_GIMME, 0);
+}
+
+/************************* readsf object ******************************/
+
+/* READSF uses the Posix threads package; for the moment we're Linux
+only although this should be portable to the other platforms.
+
+Each instance of readsf~ owns a "child" thread for doing the UNIX (NT?) file
+reading.  The parent thread signals the child each time:
+    (1) a file wants opening or closing;
+    (2) we've eaten another 1/16 of the shared buffer (so that the
+    	child thread should check if it's time to read some more.)
+The child signals the parent whenever a read has completed.  Signalling
+is done by setting "conditions" and putting data in mutex-controlled common
+areas.
+*/
+
+//#ifdef __linux__
+
+#define MAXBYTESPERSAMPLE 4
+#define MAXVECSIZE 128
+
+#define READSIZE 65536
+#define WRITESIZE 65536
+#define DEFBUFPERCHAN 262144
+#define MINBUFSIZE (4 * READSIZE)
+#define MAXBUFSIZE 16777216 	/* arbitrary; just don't want to hang malloc */
+
+#define REQUEST_NOTHING 0
+#define REQUEST_OPEN 1
+#define REQUEST_CLOSE 2
+#define REQUEST_QUIT 3
+#define REQUEST_BUSY 4
+
+#define STATE_IDLE 0
+#define STATE_STARTUP 1
+#define STATE_STREAM 2
+
+static t_class *readsfv_class;
+
+static t_sample *(tmpvec[MAXSFCHANS]);
+
+typedef struct _readsf
+{
+    t_object x_obj;
+    t_canvas *x_canvas;
+    t_clock *x_clock;
+    char *x_buf;    	    	    	    /* soundfile buffer */
+    int x_bufsize;  	    	    	    /* buffer size in bytes */
+    int x_noutlets; 	    	    	    /* number of audio outlets */
+    t_sample *(x_outvec[MAXSFCHANS]);	    /* audio vectors */
+    int x_vecsize;  	    	    	    /* vector size for transfers */
+    t_outlet *x_bangout;  	    	    /* bang-on-done outlet */
+    int x_state;    	    	    	    /* opened, running, or idle */
+    /* parameters to communicate with subthread */
+    int x_requestcode;	    /* pending request from parent to I/O thread */
+    char *x_filename;	    /* file to open (string is permanently allocated) */
+    int x_fileerror;	    /* slot for "errno" return */
+    int x_skipheaderbytes;  /* size of header we'll skip */
+    int x_bytespersample;   /* bytes per sample (2 or 3) */
+    int x_bigendian;        /* true if file is big-endian */
+    int x_sfchannels;	    /* number of channels in soundfile */
+    long x_onsetframes;	    /* number of sample frames to skip */
+    long x_bytelimit;	    /* max number of data bytes to read */
+    int x_fd;	    	    /* filedesc */
+    int x_fifosize; 	    /* buffer size appropriately rounded down */
+    int x_fifohead; 	    /* index of next byte to get from file */
+    int x_fifotail; 	    /* index of next byte the ugen will read */
+    int x_eof;   	    /* true if fifohead has stopped changing */
+    int x_sigcountdown;     /* counter for signalling child for more data */
+    int x_sigperiod;	    /* number of ticks per signal */
+    int x_filetype; 	    /* writesf~ only; type of file to create */
+    int x_itemswritten;     /* writesf~ only; items writen */
+    int x_swap; 	    /* writesf~ only; true if byte swapping */
+    float x_f; 	    	    /* writesf~ only; scalar for signal inlet */
+    /*----HACK------*/
+    float x_speed;    /*speed of reading*/
+    float x_frac;    /*fractionnal part of sample to play next buffer*/
+
+    pthread_mutex_t x_mutex;
+    pthread_cond_t x_requestcondition;
+    pthread_cond_t x_answercondition;
+    pthread_t x_childthread;
+} t_readsf;
+
+
+/************** the child thread which performs file I/O ***********/
+
+#if 0
+static void pute(char *s)   /* debug routine */
+{
+    write(2, s, strlen(s));
+}
+#else
+#define pute(x)
+#endif
+
+#if 1
+#define sfread_cond_wait pthread_cond_wait
+#define sfread_cond_signal pthread_cond_signal
+#else
+#include <sys/time.h>    /* debugging version... */
+#include <sys/types.h>
+static void readsf_fakewait(pthread_mutex_t *b)
+{
+    struct timeval timout;
+    timout.tv_sec = 0;
+    timout.tv_usec = 1000000;
+    pthread_mutex_unlock(b);
+    select(0, 0, 0, 0, &timout);
+    pthread_mutex_lock(b);
+}
+
+static void readsf_banana( void)
+{
+    struct timeval timout;
+    timout.tv_sec = 0;
+    timout.tv_usec = 200000;
+    pute("banana1\n");
+    select(0, 0, 0, 0, &timout);
+    pute("banana2\n");
+}
+
+
+#define sfread_cond_wait(a,b) readsf_fakewait(b)
+#define sfread_cond_signal(a)
+#endif
+
+static void *readsf_child_main(void *zz)
+{
+    t_readsf *x = zz;
+    pute("1\n");
+    pthread_mutex_lock(&x->x_mutex);
+    while (1)
+    {
+        int fd, fifohead;
+        char *buf;
+        pute("0\n");
+        if (x->x_requestcode == REQUEST_NOTHING)
+        {
+            pute("wait 2\n");
+            sfread_cond_signal(&x->x_answercondition);
+            sfread_cond_wait(&x->x_requestcondition, &x->x_mutex);
+            pute("3\n");
+        }
+        else if (x->x_requestcode == REQUEST_OPEN)
+        {
+            char boo[80];
+            int sysrtn, wantbytes;
+
+            /* copy file stuff out of the data structure so we can
+            relinquish the mutex while we're in open_soundfile(). */
+            long onsetframes = x->x_onsetframes;
+            long bytelimit = 0x7fffffff;
+            int skipheaderbytes = x->x_skipheaderbytes;
+            int bytespersample = x->x_bytespersample;
+            int sfchannels = x->x_sfchannels;
+            int bigendian = x->x_bigendian;
+            char *filename = x->x_filename;
+            char *dirname = canvas_getdir(x->x_canvas)->s_name;
+            /* alter the request code so that an ensuing "open" will get
+            noticed. */
+            pute("4\n");
+            x->x_requestcode = REQUEST_BUSY;
+            x->x_fileerror = 0;
+
+            /* if there's already a file open, close it */
+            if (x->x_fd >= 0)
+            {
+                fd = x->x_fd;
+                pthread_mutex_unlock(&x->x_mutex);
+                close (fd);
+                pthread_mutex_lock(&x->x_mutex);
+                x->x_fd = -1;
+                if (x->x_requestcode != REQUEST_BUSY)
+                    goto lost;
+            }
+            /* open the soundfile with the mutex unlocked */
+            pthread_mutex_unlock(&x->x_mutex);
+            fd = open_soundfile(dirname, filename,
+                                skipheaderbytes, &bytespersample, &bigendian,
+                                &sfchannels, &bytelimit, onsetframes);
+            pthread_mutex_lock(&x->x_mutex);
+
+            pute("5\n");
+            /* copy back into the instance structure. */
+            x->x_bytespersample = bytespersample;
+            x->x_sfchannels = sfchannels;
+            x->x_bigendian = bigendian;
+            x->x_fd = fd;
+            x->x_bytelimit = bytelimit;
+            if (fd < 0)
+            {
+                x->x_fileerror = errno;
+                x->x_eof = 1;
+                pute("open failed\n");
+                pute(filename);
+                pute(dirname);
+                goto lost;
+            }
+            /* check if another request has been made; if so, field it */
+            if (x->x_requestcode != REQUEST_BUSY)
+                goto lost;
+            pute("6\n");
+            x->x_fifohead = 0;
+            /* set fifosize from bufsize.  fifosize must be a
+            multiple of the number of bytes eaten for each DSP
+            tick.  We pessimistically assume MAXVECSIZE samples
+            per tick since that could change.  There could be a
+            problem here if the vector size increases while a
+            soundfile is being played...  */
+            x->x_fifosize = x->x_bufsize - (x->x_bufsize %
+                                            (x->x_bytespersample * x->x_sfchannels * MAXVECSIZE));
+            /* arrange for the "request" condition to be signalled 16
+            times per buffer */
+            sprintf(boo, "fifosize %d\n",
+                    x->x_fifosize);
+            pute(boo);
+            x->x_sigcountdown = x->x_sigperiod =
+                                    (x->x_fifosize /
+                                     (16 * x->x_bytespersample * x->x_sfchannels *
+                                      x->x_vecsize));
+            /* in a loop, wait for the fifo to get hungry and feed it */
+
+            while (x->x_requestcode == REQUEST_BUSY)
+            {
+                int fifosize = x->x_fifosize;
+                pute("77\n");
+                if (x->x_eof)
+                    break;
+                if (x->x_fifohead >= x->x_fifotail)
+                {
+                    /* if the head is >= the tail, we can immediately read
+                    to the end of the fifo.  Unless, that is, we would
+                    read all the way to the end of the buffer and the
+                    "tail" is zero; this would fill the buffer completely
+                    which isn't allowed because you can't tell a completely
+                    full buffer from an empty one. */
+                    if (x->x_fifotail || (fifosize - x->x_fifohead > READSIZE))
+                    {
+                        wantbytes = fifosize - x->x_fifohead;
+                        if (wantbytes > READSIZE)
+                            wantbytes = READSIZE;
+                        if (wantbytes > x->x_bytelimit)
+                            wantbytes = x->x_bytelimit;
+                        sprintf(boo, "head %d, tail %d, size %d\n",
+                                x->x_fifohead, x->x_fifotail, wantbytes);
+                        pute(boo);
+                    }
+                    else
+                    {
+                        pute("wait 7a ...\n");
+                        sfread_cond_signal(&x->x_answercondition);
+                        pute("signalled\n");
+                        sfread_cond_wait(&x->x_requestcondition,
+                                         &x->x_mutex);
+                        pute("7a done\n");
+                        continue;
+                    }
+                }
+                else
+                {
+                    /* otherwise check if there are at least READSIZE
+                    bytes to read.  If not, wait and loop back. */
+                    wantbytes =  x->x_fifotail - x->x_fifohead - 1;
+                    if (wantbytes < READSIZE)
+                    {
+                        pute("wait 7...\n");
+                        sfread_cond_signal(&x->x_answercondition);
+                        sfread_cond_wait(&x->x_requestcondition,
+                                         &x->x_mutex);
+                        pute("7 done\n");
+                        continue;
+                    }
+                    else wantbytes = READSIZE;
+                }
+                pute("8\n");
+                fd = x->x_fd;
+                buf = x->x_buf;
+                fifohead = x->x_fifohead;
+                pthread_mutex_unlock(&x->x_mutex);
+                sysrtn = read(fd, buf + fifohead, wantbytes);
+                pthread_mutex_lock(&x->x_mutex);
+                if (x->x_requestcode != REQUEST_BUSY)
+                    break;
+                if (sysrtn < 0)
+                {
+                    pute("fileerror\n");
+                    x->x_fileerror = errno;
+                    break;
+                }
+                else if (sysrtn == 0)
+                {
+                    x->x_eof = 1;
+                    break;
+                }
+                else
+                {
+                    x->x_fifohead += sysrtn;
+                    x->x_bytelimit -= sysrtn;
+                    if (x->x_bytelimit <= 0)
+                    {
+                        x->x_eof = 1;
+                        break;
+                    }
+                    if (x->x_fifohead == fifosize)
+                        x->x_fifohead = 0;
+                }
+                sprintf(boo, "after: head %d, tail %d\n",
+                        x->x_fifohead, x->x_fifotail);
+                pute(boo);
+                /* signal parent in case it's waiting for data */
+                sfread_cond_signal(&x->x_answercondition);
+            }
+lost:
+
+            if (x->x_requestcode == REQUEST_BUSY)
+                x->x_requestcode = REQUEST_NOTHING;
+            /* fell out of read loop: close file if necessary,
+            set EOF and signal once more */
+            if (x->x_fd >= 0)
+            {
+                fd = x->x_fd;
+                pthread_mutex_unlock(&x->x_mutex);
+                close (fd);
+                pthread_mutex_lock(&x->x_mutex);
+                x->x_fd = -1;
+            }
+            sfread_cond_signal(&x->x_answercondition);
+
+        }
+        else if (x->x_requestcode == REQUEST_CLOSE)
+        {
+            if (x->x_fd >= 0)
+            {
+                fd = x->x_fd;
+                pthread_mutex_unlock(&x->x_mutex);
+                close (fd);
+                pthread_mutex_lock(&x->x_mutex);
+                x->x_fd = -1;
+            }
+            if (x->x_requestcode == REQUEST_CLOSE)
+                x->x_requestcode = REQUEST_NOTHING;
+            sfread_cond_signal(&x->x_answercondition);
+        }
+        else if (x->x_requestcode == REQUEST_QUIT)
+        {
+            if (x->x_fd >= 0)
+            {
+                fd = x->x_fd;
+                pthread_mutex_unlock(&x->x_mutex);
+                close (fd);
+                pthread_mutex_lock(&x->x_mutex);
+                x->x_fd = -1;
+            }
+            x->x_requestcode = REQUEST_NOTHING;
+            sfread_cond_signal(&x->x_answercondition);
+            break;
+        }
+        else
+        {
+            pute("13\n");
+        }
+    }
+    pute("thread exit\n");
+    pthread_mutex_unlock(&x->x_mutex);
+    return (0);
+}
+
+/******** the object proper runs in the calling (parent) thread ****/
+
+static void readsf_tick(t_readsf *x);
+
+static void *readsf_new(t_floatarg fnchannels, t_floatarg fbufsize)
+{
+    t_readsf *x;
+    int nchannels = fnchannels, bufsize = fbufsize, i;
+    char *buf;
+
+    if (nchannels < 1)
+        nchannels = 1;
+    else if (nchannels > MAXSFCHANS)
+        nchannels = MAXSFCHANS;
+    if (bufsize <= 0) bufsize = DEFBUFPERCHAN * nchannels;
+    else if (bufsize < MINBUFSIZE)
+        bufsize = MINBUFSIZE;
+    else if (bufsize > MAXBUFSIZE)
+        bufsize = MAXBUFSIZE;
+    buf = getbytes(bufsize);
+    if (!buf) return (0);
+
+    x = (t_readsf *)pd_new(readsfv_class);
+
+    for (i = 0; i < nchannels; i++)
+        outlet_new(&x->x_obj, gensym("signal"));
+    x->x_noutlets = nchannels;
+    x->x_bangout = outlet_new(&x->x_obj, &s_bang);
+    pthread_mutex_init(&x->x_mutex, 0);
+    pthread_cond_init(&x->x_requestcondition, 0);
+    pthread_cond_init(&x->x_answercondition, 0);
+    x->x_vecsize = MAXVECSIZE;
+    x->x_state = STATE_IDLE;
+    x->x_clock = clock_new(x, (t_method)readsf_tick);
+    x->x_canvas = canvas_getcurrent();
+    x->x_bytespersample = 2;
+    x->x_sfchannels = 1;
+    x->x_fd = -1;
+    x->x_buf = buf;
+    x->x_bufsize = bufsize;
+    x->x_fifosize = x->x_fifohead = x->x_fifotail = x->x_requestcode = 0;
+    pthread_create(&x->x_childthread, 0, readsf_child_main, x);
+    return (x);
+}
+
+static void readsf_tick(t_readsf *x)
+{
+    outlet_bang(x->x_bangout);
+}
+
+static t_int *readsf_perform(t_int *w)
+{
+    t_readsf *x = (t_readsf *)(w[1]);
+    int vecsize = x->x_vecsize, noutlets = x->x_noutlets, i, j,
+        bytespersample = x->x_bytespersample,
+        bigendian = x->x_bigendian,wantsamples;
+    float *fp,tmp,speed=x->x_speed;
+    if (x->x_state == STATE_STREAM)
+    {
+        int wantbytes, nchannels, sfchannels = x->x_sfchannels;
+        pthread_mutex_lock(&x->x_mutex);
+        tmp=vecsize *speed+x->x_frac;
+        wantsamples=(int)tmp;
+        x->x_frac=tmp-wantsamples;
+
+        if(!speed) goto idle;
+
+        wantbytes = sfchannels * wantsamples * bytespersample;
+
+        while (
+            !x->x_eof && x->x_fifohead >= x->x_fifotail &&
+            x->x_fifohead < x->x_fifotail + wantbytes-1)
+        {
+            pute("wait...\n");
+            sfread_cond_signal(&x->x_requestcondition);
+            sfread_cond_wait(&x->x_answercondition, &x->x_mutex);
+            pute("done\n");
+        }
+        if (x->x_eof && x->x_fifohead >= x->x_fifotail &&
+                x->x_fifohead < x->x_fifotail + wantbytes-1)
+        {
+            if (x->x_fileerror)
+            {
+                pd_error(x, "dsp: %s: %s", x->x_filename,
+                         (x->x_fileerror == EIO ?
+                          "unknown or bad header format" :
+                          strerror(x->x_fileerror)));
+            }
+            clock_delay(x->x_clock, 0);
+            x->x_state = STATE_IDLE;
+            sfread_cond_signal(&x->x_requestcondition);
+            pthread_mutex_unlock(&x->x_mutex);
+            goto idle;
+        }
+
+        if(speed==1)
+            soundfile_xferin(sfchannels, noutlets, x->x_outvec, 0,
+                             (unsigned char *)(x->x_buf + x->x_fifotail), vecsize,
+                             bytespersample, bigendian);
+        else
+        {
+            soundfile_xferin(sfchannels, noutlets, tmpvec, 0,
+                             (unsigned char *)(x->x_buf + x->x_fifotail), wantsamples,
+                             bytespersample, bigendian);
+            interpolate(noutlets,tmpvec,wantsamples,x->x_outvec,vecsize);
+        }
+
+        x->x_fifotail += wantbytes;
+        if (x->x_fifotail >= x->x_fifosize)
+            x->x_fifotail = 0;
+        if ((--x->x_sigcountdown) <= 0)
+        {
+            sfread_cond_signal(&x->x_requestcondition);
+            x->x_sigcountdown = x->x_sigperiod;
+        }
+        pthread_mutex_unlock(&x->x_mutex);
+    }
+    else
+    {
+idle:
+        for (i = 0; i < noutlets; i++)
+            for (j = vecsize, fp = x->x_outvec[i]; j--; )
+                *fp++ = 0;
+    }
+    return (w+2);
+}
+
+static void readsf_start(t_readsf *x)
+{
+    /* start making output.  If we're in the "startup" state change
+    to the "running" state. */
+    if (x->x_state == STATE_STARTUP)
+        x->x_state = STATE_STREAM;
+    else pd_error(x, "readsf: start requested with no prior 'open'");
+}
+
+static void readsf_stop(t_readsf *x)
+{
+    /* LATER rethink whether you need the mutex just to set a variable? */
+    pthread_mutex_lock(&x->x_mutex);
+    x->x_state = STATE_IDLE;
+    x->x_requestcode = REQUEST_CLOSE;
+    sfread_cond_signal(&x->x_requestcondition);
+    pthread_mutex_unlock(&x->x_mutex);
+}
+
+static void readsf_float(t_readsf *x, t_floatarg f)
+{
+    if (f != 0)
+        readsf_start(x);
+    else readsf_stop(x);
+}
+
+static void readsf_speed(t_readsf *x, t_floatarg f)
+{
+    if((f>=0)&&(f<=8))
+        x->x_speed=f;
+}
+
+/* open method.  Called as:
+open filename [skipframes headersize channels bytespersamp endianness]
+	(if headersize is zero, header is taken to be automatically
+detected; thus, use the special "-1" to mean a truly headerless file.)
+*/
+
+static void readsf_open(t_readsf *x, t_symbol *s, int argc, t_atom *argv)
+{
+    t_symbol *filesym = atom_getsymbolarg(0, argc, argv);
+    t_float onsetframes = atom_getfloatarg(1, argc, argv);
+    t_float headerbytes = atom_getfloatarg(2, argc, argv);
+    t_float channels = atom_getfloatarg(3, argc, argv);
+    t_float bytespersamp = atom_getfloatarg(4, argc, argv);
+    t_symbol *endian = atom_getsymbolarg(5, argc, argv);
+    if (!*filesym->s_name)
+        return;
+    pthread_mutex_lock(&x->x_mutex);
+    x->x_requestcode = REQUEST_OPEN;
+    x->x_filename = filesym->s_name;
+    x->x_fifotail = 0;
+    x->x_fifohead = 0;
+    if (*endian->s_name == 'b')
+        x->x_bigendian = 1;
+    else if (*endian->s_name == 'l')
+        x->x_bigendian = 0;
+    else if (*endian->s_name)
+        pd_error(x, "endianness neither 'b' nor 'l'");
+    else x->x_bigendian = garray_ambigendian();
+    x->x_onsetframes = (onsetframes > 0 ? onsetframes : 0);
+    x->x_skipheaderbytes = (headerbytes > 0 ? headerbytes :
+                            (headerbytes == 0 ? -1 : 0));
+    x->x_sfchannels = (channels >= 1 ? channels : 1);
+    x->x_bytespersample = (bytespersamp > 2 ? bytespersamp : 2);
+    x->x_eof = 0;
+    x->x_fileerror = 0;
+    x->x_state = STATE_STARTUP;
+    x->x_speed=1;
+    x->x_frac=0;
+    sfread_cond_signal(&x->x_requestcondition);
+    pthread_mutex_unlock(&x->x_mutex);
+}
+
+static void readsf_dsp(t_readsf *x, t_signal **sp)
+{
+    int i, noutlets = x->x_noutlets;
+    pthread_mutex_lock(&x->x_mutex);
+    x->x_vecsize = sp[0]->s_n;
+
+    x->x_sigperiod = (x->x_fifosize /
+                      (x->x_bytespersample * x->x_sfchannels * x->x_vecsize));
+    for (i = 0; i < noutlets; i++)
+        x->x_outvec[i] = sp[i]->s_vec;
+    pthread_mutex_unlock(&x->x_mutex);
+    dsp_add(readsf_perform, 1, x);
+}
+
+static void readsf_print(t_readsf *x)
+{
+    post("state %d", x->x_state);
+    post("fifo head %d", x->x_fifohead);
+    post("fifo tail %d", x->x_fifotail);
+    post("fifo size %d", x->x_fifosize);
+    post("fd %d", x->x_fd);
+    post("eof %d", x->x_eof);
+}
+
+static void readsf_free(t_readsf *x)
+{
+    /* request QUIT and wait for acknowledge */
+    void *threadrtn;
+    pthread_mutex_lock(&x->x_mutex);
+    x->x_requestcode = REQUEST_QUIT;
+    post("stopping readsf thread...");
+    sfread_cond_signal(&x->x_requestcondition);
+    while (x->x_requestcode != REQUEST_NOTHING)
+    {
+        post("signalling...");
+        sfread_cond_signal(&x->x_requestcondition);
+        sfread_cond_wait(&x->x_answercondition, &x->x_mutex);
+    }
+    pthread_mutex_unlock(&x->x_mutex);
+    if (pthread_join(x->x_childthread, &threadrtn))
+        error("readsf_free: join failed");
+    post("... done.");
+
+    pthread_cond_destroy(&x->x_requestcondition);
+    pthread_cond_destroy(&x->x_answercondition);
+    pthread_mutex_destroy(&x->x_mutex);
+    freebytes(x->x_buf, x->x_bufsize);
+    clock_free(x->x_clock);
+}
+
+//#endif /* __linux__ */
+
+void readsfv_tilde_setup(void)
+{
+//#ifdef __linux__
+    int i;
+
+    readsfv_class = class_new(gensym("readsfv~"), (t_newmethod)readsf_new,
+                              (t_method)readsf_free, sizeof(t_readsf), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
+
+    class_addfloat(readsfv_class, (t_method)readsf_float);
+    class_addmethod(readsfv_class, (t_method)readsf_speed, gensym("speed"), A_FLOAT,0);
+    class_addmethod(readsfv_class, (t_method)readsf_start, gensym("start"), 0);
+    class_addmethod(readsfv_class, (t_method)readsf_stop, gensym("stop"), 0);
+    class_addmethod(readsfv_class, (t_method)readsf_dsp, gensym("dsp"), 0);
+    class_addmethod(readsfv_class, (t_method)readsf_open, gensym("open"),
+                    A_GIMME, 0);
+    class_addmethod(readsfv_class, (t_method)readsf_print, gensym("print"), 0);
+
+    for(i=0; i<MAXSFCHANS; i++)
+        tmpvec[i]=getbytes(sizeof(t_sample)*8*1024);
+//#endif /* __linux__ */
+}
+
+
+
+#endif /* NOT _WIN32 */
diff --git a/relativepath-help.pd b/relativepath-help.pd
index b056f4a..0d32a17 100644
--- a/relativepath-help.pd
+++ b/relativepath-help.pd
@@ -1,13 +1,24 @@
-#N canvas 14 323 660 379 10;
-#X text 17 352 (c) Antoine Rousseau 2004;
-#X obj 33 108 absolutepath;
-#X symbolatom 33 131 0 0 0;
-#X msg 33 51 symbol absolutepath.pd;
-#X obj 33 220 relativepath;
-#X symbolatom 33 245 0 0 0;
-#X text 14 6 absolutepath / relativepath : use filenames relatively
-to the patch's path.;
-#X connect 1 0 2 0;
-#X connect 2 0 4 0;
-#X connect 3 0 1 0;
-#X connect 4 0 5 0;
+#N canvas 619 58 535 379 10;
+#X text 17 352 (c) Antoine Rousseau 2004;
+#X obj 33 108 absolutepath;
+#X symbolatom 33 131 0 0 0 0 - - -;
+#X obj 33 220 relativepath;
+#X symbolatom 33 245 0 0 0 0 - - -;
+#X text 14 6 absolutepath / relativepath : use filenames relatively
+to the patch's path.;
+#N canvas 380 146 494 344 META 0;
+#X text 12 25 LICENSE GPL v2;
+#X text 12 5 KEYWORDS control patchfile_op;
+#X text 12 65 INLET_0 symbol;
+#X text 12 85 OUTLET_0 symbol;
+#X text 12 105 AUTHOR Antoine Rousseau;
+#X text 12 125 HELP_PATCH_AUTHORS Antoine Rousseau. "pd meta" information
+added by Jonathan Wilkes for Pd version 0.42.;
+#X text 12 45 DESCRIPTION use filename relatively to the patch's path
+;
+#X restore 475 348 pd META;
+#X msg 33 51 symbol absolutepath-help.pd;
+#X connect 1 0 2 0;
+#X connect 2 0 3 0;
+#X connect 3 0 4 0;
+#X connect 7 0 1 0;
diff --git a/relativepath.c b/relativepath.c
index 3df0051..3a835ae 100644
--- a/relativepath.c
+++ b/relativepath.c
@@ -1,148 +1,160 @@
-#ifndef _WIN32
-/*
-Copyright (C) 2002 Antoine Rousseau 
-
-This library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation; either
-version 2.1 of the License, or (at your option) any later version.
-
-This library 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
-Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with this library; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  
-
-*/
-
-/*#include <m_imp.h>*/
-#include "m_pd.h"
-#include "g_canvas.h"
-
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
-#include <libgen.h>
-#include <string.h>
-
-extern t_canvas *canvas_list;	    	    /* list of all root canvases */
-extern int canvas_getdollarzero( void);
-
-struct _canvasenvironment
-{
-    t_symbol *ce_dir;	/* directory patch lives in */
-    int ce_argc;    	/* number of "$" arguments */
-    t_atom *ce_argv;	/* array of "$" arguments */
-    int ce_dollarzero;	/* value of "$0" */
-};
-
-typedef struct _relativepath
-{
-    t_object x_obj;
-    t_canvas *x_canvas;
-	int x_dolzero;
-	int x_realized;
-}t_relativepath;
-
-t_class *relativepath_class;
-
-void relativepath_setup(void);
-
-static t_glist *getcanvas(t_glist *can,int d0)
-{
-	t_canvas *retcan=0;
-	t_gobj *ob;
-	
-	if((can->gl_env)&&(can->gl_env->ce_dollarzero==d0)){
-		return can;
-	}
-	
-	ob=can->gl_list;
-	while(ob&&(retcan==0)) {
-		if (pd_class(&ob->g_pd) == canvas_class)
-			retcan=getcanvas((t_glist *)ob,d0);
-		ob=ob->g_next;
-	} 
-
-	if((!retcan)&&(can->gl_next)) retcan=getcanvas((t_glist *)can->gl_next,d0);
-	return retcan;
-}
-
-static void relativepath_symbol(t_relativepath *x,t_symbol *sym)
-{
-	t_canvas *can=0;
-	t_symbol *s=sym;
-	char *instr=sym->s_name,*outstr=instr,
-		*candir,
-		canname[MAXPDSTRING],totaldir[MAXPDSTRING],
-		*cnamedir;
-	unsigned int n,i=0;
-
-	if(!x->x_realized) can=(t_canvas*)getcanvas(canvas_list,x->x_dolzero);
-	if(can) {
-		x->x_canvas = can;
-		x->x_realized = 1;
-		//post("found $0 canvas : %x %d ",x->x_canvas, x->x_canvas->gl_env->ce_dollarzero );
-	}
-
-	if(!instr) return;
-
-	candir=canvas_getdir(x->x_canvas)->s_name;
-	if(!candir) candir="";
-
-	strcpy(canname,x->x_canvas->gl_name->s_name);
-	//post("canname=%s",canname);
-	cnamedir=dirname(canname);
-
-	if (strcmp(cnamedir,".")) {
-		sprintf(totaldir,"%s/%s",candir,cnamedir);
-	}
-	else 
-		strcpy(totaldir,candir);
-
-	//post("dir=%s",totaldir);
-
-	n=strlen(totaldir);
-	if(strlen(instr)<=n) goto end;
-
-	while(i<n) {
-		if(instr[i]!=totaldir[i]) goto end;  
-		i++;
-	}
-	
-	if(instr[n]=='/'){
-		outstr=strdup(instr+n+1);
-		s=gensym(outstr);
-	}	
-	
-end:
-	outlet_symbol(x->x_obj.ob_outlet,s);
-}
-
-
-static void *relativepath_new(t_float dolzero)
-{
-	t_relativepath *x = (t_relativepath *)pd_new(relativepath_class);
-	int d0;
-
-	outlet_new(&x->x_obj, 0);
-	x->x_canvas = canvas_getcurrent();
-	x->x_dolzero = dolzero;
-	x->x_realized=dolzero?0:1;
-
-	return (void *)x;
-}
-
-void relativepath_setup(void)
-{
-	relativepath_class = class_new(gensym("relativepath"),(t_newmethod)relativepath_new,
-		0, sizeof(t_relativepath), 0,A_DEFFLOAT,0);
-
-	class_addsymbol(relativepath_class, relativepath_symbol);
-}
-
-#endif /* NOT _WIN32 */
+#ifndef _WIN32
+/*
+Copyright (C) 2002 Antoine Rousseau
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+*/
+
+/*#include <m_imp.h>*/
+#include "m_pd.h"
+#include "g_canvas.h"
+#include "m_imp.h"
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <libgen.h>
+#include <string.h>
+
+#if (PD_MAJOR_VERSION == 0) && (PD_MINOR_VERSION < 46)
+extern t_canvas *canvas_list;
+#else
+#define canvas_list pd_this->pd_canvaslist
+#endif
+
+extern int canvas_getdollarzero( void);
+
+struct _canvasenvironment
+{
+    t_symbol *ce_dir;	/* directory patch lives in */
+    int ce_argc;    	/* number of "$" arguments */
+    t_atom *ce_argv;	/* array of "$" arguments */
+    int ce_dollarzero;	/* value of "$0" */
+};
+
+typedef struct _relativepath
+{
+    t_object x_obj;
+    t_canvas *x_canvas;
+    int x_dolzero;
+    int x_realized;
+} t_relativepath;
+
+t_class *relativepath_class;
+
+void relativepath_setup(void);
+
+static t_glist *getcanvas(t_glist *can,int d0)
+{
+    t_canvas *retcan=0;
+    t_gobj *ob;
+
+    if((can->gl_env)&&(can->gl_env->ce_dollarzero==d0))
+    {
+        return can;
+    }
+
+    ob=can->gl_list;
+    while(ob&&(retcan==0))
+    {
+        if (pd_class(&ob->g_pd) == canvas_class)
+            retcan=getcanvas((t_glist *)ob,d0);
+        ob=ob->g_next;
+    }
+
+    if((!retcan)&&(can->gl_next)) retcan=getcanvas((t_glist *)can->gl_next,d0);
+    return retcan;
+}
+
+static void relativepath_symbol(t_relativepath *x,t_symbol *sym)
+{
+    t_canvas *can=0;
+    t_symbol *s=sym;
+    char *instr=sym->s_name,*outstr=instr,
+          *candir,
+          canname[MAXPDSTRING],totaldir[MAXPDSTRING],
+          *cnamedir;
+    unsigned int n,i=0;
+
+    if(!x->x_realized) can=(t_canvas *)getcanvas(canvas_list,x->x_dolzero);
+    if(can)
+    {
+        x->x_canvas = can;
+        x->x_realized = 1;
+        //post("found $0 canvas : %x %d ",x->x_canvas, x->x_canvas->gl_env->ce_dollarzero );
+    }
+
+    if(!instr) return;
+
+    candir=canvas_getdir(x->x_canvas)->s_name;
+    if(!candir) candir="";
+
+    strcpy(canname,x->x_canvas->gl_name->s_name);
+    //post("canname=%s",canname);
+    cnamedir=dirname(canname);
+
+    if (strcmp(cnamedir,"."))
+    {
+        sprintf(totaldir,"%s/%s",candir,cnamedir);
+    }
+    else
+        strcpy(totaldir,candir);
+
+    //post("dir=%s",totaldir);
+
+    n=strlen(totaldir);
+    if(strlen(instr)<=n) goto end;
+
+    while(i<n)
+    {
+        if(instr[i]!=totaldir[i]) goto end;
+        i++;
+    }
+
+    if(instr[n]=='/')
+    {
+        outstr=strdup(instr+n+1);
+        s=gensym(outstr);
+    }
+
+end:
+    outlet_symbol(x->x_obj.ob_outlet,s);
+}
+
+
+static void *relativepath_new(t_float dolzero)
+{
+    t_relativepath *x = (t_relativepath *)pd_new(relativepath_class);
+    int d0;
+
+    outlet_new(&x->x_obj, 0);
+    x->x_canvas = canvas_getcurrent();
+    x->x_dolzero = dolzero;
+    x->x_realized=dolzero?0:1;
+
+    return (void *)x;
+}
+
+void relativepath_setup(void)
+{
+    relativepath_class = class_new(gensym("relativepath"),(t_newmethod)relativepath_new,
+                                   0, sizeof(t_relativepath), 0,A_DEFFLOAT,0);
+
+    class_addsymbol(relativepath_class, relativepath_symbol);
+}
+
+#endif /* NOT _WIN32 */
diff --git a/s2f-help.pd b/s2f-help.pd
index 2192924..2c5b9b5 100644
--- a/s2f-help.pd
+++ b/s2f-help.pd
@@ -1,18 +1,30 @@
-#N canvas 106 74 492 266 10;
-#X obj 0 0 cnv 8 100 60 empty empty s2f 10 20 1 18 -262144 -1109 0
-;
-#X text 1 244 (c) Moonix: Antoine Rousseau 2003;
-#X text 129 8 symbol to float converter;
-#X obj 197 159 s2f;
-#X floatatom 197 184 0 0 0;
-#X symbolatom 197 142 0 0 0;
-#X obj 345 105 makesymbol %s;
-#X msg 48 84 symbol 0.0003125foo;
-#X msg 197 85 symbol 54.123e-3bar;
-#X msg 345 85 13.25;
-#X connect 3 0 4 0;
-#X connect 5 0 3 0;
-#X connect 6 0 5 0;
-#X connect 7 0 5 0;
-#X connect 8 0 5 0;
-#X connect 9 0 6 0;
+#N canvas 1 82 492 266 10;
+#X obj 0 0 cnv 8 100 60 empty empty s2f 10 20 1 18 -262144 -1109 0
+;
+#X text 1 233 (c) Moonix: Antoine Rousseau 2003;
+#X text 129 8 symbol to float converter;
+#X obj 197 168 s2f;
+#X floatatom 197 193 0 0 0 0 - - -;
+#X symbolatom 197 142 0 0 0 0 - - -;
+#X msg 19 82 symbol 0.0003125foo;
+#X msg 146 82 symbol 54.123e-3bar;
+#X msg 356 81 13.25;
+#N canvas 380 146 490 344 META 0;
+#X text 12 25 LICENSE GPL v2;
+#X text 12 65 INLET_0 symbol;
+#X text 12 105 AUTHOR Antoine Rousseau;
+#X text 12 125 HELP_PATCH_AUTHORS Antoine Rousseau. "pd meta" information
+added by Jonathan Wilkes for Pd version 0.42.;
+#X text 12 5 KEYWORDS control conversion symbol_op;
+#X text 12 45 DESCRIPTION symbol to float converter;
+#X text 12 85 OUTLET_0 float;
+#X restore 431 233 pd META;
+#X obj 356 101 makefilename %s;
+#X msg 276 82 symbol 0x80;
+#X connect 3 0 4 0;
+#X connect 5 0 3 0;
+#X connect 6 0 5 0;
+#X connect 7 0 5 0;
+#X connect 8 0 10 0;
+#X connect 10 0 5 0;
+#X connect 11 0 5 0;
diff --git a/s2f.c b/s2f.c
index 3e36b22..536d0df 100644
--- a/s2f.c
+++ b/s2f.c
@@ -1,53 +1,53 @@
-/*
-Copyright (C) 2002 Antoine Rousseau 
-
-This library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation; either
-version 2.1 of the License, or (at your option) any later version.
-
-This library 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
-Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with this library; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  
-
-*/
-
-#include "m_pd.h"
-#include <stdlib.h>
-
-typedef struct _s2f
-{
-    t_object x_obj;
-}t_s2f;
-
-t_class *s2f_class;
-
-void s2f_setup(void);
-
-static void s2f_symbol(t_s2f *x,t_symbol *sym)
-{
-	if(!sym->s_name) return;
-
-	outlet_float(x->x_obj.ob_outlet,(float)strtod(sym->s_name,0));
-}
-
-static void *s2f_new(void)
-{  
-	t_s2f *x = (t_s2f *)pd_new(s2f_class);
-	outlet_new(&x->x_obj, &s_float);
-	return (void *)x;
-}
-
-void s2f_setup(void)
-{
-	s2f_class = class_new(gensym("s2f"),(t_newmethod)s2f_new, 
-		0, sizeof(t_s2f), 0, 0);
-
-	class_addsymbol(s2f_class, s2f_symbol);
-}
-
+/*
+Copyright (C) 2002 Antoine Rousseau
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+*/
+
+#include "m_pd.h"
+#include <stdlib.h>
+
+typedef struct _s2f
+{
+    t_object x_obj;
+} t_s2f;
+
+t_class *s2f_class;
+
+void s2f_setup(void);
+
+static void s2f_symbol(t_s2f *x,t_symbol *sym)
+{
+    if(!sym->s_name) return;
+
+    outlet_float(x->x_obj.ob_outlet,(t_float)strtod(sym->s_name,0));
+}
+
+static void *s2f_new(void)
+{
+    t_s2f *x = (t_s2f *)pd_new(s2f_class);
+    outlet_new(&x->x_obj, &s_float);
+    return (void *)x;
+}
+
+void s2f_setup(void)
+{
+    s2f_class = class_new(gensym("s2f"),(t_newmethod)s2f_new,
+                          0, sizeof(t_s2f), 0, 0);
+
+    class_addsymbol(s2f_class, s2f_symbol);
+}
+
diff --git a/sarray-help.pd b/sarray-help.pd
index 157d245..7baf1c3 100644
--- a/sarray-help.pd
+++ b/sarray-help.pd
@@ -1,93 +1,116 @@
-#N canvas 158 412 745 484 10;
-#X obj 0 0 cnv 8 100 60 empty empty sarray 10 20 1 18 -262144 -1109
-0;
-#X text 2 467 (c) Moonix: Antoine Rousseau 2003;
-#X msg 74 275 1;
-#X msg 103 275 2;
-#X msg 131 275 3;
-#X symbolatom 139 356 10 0 0;
-#X msg 533 269 reset;
-#X text 109 12 shared array of symbols;
-#X obj 47 146 sarray foo 8;
-#X text 23 48 1) set the length;
-#X msg 47 71 setlen 10;
-#X text 236 43 2) set the nth element;
-#X msg 266 85 set 2 two;
-#X msg 274 106 set 3 three;
-#X obj 258 169 sarray foo;
-#X msg 129 110 print;
-#X msg 44 299 get \$1;
-#X obj 44 320 sarray foo;
-#X obj 44 339 route bang;
-#X msg 159 275 4;
-#X obj 44 359 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
--1;
-#X msg 44 275 0;
-#X text 12 256 3) get the nth symbol (first:0);
-#X obj 533 289 sarray foo;
-#X text 1 376 (bang when empty);
-#X text 298 252 4) dump the whole array;
-#X obj 299 379 sarray foo;
-#X msg 299 272 dump;
-#X obj 299 400 print dump;
-#X msg 334 325 dump _null_;
-#X msg 334 345 dump *?!;
-#X text 315 298 specify a default symbol;
-#X text 329 309 for empty elements;
-#X obj 472 175 sarray foo;
-#X text 494 85 specify a default symbol;
-#X text 494 97 for empty elements;
-#X msg 294 147 print;
-#X msg 428 146 print;
-#X text 531 251 6) clear the sarray;
-#X msg 578 269 print;
-#X text 6 165 args: sarray name [length];
-#X text 258 193 args: set [empty_symbol] first_index sym1 [sym2 [sym3...]]]
-;
-#X text 286 425 args: dump [empty_symbol];
-#X msg 258 61 set 0 zero;
-#X text 453 43 3) set many elements;
-#X text 533 134 ...erase one element;
-#X msg 281 127 set 4 four;
-#X msg 57 93 setlen 4;
-#X msg 534 149 set _niet_ 3 _niet_;
-#X msg 499 113 set _ 0 zero un _ trois _ cinq;
-#X msg 472 60 set 0 zero ein zwei drei;
-#X text 528 328 7) switch to another array;
-#X obj 523 370 sarray foo2 4;
-#X msg 523 351 set 0 zero2 one2 two2 three2;
-#X obj 528 442 sarray;
-#X msg 528 402 print;
-#X msg 577 403 setarray foo;
-#X msg 577 422 setarray foo2;
-#X connect 2 0 16 0;
-#X connect 3 0 16 0;
-#X connect 4 0 16 0;
-#X connect 6 0 23 0;
-#X connect 10 0 8 0;
-#X connect 12 0 14 0;
-#X connect 13 0 14 0;
-#X connect 15 0 8 0;
-#X connect 16 0 17 0;
-#X connect 17 0 18 0;
-#X connect 18 0 20 0;
-#X connect 18 1 5 0;
-#X connect 19 0 16 0;
-#X connect 21 0 16 0;
-#X connect 26 0 28 0;
-#X connect 27 0 26 0;
-#X connect 29 0 26 0;
-#X connect 30 0 26 0;
-#X connect 36 0 14 0;
-#X connect 37 0 33 0;
-#X connect 39 0 23 0;
-#X connect 43 0 14 0;
-#X connect 46 0 14 0;
-#X connect 47 0 8 0;
-#X connect 48 0 33 0;
-#X connect 49 0 33 0;
-#X connect 50 0 33 0;
-#X connect 53 0 52 0;
-#X connect 55 0 54 0;
-#X connect 56 0 54 0;
-#X connect 57 0 54 0;
+#N canvas 95 58 934 486 10;
+#X obj 0 0 cnv 8 100 60 empty empty sarray 10 20 1 18 -262144 -1109
+0;
+#X msg 734 75 1;
+#X msg 763 75 2;
+#X msg 791 75 3;
+#X symbolatom 799 156 10 0 0 0 - - -, f 10;
+#X msg 263 241 reset;
+#X text 109 12 shared array of symbols;
+#X obj 47 146 sarray foo 8;
+#X text 23 48 1) set the length;
+#X msg 47 71 setlen 10;
+#X text 236 43 2) set the nth element;
+#X msg 266 85 set 2 two;
+#X msg 274 106 set 3 three;
+#X obj 258 169 sarray foo;
+#X msg 129 110 print;
+#X msg 704 99 get \$1;
+#X obj 704 120 sarray foo;
+#X obj 704 139 route bang;
+#X msg 819 75 4;
+#X obj 704 159 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 704 75 0;
+#X obj 263 261 sarray foo;
+#X text 701 177 (bang when empty);
+#X obj 29 351 sarray foo;
+#X msg 29 244 dump;
+#X obj 29 372 print dump;
+#X msg 64 297 dump _null_;
+#X msg 64 317 dump *?!;
+#X text 45 270 specify a default symbol;
+#X text 59 281 for empty elements;
+#X obj 449 170 sarray foo;
+#X text 471 80 specify a default symbol;
+#X text 471 92 for empty elements;
+#X msg 294 147 print;
+#X msg 405 141 print;
+#X msg 308 241 print;
+#X text 6 165 args: sarray name [length];
+#X text 219 189 args: set [empty_symbol] first_index sym1 [sym2 [sym3...]]]
+;
+#X text 16 397 args: dump [empty_symbol];
+#X msg 258 61 set 0 zero;
+#X text 430 38 3) set many elements;
+#X text 510 129 ...erase one element;
+#X msg 281 127 set 4 four;
+#X msg 57 93 setlen 4;
+#X msg 511 144 set _niet_ 3 _niet_;
+#X msg 476 108 set _ 0 zero un _ trois _ cinq;
+#X msg 449 55 set 0 zero ein zwei drei;
+#X obj 253 342 sarray foo2 4;
+#X msg 253 323 set 0 zero2 one2 two2 three2;
+#X obj 258 414 sarray;
+#X msg 258 374 print;
+#X msg 307 375 setarray foo;
+#X msg 307 394 setarray foo2;
+#X text 699 53 4) get the nth symbol (first:0);
+#X text 28 224 5) dump the whole array;
+#X text 261 223 7) clear the sarray;
+#X text 253 305 8) switch to another array;
+#X text 494 222 9) find a symbol;
+#X obj 523 305 sarray foo;
+#X msg 508 240 find zero;
+#X msg 536 282 find two;
+#X msg 523 260 find un;
+#X floatatom 588 325 5 0 0 0 - - -, f 5;
+#X text 518 339 (-1 if not found);
+#X obj 698 320 sarray foo;
+#X floatatom 763 340 5 0 0 0 - - -, f 5;
+#X msg 683 255 add what;
+#X msg 698 275 add who;
+#X msg 711 297 add where;
+#X text 722 356 (-1 if full);
+#X text 657 233 (at the first empty place);
+#X text 668 220 10) add a symbol;
+#X text 6 447 (c) Moonix: Antoine Rousseau 2003-2005;
+#X connect 1 0 15 0;
+#X connect 2 0 15 0;
+#X connect 3 0 15 0;
+#X connect 5 0 21 0;
+#X connect 9 0 7 0;
+#X connect 11 0 13 0;
+#X connect 12 0 13 0;
+#X connect 14 0 7 0;
+#X connect 15 0 16 0;
+#X connect 16 0 17 0;
+#X connect 17 0 19 0;
+#X connect 17 1 4 0;
+#X connect 18 0 15 0;
+#X connect 20 0 15 0;
+#X connect 23 0 25 0;
+#X connect 24 0 23 0;
+#X connect 26 0 23 0;
+#X connect 27 0 23 0;
+#X connect 33 0 13 0;
+#X connect 34 0 30 0;
+#X connect 35 0 21 0;
+#X connect 39 0 13 0;
+#X connect 42 0 13 0;
+#X connect 43 0 7 0;
+#X connect 44 0 30 0;
+#X connect 45 0 30 0;
+#X connect 46 0 30 0;
+#X connect 48 0 47 0;
+#X connect 50 0 49 0;
+#X connect 51 0 49 0;
+#X connect 52 0 49 0;
+#X connect 58 1 62 0;
+#X connect 59 0 58 0;
+#X connect 60 0 58 0;
+#X connect 61 0 58 0;
+#X connect 64 1 65 0;
+#X connect 66 0 64 0;
+#X connect 67 0 64 0;
+#X connect 68 0 64 0;
diff --git a/sarray.c b/sarray.c
index d44f7ce..316bcc2 100644
--- a/sarray.c
+++ b/sarray.c
@@ -1,264 +1,282 @@
-/*
-Copyright (C) 2003 Antoine Rousseau 
-
-This library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation; either
-version 2.1 of the License, or (at your option) any later version.
-
-This library 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
-Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with this library; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  
-
-*/
-
-/* a shared symbol array, ala "value" .*/
-
-#include "m_pd.h"
-#include <stdlib.h>
-#include <string.h>
-
-static t_class *sarray_class, *scommon_class;
-static t_symbol *s__;
-
-typedef struct scommon
-{
-    t_pd c_pd;
-    t_symbol *c_sym;
-    int c_refcount;
-	int c_len;
-	t_symbol **c_array;
-} t_scommon;
-
-typedef struct _sarray
-{
-    t_object x_obj;
-    t_symbol *x_sym;
-    t_scommon *x_c;
-	//t_outlet *x_symout;
-	//t_outlet *x_lenout;
-} t_sarray;
-
-/*static int scommon_find(t_scommon *x, t_symbol *s)
-{
-	t_sitem *si=x->first;
-	t_int i=1;
-	
-	while(si) {
-		if(!strcmp(si->s->s_name,s->s_name)) return i; 
-		si=si->next;
-		i++;
-	}
-	return 0;
-}*/
- 
-static t_symbol *scommon_get(t_scommon *x, t_float f)
-{
-	int i=(int)f;
-
-	if(i<0) i=0;
-	if(i>=x->c_len) i=x->c_len-1;
-	return x->c_array[i];
-}
-
-static void scommon_set(t_scommon *x, t_float f, t_symbol *s)
-{
-	int i=(int)f;
-	
-	if((i<0)||(i>=x->c_len)) return;
-	x->c_array[i]=s;
-	//x->c_array[i]=gensym(strdup(s->s_name));
-	//x->c_array[i]=gensym("ok");
-}
-
-static void scommon_setlen(t_scommon *x, t_float flen)
-{
-    int i,oldlen=x->c_len,len=flen;
-	
-	if(len<1) len=1;
-	x->c_len=len;
-	
-	x->c_array=realloc(x->c_array,sizeof(t_symbol *)*len);
-	
-	if(len>oldlen) for(i=oldlen;i<len;i++) x->c_array[i]=&s_;
-}
-
-static void scommon_reset(t_scommon *x)
-{
- 	int i;
-	
-	for(i=0;i<x->c_len;i++) x->c_array[i]=&s_;
-}
-
-static t_atom *scommon_dump(t_scommon *x,t_symbol *s)
-{
- 	int i;
-	t_atom *atombuf;
-	
-	atombuf = (t_atom *)getbytes(sizeof(t_atom)*x->c_len);
-
- 	for(i=0;i<x->c_len;i++) {
-		if(x->c_array[i]==&s_) SETSYMBOL(&atombuf[i],s);
-		else SETSYMBOL(&atombuf[i],x->c_array[i]);
-	}
-	
-	return atombuf;
-}
-
-static void scommon_ff(t_scommon *x)
-{
- 	//scommon_reset(x);
-	pd_unbind((t_pd*)x, x->c_sym);
-}
-
-static void *scommon_new(t_symbol *s)
-{
-    t_scommon *x = (t_scommon *)pd_new(scommon_class);
-
-	x->c_refcount = 0;
-	x->c_sym=s;
-	pd_bind((t_pd*)x, s);
-	
-	x->c_len=1;
-	x->c_array=malloc(sizeof(t_symbol *)*1);
-	scommon_reset(x);
-
-    return (x);
-}
-
-
-    /* get a pointer to a named symbol list (a "scommon" object), 
-	which is created if necessary. */
-t_scommon *sarray_scget(t_symbol *s)
-{
-    t_scommon *c = (t_scommon *)pd_findbyclass(s, scommon_class);
-
-    if (!c) c = (t_scommon *)scommon_new(s);
-    c->c_refcount++;
-    return (c);
-}
-
-    /* release a variable.  This only frees the "scommon" resource when the
-    last interested party releases it. */
-void sarray_release(t_scommon *c)
-{
-	if (!--c->c_refcount) scommon_ff(c);
-}
-
- 
-static void *sarray_new(t_symbol *s,t_float len)
-{
-    t_sarray *x = (t_sarray *)pd_new(sarray_class);
- 
-    x->x_sym = s;
-    x->x_c = sarray_scget(s);
-	if(len) scommon_setlen(x->x_c,len);
-
-    outlet_new(&x->x_obj, &s_anything);
-    //x->x_symout=outlet_new(&x->x_obj, &s_anything);
-    //x->x_lenout=outlet_new(&x->x_obj, &s_float);
-    return (x);
-}
-
-static void sarray_ff(t_sarray *x)
-{
-    sarray_release(x->x_c);
-}
-
-static void sarray_print(t_sarray *x)
-{
-	int i;
-	
-	for(i=0;i<x->x_c->c_len;i++){
-		post("item %d: %s",i,x->x_c->c_array[i]->s_name);
-	}
-}
-
-static void sarray_reset(t_sarray *x)
-{
-	scommon_reset(x->x_c);
-}
-
-static void sarray_set(t_sarray *x, t_symbol *sfoo,int argc, t_atom *argv)
-{
-	int i,j=0;
-	t_symbol *snull=&s_,*s;
-	
-	/*if((argc<2)||(argv[0].a_type!=A_FLOAT))
-	{
-		error("Bad arguments for message 'set' to object 'sarray'");
-		return ;
-	}*/
-	if(argv[0].a_type==A_SYMBOL) {
-		snull=atom_getsymbol(&argv[0]); 
-		j=1;
-	}
-		
-	if(argv[j].a_type!=A_FLOAT){
-		error("Bad arguments for message 'set' to object 'sarray'");
-		return ;
-	}
-		
-	i=atom_getfloat(&argv[j++]);
-	
-	while((j<argc)&&(argv[j].a_type==A_SYMBOL)){
-		s=atom_getsymbol(&argv[j++]);
-		if(s==snull) s=&s_;
-		scommon_set(x->x_c,i++,s);
-	}
-}
-
-static void sarray_get(t_sarray *x,t_float i)
-{
-	t_symbol *s=scommon_get(x->x_c,i);
-	
-	if(s==&s_) outlet_bang(x->x_obj.ob_outlet);
-	else outlet_symbol(x->x_obj.ob_outlet,scommon_get(x->x_c,i));
-}
-
-static void sarray_dump(t_sarray *x,t_symbol *s)
-{
-	t_atom *l=scommon_dump(x->x_c,s);
-
-	outlet_list(x->x_obj.ob_outlet, &s_list, x->x_c->c_len, l);
-	free(l);
-}
-
-static void sarray_setarray(t_sarray *x,t_symbol *s)
-{
-	sarray_release(x->x_c);
-	x->x_c = sarray_scget(s);
-	x->x_sym = s;
-}
-
-static void sarray_setlen(t_sarray *x,t_float len)
-{
-	scommon_setlen(x->x_c,len);
-}
-
-
-void sarray_setup(void)
-{
-    s__=gensym("_");
-	sarray_class = class_new(gensym("sarray"), (t_newmethod)sarray_new,
-    	(t_method)sarray_ff,
-    	sizeof(t_sarray), 0, A_DEFSYM, A_DEFFLOAT,0);
-
-    //class_addbang(sarray_class, sarray_bang);
-    //class_addfloat(sarray_class, sarray_float);
-    class_addmethod(sarray_class,(t_method)sarray_set, gensym("set"),A_GIMME,0);
-    class_addmethod(sarray_class,(t_method)sarray_get, gensym("get"),A_FLOAT,0);
-    class_addmethod(sarray_class,(t_method)sarray_reset, gensym("reset"),0);
-    class_addmethod(sarray_class,(t_method)sarray_print, gensym("print"),0);
-    class_addmethod(sarray_class,(t_method)sarray_setlen, gensym("setlen"),A_FLOAT,0);
-    class_addmethod(sarray_class,(t_method)sarray_dump, gensym("dump"),A_DEFSYM,0);
-    class_addmethod(sarray_class,(t_method)sarray_setarray, gensym("setarray"),A_SYMBOL,0);
-   scommon_class = class_new(gensym("sarray"), 0, 0,
-    	sizeof(t_scommon), CLASS_PD, 0);
-}
-
+/*
+Copyright (C) 2003 Antoine Rousseau
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+*/
+
+/* a shared symbol array, ala "value" .*/
+
+#include "m_pd.h"
+#include <stdlib.h>
+#include <string.h>
+
+static t_class *sarray_class, *scommon_class;
+static t_symbol *s__;
+
+typedef struct scommon
+{
+    t_pd c_pd;
+    t_symbol *c_sym;
+    int c_refcount;
+    int c_len;
+    t_symbol **c_array;
+} t_scommon;
+
+typedef struct _sarray
+{
+    t_object x_obj;
+    t_symbol *x_sym;
+    t_scommon *x_c;
+    t_outlet *x_indexout;
+} t_sarray;
+
+static int scommon_find(t_scommon *x, t_symbol *s)
+{
+    t_int i=0;
+
+    while(i<x->c_len) {
+        if(!strcmp(x->c_array[i]->s_name,s->s_name)) return i; 
+        i++;
+    }
+    return -1;
+}
+
+static void scommon_set(t_scommon *x, t_float f, t_symbol *s)
+{
+    int i=(int)f;
+
+    if((i<0)||(i>=x->c_len)) return;
+    x->c_array[i]=s;
+}
+
+static int scommon_add(t_scommon *x, t_symbol *s)
+{
+    t_int i=0;
+
+    while(i<x->c_len) {
+        if(x->c_array[i]==&s_) {
+            scommon_set(x,i,s);
+            return i; 
+        }
+        i++;
+    }
+    return -1;
+}
+
+static t_symbol *scommon_get(t_scommon *x, t_float f)
+{
+    int i=(int)f;
+
+    if(i<0) i=0;
+    if(i>=x->c_len) i=x->c_len-1;
+    return x->c_array[i];
+}
+
+static void scommon_setlen(t_scommon *x, t_float flen)
+{
+    int i,oldlen=x->c_len,len=flen;
+
+    if(len<1) len=1;
+    x->c_len=len;
+
+    x->c_array=realloc(x->c_array,sizeof(t_symbol *)*len);
+
+    if(len>oldlen) for(i=oldlen; i<len; i++) x->c_array[i]=&s_;
+}
+
+static void scommon_reset(t_scommon *x)
+{
+    int i;
+
+    for(i=0; i<x->c_len; i++) x->c_array[i]=&s_;
+}
+
+static t_atom *scommon_dump(t_scommon *x,t_symbol *s)
+{
+    int i;
+    t_atom *atombuf;
+
+    atombuf = (t_atom *)getbytes(sizeof(t_atom)*x->c_len);
+
+    for(i=0; i<x->c_len; i++)
+    {
+        if(x->c_array[i]==&s_) SETSYMBOL(&atombuf[i],s);
+        else SETSYMBOL(&atombuf[i],x->c_array[i]);
+    }
+
+    return atombuf;
+}
+
+static void scommon_ff(t_scommon *x)
+{
+    pd_unbind((t_pd *)x, x->c_sym);
+}
+
+static void *scommon_new(t_symbol *s)
+{
+    t_scommon *x = (t_scommon *)pd_new(scommon_class);
+
+    x->c_refcount = 0;
+    x->c_sym=s;
+    pd_bind((t_pd *)x, s);
+
+    x->c_len=1;
+    x->c_array=malloc(sizeof(t_symbol *)*1);
+    scommon_reset(x);
+
+    return (x);
+}
+
+
+/* get a pointer to a named symbol list (a "scommon" object),
+which is created if necessary. */
+t_scommon *sarray_scget(t_symbol *s)
+{
+    t_scommon *c = (t_scommon *)pd_findbyclass(s, scommon_class);
+
+    if (!c) c = (t_scommon *)scommon_new(s);
+    c->c_refcount++;
+    return (c);
+}
+
+/* release a variable.  This only frees the "scommon" resource when the
+last interested party releases it. */
+void sarray_release(t_scommon *c)
+{
+    if (!--c->c_refcount) scommon_ff(c);
+}
+
+
+static void *sarray_new(t_symbol *s,t_float len)
+{
+    t_sarray *x = (t_sarray *)pd_new(sarray_class);
+
+    x->x_sym = s;
+    x->x_c = sarray_scget(s);
+    if(len) scommon_setlen(x->x_c,len);
+
+    outlet_new(&x->x_obj, &s_anything);
+    x->x_indexout=outlet_new(&x->x_obj, &s_float);
+
+    return (x);
+}
+
+static void sarray_ff(t_sarray *x)
+{
+    sarray_release(x->x_c);
+}
+
+static void sarray_print(t_sarray *x)
+{
+    int i;
+
+    for(i=0; i<x->x_c->c_len; i++)
+    {
+        post("item %d: %s",i,x->x_c->c_array[i]->s_name);
+    }
+}
+
+static void sarray_reset(t_sarray *x)
+{
+    scommon_reset(x->x_c);
+}
+
+static void sarray_add(t_sarray *x, t_symbol *s)
+{
+    outlet_float(x->x_indexout,scommon_add(x->x_c,s));
+}
+
+static void sarray_find(t_sarray *x, t_symbol *s)
+{
+    outlet_float(x->x_indexout,scommon_find(x->x_c,s));
+}
+
+static void sarray_set(t_sarray *x, t_symbol *sfoo,int argc, t_atom *argv)
+{
+    int i,j=0;
+    t_symbol *snull=&s_,*s;
+
+    if(argv[0].a_type==A_SYMBOL)
+    {
+        snull=atom_getsymbol(&argv[0]);
+        j=1;
+    }
+
+    if(argv[j].a_type!=A_FLOAT)
+    {
+        error("Bad arguments for message 'set' to object 'sarray'");
+        return ;
+    }
+
+    i=atom_getfloat(&argv[j++]);
+
+    while((j<argc)&&(argv[j].a_type==A_SYMBOL))
+    {
+        s=atom_getsymbol(&argv[j++]);
+        if(s==snull) s=&s_;
+        scommon_set(x->x_c,i++,s);
+    }
+}
+
+static void sarray_get(t_sarray *x,t_float i)
+{
+    t_symbol *s=scommon_get(x->x_c,i);
+
+    if(s==&s_) outlet_bang(x->x_obj.ob_outlet);
+    else outlet_symbol(x->x_obj.ob_outlet,scommon_get(x->x_c,i));
+}
+
+static void sarray_dump(t_sarray *x,t_symbol *s)
+{
+    t_atom *l=scommon_dump(x->x_c,s);
+
+    outlet_list(x->x_obj.ob_outlet, &s_list, x->x_c->c_len, l);
+    free(l);
+}
+
+static void sarray_setarray(t_sarray *x,t_symbol *s)
+{
+    sarray_release(x->x_c);
+    x->x_c = sarray_scget(s);
+    x->x_sym = s;
+}
+
+static void sarray_setlen(t_sarray *x,t_float len)
+{
+    scommon_setlen(x->x_c,len);
+}
+
+
+void sarray_setup(void)
+{
+    s__=gensym("_");
+    sarray_class = class_new(gensym("sarray"), (t_newmethod)sarray_new,
+                             (t_method)sarray_ff,
+                             sizeof(t_sarray), 0, A_DEFSYM, A_DEFFLOAT,0);
+
+    class_addmethod(sarray_class,(t_method)sarray_add, gensym("add"),A_SYMBOL,0);
+    class_addmethod(sarray_class,(t_method)sarray_find, gensym("find"),A_SYMBOL,0);
+    class_addmethod(sarray_class,(t_method)sarray_set, gensym("set"),A_GIMME,0);
+    class_addmethod(sarray_class,(t_method)sarray_get, gensym("get"),A_FLOAT,0);
+    class_addmethod(sarray_class,(t_method)sarray_reset, gensym("reset"),0);
+    class_addmethod(sarray_class,(t_method)sarray_print, gensym("print"),0);
+    class_addmethod(sarray_class,(t_method)sarray_setlen, gensym("setlen"),A_FLOAT,0);
+    class_addmethod(sarray_class,(t_method)sarray_dump, gensym("dump"),A_DEFSYM,0);
+    class_addmethod(sarray_class,(t_method)sarray_setarray, gensym("setarray"),A_SYMBOL,0);
+    scommon_class = class_new(gensym("sarray"), 0, 0,
+                              sizeof(t_scommon), CLASS_PD, 0);
+}
+
diff --git a/sfread2~-help.pd b/sfread2~-help.pd
index ad8ae16..f00f89e 100644
--- a/sfread2~-help.pd
+++ b/sfread2~-help.pd
@@ -1,60 +1,73 @@
-#N canvas 38 250 582 490 10;
-#X obj 0 0 cnv 8 100 60 empty empty sfread2~ 10 20 1 18 -262144 -1109
-0;
-#X text 2 459 (c) Moonix: Antoine Rousseau 2003;
-#X text 66 390 Change "mlockall(MCL_FUTURE)" with "mlockall(MCL_CURRENT)
-;
-#X obj 155 262 sfread2~ 2;
-#X msg 155 202 open \$1;
-#X obj 19 151 bng 15 250 50 0 empty empty play 20 8 1 8 -24198 -1 -1
-;
-#X msg 278 225 loop \$1;
-#X obj 278 207 tgl 15 1 empty empty loop 20 8 0 8 -241291 -1 -1 1 1
-;
-#X obj 57 103 tgl 15 1 empty empty interpolation 20 8 1 8 -257472 -1
--1 1 1;
-#X msg 57 121 interp \$1;
-#X obj 458 181 vsl 15 128 -8 8 0 0 empty empty speed 0 -8 1 8 -260818
--1 -1 7144 1;
-#X text 135 12 soundfile reader at variable speed (possibly negative)
-\, whith 4-point interpolation and loop.;
-#X obj 154 296 dac~;
-#X obj 155 92 openpanel;
-#X obj 155 72 bng 15 250 50 0 empty empty open 0 -6 1 8 -166441 -1
--1;
-#X obj 18 179 bng 15 250 50 0 empty empty stop 20 8 1 8 -1 -1 -1;
-#X msg 18 196 0;
-#X obj 148 339 sfread~;
-#X text 43 341 read manual of;
-#X text 202 339 for more details...;
-#X text 235 159 resets sound to position;
-#X text 234 148 start position in samples;
-#X msg 238 174 index 20000;
-#X obj 497 177 loadbang;
-#X msg 497 196 1;
-#X msg 261 99 symbol /usr/local/lib/pd/doc/sound/voice.wav;
-#X msg 261 78 symbol ../../sound/voice.wav;
-#X text 66 414 If not \, the whole file will be loaded in memory when
-opened (use of C function mmap()).;
-#X text 66 401 in s_linux.c... SORRY \, I mean in s_inter.c (since
-0.37...);
-#X text 59 378 CAUTION: you should hack pd sources to have d-t-d working.
-;
-#X connect 3 0 12 0;
-#X connect 3 1 12 1;
-#X connect 4 0 3 0;
-#X connect 5 0 3 0;
-#X connect 6 0 3 0;
-#X connect 7 0 6 0;
-#X connect 8 0 9 0;
-#X connect 9 0 3 0;
-#X connect 10 0 3 1;
-#X connect 13 0 4 0;
-#X connect 14 0 13 0;
-#X connect 15 0 16 0;
-#X connect 16 0 3 0;
-#X connect 22 0 3 0;
-#X connect 23 0 24 0;
-#X connect 24 0 10 0;
-#X connect 25 0 4 0;
-#X connect 26 0 4 0;
+#N canvas 386 72 582 490 10;
+#X obj 0 0 cnv 8 100 60 empty empty sfread2~ 10 20 1 18 -262144 -1109
+0;
+#X text 2 459 (c) Moonix: Antoine Rousseau 2003;
+#X text 66 390 Change "mlockall(MCL_FUTURE)" with "mlockall(MCL_CURRENT)
+;
+#X obj 155 262 sfread2~ 2;
+#X msg 155 202 open \$1;
+#X obj 19 151 bng 15 250 50 0 empty empty play 20 8 1 8 -24198 -1 -1
+;
+#X msg 278 225 loop \$1;
+#X obj 278 207 tgl 15 1 empty empty loop 20 8 0 8 -241291 -1 -1 1 1
+;
+#X obj 57 103 tgl 15 1 empty empty interpolation 20 8 1 8 -257472 -1
+-1 1 1;
+#X msg 57 121 interp \$1;
+#X obj 458 181 vsl 15 128 -8 8 0 0 empty empty speed 0 -8 1 8 -260818
+-1 -1 6244 1;
+#X text 135 12 soundfile reader at variable speed (possibly negative)
+\, whith 4-point interpolation and loop.;
+#X obj 154 296 dac~;
+#X obj 155 92 openpanel;
+#X obj 155 72 bng 15 250 50 0 empty empty open 0 -6 1 8 -166441 -1
+-1;
+#X obj 18 179 bng 15 250 50 0 empty empty stop 20 8 1 8 -1 -1 -1;
+#X msg 18 196 0;
+#X obj 148 339 sfread~;
+#X text 43 341 read manual of;
+#X text 202 339 for more details...;
+#X text 235 159 resets sound to position;
+#X text 234 148 start position in samples;
+#X msg 238 174 index 20000;
+#X obj 497 177 loadbang;
+#X msg 497 196 1;
+#X msg 261 99 symbol /usr/local/lib/pd/doc/sound/voice.wav;
+#X msg 261 78 symbol ../../doc/sound/voice.wav;
+#X text 66 414 If not \, the whole file will be loaded in memory when
+opened (use of C function mmap()).;
+#N canvas 592 238 494 344 META 0;
+#X text 12 25 LICENSE GPL v2;
+#X text 12 165 AUTHOR Antoine Rousseau;
+#X text 12 185 HELP_PATCH_AUTHORS Antoine Rousseau. "pd meta" information
+added by Jonathan Wilkes for Pd version 0.42.;
+#X text 12 5 KEYWORDS signal soundfile;
+#X text 12 45 DESCRIPTION soundfile reader at variable speed (possibly
+negative) \, whith 4-point interpolation and loop;
+#X text 12 85 INLET_0 float bang interp open index loop;
+#X text 12 105 INLET_1 float;
+#X text 12 145 comment;
+#X text 12 125 OUTLET_N signal;
+#X text 12 145 OUTLET_R float;
+#X restore 526 459 pd META;
+#X text 67 365 CAUTION: it's possible to hack pd sources to have real
+d-t-d working :;
+#X text 66 401 in s_inter.c;
+#X connect 3 0 12 0;
+#X connect 3 1 12 1;
+#X connect 4 0 3 0;
+#X connect 5 0 3 0;
+#X connect 6 0 3 0;
+#X connect 7 0 6 0;
+#X connect 8 0 9 0;
+#X connect 9 0 3 0;
+#X connect 10 0 3 1;
+#X connect 13 0 4 0;
+#X connect 14 0 13 0;
+#X connect 15 0 16 0;
+#X connect 16 0 3 0;
+#X connect 22 0 3 0;
+#X connect 23 0 24 0;
+#X connect 24 0 10 0;
+#X connect 25 0 4 0;
+#X connect 26 0 4 0;
diff --git a/sfread2~.c b/sfread2~.c
index c4d7653..4ea4c8a 100644
--- a/sfread2~.c
+++ b/sfread2~.c
@@ -1,413 +1,439 @@
-#ifndef _WIN32
-
-#include <m_pd.h>
-//#include <m_imp.h>
-#include "g_canvas.h"
-#ifdef _MSC_VER
-#pragma warning( disable : 4244 )
-#pragma warning( disable : 4305 )
-#endif
-
-#include <stdio.h>
-#include <string.h>
-#ifndef _WIN32
-#include <unistd.h>
-#include <sys/mman.h>
-#else
-#include <io.h>
-#endif
-
-
-#include <fcntl.h>
-#include <sys/stat.h>
-
-/* ------------------------ sfread~ ----------------------------- */
-
-#ifdef _WIN32
-#define BINREADMODE "rb"
-#else
-#define BINREADMODE "r"
-#endif
-
-static t_class *sfread_class;
-
-
-typedef struct _sfread
-{
-     t_object x_obj;
-     void*     x_mapaddr;
-     int       x_fd;
-
-     t_int   x_play;
-     t_int   x_outchannels;
-     t_int   x_loop;
-     double x_index;	//samples
-     t_float x_speed;	//1=sample rate
-     t_int   x_interp;
-
-     t_int   x_size;	// bytes
-     t_int   x_fchannels; // file channels
-     t_int   x_len;	// samples
-     t_int x_skip;	//bytes
-     t_clock *x_clock;
-
-
-     t_glist * x_glist;
-     t_outlet *x_stateout;
-     t_outlet *x_sizeout;
-} t_sfread;
-
-#define MAX_CHANS 4
-
-
-
-//1 -> 2
-
-//1 -> 4
-
-//2 -> 4
-
-
-static t_int *sfread_perform(t_int *w)
-{
-     t_sfread* x = (t_sfread*)(w[1]);
-     short *fp, *buf = x->x_mapaddr+x->x_skip;
-/*     t_float *in = (t_float *)(w[2]); will we need this (indexing) ?*/
-     int c = x->x_outchannels;
-     int fc = x->x_fchannels,fc2=2*fc;
-     double findex = x->x_index;
-     t_float speed = x->x_speed;
-     float frac,  a,  b,  cc,  d, cminusb;
-     int i,n,index,rindex;
-     int end =  x->x_len -3;/* -3 is for safe interpolation*/
-     t_float* out[MAX_CHANS];
-     t_int in_off[MAX_CHANS];
-     t_int loground=(fc==1?0:fc==2?1:2);
-
-     if(!x->x_mapaddr) return(w+c+4);
-	 
-	 for (i=0;i<c;i++){
-	  out[i] = (t_float *)(w[3+i]);
-	  in_off[i]=i%fc;
-     }
-     n = (int)(w[3+c]);
-
-     /* loop */
-
-     if (findex >  end)
-	  findex = end;
-
-     if (findex + n*speed > end) { // playing forward end
-	  if (!x->x_loop) {
-	       x->x_play=0;
-	       findex = 0;
-		   clock_delay(x->x_clock, 0);
-	  }
-     }
-
-     if (findex + n*speed < 1) {  // playing backwards end
-	  if (!x->x_loop) {
-	       x->x_play=0;
-	       findex = end;
-		   clock_delay(x->x_clock, 0);
-	  }
-
-     }
-
-
-     if (x->x_play && x->x_mapaddr) {
-
-	  if (speed != 1) { /* different speed */
-	       if (x->x_interp) while (n--) {
-		    index=findex;
-		    rindex=index<<loground;
-		    frac = findex - index;
-		    for (i=0;i<c;i++)  {
-			fp=buf + rindex +in_off[i];
-			a = fp[-fc];
-			b = fp[0];
-			cc = fp[fc];
-			d = fp[fc2];
-			cminusb = cc-b;
-			*out[i]++ = 3.052689e-05*
-		(b + frac * (cminusb - 0.5f * (frac-1.) *
-		((a - d + 3.0f * cminusb) * frac + (b - a - cminusb))));
-			//*out[i]++ = *(buf+rindex+in_off[i])*3.052689e-05;
-		    }
-		    findex=findex+speed;
-		    if (findex > end) {
-			 if (x->x_loop) findex = 1;
-			 else break;
-		    }
-		    if (findex < 1) {
-			 if (x->x_loop) findex = end;
-			 else break;
-		    }
-	       }
-	       else while (n--) {
-		    rindex=((int)findex)<<loground;
-		    for (i=0;i<c;i++)  {
-			 *out[i]++ = *(buf+rindex+in_off[i])*3.052689e-05;
-		    }
-		    findex+=speed;
-		    if (findex > end) {
-			 if (x->x_loop) findex = 1;
-			 else break;
-		    }
-		    if (findex < 1) {
-			 if (x->x_loop) findex = end;
-			 else break;
-		    }
-	       }
-	       /* Fill with zero in case of end */
-	       n++;
-	       while (n--)
-		    for (i=0;i<c;i++)
-			 *out[i]++ = 0;
-	       //offset = aoff;
-	  }
-	  else { /* speed == 1 */
-	       int end2=end*fc;
-	       rindex=((int)findex)<<loground;
-	       while (n--) {
-		    for (i=0;i<c;i++)  {
-			 *out[i]++ = *(buf+rindex+in_off[i])*3.052689e-05;
-		    }
-		    rindex+=fc;
-		    if (rindex > end2) {
-			 if (x->x_loop) rindex = 1;
-			 else break;
-		    }
-	       }
-
-	       /* Fill with zero in case of end */
-	       n++;
-	       while (n--)
-		    for (i=0;i<c;i++)
-			 *out[i]++ = 0.;
-	       findex=rindex>>loground;
-	  }
-
-     }
-     else {
-	  while (n--) {
-	       for (i=0;i<c;i++)
-		    *out[i]++ = 0.;
-	  }
-     }
-     x->x_index = findex;
-     return (w+c+4);
-}
-
-
-static void sfread_loop(t_sfread *x, t_floatarg f)
-{
-     x->x_loop = f;
-}
-
-static void sfread_interp(t_sfread *x, t_floatarg f)
-{
-     x->x_interp = (f!=0);
-}
-
-static void sfread_index(t_sfread *x, t_floatarg f)
-{
-     x->x_index = f;
-}
-
-
-static void sfread_size(t_sfread* x)
-{
-     outlet_float(x->x_sizeout,x->x_len);
-}
-
-static void sfread_state(t_sfread* x)
-{
-    outlet_float(x->x_stateout, x->x_play);
-}
-
-static void sfread_float(t_sfread *x, t_floatarg f)
-{
-     int t = f;
-     if (t && x->x_mapaddr) {
-	  x->x_play=1;
-     }
-     else {
-	  x->x_play=0;
-     }
-	sfread_state(x);
-}
-
-
-static void sfread_bang(t_sfread* x)
-{
-     x->x_index = x->x_speed>0?1:x->x_len-3;
-     sfread_float(x,1.0);
-}
-
-
-static void sfread_dsp(t_sfread *x, t_signal **sp)
-{
-/*     post("sfread: dsp"); */
-     switch (x->x_outchannels) {
-     case 1:
-	  dsp_add(sfread_perform, 4, x, sp[0]->s_vec,
-		  sp[1]->s_vec, sp[0]->s_n);
-	  break;
-     case 2:
-	  dsp_add(sfread_perform, 5, x, sp[0]->s_vec,
-		  sp[1]->s_vec,sp[2]->s_vec, sp[0]->s_n);
-	  break;
-     case 4:
-	  dsp_add(sfread_perform, 6, x, sp[0]->s_vec,
-		  sp[1]->s_vec,sp[2]->s_vec,
-		  sp[3]->s_vec,sp[4]->s_vec,
-		  sp[0]->s_n);
-	  break;
-     }
-}
-
-
-extern int open_soundfile(const char *dirname, const char *filename, int headersize,
-    int *p_bytespersamp, int *p_bigendian, int *p_nchannels, long *p_bytelimit,
-    long skipframes); /* in pd/src/d_soundfile.c */
-
-
-static void sfread_open(t_sfread *x,t_symbol *filename)
-{
-     struct stat  fstate;
-     char fname[MAXPDSTRING];
-     int bytespersamp=0,bigendian=0,channels=0;
-     long bytelimit= 0x7fffffff,skipframes = 0;
-
-     if (filename == &s_) {
-	  post("sfread: open without filename");
-	  return;
-     }
-
-     canvas_makefilename(glist_getcanvas(x->x_glist), filename->s_name,
-			 fname, MAXPDSTRING);
-
-
-     /* close the old file */
-
-     if (x->x_mapaddr) munmap(x->x_mapaddr,x->x_size);
-     if (x->x_fd >= 0) close(x->x_fd);
-
-     /*if ((x->x_fd = open(fname,O_RDONLY)) < 0)*/
-     //post("fname: %s",fname);
-
-     if ((x->x_fd = open_soundfile("",fname, -1,&bytespersamp,&bigendian,
-     	&channels, &bytelimit,0)) < 0)
-     {
-	  error("can't open %s",fname);
-	  x->x_play = 0;
-	  x->x_mapaddr = NULL;
-	  return;
-     }
-
-     if( ((x->x_fchannels!=1)&&(x->x_fchannels!=2)&&(x->x_fchannels!=4)) ||
-     	(bytespersamp!=2) )
-     {
-	  error("file %s error: not a 1 or 2 or 4 channels soundfile, or not a 16 bits soundfile",fname);
-	  post("channels:%d bytes:%d ",x->x_fchannels,bytespersamp);
-	  x->x_play = 0;
-	  x->x_mapaddr = NULL;
-	  return;
-     }
-
-     x->x_fchannels=channels;
-
-     /* get the size */
-
-     fstat(x->x_fd,&fstate);
-     x->x_size = (int)fstate.st_size;
-     x->x_skip=x->x_size-bytelimit;
-     x->x_len = (bytelimit)/(bytespersamp*x->x_fchannels);
-
-     //post("bytelimit=%d    x->x_size-x->x_skip=%d  x->x_size=%d x->x_skip=%d",bytelimit,x->x_size-x->x_skip,x->x_size,x->x_skip);
-
-     /* map the file into memory */
-
-     if (!(x->x_mapaddr = mmap(NULL,x->x_size,PROT_READ,MAP_PRIVATE,x->x_fd,0)))
-     {
-	  error("can't mmap %s",fname);
-	  return;
-     }
-	 sfread_size(x);
-}
-
-static void *sfread_new(t_floatarg chan,t_floatarg interp)
-{
-    t_sfread *x = (t_sfread *)pd_new(sfread_class);
-    t_int c = chan;
-
-    x->x_glist = (t_glist*) canvas_getcurrent();
-
-    if (c<1 || c > MAX_CHANS) c = 1;
-    floatinlet_new(&x->x_obj, &x->x_speed);
-
-
-    x->x_fd = -1;
-    x->x_mapaddr = NULL;
-
-    x->x_size = 0;
-    x->x_len = 0;
-    x->x_loop = 0;
-    x->x_outchannels = c;
-    x->x_fchannels = 1;
-    x->x_mapaddr=NULL;
-    x->x_index = 1;
-    x->x_skip = 0;
-    x->x_speed = 1.0;
-    x->x_play = 0;
-    x->x_interp = (interp!=0);
-	x->x_clock = clock_new(x, (t_method)sfread_state);
-	
-    while (c--) {
-	 outlet_new(&x->x_obj, gensym("signal"));
-    }
-
-     x->x_stateout = outlet_new(&x->x_obj, &s_float);
-     x->x_sizeout = outlet_new(&x->x_obj, &s_float);
-
-/*  post("sfread: x_channels = %d, x_speed = %f",x->x_channels,x->x_speed);*/
-
-    return (x);
-}
-    
-static void sfread_free(t_sfread *x)
-{
-	clock_free(x->x_clock);
-}
-
-void sfread2_tilde_setup(void)
-{
-     /* sfread */
-
-    sfread_class = class_new(gensym("sfread2~"), (t_newmethod)sfread_new, 
-		(t_method)sfread_free,sizeof(t_sfread), 0,A_DEFFLOAT,A_DEFFLOAT,0);
-
-    class_addmethod(sfread_class, nullfn, gensym("signal"), 0);
-    class_addmethod(sfread_class, (t_method) sfread_dsp, gensym("dsp"), 0);
-    class_addmethod(sfread_class, (t_method) sfread_open, gensym("open"), A_SYMBOL,A_NULL);
-    class_addmethod(sfread_class, (t_method) sfread_size, gensym("size"), 0);
-    class_addmethod(sfread_class, (t_method) sfread_state, gensym("state"), 0);
-    class_addfloat(sfread_class, sfread_float);
-    class_addbang(sfread_class,sfread_bang);
-    class_addmethod(sfread_class,(t_method)sfread_loop,gensym("loop"),A_FLOAT,A_NULL);
-    class_addmethod(sfread_class,(t_method)sfread_interp,gensym("interp"),A_FLOAT,A_NULL);
-    class_addmethod(sfread_class,(t_method)sfread_index,gensym("index"),A_FLOAT,A_NULL);
-
-
-	// Impossible with pd-0.35 because it leaves super-user mode.
-    //if(munlockall()) perror("munlockall()");
-    //if(mlockall(MCL_CURRENT)) perror("mlockall(MCL_CURRENT)");
-}
-
-
-
-
-
-#endif /* NOT _WIN32 */
-
+#ifndef _WIN32
+
+#include <m_pd.h>
+//#include <m_imp.h>
+#include "g_canvas.h"
+#ifdef _MSC_VER
+#pragma warning( disable : 4244 )
+#pragma warning( disable : 4305 )
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#ifndef _WIN32
+#include <unistd.h>
+#include <sys/mman.h>
+#else
+#include <io.h>
+#endif
+
+
+#include <fcntl.h>
+#include <sys/stat.h>
+
+/* ------------------------ sfread~ ----------------------------- */
+
+#ifdef _WIN32
+#define BINREADMODE "rb"
+#else
+#define BINREADMODE "r"
+#endif
+
+static t_class *sfread_class;
+
+
+typedef struct _sfread
+{
+    t_object x_obj;
+    void     *x_mapaddr;
+    int       x_fd;
+
+    t_int   x_play;
+    t_int   x_outchannels;
+    t_int   x_loop;
+    double x_index;	//samples
+    t_float x_speed;	//1=sample rate
+    t_int   x_interp;
+
+    t_int   x_size;	// bytes
+    t_int   x_fchannels; // file channels
+    t_int   x_len;	// samples
+    t_int x_skip;	//bytes
+    t_clock *x_clock;
+
+
+    t_glist *x_glist;
+    t_outlet *x_stateout;
+    t_outlet *x_sizeout;
+} t_sfread;
+
+#define MAX_CHANS 4
+
+
+
+//1 -> 2
+
+//1 -> 4
+
+//2 -> 4
+
+
+static t_int *sfread_perform(t_int *w)
+{
+    t_sfread *x = (t_sfread *)(w[1]);
+    short *fp, *buf = x->x_mapaddr+x->x_skip;
+    /*     t_float *in = (t_float *)(w[2]); will we need this (indexing) ?*/
+    int c = x->x_outchannels;
+    int fc = x->x_fchannels,fc2=2*fc;
+    double findex = x->x_index;
+    t_float speed = x->x_speed;
+    float frac,  a,  b,  cc,  d, cminusb;
+    int i,n,index,rindex;
+    int end =  x->x_len -3;/* -3 is for safe interpolation*/
+    t_float *out[MAX_CHANS];
+    t_int in_off[MAX_CHANS];
+    t_int loground=(fc==1?0:fc==2?1:2);
+
+    if(!x->x_mapaddr) return(w+c+4);
+
+    for (i=0; i<c; i++)
+    {
+        out[i] = (t_float *)(w[3+i]);
+        in_off[i]=i%fc;
+    }
+    n = (int)(w[3+c]);
+
+    /* loop */
+
+    if (findex >  end)
+        findex = end;
+
+    if (findex + n*speed > end)   // playing forward end
+    {
+        if (!x->x_loop)
+        {
+            x->x_play=0;
+            findex = 0;
+            clock_delay(x->x_clock, 0);
+        }
+    }
+
+    if (findex + n*speed < 1)    // playing backwards end
+    {
+        if (!x->x_loop)
+        {
+            x->x_play=0;
+            findex = end;
+            clock_delay(x->x_clock, 0);
+        }
+
+    }
+
+
+    if (x->x_play && x->x_mapaddr)
+    {
+
+        if (speed != 1)   /* different speed */
+        {
+            if (x->x_interp) while (n--)
+                {
+                    index=findex;
+                    rindex=index<<loground;
+                    frac = findex - index;
+                    for (i=0; i<c; i++)
+                    {
+                        fp=buf + rindex +in_off[i];
+                        a = fp[-fc];
+                        b = fp[0];
+                        cc = fp[fc];
+                        d = fp[fc2];
+                        cminusb = cc-b;
+                        *out[i]++ = 3.052689e-05*
+                                    (b + frac * (cminusb - 0.5f * (frac-1.) *
+                                                 ((a - d + 3.0f * cminusb) * frac + (b - a - cminusb))));
+                        //*out[i]++ = *(buf+rindex+in_off[i])*3.052689e-05;
+                    }
+                    findex=findex+speed;
+                    if (findex > end)
+                    {
+                        if (x->x_loop) findex = 1;
+                        else break;
+                    }
+                    if (findex < 1)
+                    {
+                        if (x->x_loop) findex = end;
+                        else break;
+                    }
+                }
+            else while (n--)
+                {
+                    rindex=((int)findex)<<loground;
+                    for (i=0; i<c; i++)
+                    {
+                        *out[i]++ = *(buf+rindex+in_off[i])*3.052689e-05;
+                    }
+                    findex+=speed;
+                    if (findex > end)
+                    {
+                        if (x->x_loop) findex = 1;
+                        else break;
+                    }
+                    if (findex < 1)
+                    {
+                        if (x->x_loop) findex = end;
+                        else break;
+                    }
+                }
+            /* Fill with zero in case of end */
+            n++;
+            while (n--)
+                for (i=0; i<c; i++)
+                    *out[i]++ = 0;
+            //offset = aoff;
+        }
+        else   /* speed == 1 */
+        {
+            int end2=end*fc;
+            rindex=((int)findex)<<loground;
+            while (n--)
+            {
+                for (i=0; i<c; i++)
+                {
+                    *out[i]++ = *(buf+rindex+in_off[i])*3.052689e-05;
+                }
+                rindex+=fc;
+                if (rindex > end2)
+                {
+                    if (x->x_loop) rindex = 1;
+                    else break;
+                }
+            }
+
+            /* Fill with zero in case of end */
+            n++;
+            while (n--)
+                for (i=0; i<c; i++)
+                    *out[i]++ = 0.;
+            findex=rindex>>loground;
+        }
+
+    }
+    else
+    {
+        while (n--)
+        {
+            for (i=0; i<c; i++)
+                *out[i]++ = 0.;
+        }
+    }
+    x->x_index = findex;
+    return (w+c+4);
+}
+
+
+static void sfread_loop(t_sfread *x, t_floatarg f)
+{
+    x->x_loop = f;
+}
+
+static void sfread_interp(t_sfread *x, t_floatarg f)
+{
+    x->x_interp = (f!=0);
+}
+
+static void sfread_index(t_sfread *x, t_floatarg f)
+{
+    x->x_index = f;
+}
+
+
+static void sfread_size(t_sfread *x)
+{
+    outlet_float(x->x_sizeout,x->x_len);
+}
+
+static void sfread_state(t_sfread *x)
+{
+    outlet_float(x->x_stateout, x->x_play);
+}
+
+static void sfread_float(t_sfread *x, t_floatarg f)
+{
+    int t = f;
+    if (t && x->x_mapaddr)
+    {
+        x->x_play=1;
+    }
+    else
+    {
+        x->x_play=0;
+    }
+    sfread_state(x);
+}
+
+
+static void sfread_bang(t_sfread *x)
+{
+    x->x_index = x->x_speed>0?1:x->x_len-3;
+    sfread_float(x,1.0);
+}
+
+
+static void sfread_dsp(t_sfread *x, t_signal **sp)
+{
+    /*     post("sfread: dsp"); */
+    switch (x->x_outchannels)
+    {
+    case 1:
+        dsp_add(sfread_perform, 4, x, sp[0]->s_vec,
+                sp[1]->s_vec, sp[0]->s_n);
+        break;
+    case 2:
+        dsp_add(sfread_perform, 5, x, sp[0]->s_vec,
+                sp[1]->s_vec,sp[2]->s_vec, sp[0]->s_n);
+        break;
+    case 4:
+        dsp_add(sfread_perform, 7, x, sp[0]->s_vec,
+                sp[1]->s_vec,sp[2]->s_vec,
+                sp[3]->s_vec,sp[4]->s_vec,
+                sp[0]->s_n);
+        break;
+    }
+}
+
+
+extern int open_soundfile(const char *dirname, const char *filename, int headersize,
+                          int *p_bytespersamp, int *p_bigendian, int *p_nchannels, long *p_bytelimit,
+                          long skipframes); /* in pd/src/d_soundfile.c */
+
+
+static void sfread_open(t_sfread *x,t_symbol *filename)
+{
+    struct stat  fstate;
+    char fname[MAXPDSTRING];
+    int bytespersamp=0,bigendian=0,channels=0;
+    long bytelimit= 0x7fffffff,skipframes = 0;
+
+    if (filename == &s_)
+    {
+        post("sfread: open without filename");
+        return;
+    }
+
+    canvas_makefilename(glist_getcanvas(x->x_glist), filename->s_name,
+                        fname, MAXPDSTRING);
+
+
+    /* close the old file */
+
+    if (x->x_mapaddr) munmap(x->x_mapaddr,x->x_size);
+    if (x->x_fd >= 0) close(x->x_fd);
+
+    /*if ((x->x_fd = open(fname,O_RDONLY)) < 0)*/
+    //post("fname: %s",fname);
+
+    if ((x->x_fd = open_soundfile("",fname, -1,&bytespersamp,&bigendian,
+                                  &channels, &bytelimit,0)) < 0)
+    {
+        error("can't open %s",fname);
+        x->x_play = 0;
+        x->x_mapaddr = NULL;
+        return;
+    }
+
+    if( ((x->x_fchannels!=1)&&(x->x_fchannels!=2)&&(x->x_fchannels!=4)) ||
+            (bytespersamp!=2) )
+    {
+        error("file %s error: not a 1 or 2 or 4 channels soundfile, or not a 16 bits soundfile",fname);
+        post("channels:%d bytes:%d ",x->x_fchannels,bytespersamp);
+        x->x_play = 0;
+        x->x_mapaddr = NULL;
+        return;
+    }
+
+    x->x_fchannels=channels;
+
+    /* get the size */
+
+    fstat(x->x_fd,&fstate);
+    x->x_size = (int)fstate.st_size;
+    x->x_skip=x->x_size-bytelimit;
+    x->x_len = (bytelimit)/(bytespersamp*x->x_fchannels);
+
+    //post("bytelimit=%d    x->x_size-x->x_skip=%d  x->x_size=%d x->x_skip=%d",bytelimit,x->x_size-x->x_skip,x->x_size,x->x_skip);
+
+    /* map the file into memory */
+
+    if (!(x->x_mapaddr = mmap(NULL,x->x_size,PROT_READ,MAP_PRIVATE,x->x_fd,0)))
+    {
+        error("can't mmap %s",fname);
+        return;
+    }
+    sfread_size(x);
+}
+
+static void *sfread_new(t_floatarg chan,t_floatarg interp)
+{
+    t_sfread *x = (t_sfread *)pd_new(sfread_class);
+    t_int c = chan;
+
+    x->x_glist = (t_glist *) canvas_getcurrent();
+
+    if (c<1 || c > MAX_CHANS) c = 1;
+    floatinlet_new(&x->x_obj, &x->x_speed);
+
+
+    x->x_fd = -1;
+    x->x_mapaddr = NULL;
+
+    x->x_size = 0;
+    x->x_len = 0;
+    x->x_loop = 0;
+    x->x_outchannels = c;
+    x->x_fchannels = 1;
+    x->x_mapaddr=NULL;
+    x->x_index = 1;
+    x->x_skip = 0;
+    x->x_speed = 1.0;
+    x->x_play = 0;
+    x->x_interp = (interp!=0);
+    x->x_clock = clock_new(x, (t_method)sfread_state);
+
+    while (c--)
+    {
+        outlet_new(&x->x_obj, gensym("signal"));
+    }
+
+    x->x_stateout = outlet_new(&x->x_obj, &s_float);
+    x->x_sizeout = outlet_new(&x->x_obj, &s_float);
+
+    /*  post("sfread: x_channels = %d, x_speed = %f",x->x_channels,x->x_speed);*/
+
+    return (x);
+}
+
+static void sfread_free(t_sfread *x)
+{
+    clock_free(x->x_clock);
+}
+
+void sfread2_tilde_setup(void)
+{
+    /* sfread */
+
+    sfread_class = class_new(gensym("sfread2~"), (t_newmethod)sfread_new,
+                             (t_method)sfread_free,sizeof(t_sfread), 0,A_DEFFLOAT,A_DEFFLOAT,0);
+
+    class_addmethod(sfread_class, nullfn, gensym("signal"), 0);
+    class_addmethod(sfread_class, (t_method) sfread_dsp, gensym("dsp"), 0);
+    class_addmethod(sfread_class, (t_method) sfread_open, gensym("open"), A_SYMBOL,A_NULL);
+    class_addmethod(sfread_class, (t_method) sfread_size, gensym("size"), 0);
+    class_addmethod(sfread_class, (t_method) sfread_state, gensym("state"), 0);
+    class_addfloat(sfread_class, sfread_float);
+    class_addbang(sfread_class,sfread_bang);
+    class_addmethod(sfread_class,(t_method)sfread_loop,gensym("loop"),A_FLOAT,A_NULL);
+    class_addmethod(sfread_class,(t_method)sfread_interp,gensym("interp"),A_FLOAT,A_NULL);
+    class_addmethod(sfread_class,(t_method)sfread_index,gensym("index"),A_FLOAT,A_NULL);
+
+
+    // Impossible with pd-0.35 because it leaves super-user mode.
+    //if(munlockall()) perror("munlockall()");
+    //if(mlockall(MCL_CURRENT)) perror("mlockall(MCL_CURRENT)");
+}
+
+
+
+
+
+#endif /* NOT _WIN32 */
+
diff --git a/slist-help.pd b/slist-help.pd
index f499120..a248cc5 100644
--- a/slist-help.pd
+++ b/slist-help.pd
@@ -1,61 +1,74 @@
-#N canvas 459 312 690 375 10;
-#X obj 0 0 cnv 8 100 60 empty empty slist 10 20 1 18 -262144 -1109
-0;
-#X text 3 354 (c) Moonix: Antoine Rousseau 2003;
-#X text 109 12 shared list of symbols \, with a "find" feature;
-#X obj 80 107 slist foo;
-#X obj 261 100 slist foo;
-#X text 24 55 1) fill the slist;
-#X msg 261 79 len;
-#X text 260 58 2) get the slist length;
-#X floatatom 319 121 5 0 0;
-#X obj 480 106 slist foo;
-#X msg 451 79 1;
-#X msg 480 79 2;
-#X msg 508 79 3;
-#X symbolatom 509 127 10 0 0;
-#X obj 157 218 slist foo;
-#X text 448 59 3) get the nth symbol (first:1);
-#X msg 21 189 find boo;
-#X msg 225 189 find bar;
-#X floatatom 157 242 5 0 0;
-#X msg 91 189 find bee;
-#X msg 157 189 find baa;
-#X obj 548 212 slist foo;
-#X text 21 168 4) find the index of a symbol (0 = not found);
-#X msg 548 192 reset;
-#X msg 144 77 add baa;
-#X msg 26 77 add boo \, add bee;
-#X obj 378 223 slist foo;
-#X text 364 169 5) print to console;
-#X text 546 171 6) clear the slist;
-#X msg 378 203 print;
-#X text 383 184 (debug);
-#X obj 256 318 slist foo2;
-#X text 256 271 7) switch to another slist;
-#X obj 476 345 slist;
-#X msg 503 296 setlist foo;
-#X msg 503 318 setlist foo2;
-#X msg 460 296 print;
-#X msg 256 297 add boo2 \, add bee2 \, add baa2;
-#X msg 212 297 print;
-#X connect 4 2 8 0;
-#X connect 6 0 4 0;
-#X connect 9 1 13 0;
-#X connect 10 0 9 0;
-#X connect 11 0 9 0;
-#X connect 12 0 9 0;
-#X connect 14 0 18 0;
-#X connect 16 0 14 0;
-#X connect 17 0 14 0;
-#X connect 19 0 14 0;
-#X connect 20 0 14 0;
-#X connect 23 0 21 0;
-#X connect 24 0 3 0;
-#X connect 25 0 3 0;
-#X connect 29 0 26 0;
-#X connect 34 0 33 0;
-#X connect 35 0 33 0;
-#X connect 36 0 33 0;
-#X connect 37 0 31 0;
-#X connect 38 0 31 0;
+#N canvas 0 31 690 414 10;
+#X obj 0 0 cnv 8 100 60 empty empty slist 10 20 1 18 -262144 -1109
+0;
+#X text 3 354 (c) Moonix: Antoine Rousseau 2003;
+#X text 109 12 shared list of symbols \, with a "find" feature;
+#X obj 80 107 slist foo;
+#X obj 261 100 slist foo;
+#X text 24 55 1) fill the slist;
+#X msg 261 79 len;
+#X text 260 58 2) get the slist length;
+#X floatatom 319 121 5 0 0 0 - - -;
+#X obj 480 106 slist foo;
+#X msg 451 79 1;
+#X msg 480 79 2;
+#X msg 508 79 3;
+#X symbolatom 509 127 10 0 0 0 - - -;
+#X obj 157 218 slist foo;
+#X text 448 59 3) get the nth symbol (first:1);
+#X msg 21 189 find boo;
+#X msg 225 189 find bar;
+#X floatatom 157 242 5 0 0 0 - - -;
+#X msg 91 189 find bee;
+#X msg 157 189 find baa;
+#X obj 548 212 slist foo;
+#X text 21 168 4) find the index of a symbol (0 = not found);
+#X msg 548 192 reset;
+#X msg 144 77 add baa;
+#X msg 26 77 add boo \, add bee;
+#X obj 378 223 slist foo;
+#X text 364 169 5) print to console;
+#X text 546 171 6) clear the slist;
+#X msg 378 203 print;
+#X text 383 184 (debug);
+#X obj 256 318 slist foo2;
+#X text 256 271 7) switch to another slist;
+#X obj 476 345 slist;
+#X msg 503 296 setlist foo;
+#X msg 503 318 setlist foo2;
+#X msg 460 296 print;
+#X msg 256 297 add boo2 \, add bee2 \, add baa2;
+#X msg 212 297 print;
+#N canvas 592 238 494 344 META 0;
+#X text 12 25 LICENSE GPL v2;
+#X text 12 145 AUTHOR Antoine Rousseau;
+#X text 12 165 HELP_PATCH_AUTHORS Antoine Rousseau. "pd meta" information
+added by Jonathan Wilkes for Pd version 0.42.;
+#X text 12 5 KEYWORDS control list_op;
+#X text 12 45 DESCRIPTION shared list of symbols \, with a "find" feature
+;
+#X text 12 65 INLET_0 add len float find print reset setlist;
+#X text 12 85 OUTLET_0 float;
+#X text 12 105 OUTLET_1 symbol;
+#X text 12 125 OUTLET_2 float;
+#X restore 635 385 pd META;
+#X connect 4 2 8 0;
+#X connect 6 0 4 0;
+#X connect 9 1 13 0;
+#X connect 10 0 9 0;
+#X connect 11 0 9 0;
+#X connect 12 0 9 0;
+#X connect 14 0 18 0;
+#X connect 16 0 14 0;
+#X connect 17 0 14 0;
+#X connect 19 0 14 0;
+#X connect 20 0 14 0;
+#X connect 23 0 21 0;
+#X connect 24 0 3 0;
+#X connect 25 0 3 0;
+#X connect 29 0 26 0;
+#X connect 34 0 33 0;
+#X connect 35 0 33 0;
+#X connect 36 0 33 0;
+#X connect 37 0 31 0;
+#X connect 38 0 31 0;
diff --git a/slist.c b/slist.c
index 6af28c6..4e8cf80 100644
--- a/slist.c
+++ b/slist.c
@@ -1,233 +1,237 @@
-/*
-Copyright (C) 2003 Antoine Rousseau 
-
-This library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation; either
-version 2.1 of the License, or (at your option) any later version.
-
-This library 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
-Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with this library; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  
-
-*/
-
-/* a shared symbol list, ala "value" .*/
-
-#include <m_pd.h>
-#include <stdlib.h>
-#include <string.h>
-
-static t_class *slist_class, *scommon_class;
-
-typedef struct _sitem t_sitem;
-
-struct _sitem
-{
-	t_sitem *next;
-	t_symbol *s;
-};
-
-typedef struct scommon
-{
-    t_pd c_pd;
-    t_symbol *c_sym;
-    int c_refcount;
-	t_sitem *first;
-} t_scommon;
-
-typedef struct _slist
-{
-    t_object x_obj;
-    t_symbol *x_sym;
-    t_scommon *x_c;
-	t_outlet *x_symout;
-	t_outlet *x_lenout;
-} t_slist;
-
-
-static void sitem_delete(t_sitem **x)
-{
-	t_sitem *next=(*x)->next;
-	
-	//freebytes((*x)->name,strlen((*x)->name)+1);
-	freebytes(*x,sizeof(t_sitem));
-	(*x)=next;
-}
-
-static void sitem_add(t_sitem **x,t_symbol *s)
-{
-	t_int l;
-	t_sitem *newone=getbytes(sizeof(t_sitem));
-	
-	//newone->name=getbytes(l=(strlen(s->s_name)+1));
-	//strncpy(newone->name,s->s_name,l);
-	newone->s=s;
-	newone->next=0;
-	
-	while(*x) x=&((*x)->next);
-	
-	*x=newone;
-}
-
-static void *scommon_new(t_symbol *s)
-{
-    t_scommon *x = (t_scommon *)pd_new(scommon_class);
-
-	x->c_refcount = 0;
-	x->c_sym=s;
-	pd_bind((t_pd*)x, s);
-	
-    x->first=0;
-
-    return (x);
-}
-
-static int scommon_find(t_scommon *x, t_symbol *s)
-{
-	t_sitem *si=x->first;
-	t_int i=1;
-	
-	while(si) {
-		if(!strcmp(si->s->s_name,s->s_name)) return i; 
-		si=si->next;
-		i++;
-	}
-	return 0;
-}
- 
-static void scommon_add(t_scommon *x, t_symbol *s)
-{
-	sitem_add(&x->first,s);
-}
-
-static void scommon_reset(t_scommon *x)
-{
- 	while(x->first) sitem_delete(&x->first);
-}
-
-static void scommon_ff(t_scommon *x)
-{
- 	scommon_reset(x);
-	pd_unbind((t_pd*)x, x->c_sym);
-}
-
-
-    /* get a pointer to a named symbol list (a "scommon" object), 
-	which is created if necessary. */
-t_scommon *slist_get(t_symbol *s)
-{
-    t_scommon *c = (t_scommon *)pd_findbyclass(s, scommon_class);
-
-    if (!c) c = (t_scommon *)scommon_new(s);
-    c->c_refcount++;
-    return (c);
-}
-
-    /* release a variable.  This only frees the "scommon" resource when the
-    last interested party releases it. */
-void slist_release(t_scommon *c)
-{
-	if (!--c->c_refcount) scommon_ff(c);
-}
-
- 
-static void *slist_new(t_symbol *s)
-{
-    t_slist *x = (t_slist *)pd_new(slist_class);
-    x->x_sym = s;
-    x->x_c = slist_get(s);
-    outlet_new(&x->x_obj, &s_float);
-    x->x_symout=outlet_new(&x->x_obj, &s_symbol);
-    x->x_lenout=outlet_new(&x->x_obj, &s_float);
-    return (x);
-}
-
-static void slist_ff(t_slist *x)
-{
-    slist_release(x->x_c);
-}
-
-static void slist_print(t_slist *x)
-{
-	t_sitem *t=x->x_c->first;
-	int i=0;
-	
-	while(t){
-		post("item %d: %s",++i,t->s->s_name);
-		t=t->next;
-	}
-}
-
-static void slist_reset(t_slist *x)
-{
-	scommon_reset(x->x_c);
-}
-
-static void slist_add(t_slist *x,t_symbol *s)
-{
-	scommon_add(x->x_c,s);
-}
-
-static void slist_find(t_slist *x,t_symbol *s)
-{
-	outlet_float(x->x_obj.ob_outlet,scommon_find(x->x_c,s));
-}
-
-static void slist_setlist(t_slist *x,t_symbol *s)
-{
-	slist_release(x->x_c);
-	x->x_c = slist_get(s);
-}
-
-static void slist_float(t_slist *x, t_float f)
-{
-	t_sitem *t=x->x_c->first;
-	int i=0;
-
-	if(!f) return;
-		
-	while(t&&((++i)!=f)){
-		t=t->next;
-	}
-
-	if(t) outlet_symbol(x->x_symout,t->s);
-}
-
-static void slist_len(t_slist *x)
-{
-	t_sitem *t=x->x_c->first;
-	int i=0;
-
-	while(t){
-		t=t->next;
-		i++;
-	}
-
-	outlet_float(x->x_lenout,i);
-}
-
-
-void slist_setup(void)
-{
-    slist_class = class_new(gensym("slist"), (t_newmethod)slist_new,
-    	(t_method)slist_ff,
-    	sizeof(t_slist), 0, A_DEFSYM, 0);
-
-    //class_addbang(slist_class, slist_bang);
-    class_addfloat(slist_class, slist_float);
-    class_addmethod(slist_class,(t_method)slist_add, gensym("add"),A_SYMBOL,0);
-    class_addmethod(slist_class,(t_method)slist_find, gensym("find"),A_SYMBOL,0);
-    class_addmethod(slist_class,(t_method)slist_setlist, gensym("setlist"),A_SYMBOL,0);
-    class_addmethod(slist_class,(t_method)slist_reset, gensym("reset"),0);
-    class_addmethod(slist_class,(t_method)slist_print, gensym("print"),0);
-    class_addmethod(slist_class,(t_method)slist_len, gensym("len"),0);
-   scommon_class = class_new(gensym("slist"), 0, 0,
-    	sizeof(t_scommon), CLASS_PD, 0);
-}
-
+/*
+Copyright (C) 2003 Antoine Rousseau
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+*/
+
+/* a shared symbol list, ala "value" .*/
+
+#include <m_pd.h>
+#include <stdlib.h>
+#include <string.h>
+
+static t_class *slist_class, *scommon_class;
+
+typedef struct _sitem t_sitem;
+
+struct _sitem
+{
+    t_sitem *next;
+    t_symbol *s;
+};
+
+typedef struct scommon
+{
+    t_pd c_pd;
+    t_symbol *c_sym;
+    int c_refcount;
+    t_sitem *first;
+} t_scommon;
+
+typedef struct _slist
+{
+    t_object x_obj;
+    t_symbol *x_sym;
+    t_scommon *x_c;
+    t_outlet *x_symout;
+    t_outlet *x_lenout;
+} t_slist;
+
+
+static void sitem_delete(t_sitem **x)
+{
+    t_sitem *next=(*x)->next;
+
+    //freebytes((*x)->name,strlen((*x)->name)+1);
+    freebytes(*x,sizeof(t_sitem));
+    (*x)=next;
+}
+
+static void sitem_add(t_sitem **x,t_symbol *s)
+{
+    t_int l;
+    t_sitem *newone=getbytes(sizeof(t_sitem));
+
+    //newone->name=getbytes(l=(strlen(s->s_name)+1));
+    //strncpy(newone->name,s->s_name,l);
+    newone->s=s;
+    newone->next=0;
+
+    while(*x) x=&((*x)->next);
+
+    *x=newone;
+}
+
+static void *scommon_new(t_symbol *s)
+{
+    t_scommon *x = (t_scommon *)pd_new(scommon_class);
+
+    x->c_refcount = 0;
+    x->c_sym=s;
+    pd_bind((t_pd *)x, s);
+
+    x->first=0;
+
+    return (x);
+}
+
+static int scommon_find(t_scommon *x, t_symbol *s)
+{
+    t_sitem *si=x->first;
+    t_int i=1;
+
+    while(si)
+    {
+        if(!strcmp(si->s->s_name,s->s_name)) return i;
+        si=si->next;
+        i++;
+    }
+    return 0;
+}
+
+static void scommon_add(t_scommon *x, t_symbol *s)
+{
+    sitem_add(&x->first,s);
+}
+
+static void scommon_reset(t_scommon *x)
+{
+    while(x->first) sitem_delete(&x->first);
+}
+
+static void scommon_ff(t_scommon *x)
+{
+    scommon_reset(x);
+    pd_unbind((t_pd *)x, x->c_sym);
+}
+
+
+/* get a pointer to a named symbol list (a "scommon" object),
+which is created if necessary. */
+t_scommon *slist_get(t_symbol *s)
+{
+    t_scommon *c = (t_scommon *)pd_findbyclass(s, scommon_class);
+
+    if (!c) c = (t_scommon *)scommon_new(s);
+    c->c_refcount++;
+    return (c);
+}
+
+/* release a variable.  This only frees the "scommon" resource when the
+last interested party releases it. */
+void slist_release(t_scommon *c)
+{
+    if (!--c->c_refcount) scommon_ff(c);
+}
+
+
+static void *slist_new(t_symbol *s)
+{
+    t_slist *x = (t_slist *)pd_new(slist_class);
+    x->x_sym = s;
+    x->x_c = slist_get(s);
+    outlet_new(&x->x_obj, &s_float);
+    x->x_symout=outlet_new(&x->x_obj, &s_symbol);
+    x->x_lenout=outlet_new(&x->x_obj, &s_float);
+    return (x);
+}
+
+static void slist_ff(t_slist *x)
+{
+    slist_release(x->x_c);
+}
+
+static void slist_print(t_slist *x)
+{
+    t_sitem *t=x->x_c->first;
+    int i=0;
+
+    while(t)
+    {
+        post("item %d: %s",++i,t->s->s_name);
+        t=t->next;
+    }
+}
+
+static void slist_reset(t_slist *x)
+{
+    scommon_reset(x->x_c);
+}
+
+static void slist_add(t_slist *x,t_symbol *s)
+{
+    scommon_add(x->x_c,s);
+}
+
+static void slist_find(t_slist *x,t_symbol *s)
+{
+    outlet_float(x->x_obj.ob_outlet,scommon_find(x->x_c,s));
+}
+
+static void slist_setlist(t_slist *x,t_symbol *s)
+{
+    slist_release(x->x_c);
+    x->x_c = slist_get(s);
+}
+
+static void slist_float(t_slist *x, t_float f)
+{
+    t_sitem *t=x->x_c->first;
+    int i=0;
+
+    if(!f) return;
+
+    while(t&&((++i)!=f))
+    {
+        t=t->next;
+    }
+
+    if(t) outlet_symbol(x->x_symout,t->s);
+}
+
+static void slist_len(t_slist *x)
+{
+    t_sitem *t=x->x_c->first;
+    int i=0;
+
+    while(t)
+    {
+        t=t->next;
+        i++;
+    }
+
+    outlet_float(x->x_lenout,i);
+}
+
+
+void slist_setup(void)
+{
+    slist_class = class_new(gensym("slist"), (t_newmethod)slist_new,
+                            (t_method)slist_ff,
+                            sizeof(t_slist), 0, A_DEFSYM, 0);
+
+    //class_addbang(slist_class, slist_bang);
+    class_addfloat(slist_class, slist_float);
+    class_addmethod(slist_class,(t_method)slist_add, gensym("add"),A_SYMBOL,0);
+    class_addmethod(slist_class,(t_method)slist_find, gensym("find"),A_SYMBOL,0);
+    class_addmethod(slist_class,(t_method)slist_setlist, gensym("setlist"),A_SYMBOL,0);
+    class_addmethod(slist_class,(t_method)slist_reset, gensym("reset"),0);
+    class_addmethod(slist_class,(t_method)slist_print, gensym("print"),0);
+    class_addmethod(slist_class,(t_method)slist_len, gensym("len"),0);
+    scommon_class = class_new(gensym("slist"), 0, 0,
+                              sizeof(t_scommon), CLASS_PD, 0);
+}
+
diff --git a/ssaw~-help.pd b/ssaw~-help.pd
index 25903d1..bcba817 100644
--- a/ssaw~-help.pd
+++ b/ssaw~-help.pd
@@ -1,21 +1,32 @@
-#N canvas 106 74 492 266 10;
-#X obj 0 0 cnv 8 100 60 empty empty ssaw 10 20 1 18 -262144 -1109 0
-;
-#X text 8 243 (c) Moonix: Antoine Rousseau 2004;
-#X obj 162 103 ssaw~ 440;
-#X obj 163 149 *~;
-#X obj 162 77 mtof;
-#X floatatom 161 57 5 0 0 0 - - -;
-#X floatatom 207 77 0 0 0 0 - - -;
-#X obj 197 128 hsl 128 15 0 1 0 0 empty empty empty -2 -6 0 8 -262144
--1 -1 0 1;
-#X obj 159 193 dac~;
-#X text 124 19 sweet sawtooth generator;
-#X text 121 32 (not to much aliasing below 10kHz);
-#X connect 2 0 3 0;
-#X connect 3 0 8 0;
-#X connect 3 0 8 1;
-#X connect 4 0 6 0;
-#X connect 4 0 2 0;
-#X connect 5 0 4 0;
-#X connect 7 0 3 1;
+#N canvas 588 67 492 285 10;
+#X obj 0 0 cnv 8 100 60 empty empty ssaw 10 20 1 18 -262144 -1109 0
+;
+#X text 8 243 (c) Moonix: Antoine Rousseau 2004;
+#X obj 162 103 ssaw~ 440;
+#X obj 163 149 *~;
+#X obj 162 77 mtof;
+#X floatatom 161 57 5 0 0 0 - - -, f 5;
+#X floatatom 207 77 0 0 0 0 - - -;
+#X obj 197 128 hsl 128 15 0 1 0 0 empty empty empty -2 -6 0 8 -262144
+-1 -1 0 1;
+#X obj 159 193 dac~;
+#X text 124 19 sweet sawtooth generator;
+#X text 121 32 (not to much aliasing below 10kHz);
+#N canvas 502 150 494 344 META 0;
+#X text 12 25 LICENSE GPL v2;
+#X text 12 125 AUTHOR Antoine Rousseau;
+#X text 12 145 HELP_PATCH_AUTHORS Antoine Rousseau. "pd meta" information
+added by Jonathan Wilkes for Pd version 0.42.;
+#X text 12 5 KEYWORDS signal bandlimited;
+#X text 12 45 DESCRIPTION sweet sawtooth generator;
+#X text 12 65 INLET_0 signal;
+#X text 12 85 INLET_1 float;
+#X text 12 105 OUTLET_0 signal;
+#X restore 434 232 pd META;
+#X connect 2 0 3 0;
+#X connect 3 0 8 0;
+#X connect 3 0 8 1;
+#X connect 4 0 6 0;
+#X connect 4 0 2 0;
+#X connect 5 0 4 0;
+#X connect 7 0 3 1;
diff --git a/ssaw~.c b/ssaw~.c
index c91b0f1..d0b29e6 100644
--- a/ssaw~.c
+++ b/ssaw~.c
@@ -1,213 +1,218 @@
-/*
-Copyright (C) 2004 Antoine Rousseau 
-all material Copyright (c) 1997-1999 Miller Puckette.
-
-This library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation; either
-version 2.1 of the License, or (at your option) any later version.
-
-This library 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
-Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with this library; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  
-
-*/
-
-/* a "sweet" saw generator, as described in pddoc/3.audio/K05.bandlimited .*/
-
-#include "m_pd.h"
-#include "math.h"
-#include <stdlib.h>
-
-#define UNITBIT32 1572864.  /* 3*2^19; bit 32 has place value 1 */
-
-    /* machine-dependent definitions.  These ifdefs really
-    should have been by CPU type and not by operating system! */
-#ifdef IRIX
-    /* big-endian.  Most significant byte is at low address in memory */
-#define HIOFFSET 0    /* word offset to find MSB */
-#define LOWOFFSET 1    /* word offset to find LSB */
-#define int32 long  /* a data type that has 32 bits */
-#else
-#ifdef _WIN32
-    /* little-endian; most significant byte is at highest address */
-#define HIOFFSET 1
-#define LOWOFFSET 0
-#define int32 long
-#else
-#ifdef __FreeBSD__
-#include <machine/endian.h>
-#if BYTE_ORDER == LITTLE_ENDIAN
-#define HIOFFSET 1
-#define LOWOFFSET 0
-#else
-#define HIOFFSET 0    /* word offset to find MSB */
-#define LOWOFFSET 1    /* word offset to find LSB */
-#endif /* BYTE_ORDER */
-#include <sys/types.h>
-#define int32 int32_t
-#endif
-#ifdef __linux__
-
-#include <endian.h>
-
-#if !defined(__BYTE_ORDER) || !defined(__LITTLE_ENDIAN)                         
-#error No byte order defined                                                    
-#endif                                                                          
-                                                                                
-#if __BYTE_ORDER == __LITTLE_ENDIAN                                             
-#define HIOFFSET 1                                                              
-#define LOWOFFSET 0                                                             
-#else                                                                           
-#define HIOFFSET 0    /* word offset to find MSB */                             
-#define LOWOFFSET 1    /* word offset to find LSB */                            
-#endif /* __BYTE_ORDER */                                                       
-
-#include <sys/types.h>
-#define int32 int32_t
-
-#else
-#ifdef __APPLE__
-#define HIOFFSET 0    /* word offset to find MSB */
-#define LOWOFFSET 1    /* word offset to find LSB */
-#define int32 int  /* a data type that has 32 bits */
-
-#endif /* __APPLE__ */
-#endif /* __linux__ */
-#endif /* _WIN32 */
-#endif /* SGI */
-
-union tabfudge
-{
-    double tf_d;
-    int32 tf_i[2];
-};
-
-
-/* -------------------------- ssaw~ ------------------------------ */
-static t_class *ssaw_class, *scalarssaw_class;
-static float ssaw_array[1002];
-#define SAW_ARRAY_LEN 1002
-
-typedef struct _ssaw
-{
-	t_object x_obj;
-    //from phasor~:
-	double x_phase;
-    float x_conv;
-    float x_f;	    /* scalar frequency */
-    float x_band;	/* band limit (Hertz)*/
-} t_ssaw;
-
-static void *ssaw_new(t_floatarg f)
-{
-    t_ssaw *x = (t_ssaw *)pd_new(ssaw_class);
-    x->x_f = f;
-    inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1"));
-    x->x_phase = 0;
-    x->x_conv = 0;
-    x->x_band = 22000;
-    outlet_new(&x->x_obj, gensym("signal"));
-    return (x);
-}
-
-static t_int *ssaw_perform(t_int *w)
-{
-    t_ssaw *x = (t_ssaw *)(w[1]);
-    t_float *in = (t_float *)(w[2]);
-    t_float *out = (t_float *)(w[3]);
-    int i,n = (int)(w[4]);
-    double dphase = x->x_phase + UNITBIT32;
-    union tabfudge tf;
-    int normhipart;
-    float conv = x->x_conv;
-	float band=x->x_band*.33;
-    float *buf = ssaw_array;
-
-    tf.tf_d = UNITBIT32;
-    normhipart = tf.tf_i[HIOFFSET];
-    tf.tf_d = dphase;
-
-    for (i = 0; i < n; i++)
-    //while (n--)
-    {
-		float phase,band2,findex /*= *in++*/;
-		int index /*= findex*/;
-		float frac,  a,  b,  c,  d, cminusb, *fp;
-		
-    	tf.tf_i[HIOFFSET] = normhipart;
-    	band2=abs(*in);
-		if(band2>999999) band2=999999; else if(band2<1) band2=1;
-		band2=band/band2;
-		dphase += *in++ * conv;
-		/**out++*/phase = (tf.tf_d - UNITBIT32)-0.5;
-		tf.tf_d = dphase;
-
-		findex=phase*band2;
-		if(findex>0.5) findex=0.5; else if(findex<-0.5) findex=-0.5;
-
-		/*findex=findex*1000+501;
-		index=findex;*/
-		/*if (index < 1)
-		    index = 1, frac = 0;
-		else if (index > maxindex)
-		    index = maxindex, frac = 1;
-		else*/ frac = findex - index;
-		/*fp = buf + index;
-		a = fp[-1];
-		b = fp[0];
-		c = fp[1];
-		d = fp[2];
-		cminusb = c-b;
-		*out++ = 0.5+ phase - (
-				 b + frac * ( cminusb - 0.1666667f * (1.-frac) * (
-				(d - a - 3.0f * cminusb) * frac + (d + 2.0f*a - 3.0f*b))) 
-				);*/
-		*out++ = 0.5+ phase - buf[(int)(findex*1000+501)];
-    }
-
-    tf.tf_i[HIOFFSET] = normhipart;
-    x->x_phase = tf.tf_d - UNITBIT32;
-    return (w+5);
-}
-
-static void ssaw_dsp(t_ssaw *x, t_signal **sp)
-{
-    x->x_conv = 1./sp[0]->s_sr;
-    dsp_add(ssaw_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
-}
-
-static void ssaw_ft1(t_ssaw *x, t_float f)
-{
-    x->x_phase = f;
-}
-
-static void ssaw_initarray(void)
-{
-	int i;
-	float j;
-
-	for(i=0;i<1002;i++){
-		j=(i-1)*M_PI/1000.0; //period 2000 sample, 1 sample back phase
-		ssaw_array[i]= 0.57692* 
-			(-1*cos(j) + 0.333333*cos(j*3.0) -0.2* cos(j*5.0));
-	}
-}
-
-void ssaw_tilde_setup(void)
-{
-    ssaw_class = class_new(gensym("ssaw~"), (t_newmethod)ssaw_new, 0,
-    	sizeof(t_ssaw), 0, A_DEFFLOAT, 0);
-    CLASS_MAINSIGNALIN(ssaw_class, t_ssaw, x_f);
-    class_addmethod(ssaw_class, (t_method)ssaw_dsp, gensym("dsp"), 0);
-    class_addmethod(ssaw_class, (t_method)ssaw_ft1,
-    	gensym("ft1"), A_FLOAT, 0);
-	ssaw_initarray();
-
-}
-
+/*
+Copyright (C) 2004 Antoine Rousseau
+all material Copyright (c) 1997-1999 Miller Puckette.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+*/
+
+/* a "sweet" saw generator, as described in pddoc/3.audio/K05.bandlimited .*/
+
+#include "m_pd.h"
+#include "math.h"
+#include <stdlib.h>
+
+#define UNITBIT32 1572864.  /* 3*2^19; bit 32 has place value 1 */
+
+/* machine-dependent definitions.  These ifdefs really
+should have been by CPU type and not by operating system! */
+#ifdef IRIX
+/* big-endian.  Most significant byte is at low address in memory */
+#define HIOFFSET 0    /* word offset to find MSB */
+#define LOWOFFSET 1    /* word offset to find LSB */
+#define int32 long  /* a data type that has 32 bits */
+#else
+#ifdef _WIN32
+/* little-endian; most significant byte is at highest address */
+#define HIOFFSET 1
+#define LOWOFFSET 0
+#define int32 long
+#else
+#ifdef __FreeBSD__
+#include <machine/endian.h>
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define HIOFFSET 1
+#define LOWOFFSET 0
+#else
+#define HIOFFSET 0    /* word offset to find MSB */
+#define LOWOFFSET 1    /* word offset to find LSB */
+#endif /* BYTE_ORDER */
+#include <sys/types.h>
+#define int32 int32_t
+#endif
+#ifdef __linux__
+
+#include <endian.h>
+
+#if !defined(__BYTE_ORDER) || !defined(__LITTLE_ENDIAN)
+#error No byte order defined                                                    
+#endif
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define HIOFFSET 1
+#define LOWOFFSET 0
+#else
+#define HIOFFSET 0    /* word offset to find MSB */
+#define LOWOFFSET 1    /* word offset to find LSB */
+#endif /* __BYTE_ORDER */
+
+#include <sys/types.h>
+#define int32 int32_t
+
+#else
+#ifdef __APPLE__
+#define HIOFFSET 0    /* word offset to find MSB */
+#define LOWOFFSET 1    /* word offset to find LSB */
+#define int32 int  /* a data type that has 32 bits */
+
+#endif /* __APPLE__ */
+#endif /* __linux__ */
+#endif /* _WIN32 */
+#endif /* SGI */
+
+union tabfudge
+{
+    double tf_d;
+    int32 tf_i[2];
+};
+
+
+/* -------------------------- ssaw~ ------------------------------ */
+static t_class *ssaw_class, *scalarssaw_class;
+static float ssaw_array[1002];
+#define SAW_ARRAY_LEN 1002
+
+typedef struct _ssaw
+{
+    t_object x_obj;
+    //from phasor~:
+    double x_phase;
+    float x_conv;
+    float x_f;	    /* scalar frequency */
+    float x_band;	/* band limit (Hertz)*/
+} t_ssaw;
+
+static void *ssaw_new(t_floatarg f)
+{
+    t_ssaw *x = (t_ssaw *)pd_new(ssaw_class);
+    x->x_f = f;
+    inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1"));
+    x->x_phase = 0;
+    x->x_conv = 0;
+    x->x_band = 22000;
+    outlet_new(&x->x_obj, gensym("signal"));
+    return (x);
+}
+
+static t_int *ssaw_perform(t_int *w)
+{
+    t_ssaw *x = (t_ssaw *)(w[1]);
+    t_float *in = (t_float *)(w[2]);
+    t_float *out = (t_float *)(w[3]);
+    int i,n = (int)(w[4]);
+    double dphase = x->x_phase + UNITBIT32;
+    union tabfudge tf;
+    int normhipart;
+    float conv = x->x_conv;
+    float band=x->x_band*.33;
+    float *buf = ssaw_array;
+
+    tf.tf_d = UNITBIT32;
+    normhipart = tf.tf_i[HIOFFSET];
+    tf.tf_d = dphase;
+
+    for (i = 0; i < n; i++)
+        //while (n--)
+    {
+        float phase,band2,findex /*= *in++*/;
+        int index /*= findex*/;
+        float frac,  a,  b,  c,  d, cminusb, *fp;
+
+        tf.tf_i[HIOFFSET] = normhipart;
+        band2=abs(*in);
+        if(band2>999999) band2=999999;
+        else if(band2<1) band2=1;
+        band2=band/band2;
+        dphase += *in++ * conv;
+        /**out++*/
+        phase = (tf.tf_d - UNITBIT32)-0.5;
+        tf.tf_d = dphase;
+
+        findex=phase*band2;
+        if(findex>0.5) findex=0.5;
+        else if(findex<-0.5) findex=-0.5;
+
+        /*findex=findex*1000+501;
+        index=findex;*/
+        /*if (index < 1)
+            index = 1, frac = 0;
+        else if (index > maxindex)
+            index = maxindex, frac = 1;
+        else*/
+        frac = findex - index;
+        /*fp = buf + index;
+        a = fp[-1];
+        b = fp[0];
+        c = fp[1];
+        d = fp[2];
+        cminusb = c-b;
+        *out++ = 0.5+ phase - (
+        		 b + frac * ( cminusb - 0.1666667f * (1.-frac) * (
+        		(d - a - 3.0f * cminusb) * frac + (d + 2.0f*a - 3.0f*b)))
+        		);*/
+        *out++ = 0.5+ phase - buf[(int)(findex*1000+501)];
+    }
+
+    tf.tf_i[HIOFFSET] = normhipart;
+    x->x_phase = tf.tf_d - UNITBIT32;
+    return (w+5);
+}
+
+static void ssaw_dsp(t_ssaw *x, t_signal **sp)
+{
+    x->x_conv = 1./sp[0]->s_sr;
+    dsp_add(ssaw_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+static void ssaw_ft1(t_ssaw *x, t_float f)
+{
+    x->x_phase = f;
+}
+
+static void ssaw_initarray(void)
+{
+    int i;
+    float j;
+
+    for(i=0; i<1002; i++)
+    {
+        j=(i-1)*M_PI/1000.0; //period 2000 sample, 1 sample back phase
+        ssaw_array[i]= 0.57692*
+                       (-1*cos(j) + 0.333333*cos(j*3.0) -0.2* cos(j*5.0));
+    }
+}
+
+void ssaw_tilde_setup(void)
+{
+    ssaw_class = class_new(gensym("ssaw~"), (t_newmethod)ssaw_new, 0,
+                           sizeof(t_ssaw), 0, A_DEFFLOAT, 0);
+    CLASS_MAINSIGNALIN(ssaw_class, t_ssaw, x_f);
+    class_addmethod(ssaw_class, (t_method)ssaw_dsp, gensym("dsp"), 0);
+    class_addmethod(ssaw_class, (t_method)ssaw_ft1,
+                    gensym("ft1"), A_FLOAT, 0);
+    ssaw_initarray();
+
+}
+
diff --git a/tabdump2-help.pd b/tabdump2-help.pd
index b69458c..9bb0324 100644
--- a/tabdump2-help.pd
+++ b/tabdump2-help.pd
@@ -1,31 +1,39 @@
-#N canvas 21 53 496 358 10;
-#X obj 13 21 tabdump2;
-#X obj 187 37 tabdump;
-#X text 22 332 (c) Antoine Rousseau 2004;
-#X text 104 21 dump the contents of a table as a list;
-#X text 104 37 like zexy's;
-#X text 244 38 but with min/max dumping limits.;
-#N canvas 0 0 450 300 graph5 0;
-#X array \$0-array 10 float 0;
-#X coords 0 1 9 0 100 80 1;
-#X restore 330 71 graph;
-#X obj 17 132 s \$0-array;
-#X msg 17 112 0 0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9;
-#X obj 17 92 loadbang;
-#X obj 34 243 tabdump2 \$0-array;
-#X obj 34 269 l2s;
-#X symbolatom 34 293 0 0 0 0 - - -;
-#X obj 258 204 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
--1;
-#X msg 22 204 dump 0 5;
-#X msg 95 203 dump 5 10;
-#X text 18 177 dump N M: from N to (M-1);
-#X msg 174 203 dump 5 6;
-#X connect 8 0 7 0;
-#X connect 9 0 8 0;
-#X connect 10 0 11 0;
-#X connect 11 0 12 0;
-#X connect 13 0 10 0;
-#X connect 14 0 10 0;
-#X connect 15 0 10 0;
-#X connect 17 0 10 0;
+#N canvas 326 499 496 358 10;
+#X obj 13 21 tabdump2;
+#X text 22 332 (c) Antoine Rousseau 2004;
+#X text 104 21 dump the contents of a table as a list;
+#X text 218 35 but with min/max dumping limits.;
+#N canvas 0 50 450 300 (subpatch) 0;
+#X array \$0-array 10 float 0;
+#X coords 0 1 9 0 100 80 1;
+#X restore 330 71 graph;
+#X obj 17 132 s \$0-array;
+#X msg 17 112 0 0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9;
+#X obj 17 92 loadbang;
+#X obj 258 204 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 22 204 dump 0 5;
+#X msg 95 203 dump 5 10;
+#X text 18 177 dump N M: from N to (M-1);
+#X msg 174 203 dump 5 6;
+#N canvas 502 150 494 344 META 0;
+#X text 12 25 LICENSE GPL v2;
+#X text 12 105 AUTHOR Antoine Rousseau;
+#X text 12 125 HELP_PATCH_AUTHORS Antoine Rousseau. "pd meta" information
+added by Jonathan Wilkes for Pd version 0.42.;
+#X text 12 5 KEYWORDS control array;
+#X text 12 45 DESCRIPTION dump the contents of a table as a list;
+#X text 12 65 INLET_0 bang dump;
+#X text 12 85 OUTLET_0 list;
+#X restore 440 329 pd META;
+#X obj 34 243 tabdump2 \$0-array;
+#X obj 34 269 print;
+#X obj 139 35 zexy/tabdump;
+#X text 103 36 like;
+#X connect 6 0 5 0;
+#X connect 7 0 6 0;
+#X connect 8 0 14 0;
+#X connect 9 0 14 0;
+#X connect 10 0 14 0;
+#X connect 12 0 14 0;
+#X connect 14 0 15 0;
diff --git a/tabdump2.c b/tabdump2.c
index 98dac2c..6dc30f0 100644
--- a/tabdump2.c
+++ b/tabdump2.c
@@ -1,120 +1,120 @@
-/*
-Copyright (C) 2004 Antoine Rousseau 
-
-This library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation; either
-version 2.1 of the License, or (at your option) any later version.
-
-This library 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
-Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with this library; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  
-
-*/
-
-/*
-	tabdump2 -- from tabdump (from zexy) but with min/max dumping limits.
-*/
-
-#include <m_pd.h>
-
-static t_class *tabdump_class;
-
-typedef struct _tabdump
-{
-  t_object x_obj;
-  t_symbol *x_arrayname;
-} t_tabdump;
-
-static void tabdump_bang(t_tabdump *x, t_float findex)
-{
-  t_garray *A;
-  int npoints;
-  t_float *vec;
-
-  if (!(A = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
-    error("%s: no such array", x->x_arrayname->s_name);
-  else if (!garray_getfloatarray(A, &npoints, &vec))
-    error("%s: bad template for tabdump", x->x_arrayname->s_name);
-  else
-    {
-      int n;
-      t_atom *atombuf = (t_atom *)getbytes(sizeof(t_atom)*npoints);
-
-      for (n = 0; n < npoints; n++) SETFLOAT(&atombuf[n], vec[n]);
-      outlet_list(x->x_obj.ob_outlet, &s_list, npoints, atombuf);
-    }
-}
-
-
-static void tabdump_dump(t_tabdump *x, t_float min, t_float max)
-{
-  t_garray *A;
-  int npoints,nmin=(int)min,nmax=(int)max;
-  t_float *vec;
-
-  if (!(A = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
-    error("%s: no such array", x->x_arrayname->s_name);
-  else if (!garray_getfloatarray(A, &npoints, &vec))
-    error("%s: bad template for tabdump", x->x_arrayname->s_name);
-  else if ((min<0)||(max<=min)||(max>npoints)) 
-  	error("tabdump: bad arguments min=%d max=%d for %s (%d elements)",
-		nmin,nmax,x->x_arrayname->s_name,npoints);
-  else
-    {
-      int n;
-	  t_atom *atombuf;
-	  
-	  npoints=nmax-nmin;
-      atombuf = (t_atom *)getbytes(sizeof(t_atom)*npoints);
-
-      for (n = 0; n < npoints; n++) SETFLOAT(&atombuf[n], vec[n+nmin]);
-      outlet_list(x->x_obj.ob_outlet, &s_list, npoints, atombuf);
-    }
-}
-
-
-static void tabdump_set(t_tabdump *x, t_symbol *s)
-{
-  x->x_arrayname = s;
-}
-
-static void *tabdump_new(t_symbol *s)
-{
-  t_tabdump *x = (t_tabdump *)pd_new(tabdump_class);
-  x->x_arrayname = s;
-  outlet_new(&x->x_obj, &s_list);
-
-  return (x);
-}
-
-static void tabdump_helper(void)
-{
-  post("\n tabdump2 - object : dumps a table as a package of floats");
-  post("'set <table>'\t: read out another table\n"
-       "'bang'\t\t: dump the table\n"
-       "'dump <min> <max>'\t\t: dump the table from <min> to <max> (without <max>)\n"
-       "outlet\t\t: table-data as package of floats");
-  post("creation\t: \"tabdump2 <table>\"");
-
-}
-
-void tabdump2_setup(void)
-{
-  tabdump_class = class_new(gensym("tabdump2"), (t_newmethod)tabdump_new,
-			     0, sizeof(t_tabdump), 0, A_DEFSYM, 0);
-  class_addbang(tabdump_class, (t_method)tabdump_bang);
-  class_addmethod(tabdump_class, (t_method)tabdump_dump,gensym("dump"),
-  			A_FLOAT,A_FLOAT,0);
-  class_addmethod(tabdump_class, (t_method)tabdump_set, gensym("set"),
-		  A_SYMBOL, 0);
-
-  class_addmethod(tabdump_class, (t_method)tabdump_helper, gensym("help"), 0);
-
-}
-
+/*
+Copyright (C) 2004 Antoine Rousseau
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+*/
+
+/*
+	tabdump2 -- from tabdump (from zexy) but with min/max dumping limits.
+*/
+
+#include <m_pd.h>
+
+static t_class *tabdump_class;
+
+typedef struct _tabdump
+{
+    t_object x_obj;
+    t_symbol *x_arrayname;
+} t_tabdump;
+
+static void tabdump_bang(t_tabdump *x, t_float findex)
+{
+    t_garray *A;
+    int npoints;
+    t_word *vec;
+
+    if (!(A = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
+        error("%s: no such array", x->x_arrayname->s_name);
+    else if (!garray_getfloatwords(A, &npoints, &vec))
+        error("%s: bad template for tabdump", x->x_arrayname->s_name);
+    else
+    {
+        int n;
+        t_atom *atombuf = (t_atom *)getbytes(sizeof(t_atom)*npoints);
+
+        for (n = 0; n < npoints; n++) SETFLOAT(&atombuf[n], vec[n].w_float);
+        outlet_list(x->x_obj.ob_outlet, &s_list, npoints, atombuf);
+    }
+}
+
+
+static void tabdump_dump(t_tabdump *x, t_float min, t_float max)
+{
+    t_garray *A;
+    int npoints,nmin=(int)min,nmax=(int)max;
+    t_word *vec;
+
+    if (!(A = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
+        error("%s: no such array", x->x_arrayname->s_name);
+    else if (!garray_getfloatwords(A, &npoints, &vec))
+        error("%s: bad template for tabdump", x->x_arrayname->s_name);
+    else if ((min<0)||(max<=min)||(max>npoints))
+        error("tabdump: bad arguments min=%d max=%d for %s (%d elements)",
+              nmin,nmax,x->x_arrayname->s_name,npoints);
+    else
+    {
+        int n;
+        t_atom *atombuf;
+
+        npoints=nmax-nmin;
+        atombuf = (t_atom *)getbytes(sizeof(t_atom)*npoints);
+
+        for (n = 0; n < npoints; n++) SETFLOAT(&atombuf[n], vec[n+nmin].w_float);
+        outlet_list(x->x_obj.ob_outlet, &s_list, npoints, atombuf);
+    }
+}
+
+
+static void tabdump_set(t_tabdump *x, t_symbol *s)
+{
+    x->x_arrayname = s;
+}
+
+static void *tabdump_new(t_symbol *s)
+{
+    t_tabdump *x = (t_tabdump *)pd_new(tabdump_class);
+    x->x_arrayname = s;
+    outlet_new(&x->x_obj, &s_list);
+
+    return (x);
+}
+
+static void tabdump_helper(void)
+{
+    post("\n tabdump2 - object : dumps a table as a package of floats");
+    post("'set <table>'\t: read out another table\n"
+         "'bang'\t\t: dump the table\n"
+         "'dump <min> <max>'\t\t: dump the table from <min> to <max> (without <max>)\n"
+         "outlet\t\t: table-data as package of floats");
+    post("creation\t: \"tabdump2 <table>\"");
+
+}
+
+void tabdump2_setup(void)
+{
+    tabdump_class = class_new(gensym("tabdump2"), (t_newmethod)tabdump_new,
+                              0, sizeof(t_tabdump), 0, A_DEFSYM, 0);
+    class_addbang(tabdump_class, (t_method)tabdump_bang);
+    class_addmethod(tabdump_class, (t_method)tabdump_dump,gensym("dump"),
+                    A_FLOAT,A_FLOAT,0);
+    class_addmethod(tabdump_class, (t_method)tabdump_set, gensym("set"),
+                    A_SYMBOL, 0);
+
+    class_addmethod(tabdump_class, (t_method)tabdump_helper, gensym("help"), 0);
+
+}
+
diff --git a/tabenv-help.pd b/tabenv-help.pd
index cb719d0..bd58c60 100644
--- a/tabenv-help.pd
+++ b/tabenv-help.pd
@@ -1,25 +1,35 @@
-#N canvas 205 155 534 360 10;
-#X text 22 332 (c) Antoine Rousseau 2001;
-#X obj 21 19 tabenv;
-#X text 78 21 A envelope follower for table (not in real-time).;
-#X text 35 65 args: arrayname [computation_num_points [output_period]]
-;
-#X text 147 151 change the array;
-#X msg 64 181 reset;
-#X msg 64 152 set Array1;
-#X obj 64 255 tabenv Array0;
-#X floatatom 64 283 5 0 0;
-#X msg 64 209 0 44100;
-#X text 125 209 compute 1 sec from the beginning;
-#X text 126 181 reset the computation buffers;
-#X obj 258 86 env~;
-#X text 294 85 );
-#X text 217 86 (like;
-#X text 151 84 );
-#X text 47 86 (like;
-#X obj 90 86 tabplay~;
-#X text 79 38 (in fact it's a mix between tabplay and env~);
-#X connect 5 0 7 0;
-#X connect 6 0 7 0;
-#X connect 7 0 8 0;
-#X connect 9 0 7 0;
+#N canvas 1 88 534 360 10;
+#X text 22 332 (c) Antoine Rousseau 2001;
+#X obj 21 19 tabenv;
+#X text 78 21 A envelope follower for table (not in real-time).;
+#X text 35 65 args: arrayname [computation_num_points [output_period]]
+;
+#X text 147 151 change the array;
+#X msg 64 181 reset;
+#X msg 64 152 set Array1;
+#X obj 64 255 tabenv Array0;
+#X floatatom 64 283 5 0 0 0 - - -;
+#X msg 64 209 0 44100;
+#X text 125 209 compute 1 sec from the beginning;
+#X text 126 181 reset the computation buffers;
+#X obj 258 86 env~;
+#X text 294 85 );
+#X text 217 86 (like;
+#X text 151 84 );
+#X text 47 86 (like;
+#X obj 90 86 tabplay~;
+#X text 79 38 (in fact it's a mix between tabplay and env~);
+#N canvas 379 147 494 344 META 0;
+#X text 12 25 LICENSE GPL v2;
+#X text 12 105 AUTHOR Antoine Rousseau;
+#X text 12 125 HELP_PATCH_AUTHORS Antoine Rousseau. "pd meta" information
+added by Jonathan Wilkes for Pd version 0.42.;
+#X text 12 45 DESCRIPTION dump the contents of a table as a list;
+#X text 12 65 INLET_0 set reset list;
+#X text 12 85 OUTLET_0 float;
+#X text 12 5 KEYWORDS control array;
+#X restore 471 332 pd META;
+#X connect 5 0 7 0;
+#X connect 6 0 7 0;
+#X connect 7 0 8 0;
+#X connect 9 0 7 0;
diff --git a/tabenv.c b/tabenv.c
index 9b52fbe..7d13b0c 100644
--- a/tabenv.c
+++ b/tabenv.c
@@ -1,294 +1,195 @@
-/*
-Copyright (C) 2002 Antoine Rousseau 
-
-This library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation; either
-version 2.1 of the License, or (at your option) any later version.
-
-This library 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
-Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with this library; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  
-
-*/
-
-#include "m_pd.h"
-#include "math.h"
-
-
-/* ---------------- tabenv - table envelope computer. ----------------- */
-/*------- (in fact it's a mix between env~ and tabplay~)----------------*/
-
-#define MAXOVERLAP 10
-#define MAXVSTAKEN 64
-
-typedef struct tabenv
-{
-	/*env part*/
-    t_object x_obj; 	    	    /* header */
-    t_outlet *x_outlet;		    /* a "float" outlet */
-    t_clock *x_clock;		    /* a "clock" object */
-    float *x_buf;		    /* a Hanning window */
-    int x_phase;		    /* number of points since last output */
-    int x_period;		    /* requested period of output */
-    int x_realperiod;		    /* period rounded up to vecsize multiple */
-    int x_npoints;		    /* analysis window size in samples */
-    float x_result;		    /* result to output */
-    float x_sumbuf[MAXOVERLAP];	    /* summing buffer */
-	 float x_f;
-    
-	 /*tabplay part*/
-    int x_tabphase;
-    int x_nsampsintab;
-    int x_limit;
-    float *x_vec;
-    t_symbol *x_arrayname;
-} t_tabenv;
-
-t_class *tabenv_class;
-static void tabenv_tick(t_tabenv *x);
-
-static void *tabenv_new(t_symbol *s,t_floatarg fnpoints, t_floatarg fperiod)
-{
-    int npoints = fnpoints;
-    int period = fperiod;
-    t_tabenv *x;
-    float *buf;
-    int i;
-
-    if (npoints < 1) npoints = 1024;
-    if (period < 1) period = npoints/2;
-    if (period < npoints / MAXOVERLAP + 1)
-	period = npoints / MAXOVERLAP + 1;
-    if (!(buf = getbytes(sizeof(float) * (npoints + MAXVSTAKEN))))
-    {
-	error("env: couldn't allocate buffer");
-	return (0);
-    }
-    x = (t_tabenv *)pd_new(tabenv_class);
-    x->x_buf = buf;
-    x->x_npoints = npoints;
-    x->x_phase = 0;
-    x->x_period = period;
-    for (i = 0; i < MAXOVERLAP; i++) x->x_sumbuf[i] = 0;
-    for (i = 0; i < npoints; i++)
-	buf[i] = (1. - cos((2 * 3.14159 * i) / npoints))/npoints;
-    for (; i < npoints+MAXVSTAKEN; i++) buf[i] = 0;
-    x->x_clock = clock_new(x, (t_method)tabenv_tick);
-    x->x_outlet = outlet_new(&x->x_obj, gensym("float"));
-    x->x_f = 0;
-
-	/* tabplay */
-    x->x_tabphase = 0x7fffffff;
-    x->x_limit = 0;
-    x->x_arrayname = s;
- 
-    return (x);
-}
-
-static t_int *sigenv_perform(t_int *w)
-{
-    t_tabenv *x = (t_tabenv *)(w[1]);
-    t_float *in = (t_float *)(w[2]);
-    int n = (int)(w[3]);
-    int count;
-    float *sump; 
-    in += n;
-    for (count = x->x_phase, sump = x->x_sumbuf;
-	count < x->x_npoints; count += x->x_realperiod, sump++)
-    {
-	float *hp = x->x_buf + count;
-	float *fp = in;
-	float sum = *sump;
-	int i;
-	
-	for (i = 0; i < n; i++)
-	{
-	    fp--;
-	    sum += *hp++ * (*fp * *fp);
-	}
-	*sump = sum;
-    }
-    sump[0] = 0;
-    x->x_phase -= n;
-    if (x->x_phase < 0)
-    {
-	x->x_result = x->x_sumbuf[0];
-	for (count = x->x_realperiod, sump = x->x_sumbuf;
-	    count < x->x_npoints; count += x->x_realperiod, sump++)
-		sump[0] = sump[1];
-	sump[0] = 0;
-	x->x_phase = x->x_realperiod - n;
-	clock_delay(x->x_clock, 0L);
-    }
-    return (w+4);
-}
-
-static t_int *tabplay_tilde_perform(t_int *w)
-{
-    t_tabenv *x = (t_tabenv *)(w[1]);
-    t_float *out = (t_float *)(w[2]), *fp;
-    int n = (int)(w[3]), phase = x->x_phase,
-    	endphase = (x->x_nsampsintab < x->x_limit ?
-	    x->x_nsampsintab : x->x_limit), nxfer, n3;
-    if (!x->x_vec || phase >= endphase)
-    	goto zero;
-    
-    nxfer = endphase - phase;
-    fp = x->x_vec + phase;
-    if (nxfer > n)
-    	nxfer = n;
-    n3 = n - nxfer;
-    phase += nxfer;
-    while (nxfer--)
-    	*out++ = *fp++;
-    if (phase >= endphase)
-    {
-    	clock_delay(x->x_clock, 0);
-    	x->x_phase = 0x7fffffff;
-	while (n3--)
-	    *out++ = 0;
-    }
-    else x->x_phase = phase;
-    
-    return (w+4);
-zero:
-    while (n--) *out++ = 0;
-    return (w+4);
-}
-
-
-static void tabenv_perform_64(t_tabenv *x,t_float *in)
-{
-    int n = 64;
-    int count;
-    float *sump; 
-    in += n;
-    for (count = x->x_phase, sump = x->x_sumbuf;
-	count < x->x_npoints; count += x->x_realperiod, sump++)
-    {
-	float *hp = x->x_buf + count;
-	float *fp = in;
-	float sum = *sump;
-	int i;
-	
-	for (i = 0; i < n; i++)
-	{
-	    fp--;
-	    sum += *hp++ * (*fp * *fp);
-	}
-	*sump = sum;
-    }
-    sump[0] = 0;
-    x->x_phase -= n;
-    if (x->x_phase < 0)
-    {
-	x->x_result = x->x_sumbuf[0];
-	for (count = x->x_realperiod, sump = x->x_sumbuf;
-	    count < x->x_npoints; count += x->x_realperiod, sump++)
-		sump[0] = sump[1];
-	sump[0] = 0;
-	x->x_phase = x->x_realperiod - n;
-	/*clock_delay(x->x_clock, 0L);*/
-	outlet_float(x->x_outlet, powtodb(x->x_result));
-    }
-}
-
-
-static void tabenv_set(t_tabenv *x, t_symbol *s)
-{
-    t_garray *a;
-
-    x->x_arrayname = s;
-    if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
-    {
-    	if (*s->s_name) pd_error(x, "tabenv: %s: no such array",
-    	    x->x_arrayname->s_name);
-    	x->x_vec = 0;
-    }
-    else if (!garray_getfloatarray(a, &x->x_nsampsintab, &x->x_vec))
-    {
-    	error("%s: bad template for tabenv", x->x_arrayname->s_name);
-    	x->x_vec = 0;
-    }
-    else garray_usedindsp(a);
-}
-
-static void sigenv_dsp(t_tabenv *x, t_signal **sp)
-{
-    if (x->x_period % sp[0]->s_n) x->x_realperiod =
-	x->x_period + sp[0]->s_n - (x->x_period % sp[0]->s_n);
-    else x->x_realperiod = x->x_period;
-    dsp_add(sigenv_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
-    if (sp[0]->s_n > MAXVSTAKEN) bug("sigenv_dsp");
-}
-
-static void tabenv_list(t_tabenv *x, t_symbol *s,
-    int argc, t_atom *argv)
-{
-    long start = atom_getfloatarg(0, argc, argv);
-    long length = atom_getfloatarg(1, argc, argv);
-	 float *limitp,*p;
-	 int i;
-
-	tabenv_set(x, x->x_arrayname); 
-
-   if (start < 0) start = 0;
-    if (length <= 0)
-    	x->x_limit = 0x7fffffff;
-    else
-    	x->x_limit = start + length;
-    x->x_tabphase = start;
-
-	 if(length <= 0) length = x->x_nsampsintab - 1;
-	 if(start >= x->x_nsampsintab) start = x->x_nsampsintab - 1;
-	 if((start + length) >= x->x_nsampsintab) 
-	 	length = x->x_nsampsintab - 1 - start;
-	
-	 limitp = x->x_vec + start + length - 63;
-	 /*limitp = x->x_vec + 2048;*/
-    /*if (x->x_period % length) x->x_realperiod =
-	x->x_period + length - (x->x_period % length);
-    else*/ x->x_realperiod = x->x_period;
-
-	 for(p = x->x_vec + start; p < limitp ; p += 64)
-	 tabenv_perform_64( x , p );
-}
-
-static void tabenv_reset(t_tabenv *x)
-{
-    int i;
-	 x->x_phase = 0;
-    for (i = 0; i < MAXOVERLAP; i++) x->x_sumbuf[i] = 0;
-}
-
-static void tabenv_tick(t_tabenv *x)	/* callback function for the env clock */
-{
-    outlet_float(x->x_outlet, powtodb(x->x_result));
-}
-
-static void tabenv_ff(t_tabenv *x)		/* cleanup on free */
-{
-    clock_free(x->x_clock);
-    freebytes(x->x_buf, (x->x_npoints + MAXVSTAKEN) * sizeof(float));
-}
-
-
-void tabenv_setup(void )
-{
-    tabenv_class = class_new(gensym("tabenv"), (t_newmethod)tabenv_new,
-    	(t_method)tabenv_ff, sizeof(t_tabenv), 0, A_DEFSYM, A_DEFFLOAT, A_DEFFLOAT, 0);
-    CLASS_MAINSIGNALIN(tabenv_class, t_tabenv, x_f);
-    class_addmethod(tabenv_class, (t_method)tabenv_reset,
-    	gensym("reset"), 0);
-    class_addmethod(tabenv_class, (t_method)tabenv_set,
-    	gensym("set"), A_DEFSYM, 0);
-    class_addlist(tabenv_class, tabenv_list);
-
-}
-
+/*
+Copyright (C) 2002 Antoine Rousseau
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+*/
+
+#include "m_pd.h"
+#include "math.h"
+
+
+/* ---------------- tabenv - table envelope computer. ----------------- */
+/*------- (in fact it's a mix between env~ and tabplay~)----------------*/
+
+#define MAXOVERLAP 10
+#define MAXVSTAKEN 64
+
+typedef struct tabenv
+{
+    /*env part*/
+    t_object x_obj; 	    	    /* header */
+    t_outlet *x_outlet;		    /* a "float" outlet */
+    float *x_buf;		    /* a Hanning window */
+    int x_phase;		    /* number of points since last output */
+    int x_period;		    /* requested period of output */
+    int x_realperiod;		    /* period rounded up to vecsize multiple */
+    int x_npoints;		    /* analysis window size in samples */
+    float x_result;		    /* result to output */
+    float x_sumbuf[MAXOVERLAP];	    /* summing buffer */
+
+    /*tabplay part*/
+    int x_tabphase;
+    int x_nsampsintab;
+    int x_limit;
+    t_word *x_vec;
+    t_symbol *x_arrayname;
+} t_tabenv;
+
+t_class *tabenv_class;
+
+static void *tabenv_new(t_symbol *s,t_floatarg fnpoints, t_floatarg fperiod)
+{
+    int npoints = fnpoints;
+    int period = fperiod;
+    t_tabenv *x;
+    float *buf;
+    int i;
+
+    if (npoints < 1) npoints = 1024;
+    if (period < 1) period = npoints/2;
+    if (period < npoints / MAXOVERLAP + 1)
+        period = npoints / MAXOVERLAP + 1;
+    if (!(buf = getbytes(sizeof(float) * (npoints + MAXVSTAKEN))))
+    {
+        error("env: couldn't allocate buffer");
+        return (0);
+    }
+    x = (t_tabenv *)pd_new(tabenv_class);
+    x->x_buf = buf;
+    x->x_npoints = npoints;
+    x->x_phase = 0;
+    x->x_period = period;
+    for (i = 0; i < MAXOVERLAP; i++) x->x_sumbuf[i] = 0;
+    for (i = 0; i < npoints; i++)
+        buf[i] = (1. - cos((2 * 3.14159 * i) / npoints))/npoints;
+    for (; i < npoints+MAXVSTAKEN; i++) buf[i] = 0;
+    x->x_outlet = outlet_new(&x->x_obj, gensym("float"));
+
+    /* tabplay */
+    x->x_tabphase = 0x7fffffff;
+    x->x_limit = 0;
+    x->x_arrayname = s;
+
+    return (x);
+}
+
+static void tabenv_perform_64(t_tabenv *x,t_word *in)
+{
+    int n = 64;
+    int count;
+    float *sump;
+    in += n;
+    for (count = x->x_phase, sump = x->x_sumbuf;
+            count < x->x_npoints; count += x->x_realperiod, sump++)
+    {
+        float *hp = x->x_buf + count;
+        t_word *fp = in;
+        float sum = *sump;
+        int i;
+
+        for (i = 0; i < n; i++)
+        {
+            fp--;
+            sum += *hp++ * ((*fp).w_float * (*fp).w_float);
+        }
+        *sump = sum;
+    }
+    sump[0] = 0;
+    x->x_phase -= n;
+    if (x->x_phase < 0)
+    {
+        x->x_result = x->x_sumbuf[0];
+        for (count = x->x_realperiod, sump = x->x_sumbuf;
+                count < x->x_npoints; count += x->x_realperiod, sump++)
+            sump[0] = sump[1];
+        sump[0] = 0;
+        x->x_phase = x->x_realperiod - n;
+        outlet_float(x->x_outlet, powtodb(x->x_result));
+    }
+}
+
+
+static void tabenv_set(t_tabenv *x, t_symbol *s)
+{
+    t_garray *a;
+
+    x->x_arrayname = s;
+    if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
+    {
+        if (*s->s_name) pd_error(x, "tabenv: %s: no such array",
+                                     x->x_arrayname->s_name);
+        x->x_vec = 0;
+    }
+    else if (!garray_getfloatwords(a, &x->x_nsampsintab, &x->x_vec))
+    {
+        error("%s: bad template for tabenv", x->x_arrayname->s_name);
+        x->x_vec = 0;
+    }
+}
+
+static void tabenv_list(t_tabenv *x, t_symbol *s,
+                        int argc, t_atom *argv)
+{
+    long start = atom_getfloatarg(0, argc, argv);
+    long length = atom_getfloatarg(1, argc, argv);
+    t_word *limitp, *p;
+
+    tabenv_set(x, x->x_arrayname);
+
+    if (start < 0) start = 0;
+    if (length <= 0)
+        x->x_limit = 0x7fffffff;
+    else
+        x->x_limit = start + length;
+    x->x_tabphase = start;
+
+    if(length <= 0) length = x->x_nsampsintab - 1;
+    if(start >= x->x_nsampsintab) start = x->x_nsampsintab - 1;
+    if((start + length) >= x->x_nsampsintab)
+        length = x->x_nsampsintab - 1 - start;
+
+    limitp = x->x_vec + start + length - 63;
+    x->x_realperiod = x->x_period;
+
+    for(p = x->x_vec + start; p < limitp ; p += 64)
+        tabenv_perform_64( x , p );
+}
+
+static void tabenv_reset(t_tabenv *x)
+{
+    int i;
+    x->x_phase = 0;
+    for (i = 0; i < MAXOVERLAP; i++) x->x_sumbuf[i] = 0;
+}
+
+static void tabenv_ff(t_tabenv *x)		/* cleanup on free */
+{
+    freebytes(x->x_buf, (x->x_npoints + MAXVSTAKEN) * sizeof(float));
+}
+
+
+void tabenv_setup(void )
+{
+    tabenv_class = class_new(gensym("tabenv"), (t_newmethod)tabenv_new,
+                             (t_method)tabenv_ff, sizeof(t_tabenv), 0, A_DEFSYM, A_DEFFLOAT, A_DEFFLOAT, 0);
+    class_addmethod(tabenv_class, (t_method)tabenv_reset,
+                    gensym("reset"), 0);
+    class_addmethod(tabenv_class, (t_method)tabenv_set,
+                    gensym("set"), A_DEFSYM, 0);
+    class_addlist(tabenv_class, tabenv_list);
+
+}
+
diff --git a/tabreadl-help.pd b/tabreadl-help.pd
index feebabe..42d476f 100644
--- a/tabreadl-help.pd
+++ b/tabreadl-help.pd
@@ -1,26 +1,36 @@
-#N canvas 502 181 672 415 10;
-#X obj 10 11 tabreadl;
-#X text 22 332 (c) Antoine Rousseau 2004;
-#X floatatom 15 173 0 0 0;
-#X floatatom 15 278 0 0 0;
-#N canvas 0 0 450 300 graph1 0;
-#X array \$0-array 10 float 0;
-#X coords 0 0 10 10 250 200 1;
-#X restore 362 179 graph;
-#X text 60 276 output = array99[index];
-#X text 34 50 click here to initialize;
-#X text 159 236 creation argument;
-#X text 155 254 gives array name;
-#X text 137 204 change array name;
-#X msg 25 204 set \$0-array99;
-#X msg 33 65 resize 10 \, bounds 0 0 10 10 \, xlabel -0.5 0 1 2 3 4
-5 6 7 8 9 10 \, ylabel -1 0 1 2 3 4 5 6 7 8 9 10 \, 0 1 4 2 8 5 6 1
-4 2 8;
-#X obj 34 139 s \$0-array;
-#X text 110 8 - linear interpolating read from a table;
-#X text 46 174 index(float);
-#X obj 15 245 tabreadl \$0-array;
-#X connect 2 0 15 0;
-#X connect 10 0 15 0;
-#X connect 11 0 12 0;
-#X connect 15 0 3 0;
+#N canvas 0 31 650 395 10;
+#X obj 10 11 tabreadl;
+#X text 22 332 (c) Antoine Rousseau 2004;
+#X floatatom 15 173 0 0 0 0 - - -;
+#X floatatom 15 278 0 0 0 0 - - -;
+#N canvas 0 0 450 300 (subpatch) 0;
+#X array \$0-array 10 float 0;
+#X coords 0 0 10 10 250 200 1;
+#X restore 362 139 graph;
+#X text 60 276 output = array99[index];
+#X text 34 50 click here to initialize;
+#X text 159 236 creation argument;
+#X text 155 254 gives array name;
+#X text 137 204 change array name;
+#X msg 25 204 set \$0-array99;
+#X msg 33 65 resize 10 \, bounds 0 0 10 10 \, xlabel -0.5 0 1 2 3 4
+5 6 7 8 9 10 \, ylabel -1 0 1 2 3 4 5 6 7 8 9 10 \, 0 1 4 2 8 5 6 1
+4 2 8;
+#X obj 34 139 s \$0-array;
+#X text 110 8 - linear interpolating read from a table;
+#X text 46 174 index(float);
+#X obj 15 245 tabreadl \$0-array;
+#N canvas 502 150 494 344 META 0;
+#X text 12 25 LICENSE GPL v2;
+#X text 12 105 AUTHOR Antoine Rousseau;
+#X text 12 125 HELP_PATCH_AUTHORS Antoine Rousseau. "pd meta" information
+added by Jonathan Wilkes for Pd version 0.42.;
+#X text 12 85 OUTLET_0 float;
+#X text 12 45 DESCRIPTION linear interpolating read from a table;
+#X text 12 5 KEYWORDS control array;
+#X text 12 65 INLET_0 float set;
+#X restore 592 367 pd META;
+#X connect 2 0 15 0;
+#X connect 10 0 15 0;
+#X connect 11 0 12 0;
+#X connect 15 0 3 0;
diff --git a/tabreadl.c b/tabreadl.c
index e669bd8..36eb527 100644
--- a/tabreadl.c
+++ b/tabreadl.c
@@ -1,84 +1,85 @@
-/*
-Copyright (C) 2002 Antoine Rousseau 
-
-This library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation; either
-version 2.1 of the License, or (at your option) any later version.
-
-This library 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
-Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with this library; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  
-
-*/
-
-#include "m_pd.h"
-#include "math.h"
-
-/* ---------- tabreadl: control, linear interpolating ------------------------ */
-
-static t_class *tabreadl_class;
-
-typedef struct _tabreadl
-{
-    t_object x_obj;
-    t_symbol *x_arrayname;
-} t_tabreadl;
-
-static void tabreadl_float(t_tabreadl *x, t_float f)
-{
-    t_garray *a;
-    int npoints;
-    t_float *vec;
-
-    if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
-    	error("%s: no such array", x->x_arrayname->s_name);
-    else if (!garray_getfloatarray(a, &npoints, &vec))
-    	error("%s: bad template for tabreadl", x->x_arrayname->s_name);
-    else
-    {
-    	int n ;
-		float r,v;
-
-    	if (f < 0) f = 0;
-    	else if (f >= npoints) f = npoints - 1;
-		n=f;
-		if(npoints>1){
-			r=f-n;
-			v=vec[n]*(1-r)+vec[n+1]*r;
-			outlet_float(x->x_obj.ob_outlet, v );
-		}
-    	else 
-			outlet_float(x->x_obj.ob_outlet, (npoints ? vec[n] : 0));
-    }
-}
-
-static void tabreadl_set(t_tabreadl *x, t_symbol *s)
-{
-    x->x_arrayname = s;
-}
-
-static void *tabreadl_new(t_symbol *s)
-{
-    t_tabreadl *x = (t_tabreadl *)pd_new(tabreadl_class);
-    x->x_arrayname = s;
-    outlet_new(&x->x_obj, &s_float);
-    return (x);
-}
-
-void tabreadl_setup(void)
-{
-    tabreadl_class = class_new(gensym("tabreadl"), (t_newmethod)tabreadl_new,
-    	0, sizeof(t_tabreadl), 0, A_DEFSYM, 0);
-    class_addfloat(tabreadl_class, (t_method)tabreadl_float);
-    class_addmethod(tabreadl_class, (t_method)tabreadl_set, gensym("set"),
-    	A_SYMBOL, 0);
-
-}
-
-
+/*
+Copyright (C) 2002 Antoine Rousseau
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+*/
+
+#include "m_pd.h"
+#include "math.h"
+
+/* ---------- tabreadl: control, linear interpolating ------------------------ */
+
+static t_class *tabreadl_class;
+
+typedef struct _tabreadl
+{
+    t_object x_obj;
+    t_symbol *x_arrayname;
+} t_tabreadl;
+
+static void tabreadl_float(t_tabreadl *x, t_float f)
+{
+    t_garray *a;
+    int npoints;
+    t_word *vec;
+
+    if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
+        error("%s: no such array", x->x_arrayname->s_name);
+    else if (!garray_getfloatwords(a, &npoints, &vec))
+        error("%s: bad template for tabreadl", x->x_arrayname->s_name);
+    else
+    {
+        int n ;
+        float r,v;
+
+        if (f < 0) f = 0;
+        else if (f >= npoints) f = npoints - 1;
+        n=f;
+        if(npoints>1)
+        {
+            r=f-n;
+            v=vec[n].w_float*(1-r)+vec[n+1].w_float*r;
+            outlet_float(x->x_obj.ob_outlet, v );
+        }
+        else
+            outlet_float(x->x_obj.ob_outlet, (npoints ? vec[n].w_float : 0));
+    }
+}
+
+static void tabreadl_set(t_tabreadl *x, t_symbol *s)
+{
+    x->x_arrayname = s;
+}
+
+static void *tabreadl_new(t_symbol *s)
+{
+    t_tabreadl *x = (t_tabreadl *)pd_new(tabreadl_class);
+    x->x_arrayname = s;
+    outlet_new(&x->x_obj, &s_float);
+    return (x);
+}
+
+void tabreadl_setup(void)
+{
+    tabreadl_class = class_new(gensym("tabreadl"), (t_newmethod)tabreadl_new,
+                               0, sizeof(t_tabreadl), 0, A_DEFSYM, 0);
+    class_addfloat(tabreadl_class, (t_method)tabreadl_float);
+    class_addmethod(tabreadl_class, (t_method)tabreadl_set, gensym("set"),
+                    A_SYMBOL, 0);
+
+}
+
+
diff --git a/tabsort-help.pd b/tabsort-help.pd
index 805f12a..bb2dd99 100644
--- a/tabsort-help.pd
+++ b/tabsort-help.pd
@@ -1,32 +1,43 @@
-#N canvas 118 208 534 360 10;
-#X text 22 332 (c) Antoine Rousseau 2001;
-#X floatatom 39 303 5 0 0 0 - - -;
-#X obj 21 19 tabsort;
-#X text 20 58 args: source_table dest_table;
-#N canvas 0 0 450 300 graph29 0;
-#X array source 10 float 1;
-#A 0 -0.0571429 -0.985715 -0.942858 -0.857143 -0.757143 -0.542857 -0.171429
-0.528571 0.842858 0.914287;
-#X coords 0 1 9 -1 200 140 1;
-#X restore 51 92 graph;
-#N canvas 0 0 450 300 graph29 0;
-#X array dest 10 float 1;
-#A 0 9 8 7 0 6 5 4 3 2 1;
-#X coords 0 10 9 0 200 140 1;
-#X restore 304 89 graph;
-#X obj 39 282 tabsort source dest;
-#X msg 39 262 10;
-#X text 79 12 write to dest_table the indices of source_table's elements
-sorted by decreasing order (biggest first);
-#X text 38 248 sort the n first elements;
-#X obj 304 264 tabread dest;
-#X obj 304 285 tabread source;
-#X floatatom 304 246 5 0 0 0 - - -;
-#X floatatom 304 305 5 0 0 0 - - -;
-#X text 347 244 try it!;
-#X text 300 321 it should decrease with input;
-#X connect 6 0 1 0;
-#X connect 7 0 6 0;
-#X connect 10 0 11 0;
-#X connect 11 0 13 0;
-#X connect 12 0 10 0;
+#N canvas 396 66 534 403 10;
+#X text 22 332 (c) Antoine Rousseau 2001;
+#X floatatom 39 303 5 0 0 0 - - -;
+#X obj 21 19 tabsort;
+#X text 20 58 args: source_table dest_table;
+#N canvas 0 0 450 300 (subpatch) 0;
+#X array source 10 float 1;
+#A 0 -0.0571429 -0.985715 -0.942858 -0.857143 -0.757143 -0.542857 -0.171429
+0.528571 0.842858 0.914287;
+#X coords 0 1 9 -1 200 140 1;
+#X restore 51 92 graph;
+#N canvas 0 0 450 300 (subpatch) 0;
+#X array dest 10 float 1;
+#A 0 9 8 7 0 6 5 4 3 2 1;
+#X coords 0 10 9 0 200 140 1;
+#X restore 304 89 graph;
+#X obj 39 282 tabsort source dest;
+#X msg 39 262 10;
+#X text 79 12 write to dest_table the indices of source_table's elements
+sorted by decreasing order (biggest first);
+#X text 38 248 sort the n first elements;
+#X obj 304 264 tabread dest;
+#X obj 304 285 tabread source;
+#X floatatom 304 246 5 0 9 0 - - -;
+#X floatatom 304 305 5 0 0 0 - - -;
+#X text 347 244 try it!;
+#X text 300 321 it should decrease with input;
+#N canvas 572 197 494 344 META 0;
+#X text 12 25 LICENSE GPL v2;
+#X text 12 115 AUTHOR Antoine Rousseau;
+#X text 12 135 HELP_PATCH_AUTHORS Antoine Rousseau. "pd meta" information
+added by Jonathan Wilkes for Pd version 0.42.;
+#X text 12 95 OUTLET_0 float;
+#X text 12 5 KEYWORDS control array;
+#X text 12 75 INLET_0 float;
+#X text 12 45 DESCRIPTION write to dest_table the indices of source_table's
+elements sorted by decreasing order;
+#X restore 476 370 pd META;
+#X connect 6 0 1 0;
+#X connect 7 0 6 0;
+#X connect 10 0 11 0;
+#X connect 11 0 13 0;
+#X connect 12 0 10 0;
diff --git a/tabsort.c b/tabsort.c
index ec8fcf0..3d37480 100644
--- a/tabsort.c
+++ b/tabsort.c
@@ -1,124 +1,125 @@
-/*
-Copyright (C) 2002 Antoine Rousseau 
-
-This library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation; either
-version 2.1 of the License, or (at your option) any later version.
-
-This library 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
-Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with this library; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  
-
-*/
-
-#include "m_pd.h"
-#include "math.h"
-
-
-/* ---------------- tabsort - sort a table to a table ----------------- */
-
-
-typedef struct tabsort
-{
-	/*env part*/
-    t_object x_obj; 	    	    /* header */
-    t_symbol *x_arrayname1;
-    t_symbol *x_arrayname2;
-} t_tabsort;
-
-t_class *tabsort_class;
-
-static void *tabsort_new(t_symbol *tab1,t_symbol *tab2)
-{
-    t_tabsort *x;
-    x = (t_tabsort *)pd_new(tabsort_class);
-
-    x->x_arrayname1 = tab1;
-    x->x_arrayname2 = tab2;
-    outlet_new((t_object*)x, &s_bang);
-
-    return (x);
-}
-
-static void tabsort_set1(t_tabsort *x, t_symbol *s)
-{
-	x->x_arrayname1 = s;
-}
-static void tabsort_set2(t_tabsort *x, t_symbol *s)
-{
-	x->x_arrayname2 = s;
-}
-
-static void tabsort_float(t_tabsort *x, t_floatarg n)
-{
-	t_garray *a;
-	int n1,n2,i,j;
-	float *vec1,*vec2,tmp;
-
-    if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname1, garray_class)))
-    {
-    	if (*x->x_arrayname1->s_name) pd_error(x, "tabsort: %s: no such array",
-    	    x->x_arrayname1->s_name);
-    	return;
-    }
-    else if (!garray_getfloatarray(a, &n1, &vec1))
-    {
-    	error("%s: bad template for tabsort", x->x_arrayname1->s_name);
-    	return;
-    }
-
-    if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname2, garray_class)))
-    {
-    	if (*x->x_arrayname2->s_name) pd_error(x, "tabsort: %s: no such array",
-    	    x->x_arrayname2->s_name);
-    	return;
-    }
-    else if (!garray_getfloatarray(a, &n2, &vec2))
-    {
-    	error("%s: bad template for tabsort", x->x_arrayname2->s_name);
-	return;
-    }
-
-	if(n>n1) n=n1;
-	if(n>n2) n=n2;
-
-
-	for(i=0;i<n;vec2[i]=i++);
-
-	for(i=0;i<n-1;i++)
-	for(j=n-1;j>i;j--)
-	if(vec1[(int)vec2[j-1]]<vec1[(int)vec2[j]])
-	{
-		tmp=vec2[j];
-		vec2[j]=vec2[j-1];
-		vec2[j-1]=tmp;
-	}
-
-	garray_redraw(a);
-	outlet_bang(((t_object *)x)->ob_outlet);
-}
-
-
-static void tabsort_ff(t_tabsort *x)		/* cleanup on free */
-{
-}
-
-
-void tabsort_setup(void )
-{
-    tabsort_class = class_new(gensym("tabsort"), (t_newmethod)tabsort_new,
-    	(t_method)tabsort_ff, sizeof(t_tabsort), 0, A_DEFSYM, A_DEFSYM, 0);
-    class_addmethod(tabsort_class, (t_method)tabsort_set1,
-    	gensym("set1"), A_DEFSYM, 0);
-    class_addmethod(tabsort_class, (t_method)tabsort_set2,
-    	gensym("set2"), A_DEFSYM, 0);
-    class_addfloat(tabsort_class, tabsort_float);
-
-}
-
+/*
+Copyright (C) 2002 Antoine Rousseau
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+*/
+
+#include "m_pd.h"
+#include "math.h"
+
+
+/* ---------------- tabsort - sort a table to a table ----------------- */
+
+
+typedef struct tabsort
+{
+    /*env part*/
+    t_object x_obj; 	    	    /* header */
+    t_symbol *x_arrayname1;
+    t_symbol *x_arrayname2;
+} t_tabsort;
+
+t_class *tabsort_class;
+
+static void *tabsort_new(t_symbol *tab1,t_symbol *tab2)
+{
+    t_tabsort *x;
+    x = (t_tabsort *)pd_new(tabsort_class);
+
+    x->x_arrayname1 = tab1;
+    x->x_arrayname2 = tab2;
+    outlet_new((t_object *)x, &s_bang);
+
+    return (x);
+}
+
+static void tabsort_set1(t_tabsort *x, t_symbol *s)
+{
+    x->x_arrayname1 = s;
+}
+static void tabsort_set2(t_tabsort *x, t_symbol *s)
+{
+    x->x_arrayname2 = s;
+}
+
+static void tabsort_float(t_tabsort *x, t_floatarg n)
+{
+    t_garray *a;
+    int n1,n2,i,j;
+    t_word *vec1,*vec2;
+    t_float tmp;
+
+    if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname1, garray_class)))
+    {
+        if (*x->x_arrayname1->s_name) pd_error(x, "tabsort: %s: no such array",
+                                                   x->x_arrayname1->s_name);
+        return;
+    }
+    else if (!garray_getfloatwords(a, &n1, &vec1))
+    {
+        error("%s: bad template for tabsort", x->x_arrayname1->s_name);
+        return;
+    }
+
+    if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname2, garray_class)))
+    {
+        if (*x->x_arrayname2->s_name) pd_error(x, "tabsort: %s: no such array",
+                                                   x->x_arrayname2->s_name);
+        return;
+    }
+    else if (!garray_getfloatwords(a, &n2, &vec2))
+    {
+        error("%s: bad template for tabsort", x->x_arrayname2->s_name);
+        return;
+    }
+
+    if(n>n1) n=n1;
+    if(n>n2) n=n2;
+
+
+    for(i=0; i<n; vec2[i].w_float=i++);
+
+    for(i=0; i<n-1; i++)
+        for(j=n-1; j>i; j--)
+            if(vec1[(int)vec2[j-1].w_float].w_float<vec1[(int)vec2[j].w_float].w_float)
+            {
+                tmp=vec2[j].w_float;
+                vec2[j].w_float=vec2[j-1].w_float;
+                vec2[j-1].w_float=tmp;
+            }
+
+    garray_redraw(a);
+    outlet_bang(((t_object *)x)->ob_outlet);
+}
+
+
+static void tabsort_ff(t_tabsort *x)		/* cleanup on free */
+{
+}
+
+
+void tabsort_setup(void )
+{
+    tabsort_class = class_new(gensym("tabsort"), (t_newmethod)tabsort_new,
+                              (t_method)tabsort_ff, sizeof(t_tabsort), 0, A_DEFSYM, A_DEFSYM, 0);
+    class_addmethod(tabsort_class, (t_method)tabsort_set1,
+                    gensym("set1"), A_DEFSYM, 0);
+    class_addmethod(tabsort_class, (t_method)tabsort_set2,
+                    gensym("set2"), A_DEFSYM, 0);
+    class_addfloat(tabsort_class, tabsort_float);
+
+}
+
diff --git a/tabsort2-help.pd b/tabsort2-help.pd
index 4f4e29a..295ccda 100644
--- a/tabsort2-help.pd
+++ b/tabsort2-help.pd
@@ -1,84 +1,94 @@
-#N canvas 133 15 811 538 10;
-#X floatatom 62 381 5 0 0 0 - - -;
-#N canvas 0 0 450 300 graph29 0;
-#X array source1 100 float 1;
-#A 0 -0.0428565 -0.0571422 0.085715 0.228572 0.442858 0.657144 0.871429
-1.08572 1.22857 1.51429 1.72857 1.94286 2.22857 2.37143 2.58571 2.72857
-2.87143 2.94286 3.15714 3.3 3.3 3.44286 3.58571 3.65714 3.72857 3.8
-3.94286 4.01429 4.08571 4.22857 4.3 4.13929 3.97857 3.81786 3.51429
-3.22857 2.8 2.37143 2.3 2.3 2.3 2.37143 2.44286 2.51429 2.51429 2.58572
-2.55 2.37143 2.22857 1.94286 1.72857 1.58572 1.44286 1.44286 1.37144
-1.37144 1.37144 1.44286 1.44286 1.44286 1.44286 1.51429 1.51429 1.58572
-1.65714 1.65714 1.70476 1.75238 1.8 1.87143 2.01429 2.15714 2.22857
-4.58572 4.94286 5.22857 5.44286 5.58572 5.58572 5.39524 5.20477 5.01429
-4.82381 4.63334 4.44286 4.25238 4.06191 3.8 3.72857 3.65715 3.65715
-3.58572 3.58572 4.15715 4.51429 4.58572 4.72858 4.87143 5.08572 5.44286
-;
-#X coords 0 10 99 0 200 140 1;
-#X restore 60 133 graph;
-#N canvas 0 0 450 300 graph29 0;
-#X array dest 100 float 0;
-#X coords 0 100 99 0 200 140 1;
-#X restore 547 129 graph;
-#X obj 10 8 tabsort2;
-#X text 75 9 2 dimensionnal sort.;
-#X text 24 99 args: source_table1 source_table2 dest_table;
-#X text 248 8 write to dest_table the indices of the first N source_table1's
-elements sorted by decreasing order (biggest first) \, then sort the
-"columns" of sqrt(N) indices decreasingly according to their values
-in source_table2 (is it clear?).;
-#N canvas 0 0 450 300 graph29 0;
-#X array source2 100 float 1;
-#A 0 7.71429 7.64286 7.64286 7.57143 7.5 7.35714 7.21428 6.92857 6.57143
-6 5.71428 5.57143 5.21428 4.5 4.35714 4.28571 4.28571 4.28571 4.28571
-4.28571 4.42857 4.57143 4.64285 4.78571 4.92857 5.14285 5.35714 5.71428
-6 6.21428 6.42857 6.57143 6.64286 6.64286 6.64286 6.64286 6.57143 6.57143
-6.42857 6.35714 6.28571 6.14286 5.92857 5.78571 5.64286 5.42857 7.85714
-7.92857 8.42857 8.71428 8.92857 8.92857 8.92857 8.92857 8.85714 8.78571
-8.78571 8.78571 8.5 8.28571 8.07143 7.5 7.28571 6.85714 6.57143 5.78571
-5.5 5.21428 4.78571 4.64286 4.64286 4.78571 4.92857 5.07143 5.21428
-5.42857 5.57143 5.71428 5.92857 6.28571 6.5 6.85714 7.14286 7.35714
-7.64286 7.71429 7.78572 7.85714 7.85714 7.85714 7.71429 7.64286 7.5
-7.35714 7.14286 7.07143 7 6.85714 4.5 -0.342857;
-#X coords 0 10 99 0 200 140 1;
-#X restore 311 131 graph;
-#X msg 62 340 100;
-#X obj 62 360 tabsort2 source1 source2 dest;
-#X obj 500 416 tabread dest;
-#X obj 452 362 * 10;
-#X obj 500 391 +;
-#X floatatom 451 346 5 0 9 0 - - -;
-#X obj 528 361 t b f;
-#X floatatom 528 344 5 0 9 0 - - -;
-#X floatatom 407 485 0 0 0 0 - - -;
-#X obj 407 465 tabread source1;
-#X obj 557 467 tabread source2;
-#X floatatom 557 487 0 0 0 0 - - -;
-#X floatatom 527 393 5 0 0 0 - - -;
-#X text 433 328 x(columns);
-#X text 521 327 y(lines);
-#X text 403 504 decrease with x;
-#X text 555 505 decrease with y;
-#X text 49 305 1) Sort it:;
-#X text 381 304 2) Try it:;
-#X text 8 520 (c) Antoine Rousseau 2002;
-#X floatatom 603 441 5 0 0 0 - - -;
-#X text 604 416 index of sources;
-#X text 606 426 elements;
-#X text 28 396 output=sqrt(N)=the width/height;
-#X text 28 410 of the destination "square".;
-#X text 61 326 sort the N first elements;
-#X connect 8 0 9 0;
-#X connect 9 0 0 0;
-#X connect 10 0 17 0;
-#X connect 10 0 18 0;
-#X connect 10 0 28 0;
-#X connect 11 0 12 0;
-#X connect 12 0 10 0;
-#X connect 12 0 20 0;
-#X connect 13 0 11 0;
-#X connect 14 0 12 0;
-#X connect 14 1 12 1;
-#X connect 15 0 14 0;
-#X connect 17 0 16 0;
-#X connect 18 0 19 0;
+#N canvas 0 31 811 538 10;
+#X floatatom 62 381 5 0 0 0 - - -;
+#N canvas 0 0 450 300 (subpatch) 0;
+#X array \$0-source1 100 float 1;
+#A 0 -0.0428565 -0.0571422 0.085715 0.228572 0.442858 0.657144 0.871429
+1.08572 1.22857 1.51429 1.72857 1.94286 2.22857 2.37143 2.58571 2.72857
+2.87143 2.94286 3.15714 3.3 3.3 3.44286 3.58571 3.65714 3.72857 3.8
+3.94286 4.01429 4.08571 4.22857 4.3 4.13929 3.97857 3.81786 3.51429
+3.22857 2.8 2.37143 2.3 2.3 2.3 2.37143 2.44286 2.51429 2.51429 2.58572
+2.55 2.37143 2.22857 1.94286 1.72857 1.58572 1.44286 1.44286 1.37144
+1.37144 1.37144 1.44286 1.44286 1.44286 1.44286 1.51429 1.51429 1.58572
+1.65714 1.65714 1.70476 1.75238 1.8 1.87143 2.01429 2.15714 2.22857
+4.58572 4.94286 5.22857 5.44286 5.58572 5.58572 5.39524 5.20477 5.01429
+4.82381 4.63334 4.44286 4.25238 4.06191 3.8 3.72857 3.65715 3.65715
+3.58572 3.58572 4.15715 4.51429 4.58572 4.72858 4.87143 5.08572 5.44286
+;
+#X coords 0 10 99 0 200 140 1;
+#X restore 60 133 graph;
+#N canvas 0 0 450 300 (subpatch) 0;
+#X array \$0-dest 100 float 0;
+#X coords 0 100 99 0 200 140 1;
+#X restore 547 129 graph;
+#X obj 10 8 tabsort2;
+#X text 24 99 args: source_table1 source_table2 dest_table;
+#X text 248 8 write to dest_table the indices of the first N source_table1's
+elements sorted by decreasing order (biggest first) \, then sort the
+"columns" of sqrt(N) indices decreasingly according to their values
+in source_table2 (is it clear?).;
+#N canvas 0 0 450 300 (subpatch) 0;
+#X array \$0-source2 100 float 1;
+#A 0 7.71429 7.64286 7.64286 7.57143 7.5 7.35714 7.21428 6.92857 6.57143
+6 5.71428 5.57143 5.21428 4.5 4.35714 4.28571 4.28571 4.28571 4.28571
+4.28571 4.42857 4.57143 4.64285 4.78571 4.92857 5.14285 5.35714 5.71428
+6 6.21428 6.42857 6.57143 6.64286 6.64286 6.64286 6.64286 6.57143 6.57143
+6.42857 6.35714 6.28571 6.14286 5.92857 5.78571 5.64286 5.42857 7.85714
+7.92857 8.42857 8.71428 8.92857 8.92857 8.92857 8.92857 8.85714 8.78571
+8.78571 8.78571 8.5 8.28571 8.07143 7.5 7.28571 6.85714 6.57143 5.78571
+5.5 5.21428 4.78571 4.64286 4.64286 4.78571 4.92857 5.07143 5.21428
+5.42857 5.57143 5.71428 5.92857 6.28571 6.5 6.85714 7.14286 7.35714
+7.64286 7.71429 7.78572 7.85714 7.85714 7.85714 7.71429 7.64286 7.5
+7.35714 7.14286 7.07143 7 6.85714 4.5 -0.342857;
+#X coords 0 10 99 0 200 140 1;
+#X restore 311 131 graph;
+#X msg 62 340 100;
+#X obj 452 362 * 10;
+#X obj 500 391 +;
+#X floatatom 452 342 5 0 9 0 - - -;
+#X obj 528 361 t b f;
+#X floatatom 528 340 5 0 9 0 - - -;
+#X floatatom 407 485 0 0 0 0 - - -;
+#X floatatom 557 487 0 0 0 0 - - -;
+#X floatatom 527 393 5 0 0 0 - - -;
+#X text 434 324 x(columns);
+#X text 521 323 y(lines);
+#X text 403 504 decrease with x;
+#X text 555 505 decrease with y;
+#X text 49 305 1) Sort it:;
+#X text 381 304 2) Try it:;
+#X text 8 520 (c) Antoine Rousseau 2002;
+#X floatatom 603 441 5 0 0 0 - - -;
+#X text 604 414 index of sources;
+#X text 606 424 elements;
+#X text 28 396 output=sqrt(N)=the width/height;
+#X text 28 410 of the destination "square".;
+#X text 61 323 sort the N first elements;
+#X obj 500 416 tabread \$0-dest;
+#X obj 407 465 tabread \$0-source1;
+#X obj 557 467 tabread \$0-source2;
+#X obj 62 360 tabsort2 \$0-source1 \$0-source2 \$0-dest;
+#N canvas 572 197 494 344 META 0;
+#X text 12 25 LICENSE GPL v2;
+#X text 12 105 AUTHOR Antoine Rousseau;
+#X text 12 125 HELP_PATCH_AUTHORS Antoine Rousseau. "pd meta" information
+added by Jonathan Wilkes for Pd version 0.42.;
+#X text 12 85 OUTLET_0 float;
+#X text 12 5 KEYWORDS control array;
+#X text 12 65 INLET_0 float;
+#X text 12 45 DESCRIPTION two dimensional sort;
+#X restore 750 506 pd META;
+#X text 75 9 2 dimensional sort;
+#X connect 7 0 32 0;
+#X connect 8 0 9 0;
+#X connect 9 0 15 0;
+#X connect 9 0 29 0;
+#X connect 10 0 8 0;
+#X connect 11 0 9 0;
+#X connect 11 1 9 1;
+#X connect 12 0 11 0;
+#X connect 29 0 23 0;
+#X connect 29 0 30 0;
+#X connect 29 0 31 0;
+#X connect 30 0 13 0;
+#X connect 31 0 14 0;
+#X connect 32 0 0 0;
diff --git a/tabsort2.c b/tabsort2.c
index 63d0fd6..68e0a99 100644
--- a/tabsort2.c
+++ b/tabsort2.c
@@ -1,164 +1,157 @@
-/*
-Copyright (C) 2002 Antoine Rousseau 
-
-This library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation; either
-version 2.1 of the License, or (at your option) any later version.
-
-This library 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
-Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with this library; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  
-
-*/
-
-#include "m_pd.h"
-#include "math.h"
-
-
-/* ---------------- tabsort2 - sort a table to a table ----------------- */
-
-
-typedef struct tabsort2
-{
-    t_object x_obj; 	    	    /* header */
-    t_symbol *x_arrayname1;
-    t_symbol *x_arrayname2;
-    t_symbol *x_arrayname3;
-    t_clock *x_clock;		    /* a "clock" object */
-} t_tabsort2;
-
-t_class *tabsort2_class;
-
-static void tabsort2_tick(t_tabsort2 *x);
-
-static void *tabsort2_new(t_symbol *tab1,t_symbol *tab2,t_symbol *tab3)
-{
-    t_tabsort2 *x;
-    x = (t_tabsort2 *)pd_new(tabsort2_class);
-
-    x->x_arrayname1 = tab1;
-    x->x_arrayname2 = tab2;
-    x->x_arrayname3 = tab3;
-    x->x_clock = clock_new(x, (t_method)tabsort2_tick);
-    outlet_new((t_object*)x, &s_float);
-
-    return (x);
-}
-
-static void tabsort2_set1(t_tabsort2 *x, t_symbol *s)
-{
-	x->x_arrayname1 = s;
-}
-static void tabsort2_set2(t_tabsort2 *x, t_symbol *s)
-{
-	x->x_arrayname2 = s;
-}
-
-static void tabsort2_set3(t_tabsort2 *x, t_symbol *s)
-{
-	x->x_arrayname3 = s;
-}
-
-static void tabsort2_float(t_tabsort2 *x, t_floatarg n)
-{
-	t_garray *a;
-	int n1,n2,n3,i,j,h,sqn;
-	float *vec1,*vec2,*vec3,tmp;
-
-    if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname1, garray_class)))
-    {
-    	if (*x->x_arrayname1->s_name) pd_error(x, "tabsort2: %s: no such array",
-    	    x->x_arrayname1->s_name);
-    	return;
-    }
-    else if (!garray_getfloatarray(a, &n1, &vec1))
-    {
-    	error("%s: bad template for tabsort2", x->x_arrayname1->s_name);
-    	return;
-    }
-
-    if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname2, garray_class)))
-    {
-    	if (*x->x_arrayname2->s_name) pd_error(x, "tabsort2: %s: no such array",
-    	    x->x_arrayname2->s_name);
-    	return;
-    }
-    else if (!garray_getfloatarray(a, &n2, &vec2))
-    {
-    	error("%s: bad template for tabsort2", x->x_arrayname2->s_name);
-	return;
-    }
-
-    if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname3, garray_class)))
-    {
-    	if (*x->x_arrayname3->s_name) pd_error(x, "tabsort2: %s: no such array",
-    	    x->x_arrayname3->s_name);
-    	return;
-    }
-    else if (!garray_getfloatarray(a, &n3, &vec3))
-    {
-    	error("%s: bad template for tabsort2", x->x_arrayname3->s_name);
-	return;
-    }
-
-	if(n>n1) n=n1;
-	if(n>n2) n=n2;
-	if(n>n3) n=n3;
-
-	for(i=0;i<n;vec3[i]=i++);
-
-	for(i=0;i<n-1;i++)
-	for(j=n-1;j>i;j--)
-	if(vec1[(int)vec3[j-1]]<vec1[(int)vec3[j]])
-	{
-		tmp=vec3[j];
-		vec3[j]=vec3[j-1];
-		vec3[j-1]=tmp;
-	}
-
-	sqn=(int)sqrt(n);
-
-	for(h=0;h<sqn;h++)
-	for(i=0;i<sqn-1;i++)
-	for(j=sqn-1;j>i;j--)
-	if(vec2[(int)vec3[h*sqn+j-1]]<vec2[(int)vec3[h*sqn+j]])
-	{
-		tmp=vec3[h*sqn+j];
-		vec3[h*sqn+j]=vec3[h*sqn+j-1];
-		vec3[h*sqn+j-1]=tmp;
-	}
-
-	garray_redraw(a);
-	outlet_float(((t_object *)x)->ob_outlet,(float)sqn);
-}
-
-static void tabsort2_tick(t_tabsort2 *x)	/* callback function for the env clock */
-{
-
-	//clock_delay(x->x_clock, 0L);
-}
-
-static void tabsort2_ff(t_tabsort2 *x)		/* cleanup on free */
-{
-    clock_free(x->x_clock);
-}
-
-
-void tabsort2_setup(void )
-{
-    tabsort2_class = class_new(gensym("tabsort2"), (t_newmethod)tabsort2_new,
-    	(t_method)tabsort2_ff, sizeof(t_tabsort2), 0, A_DEFSYM, A_DEFSYM, A_DEFSYM, 0);
-    class_addmethod(tabsort2_class, (t_method)tabsort2_set1,
-    	gensym("set1"), A_DEFSYM, 0);
-    class_addmethod(tabsort2_class, (t_method)tabsort2_set2,
-    	gensym("set2"), A_DEFSYM, 0);
-    class_addfloat(tabsort2_class, tabsort2_float);
-
-}
-
+/*
+Copyright (C) 2002 Antoine Rousseau
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+*/
+
+#include "m_pd.h"
+#include "math.h"
+
+
+/* ---------------- tabsort2 - sort a table to a table ----------------- */
+
+
+typedef struct tabsort2
+{
+    t_object x_obj; 	    	    /* header */
+    t_symbol *x_arrayname1;
+    t_symbol *x_arrayname2;
+    t_symbol *x_arrayname3;
+} t_tabsort2;
+
+t_class *tabsort2_class;
+
+static void *tabsort2_new(t_symbol *tab1,t_symbol *tab2,t_symbol *tab3)
+{
+    t_tabsort2 *x;
+    x = (t_tabsort2 *)pd_new(tabsort2_class);
+
+    x->x_arrayname1 = tab1;
+    x->x_arrayname2 = tab2;
+    x->x_arrayname3 = tab3;
+    outlet_new((t_object *)x, &s_float);
+
+    return (x);
+}
+
+static void tabsort2_set1(t_tabsort2 *x, t_symbol *s)
+{
+    x->x_arrayname1 = s;
+}
+static void tabsort2_set2(t_tabsort2 *x, t_symbol *s)
+{
+    x->x_arrayname2 = s;
+}
+
+static void tabsort2_set3(t_tabsort2 *x, t_symbol *s)
+{
+    x->x_arrayname3 = s;
+}
+
+static void tabsort2_float(t_tabsort2 *x, t_floatarg n)
+{
+    t_garray *a;
+    int n1,n2,n3,i,j,h,sqn;
+    t_word *vec1,*vec2,*vec3;
+    t_float tmp;
+
+    if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname1, garray_class)))
+    {
+        if (*x->x_arrayname1->s_name) pd_error(x, "tabsort2: %s: no such array",
+                                                   x->x_arrayname1->s_name);
+        return;
+    }
+    else if (!garray_getfloatwords(a, &n1, &vec1))
+    {
+        error("%s: bad template for tabsort2", x->x_arrayname1->s_name);
+        return;
+    }
+
+    if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname2, garray_class)))
+    {
+        if (*x->x_arrayname2->s_name) pd_error(x, "tabsort2: %s: no such array",
+                                                   x->x_arrayname2->s_name);
+        return;
+    }
+    else if (!garray_getfloatwords(a, &n2, &vec2))
+    {
+        error("%s: bad template for tabsort2", x->x_arrayname2->s_name);
+        return;
+    }
+
+    if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname3, garray_class)))
+    {
+        if (*x->x_arrayname3->s_name) pd_error(x, "tabsort2: %s: no such array",
+                                                   x->x_arrayname3->s_name);
+        return;
+    }
+    else if (!garray_getfloatwords(a, &n3, &vec3))
+    {
+        error("%s: bad template for tabsort2", x->x_arrayname3->s_name);
+        return;
+    }
+
+    if(n>n1) n=n1;
+    if(n>n2) n=n2;
+    if(n>n3) n=n3;
+
+    for(i=0; i<n; vec3[i].w_float=i++);
+
+    for(i=0; i<n-1; i++)
+        for(j=n-1; j>i; j--)
+            if(vec1[(int)vec3[j-1].w_float].w_float<vec1[(int)vec3[j].w_float].w_float)
+            {
+                tmp=vec3[j].w_float;
+                vec3[j].w_float=vec3[j-1].w_float;
+                vec3[j-1].w_float=tmp;
+            }
+
+    sqn=(int)sqrt(n);
+
+    for(h=0; h<sqn; h++)
+        for(i=0; i<sqn-1; i++)
+            for(j=sqn-1; j>i; j--)
+                if(vec2[(int)vec3[h*sqn+j-1].w_float].w_float<vec2[(int)vec3[h*sqn+j].w_float].w_float)
+                {
+                    tmp=vec3[h*sqn+j].w_float;
+                    vec3[h*sqn+j].w_float=vec3[h*sqn+j-1].w_float;
+                    vec3[h*sqn+j-1].w_float=tmp;
+                }
+
+    garray_redraw(a);
+    outlet_float(((t_object *)x)->ob_outlet,(t_float)sqn);
+}
+
+
+static void tabsort2_ff(t_tabsort2 *x)		/* cleanup on free */
+{
+}
+
+
+void tabsort2_setup(void )
+{
+    tabsort2_class = class_new(gensym("tabsort2"), (t_newmethod)tabsort2_new,
+                               (t_method)tabsort2_ff, sizeof(t_tabsort2), 0, A_DEFSYM, A_DEFSYM, A_DEFSYM, 0);
+    class_addmethod(tabsort2_class, (t_method)tabsort2_set1,
+                    gensym("set1"), A_DEFSYM, 0);
+    class_addmethod(tabsort2_class, (t_method)tabsort2_set2,
+                    gensym("set2"), A_DEFSYM, 0);
+    class_addmethod(tabsort2_class, (t_method)tabsort2_set3,
+                    gensym("set3"), A_DEFSYM, 0);
+    class_addfloat(tabsort2_class, tabsort2_float);
+
+}
+
diff --git a/wac-help.pd b/wac-help.pd
index 1a885e6..8757461 100644
--- a/wac-help.pd
+++ b/wac-help.pd
@@ -1,4 +1,4 @@
-#N canvas 840 624 450 300 10;
-#X obj 178 120 wac;
-#X text 122 188 placeholder help patch;
-#X text 113 52 wacom graphire on serial port only;
+#N canvas 840 624 450 300 10;
+#X obj 178 120 wac;
+#X text 122 188 placeholder help patch;
+#X text 113 52 wacom graphire on serial port only;
diff --git a/wac.c b/wac.c
index 736194e..ca21768 100644
--- a/wac.c
+++ b/wac.c
@@ -1,254 +1,258 @@
- /*
-   wacom graphire on serial port only...
-*/
-
-#include <m_pd.h>
-#include "s_stuff.h"
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-
-#define BUFSIZE 256
-#define HEADER_BIT	0x80
-#define ZAXIS_SIGN_BIT	0x40
-#define ZAXIS_BIT    	0x04
-#define ZAXIS_BITS    	0x3f
-#define POINTER_BIT     0x20
-#define PROXIMITY_BIT   0x40
-#define BUTTON_FLAG	0x08
-#define BUTTONS_BITS	0x78
-#define TILT_SIGN_BIT	0x40
-#define TILT_BITS	0x3f
-
-/* defines to discriminate second side button and the eraser */
-#define ERASER_PROX	4
-#define OTHER_PROX	1
-
-#define Threshold 1000
-unsigned char data[7];
-
-typedef struct _wac
-{
-    t_object t_ob;
-    t_outlet *axis_out;
-    t_outlet *button_out;
-    t_symbol *file;
-    int fd;
- 	int count;
-	int oldbuttons;
-	unsigned char data[BUFSIZE];
-}t_wac;
-
-t_class *wac_class;
-
-void wac_setup(void);
-static void wac_read(t_wac *x,int fd);
-static void wac_process(t_wac *x);
-
-static void wac_open(t_wac *x)
-{
-	if(x->fd>=0) return;
-	
-	x->fd = open (x->file->s_name, O_RDONLY | O_NONBLOCK);
-	if(x->fd<0){
-		post("open (%s, O_RDONLY | O_NONBLOCK)",x->file->s_name);
-		perror("open");
-		return;
-	}
-	sys_addpollfn(x->fd,(t_fdpollfn)wac_read,(void*)x);
-}
-
-static void wac_close(t_wac *x)
-{
-	if(x->fd<0) return;
-
-	sys_rmpollfn(x->fd);
-	close(x->fd);
-	x->fd=-1;
-}
-
-static void wac_float(t_wac *x,t_floatarg connect)
-{
-	if(connect!=0) wac_open(x);
-	else wac_close(x);
-}
-
-static void *wac_new(t_symbol *file)
-{  
-	t_wac *x = (t_wac *)pd_new(wac_class);
-	
-	//if(file->s_name)
-	if(file!=&s_)
-		x->file=file;
-	else x->file=gensym("/dev/ttyS0");
-	
-	post("wac_new file=%s",x->file->s_name);
-	x->axis_out = outlet_new(&x->t_ob, &s_list);
-	x->button_out = outlet_new(&x->t_ob, &s_list);
-	
-	x->fd=-1;
-	
-	return (void *)x;
-}
-
-void wac_setup(void)
-{
-	wac_class = class_new(gensym("wac"),(t_newmethod)wac_new, 
-		(t_method)wac_close, sizeof(t_wac), 0, A_DEFSYM, 0);
-	class_addfloat(wac_class, wac_float);
-	
-
-}
-
-
-static void wac_read(t_wac *x,int fd)
-{
-	int len,i=0;
-	unsigned char b;  
-	unsigned char buffer[BUFSIZE];
-  	
-	while((len=read(fd,buffer,BUFSIZE))> -1){	
-
-		for(i=0;i<len;i++){
-			if(buffer[i]&128) x->count=0;
-			x->data[x->count++]=buffer[i];
-			if(x->count==7) wac_process(x);
-		}		
-	}	
-}
-
-static void wac_process(t_wac *X)
-{
-    int			is_stylus = 1, is_button, is_proximity, wheel=0;
-    int			x, y, z, buttons, tx = 0, ty = 0;
-	unsigned char *data=X->data;
-	t_atom ats[3];
-
-	    is_stylus = (data[0] & POINTER_BIT);
-		
-		if(!is_stylus) return;
-		
-		x = (((data[0] & 0x3) << 14) +
-		 (data[1] << 7) +
-		 data[2]);
-	    y = (((data[3] & 0x3) << 14) +
-		 (data[4] << 7) +
-		 data[5]);
-
-
-	    z = ((data[6] & ZAXIS_BITS) * 2) +
-		((data[3] & ZAXIS_BIT) >> 2);
-
-		//z = z*4 + ((data[0] & ZAXIS_BIT) >> 1);
-
-		if (!(data[6] & ZAXIS_SIGN_BIT)) {
-		    z += 128;
-		}
-
-	    is_proximity = (data[0] & PROXIMITY_BIT);
-
-		buttons = ((data[3] & 0x38) >> 3);
-		/*if (is_stylus) {
-		    buttons = ((data[3] & 0x30) >> 3) |
-			(z >= Threshold ? 1 : 0);
-		}
-		else {
-		    buttons = (data[3] & 0x38) >> 3;
-
-		    wheel = (data[6] & 0x30) >> 4;
-
-		    if (data[6] & 0x40) {
-			wheel = -wheel;
-		    }
-		}*/
-		//is_button = (buttons != 0);
-		if(buttons!=X->oldbuttons)
-		{
-			X->oldbuttons=buttons;
-			
-			SETFLOAT(&ats[0],buttons&1);
-			SETFLOAT(&ats[1],(buttons&2)!=0);
-			SETFLOAT(&ats[2],(buttons&4)!=0);
-			outlet_list(X->button_out,0,3,ats);
-		}
-		SETFLOAT(&ats[0],x/5103.0);
-		SETFLOAT(&ats[1],y/3711.0);
-		SETFLOAT(&ats[2],z/256.0);
-		outlet_list(X->axis_out,0,3,ats);
-}
-	/* Format of 7 bytes data packet for Wacom Tablets
-	Byte 1
-	bit 7  Sync bit always 1
-	bit 6  Pointing device detected
-	bit 5  Cursor = 0 / Stylus = 1
-	bit 4  Reserved
-	bit 3  1 if a button on the pointing device has been pressed
-	bit 2  Reserved
-	bit 1  X15
-	bit 0  X14
-
-	Byte 2
-	bit 7  Always 0
-	bits 6-0 = X13 - X7
-
-	Byte 3
-	bit 7  Always 0
-	bits 6-0 = X6 - X0
-
-	Byte 4
-	bit 7  Always 0
-	bit 6  B3
-	bit 5  B2
-	bit 4  B1
-	bit 3  B0
-	bit 2  P0
-	bit 1  Y15
-	bit 0  Y14
-
-	Byte 5
-	bit 7  Always 0
-	bits 6-0 = Y13 - Y7
-
-	Byte 6
-	bit 7  Always 0
-	bits 6-0 = Y6 - Y0
-
-	Byte 7
-	bit 7 Always 0
-	bit 6  Sign of pressure data
-	bit 5  P6
-	bit 4  P5
-	bit 3  P4
-	bit 2  P3
-	bit 1  P2
-	bit 0  P1
-
-	byte 8 and 9 are optional and present only
-	in tilt mode.
-
-	Byte 8
-	bit 7 Always 0
-	bit 6 Sign of tilt X
-	bit 5  Xt6
-	bit 4  Xt5
-	bit 3  Xt4
-	bit 2  Xt3
-	bit 1  Xt2
-	bit 0  Xt1
-
-	Byte 9
-	bit 7 Always 0
-	bit 6 Sign of tilt Y
-	bit 5  Yt6
-	bit 4  Yt5
-	bit 3  Yt4
-	bit 2  Yt3
-	bit 1  Yt2
-	bit 0  Yt1
-
-	*/
-	
+/*
+  wacom graphire on serial port only...
+*/
+
+#include <m_pd.h>
+#include "s_stuff.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#define BUFSIZE 256
+#define HEADER_BIT	0x80
+#define ZAXIS_SIGN_BIT	0x40
+#define ZAXIS_BIT    	0x04
+#define ZAXIS_BITS    	0x3f
+#define POINTER_BIT     0x20
+#define PROXIMITY_BIT   0x40
+#define BUTTON_FLAG	0x08
+#define BUTTONS_BITS	0x78
+#define TILT_SIGN_BIT	0x40
+#define TILT_BITS	0x3f
+
+/* defines to discriminate second side button and the eraser */
+#define ERASER_PROX	4
+#define OTHER_PROX	1
+
+#define Threshold 1000
+unsigned char data[7];
+
+typedef struct _wac
+{
+    t_object t_ob;
+    t_outlet *axis_out;
+    t_outlet *button_out;
+    t_symbol *file;
+    int fd;
+    int count;
+    int oldbuttons;
+    unsigned char data[BUFSIZE];
+} t_wac;
+
+t_class *wac_class;
+
+void wac_setup(void);
+static void wac_read(t_wac *x,int fd);
+static void wac_process(t_wac *x);
+
+static void wac_open(t_wac *x)
+{
+    if(x->fd>=0) return;
+
+    x->fd = open (x->file->s_name, O_RDONLY | O_NONBLOCK);
+    if(x->fd<0)
+    {
+        post("open (%s, O_RDONLY | O_NONBLOCK)",x->file->s_name);
+        perror("open");
+        return;
+    }
+    sys_addpollfn(x->fd,(t_fdpollfn)wac_read,(void *)x);
+}
+
+static void wac_close(t_wac *x)
+{
+    if(x->fd<0) return;
+
+    sys_rmpollfn(x->fd);
+    close(x->fd);
+    x->fd=-1;
+}
+
+static void wac_float(t_wac *x,t_floatarg connect)
+{
+    if(connect!=0) wac_open(x);
+    else wac_close(x);
+}
+
+static void *wac_new(t_symbol *file)
+{
+    t_wac *x = (t_wac *)pd_new(wac_class);
+
+    //if(file->s_name)
+    if(file!=&s_)
+        x->file=file;
+    else x->file=gensym("/dev/ttyS0");
+
+    post("wac_new file=%s",x->file->s_name);
+    x->axis_out = outlet_new(&x->t_ob, &s_list);
+    x->button_out = outlet_new(&x->t_ob, &s_list);
+
+    x->fd=-1;
+
+    return (void *)x;
+}
+
+void wac_setup(void)
+{
+    wac_class = class_new(gensym("wac"),(t_newmethod)wac_new,
+                          (t_method)wac_close, sizeof(t_wac), 0, A_DEFSYM, 0);
+    class_addfloat(wac_class, wac_float);
+
+
+}
+
+
+static void wac_read(t_wac *x,int fd)
+{
+    int len,i=0;
+    unsigned char b;
+    unsigned char buffer[BUFSIZE];
+
+    while((len=read(fd,buffer,BUFSIZE))> -1)
+    {
+
+        for(i=0; i<len; i++)
+        {
+            if(buffer[i]&128) x->count=0;
+            x->data[x->count++]=buffer[i];
+            if(x->count==7) wac_process(x);
+        }
+    }
+}
+
+static void wac_process(t_wac *X)
+{
+    int			is_stylus = 1, is_button, is_proximity, wheel=0;
+    int			x, y, z, buttons, tx = 0, ty = 0;
+    unsigned char *data=X->data;
+    t_atom ats[3];
+
+    is_stylus = (data[0] & POINTER_BIT);
+
+    if(!is_stylus) return;
+
+    x = (((data[0] & 0x3) << 14) +
+         (data[1] << 7) +
+         data[2]);
+    y = (((data[3] & 0x3) << 14) +
+         (data[4] << 7) +
+         data[5]);
+
+
+    z = ((data[6] & ZAXIS_BITS) * 2) +
+        ((data[3] & ZAXIS_BIT) >> 2);
+
+    //z = z*4 + ((data[0] & ZAXIS_BIT) >> 1);
+
+    if (!(data[6] & ZAXIS_SIGN_BIT))
+    {
+        z += 128;
+    }
+
+    is_proximity = (data[0] & PROXIMITY_BIT);
+
+    buttons = ((data[3] & 0x38) >> 3);
+    /*if (is_stylus) {
+        buttons = ((data[3] & 0x30) >> 3) |
+    	(z >= Threshold ? 1 : 0);
+    }
+    else {
+        buttons = (data[3] & 0x38) >> 3;
+
+        wheel = (data[6] & 0x30) >> 4;
+
+        if (data[6] & 0x40) {
+    	wheel = -wheel;
+        }
+    }*/
+    //is_button = (buttons != 0);
+    if(buttons!=X->oldbuttons)
+    {
+        X->oldbuttons=buttons;
+
+        SETFLOAT(&ats[0],buttons&1);
+        SETFLOAT(&ats[1],(buttons&2)!=0);
+        SETFLOAT(&ats[2],(buttons&4)!=0);
+        outlet_list(X->button_out,0,3,ats);
+    }
+    SETFLOAT(&ats[0],x/5103.0);
+    SETFLOAT(&ats[1],y/3711.0);
+    SETFLOAT(&ats[2],z/256.0);
+    outlet_list(X->axis_out,0,3,ats);
+}
+/* Format of 7 bytes data packet for Wacom Tablets
+Byte 1
+bit 7  Sync bit always 1
+bit 6  Pointing device detected
+bit 5  Cursor = 0 / Stylus = 1
+bit 4  Reserved
+bit 3  1 if a button on the pointing device has been pressed
+bit 2  Reserved
+bit 1  X15
+bit 0  X14
+
+Byte 2
+bit 7  Always 0
+bits 6-0 = X13 - X7
+
+Byte 3
+bit 7  Always 0
+bits 6-0 = X6 - X0
+
+Byte 4
+bit 7  Always 0
+bit 6  B3
+bit 5  B2
+bit 4  B1
+bit 3  B0
+bit 2  P0
+bit 1  Y15
+bit 0  Y14
+
+Byte 5
+bit 7  Always 0
+bits 6-0 = Y13 - Y7
+
+Byte 6
+bit 7  Always 0
+bits 6-0 = Y6 - Y0
+
+Byte 7
+bit 7 Always 0
+bit 6  Sign of pressure data
+bit 5  P6
+bit 4  P5
+bit 3  P4
+bit 2  P3
+bit 1  P2
+bit 0  P1
+
+byte 8 and 9 are optional and present only
+in tilt mode.
+
+Byte 8
+bit 7 Always 0
+bit 6 Sign of tilt X
+bit 5  Xt6
+bit 4  Xt5
+bit 3  Xt4
+bit 2  Xt3
+bit 1  Xt2
+bit 0  Xt1
+
+Byte 9
+bit 7 Always 0
+bit 6 Sign of tilt Y
+bit 5  Yt6
+bit 4  Yt5
+bit 3  Yt4
+bit 2  Yt3
+bit 1  Yt2
+bit 0  Yt1
+
+*/
+

-- 
pd-moonlib packaging



More information about the pkg-multimedia-commits mailing list