aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Schouten <doelie@users.sourceforge.net>2003-01-21 10:18:19 +0000
committerTom Schouten <doelie@users.sourceforge.net>2003-01-21 10:18:19 +0000
commitcdf8ded57019d5c905f16422d40be7b1a18ab3bc (patch)
tree92623f40f305b1e2f51198d5c16893c7ca70a2c6
This commit was generated by cvs2svn to compensate for changes in r350,svn2git-root
which included commits to RCS files with non-trunk default branches. svn path=/trunk/externals/creb/; revision=351
-rw-r--r--COPYING340
-rw-r--r--Makefile49
-rw-r--r--Makefile.config20
-rw-r--r--Makefile.config_darwin25
-rw-r--r--Makefile.pd_darwin27
-rw-r--r--README45
-rw-r--r--README.darwin8
-rw-r--r--abs/64k.pd96
-rw-r--r--abs/bdft.pd16
-rw-r--r--abs/bdfts.pd18
-rw-r--r--abs/bhip~.pd10
-rw-r--r--abs/blop~.pd10
-rw-r--r--abs/bpm.pd18
-rw-r--r--abs/count.pd20
-rw-r--r--abs/eadh~.pd22
-rw-r--r--abs/eadsrh~.pd27
-rw-r--r--abs/fblock.pd25
-rw-r--r--abs/inv.pd8
-rw-r--r--abs/pdynwav~.pd10
-rw-r--r--abs/scale7.pd40
-rw-r--r--abs/vols~.pd24
-rw-r--r--abs/vol~.pd18
-rw-r--r--doc/bdiag~.pd97
-rw-r--r--doc/bfft~.pd18
-rw-r--r--doc/biquadseries~.pd22
-rw-r--r--doc/cheby~.pd43
-rw-r--r--doc/dist~.pd17
-rw-r--r--doc/dwt~.pd72
-rw-r--r--doc/dynwav~.pd25
-rw-r--r--doc/eadsr~.pd41
-rw-r--r--doc/ead~.pd29
-rw-r--r--doc/ear~.pd35
-rw-r--r--doc/examples/xfmdelay.pd106
-rw-r--r--doc/ffpoly.pd35
-rw-r--r--doc/filterortho~.pd58
-rw-r--r--doc/fwarp.pd37
-rw-r--r--doc/lattice~.pd63
-rw-r--r--doc/matrix~.pd10
-rw-r--r--doc/permut~.pd19
-rw-r--r--doc/qmult~.pd63
-rw-r--r--doc/qnorm~.pd35
-rw-r--r--doc/ratio.pd18
-rw-r--r--doc/reference.txt49
-rw-r--r--doc/tabreadmix~.pd45
-rw-r--r--doc/xfm~.pd106
-rw-r--r--include/Makefile5
-rw-r--r--include/dspi/DSPI.h16
-rw-r--r--include/dspi/DSPIcomplex.h191
-rw-r--r--include/dspi/DSPIfilters.h496
-rw-r--r--include/extlib_util.h31
-rw-r--r--modules++/Makefile10
-rw-r--r--modules++/biquadseries.cc128
-rw-r--r--modules++/filterortho.cc131
-rw-r--r--modules/Makefile11
-rw-r--r--modules/abs.c64
-rw-r--r--modules/bdiag.c272
-rw-r--r--modules/bfft.c304
-rw-r--r--modules/cheby.c138
-rw-r--r--modules/diag.c218
-rw-r--r--modules/dist.c262
-rw-r--r--modules/dwt.c893
-rw-r--r--modules/dynwav.c318
-rw-r--r--modules/ead.c153
-rw-r--r--modules/eadsr.c171
-rw-r--r--modules/ear.c134
-rw-r--r--modules/ffpoly.c173
-rw-r--r--modules/fwarp.c61
-rw-r--r--modules/lattice.c143
-rw-r--r--modules/matrix.c154
-rw-r--r--modules/permut.c177
-rw-r--r--modules/qmult.c165
-rw-r--r--modules/qnorm.c137
-rw-r--r--modules/ramp.c118
-rw-r--r--modules/ratio.c66
-rw-r--r--modules/statwav.c149
-rw-r--r--modules/tabreadmix.c271
-rw-r--r--modules/xfm.c271
-rw-r--r--system/Makefile8
-rw-r--r--system/envelope_util.c33
-rw-r--r--system/setup.c64
80 files changed, 7855 insertions, 0 deletions
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..7f87ef8
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR PDP.LICENSE, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..d03e9f8
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,49 @@
+include Makefile.config
+
+CREB_DISTRO = $(CREB_DIR)/../creb-$(CREB_VERSION)
+CREB_TARBALL = $(CREB_DISTRO).tar.gz
+CREB_WWWDIR = /net/zwizwa/www/zwizwa.fartit.com/pd/creb
+
+LIBNAME=creb.pd_linux
+
+current:
+ make -C system
+ make -C modules
+ make -C modules++
+
+ rm -f $(LIBNAME)
+ $(CPLUSPLUS) -export_dynamic -shared -o $(LIBNAME) system/*.o modules/*.o modules++/*.o -lm
+ strip --strip-unneeded $(LIBNAME)
+
+clean:
+ make -C include clean
+ make -C modules clean
+ make -C modules++ clean
+ make -C system clean
+ rm -f $(LIBNAME)
+ rm -f *~
+
+tags:
+ etags --language=auto include/*.h system/*.c modules/*.c modules++/*.cpp
+
+tagsclean:
+ rm -f TAGS
+
+
+distro: clean
+ rm -rf $(CREB_DISTRO)
+ mkdir $(CREB_DISTRO)
+ cp -av $(CREB_DIR)/* $(CREB_DISTRO)
+ rm -rf $(CREB_DISTRO)/CVS
+ rm -rf $(CREB_DISTRO)/*/CVS
+ rm -rf $(CREB_DISTRO)/*/*/CVS
+ rm -rf $(CREB_DISTRO)/*/*.o
+ rm -rf $(CREB_DISTRO)/*/TAGS
+ cd $(CREB_DISTRO)/.. && tar vczf creb-$(CREB_VERSION).tar.gz creb-$(CREB_VERSION)
+ rm -rf $(CREB_DISTRO)
+
+www: $(PDP_TARBALL)
+ cp -av $(CREB_TARBALL) $(CREB_WWWDIR)
+ cp -av $(CREB_DIR)/README $(CREB_WWWDIR)/README.txt
+ cp -av $(CREB_DIR)/doc/reference.txt $(CREB_WWWDIR)
+
diff --git a/Makefile.config b/Makefile.config
new file mode 100644
index 0000000..5dee604
--- /dev/null
+++ b/Makefile.config
@@ -0,0 +1,20 @@
+PD_DIR = /home/tom/pd/distro/pd/src
+CREB_DIR = /home/tom/pd/extlib
+CREB_VERSION = 0.6
+
+DEFS = -DPD -DCREB_VERSION=\"$(CREB_VERSION)\"
+
+LINUXCFLAGS = $(DEFS) -O2 -funroll-loops -fomit-frame-pointer \
+ -Wall -W -Wstrict-prototypes -Werror \
+ -Wno-unused -Wno-parentheses -Wno-switch # -Wshadow
+
+LINUXINCLUDE = -I$(PD_DIR) -I../include -I../include/dspi
+
+CC = gcc
+CPLUSPLUS = g++
+
+.c.o:
+ $(CC) $(LINUXCFLAGS) $(LINUXINCLUDE) -o $*.o -c $*.c
+.cc.o:
+ $(CPLUSPLUS) $(LINUXCFLAGS) $(LINUXINCLUDE) -o $*.o -c $*.cc
+
diff --git a/Makefile.config_darwin b/Makefile.config_darwin
new file mode 100644
index 0000000..b9c49eb
--- /dev/null
+++ b/Makefile.config_darwin
@@ -0,0 +1,25 @@
+PD_DIR = /usr/local/pd/src
+PD_EXECUTABLE = /usr/local/pd/bin/pd
+
+CREB_VERSION = 0.5
+
+LIBNAME = creb.pd_darwin
+
+DEFS = -DPD -DCREB_VERSION=\"$(CREB_VERSION)\"
+
+CFLAGS = $(DEFS) -O2 -funroll-loops -fomit-frame-pointer \
+ -Wall -W -Wstrict-prototypes -Werror \
+ -Wno-unused -Wno-parentheses -Wno-switch # -Wshadow
+
+INCLUDE = -I$(PD_DIR) -I../include -I../include/dspi
+
+LIBFLAGS = -bundle -bundle_loader $(PD_EXECUTABLE)
+
+CC = gcc
+CPLUSPLUS = g++
+
+.c.o:
+ $(CC) $(CFLAGS) $(INCLUDE) -o $*.o -c $*.c
+.cc.o:
+ $(CPLUSPLUS) $(CFLAGS) $(INCLUDE) -o $*.o -c $*.cc
+
diff --git a/Makefile.pd_darwin b/Makefile.pd_darwin
new file mode 100644
index 0000000..7dad28d
--- /dev/null
+++ b/Makefile.pd_darwin
@@ -0,0 +1,27 @@
+CONFIGFILE = Makefile.config_darwin
+include $(CONFIGFILE)
+
+current:
+ make -C system
+ make -C modules
+ make -C modules++
+
+ rm -f $(LIBNAME)
+ $(CPLUSPLUS) $(LIBFLAGS) -o $(LIBNAME) system/*.o modules/*.o modules++/*.o -lm
+# strip --strip-unneeded $(LIBNAME)
+
+clean:
+ make -C include clean
+ make -C modules clean
+ make -C modules++ clean
+ make -C system clean
+ rm -f $(LIBNAME)
+ rm -f *~
+
+tags:
+ etags --language=auto include/*.h system/*.c modules/*.c modules++/*.cpp
+
+tagsclean:
+ rm -f TAGS
+
+
diff --git a/README b/README
new file mode 100644
index 0000000..8f2bb32
--- /dev/null
+++ b/README
@@ -0,0 +1,45 @@
+CREB - compl. red. ext. blk.
+some externals for pure data
+
+Copyright (c) by Tom Schouten <creb@zzz.kotnet.org>
+
+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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+The GNU Public Licence can be found in the file COPYING
+
+
+------------------------------------------------------------------
+
+This is a collection of pd externals. No fancy stuff, just my
+personal bag of (ahem) tricks...
+
+Edit Makefile.config, type make.
+
+add the library to the pd startup line, and specify the
+path for the included abstractions (<crebdir>/abs)
+
+Documentation packages in doc/
+See doc/reference.txt for a list of objects
+
+The package only includes linux + darwin makefiles. It is plain c/c++ so
+porting should be relatively simple.
+
+For compilation on OSX, see README.darwin (thanks to Adam Lindsay for
+the darwin makefiles)
+
+Enjoy,
+
+Tom
+
diff --git a/README.darwin b/README.darwin
new file mode 100644
index 0000000..0edef42
--- /dev/null
+++ b/README.darwin
@@ -0,0 +1,8 @@
+Create a symbolic link to Makefile.config_darwin:
+
+ ln -s Makefile.config_darwin Makefile.config
+
+Make the file using the pd_darwin file:
+
+ make -f Makefile.pd_darwin
+
diff --git a/abs/64k.pd b/abs/64k.pd
new file mode 100644
index 0000000..7dc4933
--- /dev/null
+++ b/abs/64k.pd
@@ -0,0 +1,96 @@
+#N canvas 50 0 979 783 10;
+#X obj 501 74 soundfiler;
+#X obj 45 125 * 65536;
+#X obj 91 649 +~;
+#X obj 106 618 *~ 65536;
+#X obj 289 309 metro 62.5;
+#X obj 116 580 phasor~ 1;
+#X obj 279 460 sel 0;
+#X msg 279 527 0;
+#X obj 561 181 bng 15 250 50 0 empty empty empty 0 -6 32 8 -262144
+-1 -1;
+#X obj 45 35 +;
+#X obj 45 10 *;
+#X obj 391 276 bpm;
+#X msg 286 254 reset;
+#X obj 202 164 count 32;
+#X obj 478 -63 loadbang;
+#X obj 265 55 mod 16;
+#X obj 257 2 *;
+#X obj 45 97 +;
+#X obj 257 79 / 16;
+#X text 41 -46 sample shuffle;
+#X text 257 -44 beat shuffle;
+#X obj 265 28 +;
+#X obj 497 -16 symbol \$1;
+#X obj 273 -23 inlet;
+#X obj 498 99 / 65536;
+#X obj 499 128 - 1;
+#X obj 45 62 mod;
+#X obj 61 -25 inlet;
+#X obj 171 -25 inlet;
+#X text 151 -46 sample offset;
+#X obj 377 -23 inlet;
+#X text 357 -44 beat offset;
+#X obj 116 535 f;
+#X obj 681 144 inlet;
+#X text 688 123 bpm;
+#X msg 500 43 read -resize -raw 0 1 2 l \$1 \$2;
+#X obj 501 17 pack s s;
+#X obj 571 -47 t b b;
+#X obj 589 144 inlet;
+#X text 589 123 reset;
+#X obj 91 704 outlet~;
+#X obj 580 -17 symbol \$0-table;
+#X obj 795 95 table \$0-table;
+#X obj 91 675 tabread4~ \$0-table;
+#X text 608 612 reset;
+#X obj 608 633 outlet;
+#X obj 387 644 outlet;
+#X text 387 623 counter;
+#X connect 0 0 24 0;
+#X connect 1 0 2 0;
+#X connect 2 0 43 0;
+#X connect 3 0 2 1;
+#X connect 4 0 13 0;
+#X connect 5 0 3 0;
+#X connect 6 0 7 0;
+#X connect 7 0 5 1;
+#X connect 7 0 45 0;
+#X connect 8 0 4 0;
+#X connect 8 0 7 0;
+#X connect 8 0 12 0;
+#X connect 8 0 32 0;
+#X connect 9 0 26 0;
+#X connect 10 0 9 0;
+#X connect 11 0 4 1;
+#X connect 11 1 32 0;
+#X connect 12 0 13 0;
+#X connect 13 0 6 0;
+#X connect 13 0 10 0;
+#X connect 13 0 16 0;
+#X connect 13 0 46 0;
+#X connect 14 0 8 0;
+#X connect 14 0 37 0;
+#X connect 15 0 18 0;
+#X connect 16 0 21 0;
+#X connect 17 0 1 0;
+#X connect 18 0 17 1;
+#X connect 21 0 15 0;
+#X connect 22 0 36 0;
+#X connect 23 0 16 1;
+#X connect 24 0 25 0;
+#X connect 25 0 26 1;
+#X connect 26 0 17 0;
+#X connect 27 0 10 1;
+#X connect 28 0 9 1;
+#X connect 30 0 21 1;
+#X connect 32 0 5 0;
+#X connect 33 0 11 0;
+#X connect 35 0 0 0;
+#X connect 36 0 35 0;
+#X connect 37 0 22 0;
+#X connect 37 1 41 0;
+#X connect 38 0 8 0;
+#X connect 41 0 36 1;
+#X connect 43 0 40 0;
diff --git a/abs/bdft.pd b/abs/bdft.pd
new file mode 100644
index 0000000..a979df4
--- /dev/null
+++ b/abs/bdft.pd
@@ -0,0 +1,16 @@
+#N canvas 520 402 300 195 10;
+#X obj 106 9 inlet;
+#X obj 169 11 inlet;
+#X obj 121 90 pack \$1 0 0;
+#X obj 136 150 outlet;
+#X obj 167 41 t b f;
+#X obj 110 41 t b f;
+#X msg 100 125 timefreq \$1 \$2 \$3;
+#X connect 0 0 5 0;
+#X connect 1 0 4 0;
+#X connect 2 0 6 0;
+#X connect 4 0 2 0;
+#X connect 4 1 2 1;
+#X connect 5 0 2 0;
+#X connect 5 1 2 2;
+#X connect 6 0 3 0;
diff --git a/abs/bdfts.pd b/abs/bdfts.pd
new file mode 100644
index 0000000..1926d4f
--- /dev/null
+++ b/abs/bdfts.pd
@@ -0,0 +1,18 @@
+#N canvas 520 402 300 195 10;
+#X obj 106 9 inlet;
+#X obj 169 11 inlet;
+#X obj 121 90 pack \$1 0 0;
+#X obj 136 150 outlet;
+#X obj 166 60 t b f;
+#X obj 109 60 t b f;
+#X msg 100 125 timefreq \$1 \$2 \$3;
+#X obj 170 36 * 1000;
+#X connect 0 0 5 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 2 0;
+#X connect 4 1 2 1;
+#X connect 5 0 2 0;
+#X connect 5 1 2 2;
+#X connect 6 0 3 0;
+#X connect 7 0 4 0;
diff --git a/abs/bhip~.pd b/abs/bhip~.pd
new file mode 100644
index 0000000..f7c925f
--- /dev/null
+++ b/abs/bhip~.pd
@@ -0,0 +1,10 @@
+#N canvas 399 553 450 300 10;
+#X obj 87 196 biquadseries~ \$1;
+#X obj 81 134 inlet~;
+#X obj 138 134 inlet;
+#X obj 82 236 outlet~;
+#X msg 107 162 butterHP \$1;
+#X connect 0 0 3 0;
+#X connect 1 0 0 0;
+#X connect 2 0 4 0;
+#X connect 4 0 0 0;
diff --git a/abs/blop~.pd b/abs/blop~.pd
new file mode 100644
index 0000000..5a32c98
--- /dev/null
+++ b/abs/blop~.pd
@@ -0,0 +1,10 @@
+#N canvas 399 553 450 300 10;
+#X obj 87 196 biquadseries~ \$1;
+#X msg 107 162 butterLP \$1;
+#X obj 81 134 inlet~;
+#X obj 138 134 inlet;
+#X obj 82 236 outlet~;
+#X connect 0 0 4 0;
+#X connect 1 0 0 0;
+#X connect 2 0 0 0;
+#X connect 3 0 1 0;
diff --git a/abs/bpm.pd b/abs/bpm.pd
new file mode 100644
index 0000000..97d31e6
--- /dev/null
+++ b/abs/bpm.pd
@@ -0,0 +1,18 @@
+#N canvas 385 419 372 239 10;
+#X obj 48 40 inlet;
+#X obj 52 155 outlet;
+#X obj 213 157 outlet;
+#X text 30 185 quarter note time;
+#X text 184 188 measure frequency;
+#X text 46 18 bpm input;
+#X obj 55 126 /;
+#X obj 36 67 t b f;
+#X obj 200 101 / 240;
+#X msg 44 99 15000;
+#X connect 0 0 7 0;
+#X connect 0 0 8 0;
+#X connect 6 0 1 0;
+#X connect 7 0 9 0;
+#X connect 7 1 6 1;
+#X connect 8 0 2 0;
+#X connect 9 0 6 0;
diff --git a/abs/count.pd b/abs/count.pd
new file mode 100644
index 0000000..44001b5
--- /dev/null
+++ b/abs/count.pd
@@ -0,0 +1,20 @@
+#N canvas 245 395 450 300 10;
+#X obj 51 24 inlet;
+#X obj 63 144 f 0;
+#X obj 64 180 + 1;
+#X obj 99 144 mod \$1;
+#X msg 75 108 0;
+#X obj 41 246 outlet;
+#X obj 44 66 route reset;
+#X msg 13 109 bang;
+#X obj 161 20 inlet;
+#X connect 0 0 6 0;
+#X connect 1 0 2 0;
+#X connect 1 0 5 0;
+#X connect 2 0 3 0;
+#X connect 3 0 1 1;
+#X connect 4 0 1 1;
+#X connect 6 0 4 0;
+#X connect 6 1 7 0;
+#X connect 7 0 1 0;
+#X connect 8 0 3 1;
diff --git a/abs/eadh~.pd b/abs/eadh~.pd
new file mode 100644
index 0000000..0f00345
--- /dev/null
+++ b/abs/eadh~.pd
@@ -0,0 +1,22 @@
+#N canvas 127 436 262 228 10;
+#X obj 34 27 inlet;
+#X obj 84 27 inlet;
+#X obj 133 27 inlet;
+#X msg 44 108 start;
+#X msg 92 107 stop;
+#X obj 179 27 inlet;
+#X msg 34 49 bang;
+#X obj 44 187 outlet~;
+#X text 14 6 trigger - attack - decay - hold;
+#X obj 44 144 ear~ \$1 \$2;
+#X obj 68 78 del \$3;
+#X connect 0 0 6 0;
+#X connect 1 0 9 1;
+#X connect 2 0 9 2;
+#X connect 3 0 9 0;
+#X connect 4 0 9 0;
+#X connect 5 0 10 1;
+#X connect 6 0 3 0;
+#X connect 6 0 10 0;
+#X connect 9 0 7 0;
+#X connect 10 0 4 0;
diff --git a/abs/eadsrh~.pd b/abs/eadsrh~.pd
new file mode 100644
index 0000000..a1c7da5
--- /dev/null
+++ b/abs/eadsrh~.pd
@@ -0,0 +1,27 @@
+#N canvas 127 436 524 279 10;
+#X obj 34 27 inlet;
+#X obj 84 27 inlet;
+#X obj 133 27 inlet;
+#X msg 44 108 start;
+#X msg 306 113 stop;
+#X obj 354 31 inlet;
+#X msg 34 49 bang;
+#X obj 44 187 outlet~;
+#X text 13 6 trigger - attack - decay - sustain - release - duration
+;
+#X obj 44 144 eadsr~ \$1 \$2 \$3 \$4;
+#X obj 306 84 del \$5;
+#X obj 211 27 inlet;
+#X obj 260 27 inlet;
+#X connect 0 0 6 0;
+#X connect 1 0 9 1;
+#X connect 2 0 9 2;
+#X connect 3 0 9 0;
+#X connect 4 0 9 0;
+#X connect 5 0 10 1;
+#X connect 6 0 3 0;
+#X connect 6 0 10 0;
+#X connect 9 0 7 0;
+#X connect 10 0 4 0;
+#X connect 11 0 9 3;
+#X connect 12 0 9 4;
diff --git a/abs/fblock.pd b/abs/fblock.pd
new file mode 100644
index 0000000..dbbf41e
--- /dev/null
+++ b/abs/fblock.pd
@@ -0,0 +1,25 @@
+#N canvas 73 29 617 246 10;
+#X obj 36 36 inlet;
+#X obj 101 35 inlet;
+#X obj 42 196 outlet;
+#X obj 104 83 samplerate~;
+#X obj 101 115 / \$1;
+#X obj 59 158 +;
+#X obj 103 144 *;
+#X obj 103 59 t b b f;
+#X text 200 35 fblock: compute block relative frequencies;
+#X text 200 79 right inlet is also "active";
+#X text 201 119 main usage is to compute block synchronous frequencies
+;
+#X text 200 134 for spectral domain processing;
+#X text 201 49 out = left + right * (sys samplerate / sys blocksize)
+;
+#X connect 0 0 5 0;
+#X connect 1 0 7 0;
+#X connect 3 0 4 0;
+#X connect 4 0 6 0;
+#X connect 5 0 2 0;
+#X connect 6 0 5 1;
+#X connect 7 0 5 0;
+#X connect 7 1 3 0;
+#X connect 7 2 6 1;
diff --git a/abs/inv.pd b/abs/inv.pd
new file mode 100644
index 0000000..b465178
--- /dev/null
+++ b/abs/inv.pd
@@ -0,0 +1,8 @@
+#N canvas 329 434 450 300 10;
+#X obj 68 45 inlet;
+#X obj 67 130 outlet;
+#X obj 68 71 + 1;
+#X obj 68 96 mod 2;
+#X connect 0 0 2 0;
+#X connect 2 0 3 0;
+#X connect 3 0 1 0;
diff --git a/abs/pdynwav~.pd b/abs/pdynwav~.pd
new file mode 100644
index 0000000..a4da3f1
--- /dev/null
+++ b/abs/pdynwav~.pd
@@ -0,0 +1,10 @@
+#N canvas 164 313 194 151 10;
+#X obj 30 24 inlet~;
+#X obj 110 23 inlet;
+#X obj 30 98 outlet~;
+#X obj 110 49 phasor~;
+#X obj 30 67 dynwav~;
+#X connect 0 0 4 0;
+#X connect 1 0 3 0;
+#X connect 3 0 4 1;
+#X connect 4 0 2 0;
diff --git a/abs/scale7.pd b/abs/scale7.pd
new file mode 100644
index 0000000..b4f0935
--- /dev/null
+++ b/abs/scale7.pd
@@ -0,0 +1,40 @@
+#N canvas 647 521 450 373 10;
+#X obj 152 175 select 0 1 2 3 4 5 6;
+#X obj 224 115 unpack 0 0 0 0 0 0 0;
+#X obj 225 59 inlet;
+#X obj 57 51 inlet;
+#X obj 154 97 mod 7;
+#X text 219 37 scale input;
+#X text 48 29 note input;
+#X obj 224 287 outlet;
+#X obj 153 220 f;
+#X obj 185 221 f;
+#X obj 217 221 f;
+#X obj 248 220 f;
+#X obj 280 218 f;
+#X obj 311 214 f;
+#X obj 343 212 f;
+#X connect 0 0 8 0;
+#X connect 0 1 9 0;
+#X connect 0 2 10 0;
+#X connect 0 3 11 0;
+#X connect 0 4 12 0;
+#X connect 0 5 13 0;
+#X connect 0 6 14 0;
+#X connect 1 0 8 1;
+#X connect 1 1 9 1;
+#X connect 1 2 10 1;
+#X connect 1 3 11 1;
+#X connect 1 4 12 1;
+#X connect 1 5 13 1;
+#X connect 1 6 14 1;
+#X connect 2 0 1 0;
+#X connect 3 0 4 0;
+#X connect 4 0 0 0;
+#X connect 8 0 7 0;
+#X connect 9 0 7 0;
+#X connect 10 0 7 0;
+#X connect 11 0 7 0;
+#X connect 12 0 7 0;
+#X connect 13 0 7 0;
+#X connect 14 0 7 0;
diff --git a/abs/vols~.pd b/abs/vols~.pd
new file mode 100644
index 0000000..aa87a8d
--- /dev/null
+++ b/abs/vols~.pd
@@ -0,0 +1,24 @@
+#N canvas 441 433 450 300 10;
+#X obj 68 21 inlet~;
+#X obj 122 22 inlet;
+#X obj 80 104 *~;
+#X obj 77 141 outlet~;
+#X obj 116 42 dbtorms;
+#X obj 114 92 line~;
+#X msg 112 66 \$1 5;
+#X obj 215 34 loadbang;
+#X obj 218 66 f \$1;
+#X obj 6 22 inlet~;
+#X obj 18 105 *~;
+#X obj 15 142 outlet~;
+#X connect 0 0 2 0;
+#X connect 1 0 4 0;
+#X connect 2 0 3 0;
+#X connect 4 0 6 0;
+#X connect 5 0 2 1;
+#X connect 5 0 10 1;
+#X connect 6 0 5 0;
+#X connect 7 0 8 0;
+#X connect 8 0 4 0;
+#X connect 9 0 10 0;
+#X connect 10 0 11 0;
diff --git a/abs/vol~.pd b/abs/vol~.pd
new file mode 100644
index 0000000..2fcc995
--- /dev/null
+++ b/abs/vol~.pd
@@ -0,0 +1,18 @@
+#N canvas 441 433 450 300 10;
+#X obj 68 21 inlet~;
+#X obj 122 22 inlet;
+#X obj 80 104 *~;
+#X obj 77 141 outlet~;
+#X obj 116 42 dbtorms;
+#X obj 114 92 line~;
+#X msg 112 66 \$1 5;
+#X obj 215 34 loadbang;
+#X obj 218 66 f \$1;
+#X connect 0 0 2 0;
+#X connect 1 0 4 0;
+#X connect 2 0 3 0;
+#X connect 4 0 6 0;
+#X connect 5 0 2 1;
+#X connect 6 0 5 0;
+#X connect 7 0 8 0;
+#X connect 8 0 4 0;
diff --git a/doc/bdiag~.pd b/doc/bdiag~.pd
new file mode 100644
index 0000000..f5e835f
--- /dev/null
+++ b/doc/bdiag~.pd
@@ -0,0 +1,97 @@
+#N canvas 34 203 724 407 10;
+#X obj 34 45 metro;
+#X msg 34 20 bang;
+#X floatatom 76 20 5 0 0;
+#X obj 34 327 dist~ 1;
+#X obj 24 359 dac~;
+#N canvas 731 115 262 403 systemparams 1;
+#X floatatom 81 47 5 0 0;
+#X floatatom 125 47 5 0 0;
+#X floatatom 81 74 5 0 0;
+#X floatatom 125 74 5 0 0;
+#X floatatom 81 102 5 0 0;
+#X floatatom 125 102 5 0 0;
+#X floatatom 81 129 5 0 0;
+#X floatatom 125 129 5 0 0;
+#X floatatom 81 157 5 0 0;
+#X floatatom 125 157 5 0 0;
+#X floatatom 81 184 5 0 0;
+#X floatatom 125 184 5 0 0;
+#X floatatom 81 212 5 0 0;
+#X floatatom 125 212 5 0 0;
+#X floatatom 81 239 5 0 0;
+#X floatatom 125 239 5 0 0;
+#X obj 28 65 bdft 1;
+#X obj 27 93 bdft 2;
+#X obj 28 120 bdft 3;
+#X obj 28 175 bdft 7;
+#X obj 28 202 bdft 11;
+#X obj 28 230 bdft 17;
+#X obj 28 257 bdft 30;
+#X obj 28 319 outlet;
+#X text 20 23 frequency detune and damping;
+#X text 49 283 bdft argument = harmonic;
+#X obj 28 147 bdft 5;
+#X connect 0 0 16 0;
+#X connect 1 0 16 1;
+#X connect 2 0 17 0;
+#X connect 3 0 17 1;
+#X connect 4 0 18 0;
+#X connect 5 0 18 1;
+#X connect 6 0 26 0;
+#X connect 7 0 26 1;
+#X connect 8 0 19 0;
+#X connect 9 0 19 1;
+#X connect 10 0 20 0;
+#X connect 11 0 20 1;
+#X connect 12 0 21 0;
+#X connect 13 0 21 1;
+#X connect 14 0 22 0;
+#X connect 15 0 22 1;
+#X connect 16 0 23 0;
+#X connect 17 0 23 0;
+#X connect 18 0 23 0;
+#X connect 19 0 23 0;
+#X connect 20 0 23 0;
+#X connect 21 0 23 0;
+#X connect 22 0 23 0;
+#X connect 26 0 23 0;
+#X restore 89 76 pd systemparams;
+#X obj 34 93 bdiag~;
+#X obj 34 129 ibfft~;
+#X obj 34 232 dynwav~;
+#X obj 34 283 vol~;
+#X floatatom 57 257 5 0 0;
+#X floatatom 78 168 5 0 0;
+#X obj 78 196 phasor~;
+#X text 258 168 the [eig <index> <real> <imag>] message sets the eigenvalue
+for the corresponding block. there are n/2 blocks \, with n the dsp
+blocksize.;
+#X text 259 223 you can use [timefreq <index> <60dB time> <frequency>]
+for a more appropriate initialization of the eigenvalues using decay
+time in milliseconds and oscillation frequency in Hz.;
+#X text 256 18 bdiag~: parallel block diagonal state space model (parallel
+2d rotations) see bdiag.c for more info. the state equations for one
+block are:;
+#X text 300 70 state1 = real * state1 - imag * state2 + input1;
+#X text 300 85 state2 = real * state2 + imag * state1 + input2;
+#X text 258 121 this module is intended to "filter" spectral data produced
+by bfft or other short time spectral transforms like dwt.;
+#X text 256 279 [bang] or [random] set the state vector to a random
+value. [reset] sets it to 0;
+#X text 256 327 this patch uses of bdiag~ \, ibfft~ and dynwav~ to
+build a 32 voice harmonic modal synth \, with the state excited with
+white noise on bang.;
+#X connect 0 0 6 0;
+#X connect 1 0 0 0;
+#X connect 2 0 0 1;
+#X connect 3 0 4 0;
+#X connect 3 0 4 1;
+#X connect 5 0 6 0;
+#X connect 6 0 7 0;
+#X connect 7 0 8 0;
+#X connect 8 0 9 0;
+#X connect 9 0 3 0;
+#X connect 10 0 9 1;
+#X connect 11 0 12 0;
+#X connect 12 0 8 1;
diff --git a/doc/bfft~.pd b/doc/bfft~.pd
new file mode 100644
index 0000000..62507f9
--- /dev/null
+++ b/doc/bfft~.pd
@@ -0,0 +1,18 @@
+#N canvas 488 64 480 309 10;
+#X obj 17 62 osc~ 500;
+#X floatatom 17 -11 5 0 0;
+#X obj 17 23 * 187.5;
+#X obj 17 180 tabsend~ scope;
+#N canvas 0 0 450 300 graph2 0;
+#X array scope 64 float 0;
+#X coords 0 1 63 -1 200 140 1;
+#X restore 233 16 graph;
+#X obj 18 113 bfft~;
+#X obj 71 112 ibfft~;
+#X text 12 -60 spectrum: (DC \, NY) \, (R1 \, I1) \, ...(RN-1 \, IN-1)
+;
+#X text 13 -74 like fft~ but normalized and;
+#X connect 0 0 5 0;
+#X connect 1 0 2 0;
+#X connect 2 0 0 0;
+#X connect 5 0 3 0;
diff --git a/doc/biquadseries~.pd b/doc/biquadseries~.pd
new file mode 100644
index 0000000..89d7ce0
--- /dev/null
+++ b/doc/biquadseries~.pd
@@ -0,0 +1,22 @@
+#N canvas 389 207 533 299 10;
+#X obj 37 246 dac~;
+#X msg 81 132 butterLP \$1;
+#X msg 173 131 butterHP \$1;
+#X floatatom 81 105 5 0 0;
+#X floatatom 173 104 5 0 0;
+#X obj 48 78 *~;
+#X floatatom 82 55 5 0 0;
+#X obj 48 35 noise~;
+#X text 269 132 butterworth lowpass and highpass;
+#X text 181 178 creation argument: number of 2nd order sections;
+#X obj 48 178 biquadseries~ 4;
+#X text 173 22 biquadseries~ second order iir series section;
+#X connect 1 0 10 0;
+#X connect 2 0 10 0;
+#X connect 3 0 1 0;
+#X connect 4 0 2 0;
+#X connect 5 0 10 0;
+#X connect 6 0 5 1;
+#X connect 7 0 5 0;
+#X connect 10 0 0 0;
+#X connect 10 0 0 1;
diff --git a/doc/cheby~.pd b/doc/cheby~.pd
new file mode 100644
index 0000000..30bb77e
--- /dev/null
+++ b/doc/cheby~.pd
@@ -0,0 +1,43 @@
+#N canvas 262 87 566 348 10;
+#X obj 130 230 cheby~ 4;
+#X msg 147 149 coef 1 \$1;
+#X floatatom 147 93 5 0 0;
+#X obj 147 117 dbtorms;
+#X obj 124 313 dac~;
+#X obj 130 281 vol~;
+#X floatatom 156 261 5 0 0;
+#X obj 40 113 osc~;
+#X floatatom 40 88 5 0 0;
+#X floatatom 226 94 5 0 0;
+#X obj 226 118 dbtorms;
+#X floatatom 305 94 5 0 0;
+#X obj 305 118 dbtorms;
+#X floatatom 384 93 5 0 0;
+#X obj 384 117 dbtorms;
+#X msg 226 150 coef 2 \$1;
+#X msg 305 150 coef 3 \$1;
+#X msg 384 150 coef 4 \$1;
+#X text 96 3 chebychev waveshaper;
+#X text 207 229 creation argument: order of polynomial;
+#X text 135 47 coef n x sets coefficient of nth order cheby poly to
+x;
+#X text 135 60 if the input is a sine wave \, these are the amplitudes
+for the harmonics.;
+#X connect 0 0 5 0;
+#X connect 1 0 0 0;
+#X connect 2 0 3 0;
+#X connect 3 0 1 0;
+#X connect 5 0 4 1;
+#X connect 5 0 4 0;
+#X connect 6 0 5 1;
+#X connect 7 0 0 0;
+#X connect 8 0 7 0;
+#X connect 9 0 10 0;
+#X connect 10 0 15 0;
+#X connect 11 0 12 0;
+#X connect 12 0 16 0;
+#X connect 13 0 14 0;
+#X connect 14 0 17 0;
+#X connect 15 0 0 0;
+#X connect 16 0 0 0;
+#X connect 17 0 0 0;
diff --git a/doc/dist~.pd b/doc/dist~.pd
new file mode 100644
index 0000000..3533471
--- /dev/null
+++ b/doc/dist~.pd
@@ -0,0 +1,17 @@
+#N canvas 497 336 450 300 10;
+#X text 156 35 dist~ waveshaper;
+#X text 154 53 creation argument: type (see dist.c);
+#X floatatom 136 120 5 0 0;
+#X obj 64 121 osc~;
+#X obj 66 206 dac~;
+#X floatatom 63 84 5 0 0;
+#X text 189 119 right inlet: pre gain;
+#X obj 148 95 hsl 128 15 0.5 20 0 0 empty empty empty -2 -6 32 8 -262144
+-1 -1 7000 1;
+#X obj 64 157 dist~ 1;
+#X connect 2 0 8 1;
+#X connect 3 0 8 0;
+#X connect 5 0 3 0;
+#X connect 7 0 2 0;
+#X connect 8 0 4 0;
+#X connect 8 0 4 1;
diff --git a/doc/dwt~.pd b/doc/dwt~.pd
new file mode 100644
index 0000000..52986e1
--- /dev/null
+++ b/doc/dwt~.pd
@@ -0,0 +1,72 @@
+#N canvas 47 99 994 611 10;
+#X obj 17 62 osc~ 500;
+#X msg 83 -115 predict 0.5 0.5 \, update 0.25 0.25;
+#X msg 83 -76 predict -0.0625 0.5625 0.5625 -0.0625 \, update -0.03125
+0.28125 0.28125 -0.03125;
+#X floatatom 24 10 5 0 0;
+#X msg 201 144 mask -1 9 9 -1;
+#X obj 67 279 r coef;
+#X obj 82 -30 s coef;
+#X obj 195 337 s coef;
+#X msg 201 167 mask 3 -25 150 150 -25 3;
+#X msg 216 189 mask -5 49 -245 1225 1225 -245 49 -5;
+#X obj 196 39 pack;
+#X floatatom 222 8 5 0 0;
+#X floatatom 166 -4 5 0 0;
+#X msg 171 64 coef \$1 \$2;
+#X msg 191 120 mask 1 1;
+#X msg 228 212 mask 35 -405 2268 -8820 39690 39690 -8820 2268 -405
+35;
+#X msg 244 246 mask -63 847 -5445 22869 -76230 320166 320166 -76230
+22869 -5445 847 -63;
+#X msg 245 306 predict 1 0 \, update 0 0.5;
+#X obj 36 31 * 187.5;
+#X obj 26 341 dwt~ 1;
+#X obj 80 343 idwt~ 1;
+#X msg 469 376 mask 0 0 0 35 140 -70 28 -5;
+#X msg 469 352 mask 7 -45 126 -210 315 63 0 0 0 0;
+#X msg 469 328 mask -21 154 -495 924 -1155 1386 231 0 0 0 0 0;
+#X obj 26 443 tabsend~ scope;
+#N canvas 0 0 450 300 graph2 0;
+#X array scope 256 float 0;
+#X coords 0 1 255 -1 200 140 1;
+#X restore 718 -98 graph;
+#X text 61 165 print out coefs;
+#X msg 100 184 print;
+#X text 315 -24 dwt~ performs a discrete wavelet transform;
+#X text 315 -10 idwt~ performs the inverse transform;
+#X text 309 105 mask sets the predict mask \, and uses the corresponding
+update mask;
+#X text 266 63 coef sets half of a symmetric predict mask;
+#X text 243 286 predict and update masks can be specified explicitly
+;
+#X text 433 307 haar wavelet;
+#X msg 672 189 even \$1;
+#X floatatom 672 167 5 0 0;
+#X text 570 134 even <n> is the order symmetric interpolating biorthogonal
+wavelet with n vanishing moments.;
+#X connect 0 0 19 0;
+#X connect 1 0 6 0;
+#X connect 2 0 6 0;
+#X connect 3 0 18 0;
+#X connect 4 0 7 0;
+#X connect 5 0 20 0;
+#X connect 5 0 19 0;
+#X connect 8 0 7 0;
+#X connect 9 0 7 0;
+#X connect 10 0 13 0;
+#X connect 11 0 10 1;
+#X connect 12 0 10 0;
+#X connect 13 0 7 0;
+#X connect 14 0 7 0;
+#X connect 15 0 7 0;
+#X connect 16 0 7 0;
+#X connect 17 0 7 0;
+#X connect 18 0 0 0;
+#X connect 19 0 24 0;
+#X connect 21 0 7 0;
+#X connect 22 0 7 0;
+#X connect 23 0 7 0;
+#X connect 27 0 7 0;
+#X connect 34 0 7 0;
+#X connect 35 0 34 0;
diff --git a/doc/dynwav~.pd b/doc/dynwav~.pd
new file mode 100644
index 0000000..59f86bd
--- /dev/null
+++ b/doc/dynwav~.pd
@@ -0,0 +1,25 @@
+#N canvas 193 151 450 300 10;
+#X text 96 6 dynwav~: dynamic wavetable oscillator;
+#X obj 61 98 osc~;
+#X floatatom 60 56 5 0 0;
+#X obj 60 151 dynwav~;
+#X obj 60 214 vol~;
+#X floatatom 85 190 5 0 0;
+#X obj 50 256 dac~;
+#X obj 172 105 phasor~;
+#X floatatom 172 80 5 0 0;
+#X obj 107 54 bang~;
+#X text 171 22 (scanned synthesis);
+#X text 165 143 left inlet's dsp block = wavetable;
+#X msg 107 78 0.25;
+#X text 242 157 right inlet = phase (0-1);
+#X connect 1 0 3 0;
+#X connect 2 0 1 0;
+#X connect 3 0 4 0;
+#X connect 4 0 6 1;
+#X connect 4 0 6 0;
+#X connect 5 0 4 1;
+#X connect 7 0 3 1;
+#X connect 8 0 7 0;
+#X connect 9 0 12 0;
+#X connect 12 0 1 1;
diff --git a/doc/eadsr~.pd b/doc/eadsr~.pd
new file mode 100644
index 0000000..220ea54
--- /dev/null
+++ b/doc/eadsr~.pd
@@ -0,0 +1,41 @@
+#N canvas 478 386 580 306 10;
+#X obj 89 227 *~;
+#X obj 105 40 metro;
+#X obj 105 12 bng 15 250 50 0 empty empty empty 0 -6 32 8 -262144 -1
+-1;
+#X obj 26 203 osc~;
+#X floatatom 26 171 5 0 0;
+#X floatatom 135 12 5 0 0;
+#X floatatom 209 117 5 0 0;
+#X floatatom 208 139 5 0 0;
+#X obj 77 265 dac~;
+#X msg 58 12 stop;
+#X msg 26 124 start;
+#X msg 71 123 stop;
+#X obj 105 77 del;
+#X floatatom 159 50 5 0 0;
+#X obj 105 197 eadsr~ 0 0;
+#X text 191 81 exponential attack/decay/sustain/release envelope;
+#X text 265 125 60db attack and decay time;
+#X text 265 182 60db attack and decay time;
+#X floatatom 209 160 5 0 0;
+#X floatatom 209 180 5 0 0;
+#X text 264 159 sustain level;
+#X connect 0 0 8 0;
+#X connect 0 0 8 1;
+#X connect 1 0 10 0;
+#X connect 1 0 12 0;
+#X connect 2 0 1 0;
+#X connect 3 0 0 0;
+#X connect 4 0 3 0;
+#X connect 5 0 1 1;
+#X connect 6 0 14 1;
+#X connect 7 0 14 2;
+#X connect 9 0 1 0;
+#X connect 10 0 14 0;
+#X connect 11 0 14 0;
+#X connect 12 0 11 0;
+#X connect 13 0 12 1;
+#X connect 14 0 0 1;
+#X connect 18 0 14 3;
+#X connect 19 0 14 4;
diff --git a/doc/ead~.pd b/doc/ead~.pd
new file mode 100644
index 0000000..9d9bc5f
--- /dev/null
+++ b/doc/ead~.pd
@@ -0,0 +1,29 @@
+#N canvas 478 386 459 306 10;
+#X obj 105 111 ead~ 0 0;
+#X obj 89 179 *~;
+#X obj 105 40 metro;
+#X obj 105 12 bng 15 250 50 0 empty empty empty 0 -6 32 8 -262144 -1
+-1;
+#X obj 41 144 osc~;
+#X floatatom 41 112 5 0 0;
+#X floatatom 135 12 5 0 0;
+#X floatatom 130 64 5 0 0;
+#X floatatom 156 86 5 0 0;
+#X obj 77 217 dac~;
+#X text 202 71 60db attack and decay time;
+#X obj 70 76 bng 15 250 50 0 empty empty empty 0 -6 32 8 -262144 -1
+-1;
+#X msg 58 12 stop;
+#X text 201 51 exponential attack/decay envelope;
+#X connect 0 0 1 1;
+#X connect 1 0 9 0;
+#X connect 1 0 9 1;
+#X connect 2 0 0 0;
+#X connect 3 0 2 0;
+#X connect 4 0 1 0;
+#X connect 5 0 4 0;
+#X connect 6 0 2 1;
+#X connect 7 0 0 1;
+#X connect 8 0 0 2;
+#X connect 11 0 0 0;
+#X connect 12 0 2 0;
diff --git a/doc/ear~.pd b/doc/ear~.pd
new file mode 100644
index 0000000..8527a12
--- /dev/null
+++ b/doc/ear~.pd
@@ -0,0 +1,35 @@
+#N canvas 478 386 459 306 10;
+#X obj 89 227 *~;
+#X obj 105 40 metro;
+#X obj 105 12 bng 15 250 50 0 empty empty empty 0 -6 32 8 -262144 -1
+-1;
+#X obj 41 192 osc~;
+#X floatatom 41 160 5 0 0;
+#X floatatom 135 12 5 0 0;
+#X floatatom 130 112 5 0 0;
+#X floatatom 157 134 5 0 0;
+#X obj 77 265 dac~;
+#X msg 58 12 stop;
+#X msg 26 124 start;
+#X msg 71 123 stop;
+#X obj 105 159 ear~ 0 0;
+#X obj 105 77 del;
+#X floatatom 159 50 5 0 0;
+#X text 201 99 exponential attack/release envelope;
+#X text 202 119 60db attack and release time;
+#X connect 0 0 8 0;
+#X connect 0 0 8 1;
+#X connect 1 0 10 0;
+#X connect 1 0 13 0;
+#X connect 2 0 1 0;
+#X connect 3 0 0 0;
+#X connect 4 0 3 0;
+#X connect 5 0 1 1;
+#X connect 6 0 12 1;
+#X connect 7 0 12 2;
+#X connect 9 0 1 0;
+#X connect 10 0 12 0;
+#X connect 11 0 12 0;
+#X connect 12 0 0 1;
+#X connect 13 0 11 0;
+#X connect 14 0 13 1;
diff --git a/doc/examples/xfmdelay.pd b/doc/examples/xfmdelay.pd
new file mode 100644
index 0000000..078733a
--- /dev/null
+++ b/doc/examples/xfmdelay.pd
@@ -0,0 +1,106 @@
+#N canvas 25 206 921 653 10;
+#X obj 289 329 xfm~ 0 0 0 0;
+#X obj 279 280 *~;
+#X obj 398 233 nbx 5 14 -1e+37 1e+37 0 1 empty empty empty 0 -6 0 10
+-262144 -1 -1 862.744 256;
+#X obj 306 279 *~;
+#X obj 398 250 nbx 5 14 -1e+37 1e+37 0 1 empty empty empty 0 -6 0 10
+-262144 -1 -1 795.103 256;
+#X obj 332 279 *~;
+#X obj 399 266 nbx 5 14 -1e+37 1e+37 0 1 empty empty empty 0 -6 0 10
+-262144 -1 -1 23.7527 256;
+#X obj 359 278 *~;
+#X obj 398 284 nbx 5 14 -1e+37 1e+37 0 1 empty empty empty 0 -6 0 10
+-262144 -1 -1 224.294 256;
+#X obj 251 170 xfm~ 0 0 0 0;
+#X obj 392 111 nbx 5 14 -1e+37 1e+37 0 1 empty empty empty 0 -6 0 10
+-262144 -1 -1 703.454 256;
+#X obj 392 132 nbx 5 14 -1e+37 1e+37 0 1 empty empty empty 0 -6 0 10
+-262144 -1 -1 675.315 256;
+#X obj 304 138 *~;
+#X obj 393 148 nbx 5 14 -1e+37 1e+37 0 1 empty empty empty 0 -6 0 10
+-262144 -1 -1 51.5902 256;
+#X obj 331 137 *~;
+#X obj 392 166 nbx 5 14 -1e+37 1e+37 0 1 empty empty empty 0 -6 0 10
+-262144 -1 -1 49.5265 256;
+#X obj 191 403 vols~;
+#X floatatom 233 374 5 0 0;
+#X obj 195 525 dac~;
+#X obj 274 51 vd~ del1;
+#X obj 274 24 nbx 5 14 -1e+37 1e+37 0 1 empty empty empty 0 -6 0 10
+-262144 -1 -1 73 256;
+#X obj 339 23 nbx 5 14 -1e+37 1e+37 0 1 empty empty empty 0 -6 0 10
+-262144 -1 -1 339 256;
+#X obj 339 50 vd~ del2;
+#X obj 296 393 delwrite~ del1 1000;
+#X obj 448 393 delwrite~ del2 1000;
+#X msg 136 125 type 0;
+#X msg 137 146 type 1;
+#X obj 464 110 hsl 300 15 0.1 20000 1 1 empty empty empty -2 -6 0 8
+-262144 -1 -1 21700 1;
+#X obj 464 130 hsl 300 15 0.1 20000 1 1 empty empty empty -2 -6 0 8
+-262144 -1 -1 21600 1;
+#X obj 463 150 hsl 300 15 0.1 20000 1 1 empty empty empty -2 -6 0 8
+-262144 -1 -1 15300 1;
+#X obj 464 168 hsl 300 15 0.1 20000 1 1 empty empty empty -2 -6 0 8
+-262144 -1 -1 15200 1;
+#X obj 465 232 hsl 300 15 0.1 20000 1 1 empty empty empty -2 -6 0 8
+-262144 -1 -1 22200 1;
+#X obj 465 252 hsl 300 15 0.1 20000 1 1 empty empty empty -2 -6 0 8
+-262144 -1 -1 22000 1;
+#X obj 464 271 hsl 300 15 0.1 20000 1 1 empty empty empty -2 -6 0 8
+-262144 -1 -1 13400 1;
+#X obj 465 289 hsl 300 15 0.1 20000 1 1 empty empty empty -2 -6 0 8
+-262144 -1 -1 18900 1;
+#X text 479 29 2 xfm oscillators coupled by 2 delay lines;
+#X obj 188 475 *~;
+#X obj 217 474 *~;
+#X obj 270 458 osc~;
+#X obj 269 433 hsl 300 15 0.1 20000 1 1 empty empty empty -2 -6 0 8
+-262144 -1 -1 18900 1;
+#X connect 0 0 23 0;
+#X connect 0 1 24 0;
+#X connect 1 0 0 0;
+#X connect 2 0 1 1;
+#X connect 3 0 0 1;
+#X connect 4 0 3 1;
+#X connect 5 0 0 2;
+#X connect 6 0 5 1;
+#X connect 7 0 0 3;
+#X connect 8 0 7 1;
+#X connect 9 0 3 0;
+#X connect 9 0 5 0;
+#X connect 9 0 16 0;
+#X connect 9 1 1 0;
+#X connect 9 1 7 0;
+#X connect 9 1 16 1;
+#X connect 10 0 9 0;
+#X connect 11 0 9 1;
+#X connect 12 0 9 2;
+#X connect 13 0 12 1;
+#X connect 14 0 9 3;
+#X connect 15 0 14 1;
+#X connect 16 0 36 0;
+#X connect 16 1 37 0;
+#X connect 17 0 16 2;
+#X connect 19 0 12 0;
+#X connect 20 0 19 0;
+#X connect 21 0 22 0;
+#X connect 22 0 14 0;
+#X connect 25 0 9 0;
+#X connect 25 0 0 0;
+#X connect 26 0 9 0;
+#X connect 26 0 0 0;
+#X connect 27 0 10 0;
+#X connect 28 0 11 0;
+#X connect 29 0 13 0;
+#X connect 30 0 15 0;
+#X connect 31 0 2 0;
+#X connect 32 0 4 0;
+#X connect 33 0 6 0;
+#X connect 34 0 8 0;
+#X connect 36 0 18 0;
+#X connect 37 0 18 1;
+#X connect 38 0 37 1;
+#X connect 38 0 36 1;
+#X connect 39 0 38 0;
diff --git a/doc/ffpoly.pd b/doc/ffpoly.pd
new file mode 100644
index 0000000..7ec8886
--- /dev/null
+++ b/doc/ffpoly.pd
@@ -0,0 +1,35 @@
+#N canvas 372 77 515 425 10;
+#X text 85 14 ffpoly - compute a finite field polynomial;
+#X msg 103 89 coef 0 \$1;
+#X floatatom 103 65 5 0 0;
+#X floatatom 181 65 5 0 0;
+#X floatatom 257 65 5 0 0;
+#X floatatom 334 64 5 0 0;
+#X msg 181 89 coef 1 \$1;
+#X msg 257 89 coef 2 \$1;
+#X msg 334 89 coef 3 \$1;
+#X floatatom 38 106 5 0 0;
+#X obj 38 350 ffpoly 3 5;
+#X text 125 350 creation args: <poly order> <field order>;
+#X floatatom 38 384 5 0 0;
+#X msg 334 150 order \$1;
+#X floatatom 334 125 5 0 0;
+#X text 332 174 finite field order;
+#X floatatom 335 217 5 0 0;
+#X msg 335 242 coefficients \$1;
+#X text 271 279 set coefs in packed form;
+#X text 203 292 digit representation in base = field order;
+#X connect 1 0 10 0;
+#X connect 2 0 1 0;
+#X connect 3 0 6 0;
+#X connect 4 0 7 0;
+#X connect 5 0 8 0;
+#X connect 6 0 10 0;
+#X connect 7 0 10 0;
+#X connect 8 0 10 0;
+#X connect 9 0 10 0;
+#X connect 10 0 12 0;
+#X connect 13 0 10 0;
+#X connect 14 0 13 0;
+#X connect 16 0 17 0;
+#X connect 17 0 10 0;
diff --git a/doc/filterortho~.pd b/doc/filterortho~.pd
new file mode 100644
index 0000000..e120101
--- /dev/null
+++ b/doc/filterortho~.pd
@@ -0,0 +1,58 @@
+#N canvas 634 361 578 534 10;
+#X obj 146 452 dac~;
+#X floatatom 255 83 7 0 0;
+#X floatatom 194 83 7 0 0;
+#X obj 158 405 filterortho~;
+#X obj 194 123 t b f;
+#X floatatom 29 31 5 0 0;
+#X obj 13 9 noise~;
+#X floatatom 133 83 7 0 0;
+#X obj 150 123 t b f;
+#X obj 13 52 *~;
+#X text 333 9 orthogonal biquad object;
+#X obj 157 330 pack s 0 0 0;
+#X obj 237 122 t b f;
+#X text 137 61 freq;
+#X text 213 61 Q;
+#X msg 335 126 setEQ;
+#X msg 335 150 setLP;
+#X msg 158 363 \$1 \$2 \$3 \$4;
+#X msg 336 175 setHP;
+#X msg 336 201 setBP;
+#X msg 336 225 setBR;
+#X msg 336 251 setHS;
+#X msg 337 275 setLS;
+#X msg 338 299 setAP;
+#X text 391 127 parametric equalizer;
+#X text 390 150 lowpass;
+#X text 391 175 highpass;
+#X text 391 201 bandpass;
+#X text 391 224 bandreject;
+#X text 390 252 highshelf;
+#X text 390 277 lowshelf;
+#X text 391 300 allpass;
+#X text 265 62 gain (only for EQ \, LS \, HS);
+#X connect 1 0 12 0;
+#X connect 2 0 4 0;
+#X connect 3 0 0 0;
+#X connect 3 0 0 1;
+#X connect 4 0 11 0;
+#X connect 4 1 11 2;
+#X connect 5 0 9 1;
+#X connect 6 0 9 0;
+#X connect 7 0 8 0;
+#X connect 8 0 11 0;
+#X connect 8 1 11 1;
+#X connect 9 0 3 0;
+#X connect 11 0 17 0;
+#X connect 12 0 11 0;
+#X connect 12 1 11 3;
+#X connect 15 0 11 0;
+#X connect 16 0 11 0;
+#X connect 17 0 3 0;
+#X connect 18 0 11 0;
+#X connect 19 0 11 0;
+#X connect 20 0 11 0;
+#X connect 21 0 11 0;
+#X connect 22 0 11 0;
+#X connect 23 0 11 0;
diff --git a/doc/fwarp.pd b/doc/fwarp.pd
new file mode 100644
index 0000000..d43a5a3
--- /dev/null
+++ b/doc/fwarp.pd
@@ -0,0 +1,37 @@
+#N canvas 403 309 522 388 10;
+#X obj 18 85 fwarp;
+#X floatatom 18 53 5 0 0;
+#X floatatom 18 121 7 0 0;
+#X text 112 49 fwarp - warps a frequency using the formula;
+#X obj 173 261 xfm~ 0 0 0 0;
+#X obj 173 218 fwarp;
+#X floatatom 173 186 5 0 0;
+#X obj 117 260 osc~;
+#X obj 152 324 vol~;
+#X obj 152 350 dac~;
+#X floatatom 212 298 5 0 0;
+#X obj 351 263 xfm~ 0 0 0 0;
+#X floatatom 351 188 5 0 0;
+#X obj 295 262 osc~;
+#X obj 330 326 vol~;
+#X obj 330 352 dac~;
+#X floatatom 390 300 5 0 0;
+#X text 132 126 example: xfm~ uses warped frequencies;
+#X text 112 67 out = tan(2pi*in/sr) * (sr/2pi);
+#X connect 0 0 2 0;
+#X connect 1 0 0 0;
+#X connect 4 0 8 0;
+#X connect 5 0 4 0;
+#X connect 6 0 5 0;
+#X connect 6 0 7 0;
+#X connect 7 0 8 0;
+#X connect 8 0 9 0;
+#X connect 8 0 9 1;
+#X connect 10 0 8 1;
+#X connect 11 0 14 0;
+#X connect 12 0 13 0;
+#X connect 12 0 11 0;
+#X connect 13 0 14 0;
+#X connect 14 0 15 0;
+#X connect 14 0 15 1;
+#X connect 16 0 14 1;
diff --git a/doc/lattice~.pd b/doc/lattice~.pd
new file mode 100644
index 0000000..4545470
--- /dev/null
+++ b/doc/lattice~.pd
@@ -0,0 +1,63 @@
+#N canvas 338 162 527 557 10;
+#X obj 57 -77 vsl 15 250 -1 1 0 1 empty empty empty 20 8 32 8 -262144
+-1 -1 12100 1;
+#X msg 57 223 rc 0 \$1;
+#X obj 88 -78 vsl 15 250 -1 1 0 1 empty empty empty 20 8 32 8 -262144
+-1 -1 7150 1;
+#X obj 119 -77 vsl 15 250 -1 1 0 1 empty empty empty 20 8 32 8 -262144
+-1 -1 5150 1;
+#X obj 149 -77 vsl 15 250 -1 1 0 1 empty empty empty 20 8 32 8 -262144
+-1 -1 8100 1;
+#X obj 179 -77 vsl 15 250 -1 1 0 1 empty empty empty 20 8 32 8 -262144
+-1 -1 11850 1;
+#X obj 210 -78 vsl 15 250 -1 1 0 1 empty empty empty 20 8 32 8 -262144
+-1 -1 15850 1;
+#X obj 241 -78 vsl 15 250 -1 1 0 1 empty empty empty 20 8 32 8 -262144
+-1 -1 17550 1;
+#X obj 271 -77 vsl 15 250 -1 1 0 1 empty empty empty 20 8 32 8 -262144
+-1 -1 15050 1;
+#X msg 86 199 rc 1 \$1;
+#X msg 118 224 rc 2 \$1;
+#X msg 147 200 rc 3 \$1;
+#X msg 179 223 rc 4 \$1;
+#X msg 208 199 rc 5 \$1;
+#X msg 240 224 rc 6 \$1;
+#X msg 269 200 rc 7 \$1;
+#X floatatom 154 -125 5 -1 1;
+#X obj 64 302 lattice~ 8;
+#X obj 6 254 noise~;
+#X obj 63 363 vol~;
+#X obj 63 397 dac~;
+#X floatatom 85 333 5 0 0;
+#X text 159 298 lattice~ a lattice filter;
+#X text 139 333 [rc <index> <val>] sets reflection coefficient;
+#X text 159 311 creation argument sets order;
+#X connect 0 0 1 0;
+#X connect 1 0 17 0;
+#X connect 2 0 9 0;
+#X connect 3 0 10 0;
+#X connect 4 0 11 0;
+#X connect 5 0 12 0;
+#X connect 6 0 13 0;
+#X connect 7 0 14 0;
+#X connect 8 0 15 0;
+#X connect 9 0 17 0;
+#X connect 10 0 17 0;
+#X connect 11 0 17 0;
+#X connect 12 0 17 0;
+#X connect 13 0 17 0;
+#X connect 14 0 17 0;
+#X connect 15 0 17 0;
+#X connect 16 0 0 0;
+#X connect 16 0 2 0;
+#X connect 16 0 3 0;
+#X connect 16 0 4 0;
+#X connect 16 0 5 0;
+#X connect 16 0 6 0;
+#X connect 16 0 7 0;
+#X connect 16 0 8 0;
+#X connect 17 0 19 0;
+#X connect 18 0 17 0;
+#X connect 19 0 20 1;
+#X connect 19 0 20 0;
+#X connect 21 0 19 1;
diff --git a/doc/matrix~.pd b/doc/matrix~.pd
new file mode 100644
index 0000000..5a6e9d5
--- /dev/null
+++ b/doc/matrix~.pd
@@ -0,0 +1,10 @@
+#N canvas 523 376 560 300 10;
+#X obj 30 165 matrix~;
+#X text 29 23 matrix multiplies a signal block with an arbitrary matrix
+;
+#X msg 69 127 load matrix.bin;
+#X text 27 39 added for completeness. mainly intended for spectral
+transfos;
+#X text 26 73 the file format is binary floating point \, column encoded.
+;
+#X connect 2 0 0 0;
diff --git a/doc/permut~.pd b/doc/permut~.pd
new file mode 100644
index 0000000..c8aa822
--- /dev/null
+++ b/doc/permut~.pd
@@ -0,0 +1,19 @@
+#N canvas 523 376 560 300 10;
+#X text 29 10 permut~ performs a random permutation on a signal block
+;
+#X text 30 27 mainly intended for shuffling spectral data (dynwav)
+;
+#X obj 73 127 bng 15 250 50 0 empty empty empty 0 -6 32 8 -262144 -1
+-1;
+#X msg 96 126 random;
+#X text 154 124 bang or random create a new random permutation;
+#X obj 30 91 osc~;
+#X obj 30 166 permut~;
+#X obj 29 210 dac~;
+#X floatatom 30 61 5 0 0;
+#X connect 2 0 6 0;
+#X connect 3 0 6 0;
+#X connect 5 0 6 0;
+#X connect 6 0 7 0;
+#X connect 6 0 7 1;
+#X connect 8 0 5 0;
diff --git a/doc/qmult~.pd b/doc/qmult~.pd
new file mode 100644
index 0000000..674df3e
--- /dev/null
+++ b/doc/qmult~.pd
@@ -0,0 +1,63 @@
+#N canvas 195 283 786 398 10;
+#X obj 111 145 qnorm~;
+#X obj 38 71 osc~ 30;
+#X obj 101 71 osc~ 40;
+#X obj 163 70 osc~ 50;
+#X obj 229 71 osc~ 60;
+#X obj 143 319 dac~;
+#X obj 123 244 vol~;
+#X obj 163 244 vol~;
+#X floatatom 230 230 5 0 0;
+#X floatatom 58 36 5 0 0;
+#X floatatom 107 36 5 0 0;
+#X floatatom 159 36 5 0 0;
+#X floatatom 208 36 5 0 0;
+#X obj 167 282 hip~ 10;
+#X obj 103 281 hip~ 10;
+#X text 402 190 qmult multiplies 2 quaternion signals;
+#X floatatom 347 35 5 0 0;
+#X floatatom 396 35 5 0 0;
+#X floatatom 448 35 5 0 0;
+#X floatatom 497 35 5 0 0;
+#X obj 327 70 osc~ 70;
+#X obj 390 70 osc~ 80;
+#X obj 452 69 osc~ 90;
+#X obj 518 70 osc~ 100;
+#X obj 410 136 qnorm~;
+#X obj 106 195 qmult~ 0 0 0 0 0;
+#X text 410 208 "quaternion ring modulation";
+#X text 403 245 the inlets are in 1 x real 3 x imag form;
+#X connect 0 0 25 0;
+#X connect 0 1 25 1;
+#X connect 0 2 25 2;
+#X connect 0 3 25 3;
+#X connect 1 0 0 0;
+#X connect 2 0 0 1;
+#X connect 3 0 0 2;
+#X connect 4 0 0 3;
+#X connect 6 0 14 0;
+#X connect 7 0 13 0;
+#X connect 8 0 7 1;
+#X connect 8 0 6 1;
+#X connect 9 0 1 0;
+#X connect 10 0 2 0;
+#X connect 11 0 3 0;
+#X connect 12 0 4 0;
+#X connect 13 0 5 1;
+#X connect 14 0 5 0;
+#X connect 16 0 20 0;
+#X connect 17 0 21 0;
+#X connect 18 0 22 0;
+#X connect 19 0 23 0;
+#X connect 20 0 24 0;
+#X connect 21 0 24 1;
+#X connect 22 0 24 2;
+#X connect 23 0 24 3;
+#X connect 24 0 25 4;
+#X connect 24 1 25 5;
+#X connect 24 2 25 6;
+#X connect 24 3 25 7;
+#X connect 25 0 6 0;
+#X connect 25 1 6 0;
+#X connect 25 2 7 0;
+#X connect 25 3 7 0;
diff --git a/doc/qnorm~.pd b/doc/qnorm~.pd
new file mode 100644
index 0000000..3f6a8d0
--- /dev/null
+++ b/doc/qnorm~.pd
@@ -0,0 +1,35 @@
+#N canvas 334 368 513 350 10;
+#X obj 119 137 qnorm~;
+#X obj 96 68 osc~ 30;
+#X obj 159 68 osc~ 40;
+#X obj 221 67 osc~ 50;
+#X obj 287 68 osc~ 60;
+#X obj 131 265 dac~;
+#X obj 111 190 vol~;
+#X obj 151 190 vol~;
+#X floatatom 185 154 5 0 0;
+#X floatatom 116 33 5 0 0;
+#X floatatom 165 33 5 0 0;
+#X floatatom 217 33 5 0 0;
+#X floatatom 266 33 5 0 0;
+#X obj 155 228 hip~ 10;
+#X obj 91 227 hip~ 10;
+#X text 45 -2 qnorm normalizes a quaternion signal to unit norm;
+#X connect 0 0 6 0;
+#X connect 0 1 6 0;
+#X connect 0 2 7 0;
+#X connect 0 3 7 0;
+#X connect 1 0 0 0;
+#X connect 2 0 0 1;
+#X connect 3 0 0 2;
+#X connect 4 0 0 3;
+#X connect 6 0 14 0;
+#X connect 7 0 13 0;
+#X connect 8 0 7 1;
+#X connect 8 0 6 1;
+#X connect 9 0 1 0;
+#X connect 10 0 2 0;
+#X connect 11 0 3 0;
+#X connect 12 0 4 0;
+#X connect 13 0 5 1;
+#X connect 14 0 5 0;
diff --git a/doc/ratio.pd b/doc/ratio.pd
new file mode 100644
index 0000000..9750058
--- /dev/null
+++ b/doc/ratio.pd
@@ -0,0 +1,18 @@
+#N canvas 328 388 450 300 10;
+#X obj 75 99 ratio;
+#X obj 103 192 osc~;
+#X floatatom 131 122 5 0 0;
+#X obj 103 150 *;
+#X obj 103 223 dac~;
+#X floatatom 75 51 5 0 0;
+#X floatatom 35 135 5 0 0;
+#X text 189 32 ratio is an octave shifter.;
+#X text 188 46 output is between 1 and 2;
+#X text 189 62 it computes 2^(log2(x)-int(log2(x)));
+#X connect 0 0 3 0;
+#X connect 0 0 6 0;
+#X connect 1 0 4 0;
+#X connect 1 0 4 1;
+#X connect 2 0 3 1;
+#X connect 3 0 1 0;
+#X connect 5 0 0 0;
diff --git a/doc/reference.txt b/doc/reference.txt
new file mode 100644
index 0000000..6485266
--- /dev/null
+++ b/doc/reference.txt
@@ -0,0 +1,49 @@
+abstractions
+
+64k a beat shuffler using raw 64k/break sample banks
+bdft,bdfts set decay time (ms/sec) and osc frequency (for bdiag~)
+bhip~ butterworth high pass filter
+blop~ butterworth low pass filter
+bpm convert bpm to metro time and phasor freq
+count modulo counter
+eadh~ exponential attack decay (with hold == duration)
+eadsrh~ exponential attack decay sustain release (..)
+fblock block relative frequency conversion
+inv inverse
+pdynwav~ phasor~ + dynwav~
+scale7 arbitrary 7 tone scale
+vols~ volume for a stereo signal
+vol~ volume for a mono signal
+
+externs
+
+ffpoly finite field polynomial
+fwarp tangent warp frequency
+ratio multiply by 2^k so result is 1<=r<2 (transposer)
+
+
+tilde externs
+
+abs~ absolute value
+bdiag~ block diagonal state space system (spectral processor)
+bfft~ reordered fft
+cheby~ chebychev polynomial waveshaper
+diag~ diagonal state space system (spectral processor)
+dist~ several distortions & waveshaping functions
+dwt~ discrete wavelet transform
+idwt~ inverse
+dynwav~ dynamic wavetable: use a signal block as wavetable
+ead~ exp. attack decay
+eadsr~ exp. attack decay sustain release
+ear~ exp. attack release
+lattice~ lattice filter
+matrix~ multiply a signal block with an arbitrary matrix
+permut~ random permute a signal block
+qmult~ multiply 2 quaternion signals
+qnorm~ normalize a quaternion signal (or any 4 channel sig)
+ramp~ generates an integer ramp
+statwav~ a tabread4~ clone with 8 point interpolation
+tabreadmix~ a tabread~ clone with overlap add (for smooth time stretch)
+xfm~ coupled frequency modulation
+biquadseries~ biquad second order sections (i.e. butterworth)
+filterortho~ several biquad filters, orthogonal implementation
diff --git a/doc/tabreadmix~.pd b/doc/tabreadmix~.pd
new file mode 100644
index 0000000..aad25ab
--- /dev/null
+++ b/doc/tabreadmix~.pd
@@ -0,0 +1,45 @@
+#N canvas 466 143 551 422 10;
+#X floatatom 199 254 5 0 0;
+#X obj 48 315 dac~;
+#X floatatom 38 40 5 0 0;
+#X text 135 7 tabreadmix~ an overlap add tabread clone;
+#X obj 288 362 soundfiler;
+#X text 203 236 right inlet: window hop size;
+#X text 249 247 (window size = 2x hop size);
+#X obj 38 77 phasor~;
+#X obj 38 124 *~;
+#X text 136 40 usage analogous to tabread~;
+#X text 136 58 only sample adressing is modulo length;
+#X obj 288 311 openpanel;
+#X obj 288 291 bng 15 250 50 0 empty empty empty 0 -6 32 8 -262144
+-1 -1;
+#X msg 171 97 bang;
+#X text 219 97 reset windowing;
+#X msg 171 150 pitch \$1;
+#X floatatom 171 132 5 0 0;
+#X text 245 151 set window hop size corresponding to pitch;
+#X floatatom 172 178 5 0 0;
+#X msg 172 196 chunks \$1;
+#X text 246 196 set hop size to 1/xth of length;
+#X obj 374 304 table sample123;
+#X msg 288 338 read -resize \$1 sample123;
+#X obj 288 386 s length;
+#X obj 54 100 r length;
+#X obj 57 275 tabreadmix~ sample123;
+#X text 136 24 simple (sample rate synchronous) playback;
+#X connect 0 0 25 1;
+#X connect 2 0 7 0;
+#X connect 4 0 23 0;
+#X connect 7 0 8 0;
+#X connect 8 0 25 0;
+#X connect 11 0 22 0;
+#X connect 12 0 11 0;
+#X connect 13 0 25 0;
+#X connect 15 0 25 0;
+#X connect 16 0 15 0;
+#X connect 18 0 19 0;
+#X connect 19 0 25 0;
+#X connect 22 0 4 0;
+#X connect 24 0 8 1;
+#X connect 25 0 1 0;
+#X connect 25 0 1 1;
diff --git a/doc/xfm~.pd b/doc/xfm~.pd
new file mode 100644
index 0000000..6b59329
--- /dev/null
+++ b/doc/xfm~.pd
@@ -0,0 +1,106 @@
+#N canvas 182 174 656 604 10;
+#X text 298 24 xfm~ cross frequency modulation;
+#X msg 180 308 reset;
+#X floatatom 231 255 5 0 0;
+#X floatatom 282 255 5 0 0;
+#X floatatom 332 255 5 0 0;
+#X floatatom 382 255 5 0 0;
+#X obj 287 514 dac~;
+#X obj 231 282 lop~ 1;
+#X obj 282 282 lop~ 1;
+#X obj 332 282 lop~ 1;
+#X obj 382 282 lop~ 1;
+#X floatatom 444 268 5 0 0;
+#X text 228 232 freq1;
+#X text 279 232 freq2;
+#X text 337 233 fb1;
+#X text 381 234 fb2;
+#X text 297 43 freq_osc1 = freq1 + wave_out2*fb1;
+#X text 297 58 freq_osc2 = freq2 + wave_out1*fb2;
+#X obj 275 99 hsl 300 15 1 20000 1 1 empty empty empty -2 -6 0 8 -262144
+-1 -1 15200 1;
+#X obj 275 121 hsl 300 15 1 20000 1 1 empty empty empty -2 -6 0 8 -262144
+-1 -1 14400 1;
+#X obj 276 146 hsl 300 15 1 20000 1 1 empty empty empty -2 -6 0 8 -262144
+-1 -1 18938 1;
+#X obj 276 171 hsl 300 15 1 20000 1 1 empty empty empty -2 -6 0 8 -262144
+-1 -1 21000 1;
+#X floatatom 487 377 5 0 0;
+#X floatatom 534 375 5 0 0;
+#X obj 462 348 metro;
+#X floatatom 534 335 5 0 0;
+#X obj 463 324 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 534 306 500;
+#X msg 565 305 125;
+#X msg 444 241 0.1;
+#X msg 495 306 1000;
+#X msg 150 223 type 0;
+#X msg 151 263 type 1;
+#X text 42 213 square phasor;
+#X text 45 158 algo type;
+#X text 37 257 circular phasor;
+#X text 7 371 remark: all frequencies are warped;
+#X text 8 388 (f_real = arctan(2pi*f_in)/2pi);
+#X obj 288 485 vols~;
+#X floatatom 352 453 5 0 0;
+#X text 7 416 for frequencies under 1000Hz;
+#X text 8 430 this effect is minimal;
+#X text 9 465 use the fwarp to convert from;
+#X text 9 478 real to warped;
+#X text 9 505 the square phasor type is warped too;
+#X text 9 520 but not in such a nice way as the;
+#X text 9 534 circular phasor;
+#X text 36 229 (chaotic 4DOF);
+#X text 5 272 (quasiperiodic 2DOF);
+#X obj 277 325 xfm~;
+#X obj 462 411 ead~ 0 0;
+#X obj 442 517 dac~;
+#X obj 435 451 *~;
+#X obj 472 451 *~;
+#X obj 443 488 vols~;
+#X floatatom 507 456 5 0 0;
+#X text 2 173 (can be set by creation argument);
+#X connect 1 0 49 0;
+#X connect 2 0 7 0;
+#X connect 3 0 8 0;
+#X connect 4 0 9 0;
+#X connect 5 0 10 0;
+#X connect 7 0 49 0;
+#X connect 8 0 49 1;
+#X connect 9 0 49 2;
+#X connect 10 0 49 3;
+#X connect 11 0 10 1;
+#X connect 11 0 9 1;
+#X connect 11 0 7 1;
+#X connect 11 0 8 1;
+#X connect 18 0 2 0;
+#X connect 19 0 3 0;
+#X connect 20 0 4 0;
+#X connect 21 0 5 0;
+#X connect 22 0 50 1;
+#X connect 23 0 50 2;
+#X connect 24 0 50 0;
+#X connect 25 0 24 1;
+#X connect 25 0 23 0;
+#X connect 26 0 24 0;
+#X connect 27 0 25 0;
+#X connect 28 0 25 0;
+#X connect 29 0 11 0;
+#X connect 30 0 25 0;
+#X connect 31 0 49 0;
+#X connect 32 0 49 0;
+#X connect 38 0 6 0;
+#X connect 38 1 6 1;
+#X connect 39 0 38 2;
+#X connect 49 0 52 0;
+#X connect 49 0 38 0;
+#X connect 49 1 53 0;
+#X connect 49 1 38 1;
+#X connect 50 0 52 1;
+#X connect 50 0 53 1;
+#X connect 52 0 54 0;
+#X connect 53 0 54 1;
+#X connect 54 0 51 0;
+#X connect 54 1 51 1;
+#X connect 55 0 54 2;
diff --git a/include/Makefile b/include/Makefile
new file mode 100644
index 0000000..33d4426
--- /dev/null
+++ b/include/Makefile
@@ -0,0 +1,5 @@
+all:
+clean:
+ rm -f *~
+ rm -f dspi/*~
+
diff --git a/include/dspi/DSPI.h b/include/dspi/DSPI.h
new file mode 100644
index 0000000..d9e2acf
--- /dev/null
+++ b/include/dspi/DSPI.h
@@ -0,0 +1,16 @@
+#ifndef DSPI_h
+#define DSPI_h
+
+#define DSPImin(x,y) (((x)<(y)) ? (x) : (y))
+#define DSPImax(x,y) (((x)>(y)) ? (x) : (y))
+#define DSPIclip(min, x, max) (DSPImin(DSPImax((min), (x)), max))
+
+
+// test if floating point number is denormal
+#define DSPI_IS_DENORMAL(f) (((*(unsigned int *)&(f))&0x7f800000) == 0)
+
+// test if almost denormal, choose whichever is fastest
+#define DSPI_IS_ALMOST_DENORMAL(f) (((*(unsigned int *)&(f))&0x7f800000) < 0x08000000)
+//#define DSPI_IS_ALMOST_DENORMAL(f) (fabs(f) < 3.e-34)
+
+#endif
diff --git a/include/dspi/DSPIcomplex.h b/include/dspi/DSPIcomplex.h
new file mode 100644
index 0000000..c0e2d63
--- /dev/null
+++ b/include/dspi/DSPIcomplex.h
@@ -0,0 +1,191 @@
+/*
+ * DSPIcomplex.h - Quick and dirty inline class for complex numbers
+ * (mainly to compute filter poles/zeros, not to be used inside loops)
+ * Copyright (c) 2000 by Tom Schouten
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef DSPIcomplex_h
+#define DSPIcomplex_h
+
+#include <math.h>
+#include <iostream.h>
+
+class DSPIcomplex
+{
+ public:
+ inline DSPIcomplex() {_r = _i = 0;}
+ inline DSPIcomplex(const float &a, const float &b) {setCart(a, b);}
+ inline DSPIcomplex(const float &phasor) {setAngle(phasor);}
+
+ inline void setAngle(const float &angle) {_r = cos(angle); _i = sin(angle);}
+ inline void setPolar(const float &phasor, const float &norm)
+ {_r = norm * cos(phasor); _i = norm * sin(phasor);}
+ inline void setCart(const float &a, const float &b) {_r = a; _i = b;}
+
+ inline const float& r() const {return _r;}
+ inline const float& i() const {return _i;}
+
+ inline float norm2() const {return _r*_r+_i*_i;}
+ inline float norm() const {return sqrt(norm2());}
+ inline void normalize() {float n = 1.0f / norm(); _r *= n; _i *= n;}
+
+ inline DSPIcomplex conj() const {return DSPIcomplex(_r, -_i);}
+
+ inline float angle() const {return atan2(_i, _r);}
+
+
+ inline DSPIcomplex operator+ (const DSPIcomplex &a) const
+ {
+ return DSPIcomplex(_r + a.r(), _i + a.i());
+ }
+ inline DSPIcomplex operator+ (float f) const
+ {
+ return DSPIcomplex(_r + f, _i);
+ }
+ inline DSPIcomplex operator- (const DSPIcomplex &a) const
+ {
+ return DSPIcomplex(_r - a.r(), _i - a.i());
+ }
+ inline DSPIcomplex operator- (float f) const
+ {
+ return DSPIcomplex(_r - f, _i);
+ }
+
+ inline DSPIcomplex operator* (const DSPIcomplex &a) const
+ {
+ return DSPIcomplex(_r * a.r() - _i * a.i(), _i * a.r() + _r * a.i());
+ }
+ inline DSPIcomplex operator* (float f) const
+ {
+ return DSPIcomplex(_r * f, _i * f);
+ }
+ inline DSPIcomplex operator/ (const DSPIcomplex &a) const
+ {
+ float n_t = 1.0f / a.norm2();
+ return DSPIcomplex(n_t * (_r * a.r() + _i * a.i()), n_t * (_i * a.r() - _r * a.i()));
+ }
+ inline DSPIcomplex operator/ (float f) const
+ {
+ float n_t = 1.0f / f;
+ return DSPIcomplex(n_t * _r, n_t * _i);
+ }
+
+ inline friend std::ostream& operator<< (std::ostream& o, DSPIcomplex& a)
+ {
+ return o << "(" << a.r() << "," << a.i() << ")";
+ }
+
+ inline friend DSPIcomplex operator+ (float f, DSPIcomplex& a)
+ {
+ return(DSPIcomplex(a.r() + f, a.i()));
+ }
+
+ inline friend DSPIcomplex operator- (float f, DSPIcomplex& a)
+ {
+ return(DSPIcomplex(f - a.r(), - a.i()));
+ }
+
+ inline friend DSPIcomplex operator/ (float f, DSPIcomplex& a)
+ {
+ return(DSPIcomplex(f,0) / a);
+ }
+
+ // ????
+ inline friend DSPIcomplex operator* (float f, DSPIcomplex& a)
+ {
+ return(DSPIcomplex(f*a.r(), f*a.i()));
+ }
+
+
+ inline DSPIcomplex& operator *= (float f)
+ {
+ _r *= f;
+ _i *= f;
+ return *this;
+ }
+
+ inline DSPIcomplex& operator /= (float f)
+ {
+ _r /= f;
+ _i /= f;
+ return *this;
+ }
+
+ inline DSPIcomplex& operator *= (DSPIcomplex& a)
+ {
+ float r_t = _r * a.r() - _i * a.i();
+ _i = _r * a.i() + _i * a.r();
+ _r = r_t;
+
+ return *this;
+ }
+
+ inline DSPIcomplex& operator /= (DSPIcomplex& a)
+ {
+ float n_t = a.norm2();
+ float r_t = n_t * (_r * a.r() + _i * a.i());
+ _i = n_t * (_i * a.r() - _r * a.i());
+ _r = r_t;
+
+ return *this;
+ }
+
+
+ float _r;
+ float _i;
+};
+
+
+// COMPLEX LOG
+
+inline DSPIcomplex dspilog(DSPIcomplex a) /* complex log */
+{
+ float r_t = log(a.norm());
+ float i_t = a.angle();
+ return DSPIcomplex(r_t, i_t);
+}
+
+// COMPLEX EXP
+
+inline DSPIcomplex dspiexp(DSPIcomplex a) /* complex exp */
+{
+ return (DSPIcomplex(a.i()) * exp(a.r()));
+}
+
+// BILINEAR TRANSFORM analog -> digital
+
+inline DSPIcomplex bilin_stoz(DSPIcomplex a)
+{
+ DSPIcomplex a2 = a * 0.5f;
+ return((1.0f + a2)/(1.0f - a2));
+}
+
+// BILINEAR TRANSFORM digital -> analog
+
+inline DSPIcomplex bilin_ztos(DSPIcomplex a)
+{
+ return ((a - 1.0f) / (a + 1.0f))*2.0f;
+}
+
+// not really a complex function but a nice complement to the bilinear routines
+
+inline float bilin_prewarp(float freq)
+{
+ return 2.0f * tan(M_PI * freq);
+}
+
+#endif //DSPIcomplex_h
diff --git a/include/dspi/DSPIfilters.h b/include/dspi/DSPIfilters.h
new file mode 100644
index 0000000..09268de
--- /dev/null
+++ b/include/dspi/DSPIfilters.h
@@ -0,0 +1,496 @@
+/*
+ * DSPIfilters.h - Inline classes for biquad filters
+ * Copyright (c) 2000 by Tom Schouten
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef DSPIfilters_h
+#define DSPIfilters_h
+
+
+#include "DSPIcomplex.h"
+#include "DSPI.h"
+//#include <stdio.h>
+
+/* orthogonal biquad */
+
+class DSPIfilterOrtho {
+ public:
+
+ inline DSPIfilterOrtho(){resetState();resetCoef();resetSCoef();}
+ inline ~DSPIfilterOrtho(){}
+
+ inline void resetState(){d1A = d1B = d2A = d2B = 0.0f;}
+ inline void resetCoef(){ai = ar = c0 = c1 = c2 = 0.0f;}
+ inline void resetSCoef(){s_ai = s_ar = s_c0 = s_c1 = s_c2 = 0.0f;}
+
+ /*
+ * Biquad filters remarks
+ *
+ * Q is defined with reference to the analog prototype:
+ * poles/zeros = w0 * (1/Q +- sqrt(1 - 1/Q^2))
+ *
+ * the num/den polynomial then has the form:
+ * 1 + 2s/Qw0 + (s/w0)^2
+ *
+ * if Q < 1 => real valued poles/zeros
+ * if Q > 1 => complex values poles/zeros
+ * if Q = inf => imaginary poles/zeros
+ * if Q = sqrt(2) => 'maximally flat' poles/zeros
+ *
+ * the analog prototypes are converted to the digital domain
+ * using the bilinear transform. hence the prewarping.
+ */
+
+ // make sure freq and Q are positive and within bounds
+ inline void checkBounds(float &freq, float &Q)
+ {
+ freq = fabs(freq);
+ Q = fabs(Q);
+
+ float epsilon = .0001f; // stability guard
+ float fmin = 0.0f + epsilon;
+ float fmax = 0.5f - epsilon;
+ float Qmin = 1.1f;
+
+ if (freq < fmin) freq = fmin;
+ if (freq > fmax) freq = fmax;
+
+ if (Q < Qmin) Q = Qmin;
+
+ }
+
+ inline void setAP(float freq, float Q) // allpass
+ {
+
+ // prototype: H(s) = (1 - 2s/Qw0 + (s/w0)^2) / (1 + 2s/Qw0 + (s/w0)^2)
+ // s_p = - s_z (analog: symmetric wrt. im axis)
+ // z_p = 1/z_z (digiatl: summ wrt. unit circle)
+ checkBounds(freq, Q);
+
+ // prewarp for bilin transfo
+ freq = bilin_prewarp(freq);
+ float zeta = 1.0f/Q;
+
+ DSPIcomplex p = bilin_stoz(DSPIcomplex(-zeta, (1.0f-zeta*zeta))*freq);
+ DSPIcomplex z = 1.0f / p;
+ setPoleZeroNormalized(p, z, DSPIcomplex(1,0));
+
+
+ }
+ inline void setLP(float freq, float Q) // low pass
+ {
+ // prototype: H(s) = 1 / (1 + 2s/Qw0 + (s/w0)^2)
+ // the bilinear transform has 2 zeros at NY
+
+ checkBounds(freq, Q);
+ freq = bilin_prewarp(freq);
+ float zeta = 1/Q;
+
+ DSPIcomplex p = bilin_stoz(DSPIcomplex(-zeta, (1.0f-zeta*zeta))*freq);
+ setPoleZeroNormalized(p, DSPIcomplex(-1, 0), DSPIcomplex(1, 0));
+
+ }
+ inline void setHP(float freq, float Q) // hi pass
+ {
+ // prototype: H(s) = (s/w0)^2 / (1 + 2s/Qw0 + (s/w0)^2)
+ // the bilinear transform has 2 zeros at DC
+
+ checkBounds(freq, Q);
+ freq = bilin_prewarp(freq);
+ float zeta = 1/Q;
+
+ DSPIcomplex p = bilin_stoz(DSPIcomplex(-zeta, (1.0f-zeta*zeta))*freq);
+ setPoleZeroNormalized(p, DSPIcomplex(1, 0), DSPIcomplex(-1, 0));
+
+ }
+
+ inline void setBP(float freq, float Q) // band pass (1-allpass)
+ {
+ // prototype: 1/2 * (1 - H_allpass(z))
+ setAP(freq, Q);
+ float h = -0.5f;
+ c0 *= h;
+ c1 *= h;
+ c2 *= h;
+ c0 -= h;
+
+ }
+
+ inline void setBR(float freq, float Q) // band reject
+ {
+ // prototype: H(s) = (1 - (s/w0)^2) / (1 + 2s/Qw0 + (s/w0)^2)
+ checkBounds(freq, Q);
+ // pole phasor
+ DSPIcomplex z = DSPIcomplex(2.0f * M_PI * freq);
+
+ // prewarp for bilin transfo
+ freq = bilin_prewarp(freq);
+ float zeta = 1/Q;
+
+ DSPIcomplex p = bilin_stoz(DSPIcomplex(-zeta, (1.0f-zeta*zeta))*freq);
+ setPoleZeroNormalized(p, z, DSPIcomplex(1,0));
+ }
+
+ inline void setHS(float freq, float gain) // low shelf
+ {
+ // hi shelf = LP - g(LP-1)
+ float Q = M_SQRT2;
+ setLP(freq, Q);
+ c0 -= gain * (c0 - 1.0f);
+ c1 -= gain * (c1);
+ c2 -= gain * (c2);
+ }
+
+ inline void setLS(float freq, float gain) // low shelf
+ {
+ // hi shelf = HP - g(HP-1)
+ float Q = M_SQRT2;
+ setHP(freq, Q);
+ c0 -= gain * (c0 - 1.0f);
+ c1 -= gain * (c1);
+ c2 -= gain * (c2);
+ }
+ inline void setEQ(float freq, float Q, float gain)// param EQ
+ {
+ // EQ = (1+A)/2 + (1-A)/2 AP
+
+ float a0 = 0.5f * (1.0f + gain);
+ float a1 = 0.5f * (1.0f - gain);
+ setAP(freq, Q);
+ c0 *= a1;
+ c1 *= a1;
+ c2 *= a1;
+ c0 += a0;
+ }
+
+ inline void setPoleZero
+ (
+ const DSPIcomplex& a, // pole
+ const DSPIcomplex& b // zero
+ )
+ {
+ ar = a.r();
+ ai = a.i();
+
+ c0 = 1.0f;
+ c1 = 2.0f * (a.r() - b.r());
+ c2 = (a.norm2() - b.norm2() - c1 * a.r()) / a.i();
+ }
+
+
+ inline void setPoleZeroNormalized
+ (
+ const DSPIcomplex& a, // pole
+ const DSPIcomplex& b, // zero
+ const DSPIcomplex& c // gain = 1 at this freq
+ )
+ {
+ setPoleZero(a, b);
+ DSPIcomplex invComplexGain = ((c-a)*(c-a.conj()))/((c-b)*(c-b.conj()));
+ float invGain = invComplexGain.norm();
+ c0 *= invGain;
+ c1 *= invGain;
+ c2 *= invGain;
+
+ }
+
+
+ // one channel bang
+ inline void Bang
+ (
+ float &input,
+ float &output
+ )
+ {
+ float d1t = ar * d1A + ai * d2A + input;
+ float d2t = ar * d2A - ai * d1A;
+ output = c0 * input + c1 * d1A + c2 * d2A;
+ d1A = d1t;
+ d2A = d2t;
+ }
+
+ // one channel bang smooth
+ // a default s could be s = (1 - (.1)^(1/n))
+ inline void BangSmooth
+ (
+ float &input, // input ref
+ float &output, // output ref
+ float s // smooth pole
+ )
+ {
+ float d1t = s_ar * d1A + s_ai * d2A + input;
+ float d2t = s_ar * d2A - s_ai * d1A;
+ s_ar += s * (ar - s_ar);
+ s_ai += s * (ai - s_ai);
+ output = s_c0 * input + s_c1 * d1A + s_c2 * d2A;
+ d1A = d1t;
+ d2A = d2t;
+ s_c0 += s * (c0 - s_c0);
+ s_c1 += s * (c1 - s_c1);
+ s_c2 += s * (c2 - s_c2);
+ }
+
+ // two channel bang
+ inline void Bang2
+ (
+ float &input1,
+ float &input2,
+ float &output1,
+ float &output2
+ )
+ {
+ float d1tA = ar * d1A + ai * d2A + input1;
+ float d1tB = ar * d1B + ai * d2B + input2;
+ float d2tA = ar * d2A - ai * d1A;
+ float d2tB = ar * d2B - ai * d1B;
+ output1 = c0 * input1 + d1A * c1 + d2A * c2;
+ output2 = c0 * input2 + d1B * c1 + d2B * c2;
+ d1A = d1tA;
+ d2A = d2tA;
+ d1B = d1tB;
+ d2B = d2tB;
+ }
+
+ // two channel bang smooth
+ inline void Bang2Smooth
+ (
+ float &input1,
+ float &input2,
+ float &output1,
+ float &output2,
+ float s
+ )
+ {
+ float d1tA = s_ar * d1A + s_ai * d2A + input1;
+ float d1tB = s_ar * d1B + s_ai * d2B + input2;
+ float d2tA = s_ar * d2A - s_ai * d1A;
+ float d2tB = s_ar * d2B - s_ai * d1B;
+ s_ar += s * (ar - s_ar);
+ s_ai += s * (ai - s_ai);
+ output1 = s_c0 * input1 + d1A * s_c1 + d2A * s_c2;
+ output2 = s_c0 * input2 + d1B * s_c1 + d2B * s_c2;
+ d1A = d1tA;
+ d2A = d2tA;
+ d1B = d1tB;
+ d2B = d2tB;
+ s_c0 += s * (c0 - s_c0);
+ s_c1 += s * (c1 - s_c1);
+ s_c2 += s * (c2 - s_c2);
+ }
+
+ inline void killDenormals()
+ {
+
+ // state data
+ float zero = 0.0f;
+
+ d1A = DSPI_IS_DENORMAL(d1A) ? zero : d1A;
+ d2A = DSPI_IS_DENORMAL(d2A) ? zero : d2A;
+ d1B = DSPI_IS_DENORMAL(d1B) ? zero : d1B;
+ d2B = DSPI_IS_DENORMAL(d2B) ? zero : d2B;
+
+
+ /* test on athlon showed nuking smooth data does not
+ * present a noticable difference in performance however
+ * nuking state data is really necessary
+
+
+ // smooth data
+ float dai = ai - s_ai;
+ float dar = ar - s_ar;
+ float dc0 = c0 - s_c0;
+ float dc1 = c1 - s_c1;
+ float dc2 = c2 - s_c2;
+
+
+ s_ai = DSPI_IS_DENORMAL(dai) ? ai : s_ai;
+ s_ar = DSPI_IS_DENORMAL(dar) ? ar : s_ar;
+ s_c0 = DSPI_IS_DENORMAL(dc0) ? c0 : s_c0;
+ s_c1 = DSPI_IS_DENORMAL(dc0) ? c1 : s_c1;
+ s_c2 = DSPI_IS_DENORMAL(dc0) ? c2 : s_c2;
+
+ */
+
+
+
+ }
+
+ private:
+
+ // state data
+ float d1A;
+ float d2A;
+
+ float d1B;
+ float d2B;
+
+ // pole data
+ float ai;
+ float s_ai;
+ float ar;
+ float s_ar;
+
+ // zero data
+ float c0;
+ float s_c0;
+ float c1;
+ float s_c1;
+ float c2;
+ float s_c2;
+
+
+};
+
+
+
+class DSPIfilterSeries{
+ public:
+ inline DSPIfilterSeries() {DSPIfilterSeries(1);}
+ inline ~DSPIfilterSeries() {delete [] biquad;};
+
+ inline DSPIfilterSeries(int numberOfSections)
+ {
+ // create a set of biquads
+ sections = numberOfSections;
+ biquad = new DSPIfilterOrtho[numberOfSections];
+ }
+
+ inline void setButterHP(float freq)
+ {
+ /* This member function computes the poles for a highpass butterworth filter.
+ * The filter is transformed to the digital domain using a bilinear transform.
+ * Every biquad section is normalized at NY.
+ */
+
+ float epsilon = .0001f; // stability guard
+ float min = 0.0f + epsilon;
+ float max = 0.5f - epsilon;
+
+ if (freq < min) freq = min;
+ if (freq > max) freq = max;
+
+ // prewarp cutoff frequency
+ float omega = bilin_prewarp(freq);
+
+ DSPIcomplex NY(-1,0); //normalize at NY
+ DSPIcomplex DC(1,0); //all zeros will be at DC
+ DSPIcomplex pole( (2*sections + 1) * M_PI / (4*sections)); // first pole of lowpass filter with omega == 1
+ DSPIcomplex pole_inc(M_PI / (2*sections)); // phasor to get to next pole, see Porat p. 331
+
+ for (int i=0; i<sections; i++)
+ {
+ // setup the biquad with the computed pole and zero and unit gain at NY
+ biquad[i].setPoleZeroNormalized(
+ bilin_stoz(omega/pole), // LP -> HP -> digital transfo
+ DC, // all zeros at DC
+ NY); // normalized (gain == 1) at NY
+ pole *= pole_inc; // compe next (lowpass) pole
+ }
+
+ }
+
+ inline void setButterLP(float freq)
+ {
+ /* This member function computes the poles for a lowpass butterworth filter.
+ * The filter is transformed to the digital domain using a bilinear transform.
+ * Every biquad section is normalized at DC.
+ * Doing it this way, only the pole locations need to be transformed.
+ * The constant gain factor can be computed by setting the DC gain of every section to 1.
+ * An analog butterworth is all-pole, meaning the bilinear transform has all zeros at -1
+ */
+
+
+ float epsilon = .0001f; // stability guard
+ float min = 0.0f + epsilon;
+ float max = 0.5f - epsilon;
+
+
+ if (freq < min) freq = min;
+ if (freq > max) freq = max;
+
+ // prewarp cutoff frequency
+ float omega = bilin_prewarp(freq);
+
+ DSPIcomplex DC(1,0); //normalize at DC
+ DSPIcomplex NY(-1,0); //all zeros will be at NY
+ DSPIcomplex pole( (2*sections + 1) * M_PI / (4*sections));
+ pole *= omega; // first pole, see Porat p. 331
+ DSPIcomplex pole_inc(M_PI / (2*sections)); // phasor to get to next pole, see Porat p. 331
+
+ for (int i=0; i<sections; i++)
+ {
+ // setup the biquad with the computed pole and zero and unit gain at DC
+ biquad[i].setPoleZeroNormalized(bilin_stoz(pole), NY, DC);
+ pole *= pole_inc;
+ }
+ }
+
+ inline void resetState()
+ {
+ for (int i=0; i<sections; i++) biquad[i].resetState();
+ }
+
+ inline void Bang(float &input, float &output)
+ {
+ float x = input;
+ for (int i=0; i<sections; i++)
+ {
+ biquad[i].Bang(x, x);
+ }
+ output = x;
+ }
+ inline void Bang2(float &input1, float &input2, float &output1, float &output2)
+ {
+ float x = input1;
+ float y = input2;
+ for (int i=0; i<sections; i++)
+ {
+ biquad[i].Bang2(x, y, x, y);
+ }
+ output1 = x;
+ output2 = y;
+ }
+
+ inline void BangSmooth(float &input, float &output, float s)
+ {
+ float x = input;
+ for (int i=0; i<sections; i++)
+ {
+ biquad[i].BangSmooth(x, x, s);
+ }
+ output = x;
+ }
+ inline void Bang2(float &input1, float &input2, float &output1, float &output2, float s)
+ {
+ float x = input1;
+ float y = input2;
+ for (int i=0; i<sections; i++)
+ {
+ biquad[i].Bang2Smooth(x, y, x, y, s);
+ }
+ output1 = x;
+ output2 = y;
+ }
+
+ private:
+ int sections;
+ DSPIfilterOrtho *biquad;
+ float gain;
+};
+
+#endif //DSPIfilters_h
+
diff --git a/include/extlib_util.h b/include/extlib_util.h
new file mode 100644
index 0000000..259d944
--- /dev/null
+++ b/include/extlib_util.h
@@ -0,0 +1,31 @@
+/*
+ * Prototypes for utility functions used in pd externals
+ * Copyright (c) 2000-2003 by Tom Schouten
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <math.h>
+#include "m_pd.h"
+
+/* envelope stuff */
+
+/* exponential range for envelopes is 60dB */
+#define ENVELOPE_RANGE 0.001f
+#define ENVELOPE_MAX (1.0f - ENVELOPE_RANGE)
+#define ENVELOPE_MIN ENVELOPE_RANGE
+
+/* convert milliseconds to 1-p, with p a real pole */
+float milliseconds_2_one_minus_realpole(float time);
diff --git a/modules++/Makefile b/modules++/Makefile
new file mode 100644
index 0000000..1329f4b
--- /dev/null
+++ b/modules++/Makefile
@@ -0,0 +1,10 @@
+include ../Makefile.config
+current: all
+
+all: biquadseries.o filterortho.o
+
+
+clean:
+ rm -f *~
+ rm -f *.o
+
diff --git a/modules++/biquadseries.cc b/modules++/biquadseries.cc
new file mode 100644
index 0000000..40b3aef
--- /dev/null
+++ b/modules++/biquadseries.cc
@@ -0,0 +1,128 @@
+/*
+ * biquadseries.cc - second order section filter pd interface
+ * Copyright (c) 2000-2003 by Tom Schouten
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include "m_pd.h"
+#include <math.h>
+
+#include "DSPIcomplex.h"
+#include "DSPIfilters.h"
+
+
+
+typedef struct biquadseries_struct
+{
+ t_object x_obj;
+ t_float x_f;
+ DSPIfilterSeries* biquadseries;
+} t_biquadseries;
+
+void biquadseries_bang(t_biquadseries *x)
+{
+
+}
+
+void biquadseries_butterLP(t_biquadseries *x, t_floatarg f)
+{
+ x->biquadseries->setButterLP(f / sys_getsr());
+}
+
+void biquadseries_butterHP(t_biquadseries *x, t_floatarg f)
+{
+ x->biquadseries->setButterHP(f / sys_getsr());
+}
+
+
+
+static t_int *biquadseries_perform(t_int *w)
+{
+
+
+ t_float *in = (float *)(w[3]);
+ t_float *out = (float *)(w[4]);
+ DSPIfilterSeries* biquadseries = (DSPIfilterSeries *)(w[1]);
+ t_int n = (t_int)(w[2]);
+ t_int i;
+ t_float x;
+
+ // dit kan beter
+ float smooth = .01;
+ //1.0f - pow(.9f,1.0f/(float)(n));
+
+ for (i = 0; i < n; i++)
+ {
+ x = *in++;
+ biquadseries->BangSmooth(x, x, smooth);
+ *out++ = x;
+ }
+
+ return (w+5);
+}
+
+static void biquadseries_dsp(t_biquadseries *x, t_signal **sp)
+{
+ dsp_add(biquadseries_perform, 4, x->biquadseries, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+
+}
+void biquadseries_free(void)
+{
+
+}
+
+t_class *biquadseries_class;
+
+void *biquadseries_new(t_floatarg fsections)
+{
+ t_biquadseries *x = (t_biquadseries *)pd_new(biquadseries_class);
+
+ int sections = (int)fsections;
+ if (sections < 1) sections = 1;
+ // post("biquadseries~: %d sections", sections);
+ x->biquadseries = new DSPIfilterSeries(sections);
+
+ // inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("freq"));
+ outlet_new(&x->x_obj, gensym("signal"));
+
+ biquadseries_butterLP(x, 10000);
+
+ return (void *)x;
+}
+
+
+extern "C" {
+
+void biquadseries_tilde_setup(void)
+{
+ //post("biquadseries~ v0.1");
+
+ biquadseries_class = class_new(gensym("biquadseries~"), (t_newmethod)biquadseries_new,
+ (t_method)biquadseries_free, sizeof(t_biquadseries), 0, A_DEFFLOAT, 0);
+
+ CLASS_MAINSIGNALIN(biquadseries_class, t_biquadseries, x_f);
+
+ class_addmethod(biquadseries_class, (t_method)biquadseries_bang, gensym("bang"), (t_atomtype)0);
+
+ class_addmethod(biquadseries_class, (t_method)biquadseries_dsp, gensym("dsp"), (t_atomtype)0);
+
+ class_addmethod(biquadseries_class, (t_method)biquadseries_butterLP, gensym("butterLP"), A_FLOAT, A_NULL);
+ class_addmethod(biquadseries_class, (t_method)biquadseries_butterHP, gensym("butterHP"), A_FLOAT, A_NULL);
+
+}
+
+}
diff --git a/modules++/filterortho.cc b/modules++/filterortho.cc
new file mode 100644
index 0000000..11c6aac
--- /dev/null
+++ b/modules++/filterortho.cc
@@ -0,0 +1,131 @@
+/*
+ * filterortho.cc - orthogonal biquad filter pd interface
+ * Copyright (c) 2000-2003 by Tom Schouten
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include "m_pd.h"
+#include <math.h>
+
+#include "DSPIcomplex.h"
+#include "DSPIfilters.h"
+
+
+
+typedef struct filterortho_struct
+{
+ t_object x_obj;
+ t_float x_f;
+ DSPIfilterOrtho filterortho;
+} t_filterortho;
+
+void filterortho_bang(t_filterortho *x)
+{
+
+}
+
+
+static t_int *filterortho_perform(t_int *w)
+{
+
+
+ t_float *in = (float *)(w[3]);
+ t_float *out = (float *)(w[4]);
+ DSPIfilterOrtho* filterortho = (DSPIfilterOrtho *)(w[1]);
+ t_int n = (t_int)(w[2]);
+ t_int i;
+ t_float x;
+
+
+ // dit kan beter
+ float smooth = 1.0f - pow(.05f,1.0f/(float)(n));
+
+ for (i = 0; i < n; i++)
+ {
+ x = *in++;
+ filterortho->BangSmooth(x, x, smooth);
+ *out++ = x;
+ }
+
+ filterortho->killDenormals();
+
+ return (w+5);
+}
+
+static void filterortho_dsp(t_filterortho *x, t_signal **sp)
+{
+ dsp_add(filterortho_perform, 4, &(x->filterortho), sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+
+}
+void filterortho_free(void)
+{
+
+}
+
+t_class *filterortho_class;
+
+
+
+void setLP(t_filterortho *x, t_floatarg f, t_floatarg Q) {x->filterortho.setLP(f / sys_getsr(), Q);}
+void setHP(t_filterortho *x, t_floatarg f, t_floatarg Q) {x->filterortho.setHP(f / sys_getsr(), Q);}
+void setBP(t_filterortho *x, t_floatarg f, t_floatarg Q) {x->filterortho.setBP(f / sys_getsr(), Q);}
+void setBR(t_filterortho *x, t_floatarg f, t_floatarg Q) {x->filterortho.setBR(f / sys_getsr(), Q);}
+void setAP(t_filterortho *x, t_floatarg f, t_floatarg Q) {x->filterortho.setAP(f / sys_getsr(), Q);}
+
+void setLS(t_filterortho *x, t_floatarg f, t_floatarg A) {x->filterortho.setLS(f / sys_getsr(), A);}
+void setHS(t_filterortho *x, t_floatarg f, t_floatarg A) {x->filterortho.setHS(f / sys_getsr(), A);}
+
+void setEQ(t_filterortho *x, t_floatarg f, t_floatarg Q, t_floatarg A) {x->filterortho.setEQ(f / sys_getsr(), Q, A);}
+
+
+void *filterortho_new()
+{
+ t_filterortho *x = (t_filterortho *)pd_new(filterortho_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ setLP(x, 10000, 2);
+ return (void *)x;
+}
+
+
+
+extern "C" {
+
+void filterortho_tilde_setup(void)
+{
+ //post("filterortho~ v0.1");
+
+ filterortho_class = class_new(gensym("filterortho~"), (t_newmethod)filterortho_new,
+ (t_method)filterortho_free, sizeof(t_filterortho), 0, A_NULL);
+
+ CLASS_MAINSIGNALIN(filterortho_class, t_filterortho, x_f);
+
+ class_addmethod(filterortho_class, (t_method)filterortho_bang, gensym("bang"), A_NULL);
+
+ class_addmethod(filterortho_class, (t_method)filterortho_dsp, gensym("dsp"), A_NULL);
+
+ class_addmethod(filterortho_class, (t_method)setLP, gensym("setLP"), A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(filterortho_class, (t_method)setHP, gensym("setHP"), A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(filterortho_class, (t_method)setBP, gensym("setBP"), A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(filterortho_class, (t_method)setBR, gensym("setBR"), A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(filterortho_class, (t_method)setAP, gensym("setAP"), A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(filterortho_class, (t_method)setLS, gensym("setLS"), A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(filterortho_class, (t_method)setHS, gensym("setHS"), A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(filterortho_class, (t_method)setEQ, gensym("setEQ"), A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
+
+}
+
+}
diff --git a/modules/Makefile b/modules/Makefile
new file mode 100644
index 0000000..4e1cabd
--- /dev/null
+++ b/modules/Makefile
@@ -0,0 +1,11 @@
+include ../Makefile.config
+
+current: ead.o ear.o eadsr.o dist.o tabreadmix.o xfm.o qmult.o qnorm.o \
+ cheby.o abs.o ramp.o dwt.o bfft.o dynwav.o statwav.o bdiag.o \
+ diag.o matrix.o permut.o lattice.o ratio.o ffpoly.o fwarp.o
+
+
+clean:
+ rm -f *.o
+ rm -f *~
+
diff --git a/modules/abs.c b/modules/abs.c
new file mode 100644
index 0000000..4d8b8eb
--- /dev/null
+++ b/modules/abs.c
@@ -0,0 +1,64 @@
+/*
+ * abs.c - computes absolute value of a signal
+ * Copyright (c) 2000-2003 by Tom Schouten
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "m_pd.h"
+#include <math.h>
+
+/* ------------------------- abs~ -------------------------- */
+static t_class *abs_class;
+
+typedef struct _abs
+{
+ t_object x_obj;
+} t_abs;
+
+static t_int *abs_perform(t_int *w)
+{
+ t_abs *x = (t_abs *)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ while (n--)
+ {
+ float f = *in++;
+ if (f < 0) f = -f;
+ *out++ = f;
+ }
+ return (w+5);
+}
+
+static void abs_dsp(t_abs *x, t_signal **sp)
+{
+ dsp_add(abs_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+static void *abs_new(void)
+{
+ t_abs *x = (t_abs *)pd_new(abs_class);
+ outlet_new(&x->x_obj, &s_signal);
+ return (x);
+}
+
+void abs_tilde_setup(void)
+{
+ abs_class = class_new(gensym("abs~"), (t_newmethod)abs_new, 0,
+ sizeof(t_abs), 0, A_NULL);
+ class_addmethod(abs_class, (t_method)nullfn, &s_signal, A_NULL);
+ class_addmethod(abs_class, (t_method)abs_dsp, gensym("dsp"), A_NULL);
+}
diff --git a/modules/bdiag.c b/modules/bdiag.c
new file mode 100644
index 0000000..37a0349
--- /dev/null
+++ b/modules/bdiag.c
@@ -0,0 +1,272 @@
+/*
+ * bdiag.c - block diagonal state space system
+ * treats input dsp block as n parallel signals
+ *
+ * s1 = (a * s1) + (b * s2) + u1;
+ * s2 = (a * s2) - (b * s1) + u2;
+ *
+ * Copyright (c) 2000-2003 by Tom Schouten
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include "m_pd.h"
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define MAXORDER 64
+
+typedef struct bdiagctl
+{
+ t_float *c_state;
+ t_float *c_eigen;
+ t_int c_order;
+} t_bdiagctl;
+
+typedef struct bdiag
+{
+ t_object x_obj;
+ t_float x_f;
+ t_bdiagctl x_ctl;
+} t_bdiag;
+
+
+static float randfloat(void){
+ float r = rand ();
+ r /= (RAND_MAX/2);
+ r -= 1;
+ return r;
+
+}
+
+static void bdiag_random(t_bdiag *x)
+{
+ int i;
+
+ for (i=0; i<x->x_ctl.c_order; i++)
+ {
+ x->x_ctl.c_state[i] = randfloat();
+ }
+
+}
+
+
+static void bdiag_reset(t_bdiag *x)
+{
+ int i;
+
+ for (i=0; i<x->x_ctl.c_order; i++)
+ {
+ x->x_ctl.c_state[i] = 0;
+ }
+
+}
+
+
+
+
+
+
+static void bdiag_eigen(t_bdiag *x, t_floatarg index, t_floatarg aval, t_floatarg bval)
+{
+ int i = (int)index;
+ if (i<0) return;
+ if (i>=x->x_ctl.c_order/2) return;
+ x->x_ctl.c_eigen[2*i+0] = aval;
+ x->x_ctl.c_eigen[2*i+1] = bval;
+
+}
+
+/* set decay time and frequency of pole at index */
+static void bdiag_timefreq(t_bdiag *x, t_floatarg index, t_floatarg time, t_floatarg freq)
+{
+ float r,a,b,n;
+ float sr = sys_getsr() / (float)x->x_ctl.c_order;
+
+ /* time in ms */
+ time *= 0.001;
+
+ if (time < 0.0f) time = 0.0f;
+ r = pow(0.001f, 1.0f / (time * sr));
+ if (r < 0.0f) r = 0.0f;
+ if (r > 1.0f) r = 1.0f;
+
+ a = cos(2*M_PI*freq/sr);
+ b = sin(2*M_PI*freq/sr);
+
+ /* normalize to be sure */
+ n = 1.0f / sqrt(a*a + b*b);
+ a *= n;
+ b *= n;
+
+ bdiag_eigen(x, index, r*a, r*b);
+}
+
+static void bdiag_preset(t_bdiag *x, t_floatarg preset)
+{
+ int p = preset;
+ int i;
+ float a, b, w, r;
+
+ switch(p){
+ case 0:
+ post("preset 0");
+ for (i=0; i<x->x_ctl.c_order/2; i++){
+ w = randfloat() * .001;
+ r = 1. - (((float)i + 1.)/1000.);
+ a = cos(w) * r;
+ b = sin(w) * r;
+ post("%f %f %f %f", w, r, a, b);
+ bdiag_eigen(x,i,a,b);
+ }
+ break;
+ case 1:
+ default:
+ break;
+
+ }
+}
+
+static t_int *bdiag_perform(t_int *w)
+{
+
+
+ t_float *in = (float *)(w[3]);
+ t_float *out = (float *)(w[4]);
+ t_bdiagctl *ctl = (t_bdiagctl *)(w[1]);
+
+ t_float *eigen = ctl->c_eigen;
+ t_float *state = ctl->c_state;
+ t_int n = (t_int)(w[2]);
+
+ t_float u1,u2,a,b,s1,s2,s1new,s2new;
+
+ int i;
+
+ for (i=0; i<n; i+=2)
+ {
+ u1 = *in++;
+ u2 = *in++;
+ a = *eigen++; /* real part */
+ b = *eigen++; /* imag part */
+ s1 = state[0];
+ s2 = state[1];
+
+
+ s1new = (a * s1) - (b * s2) + u1; /* update state */
+ s2new = (a * s2) + (b * s1) + u2;
+
+ *state++ = s1new; /* store state */
+ *state++ = s2new;
+
+ *out++ = s1new; /* output state */
+ *out++ = s2new;
+ }
+
+ return (w+5);
+}
+
+
+static void bdiag_dsp(t_bdiag *x, t_signal **sp)
+{
+
+ int n = sp[0]->s_n;
+ int i;
+
+ if (n == 1)
+ {
+ post("bdiag: doesnt work with blocksize == 1");
+ dsp_add_copy(sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+ }
+ else
+ {
+ if (x->x_ctl.c_order != n)
+ {
+ if (x->x_ctl.c_state) free(x->x_ctl.c_state);
+ if (x->x_ctl.c_eigen) free(x->x_ctl.c_eigen);
+
+ x->x_ctl.c_state = (t_float *)malloc(n*sizeof(t_float));
+ x->x_ctl.c_eigen = (t_float *)malloc(n*sizeof(t_float));
+
+ for(i=0;i<n;i++)
+ {
+ x->x_ctl.c_state[i] = 0;
+ x->x_ctl.c_eigen[i] = 0;
+ }
+
+ x->x_ctl.c_order = n;
+ }
+
+
+ dsp_add(bdiag_perform, 4, &x->x_ctl, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+ }
+
+}
+
+static void bdiag_free(t_bdiag *x)
+{
+
+ if (x->x_ctl.c_state) free(x->x_ctl.c_state);
+ if (x->x_ctl.c_eigen) free(x->x_ctl.c_eigen);
+
+
+}
+
+t_class *bdiag_class;
+
+
+static void *bdiag_new(t_floatarg permute)
+{
+ t_bdiag *x = (t_bdiag *)pd_new(bdiag_class);
+ int i, n=64;
+
+ outlet_new(&x->x_obj, gensym("signal"));
+
+ x->x_ctl.c_state = (t_float *)malloc(n*sizeof(t_float));
+ x->x_ctl.c_eigen = (t_float *)malloc(n*sizeof(t_float));
+
+ for(i=0;i<n;i++)
+ {
+ x->x_ctl.c_state[i] = 0;
+ x->x_ctl.c_eigen[i] = 0;
+ }
+
+ x->x_ctl.c_order = n;
+
+
+ return (void *)x;
+
+
+}
+
+
+void bdiag_tilde_setup(void)
+{
+ //post("bdiag~ v0.1");
+ bdiag_class = class_new(gensym("bdiag~"), (t_newmethod)bdiag_new,
+ (t_method)bdiag_free, sizeof(t_bdiag), 0, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(bdiag_class, t_bdiag, x_f);
+ class_addmethod(bdiag_class, (t_method)bdiag_random, gensym("random"), 0);
+ class_addmethod(bdiag_class, (t_method)bdiag_random, gensym("bang"), 0);
+ class_addmethod(bdiag_class, (t_method)bdiag_reset, gensym("reset"), 0);
+ class_addmethod(bdiag_class, (t_method)bdiag_dsp, gensym("dsp"), 0);
+
+ class_addmethod(bdiag_class, (t_method)bdiag_eigen, gensym("eigen"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addmethod(bdiag_class, (t_method)bdiag_timefreq, gensym("timefreq"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addmethod(bdiag_class, (t_method)bdiag_preset, gensym("preset"), A_DEFFLOAT, 0);
+}
+
diff --git a/modules/bfft.c b/modules/bfft.c
new file mode 100644
index 0000000..76b0254
--- /dev/null
+++ b/modules/bfft.c
@@ -0,0 +1,304 @@
+/*
+ * bfft.c - code for fourrier transform
+ * data organization is in (real, imag) pairs
+ * the first 2 components are (DC, NY)
+ * Copyright (c) 2000-2003 by Tom Schouten
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include "m_pd.h"
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define MAXORDER 64
+
+typedef struct bfftctl
+{
+ t_int c_levels;
+ char c_name[16];
+ t_int *c_clutter;
+ t_int *c_unclutter;
+} t_bfftctl;
+
+typedef struct bfft
+{
+ t_object x_obj;
+ t_float x_f;
+ t_bfftctl x_ctl;
+} t_bfft;
+
+t_class *bfft_class, *ibfft_class, *fht_class;
+
+
+static inline void bfft_perform_permutation(t_float *S, int n, t_int *f)
+{
+ t_int k,l;
+ t_float swap;
+ for(k=0; k<n; k++)
+ {
+ l = f[k];
+ while (l<k) l = f[l];
+ swap = S[k];
+ S[k] = S[l];
+ S[l] = swap;
+ }
+}
+
+static void bfft_permutation(t_bfft *x, t_int n){
+
+ t_bfftctl *ctl = &x->x_ctl;
+ int i;
+
+ if (ctl->c_clutter) free(ctl->c_clutter);
+ if (ctl->c_unclutter) free(ctl->c_unclutter);
+
+ ctl->c_clutter = (t_int *)malloc(n*sizeof(t_int));
+ ctl->c_unclutter = (t_int *)malloc(n*sizeof(t_int));
+
+
+ ctl->c_unclutter[0] = 0;
+ ctl->c_unclutter[1] = n/2;
+ for (i=1; i<n/2; i++){
+ ctl->c_unclutter[2*i] = i;
+ ctl->c_unclutter[2*i+1] = n-i;
+ }
+
+ for(i=0; i<n; i++)
+ ctl->c_clutter[ctl->c_unclutter[i]] = i;
+
+ return;
+
+ /* debug */
+ /* for(k=0; k<n; k++)
+ ** printf("clutter[%d] = %d\n", k, ctl->c_clutter[k]);
+ ** for(k=0; k<n; k++)
+ ** printf("unclutter[%d] = %d\n", k, ctl->c_unclutter[k]);
+ **
+ ** exit(1);
+ */
+}
+
+
+
+static t_int *bfft_perform(t_int *w)
+{
+
+
+ t_float *in = (float *)(w[3]);
+ t_float *out = (float *)(w[4]);
+ t_bfftctl *ctl = (t_bfftctl *)(w[1]);
+ t_int n = (t_int)(w[2]);
+ t_float scale = sqrt(1.0f / (float)(n));
+
+ mayer_fht(out, n);
+ bfft_perform_permutation(out, n, ctl->c_unclutter);
+
+ while (n--) *out++ *= scale;
+
+ return (w+5);
+}
+
+
+
+
+static t_int *ibfft_perform(t_int *w)
+{
+
+
+ t_float *in = (float *)(w[3]);
+ t_float *out = (float *)(w[4]);
+ t_bfftctl *ctl = (t_bfftctl *)(w[1]);
+ t_int n = (t_int)(w[2]);
+ t_float scale = sqrt(1.0f / (float)(n));
+
+
+ bfft_perform_permutation(out, n, ctl->c_clutter);
+ mayer_fht(out, n);
+ while (n--) *out++ *= scale;
+
+
+ return (w+5);
+}
+
+
+static t_int *fht_perform(t_int *w)
+{
+
+
+ t_float *in = (float *)(w[3]);
+ t_float *out = (float *)(w[4]);
+ t_bfftctl *ctl = (t_bfftctl *)(w[1]);
+
+
+ t_int n = (t_int)(w[2]);
+
+ mayer_fht(out, n);
+
+ return (w+5);
+}
+
+
+static void bfft_dsp(t_bfft *x, t_signal **sp)
+{
+
+ int n = sp[0]->s_n;
+ t_float *in = sp[0]->s_vec;
+ t_float *out = sp[1]->s_vec;
+
+ bfft_permutation(x, n);
+
+ if (in != out)
+ {
+ dsp_add_copy(in,out,n);
+ in = out;
+ }
+
+ dsp_add(bfft_perform, 4, &x->x_ctl, n, in, out);
+
+}
+
+static void ibfft_dsp(t_bfft *x, t_signal **sp)
+{
+
+ int n = sp[0]->s_n;
+ t_float *in = sp[0]->s_vec;
+ t_float *out = sp[1]->s_vec;
+
+ bfft_permutation(x, n);
+
+ if (in != out)
+ {
+ dsp_add_copy(in,out,n);
+ in = out;
+ }
+
+ dsp_add(ibfft_perform, 4, &x->x_ctl, n, in, out);
+
+}
+
+static void fht_dsp(t_bfft *x, t_signal **sp)
+{
+
+ int n = sp[0]->s_n;
+ t_float *in = sp[0]->s_vec;
+ t_float *out = sp[1]->s_vec;
+
+
+ if (in != out)
+ {
+ dsp_add_copy(in,out,n);
+ in = out;
+ }
+
+ dsp_add(fht_perform, 4, &x->x_ctl, n, in, out);
+
+}
+
+
+
+static void bfft_free(t_bfft *x)
+{
+
+ if (x->x_ctl.c_clutter) free(x->x_ctl.c_clutter);
+ if (x->x_ctl.c_unclutter) free(x->x_ctl.c_unclutter);
+
+}
+
+
+
+
+static void *bfft_new(void)
+{
+ t_bfft *x = (t_bfft *)pd_new(bfft_class);
+ int i;
+
+ outlet_new(&x->x_obj, gensym("signal"));
+
+
+ sprintf(x->x_ctl.c_name,"bfft");
+
+ x->x_ctl.c_clutter = NULL;
+ x->x_ctl.c_unclutter = NULL;
+
+ return (void *)x;
+
+
+}
+
+static void *ibfft_new(void)
+{
+ t_bfft *x = (t_bfft *)pd_new(ibfft_class);
+ int i;
+
+ outlet_new(&x->x_obj, gensym("signal"));
+
+
+ x->x_ctl.c_clutter = NULL;
+ x->x_ctl.c_unclutter = NULL;
+
+ sprintf(x->x_ctl.c_name,"ibfft");
+
+ return (void *)x;
+}
+
+static void *fht_new(void)
+{
+ t_bfft *x = (t_bfft *)pd_new(fht_class);
+ int i;
+
+ outlet_new(&x->x_obj, gensym("signal"));
+
+
+ x->x_ctl.c_clutter = NULL;
+ x->x_ctl.c_unclutter = NULL;
+
+ sprintf(x->x_ctl.c_name,"fht");
+
+ return (void *)x;
+}
+
+
+
+
+void bfft_tilde_setup(void)
+{
+ //post("bfft~ v0.1");
+ bfft_class = class_new(gensym("bfft~"), (t_newmethod)bfft_new,
+ (t_method)bfft_free, sizeof(t_bfft), 0, 0);
+ CLASS_MAINSIGNALIN(bfft_class, t_bfft, x_f);
+ class_addmethod(bfft_class, (t_method)bfft_dsp, gensym("dsp"), 0);
+
+
+
+ ibfft_class = class_new(gensym("ibfft~"), (t_newmethod)ibfft_new,
+ (t_method)bfft_free, sizeof(t_bfft), 0, 0);
+
+ CLASS_MAINSIGNALIN(ibfft_class, t_bfft, x_f);
+ class_addmethod(ibfft_class, (t_method)ibfft_dsp, gensym("dsp"), 0);
+
+
+
+ fht_class = class_new(gensym("fht~"), (t_newmethod)fht_new,
+ (t_method)bfft_free, sizeof(t_bfft), 0, 0);
+
+ CLASS_MAINSIGNALIN(fht_class, t_bfft, x_f);
+ class_addmethod(fht_class, (t_method)fht_dsp, gensym("dsp"), 0);
+
+
+
+}
diff --git a/modules/cheby.c b/modules/cheby.c
new file mode 100644
index 0000000..2c32d68
--- /dev/null
+++ b/modules/cheby.c
@@ -0,0 +1,138 @@
+/*
+ * cheby.c - chebychev polynomial evaluation
+ * Copyright (c) 2000-2003 by Tom Schouten
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "m_pd.h"
+#include <math.h>
+
+
+#define MAX_ORDER 1024
+#define DEFAULT_ORDER 4
+
+typedef struct chebyctl
+{
+ t_float c_gain[MAX_ORDER];
+ t_int c_order;
+} t_chebyctl;
+
+typedef struct cheby
+{
+ t_object x_obj;
+ t_float x_f;
+ t_chebyctl x_ctl;
+} t_cheby;
+
+static void cheby_bang(t_cheby *x)
+{
+
+}
+
+static void cheby_coef(t_cheby *x, t_floatarg coef, t_floatarg f)
+{
+ int i = (int)coef;
+ if ((i > 0) && (i < x->x_ctl.c_order + 1)){
+ x->x_ctl.c_gain[i-1] = f;
+ /* post("cheby: harmonic %d set to %f", i, f); */
+ }
+}
+
+
+static t_int *cheby_perform(t_int *w)
+{
+
+
+ t_float *in = (float *)(w[3]);
+ t_float *out = (float *)(w[4]);
+ t_chebyctl *ctl = (t_chebyctl *)(w[1]);
+ t_float *gain = ctl->c_gain;
+ t_int i;
+ t_int n = (t_int)(w[2]), k;
+ t_float x,y,t1,t2,t,acc;
+
+
+ for (i = 0; i < n; i++)
+ {
+ x = *in++;
+
+ gain = ctl->c_gain;
+ t2 = 1; /* T_0 */
+ t1 = x; /* T_1 */
+
+ acc = *gain++ * x; /* a_1 T_1 */
+ for (k=2; k<=ctl->c_order; k++){
+ t = 2*x*t1 - t2; /* T_k = 2 x T_{k-1} - T_{k-2} */
+ acc += *gain++ * t; /* a_k T_k */
+ t2 = t1;
+ t1 = t;
+ }
+
+ *out++ = acc;
+
+ }
+
+
+ return (w+5);
+}
+
+static void cheby_dsp(t_cheby *x, t_signal **sp)
+{
+ dsp_add(cheby_perform, 4, &x->x_ctl, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+
+}
+static void cheby_free(void)
+{
+
+}
+
+t_class *cheby_class;
+
+static void *cheby_new(t_floatarg order_f)
+{
+ int i;
+ int order = (int)order_f;
+
+ t_cheby *x = (t_cheby *)pd_new(cheby_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+
+ if (order < 1) order = DEFAULT_ORDER; /* default */
+ if (order > MAX_ORDER) order = MAX_ORDER; /* maximum */
+
+
+ //post("cheby: order = %d", order);
+
+ x->x_ctl.c_order = order;
+ cheby_coef(x, 1, 1);
+ for (i=2; i<order+1; i++){
+ cheby_coef(x, 0, i);
+ }
+
+ return (void *)x;
+}
+
+void cheby_tilde_setup(void)
+{
+ //post("cheby~ v0.1");
+ cheby_class = class_new(gensym("cheby~"), (t_newmethod)cheby_new,
+ (t_method)cheby_free, sizeof(t_cheby), 0, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(cheby_class, t_cheby, x_f);
+ class_addmethod(cheby_class, (t_method)cheby_bang, gensym("bang"), 0);
+ class_addmethod(cheby_class, (t_method)cheby_dsp, gensym("dsp"), 0);
+ class_addmethod(cheby_class, (t_method)cheby_coef, gensym("coef"), A_DEFFLOAT, A_DEFFLOAT, 0);
+
+}
+
diff --git a/modules/diag.c b/modules/diag.c
new file mode 100644
index 0000000..5f7fe36
--- /dev/null
+++ b/modules/diag.c
@@ -0,0 +1,218 @@
+/*
+ * diag.c - diagonal state space system.
+ * treats input dsp block as n parallel signals
+ *
+ * s1 = (a * s1) + (b * s2) + u1;
+ * s2 = (a * s2) - (b * s1) + u2;
+ *
+ * Copyright (c) 2000-2003 by Tom Schouten
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "m_pd.h"
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define MAXORDER 64
+
+typedef struct diagctl
+{
+ t_float *c_state;
+ t_float *c_eigen;
+ t_int c_order;
+} t_diagctl;
+
+typedef struct diag
+{
+ t_object x_obj;
+ t_float x_f;
+ t_diagctl x_ctl;
+} t_diag;
+
+
+static float randfloat(void){
+ float r = rand ();
+ r /= (RAND_MAX/2);
+ r -= 1;
+ return r;
+
+}
+
+static void diag_eigen(t_diag *x, t_floatarg index, t_floatarg val)
+{
+ int i = (int)index;
+ if (i<0) return;
+ if (i>=x->x_ctl.c_order) return;
+ x->x_ctl.c_eigen[i] = val;
+}
+
+/* set decay time of pole at index */
+static void diag_time(t_diag *x, t_floatarg index, t_floatarg time)
+{
+ float r;
+
+ /* time in ms */
+ time *= 0.001;
+
+ if (time < 0.0f) time = 0.0f;
+ r = pow(0.001f, (float)x->x_ctl.c_order / (time * sys_getsr()));
+ if (r < 0.0f) r = 0.0f;
+ if (r > 1.0f) r = 1.0f;
+
+ diag_eigen(x, index, r);
+}
+
+
+
+static void diag_reset(t_diag *x)
+{
+ int i;
+
+ for (i=0; i<x->x_ctl.c_order; i++)
+ {
+ x->x_ctl.c_state[i] = 0;
+ }
+
+}
+
+static void diag_random(t_diag *x)
+{
+ int i;
+
+ for (i=0; i<x->x_ctl.c_order; i++)
+ {
+ x->x_ctl.c_state[i] = randfloat();
+ }
+
+}
+
+
+
+static t_int *diag_perform(t_int *w)
+{
+
+
+ t_float *in = (float *)(w[3]);
+ t_float *out = (float *)(w[4]);
+ t_diagctl *ctl = (t_diagctl *)(w[1]);
+
+ t_float *eigen = ctl->c_eigen;
+ t_float *state = ctl->c_state;
+ t_int n = (t_int)(w[2]);
+
+ t_float x;
+
+ int i;
+
+ for (i=0; i<n; i++)
+ {
+ x = *in;
+ *state += x;
+ *state *= *eigen;
+ *out = *state;
+
+ in++;
+ out++;
+ state++;
+ eigen++;
+ }
+
+
+
+ return (w+5);
+}
+
+
+static void diag_dsp(t_diag *x, t_signal **sp)
+{
+
+ int n = sp[0]->s_n;
+ int i;
+
+ if (x->x_ctl.c_order != n)
+ {
+ if (x->x_ctl.c_state) free(x->x_ctl.c_state);
+ if (x->x_ctl.c_eigen) free(x->x_ctl.c_eigen);
+
+ x->x_ctl.c_state = (t_float *)malloc(n*sizeof(t_float));
+ x->x_ctl.c_eigen = (t_float *)malloc(n*sizeof(t_float));
+
+ for(i=0;i<n;i++)
+ {
+ x->x_ctl.c_state[i] = 0;
+ x->x_ctl.c_eigen[i] = 0;
+ }
+
+ x->x_ctl.c_order = n;
+ }
+
+
+
+ dsp_add(diag_perform, 4, &x->x_ctl, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+
+}
+
+static void diag_free(t_diag *x)
+{
+
+ if (x->x_ctl.c_state) free(x->x_ctl.c_state);
+ if (x->x_ctl.c_eigen) free(x->x_ctl.c_eigen);
+
+
+}
+
+t_class *diag_class;
+
+
+static void *diag_new(t_floatarg permute)
+{
+ t_diag *x = (t_diag *)pd_new(diag_class);
+ int i, n=64;
+
+ outlet_new(&x->x_obj, gensym("signal"));
+
+ x->x_ctl.c_state = (t_float *)malloc(n*sizeof(t_float));
+ x->x_ctl.c_eigen = (t_float *)malloc(n*sizeof(t_float));
+
+ for(i=0;i<n;i++)
+ {
+ x->x_ctl.c_state[i] = 0;
+ x->x_ctl.c_eigen[i] = 0;
+ }
+
+ x->x_ctl.c_order = n;
+
+
+ return (void *)x;
+}
+
+
+void diag_tilde_setup(void)
+{
+ //post("diag~ v0.1");
+ diag_class = class_new(gensym("diag~"), (t_newmethod)diag_new,
+ (t_method)diag_free, sizeof(t_diag), 0, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(diag_class, t_diag, x_f);
+ class_addmethod(diag_class, (t_method)diag_dsp, gensym("dsp"), 0);
+ class_addmethod(diag_class, (t_method)diag_reset, gensym("reset"), 0);
+ class_addmethod(diag_class, (t_method)diag_random, gensym("random"), 0);
+ class_addmethod(diag_class, (t_method)diag_random, gensym("bang"), 0);
+ class_addmethod(diag_class, (t_method)diag_eigen, gensym("eigen"), A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addmethod(diag_class, (t_method)diag_time, gensym("time"), A_DEFFLOAT, A_DEFFLOAT, 0);
+
+}
+
diff --git a/modules/dist.c b/modules/dist.c
new file mode 100644
index 0000000..578e2ef
--- /dev/null
+++ b/modules/dist.c
@@ -0,0 +1,262 @@
+/*
+ * dist.c - wave shaping extern
+ * Copyright (c) 2000-2003 by Tom Schouten
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "extlib_util.h"
+
+
+#define CLIP 0
+#define INVERSE 1
+#define INVERSESQ 2
+#define INVERSECUB 3
+#define RAT1 4
+#define RAT2 5
+#define FULLRECT 6
+#define HALFRECT 7
+#define PULSE 8
+#define NEWTON1 9
+#define UPPERCLIP 10
+
+
+
+
+typedef struct distctl
+{
+ t_float c_gain;
+ t_float c_delay;
+ char c_type;
+} t_distctl;
+
+typedef struct dist
+{
+ t_object x_obj;
+ t_float x_f;
+ t_distctl x_ctl;
+} t_dist;
+
+void dist_bang(t_dist *x)
+{
+
+}
+
+void dist_gain(t_dist *x, t_floatarg f)
+{
+ x->x_ctl.c_gain = f;
+
+}
+
+
+static t_int *dist_perform(t_int *w)
+{
+
+
+ t_float *in = (float *)(w[3]);
+ t_float *out = (float *)(w[4]);
+ t_distctl *ctl = (t_distctl *)(w[1]);
+ t_float gain = ctl->c_gain;
+ t_int i;
+ t_int n = (t_int)(w[2]);
+ t_float x,y,v;
+ t_float z = ctl->c_delay;
+
+ switch(ctl->c_type){
+ case CLIP:
+ for (i = 0; i < n; i++)
+ {
+ x = *in++ * gain;
+ x = (x > 1) ? ( 1.) : x;
+ x = (x < -1) ? (-1.) : x;
+ *out++ = 0.9999 * x;
+
+ }
+ break;
+
+ case INVERSE:
+ for (i = 0; i < n; i++)
+ {
+ x = *in++ * gain;
+ x = (x > 1) ? (2. - 1/x) : x;
+ x = (x < -1) ? (-2. - 1/x) : x;
+ *out++ = x/2.0001;
+
+ }
+ break;
+
+ case INVERSESQ:
+ for (i = 0; i < n; i++)
+ {
+ x = *in++ * gain;
+ x = (x > 1) ? (2. - 1/x) : x;
+ x = (x < -1) ? (-2. - 1/x) : x;
+ x /= 2;
+ *out++ = 1.999*x*x-1;
+
+ }
+ break;
+
+ case INVERSECUB:
+ for (i = 0; i < n; i++)
+ {
+ x = *in++ * gain;
+ x = (x > 1) ? (2. - 1/x) : x;
+ x = (x < -1) ? (-2. - 1/x) : x;
+ x /= 2;
+ *out++ = .9999 * x*x*x;
+
+ }
+ break;
+
+ case RAT1: /*(2*d./((1+(d).^2)))*/
+ for (i = 0; i < n; i++)
+ {
+ x = *in++ * gain;
+ y = (1. + x*x);
+ x = 1.9999*x/y;
+ *out++ = x;
+ }
+ break;
+
+ case RAT2: /*(2*d./((1+(d).^16)))*/
+ for (i = 0; i < n; i++)
+ {
+ x = *in++ * gain;
+ y = x*x;
+ y *= y;
+ y *= y;
+ y *= y;
+ y = (1. + y);
+ x = 1.2*x/y;
+ *out++ = x;
+ }
+ break;
+
+ case FULLRECT:
+ for (i = 0; i < n; i++)
+ {
+ x = *in++ * gain;
+ x = (x>0) ? x : -x;
+ x = (x>1) ? 1 : x;
+ *out++ = 1.9999*(x-.5);
+ }
+ break;
+
+ case HALFRECT:
+ for (i = 0; i < n; i++)
+ {
+ x = *in++ * gain;
+ x = (x>0) ? x : 0;
+ x = (x>1) ? 1 : x;
+ *out++ = 1.9999*(x-.5);
+ }
+ break;
+
+ case PULSE:
+ for (i = 0; i < n; i++)
+ {
+ x = *in++ * gain;
+ y = (x>0) ? (1):(-1);
+ x = (z*y > 0) ? (0) : (y);
+ *out++ = .9999 * x;
+ z = x;
+
+ }
+ ctl->c_delay = z;
+ break;
+
+ case NEWTON1:
+ for (i = 0; i < n; i++)
+ {
+ x = *in++ * gain;
+ y = 1./(1.+x*x);
+
+ z = .5;
+ z = .5*(y/z + z);
+ z = .5*(y/z + z);
+ z = .5*(y/z + z);
+
+ /* z = .5*(y/z + z);
+ * z = .5*(y/z + z);
+ * z = .5*(y/z + z);
+ */
+
+ *out++ = x * z;
+
+ }
+ ctl->c_delay = z;
+ break;
+
+ case UPPERCLIP:
+ for (i = 0; i < n; i++)
+ {
+ x = *in++ * gain;
+
+ x = (x < 0.0f) ? 0.0f : x;
+ x = (x > 0.9999f) ? 0.9999f : x;
+
+ *out++ = x;
+
+ }
+ break;
+
+ default:
+
+ for (i = 0; i < n; i++) *out++ = *in++;
+ break;
+
+ }
+
+ return (w+5);
+}
+
+static void dist_dsp(t_dist *x, t_signal **sp)
+{
+ dsp_add(dist_perform, 4, &x->x_ctl, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+
+}
+void dist_free(void)
+{
+
+}
+
+t_class *dist_class;
+
+void *dist_new(t_floatarg type)
+{
+ t_dist *x = (t_dist *)pd_new(dist_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("gain"));
+ outlet_new(&x->x_obj, gensym("signal"));
+
+ dist_gain(x, 1);
+ x->x_ctl.c_type = (char)type;
+ x->x_ctl.c_delay = 0;
+
+ return (void *)x;
+}
+
+void dist_tilde_setup(void)
+{
+ //post("dist~ v0.1");
+ dist_class = class_new(gensym("dist~"), (t_newmethod)dist_new,
+ (t_method)dist_free, sizeof(t_dist), 0, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(dist_class, t_dist, x_f);
+ class_addmethod(dist_class, (t_method)dist_bang, gensym("bang"), 0);
+ class_addmethod(dist_class, (t_method)dist_dsp, gensym("dsp"), 0);
+ class_addmethod(dist_class, (t_method)dist_gain, gensym("gain"), A_FLOAT, 0);
+
+}
+
diff --git a/modules/dwt.c b/modules/dwt.c
new file mode 100644
index 0000000..caa75ff
--- /dev/null
+++ b/modules/dwt.c
@@ -0,0 +1,893 @@
+/*
+ * dwt.c - code for discrete wavelet transform
+ * (symmetric interpolating biorthogonal wavelets using the lifting transform)
+ * Copyright (c) 2000-2003 by Tom Schouten
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include "m_pd.h"
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define MAXORDER 64
+
+typedef enum{DWT,IDWT,DWT16,IDWT16} t_dwttype;
+
+typedef struct dwtctl
+{
+ t_float c_update[MAXORDER];
+ t_float c_predict[MAXORDER];
+ t_int c_nupdate;
+ t_int c_npredict;
+ t_int c_levels;
+ t_int c_fakein;
+ t_float c_fakeval;
+ t_int c_mask;
+ char c_name[16];
+ t_int *c_clutter;
+ t_int *c_unclutter;
+ t_int c_permute;
+ t_dwttype c_type;
+} t_dwtctl;
+
+typedef struct dwt
+{
+ t_object x_obj;
+ t_float x_f;
+ t_dwtctl x_ctl;
+} t_dwt;
+
+
+static void dwt_even(t_dwt *x, t_floatarg f)
+{
+ int k = (int)f;
+ int i, j;
+ float *p = x->x_ctl.c_predict;
+ float *u = x->x_ctl.c_update;
+ float l, xi, xj;
+
+ if ((k>0) && (k<MAXORDER/2))
+ {
+ for (i=0; i<k; i++){
+ l = 1;
+ xi = 1+2*i;
+ for (j=0; j<k; j++)
+ {
+ xj = 1+2*j;
+ if (i != j) l /= (1 - ((xi*xi) / (xj*xj)));
+ }
+ l *= .5;
+
+ p[k-i-1] = l;
+ p[k+i] = l;
+ u[k-i-1] = l/2;
+ u[k+i] = l/2;
+ }
+
+ x->x_ctl.c_npredict = 2*k;
+ x->x_ctl.c_nupdate = 2*k;
+ }
+}
+
+static void dwt_wavelet(t_dwt *x, t_floatarg f)
+{
+ int k = (int)f;
+ t_float *p = x->x_ctl.c_predict;
+ t_float *u = x->x_ctl.c_update;
+ t_int *np = &x->x_ctl.c_npredict;
+ t_int *nu = &x->x_ctl.c_nupdate;
+
+ switch(k)
+ {
+ default:
+ case 1: /* haar */
+ *np = *nu = 2; /* actual order is one */
+ p[0] = 1;
+ p[1] = 0;
+ u[0] = 0;
+ u[1] = .5;
+ break;
+
+ case 2: /* hat */
+ case 3:
+ *np = *nu = 2;
+ p[0] = .5;
+ p[1] = .5;
+ u[0] = .25;
+ u[1] = .25;
+ break;
+
+ case 4: /* N = 4, N~ = 4 */
+ case 5:
+ *np = *nu = 4;
+ p[0] = -0.0625;
+ p[1] = 0.5625;
+ p[2] = 0.5625;
+ p[3] = -0.0625;
+ u[0] = -0.03125;
+ u[1] = 0.28125;
+ u[2] = 0.28125;
+ u[3] = -0.03125;
+ break;
+
+ case 6:
+ case 7:
+ *np = *nu = 6;
+ p[0] = 0.01171875000000;
+ p[1] = -0.09765625000000;
+ p[2] = 0.58593750000000;
+ p[3] = 0.58593750000000;
+ p[4] = -0.09765625000000;
+ p[5] = 0.01171875000000;
+ u[0] = 0.00585937500000;
+ u[1] = -0.04882812500000;
+ u[2] = 0.29296875000000;
+ u[3] = 0.29296875000000;
+ u[4] = -0.04882812500000;
+ u[5] = 0.00585937500000;
+ break;
+ }
+}
+
+static inline void dwt_perform_permutation(t_float *S, int n, t_int *f)
+{
+ t_int k,l;
+ t_float swap;
+ for(k=0; k<n; k++)
+ {
+ l = f[k];
+ while (l<k) l = f[l];
+ swap = S[k];
+ S[k] = S[l];
+ S[l] = swap;
+ }
+}
+
+static void dwt_permutation(t_dwt *x, t_int n){
+
+ t_dwtctl *ctl = &x->x_ctl;
+ t_int k, L=0, l, start, power;
+ t_int nsave = n;
+
+ while(nsave>>=1) L++;
+
+ if (ctl->c_clutter) free(ctl->c_clutter);
+ if (ctl->c_unclutter) free(ctl->c_unclutter);
+
+ ctl->c_clutter = (t_int *)malloc(n*sizeof(t_int));
+ ctl->c_unclutter = (t_int *)malloc(n*sizeof(t_int));
+
+
+ for(l = L, start = n/2, power=1; l>0; l--, start /=2, power *=2)
+ {
+ for(k=0; k<start; k++)
+ {
+ ctl->c_unclutter[start+k] = (1 + 2*k) * power;
+ }
+ }
+ ctl->c_unclutter[0] = 0;
+
+ for(k=0; k<n; k++)
+ ctl->c_clutter[ctl->c_unclutter[k]] = k;
+
+ return;
+
+ /* debug */
+ for(k=0; k<n; k++)
+ printf("clutter[%d] = %d\n", k, ctl->c_clutter[k]);
+ for(k=0; k<n; k++)
+ printf("unclutter[%d] = %d\n", k, ctl->c_unclutter[k]);
+
+ exit(1);
+}
+
+
+
+static void idwt_coef(t_dwt *x, t_floatarg index, t_floatarg value)
+{
+ x->x_ctl.c_fakein = (int)index;
+ x->x_ctl.c_fakeval = value;
+
+}
+
+static void dwt_print(t_dwt *x)
+{
+ int i;
+
+ printf("%s: predict: [ ", x->x_ctl.c_name);
+ for (i=0; i<x->x_ctl.c_npredict; i++) printf("%f ", x->x_ctl.c_predict[i]);
+ printf("], ");
+
+ printf("update: [ ");
+ for (i=0; i<x->x_ctl.c_nupdate; i++) printf("%f ", x->x_ctl.c_update[i]);
+ printf("]\n");
+
+
+
+}
+
+
+static void dwt_filter(t_dwt *x, t_symbol *s, int argc, t_atom *argv)
+{
+ int invalid_argument = 0;
+ int i;
+
+ char *name = x->x_ctl.c_name;
+
+ float *pfilter = x->x_ctl.c_predict;
+ float *ufilter = x->x_ctl.c_update;
+ float *mask = NULL;
+
+ int *length = NULL;
+ float sum = 0;
+
+ if (s == gensym("predict"))
+ {
+ mask = pfilter;
+ length = &(x->x_ctl.c_npredict);
+ }
+ else if (s == gensym("update"))
+ {
+ mask = ufilter;
+ length = &(x->x_ctl.c_nupdate);
+ }
+ else if (s == gensym("mask"))
+ {
+ mask = NULL;
+ }
+ else
+ {
+ return;
+ }
+
+ if (argc >= MAXORDER) post("%s: error, maximum order exceeded.",name);
+ else if ((x->x_ctl.c_type == DWT16 || x->x_ctl.c_type == IDWT16 ) && (argc != 16))
+ post("%s: error, need to have 16 coefficients.",name);
+ else if (argc == 0) post("%s: no arguments given.",name);
+ else if (argc & 1) post("%s: error, only an even number of coefficients is allowed.", name);
+ else
+ {
+ for (i=0; i<argc; i++){
+ if (argv[i].a_type != A_FLOAT )
+ {
+ invalid_argument = 1;
+ break;
+ }
+ }
+
+ if (invalid_argument) post("%s: invalid argument, must be a number.", name);
+ else
+ {
+ if (mask) /* one of update / predict */
+ {
+ for (i=0; i<argc; i++) mask[i] = argv[i].a_w.w_float;
+ *length = argc;
+ }
+ else /* both + normalization */
+ {
+ for (i=0; i<argc; i++) sum += argv[i].a_w.w_float;
+ for (i=0; i<argc; i++)
+ {
+ pfilter[i] = argv[i].a_w.w_float / sum;
+ ufilter[i] = argv[i].a_w.w_float / (sum*2);
+ }
+ x->x_ctl.c_npredict = argc;
+ x->x_ctl.c_nupdate = argc;
+ }
+ }
+
+ }
+
+}
+
+
+
+static inline void dwtloop(float *vector,
+ int source,
+ int dest,
+ int increment,
+ int backup,
+ int numcoef,
+ int mask,
+ float *filter,
+ int filtlength,
+ float sign)
+{
+
+ int k,m;
+ float acc;
+
+ for (k = 0; k < numcoef; k++)
+ {
+ acc = 0;
+ for (m = 0; m < filtlength; m++)
+ {
+
+ acc += filter[m] * vector[source];
+ source += increment;
+ source &= mask;
+ }
+ vector[dest] += sign * acc;
+ dest += increment;
+ source -= backup;
+ source &= mask;
+ }
+
+}
+
+static inline void dwtloop16(float *vector,
+ int source,
+ int dest,
+ int increment,
+ int backup,
+ int numcoef,
+ int mask,
+ float *filter,
+ int filtlength, /* ignored, set to 16 */
+ float sign)
+{
+
+ int k,m;
+ float acc;
+
+ for (k = 0; k < numcoef; k++)
+ {
+ acc = 0;
+
+ acc += filter[0] * vector[source];
+ source += increment;
+ source &= mask;
+
+ acc += filter[1] * vector[source];
+ source += increment;
+ source &= mask;
+
+ acc += filter[2] * vector[source];
+ source += increment;
+ source &= mask;
+
+ acc += filter[3] * vector[source];
+ source += increment;
+ source &= mask;
+
+ acc += filter[4] * vector[source];
+ source += increment;
+ source &= mask;
+
+ acc += filter[5] * vector[source];
+ source += increment;
+ source &= mask;
+
+ acc += filter[6] * vector[source];
+ source += increment;
+ source &= mask;
+
+ acc += filter[7] * vector[source];
+ source += increment;
+ source &= mask;
+
+ acc += filter[8] * vector[source];
+ source += increment;
+ source &= mask;
+
+ acc += filter[9] * vector[source];
+ source += increment;
+ source &= mask;
+
+ acc += filter[10] * vector[source];
+ source += increment;
+ source &= mask;
+
+ acc += filter[11] * vector[source];
+ source += increment;
+ source &= mask;
+
+ acc += filter[12] * vector[source];
+ source += increment;
+ source &= mask;
+
+ acc += filter[13] * vector[source];
+ source += increment;
+ source &= mask;
+
+ acc += filter[14] * vector[source];
+ source += increment;
+ source &= mask;
+
+ acc += filter[15] * vector[source];
+ source += increment;
+ source &= mask;
+
+ vector[dest] += sign * acc;
+ dest += increment;
+ source -= backup;
+ source &= mask;
+ }
+
+}
+
+
+
+
+
+static t_int *dwt_perform(t_int *w)
+{
+
+
+ t_float *in = (float *)(w[3]);
+ t_float *out = (float *)(w[4]);
+ t_dwtctl *ctl = (t_dwtctl *)(w[1]);
+
+
+ t_int n = (t_int)(w[2]);
+
+ int i;
+
+ int numcoef = n/2;
+ /* int source_u = ((1 - ctl->c_nupdate)/2 - 1);
+ * int source_p = ((1 - ctl->c_npredict)/2);
+ */
+ int source_u = ((2 - ctl->c_nupdate) - 1);
+ int source_p = ((2 - ctl->c_npredict));
+ int increment = 2;
+ int dest = 1;
+ int backup_u = (ctl->c_nupdate-1)*2;
+ int backup_p = (ctl->c_npredict-1)*2;
+
+ /* copy input to output */
+ if (in != out)
+ for (i=0; i<n; i++) out[i]=in[i];
+
+
+ /* fake input */
+ /* for (i=0; i<n; i++) out[i]=0; out[n/8]=1;*/
+
+
+
+ /* backward transform */
+
+
+ /* iterate over all levels */
+ for (i=0; i < ctl->c_levels; i++){
+
+
+ /* foreward predict */
+ dwtloop(out, (source_p & (n-1)), dest, increment, backup_p, numcoef, n-1, ctl->c_predict, ctl->c_npredict, -1);
+
+
+ /* foreward update */
+ dwtloop(out, (source_u & (n-1)), 0, increment, backup_u, numcoef, n-1, ctl->c_update, ctl->c_nupdate, +1);
+
+
+ /* update control parameters */
+ numcoef /= 2;
+ source_p *= 2;
+ source_u *= 2;
+ backup_p *= 2;
+ backup_u *= 2;
+ increment *= 2;
+ dest *= 2;
+ }
+
+ if (ctl->c_permute)
+ dwt_perform_permutation(out, n, ctl->c_unclutter);
+
+
+ return (w+5);
+}
+
+
+
+
+static t_int *idwt_perform(t_int *w)
+{
+
+
+ t_float *in = (float *)(w[3]);
+ t_float *out = (float *)(w[4]);
+ t_dwtctl *ctl = (t_dwtctl *)(w[1]);
+
+
+ t_int n = (t_int)(w[2]);
+
+ int i;
+
+ int numcoef = 1;
+ int source_u = ((2 - ctl->c_nupdate) - 1) * (n/2);
+ int source_p = ((2 - ctl->c_npredict)) * (n/2);
+ int increment = n;
+ int dest = n/2;
+ int backup_u = (ctl->c_nupdate-1)*n;
+ int backup_p = (ctl->c_npredict-1)*n;
+ int fake_in = ctl->c_fakein;
+ float fake_val = ctl->c_fakeval;
+
+ /* copy input to output */
+ if (in != out)
+ for (i=0; i<n; i++) out[i]=in[i];
+
+
+ /* fake input */
+
+ if ((fake_in >= 0) && (fake_in<n)){
+ for (i=0; i<n; i++) out[i]=0;
+ out[fake_in]=fake_val;
+ }
+
+
+ if (ctl->c_permute)
+ dwt_perform_permutation(out, n, ctl->c_clutter);
+
+
+ /* backward transform */
+
+
+ /* iterate over all levels */
+ for (i=0; i < ctl->c_levels; i++){
+
+ /* backward update */
+ dwtloop(out, (source_u & (n-1)), 0, increment, backup_u, numcoef, n-1, ctl->c_update, ctl->c_nupdate, -1);
+
+
+ /* backward predict */
+ dwtloop(out, (source_p & (n-1)), dest, increment, backup_p, numcoef, n-1, ctl->c_predict, ctl->c_npredict, +1);
+
+ /* update control parameters */
+ numcoef *= 2;
+ source_p /= 2;
+ source_u /= 2;
+ backup_p /= 2;
+ backup_u /= 2;
+ increment /= 2;
+ dest /= 2;
+ }
+
+
+
+ return (w+5);
+}
+
+static t_int *dwt16_perform(t_int *w)
+{
+
+
+ t_float *in = (float *)(w[3]);
+ t_float *out = (float *)(w[4]);
+ t_dwtctl *ctl = (t_dwtctl *)(w[1]);
+
+
+ t_int n = (t_int)(w[2]);
+
+ int i;
+
+ int numcoef = n/2;
+ /* int source_u = ((1 - ctl->c_nupdate)/2 - 1);
+ * int source_p = ((1 - ctl->c_npredict)/2);
+ */
+ int source_u = ((2 - ctl->c_nupdate) - 1);
+ int source_p = ((2 - ctl->c_npredict));
+ int increment = 2;
+ int dest = 1;
+ int backup_u = (ctl->c_nupdate-1)*2;
+ int backup_p = (ctl->c_npredict-1)*2;
+
+ /* copy input to output */
+ if (in != out)
+ for (i=0; i<n; i++) out[i]=in[i];
+
+
+ /* fake input */
+ /* for (i=0; i<n; i++) out[i]=0; out[n/8]=1;*/
+
+
+
+ /* backward transform */
+
+
+ /* iterate over all levels */
+ for (i=0; i < ctl->c_levels; i++){
+
+
+ /* foreward predict */
+ dwtloop16(out, (source_p & (n-1)), dest, increment, backup_p, numcoef, n-1, ctl->c_predict, 16, -1);
+
+
+ /* foreward update */
+ dwtloop16(out, (source_u & (n-1)), 0, increment, backup_u, numcoef, n-1, ctl->c_update, 16, +1);
+
+
+ /* update control parameters */
+ numcoef /= 2;
+ source_p *= 2;
+ source_u *= 2;
+ backup_p *= 2;
+ backup_u *= 2;
+ increment *= 2;
+ dest *= 2;
+ }
+
+ if (ctl->c_permute)
+ dwt_perform_permutation(out, n, ctl->c_unclutter);
+
+
+ return (w+5);
+}
+
+
+
+
+static t_int *idwt16_perform(t_int *w)
+{
+
+
+ t_float *in = (float *)(w[3]);
+ t_float *out = (float *)(w[4]);
+ t_dwtctl *ctl = (t_dwtctl *)(w[1]);
+
+
+ t_int n = (t_int)(w[2]);
+
+ int i;
+
+ int numcoef = 1;
+ int source_u = ((2 - ctl->c_nupdate) - 1) * (n/2);
+ int source_p = ((2 - ctl->c_npredict)) * (n/2);
+ int increment = n;
+ int dest = n/2;
+ int backup_u = (ctl->c_nupdate-1)*n;
+ int backup_p = (ctl->c_npredict-1)*n;
+ int fake_in = ctl->c_fakein;
+ float fake_val = ctl->c_fakeval;
+
+ /* copy input to output */
+ if (in != out)
+ for (i=0; i<n; i++) out[i]=in[i];
+
+
+ /* fake input */
+
+ if ((fake_in >= 0) && (fake_in<n)){
+ for (i=0; i<n; i++) out[i]=0;
+ out[fake_in]=fake_val;
+ }
+
+
+ if (ctl->c_permute)
+ dwt_perform_permutation(out, n, ctl->c_clutter);
+
+
+ /* backward transform */
+
+
+ /* iterate over all levels */
+ for (i=0; i < ctl->c_levels; i++){
+
+ /* backward update */
+ dwtloop16(out, (source_u & (n-1)), 0, increment, backup_u, numcoef, n-1, ctl->c_update, 16, -1);
+
+
+ /* backward predict */
+ dwtloop16(out, (source_p & (n-1)), dest, increment, backup_p, numcoef, n-1, ctl->c_predict, 16, +1);
+
+ /* update control parameters */
+ numcoef *= 2;
+ source_p /= 2;
+ source_u /= 2;
+ backup_p /= 2;
+ backup_u /= 2;
+ increment /= 2;
+ dest /= 2;
+ }
+
+
+
+ return (w+5);
+}
+
+
+
+static void dwt_dsp(t_dwt *x, t_signal **sp)
+{
+
+ int n = sp[0]->s_n;
+ int ln = 0;
+
+ dwt_permutation(x, n);
+
+ x->x_ctl.c_mask = n-1;
+ while (n >>= 1) ln++;
+ x->x_ctl.c_levels = ln;
+
+ switch(x->x_ctl.c_type){
+ case DWT:
+ dsp_add(dwt_perform, 4, &x->x_ctl, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+ break;
+ case IDWT:
+ dsp_add(idwt_perform, 4, &x->x_ctl, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+ break;
+ case DWT16:
+ dsp_add(dwt16_perform, 4, &x->x_ctl, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+ break;
+ case IDWT16:
+ dsp_add(idwt16_perform, 4, &x->x_ctl, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+ break;
+
+
+ }
+}
+
+
+void dwt_free(t_dwt *x)
+{
+
+ if (x->x_ctl.c_clutter) free(x->x_ctl.c_clutter);
+ if (x->x_ctl.c_unclutter) free(x->x_ctl.c_unclutter);
+
+
+}
+
+t_class *dwt_class, *idwt_class, *dwt16_class, *idwt16_class;
+
+
+static void dwt_reset(t_dwt *x)
+{
+ bzero(x->x_ctl.c_update, 16*sizeof(t_float));
+ bzero(x->x_ctl.c_predict, 16*sizeof(t_float));
+
+ x->x_ctl.c_update[7] = .25;
+ x->x_ctl.c_update[8] = .25;
+ x->x_ctl.c_nupdate = 16;
+
+ x->x_ctl.c_predict[7] = .5;
+ x->x_ctl.c_predict[8] = .5;
+ x->x_ctl.c_npredict = 16;
+
+ x->x_ctl.c_fakein = -1;
+ x->x_ctl.c_fakeval = 0;
+
+}
+
+
+static void *dwt_new_common(t_floatarg permute)
+{
+ t_dwt *x = (t_dwt *)pd_new(dwt_class);
+ int i;
+
+ outlet_new(&x->x_obj, gensym("signal"));
+
+ /* init data */
+ dwt_reset(x);
+
+ x->x_ctl.c_clutter = NULL;
+ x->x_ctl.c_unclutter = NULL;
+ x->x_ctl.c_permute = (t_int) permute;
+
+ return (void *)x;
+
+
+}
+
+static void *dwt_new(t_floatarg permute)
+{
+ t_dwt *x = dwt_new_common(permute);
+ sprintf(x->x_ctl.c_name,"dwt");
+ x->x_ctl.c_type = DWT;
+ return (void *)x;
+}
+
+
+static void *idwt_new(t_floatarg permute)
+{
+ t_dwt *x = dwt_new_common(permute);
+ sprintf(x->x_ctl.c_name,"idwt");
+ x->x_ctl.c_type = IDWT;
+ return (void *)x;
+}
+
+static void *dwt16_new(t_floatarg permute)
+{
+ t_dwt *x = dwt_new_common(permute);
+ sprintf(x->x_ctl.c_name,"dwt16");
+ x->x_ctl.c_type = DWT16;
+ return (void *)x;
+}
+
+
+static void *idwt16_new(t_floatarg permute)
+{
+ t_dwt *x = dwt_new_common(permute);
+ sprintf(x->x_ctl.c_name,"idwt16");
+ x->x_ctl.c_type = IDWT16;
+ return (void *)x;
+}
+
+
+void dwt_tilde_setup(void)
+{
+ //post("dwt~ v0.1");
+
+
+ dwt_class = class_new(gensym("dwt~"), (t_newmethod)dwt_new,
+ (t_method)dwt_free, sizeof(t_dwt), 0, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(dwt_class, t_dwt, x_f);
+ class_addmethod(dwt_class, (t_method)dwt_print, gensym("print"), 0);
+ class_addmethod(dwt_class, (t_method)dwt_reset, gensym("reset"), 0);
+ class_addmethod(dwt_class, (t_method)dwt_dsp, gensym("dsp"), 0);
+
+ class_addmethod(dwt_class, (t_method)dwt_filter, gensym("predict"), A_GIMME, 0);
+ class_addmethod(dwt_class, (t_method)dwt_filter, gensym("update"), A_GIMME, 0);
+ class_addmethod(dwt_class, (t_method)dwt_filter, gensym("mask"), A_GIMME, 0);
+
+ class_addmethod(dwt_class, (t_method)dwt_even, gensym("even"), A_DEFFLOAT, 0);
+ class_addmethod(dwt_class, (t_method)idwt_coef, gensym("coef"), A_DEFFLOAT, A_DEFFLOAT, 0);
+
+
+
+ /*class_addmethod(dwt_class, (t_method)dwt_wavelet, gensym("wavelet"), A_DEFFLOAT, 0); */
+
+
+ idwt_class = class_new(gensym("idwt~"), (t_newmethod)idwt_new,
+ (t_method)dwt_free, sizeof(t_dwt), 0, A_DEFFLOAT, 0);
+
+ CLASS_MAINSIGNALIN(idwt_class, t_dwt, x_f);
+ class_addmethod(idwt_class, (t_method)dwt_print, gensym("print"), 0);
+ class_addmethod(idwt_class, (t_method)dwt_dsp, gensym("dsp"), 0);
+
+ class_addmethod(idwt_class, (t_method)dwt_filter, gensym("predict"), A_GIMME, 0);
+ class_addmethod(idwt_class, (t_method)dwt_filter, gensym("update"), A_GIMME, 0);
+ class_addmethod(idwt_class, (t_method)dwt_filter, gensym("mask"), A_GIMME, 0);
+
+ class_addmethod(idwt_class, (t_method)idwt_coef, gensym("coef"), A_DEFFLOAT, A_DEFFLOAT, 0);
+
+ class_addmethod(idwt_class, (t_method)dwt_even, gensym("even"), A_DEFFLOAT, 0);
+
+
+
+ dwt16_class = class_new(gensym("dwt16~"), (t_newmethod)dwt16_new,
+ (t_method)dwt_free, sizeof(t_dwt), 0, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(dwt16_class, t_dwt, x_f);
+ class_addmethod(dwt16_class, (t_method)dwt_print, gensym("print"), 0);
+ class_addmethod(dwt16_class, (t_method)dwt_reset, gensym("reset"), 0);
+ class_addmethod(dwt16_class, (t_method)dwt_dsp, gensym("dsp"), 0);
+
+ class_addmethod(dwt16_class, (t_method)dwt_filter, gensym("predict"), A_GIMME, 0);
+ class_addmethod(dwt16_class, (t_method)dwt_filter, gensym("update"), A_GIMME, 0);
+ class_addmethod(dwt16_class, (t_method)dwt_filter, gensym("mask"), A_GIMME, 0);
+
+
+
+
+ idwt16_class = class_new(gensym("idwt16~"), (t_newmethod)idwt16_new,
+ (t_method)dwt_free, sizeof(t_dwt), 0, A_DEFFLOAT, 0);
+
+ CLASS_MAINSIGNALIN(idwt16_class, t_dwt, x_f);
+ class_addmethod(idwt16_class, (t_method)dwt_print, gensym("print"), 0);
+ class_addmethod(idwt16_class, (t_method)dwt_dsp, gensym("dsp"), 0);
+
+ class_addmethod(idwt16_class, (t_method)dwt_filter, gensym("predict"), A_GIMME, 0);
+ class_addmethod(idwt16_class, (t_method)dwt_filter, gensym("update"), A_GIMME, 0);
+ class_addmethod(idwt16_class, (t_method)dwt_filter, gensym("mask"), A_GIMME, 0);
+
+ class_addmethod(idwt16_class, (t_method)idwt_coef, gensym("coef"), A_DEFFLOAT, A_DEFFLOAT, 0);
+
+
+
+
+}
+
diff --git a/modules/dynwav.c b/modules/dynwav.c
new file mode 100644
index 0000000..0ff75f3
--- /dev/null
+++ b/modules/dynwav.c
@@ -0,0 +1,318 @@
+/*
+ * dynwav.c - dynamic wavetable oscillator
+ * data organization is in (real, imag) pairs
+ * the first 2 components are (DC, NY)
+ * Copyright (c) 2000-2003 by Tom Schouten
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include "m_pd.h"
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define MAXORDER 1024
+
+typedef struct dynwavctl
+{
+ t_float *c_buf1; /* current */
+ t_float *c_buf2; /* old */
+ t_int c_order;
+
+} t_dynwavctl;
+
+typedef struct dynwav
+{
+ t_object x_obj;
+ t_float x_f;
+ t_dynwavctl x_ctl;
+} t_dynwav;
+
+
+static t_int *dynwav_perform(t_int *w)
+{
+
+
+ t_float *wave = (float *)(w[3]);
+ t_float *freq = (float *)(w[4]);
+ t_float *out = (float *)(w[5]);
+ t_dynwavctl *ctl = (t_dynwavctl *)(w[1]);
+ t_int n = (t_int)(w[2]);
+
+ t_float *buf, *dbuf, *swap;
+
+ int i;
+ int mask = n-1;
+
+
+ /* swap buffer pointers */
+ swap = ctl->c_buf1; /* this is the last one stored */
+ buf = ctl->c_buf1 = ctl->c_buf2; /* put oldest in newest to overwrite */
+ dbuf = ctl->c_buf2 = swap; /* put last one in oldest */
+
+
+ if (buf && dbuf)
+ {
+
+ /* store input wavetable in buffer */
+ memcpy(buf, wave, n*sizeof(t_float));
+
+
+ for (i = 0; i < n; i++)
+ {
+ float findex = *freq++ * (t_float)n;
+ int index = findex;
+ float frac, a, b, c, d, cminusb, q, r;
+ int ia, ib, ic, id;
+
+ frac = findex - index;
+
+ ia = (index-1) & mask;
+ ib = (index ) & mask;
+ ic = (index+1) & mask;
+ id = (index+2) & mask;
+
+ q = i+1;
+ q /= n;
+
+ r = n-1-i;
+ r /= n;
+
+ /* get 4 points, wrap index */
+ a = q * buf[ia] + r * dbuf[ia];
+ b = q * buf[ib] + r * dbuf[ib];
+ c = q * buf[ic] + r * dbuf[ic];
+ d = q * buf[id] + r * dbuf[id];
+
+ cminusb = c-b;
+ *out++ = b + frac * (cminusb - 0.5f * (frac-1.) *
+ ((a - d + 3.0f * cminusb) * frac +
+ (b - a - cminusb)));
+ }
+
+ }
+ return (w+6);
+}
+
+static t_int *dynwav_perform_8point(t_int *w) /* werkt nog nie tegoei */
+{
+
+
+ t_float *wave = (float *)(w[3]);
+ t_float *freq = (float *)(w[4]);
+ t_float *out = (float *)(w[5]);
+ t_dynwavctl *ctl = (t_dynwavctl *)(w[1]);
+ t_int n = (t_int)(w[2]);
+
+ t_float *buf, *dbuf, *swap;
+
+ int i;
+ int mask = n-1;
+
+
+ /* swap buffer pointers */
+ swap = ctl->c_buf1; /* this is the last one stored */
+ buf = ctl->c_buf1 = ctl->c_buf2; /* put oldest in newest to overwrite */
+ dbuf = ctl->c_buf2 = swap; /* put last one in oldest */
+
+
+ if (buf && dbuf)
+ {
+
+ /* const float N1 = 1 / ( 2 * (1-(1/9)) * (1-(1/25)) * (1-(1/49)) );
+ ** const float N2 = 1 / ( (1-(9)) * 2 * (1-(9/25)) * (1-(9/49)) );
+ ** const float N3 = 1 / ( (1-(25)) * (1-(25/9)) * 2 * (1-(25/49)) );
+ ** const float N4 = 1 / ( (1-(49)) * (1-(49/9)) * (1-(49/25)) * 2 );
+ */
+
+ const float N1 = 0.59814453125;
+ const float N2 = -0.11962890625;
+ const float N3 = 0.02392578125;
+ const float N4 = -0.00244140625;
+
+
+ /* store input wavetable in buffer */
+ memcpy(buf, wave, n*sizeof(t_float));
+
+
+ for (i = 0; i < n; i++)
+ {
+ float findex = *freq++ * (t_float)n;
+ int index = findex;
+ float frac, q, r, fm, fp, fe, fo;
+ float x1, x2, x3, x4;
+ float g1, g2, g3, g4;
+ float gg, g2g3g4, g1g3g4, g1g2g4, g1g2g3;
+ float acc;
+ int im, ip;
+
+ frac = 2 *(findex - index) - 1;
+
+ x1 = frac;
+ x2 = frac/3;
+ x3 = frac/5;
+ x4 = frac/7;
+
+ g1 = 1 - x1*x1;
+ g2 = 1 - x2*x2;
+ g3 = 1 - x3*x3;
+ g4 = 1 - x4*x4;
+
+ gg = g3 * g4;
+ g2g3g4 = g2 * gg; /* 1 */
+ g1g3g4 = g1 * gg; /* 2 */
+ gg = g1 * g2;
+ g1g2g4 = g4 * gg; /* 3 */
+ g1g2g3 = g3 * gg; /* 4 */
+
+
+ /* triangle interpolation between current and past wavetable*/
+ q = i+1;
+ q /= n;
+
+ r = n-1-i;
+ r /= n;
+
+
+ /* 1, -1*/
+ im = (index ) & mask;
+ ip = (index+1) & mask;
+ fm = q * buf[im] + r * dbuf[im];
+ fp = q * buf[ip] + r * dbuf[ip];
+ fe = fp + fm;
+ fo = fp - fm;
+
+ acc = N1 * g2g3g4 * (fe + x1*fo);
+
+ /* 2, -2 */
+ im = (index-1) & mask;
+ ip = (index+2) & mask;
+ fm = q * buf[im] + r * dbuf[im];
+ fp = q * buf[ip] + r * dbuf[ip];
+ fe = fp + fm;
+ fo = fp - fm;
+
+ acc += N2 * g1g3g4 * (fe + x2*fo);
+
+ /* 3, -3 */
+ im = (index-2) & mask;
+ ip = (index+3) & mask;
+ fm = q * buf[im] + r * dbuf[im];
+ fp = q * buf[ip] + r * dbuf[ip];
+ fe = fp + fm;
+ fo = fp - fm;
+
+ acc += N3 * g1g2g4 * (fe + x3*fo);
+
+ /* 4, -4 */
+ im = (index-3) & mask;
+ ip = (index+4) & mask;
+ fm = q * buf[im] + r * dbuf[im];
+ fp = q * buf[ip] + r * dbuf[ip];
+ fe = fp + fm;
+ fo = fp - fm;
+
+ acc += N4 * g1g2g3 * (fe + x4*fo);
+
+
+ *out++ = acc;
+
+ }
+
+ }
+ return (w+6);
+}
+
+
+static void dynwav_dsp(t_dynwav *x, t_signal **sp)
+{
+ int n = sp[0]->s_n;
+ int k;
+
+ if (x->x_ctl.c_order != n)
+ {
+ if (x->x_ctl.c_buf1) free (x->x_ctl.c_buf1);
+ if (x->x_ctl.c_buf2) free (x->x_ctl.c_buf2);
+
+ x->x_ctl.c_buf1 = (t_float *)malloc(n*sizeof(t_float));
+ x->x_ctl.c_buf2 = (t_float *)malloc(n*sizeof(t_float));
+
+ for(k=0; k<n; k++)
+ {
+ x->x_ctl.c_buf1[k] = 0;
+ x->x_ctl.c_buf2[k] = 0;
+ }
+
+ x->x_ctl.c_order = n;
+ }
+
+
+ dsp_add(dynwav_perform_8point, 5, &x->x_ctl, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec);
+
+
+}
+static void dynwav_free(t_dynwav *x)
+{
+
+ if (x->x_ctl.c_buf1) free (x->x_ctl.c_buf1);
+ if (x->x_ctl.c_buf2) free (x->x_ctl.c_buf2);
+
+}
+
+t_class *dynwav_class;
+
+static void *dynwav_new(t_floatarg order)
+{
+ t_dynwav *x = (t_dynwav *)pd_new(dynwav_class);
+ int iorder = (int)order;
+ int i, n=64, k;
+
+ /* in 2 */
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("signal"), gensym("signal"));
+
+ /* out 1 */
+ outlet_new(&x->x_obj, gensym("signal"));
+
+
+
+ /* init data */
+ x->x_ctl.c_buf1 = (t_float *)malloc(n*sizeof(t_float));
+ x->x_ctl.c_buf2 = (t_float *)malloc(n*sizeof(t_float));
+
+ for(k=0; k<n; k++)
+ {
+ x->x_ctl.c_buf1[k] = 0;
+ x->x_ctl.c_buf2[k] = 0;
+ }
+
+ x->x_ctl.c_order = n;
+
+ return (void *)x;
+}
+
+void dynwav_tilde_setup(void)
+{
+ //post("dynwav~ v0.1");
+ dynwav_class = class_new(gensym("dynwav~"), (t_newmethod)dynwav_new,
+ (t_method)dynwav_free, sizeof(t_dynwav), 0, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(dynwav_class, t_dynwav, x_f);
+ class_addmethod(dynwav_class, (t_method)dynwav_dsp, gensym("dsp"), 0);
+
+
+}
+
diff --git a/modules/ead.c b/modules/ead.c
new file mode 100644
index 0000000..8b93faa
--- /dev/null
+++ b/modules/ead.c
@@ -0,0 +1,153 @@
+/*
+ * ead.c - exponential attack decay envelope
+ * Copyright (c) 2000-2003 by Tom Schouten
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "extlib_util.h"
+
+/* pointer to */
+t_class *ead_class;
+
+
+/* state data fpr attack/decay dsp plugin */
+typedef struct eadctl
+{
+ t_float c_attack;
+ t_float c_decay;
+ t_float c_state;
+ t_float c_target;
+} t_eadctl;
+
+
+/* object data structure */
+typedef struct ead
+{
+ t_object x_obj;
+ t_eadctl x_ctl;
+} t_ead;
+
+
+
+static void ead_attack(t_ead *x, t_floatarg f)
+{
+ x->x_ctl.c_attack = milliseconds_2_one_minus_realpole(f);
+}
+
+static void ead_decay(t_ead *x, t_floatarg f)
+{
+ x->x_ctl.c_decay = milliseconds_2_one_minus_realpole(f);
+}
+
+static void ead_start(t_ead *x)
+{
+ x->x_ctl.c_target = 1;
+}
+
+
+/* dsp callback function, not a method */
+static t_int *ead_perform(t_int *w)
+{
+
+ /* interprete arguments */
+ t_float *out = (float *)(w[3]);
+ t_eadctl *ctl = (t_eadctl *)(w[1]);
+ t_float attack = ctl->c_attack;
+ t_float decay = ctl->c_decay;
+ t_float state = ctl->c_state;
+ t_float target = ctl->c_target;
+ t_int n = (t_int)(w[2]);
+
+ t_int i;
+
+
+ /* A/D code */
+
+ if (target == 1)
+ /* attack phase */
+ {
+ for (i = 0; i < n; i++)
+ {
+ *out++ = state;
+ state += attack*(1 - state);
+ }
+ if (state > ENVELOPE_MAX)
+ ctl->c_target = 0;
+ }
+
+ else
+ /* decay phase */
+ for (i = 0; i < n; i++)
+ {
+ *out++ = state;
+ state -= decay*state;
+ }
+
+ ctl->c_state = state;
+
+ return (w+4); /* pd quirk: pointer for sequencer */
+}
+
+
+static void ead_dsp(t_ead *x, t_signal **sp)
+{
+ dsp_add(ead_perform, 3, &x->x_ctl, sp[0]->s_n, sp[0]->s_vec);
+}
+
+/* destructor */
+static void ead_free(void)
+{
+
+}
+
+
+
+/* constructor */
+static void *ead_new(t_floatarg attack, t_floatarg decay, t_floatarg sustain, t_floatarg release)
+{
+ /* create instance */
+ t_ead *x = (t_ead *)pd_new(ead_class);
+ /* create new inlets, convert incoming message float to attack/decay */
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("attack"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("decay"));
+ /* create a dsp outlet */
+ outlet_new(&x->x_obj, gensym("signal"));
+
+ /* initialize */
+ x->x_ctl.c_state = 0;
+ x->x_ctl.c_target = 0;
+ ead_attack(x, attack);
+ ead_decay(x, decay);
+
+ /* return instance */
+ return (void *)x;
+}
+
+void ead_tilde_setup(void)
+{
+ //post("ead~ v0.1");
+
+ ead_class = class_new(gensym("ead~"), (t_newmethod)ead_new,
+ (t_method)ead_free, sizeof(t_ead), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
+
+
+ class_addmethod(ead_class, (t_method)ead_start, gensym("start"), 0);
+ class_addmethod(ead_class, (t_method)ead_start, gensym("bang"), 0);
+ class_addmethod(ead_class, (t_method)ead_dsp, gensym("dsp"), 0);
+ class_addmethod(ead_class, (t_method)ead_attack, gensym("attack"), A_FLOAT, 0);
+ class_addmethod(ead_class, (t_method)ead_decay, gensym("decay"), A_FLOAT, 0);
+}
+
diff --git a/modules/eadsr.c b/modules/eadsr.c
new file mode 100644
index 0000000..0e0b9db
--- /dev/null
+++ b/modules/eadsr.c
@@ -0,0 +1,171 @@
+/*
+ * eadsr.c - exponential attack decay sustain release envelope
+ * Copyright (c) 2000-2003 by Tom Schouten
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "extlib_util.h"
+
+typedef struct eadsrctl
+{
+ t_float c_attack;
+ t_float c_decay;
+ t_float c_sustain;
+ t_float c_release;
+ t_float c_state;
+ t_float c_target;
+} t_eadsrctl;
+
+typedef struct eadsr
+{
+ t_object x_obj;
+ t_float x_sr;
+ t_eadsrctl x_ctl;
+} t_eadsr;
+
+void eadsr_attack(t_eadsr *x, t_floatarg f)
+{
+ x->x_ctl.c_attack = milliseconds_2_one_minus_realpole(f);
+}
+
+void eadsr_decay(t_eadsr *x, t_floatarg f)
+{
+ x->x_ctl.c_decay = milliseconds_2_one_minus_realpole(f);
+}
+
+void eadsr_sustain(t_eadsr *x, t_floatarg f)
+{
+ if (f>ENVELOPE_MAX) f = ENVELOPE_MAX;
+ if (f<ENVELOPE_MIN) f = ENVELOPE_MIN;
+
+ x->x_ctl.c_sustain = f;
+}
+
+void eadsr_release(t_eadsr *x, t_floatarg f)
+{
+ x->x_ctl.c_release = milliseconds_2_one_minus_realpole(f);
+
+}
+
+void eadsr_start(t_eadsr *x)
+{
+ x->x_ctl.c_target = 1;
+
+}
+
+void eadsr_stop(t_eadsr *x)
+{
+ x->x_ctl.c_target = 0;
+
+}
+
+static t_int *eadsr_perform(t_int *w)
+{
+ t_float *out = (float *)(w[3]);
+ t_eadsrctl *ctl = (t_eadsrctl *)(w[1]);
+ t_float attack = ctl->c_attack;
+ t_float decay = ctl->c_decay;
+ t_float sustain = ctl->c_sustain;
+ t_float release = ctl->c_release;
+ t_float state = ctl->c_state;
+ t_float target = ctl->c_target;
+ t_int n = (t_int)(w[2]);
+
+ t_int i;
+
+
+ if (target == 1)
+ /* attack phase */
+ {
+ for (i = 0; i < n; i++)
+ {
+ *out++ = state;
+ state += attack*(1 - state);
+ }
+ if (state > ENVELOPE_MAX)
+ ctl->c_target = sustain;
+ }
+
+ else if (target == 0)
+ /* release phase */
+ for (i = 0; i < n; i++)
+ {
+ *out++ = state;
+ state -= release*state;
+ }
+
+ else
+ /* decay phase */
+ for (i = 0; i < n; i++)
+ {
+ *out++ = state;
+ state -= decay*(state-sustain);
+ }
+
+ ctl->c_state = state;
+ return (w+4);
+}
+
+static void eadsr_dsp(t_eadsr *x, t_signal **sp)
+{
+ x->x_sr = sp[0]->s_sr;
+ dsp_add(eadsr_perform, 3, &x->x_ctl, sp[0]->s_n, sp[0]->s_vec);
+
+}
+void eadsr_free(void)
+{
+
+}
+
+t_class *eadsr_class;
+
+void *eadsr_new(t_floatarg attack, t_floatarg decay, t_floatarg sustain, t_floatarg release)
+{
+ t_eadsr *x = (t_eadsr *)pd_new(eadsr_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("attack"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("decay"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("sustain"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("release"));
+ outlet_new(&x->x_obj, gensym("signal"));
+
+ x->x_ctl.c_state = 0;
+ x->x_ctl.c_target = 0;
+ eadsr_attack(x, attack);
+ eadsr_decay(x, decay);
+ eadsr_sustain(x, sustain);
+ eadsr_release(x, release);
+
+
+ return (void *)x;
+}
+
+void eadsr_tilde_setup(void)
+{
+ //post("eadsr~ v0.1");
+ eadsr_class = class_new(gensym("eadsr~"), (t_newmethod)eadsr_new,
+ (t_method)eadsr_free, sizeof(t_eadsr), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addmethod(eadsr_class, (t_method)eadsr_start, gensym("start"), 0);
+ class_addmethod(eadsr_class, (t_method)eadsr_start, gensym("bang"), 0);
+ class_addmethod(eadsr_class, (t_method)eadsr_stop, gensym("stop"), 0);
+ class_addmethod(eadsr_class, (t_method)eadsr_dsp, gensym("dsp"), 0);
+ class_addmethod(eadsr_class, (t_method)eadsr_attack, gensym("attack"), A_FLOAT, 0);
+ class_addmethod(eadsr_class, (t_method)eadsr_decay, gensym("decay"), A_FLOAT, 0);
+ class_addmethod(eadsr_class, (t_method)eadsr_sustain, gensym("sustain"), A_FLOAT, 0);
+ class_addmethod(eadsr_class, (t_method)eadsr_release, gensym("release"), A_FLOAT, 0);
+
+
+}
+
diff --git a/modules/ear.c b/modules/ear.c
new file mode 100644
index 0000000..efe9b3f
--- /dev/null
+++ b/modules/ear.c
@@ -0,0 +1,134 @@
+/*
+ * ear.c - exponential attack release envelope
+ * Copyright (c) 2000-2003 by Tom Schouten
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "extlib_util.h"
+
+typedef struct earctl
+{
+ t_float c_attack;
+ t_float c_release;
+ t_float c_state;
+ t_float c_target;
+} t_earctl;
+
+typedef struct ear
+{
+ t_object x_obj;
+ t_float x_sr;
+ t_earctl x_ctl;
+} t_ear;
+
+void ear_attack(t_ear *x, t_floatarg f)
+{
+ x->x_ctl.c_attack = milliseconds_2_one_minus_realpole(f);
+}
+
+void ear_release(t_ear *x, t_floatarg f)
+{
+ x->x_ctl.c_release = milliseconds_2_one_minus_realpole(f);
+}
+
+void ear_start(t_ear *x)
+{
+ x->x_ctl.c_target = 1;
+
+}
+
+void ear_stop(t_ear *x)
+{
+ x->x_ctl.c_target = 0;
+
+}
+
+static t_int *ear_perform(t_int *w)
+{
+ t_float *out = (float *)(w[3]);
+ t_earctl *ctl = (t_earctl *)(w[1]);
+ t_float attack = ctl->c_attack;
+ t_float release = ctl->c_release;
+ t_float state = ctl->c_state;
+ t_float target = ctl->c_target;
+ t_int n = (t_int)(w[2]);
+
+ t_int i;
+
+ if (target) /* attack phase */
+ for (i = 0; i < n; i++)
+ {
+ *out++ = state;
+ state += attack*(1 - state);
+ }
+ else /* release phase */
+ for (i = 0; i < n; i++)
+ {
+ *out++ = state;
+ state -= release*state;
+ }
+
+ ctl->c_state = state;
+ return (w+4);
+}
+
+static void ear_dsp(t_ear *x, t_signal **sp)
+{
+ x->x_sr = sp[0]->s_sr;
+ dsp_add(ear_perform, 3, &x->x_ctl, sp[0]->s_n, sp[0]->s_vec);
+
+}
+void ear_free(void)
+{
+
+}
+
+
+t_class *ear_class; /* attack - release */
+
+void *ear_new(t_floatarg attack, t_floatarg release)
+{
+ t_ear *x = (t_ear *)pd_new(ear_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("attack"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("release"));
+ outlet_new(&x->x_obj, gensym("signal"));
+
+ ear_attack(x,attack);
+ ear_release(x,release);
+ x->x_ctl.c_state = 0;
+ x->x_ctl.c_target = 0;
+
+ return (void *)x;
+}
+
+
+void ear_tilde_setup(void)
+{
+ //post("ear~ v0.1");
+ ear_class = class_new(gensym("ear~"), (t_newmethod)ear_new,
+ (t_method)ear_free, sizeof(t_ear), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addmethod(ear_class, (t_method)ear_start, gensym("start"), 0);
+ class_addmethod(ear_class, (t_method)ear_start, gensym("bang"), 0);
+ class_addmethod(ear_class, (t_method)ear_stop, gensym("stop"), 0);
+ class_addmethod(ear_class, (t_method)ear_dsp, gensym("dsp"), 0);
+ class_addmethod(ear_class,
+ (t_method)ear_attack, gensym("attack"), A_FLOAT, 0);
+ class_addmethod(ear_class,
+ (t_method)ear_release, gensym("release"), A_FLOAT, 0);
+
+
+}
+
diff --git a/modules/ffpoly.c b/modules/ffpoly.c
new file mode 100644
index 0000000..023f29d
--- /dev/null
+++ b/modules/ffpoly.c
@@ -0,0 +1,173 @@
+/*
+ * ffpoly.c - compute a finite field polynomial
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+#include "m_pd.h"
+#include <stdlib.h>
+
+
+
+
+typedef struct ffpoly_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet;
+ t_int *x_coef;
+ t_int x_poly_order;
+ t_int x_field_order;
+
+ t_int x_lastpackedcoef;
+
+
+
+} t_ffpoly;
+
+
+
+
+static void ffpoly_compute(t_ffpoly *x, t_floatarg fcoef)
+{
+ int in = (int)fcoef;
+ int fo = x->x_field_order;
+ int po = x->x_poly_order;
+ int* c = x->x_coef;
+ int i, out;
+
+ in %= fo;
+ if (in < 0) in += fo;
+
+ out = c[po];
+ for (i=po-1; i>=0; i--){
+ out *= in;
+ out += c[i];
+ out %= fo;
+ }
+
+
+ outlet_float(x->x_outlet, (float)out);
+}
+
+
+/* this sets all coefficients given one float */
+static void ffpoly_coefficients(t_ffpoly *x, t_floatarg fcoef)
+{
+ int coef = (int)fcoef;
+ int i;
+ if (coef < 0) coef = -coef;
+
+ x->x_lastpackedcoef = coef;
+
+ for (i=0; i<x->x_poly_order + 1; i++){
+ x->x_coef[i] = coef % x->x_field_order;
+ coef = coef / x->x_field_order;
+ }
+
+
+}
+
+/* this sets one coefficient */
+static void ffpoly_coef(t_ffpoly *x, t_floatarg index, t_floatarg val)
+{
+ int i = (int)index;
+ int v = (int)val;
+ if (i<0) return;
+ if (i>x->x_poly_order) return;
+
+ v %= x->x_field_order;
+ if (v<0) v += x->x_field_order;
+
+ x->x_coef[i] = v;
+
+
+}
+
+static void ffpoly_fieldorder(t_ffpoly *x, t_floatarg ffieldorder)
+{
+ int i;
+ int order = (int)ffieldorder;
+ if (order < 2) order = 2;
+ x->x_field_order = order;
+
+ for (i=0; i<x->x_poly_order+1; i++)
+ x->x_coef[i] %= x->x_field_order;
+
+ //ffpoly_coefficients(x, x->x_lastpackedcoef);
+}
+
+static void ffpoly_free(t_ffpoly *x)
+{
+ free (x->x_coef);
+}
+
+t_class *ffpoly_class;
+
+
+
+static void *ffpoly_new(t_floatarg fpolyorder, t_floatarg ffieldorder)
+{
+ t_int polyorder = (int)fpolyorder;
+ t_int fieldorder = (int)ffieldorder;
+
+ t_ffpoly *x = (t_ffpoly *)pd_new(ffpoly_class);
+
+ if (polyorder < 1) polyorder = 1;
+ if (fieldorder < 2) fieldorder = 2;
+
+ x->x_poly_order = polyorder;
+ x->x_field_order = fieldorder;
+
+ x->x_coef = (int *)malloc((x->x_poly_order + 1) * sizeof(int));
+
+ /* set poly to f(x) = x */
+ ffpoly_coefficients(x, x->x_field_order);
+
+ x->x_outlet = outlet_new(&x->x_obj, &s_float);
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void ffpoly_setup(void)
+{
+
+
+ ffpoly_class = class_new(gensym("ffpoly"), (t_newmethod)ffpoly_new,
+ (t_method)ffpoly_free, sizeof(t_ffpoly), 0, A_DEFFLOAT, A_DEFFLOAT, A_NULL);
+
+ class_addmethod(ffpoly_class, (t_method)ffpoly_coefficients, gensym("coefficients"), A_FLOAT, A_NULL);
+
+ class_addmethod(ffpoly_class, (t_method)ffpoly_coef, gensym("coef"), A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(ffpoly_class, (t_method)ffpoly_fieldorder, gensym("order"), A_FLOAT, A_NULL);
+ class_addfloat(ffpoly_class, (t_method)ffpoly_compute);
+
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/fwarp.c b/modules/fwarp.c
new file mode 100644
index 0000000..28fe024
--- /dev/null
+++ b/modules/fwarp.c
@@ -0,0 +1,61 @@
+/*
+ * fwarp.c - converts a frequency to a "standard" tangent warped freq
+ * Copyright (c) 2000-2003 by Tom Schouten
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include "m_pd.h"
+#include <math.h>
+
+#define SEQL 16
+
+
+typedef struct fwarp
+{
+ t_object t_ob;
+ t_outlet *x_out;
+} t_fwarp;
+
+static void fwarp_float(t_fwarp *x, t_floatarg f)
+{
+ float twopi = 2.0f * M_PI;
+ float sr = sys_getsr();
+ f /= sr;
+ f = tan(twopi * f) / twopi;
+ outlet_float(x->x_out, f * sr);
+}
+
+static void fwarp_free(void)
+{
+}
+
+t_class *fwarp_class;
+
+static void *fwarp_new(void)
+{
+ t_fwarp *x = (t_fwarp *)pd_new(fwarp_class);
+ x->x_out = outlet_new(&x->t_ob, gensym("float"));
+ return (void *)x;
+}
+
+void fwarp_setup(void)
+{
+ fwarp_class = class_new(gensym("fwarp"), (t_newmethod)fwarp_new,
+ (t_method)fwarp_free, sizeof(t_fwarp), 0, 0);
+ class_addfloat(fwarp_class, fwarp_float);
+}
+
diff --git a/modules/lattice.c b/modules/lattice.c
new file mode 100644
index 0000000..9403393
--- /dev/null
+++ b/modules/lattice.c
@@ -0,0 +1,143 @@
+/*
+ * lattice.c - a lattice filter for pd
+ * Copyright (c) 2000-2003 by Tom Schouten
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+
+#include "m_pd.h"
+#include <math.h>
+
+#define maxorder 1024
+
+typedef struct latticesegment
+{
+ t_float delay; // delay element
+ t_float rc; // reflection coefficient
+} t_latticesegment;
+
+typedef struct latticectl
+{
+ t_latticesegment c_segment[maxorder]; // array of lattice segment data
+ t_int c_segments;
+} t_latticectl;
+
+typedef struct lattice
+{
+ t_object x_obj;
+ t_float x_f;
+ t_latticectl x_ctl;
+} t_lattice;
+
+
+
+static t_int *lattice_perform(t_int *w)
+{
+
+
+ t_float *in = (float *)(w[3]);
+ t_float *out = (float *)(w[4]);
+ t_latticectl *ctl = (t_latticectl *)(w[1]);
+ t_int i,j;
+ t_int n = (t_int)(w[2]);
+ t_float x,rc,d;
+
+ t_latticesegment* seg = ctl->c_segment;
+ t_int segments = ctl->c_segments;
+ for (i=0; i<n; i++)
+ {
+ x = *in++;
+ // section 0
+ rc = seg[0].rc;
+ x += seg[0].delay * rc;
+
+ // section 1 to segments-1
+ for (j=1; j < segments; j++)
+ {
+ rc = seg[j].rc;
+ d = seg[j].delay;
+ x += d * rc;
+ seg[j-1].delay = d - rc * x;
+ }
+ // stub
+ seg[segments-1].delay = x;
+
+ *out++ = x;
+ }
+
+ return (w+5);
+}
+
+static void lattice_dsp(t_lattice *x, t_signal **sp)
+{
+ dsp_add(lattice_perform, 4, &x->x_ctl, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+
+}
+static void lattice_free(void)
+{
+
+}
+
+t_class *lattice_class;
+
+static void lattice_rc(t_lattice *x, t_float segment, t_float refco)
+{
+ t_int seg = (t_float)segment;
+ if ((seg >= 0) && (seg < x->x_ctl.c_segments)){
+ if (refco > 1.0f) refco = 1.0f;
+ if (refco < -1.0f) refco = -1.0f;
+ x->x_ctl.c_segment[seg].rc = refco;
+ }
+}
+
+static void lattice_reset(t_lattice *x)
+{
+ t_float* buf = (t_float *)x->x_ctl.c_segment;
+ t_int n = x->x_ctl.c_segments;
+ t_int i;
+ for (i=0; i<n; i++) buf[i]=0;
+}
+
+static void *lattice_new(t_floatarg segments)
+{
+ t_lattice *x = (t_lattice *)pd_new(lattice_class);
+ t_int seg = (t_int)segments;
+
+ outlet_new(&x->x_obj, gensym("signal"));
+
+ if (seg < 1) seg = 1;
+ if (seg > maxorder) seg = maxorder;
+
+ x->x_ctl.c_segments = seg;
+
+ lattice_reset(x);
+
+ return (void *)x;
+}
+
+void lattice_tilde_setup(void)
+{
+ //post("lattice~ v0.1");
+ lattice_class = class_new(gensym("lattice~"), (t_newmethod)lattice_new,
+ (t_method)lattice_free, sizeof(t_lattice), 0, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(lattice_class, t_lattice, x_f);
+ class_addmethod(lattice_class, (t_method)lattice_dsp, gensym("dsp"), 0);
+ class_addmethod(lattice_class, (t_method)lattice_reset, gensym("reset"), 0);
+ class_addmethod(lattice_class, (t_method)lattice_rc, gensym("rc"), A_FLOAT, A_FLOAT, 0);
+
+}
+
diff --git a/modules/matrix.c b/modules/matrix.c
new file mode 100644
index 0000000..6fd55b7
--- /dev/null
+++ b/modules/matrix.c
@@ -0,0 +1,154 @@
+/*
+ * matrix.c - applies a matrix transform to a signal block
+ * intended for spectral processing, dynwav
+ *
+ * Copyright (c) 2000-2003 by Tom Schouten
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "m_pd.h"
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define MAXORDER 1024
+
+typedef struct matrixctl
+{
+ t_float *c_A; /* matrix */
+ t_float *c_x; /* vector */
+ t_int c_order;
+
+} t_matrixctl;
+
+typedef struct matrix
+{
+ t_object x_obj;
+ t_float x_f;
+ t_matrixctl x_ctl;
+} t_matrix;
+
+static void matrix_load(t_matrix *x, t_symbol *s)
+{
+ FILE *matrix;
+
+ if(s && s->s_name)
+ {
+ post("matrix: loading %s",s->s_name);
+ if(matrix = fopen(s->s_name, "r"))
+ {
+ int n = x->x_ctl.c_order;
+ fread(x->x_ctl.c_A, sizeof(float), n*n, matrix);
+ }
+ else post("matrix: error, cant open file.");
+ }
+}
+
+
+static t_int *matrix_perform(t_int *w)
+{
+
+
+ t_float *in = (float *)(w[3]);
+ t_float *out = (float *)(w[4]);
+ t_matrixctl *ctl = (t_matrixctl *)(w[1]);
+ t_int n = (t_int)(w[2]);
+
+ t_int i,j;
+ t_float *A = ctl->c_A;
+ t_float *x = ctl->c_x;
+
+ if (in == out) /* store input if ness. */
+ {
+ memcpy(x, in, sizeof(t_float)*n);
+ in = x;
+ }
+ bzero(out, sizeof(t_float)*n); /* init output */
+
+ for (j=0; j<n; j++)
+ for (i=0; i<n; i++)
+ out[i] += A[i+j*n] * in[j];
+
+ return (w+5);
+}
+
+static void matrix_dsp(t_matrix *x, t_signal **sp)
+{
+ int n = sp[0]->s_n;
+ int k,i;
+
+ if (x->x_ctl.c_order != n)
+ {
+ if (x->x_ctl.c_A) free (x->x_ctl.c_A);
+
+ x->x_ctl.c_A = (t_float *)calloc(n*n,sizeof(t_float));
+ x->x_ctl.c_x = (t_float *)calloc(n,sizeof(t_float));
+ x->x_ctl.c_order = n;
+ }
+
+ for (i=0;i<n;i++) x->x_ctl.c_A[i] = 1;
+
+ dsp_add(matrix_perform, 4, &x->x_ctl, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+
+
+}
+static void matrix_free(t_matrix *x)
+{
+
+ if (x->x_ctl.c_A) free (x->x_ctl.c_A);
+ if (x->x_ctl.c_x) free (x->x_ctl.c_x);
+
+}
+
+t_class *matrix_class;
+
+static void *matrix_new(t_floatarg order)
+{
+ t_matrix *x = (t_matrix *)pd_new(matrix_class);
+ int iorder = (int)order;
+ int i, n=64, k;
+
+
+ /* out 1 */
+ outlet_new(&x->x_obj, gensym("signal"));
+
+
+
+ /* init data */
+
+ x->x_ctl.c_A = (t_float *)calloc(n*n,sizeof(t_float));
+ x->x_ctl.c_x = (t_float *)calloc(n,sizeof(t_float));
+
+
+ for (i=0;i<n;i++) x->x_ctl.c_A[i] = 1;
+ x->x_ctl.c_order = n;
+
+ return (void *)x;
+}
+
+void matrix_tilde_setup(void)
+{
+ //post("matrix~ v0.1");
+ matrix_class = class_new(gensym("matrix~"), (t_newmethod)matrix_new,
+ (t_method)matrix_free, sizeof(t_matrix), 0, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(matrix_class, t_matrix, x_f);
+ class_addmethod(matrix_class, (t_method)matrix_dsp, gensym("dsp"), 0);
+ class_addmethod(matrix_class, (t_method)matrix_load, gensym("load"), A_SYMBOL,0);
+
+
+}
+
diff --git a/modules/permut.c b/modules/permut.c
new file mode 100644
index 0000000..bc143d2
--- /dev/null
+++ b/modules/permut.c
@@ -0,0 +1,177 @@
+/*
+ * permut.c - applies a (random) permutation on a signal block
+ * intended for spectral processing, dynwav
+ *
+ * Copyright (c) 2000-2003 by Tom Schouten
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include "m_pd.h"
+#include <math.h>
+#include <stdlib.h>
+
+
+
+typedef struct permutctl
+{
+ char c_type;
+ int *c_permutationtable;
+ int c_blocksize;
+} t_permutctl;
+
+typedef struct permut
+{
+ t_object x_obj;
+ t_float x_f;
+ t_permutctl x_ctl;
+} t_permut;
+
+
+static inline void permut_perform_permutation(t_float *S, int n, t_int *f)
+{
+ t_int k,l;
+ t_float swap;
+ for(k=0; k<n; k++)
+ {
+ l = f[k];
+ while (l<k) l = f[l];
+ swap = S[k];
+ S[k] = S[l];
+ S[l] = swap;
+ }
+}
+
+
+static void permut_random(t_permut *x, t_floatarg seed)
+{
+ int i,j;
+ int N = x->x_ctl.c_blocksize;
+ int mask = N-1;
+ int *p = x->x_ctl.c_permutationtable;
+ int r, last = 0;
+
+ srand(* ((unsigned int *)(&seed)));
+
+ if(p)
+ {
+ p[0] = rand() & mask;
+ for (i=1;i<N;i++)
+ {
+ r = rand() & mask;
+ j = 0;
+ while(j<i)
+ {
+ if (p[j] == r)
+ {
+ r = (r + 1) & mask;
+ j = 0;
+ }
+ else j++;
+ }
+ p[i] = r;
+
+ }
+ }
+}
+
+static void permut_bang(t_permut *x)
+{
+ unsigned int r = rand();
+ permut_random(x, *((float *)(&r)));
+}
+
+static void permut_resize_table(t_permut *x, int size)
+{
+ if (x->x_ctl.c_blocksize != size)
+ {
+ if (x->x_ctl.c_permutationtable)
+ free(x->x_ctl.c_permutationtable);
+ x->x_ctl.c_permutationtable = (int *)malloc(sizeof(int)*size);
+ x->x_ctl.c_blocksize = size;
+
+ /* make sure it's initialized */
+ permut_bang(x);
+
+
+ }
+}
+
+
+
+
+static t_int *permut_perform(t_int *w)
+{
+
+
+ t_float *in = (float *)(w[3]);
+ t_float *out = (float *)(w[4]);
+ t_permutctl *ctl = (t_permutctl *)(w[1]);
+ t_int i;
+ t_int n = (t_int)(w[2]);
+ t_float x,y;
+ t_int *p = ctl->c_permutationtable;
+
+
+ if (in != out)
+ for (i=0; i<n; i++) out[i] = in[i];
+
+
+ permut_perform_permutation(out, n, p);
+
+ return (w+5);
+}
+
+static void permut_dsp(t_permut *x, t_signal **sp)
+{
+ permut_resize_table(x, sp[0]->s_n);
+ dsp_add(permut_perform, 4, &x->x_ctl, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+
+}
+
+static void permut_free(t_permut *x)
+{
+ if (x->x_ctl.c_permutationtable) free(x->x_ctl.c_permutationtable);
+
+}
+
+t_class *permut_class;
+
+static void *permut_new(void)
+{
+ t_permut *x = (t_permut *)pd_new(permut_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+
+ x->x_ctl.c_permutationtable = 0;
+ x->x_ctl.c_blocksize = 0;
+ permut_resize_table(x, 64);
+ permut_random(x, 0);
+
+ return (void *)x;
+}
+
+void permut_tilde_setup(void)
+{
+ //post("permut~ v0.1");
+ permut_class = class_new(gensym("permut~"), (t_newmethod)permut_new,
+ (t_method)permut_free, sizeof(t_permut), 0, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(permut_class, t_permut, x_f);
+ class_addmethod(permut_class, (t_method)permut_random, gensym("random"), A_FLOAT, 0);
+ class_addmethod(permut_class, (t_method)permut_bang, gensym("bang"), 0);
+ class_addmethod(permut_class, (t_method)permut_dsp, gensym("dsp"), 0);
+
+}
+
diff --git a/modules/qmult.c b/modules/qmult.c
new file mode 100644
index 0000000..94766e1
--- /dev/null
+++ b/modules/qmult.c
@@ -0,0 +1,165 @@
+/*
+ * qmult.c - quaternion multiplication dsp object
+ * Copyright (c) 2000-2003 by Tom Schouten
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "m_pd.h"
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+
+
+typedef struct qmultctl
+{
+ t_float *c_inputleft[4];
+ t_float *c_inputright[4];
+ t_float *c_output[4];
+} t_qmultctl;
+
+typedef struct qmult
+{
+ t_object x_obj;
+ t_float x_f;
+ t_qmultctl x_ctl;
+} t_qmult;
+
+
+static t_int *qmult_perform(t_int *word)
+{
+
+
+
+ t_qmultctl *ctl = (t_qmultctl *)(word[1]);
+ t_int n = (t_int)(word[2]);
+ t_int i;
+
+ t_float *in0l = ctl->c_inputleft[0];
+ t_float *in1l = ctl->c_inputleft[1];
+ t_float *in2l = ctl->c_inputleft[2];
+ t_float *in3l = ctl->c_inputleft[3];
+
+ t_float *in0r = ctl->c_inputright[0];
+ t_float *in1r = ctl->c_inputright[1];
+ t_float *in2r = ctl->c_inputright[2];
+ t_float *in3r = ctl->c_inputright[3];
+
+ t_float *out0 = ctl->c_output[0];
+ t_float *out1 = ctl->c_output[1];
+ t_float *out2 = ctl->c_output[2];
+ t_float *out3 = ctl->c_output[3];
+
+ t_float wl, xl, yl, zl;
+ t_float wr, xr, yr, zr;
+ t_float w, x, y, z;
+
+ for (i=0;i<n;i++)
+ {
+
+ /* read input quaternions */
+ wl = *in0l++;
+ xl = *in1l++;
+ yl = *in2l++;
+ zl = *in3l++;
+
+ wr = *in0r++;
+ xr = *in1r++;
+ yr = *in2r++;
+ zr = *in3r++;
+
+
+ /* multiply quaternions */
+ w = wl * wr;
+ x = wl * xr;
+ y = wl * yr;
+ z = wl * zr;
+
+ w -= xl * xr;
+ x += xl * wr;
+ y -= xl * zr;
+ z += xl * yr;
+
+ w -= yl * yr;
+ x += yl * zr;
+ y += yl * wr;
+ z -= yl * xr;
+
+ w -= zl * zr;
+ x -= zl * yr;
+ y += zl * xr;
+ z += zl * wr;
+
+
+
+ /* write output quaternion */
+ *out0++ = w;
+ *out1++ = x;
+ *out2++ = y;
+ *out3++ = z;
+ }
+
+
+ return (word+3);
+}
+
+
+
+static void qmult_dsp(t_qmult *x, t_signal **sp)
+{
+
+ int i;
+ for (i=0;i<4;i++)
+ {
+ x->x_ctl.c_inputleft[i] = sp[i]->s_vec;
+ x->x_ctl.c_inputright[i] = sp[i+4]->s_vec;
+ x->x_ctl.c_output[i] = sp[i+8]->s_vec;
+ }
+
+ dsp_add(qmult_perform, 2, &x->x_ctl, sp[0]->s_n);
+
+
+}
+
+
+static void qmult_free(t_qmult *x)
+{
+
+}
+
+t_class *qmult_class;
+
+static void *qmult_new(t_floatarg channels)
+{
+ int i;
+ t_qmult *x = (t_qmult *)pd_new(qmult_class);
+
+ for (i=1;i<8;i++) inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("signal"), gensym("signal"));
+ for (i=0;i<4;i++) outlet_new(&x->x_obj, gensym("signal"));
+
+ return (void *)x;
+}
+
+void qmult_tilde_setup(void)
+{
+ //post("qmult~ v0.1");
+ qmult_class = class_new(gensym("qmult~"), (t_newmethod)qmult_new,
+ (t_method)qmult_free, sizeof(t_qmult), 0, 0);
+ CLASS_MAINSIGNALIN(qmult_class, t_qmult, x_f);
+ class_addmethod(qmult_class, (t_method)qmult_dsp, gensym("dsp"), 0);
+
+}
+
diff --git a/modules/qnorm.c b/modules/qnorm.c
new file mode 100644
index 0000000..e826b1b
--- /dev/null
+++ b/modules/qnorm.c
@@ -0,0 +1,137 @@
+/*
+ * qnorm.c - quaternion normalization dsp object
+ * Copyright (c) 2000-2003 by Tom Schouten
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "m_pd.h"
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+
+
+typedef struct qnormctl
+{
+ t_float *c_input[4];
+ t_float *c_output[4];
+} t_qnormctl;
+
+typedef struct qnorm
+{
+ t_object x_obj;
+ t_float x_f;
+ t_qnormctl x_ctl;
+} t_qnorm;
+
+
+static t_int *qnorm_perform(t_int *word)
+{
+
+
+
+ t_qnormctl *ctl = (t_qnormctl *)(word[1]);
+ t_int n = (t_int)(word[2]);
+ t_int i;
+
+ t_float *in0 = ctl->c_input[0];
+ t_float *in1 = ctl->c_input[1];
+ t_float *in2 = ctl->c_input[2];
+ t_float *in3 = ctl->c_input[3];
+
+ t_float *out0 = ctl->c_output[0];
+ t_float *out1 = ctl->c_output[1];
+ t_float *out2 = ctl->c_output[2];
+ t_float *out3 = ctl->c_output[3];
+
+ t_float w, x, y, z;
+ t_float norm;
+ t_float inorm;
+
+ for (i=0;i<n;i++)
+ {
+
+ /* read input */
+ w = *in0++;
+ x = *in1++;
+ y = *in2++;
+ z = *in3++;
+
+ /* transform */
+ norm = w * w;
+ norm += x * x;
+ norm += y * y;
+ norm += z * z;
+
+ inorm = (norm == 0.0f) ? (0.0f) : (1.0f / sqrt(norm));
+
+ /* write output */
+ *out0++ = w * inorm;
+ *out1++ = x * inorm;
+ *out2++ = y * inorm;
+ *out3++ = z * inorm;
+ }
+
+
+ return (word+3);
+}
+
+
+
+static void qnorm_dsp(t_qnorm *x, t_signal **sp)
+{
+
+ int i;
+ for (i=0;i<4;i++)
+ {
+ x->x_ctl.c_input[i] = sp[i]->s_vec;
+ x->x_ctl.c_output[i] = sp[i+4]->s_vec;
+ }
+
+ dsp_add(qnorm_perform, 2, &x->x_ctl, sp[0]->s_n);
+
+
+}
+
+
+static void qnorm_free(t_qnorm *x)
+{
+
+}
+
+t_class *qnorm_class;
+
+static void *qnorm_new(t_floatarg channels)
+{
+ int i;
+ t_qnorm *x = (t_qnorm *)pd_new(qnorm_class);
+
+ for (i=1;i<4;i++) inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("signal"), gensym("signal"));
+ for (i=0;i<4;i++) outlet_new(&x->x_obj, gensym("signal"));
+
+ return (void *)x;
+}
+
+void qnorm_tilde_setup(void)
+{
+ //post("qnorm~ v0.1");
+ qnorm_class = class_new(gensym("qnorm~"), (t_newmethod)qnorm_new,
+ (t_method)qnorm_free, sizeof(t_qnorm), 0, 0);
+ CLASS_MAINSIGNALIN(qnorm_class, t_qnorm, x_f);
+ class_addmethod(qnorm_class, (t_method)qnorm_dsp, gensym("dsp"), 0);
+
+}
+
diff --git a/modules/ramp.c b/modules/ramp.c
new file mode 100644
index 0000000..ad13582
--- /dev/null
+++ b/modules/ramp.c
@@ -0,0 +1,118 @@
+/*
+ * ramp.c - retriggerable counter for dsp signals
+ * Copyright (c) 2000-2003 by Tom Schouten
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include "m_pd.h"
+#include <math.h>
+
+
+typedef struct rampctl
+{
+ t_float c_offset;
+ t_float c_looppoint;
+} t_rampctl;
+
+typedef struct ramp
+{
+ t_object x_obj;
+ t_float x_f;
+ t_rampctl x_ctl;
+} t_ramp;
+
+
+void ramp_offset(t_ramp *x, t_floatarg f)
+{
+
+ x->x_ctl.c_offset = f;
+
+}
+
+void ramp_looppoint(t_ramp *x, t_floatarg f)
+{
+
+ x->x_ctl.c_looppoint = f;
+
+}
+
+
+void ramp_bang(t_ramp *x)
+{
+ ramp_offset(x, 0);
+
+}
+
+
+
+static t_int *ramp_perform(t_int *w)
+{
+
+
+ t_float *out = (float *)(w[3]);
+ t_rampctl *ctl = (t_rampctl *)(w[1]);
+ t_int i;
+ t_int n = (t_int)(w[2]);
+ t_float x;
+
+
+
+ x = ctl->c_offset;
+
+ for (i = 0; i < n; i++)
+ {
+ *out++ = (float)x++;
+ }
+
+ ctl->c_offset = x; /* save state */
+
+
+ return (w+4);
+}
+
+static void ramp_dsp(t_ramp *x, t_signal **sp)
+{
+ dsp_add(ramp_perform, 3, &x->x_ctl, sp[0]->s_n, sp[0]->s_vec);
+
+}
+void ramp_free(void)
+{
+
+}
+
+t_class *ramp_class;
+
+void *ramp_new(void)
+{
+ t_ramp *x = (t_ramp *)pd_new(ramp_class);
+ /* inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("looppoint"));*/
+ outlet_new(&x->x_obj, gensym("signal"));
+
+ ramp_bang(x);
+ return (void *)x;
+}
+
+void ramp_tilde_setup(void)
+{
+ //post("ramp~ v0.1");
+ ramp_class = class_new(gensym("ramp~"), (t_newmethod)ramp_new,
+ (t_method)ramp_free, sizeof(t_ramp), 0, 0);
+ class_addmethod(ramp_class, (t_method)ramp_bang, gensym("bang"), 0);
+ class_addmethod(ramp_class, (t_method)ramp_dsp, gensym("dsp"), 0);
+ class_addfloat(ramp_class, (t_method)ramp_offset);
+}
+
diff --git a/modules/ratio.c b/modules/ratio.c
new file mode 100644
index 0000000..777f2b9
--- /dev/null
+++ b/modules/ratio.c
@@ -0,0 +1,66 @@
+/*
+ * ratio.c - multiplies by 2^k such that output is between 1 and 2
+ * Copyright (c) 2000-2003 by Tom Schouten
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include "m_pd.h"
+
+#define SEQL 16
+
+typedef struct{
+} t_ratio_data;
+
+typedef struct ratio
+{
+ t_object t_ob;
+ t_outlet *x_out;
+ t_ratio_data x_c;
+} t_ratio;
+
+static void ratio_float(t_ratio *x, t_floatarg f)
+{
+ f = (f<0)?(-f):(f);
+ if (f)
+ {
+ while (f < 1.0f) f *= 2.0f;
+ while (f >= 2.0f) f *= 0.5f;
+ }
+ outlet_float(x->x_out, f);
+
+}
+
+static void ratio_free(void)
+{
+}
+
+t_class *ratio_class;
+
+static void *ratio_new(void)
+{
+ t_ratio *x = (t_ratio *)pd_new(ratio_class);
+ x->x_out = outlet_new(&x->t_ob, gensym("float"));
+ return (void *)x;
+}
+
+void ratio_setup(void)
+{
+ ratio_class = class_new(gensym("ratio"), (t_newmethod)ratio_new,
+ (t_method)ratio_free, sizeof(t_ratio), 0, 0);
+ class_addfloat(ratio_class, ratio_float);
+}
+
diff --git a/modules/statwav.c b/modules/statwav.c
new file mode 100644
index 0000000..52c6a0b
--- /dev/null
+++ b/modules/statwav.c
@@ -0,0 +1,149 @@
+/*
+ * dynwav.c - static wavetable oscillator (scale + tabread)
+ * data organization is in (real, imag) pairs
+ * the first 2 components are (DC, NY)
+ * Copyright (c) 2000-2003 by Tom Schouten
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "m_pd.h"
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static t_class *statwav_tilde_class;
+
+typedef struct _statwav_tilde
+{
+ t_object x_obj;
+ int x_npoints;
+ float *x_vec;
+ t_symbol *x_arrayname;
+ float x_f;
+} t_statwav_tilde;
+
+static void *statwav_tilde_new(t_symbol *s)
+{
+ t_statwav_tilde *x = (t_statwav_tilde *)pd_new(statwav_tilde_class);
+ x->x_arrayname = s;
+ x->x_vec = 0;
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *statwav_tilde_perform(t_int *w)
+{
+ t_statwav_tilde *x = (t_statwav_tilde *)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ float maxindex;
+ int imaxindex;
+ float *buf = x->x_vec, *fp;
+ int i;
+
+ maxindex = x->x_npoints;
+ imaxindex = x->x_npoints;
+
+ if (!buf) goto zero;
+
+
+ for (i = 0; i < n; i++)
+ {
+ float phase = *in++;
+ float modphase = phase - (int)phase;
+ float findex = modphase * maxindex;
+ int index = findex;
+ int ia, ib, ic, id;
+ float frac, a, b, c, d, cminusb;
+ static int count;
+
+
+ frac = findex - index;
+ ia = (imaxindex+index-1) % imaxindex;
+ ib = index;
+ ic = (index+1) % imaxindex;
+ id = (index+2) % imaxindex;
+
+ a = buf[ia];
+ b = buf[ib];
+ c = buf[ic];
+ d = buf[id];
+ /* if (!i && !(count++ & 1023))
+ post("fp = %lx, shit = %lx, b = %f", fp, buf->b_shit, b); */
+ cminusb = c-b;
+
+ *out++ = b + frac * (
+ cminusb - 0.5f * (frac-1.) * (
+ (a - d + 3.0f * cminusb) * frac + (b - a - cminusb)
+ )
+ );
+ }
+
+ return (w+5);
+ zero:
+ while (n--) *out++ = 0;
+
+ return (w+5);
+}
+
+static void statwav_tilde_set(t_statwav_tilde *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)
+ error("statwav~: %s: no such array", x->x_arrayname->s_name);
+ x->x_vec = 0;
+ }
+ else if (!garray_getfloatarray(a, &x->x_npoints, &x->x_vec))
+ {
+ error("%s: bad template for statwav~", x->x_arrayname->s_name);
+ x->x_vec = 0;
+ }
+ else garray_usedindsp(a);
+}
+
+static void statwav_tilde_dsp(t_statwav_tilde *x, t_signal **sp)
+{
+ statwav_tilde_set(x, x->x_arrayname);
+
+ dsp_add(statwav_tilde_perform, 4, x,
+ sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+
+}
+
+static void statwav_tilde_free(t_statwav_tilde *x)
+{
+}
+
+void statwav_tilde_setup(void)
+{
+ //post("statwav~ v0.1");
+ statwav_tilde_class = class_new(gensym("statwav~"),
+ (t_newmethod)statwav_tilde_new, (t_method)statwav_tilde_free,
+ sizeof(t_statwav_tilde), 0, A_DEFSYM, 0);
+ CLASS_MAINSIGNALIN(statwav_tilde_class, t_statwav_tilde, x_f);
+ class_addmethod(statwav_tilde_class, (t_method)statwav_tilde_dsp,
+ gensym("dsp"), 0);
+ class_addmethod(statwav_tilde_class, (t_method)statwav_tilde_set,
+ gensym("set"), A_SYMBOL, 0);
+}
+
diff --git a/modules/tabreadmix.c b/modules/tabreadmix.c
new file mode 100644
index 0000000..91181c5
--- /dev/null
+++ b/modules/tabreadmix.c
@@ -0,0 +1,271 @@
+/*
+ * tabreadmix.c - an overlap add tabread~ clone
+ * Copyright (c) 2000-2003 by Tom Schouten
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "extlib_util.h"
+
+/******************** tabreadmix~ ***********************/
+
+static t_class *tabreadmix_tilde_class;
+
+typedef struct _tabreadmix_tilde
+{
+ t_object x_obj;
+ int x_npoints;
+ float *x_vec;
+ t_symbol *x_arrayname;
+ float x_f;
+
+ /* file position vars */
+ int x_currpos;
+ int x_prevpos;
+
+ /* cross fader state vars */
+ int x_xfade_size;
+ int x_xfade_phase;
+ float x_xfade_cos;
+ float x_xfade_sin;
+ float x_xfade_state_c;
+ float x_xfade_state_s;
+
+} t_tabreadmix_tilde;
+
+
+
+inline void tabreadmix_tilde_wrapindices(t_tabreadmix_tilde *x)
+{
+ int max;
+
+ /* modulo */
+ x->x_currpos %= x->x_npoints;
+ x->x_prevpos %= x->x_npoints;
+
+ /* make sure 0<=..<x->x_npoints */
+ //if (x->x_currpos < 0) x->x_currpos += x->x_npoints;
+ //if (x->x_prevpos < 0) x->x_prevpos += x->x_npoints;
+ x->x_currpos += (x->x_currpos < 0) * x->x_npoints;
+ x->x_prevpos += (x->x_prevpos < 0) * x->x_npoints;
+
+}
+
+
+
+#define min(x,y) ((x)<(y)?(x):(y))
+
+static t_int *tabreadmix_tilde_perform(t_int *w)
+{
+ t_tabreadmix_tilde *x = (t_tabreadmix_tilde *)(w[1]);
+ t_float *pos = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ int maxxindex;
+ float *buf = x->x_vec;
+ int i;
+ float currgain, prevgain;
+ float c,s;
+ int chunk;
+ int leftover;
+ int newpos = (int)*pos;
+
+ maxxindex = x->x_npoints;
+ if (!buf) goto zero;
+ if (maxxindex <= 0) goto zero;
+
+
+ while (n){
+
+ /* process as much data as possible */
+ leftover = x->x_xfade_size - x->x_xfade_phase;
+ chunk = min(n, leftover);
+
+ for (i = 0; i < chunk; i++){
+ /* compute crossfade gains from oscillator state */
+ currgain = 0.5f - x->x_xfade_state_c;
+ prevgain = 0.5f + x->x_xfade_state_c;
+
+ /* check indices & wrap */
+ tabreadmix_tilde_wrapindices(x);
+
+ /* mix and write */
+ newpos = (int)(*pos++);
+ *out++ = currgain * buf[x->x_currpos++] + prevgain * buf[x->x_prevpos++];
+
+ /* advance oscillator */
+ c = x->x_xfade_state_c * x->x_xfade_cos - x->x_xfade_state_s * x->x_xfade_sin;
+ s = x->x_xfade_state_c * x->x_xfade_sin + x->x_xfade_state_s * x->x_xfade_cos;
+ x->x_xfade_state_c = c;
+ x->x_xfade_state_s = s;
+ }
+
+ /* update indices */
+ x->x_xfade_phase += chunk;
+ n -= chunk;
+ //pos += chunk;
+
+ /* check if prev chunk is finished */
+ if (x->x_xfade_size == x->x_xfade_phase){
+ x->x_prevpos = x->x_currpos;
+ x->x_currpos = newpos;
+ x->x_xfade_state_c = 0.5f;
+ x->x_xfade_state_s = 0.0f;
+ x->x_xfade_phase = 0;
+ }
+
+ }
+
+ /* return if we ran out of data */
+ return (w+5);
+
+
+ zero:
+ while (n--) *out++ = 0;
+ return (w+5);
+}
+
+
+static void tabreadmix_tilde_blocksize(t_tabreadmix_tilde *x, t_float size)
+{
+ double prev_phase;
+ int max;
+ float fmax = (float)x->x_npoints * 0.5f;
+
+ if (size < 1.0) size = 1.0;
+
+ prev_phase = (double)x->x_xfade_phase;
+ prev_phase *= size;
+ prev_phase /= (double)x->x_xfade_size;
+
+
+ /* preserve the crossfader state */
+ x->x_xfade_phase = (int)prev_phase;
+ x->x_xfade_size = (int)size;
+
+
+ x->x_xfade_cos = cos(M_PI / (float)x->x_xfade_size);
+ x->x_xfade_sin = sin(M_PI / (float)x->x_xfade_size);
+
+
+ /* make sure indices are inside array */
+ if (x->x_npoints == 0){
+ x->x_currpos = 0;
+ x->x_prevpos = 0;
+ }
+
+ //else tabreadmix_tilde_wrapindices(x);
+
+
+
+}
+
+void tabreadmix_tilde_pitch(t_tabreadmix_tilde *x, t_float f)
+{
+ if (f < 1) f = 1;
+
+ tabreadmix_tilde_blocksize(x, sys_getsr() / f);
+}
+
+void tabreadmix_tilde_chunks(t_tabreadmix_tilde *x, t_float f)
+{
+ if (f < 1.0f) f = 1.0f;
+ tabreadmix_tilde_blocksize(x, (float)x->x_npoints / f);
+}
+
+void tabreadmix_tilde_bang(t_tabreadmix_tilde *x, t_float f)
+{
+ //trigger a chunk reset on next dsp call
+ x->x_xfade_phase = x->x_xfade_size;
+}
+
+void tabreadmix_tilde_set(t_tabreadmix_tilde *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)
+ error("tabreadmix~: %s: no such array", x->x_arrayname->s_name);
+ x->x_vec = 0;
+ }
+ else if (!garray_getfloatarray(a, &x->x_npoints, &x->x_vec))
+ {
+ error("%s: bad template for tabreadmix~", x->x_arrayname->s_name);
+ x->x_vec = 0;
+ }
+ else garray_usedindsp(a);
+
+ /* make sure indices are inside array */
+ if (x->x_npoints == 0){
+ x->x_currpos = 0;
+ x->x_prevpos = 0;
+ }
+
+ //else tabreadmix_tilde_wrapindices(x);
+
+}
+
+static void tabreadmix_tilde_dsp(t_tabreadmix_tilde *x, t_signal **sp)
+{
+ tabreadmix_tilde_set(x, x->x_arrayname);
+
+ dsp_add(tabreadmix_tilde_perform, 4, x,
+ sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+
+}
+
+static void tabreadmix_tilde_free(t_tabreadmix_tilde *x)
+{
+}
+
+static void *tabreadmix_tilde_new(t_symbol *s)
+{
+ t_tabreadmix_tilde *x = (t_tabreadmix_tilde *)pd_new(tabreadmix_tilde_class);
+ x->x_arrayname = s;
+ x->x_vec = 0;
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("blocksize"));
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ x->x_xfade_phase = 0;
+ x->x_xfade_size = 1024;
+ x->x_currpos = 0;
+ x->x_prevpos = 0;
+ x->x_xfade_state_c = 0.5f;
+ x->x_xfade_state_s = 0.0f;
+ tabreadmix_tilde_blocksize(x, 1024);
+ return (x);
+}
+
+void tabreadmix_tilde_setup(void)
+{
+ tabreadmix_tilde_class = class_new(gensym("tabreadmix~"),
+ (t_newmethod)tabreadmix_tilde_new, (t_method)tabreadmix_tilde_free,
+ sizeof(t_tabreadmix_tilde), 0, A_DEFSYM, 0);
+ CLASS_MAINSIGNALIN(tabreadmix_tilde_class, t_tabreadmix_tilde, x_f);
+ class_addmethod(tabreadmix_tilde_class, (t_method)tabreadmix_tilde_dsp,
+ gensym("dsp"), 0);
+ class_addmethod(tabreadmix_tilde_class, (t_method)tabreadmix_tilde_set,
+ gensym("set"), A_SYMBOL, 0);
+ class_addmethod(tabreadmix_tilde_class, (t_method)tabreadmix_tilde_blocksize,
+ gensym("blocksize"), A_FLOAT, 0);
+ class_addmethod(tabreadmix_tilde_class, (t_method)tabreadmix_tilde_pitch,
+ gensym("pitch"), A_FLOAT, 0);
+ class_addmethod(tabreadmix_tilde_class, (t_method)tabreadmix_tilde_chunks,
+ gensym("chunks"), A_FLOAT, 0);
+ class_addmethod(tabreadmix_tilde_class, (t_method)tabreadmix_tilde_bang,
+ gensym("bang"), 0);
+}
diff --git a/modules/xfm.c b/modules/xfm.c
new file mode 100644
index 0000000..63c79ab
--- /dev/null
+++ b/modules/xfm.c
@@ -0,0 +1,271 @@
+/*
+ * xfm.c - cross frequency modulation object
+ * Copyright (c) 2000-2003 by Tom Schouten
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/*
+coupled fm. osc state equations:
+
+phasor for system i =
+
+ [ 1 -phi ]
+(1+phi^2)^(1/2) * [ phi 1 ]
+
+
+with phi = 2*pi*(freq_base + freq_mod * out_other) / sr
+
+
+ideal phasor would be
+
+[ cos(phi) - sin(phi) ]
+[ sin(phi) cos(phi) ]
+
+
+this means frequencies are warped:
+
+2*pi*f_real = atan(2*pi*f)
+
+some (possible) enhancements:
+ + add an integrator to get phase modulation
+ + undo the frequency warping
+
+*/
+
+#include "m_pd.h"
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define SINSAMPLES 512
+#define MYPI 3.1415927
+
+
+#define DISTORTED 0
+#define NORMALIZED 1
+
+
+typedef struct xfmctl
+{
+ //t_float c_sintab[SINSAMPLES + 1];
+ t_float c_x1, c_y1; /* state osc 1 */
+ t_float c_x2, c_y2; /* state osc 2 */
+ t_int c_type; /* type of algo */
+
+} t_xfmctl;
+
+typedef struct xfm
+{
+ t_object x_obj;
+ t_float x_f;
+ t_xfmctl x_ctl;
+} t_xfm;
+
+void xfm_type(t_xfm *x, t_float f)
+{
+ int t = (int)f;
+
+ if (t == DISTORTED) x->x_ctl.c_type = t;
+ if (t == NORMALIZED) x->x_ctl.c_type = t;
+
+}
+
+
+static inline t_float xfm_sat(t_float x)
+{
+ const float max = 1;
+ const float min = -1;
+
+ x = (x > max) ? (max) : (x);
+ x = (x < min) ? (min) : (x);
+
+ return(x);
+}
+
+static t_int *xfm_perform(t_int *w)
+{
+
+
+ t_float *inA = (float *)(w[3]);
+ t_float *inB = (float *)(w[4]);
+ t_float *fbA = (float *)(w[5]);
+ t_float *fbB = (float *)(w[6]);
+ t_float *outA = (float *)(w[7]);
+ t_float *outB = (float *)(w[8]);
+ t_xfmctl *ctl = (t_xfmctl *)(w[1]);
+ t_int n = (t_int)(w[2]);
+ //t_float *tab = ctl->c_sintab;
+
+ t_float x1 = ctl->c_x1, y1 = ctl->c_y1, z1, dx1, dy1, inv_norm1;
+ t_float x2 = ctl->c_x2, y2 = ctl->c_y2, z2, dx2, dy2, inv_norm2;
+
+ t_float scale = 2 * M_PI / sys_getsr();
+
+ t_int i;
+
+ switch(ctl->c_type){
+ default:
+ case DISTORTED:
+
+ /* this is a 4 degree of freedom hyperchaotic system */
+ /* two coupled saturated unstable oscillators */
+
+ for (i=0; i<n; i++){
+ /* osc 1 */
+ z1 = scale * (x2 * (*fbA++) + (*inA++));
+
+ dx1 = x1 - z1*y1;
+ dy1 = y1 + z1*x1;
+
+ x1 = xfm_sat(dx1);
+ y1 = xfm_sat(dy1);
+
+ /* osc 2*/
+ z2 = scale * (x1 * (*fbB++) + (*inB++));
+
+ dx2 = x2 - z2*y2;
+ dy2 = y2 + z2*x2;
+
+ x2 = xfm_sat(dx2);
+ y2 = xfm_sat(dy2);
+
+ /* output */
+ (*outA++) = x1;
+ (*outB++) = x2;
+
+ }
+ break;
+
+ case NORMALIZED:
+
+ /* this is a an effective 2 degree of freedom quasiperiodic system */
+ /* two coupled stable oscillators */
+
+ for (i=0; i<n; i++){
+
+ /* osc 1 */
+ z1 = scale * (x2 * (*fbA++) + (*inA++));
+
+ dx1 = x1 - z1*y1;
+ dy1 = y1 + z1*x1;
+ inv_norm1 = 1.0f / hypot(dx1, dy1);
+
+
+ /* osc 2*/
+ z2 = scale * (x1 * (*fbB++) + (*inB++));
+
+ dx2 = x2 - z2*y2;
+ dy2 = y2 + z2*x2;
+ inv_norm2 = 1.0f / hypot(dx2, dy2);
+
+ /* renormalize */
+ x1 = dx1 * inv_norm1;
+ y1 = dy1 * inv_norm1;
+ x2 = dx2 * inv_norm2;
+ y2 = dy2 * inv_norm2;
+
+ /* output */
+ (*outA++) = x1;
+ (*outB++) = x2;
+ }
+ break;
+ }
+
+ ctl->c_x1 = x1;
+ ctl->c_y1 = y1;
+ ctl->c_x2 = x2;
+ ctl->c_y2 = y2;
+
+ return (w+9);
+}
+
+static void xfm_dsp(t_xfm *x, t_signal **sp)
+{
+ int n = sp[0]->s_n;
+ int k;
+
+
+ dsp_add(xfm_perform,
+ 8,
+ &x->x_ctl,
+ sp[0]->s_n,
+ sp[0]->s_vec,
+ sp[1]->s_vec,
+ sp[2]->s_vec,
+ sp[3]->s_vec,
+ sp[4]->s_vec,
+ sp[5]->s_vec);
+
+
+}
+static void xfm_free(t_xfm *x)
+{
+
+
+}
+
+
+
+
+static void xfm_reset(t_xfm *x)
+{
+ x->x_ctl.c_x1 = 1;
+ x->x_ctl.c_y1 = 0;
+ x->x_ctl.c_x2 = 1;
+ x->x_ctl.c_y2 = 0;
+
+}
+
+
+t_class *xfm_class;
+
+static void *xfm_new(t_floatarg algotype)
+{
+ t_xfm *x = (t_xfm *)pd_new(xfm_class);
+
+ /* ins */
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("signal"), gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("signal"), gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("signal"), gensym("signal"));
+
+ /* outs */
+ outlet_new(&x->x_obj, gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+
+
+
+ /* init data */
+ xfm_reset(x);
+ xfm_type(x, algotype);
+
+ return (void *)x;
+}
+
+void xfm_tilde_setup(void)
+{
+ //post("xfm~ v0.1");
+ xfm_class = class_new(gensym("xfm~"), (t_newmethod)xfm_new,
+ (t_method)xfm_free, sizeof(t_xfm), 0, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(xfm_class, t_xfm, x_f);
+ class_addmethod(xfm_class, (t_method)xfm_type, gensym("type"), A_FLOAT, 0);
+ class_addmethod(xfm_class, (t_method)xfm_dsp, gensym("dsp"), 0);
+ class_addmethod(xfm_class, (t_method)xfm_reset, gensym("reset"), 0);
+
+
+}
+
diff --git a/system/Makefile b/system/Makefile
new file mode 100644
index 0000000..12666a4
--- /dev/null
+++ b/system/Makefile
@@ -0,0 +1,8 @@
+include ../Makefile.config
+
+all: setup.o envelope_util.o
+
+clean:
+ rm -f *.o
+ rm -f *~
+
diff --git a/system/envelope_util.c b/system/envelope_util.c
new file mode 100644
index 0000000..7117149
--- /dev/null
+++ b/system/envelope_util.c
@@ -0,0 +1,33 @@
+/*
+ * Utility functions for exponential decay
+ * Copyright (c) 2000-2003 by Tom Schouten
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include "extlib_util.h"
+
+float milliseconds_2_one_minus_realpole(float time)
+{
+ float r;
+
+ if (time < 0.0f) time = 0.0f;
+ r = -expm1(1000.0f * log(ENVELOPE_RANGE) / (sys_getsr() * time));
+ if (!(r < 1.0f)) r = 1.0f;
+
+ //post("%f",r);
+ return r;
+}
diff --git a/system/setup.c b/system/setup.c
new file mode 100644
index 0000000..b425f84
--- /dev/null
+++ b/system/setup.c
@@ -0,0 +1,64 @@
+#include "m_pd.h"
+
+void ead_tilde_setup(void);
+void ear_tilde_setup(void);
+void eadsr_tilde_setup(void);
+void dist_tilde_setup(void);
+void tabreadmix_tilde_setup(void);
+void xfm_tilde_setup(void);
+void biquadseries_tilde_setup(void);
+void filterortho_tilde_setup(void);
+void qmult_tilde_setup(void);
+void qnorm_tilde_setup(void);
+void cheby_tilde_setup(void);
+void abs_tilde_setup(void);
+void ramp_tilde_setup(void);
+void dwt_tilde_setup(void);
+void bfft_tilde_setup(void);
+void dynwav_tilde_setup(void);
+void statwav_tilde_setup(void);
+void bdiag_tilde_setup(void);
+void diag_tilde_setup(void);
+void matrix_tilde_setup(void);
+void permut_tilde_setup(void);
+void lattice_tilde_setup(void);
+void ratio_setup(void);
+void ffpoly_setup(void);
+void fwarp_setup(void);
+
+void creb_setup(void)
+{
+ post("CREB: version " CREB_VERSION);
+
+ /* setup tilde objects */
+ ead_tilde_setup();
+ ear_tilde_setup();
+ eadsr_tilde_setup();
+ dist_tilde_setup();
+ tabreadmix_tilde_setup();
+ xfm_tilde_setup();
+ qmult_tilde_setup();
+ qnorm_tilde_setup();
+ cheby_tilde_setup();
+ abs_tilde_setup();
+ ramp_tilde_setup();
+ dwt_tilde_setup();
+ bfft_tilde_setup();
+ dynwav_tilde_setup();
+ statwav_tilde_setup();
+ bdiag_tilde_setup();
+ diag_tilde_setup();
+ matrix_tilde_setup();
+ permut_tilde_setup();
+ lattice_tilde_setup();
+
+ /* setup other objects */
+ ratio_setup();
+ ffpoly_setup();
+ fwarp_setup();
+
+ /* setup c++ modules */
+ biquadseries_tilde_setup();
+ filterortho_tilde_setup();
+
+}