aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormusil <tmusil@users.sourceforge.net>2006-03-09 17:05:43 +0000
committermusil <tmusil@users.sourceforge.net>2006-03-09 17:05:43 +0000
commite5a3c99d0f46d825a5550e88a0906f900e31be52 (patch)
treee30df3751e6699012e87db2d8c36f531c3e85213
initial version JAN_06 with all sourcessvn2git-root
svn path=/trunk/externals/iem/iem_ambi/; revision=4668
-rw-r--r--GnuGPL.txt340
-rw-r--r--LICENSE.txt27
-rw-r--r--READ_ME.txt6
-rw-r--r--help/help-ambi_decode.pd247
-rw-r--r--help/help-ambi_decode2.pd97
-rw-r--r--help/help-ambi_decode3.pd150
-rw-r--r--help/help-ambi_encode.pd283
-rw-r--r--help/help-ambi_rot.pd80
-rw-r--r--help/test-ambi_rot.pd80
-rw-r--r--src/Make.config.in28
-rw-r--r--src/Makefile88
-rw-r--r--src/ambi_decode.c724
-rw-r--r--src/ambi_decode2.c824
-rw-r--r--src/ambi_decode3.c772
-rw-r--r--src/ambi_decode_cube.c799
-rw-r--r--src/ambi_encode.c433
-rw-r--r--src/ambi_rot.c1534
-rw-r--r--src/configure.ac292
-rw-r--r--src/iem_ambi.c44
-rw-r--r--src/iem_ambi.dsp85
-rw-r--r--src/iem_ambi.dsw29
-rw-r--r--src/iem_ambi.h15
-rw-r--r--src/iem_ambi_sources.h11
-rw-r--r--src/iem_bin_ambi_sources.c13
-rw-r--r--src/iemlib.h102
-rw-r--r--src/makefile_win42
-rw-r--r--src/makesource.sh65
27 files changed, 7210 insertions, 0 deletions
diff --git a/GnuGPL.txt b/GnuGPL.txt
new file mode 100644
index 0000000..d60c31a
--- /dev/null
+++ b/GnuGPL.txt
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..cdd6236
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,27 @@
+iem_ambi - ambisonic encoder, rotation and decoder rendering
+
+Copyright (C) 2000-2006 Thomas MUSIL [musil_at_iem.at]
+
+IEM - Institute of Electronic Music and Acoustics, Graz
+Inffeldgasse 10/3, 8010 Graz, Austria
+http://iem.at
+
+
+
+ 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 ( GnuGPL.txt ).
+ (e.g. http://www.gnu.org/copyleft/gpl.html)
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Graz, 15 June 2005
+ Thomas Musil \ No newline at end of file
diff --git a/READ_ME.txt b/READ_ME.txt
new file mode 100644
index 0000000..d37dd65
--- /dev/null
+++ b/READ_ME.txt
@@ -0,0 +1,6 @@
+This library extends the performance of miller puckette's pure data (pd).
+
+iem_ambi contains 3 objects:
+"ambi_encode", "ambi_rot" and "ambi_decode3"
+they calculate ambisonic encoder matrices, rotation matrices and
+decoder matrices from 1st to 4th order in 2D or 3D.
diff --git a/help/help-ambi_decode.pd b/help/help-ambi_decode.pd
new file mode 100644
index 0000000..93ce8e3
--- /dev/null
+++ b/help/help-ambi_decode.pd
@@ -0,0 +1,247 @@
+#N canvas 117 18 719 674 10;
+#X obj 47 249 print;
+#X text 291 171 1.arg: <float> ambisonic order;
+#X text 306 180 (1 .. 12 for 2 dimensional use);
+#X obj 47 226 round_zero 1e-006;
+#X text 117 310 ambisonic-order = n_ao;
+#X msg 150 170 ambi_weight 1 1 1;
+#X msg 133 149 ambi_weight 1 1 0.3904;
+#X text 305 385 ambisonic-order-group;
+#X text 98 416 -90 <= delta <= +90;
+#X text 98 428 -180 <= phi <= +180;
+#X text 34 385 input: <ambi_weight> one mul-factor for each;
+#X text 21 12 ambi_decode;
+#X text 105 12 calculates a decoder-matrix;
+#X obj 47 204 ambi_decode 2 2 5 0;
+#X text 291 199 2.arg: <float> dimension;
+#X text 440 199 (2 or 3);
+#X text 291 211 3.arg: <float> number of real loudspeakers;
+#X text 305 222 (best results \, if n_ls = n_ambi_channels);
+#X text 316 232 (could be more or less);
+#X text 292 243 4.arg: <float> number of phantom_loudspeakers;
+#X text 334 254 (optional \, default 0);
+#X msg 46 116 pinv;
+#X obj 59 90 t b b;
+#X obj 59 46 bng 35 250 50 0 empty empty empty 0 -6 0 8 -24198 -42246
+-1;
+#X text 34 334 input: <ls> index + phi [degree] .. 2-dimensional;
+#X text 34 344 input: <ls> index + delta + phi [degree] .. 3-dimensional
+;
+#X text 34 358 input: <phls> index + phi [degree .. 2-dimensional;
+#X text 34 369 input: <phls> index + delta + phi [degree] .. 3-dimensional
+;
+#X text 63 525 <float> n_col = (2*n_ao+1) = number of ambisonic-channels
+;
+#X text 51 534 + <float> n_row = (n_ls) = number of loudspeakers;
+#X text 286 311 number of loudspeakers = n_ls;
+#X text 51 594 + <float> n_row = (n_ls) = number of loudspeakers;
+#X text 36 575 output in case of 3d: <matrix> ((n_ao+1)*(n_ao+1)*n_ls+2)
+;
+#X text 37 514 output in case of 2d: <matrix> ((2*n_ao+1)*n_ls+2);
+#X text 384 575 <float> :;
+#X text 341 513 <float> :;
+#X text 281 585 number of ambisonic-channels;
+#X text 63 585 <float> n_col = (n_ao+1)*(n_ao+1) =;
+#X text 252 604 <float> elements of a matrix;
+#X text 51 604 + (n_ao + 1) * (n_ao + 1) * n_ls;
+#X text 51 544 + (2*n_ao + 1) * n_ls <float> elements of a matrix;
+#X text 34 458 input: <pinv> calculates the pseudo-inverse of the encoded
+;
+#X text 90 469 loudspeaker-positions (+ the phantom-speakers);
+#X text 104 480 and output a matrix-message;
+#X text 306 189 (1 .. 5 for 3 dimensional use);
+#X msg 95 116 ls 1 0 \, ls 2 72 \, ls 3 144 \, ls 4 216 \, ls 5 288
+;
+#X text 113 405 1 <= index <= n_ao;
+#X text 340 275 a regular matrix to inverse it);
+#X text 437 384 to suppress the side-lobe-phenomena;
+#X text 308 265 (it is sometimes necessary to add phantom-ls. for achieving
+;
+#N canvas 0 0 812 677 phantom_example 0;
+#X obj 57 631 print;
+#X obj 57 608 round_zero 1e-006;
+#X msg 57 94 pinv;
+#X obj 70 24 bng 35 250 50 0 empty empty empty 0 -6 0 8 -24198 -42246
+-1;
+#X msg 198 72 ls 1 5 \, ls 2 2.5 \, ls 3 0 \, ls 4 -2.5 \, ls 5 -5
+;
+#X msg 92 176 phls 5 -17.5 \, phls 6 -20 \, phls 7 -22.5 \, phls 8
+-25;
+#X msg 92 200 phls 9 -27.5 \, phls 10 -30 \, phls 11 -32.5 \, phls
+12 -35;
+#X msg 92 223 phls 13 -37.5 \, phls 14 -40 \, phls 15 -42.5 \, phls
+16 -45;
+#X msg 92 247 phls 17 -47.5 \, phls 18 -50 \, phls 19 -52.5 \, phls
+20 -55;
+#X msg 92 270 phls 21 -57.5 \, phls 22 -60 \, phls 23 -62.5 \, phls
+24 -65;
+#X msg 92 294 phls 25 -67.5 \, phls 26 -70 \, phls 27 -72.5 \, phls
+28 -75;
+#X msg 92 317 phls 29 -77.5 \, phls 30 -80 \, phls 31 -82.5 \, phls
+32 -85;
+#X msg 92 340 phls 33 -87.5 \, phls 34 -90 \, phls 35 -92.5 \, phls
+36 -95;
+#X msg 92 364 phls 37 -97.5 \, phls 38 -100 \, phls 39 -102.5 \, phls
+40 -105;
+#X msg 92 387 phls 41 -107.5 \, phls 42 -110 \, phls 43 -112.5 \, phls
+44 -115;
+#X msg 92 411 phls 45 -117.5 \, phls 46 -120 \, phls 47 -122.5 \, phls
+48 -125;
+#X msg 92 434 phls 49 -127.5 \, phls 50 -130 \, phls 51 -132.5 \, phls
+52 -135;
+#X msg 92 456 phls 53 -137.5 \, phls 54 -140 \, phls 55 -142.5 \, phls
+56 -145;
+#X msg 92 480 phls 57 -147.5 \, phls 58 -150 \, phls 59 -152.5 \, phls
+60 -155;
+#X msg 92 503 phls 61 -157.5 \, phls 62 -160 \, phls 63 -162.5 \, phls
+64 -165;
+#X msg 92 527 phls 65 -167.5 \, phls 66 -170 \, phls 67 -172.5 \, phls
+68 -175;
+#X msg 92 550 phls 69 -177.5 \, phls 70 -180 \, phls 71 177.5 \, phls
+72 175;
+#X msg 497 228 phls 73 172.5 \, phls 74 170 \, phls 75 167.5 \, phls
+76 165;
+#X msg 497 249 phls 77 162.5 \, phls 78 160 \, phls 79 157.5 \, phls
+80 155;
+#X msg 497 270 phls 81 152.5 \, phls 82 150 \, phls 83 147.5 \, phls
+84 145;
+#X msg 497 290 phls 85 142.5 \, phls 86 140 \, phls 87 137.5 \, phls
+88 135;
+#X msg 497 312 phls 89 132.5 \, phls 90 130 \, phls 91 127.5 \, phls
+92 125;
+#X msg 497 333 phls 93 122.5 \, phls 94 120 \, phls 95 117.5 \, phls
+96 115;
+#X msg 497 354 phls 97 112.5 \, phls 98 110 \, phls 99 107.5 \, phls
+100 105;
+#X msg 497 375 phls 101 102.5 \, phls 102 100 \, phls 103 97.5 \, phls
+104 95;
+#X msg 497 396 phls 105 92.5 \, phls 106 90 \, phls 107 87.5 \, phls
+108 85;
+#X msg 497 418 phls 109 82.5 \, phls 110 80 \, phls 111 77.5 \, phls
+112 75;
+#X msg 497 439 phls 113 72.5 \, phls 114 70 \, phls 115 67.5 \, phls
+116 65;
+#X msg 497 460 phls 117 62.5 \, phls 118 60 \, phls 119 57.5 \, phls
+120 55;
+#X msg 497 481 phls 121 52.5 \, phls 122 50 \, phls 123 47.5 \, phls
+124 45;
+#X msg 497 502 phls 125 42.5 \, phls 126 40 \, phls 127 37.5 \, phls
+128 35;
+#X msg 497 524 phls 129 32.5 \, phls 130 30 \, phls 131 27.5 \, phls
+132 25;
+#X msg 497 545 phls 133 22.5 \, phls 134 20 \, phls 135 17.5 \, phls
+136 15;
+#X msg 497 566 phls 137 12.5 \, phls 138 10 \, phls 139 7.5;
+#X obj 70 68 t b b b b;
+#X obj 92 127 t b;
+#X obj 497 206 t b;
+#X obj 57 586 ambi_decode 2 2 5 139;
+#X msg 92 152 phls 1 -7.5 \, phls 2 -10 \, phls 3 -12.5 \, phls 4 -15
+;
+#X connect 1 0 0 0;
+#X connect 2 0 42 0;
+#X connect 3 0 39 0;
+#X connect 4 0 42 0;
+#X connect 5 0 42 0;
+#X connect 6 0 42 0;
+#X connect 7 0 42 0;
+#X connect 8 0 42 0;
+#X connect 9 0 42 0;
+#X connect 10 0 42 0;
+#X connect 11 0 42 0;
+#X connect 12 0 42 0;
+#X connect 13 0 42 0;
+#X connect 14 0 42 0;
+#X connect 15 0 42 0;
+#X connect 16 0 42 0;
+#X connect 17 0 42 0;
+#X connect 18 0 42 0;
+#X connect 19 0 42 0;
+#X connect 20 0 42 0;
+#X connect 21 0 42 0;
+#X connect 22 0 42 0;
+#X connect 23 0 42 0;
+#X connect 24 0 42 0;
+#X connect 25 0 42 0;
+#X connect 26 0 42 0;
+#X connect 27 0 42 0;
+#X connect 28 0 42 0;
+#X connect 29 0 42 0;
+#X connect 30 0 42 0;
+#X connect 31 0 42 0;
+#X connect 32 0 42 0;
+#X connect 33 0 42 0;
+#X connect 34 0 42 0;
+#X connect 35 0 42 0;
+#X connect 36 0 42 0;
+#X connect 37 0 42 0;
+#X connect 38 0 42 0;
+#X connect 39 0 2 0;
+#X connect 39 1 41 0;
+#X connect 39 2 40 0;
+#X connect 39 3 4 0;
+#X connect 40 0 43 0;
+#X connect 40 0 5 0;
+#X connect 40 0 6 0;
+#X connect 40 0 7 0;
+#X connect 40 0 8 0;
+#X connect 40 0 9 0;
+#X connect 40 0 10 0;
+#X connect 40 0 11 0;
+#X connect 40 0 12 0;
+#X connect 40 0 13 0;
+#X connect 40 0 14 0;
+#X connect 40 0 15 0;
+#X connect 40 0 16 0;
+#X connect 40 0 17 0;
+#X connect 40 0 18 0;
+#X connect 40 0 19 0;
+#X connect 40 0 20 0;
+#X connect 40 0 21 0;
+#X connect 41 0 22 0;
+#X connect 41 0 23 0;
+#X connect 41 0 24 0;
+#X connect 41 0 25 0;
+#X connect 41 0 26 0;
+#X connect 41 0 27 0;
+#X connect 41 0 28 0;
+#X connect 41 0 29 0;
+#X connect 41 0 30 0;
+#X connect 41 0 31 0;
+#X connect 41 0 32 0;
+#X connect 41 0 33 0;
+#X connect 41 0 34 0;
+#X connect 41 0 35 0;
+#X connect 41 0 36 0;
+#X connect 41 0 37 0;
+#X connect 41 0 38 0;
+#X connect 42 0 1 0;
+#X connect 43 0 42 0;
+#X restore 421 117 pd phantom_example regular;
+#N canvas 0 0 814 679 real_example 0;
+#X obj 58 293 print;
+#X obj 58 270 round_zero 1e-006;
+#X msg 57 94 pinv;
+#X obj 70 24 bng 35 250 50 0 empty empty empty 0 -6 0 8 -24198 -42246
+-1;
+#X msg 103 115 ls 1 5 \, ls 2 2.5 \, ls 3 0 \, ls 4 -2.5 \, ls 5 -5
+;
+#X obj 70 68 t b b;
+#X obj 58 248 ambi_decode 2 2 5 0;
+#X connect 1 0 0 0;
+#X connect 2 0 6 0;
+#X connect 3 0 5 0;
+#X connect 4 0 6 0;
+#X connect 5 0 2 0;
+#X connect 5 1 4 0;
+#X connect 6 0 1 0;
+#X restore 421 90 pd real_example singular;
+#X connect 3 0 0 0;
+#X connect 5 0 13 0;
+#X connect 6 0 13 0;
+#X connect 13 0 3 0;
+#X connect 21 0 13 0;
+#X connect 22 0 21 0;
+#X connect 22 1 45 0;
+#X connect 23 0 22 0;
+#X connect 45 0 13 0;
diff --git a/help/help-ambi_decode2.pd b/help/help-ambi_decode2.pd
new file mode 100644
index 0000000..c1c998b
--- /dev/null
+++ b/help/help-ambi_decode2.pd
@@ -0,0 +1,97 @@
+#N canvas 82 3 844 643 10;
+#X obj 38 441 print;
+#X text 454 156 1.arg: <float> ambisonic order;
+#X obj 38 418 round_zero 1e-006;
+#X text 297 312 ambisonic-order = n_ao;
+#X text 485 387 ambisonic-order-group;
+#X text 273 428 -90 <= delta <= +90;
+#X text 273 440 -180 <= phi <= +180;
+#X text 214 387 input: <ambi_weight> one mul-factor for each;
+#X text 21 12 ambi_decode;
+#X text 105 12 calculates a decoder-matrix;
+#X obj 38 33 bng 35 250 50 0 empty empty empty 0 -6 0 8 -24198 -42246
+-1;
+#X text 214 336 input: <ls> index + phi [degree] .. 2-dimensional;
+#X text 214 346 input: <ls> index + delta + phi [degree] .. 3-dimensional
+;
+#X text 214 360 input: <phls> index + phi [degree .. 2-dimensional
+;
+#X text 214 371 input: <phls> index + delta + phi [degree] .. 3-dimensional
+;
+#X text 238 518 <float> n_col = (2*n_ao+1) = number of ambisonic-channels
+;
+#X text 226 527 + <float> n_row = (n_ls) = number of loudspeakers;
+#X text 466 313 number of loudspeakers = n_ls;
+#X text 229 587 + <float> n_row = (n_ls) = number of loudspeakers;
+#X text 214 568 output in case of 3d: <matrix> ((n_ao+1)*(n_ao+1)*n_ls+2)
+;
+#X text 212 507 output in case of 2d: <matrix> ((2*n_ao+1)*n_ls+2)
+;
+#X text 559 568 <float> :;
+#X text 516 506 <float> :;
+#X text 456 578 number of ambisonic-channels;
+#X text 241 578 <float> n_col = (n_ao+1)*(n_ao+1) =;
+#X text 427 597 <float> elements of a matrix;
+#X text 229 597 + (n_ao + 1) * (n_ao + 1) * n_ls;
+#X text 226 537 + (2*n_ao + 1) * n_ls <float> elements of a matrix
+;
+#X text 207 460 input: <pinv> calculates the pseudo-inverse of the
+encoded;
+#X text 263 471 loudspeaker-positions (+ the phantom-speakers);
+#X text 277 482 and output a matrix-message;
+#X text 288 417 1 <= index <= n_ao;
+#X text 544 268 a regular matrix to inverse it);
+#X text 375 399 to suppress the side-lobe-phenomena;
+#X text 467 258 (it is sometimes necessary to add phantom-ls. for achieving
+;
+#X msg 38 372 pseudo_inverse;
+#X msg 234 128 ambi_weight 1 1 1 0.3904;
+#X msg 108 129 ambi_weight 1 1 1 1;
+#X msg 123 104 mirror_weight 0.7;
+#X obj 94 178 pp ind_ls;
+#X msg 94 155 1 90 0 \, 2 45 45 \, 3 45 135 \, 4 45 225 \, 5 45 315
+;
+#X obj 38 396 ambi_decode2 3 3 5 8 1;
+#X obj 80 243 pp mrg_ls;
+#X msg 80 208 1 0 0 \, 2 0 45 \, 3 0 90 \, 4 0 135 \, 5 0 180 \, 6
+0 225 \, 7 0 270 \, 8 0 315;
+#X obj 66 300 pp mir_ls;
+#X msg 66 265 1 -45 0 \, 2 -45 45 \, 3 -45 90 \, 4 -45 135 \, 5 -45
+180 \, 6 -45 225 \, 7 -45 270 \, 8 -45 315;
+#X obj 52 346 pp pht_ls;
+#X msg 52 323 1 -90 0;
+#X obj 38 77 t b b b b b b b;
+#X text 469 174 (1 .. 5 in case of 3 dimensional);
+#X text 469 165 (1 .. 12 in case of 2 dimensional);
+#X text 455 196 3.arg: <float> number of independent loudspeakers;
+#X text 454 184 2.arg: <float> dimension (2 or 3);
+#X text 454 247 5.arg: <float> number of canceled phantom_loudspeakers
+;
+#X text 455 208 4.arg: <float> number of merged and mirrored loudspeakers
+;
+#X text 501 221 (the merged loudspeakers are at the border of the arc
+;
+#X text 514 233 or the hemisphere \, the mirrored loudspeakers are
+;
+#X connect 2 0 0 0;
+#X connect 10 0 48 0;
+#X connect 35 0 41 0;
+#X connect 36 0 41 0;
+#X connect 37 0 41 0;
+#X connect 38 0 41 0;
+#X connect 39 0 41 0;
+#X connect 40 0 39 0;
+#X connect 41 0 2 0;
+#X connect 42 0 41 0;
+#X connect 43 0 42 0;
+#X connect 44 0 41 0;
+#X connect 45 0 44 0;
+#X connect 46 0 41 0;
+#X connect 47 0 46 0;
+#X connect 48 0 35 0;
+#X connect 48 1 47 0;
+#X connect 48 2 45 0;
+#X connect 48 3 43 0;
+#X connect 48 4 40 0;
+#X connect 48 5 37 0;
+#X connect 48 6 38 0;
diff --git a/help/help-ambi_decode3.pd b/help/help-ambi_decode3.pd
new file mode 100644
index 0000000..acc1c6d
--- /dev/null
+++ b/help/help-ambi_decode3.pd
@@ -0,0 +1,150 @@
+#N canvas 4 4 856 655 10;
+#X obj 60 572 print;
+#X text 513 156 1.arg: <float> ambisonic order;
+#X obj 60 549 round_zero 1e-006;
+#X text 348 312 ambisonic-order = n_ao;
+#X text 536 387 ambisonic-order-group;
+#X text 324 428 -90 <= delta <= +90;
+#X text 324 440 -180 <= phi <= +180;
+#X text 265 387 input: <ambi_weight> one mul-factor for each;
+#X text 21 12 ambi_decode;
+#X text 105 12 calculates a decoder-matrix;
+#X obj 38 33 bng 35 250 50 0 empty empty empty 0 -6 0 8 -24198 -42246
+-1;
+#X text 265 336 input: <ls> index + phi [degree] .. 2-dimensional;
+#X text 265 346 input: <ls> index + delta + phi [degree] .. 3-dimensional
+;
+#X text 265 360 input: <phls> index + phi [degree .. 2-dimensional
+;
+#X text 265 371 input: <phls> index + delta + phi [degree] .. 3-dimensional
+;
+#X text 289 518 <float> n_col = (2*n_ao+1) = number of ambisonic-channels
+;
+#X text 277 527 + <float> n_row = (n_ls) = number of loudspeakers;
+#X text 517 313 number of loudspeakers = n_ls;
+#X text 280 587 + <float> n_row = (n_ls) = number of loudspeakers;
+#X text 265 568 output in case of 3d: <matrix> ((n_ao+1)*(n_ao+1)*n_ls+2)
+;
+#X text 263 507 output in case of 2d: <matrix> ((2*n_ao+1)*n_ls+2)
+;
+#X text 610 568 <float> :;
+#X text 567 506 <float> :;
+#X text 507 578 number of ambisonic-channels;
+#X text 292 578 <float> n_col = (n_ao+1)*(n_ao+1) =;
+#X text 478 597 <float> elements of a matrix;
+#X text 280 597 + (n_ao + 1) * (n_ao + 1) * n_ls;
+#X text 277 537 + (2*n_ao + 1) * n_ls <float> elements of a matrix
+;
+#X text 258 460 input: <pinv> calculates the pseudo-inverse of the
+encoded;
+#X text 314 471 loudspeaker-positions (+ the phantom-speakers);
+#X text 328 482 and output a matrix-message;
+#X text 339 417 1 <= index <= n_ao;
+#X text 603 268 a regular matrix to inverse it);
+#X text 426 399 to suppress the side-lobe-phenomena;
+#X text 526 258 (it is sometimes necessary to add phantom-ls. for achieving
+;
+#X msg 272 130 ambi_weight 1 1 1 0.3904;
+#X msg 123 129 ambi_weight 1 1 1 1;
+#X msg 138 106 mirror_weight 0.7;
+#X obj 94 237 pp pht_ls;
+#X obj 38 77 t b b b b b b b;
+#X text 528 174 (1 .. 5 in case of 3 dimensional);
+#X text 528 165 (1 .. 12 in case of 2 dimensional);
+#X text 514 196 3.arg: <float> number of independent loudspeakers;
+#X text 513 184 2.arg: <float> dimension (2 or 3);
+#X text 513 247 5.arg: <float> number of canceled phantom_loudspeakers
+;
+#X text 514 208 4.arg: <float> number of merged and mirrored loudspeakers
+;
+#X text 560 221 (the merged loudspeakers are at the border of the arc
+;
+#X text 573 233 or the hemisphere \, the mirrored loudspeakers are
+;
+#X obj 742 385 pp ind_ls;
+#X msg 742 362 1 90 0 \, 2 45 45 \, 3 45 135 \, 4 45 225 \, 5 45 315
+;
+#X obj 728 450 pp mrg_ls;
+#X msg 728 415 1 0 0 \, 2 0 45 \, 3 0 90 \, 4 0 135 \, 5 0 180 \, 6
+0 225 \, 7 0 270 \, 8 0 315;
+#X obj 714 507 pp mir_ls;
+#X msg 714 472 1 -45 0 \, 2 -45 45 \, 3 -45 90 \, 4 -45 135 \, 5 -45
+180 \, 6 -45 225 \, 7 -45 270 \, 8 -45 315;
+#X obj 700 553 pp pht_ls;
+#X msg 700 530 1 -90 0;
+#X msg 108 155 1 90 0 \, 2 45 45 \, 3 45 135 \, 4 45 225 \, 5 45 315
+\, 6 0 0 \, 7 0 45 \, 8 0 90 \, 9 0 135 \, 10 0 180 \, 11 0 225 \,
+12 0 270 \, 13 0 315;
+#X obj 108 190 pp real_ls;
+#X msg 80 263 begin_pseudo_inverse;
+#X obj 60 527 ambi_decode3 3 3 13 6;
+#X msg 30 501 end_pseudo_inverse;
+#X msg 94 215 1 -45 0 \, 2 -45 90 \, 3 -45 180 \, 4 -45 270 \, 6 -90
+0;
+#X msg 47 476 ipht_ireal_muladd \$1 \$2 \$3;
+#N canvas 337 146 559 509 /SUBPATCH/ 0;
+#X msg 142 186 1 6 \$1;
+#X obj 102 58 inlet;
+#X obj 101 441 outlet;
+#X obj 162 59 inlet;
+#X obj 71 135 f;
+#X obj 103 135 f;
+#X obj 157 106 * 0.25;
+#X obj 214 106 * 0.5;
+#X msg 163 211 2 8 \$1;
+#X msg 40 187 1 13 \$1 \, 1 7 \$1;
+#X msg 61 212 2 7 \$1 \, 2 9 \$1;
+#X msg 179 241 3 10 \$1;
+#X msg 77 242 3 9 \$1 \, 3 11 \$1;
+#X msg 199 271 4 12 \$1;
+#X msg 87 271 4 11 \$1 \, 4 13 \$1;
+#X obj 162 81 route mirror_weight;
+#X connect 0 0 2 0;
+#X connect 1 0 4 0;
+#X connect 1 0 5 0;
+#X connect 3 0 15 0;
+#X connect 4 0 9 0;
+#X connect 4 0 10 0;
+#X connect 4 0 12 0;
+#X connect 4 0 14 0;
+#X connect 5 0 0 0;
+#X connect 5 0 8 0;
+#X connect 5 0 11 0;
+#X connect 5 0 13 0;
+#X connect 6 0 4 1;
+#X connect 7 0 5 1;
+#X connect 8 0 2 0;
+#X connect 9 0 2 0;
+#X connect 10 0 2 0;
+#X connect 11 0 2 0;
+#X connect 12 0 2 0;
+#X connect 13 0 2 0;
+#X connect 14 0 2 0;
+#X connect 15 0 7 0;
+#X connect 15 0 6 0;
+#X restore 47 436 pd;
+#X connect 2 0 0 0;
+#X connect 10 0 39 0;
+#X connect 35 0 59 0;
+#X connect 36 0 59 0;
+#X connect 37 0 63 1;
+#X connect 38 0 59 0;
+#X connect 39 0 60 0;
+#X connect 39 1 63 0;
+#X connect 39 2 58 0;
+#X connect 39 3 61 0;
+#X connect 39 4 56 0;
+#X connect 39 5 36 0;
+#X connect 39 6 37 0;
+#X connect 49 0 48 0;
+#X connect 51 0 50 0;
+#X connect 53 0 52 0;
+#X connect 55 0 54 0;
+#X connect 56 0 57 0;
+#X connect 57 0 59 0;
+#X connect 58 0 59 0;
+#X connect 59 0 2 0;
+#X connect 60 0 59 0;
+#X connect 61 0 38 0;
+#X connect 62 0 59 0;
+#X connect 63 0 62 0;
diff --git a/help/help-ambi_encode.pd b/help/help-ambi_encode.pd
new file mode 100644
index 0000000..b5e1632
--- /dev/null
+++ b/help/help-ambi_encode.pd
@@ -0,0 +1,283 @@
+#N canvas 61 48 860 672 10;
+#X obj 374 243 ambi_encode 2;
+#X obj 374 288 print;
+#X text 478 247 1.arg: <float> ambisonic order;
+#X text 489 259 (1 .. 12 for 2 dimensional use);
+#X msg 461 178 col 2 \$1;
+#X msg 425 97 row 1 \$1;
+#X msg 288 211 col 3 \$1 \$2;
+#X obj 288 188 pack 0 0;
+#X obj 306 166 t b f;
+#X obj 374 265 round_zero 1e-006;
+#X obj 184 193 pack 0 0;
+#X obj 202 171 t b f;
+#X floatatom 100 161 5 -180 180 0 - - -;
+#X floatatom 51 162 5 -90 90 0 - - -;
+#X obj 82 222 pack 0 0;
+#X obj 100 200 t b f;
+#X text 48 143 delta;
+#X text 102 142 phi;
+#X text 21 12 ambi_encode;
+#X text 34 291 ambisonic-order = n_ao;
+#X text 346 320 -> output: <list> of (2*n_ao+1) <float>;
+#X text 346 331 -> output: <list> of (n_ao+1)*(n_ao+1) <float>;
+#X text 387 356 -> output: <row> + index + (2*n_ao+1) <float>;
+#X text 387 368 -> output: <row> + index + (n_ao+1)*(n_ao+1) <float>
+;
+#X text 383 394 -> output: <col> + index + (2*n_ao+1) <float>;
+#X text 383 406 -> output: <col> + index + (n_ao+1)*(n_ao+1) <float>
+;
+#X text 432 424 for crossfading of 2 ambisonic-systems;
+#X msg 605 183 ambi_weight 1 1 1;
+#X msg 588 162 ambi_weight 1 1 0.3904;
+#X text 299 424 ambisonic-order-group;
+#X text 89 452 -90 <= delta <= +90;
+#X text 89 464 -180 <= phi <= +180;
+#X text 415 439 or for bluring a signal-source-direction;
+#X text 31 506 order of ambisonic-channels in 2d-case: W X1 Y1 X2 Y2
+X3 Y3;
+#X text 391 506 X4 Y4 X5 Y5 ....;
+#X text 167 520 W := 1 \, X-term ... cos(i*phi) \, Y-term ... sin(i*phi)
+;
+#X text 30 560 order of ambisonic-channels in 3d-case: W Z1X1 Z1Y1
+Z1;
+#X text 358 560 Z2X2 Z2Y2 Z2X1 Z2Y1 Z2 Z3X3 Z3Y3 Z3X2 Z3Y2 Z3X1 Z3Y1
+Z3 ...;
+#X text 166 574 W := 1 \, X-term ... cos(i*phi) \, Y-term ... sin(i*phi)
+\,;
+#X text 489 574 Z-term ... cos(j*delta)*sin(k*delta);
+#X text 33 318 input: <float> phi [degree] .. 2-dimensional;
+#X text 33 331 input: <list> delta + phi [degree] .. 3-dimensional
+;
+#X text 33 356 input: <row> index + phi [degree] .. 2-dimensional;
+#X text 34 368 input: <row> index + delta + phi [degree] .. 3-dimensional
+;
+#X text 31 395 input: <col> index + phi [degree .. 2-dimensional;
+#X text 31 407 input: <col> index + delta + phi [degree] .. 3-dimensional
+;
+#X text 31 424 input: <ambi_weight> one mul-factor for each;
+#X text 267 492 |0| 1 | 2 | 3 | 4 | 5 |;
+#X text 687 549 |;
+#X text 263 547 |0| 1 | 2 | 3;
+#X floatatom 226 142 5 -180 180 0 - - -;
+#X floatatom 177 143 5 -90 90 0 - - -;
+#X text 174 124 delta;
+#X text 228 123 phi;
+#X floatatom 327 139 5 -180 180 0 - - -;
+#X floatatom 278 140 5 -90 90 0 - - -;
+#X text 275 121 delta;
+#X text 329 120 phi;
+#X floatatom 370 65 5 -180 180 0 - - -;
+#X text 372 46 phi;
+#X floatatom 425 79 5 -180 180 0 - - -;
+#X text 427 60 phi;
+#X floatatom 461 160 5 -180 180 0 - - -;
+#X text 463 141 phi;
+#X text 491 272 (1 .. 5 for 3 dimensional use);
+#X msg 184 218 row 4 \$1 \$2;
+#X text 112 12 calculates a row or column of a ambisonic-encoder-matrix
+;
+#X text 82 849 "float"-message: <float> azimuth-angle phi [degree]
+-> two-dimensional ambisonic-system -> output a <list> of (2*n_ao +
+1) <float> elements;
+#X text 478 850 "list"-message: 1.item <float> elevation-angle delta
+[degree] \, 2.item <float> azimuth-angle phi [degree] -> three-dimensional
+ambisonic-system -> output a <list> of (n_ao + 1)^2 <float> elements
+;
+#X text 87 914 "row"-message: <float> row-index of ambisonic-encoder-matrix
+\, <float> azimuth-angle phi [degree] -> two-dimensional ambisonic-system
+-> output a "row"-message + <float> row-index + (2*n_ao + 1) <float>
+elements;
+#X text 480 919 "row"-message: 1.item <float> elevation-angle delta
+[degree] \, 2.item <float> azimuth-angle phi [degree] -> three-dimensional
+ambisonic-system -> output a <list> of (n_ao + 1)^2 <float> elements
+;
+#X text 105 441 1 <= index <= nr_sources;
+#N canvas 0 0 860 478 3D-5.Order-example 0;
+#X obj 78 97 pack 0 0;
+#X floatatom 78 55 5 -90 90 0 - - -;
+#X floatatom 121 56 5 -180 180 0 - - -;
+#X text 63 24 delta;
+#X text 44 38 -90 .. +90;
+#X text 147 26 phi;
+#X text 120 40 -180 .. +180;
+#X obj 96 76 t b f;
+#X obj 97 268 vsl 8 101 -1 1 0 0 empty empty empty 0 -8 0 8 -225280
+-1109 -1 9439 1;
+#X obj 107 268 vsl 8 101 -1 1 0 0 empty empty empty 0 -8 0 8 -225280
+-1109 -1 6442 1;
+#X obj 117 268 vsl 8 101 -1 1 0 0 empty empty empty 0 -8 0 8 -225280
+-1109 -1 3208 1;
+#X obj 127 268 vsl 8 101 -1 1 0 0 empty empty empty 0 -8 0 8 -225280
+-1109 -1 5000 1;
+#X obj 137 268 vsl 8 101 -1 1 0 0 empty empty empty 0 -8 0 8 -225280
+-1109 -1 5000 1;
+#X obj 147 268 vsl 8 101 -1 1 0 0 empty empty empty 0 -8 0 8 -225280
+-1109 -1 5000 1;
+#X obj 157 268 vsl 8 101 -1 1 0 0 empty empty empty 0 -8 0 8 -225280
+-1109 -1 5000 1;
+#X obj 167 268 vsl 8 101 -1 1 0 0 empty empty empty 0 -8 0 8 -225280
+-1109 -1 5000 1;
+#X obj 177 268 vsl 8 101 -1 1 0 0 empty empty empty 0 -8 0 8 -225280
+-1109 -1 5000 1;
+#X obj 187 268 vsl 8 101 -1 1 0 0 empty empty empty 0 -8 0 8 -225280
+-1109 -1 5000 1;
+#X obj 197 268 vsl 8 101 -1 1 0 0 empty empty empty 0 -8 0 8 -225280
+-1109 -1 5000 1;
+#X obj 207 268 vsl 8 101 -1 1 0 0 empty empty empty 0 -8 0 8 -225280
+-1109 -1 5000 1;
+#X obj 217 268 vsl 8 101 -1 1 0 0 empty empty empty 0 -8 0 8 -225280
+-1109 -1 5000 1;
+#X obj 227 268 vsl 8 101 -1 1 0 0 empty empty empty 0 -8 0 8 -225280
+-1109 -1 5000 1;
+#X obj 237 268 vsl 8 101 -1 1 0 0 empty empty empty 0 -8 0 8 -225280
+-1109 -1 5000 1;
+#X obj 247 268 vsl 8 101 -1 1 0 0 empty empty empty 0 -8 0 8 -225280
+-1109 -1 5000 1;
+#X obj 257 268 vsl 8 101 -1 1 0 0 empty empty empty 0 -8 0 8 -225280
+-1109 -1 5000 1;
+#X obj 267 268 vsl 8 101 -1 1 0 0 empty empty empty 0 -8 0 8 -225280
+-1109 -1 5000 1;
+#X obj 277 268 vsl 8 101 -1 1 0 0 empty empty empty 0 -8 0 8 -225280
+-1109 -1 5000 1;
+#X obj 287 268 vsl 8 101 -1 1 0 0 empty empty empty 0 -8 0 8 -225280
+-1109 -1 5000 1;
+#X obj 297 268 vsl 8 101 -1 1 0 0 empty empty empty 0 -8 0 8 -225280
+-1109 -1 5000 1;
+#X obj 307 268 vsl 8 101 -1 1 0 0 empty empty empty 0 -8 0 8 -225280
+-1109 -1 5000 1;
+#X obj 317 268 vsl 8 101 -1 1 0 0 empty empty empty 0 -8 0 8 -225280
+-1109 -1 5000 1;
+#X obj 327 268 vsl 8 101 -1 1 0 0 empty empty empty 0 -8 0 8 -225280
+-1109 -1 5000 1;
+#X obj 87 268 vsl 8 101 -1 1 0 0 empty empty empty 0 -8 0 8 -225280
+-1109 -1 10000 1;
+#X obj 422 89 ambi_encode 4;
+#X floatatom 422 68 5 -180 180 0 - - -;
+#X text 434 31 phi;
+#X text 407 45 -180 .. +180;
+#X obj 142 202 print 3d;
+#X obj 422 132 print 2d;
+#X obj 78 201 route row;
+#X obj 142 180 round_zero 1e-006;
+#X floatatom 42 244 5 0 0 0 - - -;
+#X obj 78 124 pp row 7;
+#X text 13 254 row-index;
+#X obj 422 111 round_zero 1e-006;
+#X text 448 260 +1;
+#X text 448 360 -1;
+#X text 451 311 0;
+#X obj 78 151 ambi_encode 5;
+#X obj 78 222 unpack 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0;
+#X obj 337 268 vsl 8 101 -1 1 0 0 empty empty empty 0 -8 0 8 -225280
+-1109 -1 5000 1;
+#X obj 347 268 vsl 8 101 -1 1 0 0 empty empty empty 0 -8 0 8 -225280
+-1109 -1 5000 1;
+#X obj 357 268 vsl 8 101 -1 1 0 0 empty empty empty 0 -8 0 8 -225280
+-1109 -1 5000 1;
+#X obj 367 268 vsl 8 101 -1 1 0 0 empty empty empty 0 -8 0 8 -225280
+-1109 -1 5000 1;
+#X obj 377 268 vsl 8 101 -1 1 0 0 empty empty empty 0 -8 0 8 -225280
+-1109 -1 5000 1;
+#X obj 387 268 vsl 8 101 -1 1 0 0 empty empty empty 0 -8 0 8 -225280
+-1109 -1 5000 1;
+#X obj 397 268 vsl 8 101 -1 1 0 0 empty empty empty 0 -8 0 8 -225280
+-1109 -1 5000 1;
+#X obj 407 268 vsl 8 101 -1 1 0 0 empty empty empty 0 -8 0 8 -225280
+-1109 -1 5000 1;
+#X obj 417 268 vsl 8 101 -1 1 0 0 empty empty empty 0 -8 0 8 -225280
+-1109 -1 5000 1;
+#X obj 427 268 vsl 8 101 -1 1 0 0 empty empty empty 0 -8 0 8 -225280
+-1109 -1 5000 1;
+#X obj 437 268 vsl 8 101 -1 1 0 0 empty empty empty 0 -8 0 8 -225280
+-1109 -1 5000 1;
+#X msg 260 57 ambi_weight 1 1 1 1 1 1;
+#X msg 260 95 ambi_weight 1 1 1 1 0 0;
+#X msg 260 114 ambi_weight 1 1 1 0 0 0;
+#X msg 260 134 ambi_weight 1 1 0 0 0 0;
+#X msg 260 154 ambi_weight 1 0 0 0 0 0;
+#X msg 260 76 ambi_weight 1 1 1 1 1 0;
+#X connect 0 0 42 0;
+#X connect 1 0 0 0;
+#X connect 2 0 7 0;
+#X connect 7 0 0 0;
+#X connect 7 1 0 1;
+#X connect 33 0 44 0;
+#X connect 34 0 33 0;
+#X connect 39 0 49 0;
+#X connect 40 0 37 0;
+#X connect 42 0 48 0;
+#X connect 44 0 38 0;
+#X connect 48 0 39 0;
+#X connect 48 0 40 0;
+#X connect 49 0 41 0;
+#X connect 49 1 32 0;
+#X connect 49 2 8 0;
+#X connect 49 3 9 0;
+#X connect 49 4 10 0;
+#X connect 49 5 11 0;
+#X connect 49 6 12 0;
+#X connect 49 7 13 0;
+#X connect 49 8 14 0;
+#X connect 49 9 15 0;
+#X connect 49 10 16 0;
+#X connect 49 11 17 0;
+#X connect 49 12 18 0;
+#X connect 49 13 19 0;
+#X connect 49 14 20 0;
+#X connect 49 15 21 0;
+#X connect 49 16 22 0;
+#X connect 49 17 23 0;
+#X connect 49 18 24 0;
+#X connect 49 19 25 0;
+#X connect 49 20 26 0;
+#X connect 49 21 27 0;
+#X connect 49 22 28 0;
+#X connect 49 23 29 0;
+#X connect 49 24 30 0;
+#X connect 49 25 31 0;
+#X connect 49 26 50 0;
+#X connect 49 27 51 0;
+#X connect 49 28 52 0;
+#X connect 49 29 53 0;
+#X connect 49 30 54 0;
+#X connect 49 31 55 0;
+#X connect 49 32 56 0;
+#X connect 49 33 57 0;
+#X connect 49 34 58 0;
+#X connect 49 35 59 0;
+#X connect 49 36 60 0;
+#X connect 61 0 48 0;
+#X connect 62 0 48 0;
+#X connect 63 0 48 0;
+#X connect 64 0 48 0;
+#X connect 65 0 48 0;
+#X connect 66 0 48 0;
+#X restore 538 61 pd 3D-5.Order-example;
+#X connect 0 0 9 0;
+#X connect 4 0 0 0;
+#X connect 5 0 0 0;
+#X connect 6 0 0 0;
+#X connect 7 0 6 0;
+#X connect 8 0 7 0;
+#X connect 8 1 7 1;
+#X connect 9 0 1 0;
+#X connect 10 0 65 0;
+#X connect 11 0 10 0;
+#X connect 11 1 10 1;
+#X connect 12 0 15 0;
+#X connect 13 0 14 0;
+#X connect 14 0 0 0;
+#X connect 15 0 14 0;
+#X connect 15 1 14 1;
+#X connect 27 0 0 0;
+#X connect 28 0 0 0;
+#X connect 50 0 11 0;
+#X connect 51 0 10 0;
+#X connect 54 0 8 0;
+#X connect 55 0 7 0;
+#X connect 58 0 0 0;
+#X connect 60 0 5 0;
+#X connect 62 0 4 0;
+#X connect 65 0 0 0;
diff --git a/help/help-ambi_rot.pd b/help/help-ambi_rot.pd
new file mode 100644
index 0000000..1d3baae
--- /dev/null
+++ b/help/help-ambi_rot.pd
@@ -0,0 +1,80 @@
+#N canvas 44 25 730 500 10;
+#X text 230 40 phi ... azimut \, positiv direction from nose to left
+ear;
+#X text 228 18 delta ... elevation \, positiv direction from nose to
+top of the head;
+#X floatatom 52 76 6 -180 180 0 - - -;
+#X obj 29 76 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X floatatom 128 76 6 -180 180 0 - - -;
+#X text 129 59 rho_y;
+#X text 54 59 rho_z;
+#X floatatom 195 76 6 -180 180 0 - - -;
+#X text 197 59 rho_x;
+#X obj 127 149 pack 0 0 0;
+#X obj 195 120 t b f;
+#X obj 128 120 t b f;
+#X obj 52 93 deg2rad;
+#X obj 128 94 deg2rad;
+#X obj 195 95 deg2rad;
+#X text 241 6 AMBISONIC Encoder 4.Order 3-Dimensional;
+#X text 254 73 umkehrung der matrizen multiplikation: funktioniert
+nicht;
+#X obj 63 393 print r1;
+#X obj 174 390 print r2;
+#X obj 292 389 print r3;
+#X obj 407 387 print r4;
+#X obj 63 342 mtx_mul;
+#X obj 389 275 pack 0 0 0;
+#X obj 389 214 unpack 0 0 0;
+#X obj 389 237 * -1;
+#X obj 126 172 t l l;
+#X obj 174 341 mtx_mul;
+#X obj 292 339 mtx_mul;
+#X obj 407 338 mtx_mul;
+#X obj 422 238 * -1;
+#X obj 455 237 * -1;
+#X obj 389 300 ambi_rot 4;
+#X obj 63 244 ambi_rot 4;
+#X text 10 8 ambi_rot;
+#X obj 407 362 round_zero 0.0001;
+#X obj 292 365 round_zero 0.0001;
+#X obj 174 364 round_zero 0.0001;
+#X obj 63 365 round_zero 0.0001;
+#X connect 2 0 12 0;
+#X connect 3 0 2 0;
+#X connect 4 0 13 0;
+#X connect 7 0 14 0;
+#X connect 9 0 25 0;
+#X connect 10 0 9 0;
+#X connect 10 1 9 2;
+#X connect 11 0 9 0;
+#X connect 11 1 9 1;
+#X connect 12 0 9 0;
+#X connect 13 0 11 0;
+#X connect 14 0 10 0;
+#X connect 21 0 37 0;
+#X connect 22 0 31 0;
+#X connect 23 0 24 0;
+#X connect 23 1 29 0;
+#X connect 23 2 30 0;
+#X connect 24 0 22 0;
+#X connect 25 0 32 0;
+#X connect 25 1 23 0;
+#X connect 26 0 36 0;
+#X connect 27 0 35 0;
+#X connect 28 0 34 0;
+#X connect 29 0 22 1;
+#X connect 30 0 22 2;
+#X connect 31 0 21 1;
+#X connect 31 1 26 1;
+#X connect 31 2 27 1;
+#X connect 31 3 28 1;
+#X connect 32 0 21 0;
+#X connect 32 1 26 0;
+#X connect 32 2 27 0;
+#X connect 32 3 28 0;
+#X connect 34 0 20 0;
+#X connect 35 0 19 0;
+#X connect 36 0 18 0;
+#X connect 37 0 17 0;
diff --git a/help/test-ambi_rot.pd b/help/test-ambi_rot.pd
new file mode 100644
index 0000000..e859374
--- /dev/null
+++ b/help/test-ambi_rot.pd
@@ -0,0 +1,80 @@
+#N canvas 44 25 726 496 10;
+#X text 230 40 phi ... azimut \, positiv direction from nose to left
+ear;
+#X text 228 18 delta ... elevation \, positiv direction from nose to
+top of the head;
+#X floatatom 52 76 6 -180 180 0 - - -;
+#X obj 29 76 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X floatatom 128 76 6 -180 180 0 - - -;
+#X text 129 59 rho_y;
+#X text 54 59 rho_z;
+#X floatatom 195 76 6 -180 180 0 - - -;
+#X text 197 59 rho_x;
+#X obj 127 149 pack 0 0 0;
+#X obj 195 120 t b f;
+#X obj 128 120 t b f;
+#X obj 52 93 deg2rad;
+#X obj 128 94 deg2rad;
+#X obj 195 95 deg2rad;
+#X text 241 6 AMBISONIC Encoder 4.Order 3-Dimensional;
+#X text 254 73 umkehrung der matrizen multiplikation: funktioniert
+nicht;
+#X obj 63 393 print r1;
+#X obj 174 390 print r2;
+#X obj 292 389 print r3;
+#X obj 407 387 print r4;
+#X text 10 8 test-ambi_rot.pd;
+#X obj 63 342 mtx_mul;
+#X obj 389 275 pack 0 0 0;
+#X obj 389 214 unpack 0 0 0;
+#X obj 389 237 * -1;
+#X obj 126 172 t l l;
+#X obj 174 341 mtx_mul;
+#X obj 292 339 mtx_mul;
+#X obj 407 338 mtx_mul;
+#X obj 422 238 * -1;
+#X obj 455 237 * -1;
+#X obj 389 300 ambi_rot 4;
+#X obj 63 244 ambi_rot 4;
+#X obj 63 365 round_zero 1e-007;
+#X obj 174 364 round_zero 1e-007;
+#X obj 292 365 round_zero 1e-007;
+#X obj 407 362 round_zero 1e-007;
+#X connect 2 0 12 0;
+#X connect 3 0 2 0;
+#X connect 4 0 13 0;
+#X connect 7 0 14 0;
+#X connect 9 0 26 0;
+#X connect 10 0 9 0;
+#X connect 10 1 9 2;
+#X connect 11 0 9 0;
+#X connect 11 1 9 1;
+#X connect 12 0 9 0;
+#X connect 13 0 11 0;
+#X connect 14 0 10 0;
+#X connect 22 0 34 0;
+#X connect 23 0 32 0;
+#X connect 24 0 25 0;
+#X connect 24 1 30 0;
+#X connect 24 2 31 0;
+#X connect 25 0 23 0;
+#X connect 26 0 33 0;
+#X connect 26 1 24 0;
+#X connect 27 0 35 0;
+#X connect 28 0 36 0;
+#X connect 29 0 37 0;
+#X connect 30 0 23 1;
+#X connect 31 0 23 2;
+#X connect 32 0 22 1;
+#X connect 32 1 27 1;
+#X connect 32 2 28 1;
+#X connect 32 3 29 1;
+#X connect 33 0 22 0;
+#X connect 33 1 27 0;
+#X connect 33 2 28 0;
+#X connect 33 3 29 0;
+#X connect 34 0 17 0;
+#X connect 35 0 18 0;
+#X connect 36 0 19 0;
+#X connect 37 0 20 0;
diff --git a/src/Make.config.in b/src/Make.config.in
new file mode 100644
index 0000000..8bba163
--- /dev/null
+++ b/src/Make.config.in
@@ -0,0 +1,28 @@
+LIBNAME =iem_bin_ambi
+
+PREFIX =@prefix@@PDLIBDIR@
+
+INSTALL_BIN=$(PREFIX)/extra
+INSTALL_DOC=$(PREFIX)/@REFERENCEPATH@$(LIBNAME)
+
+EXT = @EXT@
+DEFS = @DFLAGS@
+IFLAGS = -I. @INCLUDES@
+
+CC = @CC@
+LD = @LD@
+STRIP = @STRIP@
+STRIPFLAGS= @STRIPFLAGS@
+
+AFLAGS =
+LFLAGS = @LFLAGS@
+WFLAGS =
+
+TARNAME = $(LIBNAME)-@IEMBINAMBI_VERSION@.tgz
+
+# ICCFLAGS=-march=pentiumiii -axK
+Z_CFLAGS = $(IFLAGS) $(DEFS) -DPD $(WFLAGS) @CFLAGS@ $(CFLAGS)
+
+MAKEDEP_FLAGS = @MAKEDEP_FLAGS@
+
+LIBS = @LIBS@
diff --git a/src/Makefile b/src/Makefile
new file mode 100644
index 0000000..8e18398
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,88 @@
+default: all
+
+.PHONEY: default all everything dist \
+ clean realclean distclean \
+ install install-bin install-doc install-abs
+
+SOURCES=$(sort $(filter %.c, $(wildcard *.c)))
+
+ifeq (,$(findstring clean, $(MAKECMDGOALS)))
+Make.config: Make.config.in configure
+ ./configure
+endif
+
+iem_bin_ambi_sources.c iem_bin_ambi_sources.h:
+ ./makesource.sh
+
+configure: configure.ac
+ autoconf
+
+## uaehh, here comes some magic
+## 1st we don't want depend and config-makefiles to be included on "clean"-targets
+
+ifeq (,$(findstring clean, $(MAKECMDGOALS)))
+-include $(SOURCES:.c=.d)
+endif
+
+-include Make.config
+
+## 2nd only generate depend-files when we have Make.config included
+## and thus MAKEDEP_FLAGS defined
+ifdef MAKEDEP_FLAGS
+## dependencies: as proposed by the GNU-make documentation
+## see http://www.gnu.org/software/make/manual/html_node/make_47.html#SEC51
+%.d: %.c
+ @set -e; rm -f $@; \
+ $(CPP) $(MAKEDEP_FLAGS) $(Z_CFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+endif
+
+.SUFFIXES: .$(EXT)
+
+TARGETS = $(SOURCES:.c=.o)
+
+
+all: $(LIBNAME)
+ cp $(LIBNAME).$(EXT) ..
+
+$(LIBNAME): $(TARGETS) iem_bin_ambi_sources.c iem_bin_ambi_sources.h
+ $(LD) $(LFLAGS) -o $(LIBNAME).$(EXT) *.o $(LIBS)
+ $(STRIP) $(STRIPFLAGS) $(LIBNAME).$(EXT)
+
+$(TARGETS): %.o : %.c
+ $(CC) $(Z_CFLAGS) -c -o $@ $*.c
+
+
+clean:
+ -rm -f *.$(EXT) *.o
+
+realclean: clean
+ -rm -f *~ _* config.*
+ -rm -f *.d *.d.*
+
+distclean: realclean
+ -rm -f Make.config ../*.$(EXT)
+ -rm -f *.exp *.lib *.ncb \
+ *.opt *.plg
+ -rm -rf autom4te.cache/
+
+install: install-bin install-doc install-abs
+
+install-bin:
+ -install -d $(INSTALL_BIN)
+ -install -m 644 $(LIBNAME).$(EXT) $(INSTALL_BIN)
+
+install-doc:
+ -install -d $(INSTALL_DOC)
+ -install -m 644 ../examples/*.pd $(INSTALL_DOC)
+
+install-abs:
+ -install -d $(INSTALL_BIN)
+ -install -m 644 ../abs/*.pd $(INSTALL_BIN)
+
+dist: all realclean
+ (cd ../..;tar czvf $(TARNAME) $(LIBNAME))
+
+everything: clean all install distclean
+
diff --git a/src/ambi_decode.c b/src/ambi_decode.c
new file mode 100644
index 0000000..db030cf
--- /dev/null
+++ b/src/ambi_decode.c
@@ -0,0 +1,724 @@
+/* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution.
+
+iem_ambi written by Thomas Musil, Copyright (c) IEM KUG Graz Austria 2000 - 2005 */
+
+#ifdef NT
+#pragma warning( disable : 4244 )
+#pragma warning( disable : 4305 )
+#endif
+
+
+#include "m_pd.h"
+#include "iemlib.h"
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+
+
+/* -------------------------- ambi_decode ------------------------------ */
+/*
+ ** berechnet ein reduziertes Ambisonic-Decoder-Set in die HRTF-Spektren **
+ ** Inputs: ls + Liste von 3 floats: Index [1 .. 25] + Elevation [-90 .. +90 degree] + Azimut [0 .. 360 degree] **
+ ** Inputs: calc_inv **
+ ** Inputs: load_HRIR + float index1..25 **
+ ** Outputs: List of 2 symbols: left-HRIR-File-name + HRIR-table-name **
+ ** Inputs: calc_reduced **
+ ** "output" ... writes the HRTF into tables **
+ ** **
+ ** **
+ ** setzt voraus , dass die HRIR-tabele-names von LS1_L_HRIR .. LS25_L_HRIR heissen und existieren **
+ ** setzt voraus , dass die HRTF-tabele-names von LS1_HRTF_re .. LS25_HRTF_re heissen und existieren **
+ ** setzt voraus , dass die HRTF-tabele-names von LS1_HRTF_im .. LS25_HRTF_im heissen und existieren **
+ */
+
+typedef struct _ambi_decode
+{
+ t_object x_obj;
+ t_atom *x_at;
+ double *x_inv_work1;
+ double *x_inv_work2;
+ double *x_inv_buf2;
+ double *x_transp;
+ double *x_ls_encode;
+ double *x_prod;
+ double *x_ambi_channel_weight;
+ double x_sing_range;
+ int x_n_ambi;
+ int x_n_order;
+ int x_n_ls;
+ int x_n_phls;
+ int x_n_dim;
+ t_symbol *x_s_matrix;
+ double x_sqrt3;
+ double x_sqrt10_4;
+ double x_sqrt15_2;
+ double x_sqrt6_4;
+ double x_sqrt35_8;
+ double x_sqrt70_4;
+ double x_sqrt5_2;
+ double x_sqrt126_16;
+ double x_sqrt315_8;
+ double x_sqrt105_4;
+ double x_pi_over_180;
+} t_ambi_decode;
+
+static t_class *ambi_decode_class;
+
+static void ambi_decode_copy_row2buf(t_ambi_decode *x, int row)
+{
+ int n_ambi2 = 2*x->x_n_ambi;
+ int i;
+ double *dw=x->x_inv_work2;
+ double *db=x->x_inv_buf2;
+
+ dw += row*n_ambi2;
+ for(i=0; i<n_ambi2; i++)
+ *db++ = *dw++;
+}
+
+static void ambi_decode_copy_buf2row(t_ambi_decode *x, int row)
+{
+ int n_ambi2 = 2*x->x_n_ambi;
+ int i;
+ double *dw=x->x_inv_work2;
+ double *db=x->x_inv_buf2;
+
+ dw += row*n_ambi2;
+ for(i=0; i<n_ambi2; i++)
+ *dw++ = *db++;
+}
+
+static void ambi_decode_copy_row2row(t_ambi_decode *x, int src_row, int dst_row)
+{
+ int n_ambi2 = 2*x->x_n_ambi;
+ int i;
+ double *dw_src=x->x_inv_work2;
+ double *dw_dst=x->x_inv_work2;
+
+ dw_src += src_row*n_ambi2;
+ dw_dst += dst_row*n_ambi2;
+ for(i=0; i<n_ambi2; i++)
+ *dw_dst++ = *dw_src++;
+}
+
+static void ambi_decode_xch_rows(t_ambi_decode *x, int row1, int row2)
+{
+ ambi_decode_copy_row2buf(x, row1);
+ ambi_decode_copy_row2row(x, row2, row1);
+ ambi_decode_copy_buf2row(x, row2);
+}
+
+static void ambi_decode_mul_row(t_ambi_decode *x, int row, double mul)
+{
+ int n_ambi2 = 2*x->x_n_ambi;
+ int i;
+ double *dw=x->x_inv_work2;
+
+ dw += row*n_ambi2;
+ for(i=0; i<n_ambi2; i++)
+ {
+ (*dw) *= mul;
+ dw++;
+ }
+}
+
+static void ambi_decode_mul_buf_and_add2row(t_ambi_decode *x, int row, double mul)
+{
+ int n_ambi2 = 2*x->x_n_ambi;
+ int i;
+ double *dw=x->x_inv_work2;
+ double *db=x->x_inv_buf2;
+
+ dw += row*n_ambi2;
+ for(i=0; i<n_ambi2; i++)
+ {
+ *dw += (*db)*mul;
+ dw++;
+ db++;
+ }
+}
+
+static int ambi_decode_eval_which_element_of_col_not_zero(t_ambi_decode *x, int col, int start_row)
+{
+ int n_ambi = x->x_n_ambi;
+ int n_ambi2 = 2*n_ambi;
+ int i, j;
+ double *dw=x->x_inv_work2;
+ double singrange=x->x_sing_range;
+ int ret=-1;
+
+ dw += start_row*n_ambi2 + col;
+ j = 0;
+ for(i=start_row; i<n_ambi; i++)
+ {
+ if((*dw > singrange) || (*dw < -singrange))
+ {
+ ret = i;
+ i = n_ambi+1;
+ }
+ dw += n_ambi2;
+ }
+ return(ret);
+}
+
+static void ambi_decode_mul1(t_ambi_decode *x)
+{
+ double *vec1, *beg1=x->x_ls_encode;
+ double *vec2, *beg2=x->x_ls_encode;
+ double *inv=x->x_inv_work1;
+ double sum;
+ int n_ls=x->x_n_ls+x->x_n_phls;
+ int n_ambi=x->x_n_ambi;
+ int i, j, k;
+
+ for(k=0; k<n_ambi; k++)
+ {
+ beg2=x->x_ls_encode;
+ for(j=0; j<n_ambi; j++)
+ {
+ sum = 0.0;
+ vec1 = beg1;
+ vec2 = beg2;
+ for(i=0; i<n_ls; i++)
+ {
+ sum += *vec1++ * *vec2++;
+ }
+ beg2 += n_ls;
+ *inv++ = sum;
+ }
+ beg1 += n_ls;
+ }
+}
+
+static void ambi_decode_mul2(t_ambi_decode *x)
+{
+ int n_ls=x->x_n_ls+x->x_n_phls;
+ int n_ambi=x->x_n_ambi;
+ int n_ambi2=2*n_ambi;
+ int i, j, k;
+ double *vec1, *beg1=x->x_transp;
+ double *vec2, *beg2=x->x_inv_work2+n_ambi;
+ double *vec3=x->x_prod;
+ double *acw_vec=x->x_ambi_channel_weight;
+ double sum;
+
+ for(k=0; k<n_ls; k++)
+ {
+ beg2=x->x_inv_work2+n_ambi;
+ for(j=0; j<n_ambi; j++)
+ {
+ sum = 0.0;
+ vec1 = beg1;
+ vec2 = beg2;
+ for(i=0; i<n_ambi; i++)
+ {
+ sum += *vec1++ * *vec2;
+ vec2 += n_ambi2;
+ }
+ beg2++;
+ *vec3++ = sum * acw_vec[j];
+ }
+ beg1 += n_ambi;
+ }
+}
+
+static void ambi_decode_transp_back(t_ambi_decode *x)
+{
+ double *vec, *transp=x->x_transp;
+ double *straight=x->x_ls_encode;
+ int n_ls=x->x_n_ls+x->x_n_phls;
+ int n_ambi=x->x_n_ambi;
+ int i, j;
+
+ for(j=0; j<n_ambi; j++)
+ {
+ vec = transp;
+ for(i=0; i<n_ls; i++)
+ {
+ *straight++ = *vec;
+ vec += n_ambi;
+ }
+ transp++;
+ }
+}
+
+static void ambi_decode_inverse(t_ambi_decode *x)
+{
+ int n_ambi = x->x_n_ambi;
+ int n_ambi2 = 2*n_ambi;
+ int i, j, nz;
+ int r,c;
+ double *src=x->x_inv_work1;
+ double *db=x->x_inv_work2;
+ double rcp, *dv;
+
+ dv = db;
+ for(i=0; i<n_ambi; i++) /* init */
+ {
+ for(j=0; j<n_ambi; j++)
+ {
+ *dv++ = *src++;
+ }
+ for(j=0; j<n_ambi; j++)
+ {
+ if(j == i)
+ *dv++ = 1.0;
+ else
+ *dv++ = 0.0;
+ }
+ }
+
+ /* make 1 in main-diagonale, and 0 below */
+ for(i=0; i<n_ambi; i++)
+ {
+ nz = ambi_decode_eval_which_element_of_col_not_zero(x, i, i);
+ if(nz < 0)
+ {
+ post("ambi_decode ERROR: matrix not regular !!!!");
+ return;
+ }
+ else
+ {
+ if(nz != i)
+ ambi_decode_xch_rows(x, i, nz);
+ dv = db + i*n_ambi2 + i;
+ rcp = 1.0 /(*dv);
+ ambi_decode_mul_row(x, i, rcp);
+ ambi_decode_copy_row2buf(x, i);
+ for(j=i+1; j<n_ambi; j++)
+ {
+ dv += n_ambi2;
+ rcp = -(*dv);
+ ambi_decode_mul_buf_and_add2row(x, j, rcp);
+ }
+ }
+ }
+
+ /* make 0 above the main diagonale */
+ for(i=n_ambi-1; i>=0; i--)
+ {
+ dv = db + i*n_ambi2 + i;
+ ambi_decode_copy_row2buf(x, i);
+ for(j=i-1; j>=0; j--)
+ {
+ dv -= n_ambi2;
+ rcp = -(*dv);
+ ambi_decode_mul_buf_and_add2row(x, j, rcp);
+ }
+ }
+
+ post("matrix_inverse regular");
+}
+
+static void ambi_decode_pinv(t_ambi_decode *x)
+{
+ t_atom *at=x->x_at;
+ int i, n=x->x_n_ls*x->x_n_ambi;
+ double *dv=x->x_prod;
+
+ ambi_decode_transp_back(x);
+ ambi_decode_mul1(x);
+ ambi_decode_inverse(x);
+ ambi_decode_mul2(x);
+ at += 2;
+ for(i=0; i<n; i++)
+ {
+ SETFLOAT(at, (float)(*dv));
+ dv++;
+ at++;
+ }
+ outlet_anything(x->x_obj.ob_outlet, x->x_s_matrix, n+2, x->x_at);
+}
+
+static void ambi_decode_encode_ls_2d(t_ambi_decode *x, int argc, t_atom *argv, int ls0_ph1)
+{
+ double phi;
+ double *dw = x->x_transp;
+ int index;
+ int n_ls=x->x_n_ls;
+ int n_phls=x->x_n_phls;
+ int order=x->x_n_order;
+
+ if(argc < 2)
+ {
+ post("ambi_decode ERROR: ls-input needs 1 index and 1 angle: ls_index + phi [degree]");
+ return;
+ }
+ index = (int)atom_getint(argv++) - 1;
+ phi = (double)atom_getfloat(argv);
+
+ if(index < 0)
+ index = 0;
+ if(ls0_ph1)
+ {
+ if(n_phls)
+ {
+ if(index >= n_phls)
+ index = n_phls - 1;
+ index += n_ls;
+ }
+ else
+ return;
+ }
+ else
+ {
+ if(index >= n_ls)
+ index = n_ls - 1;
+ }
+
+ phi *= x->x_pi_over_180;
+
+ dw += index * x->x_n_ambi;
+
+ *dw++ = 1.0;
+ *dw++ = cos(phi);
+ *dw++ = sin(phi);
+
+ if(order >= 2)
+ {
+ *dw++ = cos(2.0*phi);
+ *dw++ = sin(2.0*phi);
+
+ if(order >= 3)
+ {
+ *dw++ = cos(3.0*phi);
+ *dw++ = sin(3.0*phi);
+ if(order >= 4)
+ {
+ *dw++ = cos(4.0*phi);
+ *dw++ = sin(4.0*phi);
+
+ if(order >= 5)
+ {
+ *dw++ = cos(5.0*phi);
+ *dw++ = sin(5.0*phi);
+
+ if(order >= 6)
+ {
+ *dw++ = cos(6.0*phi);
+ *dw++ = sin(6.0*phi);
+
+ if(order >= 7)
+ {
+ *dw++ = cos(7.0*phi);
+ *dw++ = sin(7.0*phi);
+
+ if(order >= 8)
+ {
+ *dw++ = cos(8.0*phi);
+ *dw++ = sin(8.0*phi);
+
+ if(order >= 9)
+ {
+ *dw++ = cos(9.0*phi);
+ *dw++ = sin(9.0*phi);
+
+ if(order >= 10)
+ {
+ *dw++ = cos(10.0*phi);
+ *dw++ = sin(10.0*phi);
+
+ if(order >= 11)
+ {
+ *dw++ = cos(11.0*phi);
+ *dw++ = sin(11.0*phi);
+
+ if(order >= 12)
+ {
+ *dw++ = cos(12.0*phi);
+ *dw++ = sin(12.0*phi);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+static void ambi_decode_encode_ls_3d(t_ambi_decode *x, int argc, t_atom *argv, int ls0_ph1)
+{
+ double delta, phi;
+ double cd, sd, cd2, cd3, sd2, csd, cp, sp, cp2, sp2, cp3, sp3, cp4, sp4;
+ double *dw = x->x_transp;
+ int index;
+ int n_ls=x->x_n_ls;
+ int n_phls=x->x_n_phls;
+ int order=x->x_n_order;
+
+ if(argc < 3)
+ {
+ post("ambi_decode ERROR: ls-input needs 1 index and 2 angles: ls index + delta [degree] + phi [degree]");
+ return;
+ }
+ index = (int)atom_getint(argv++) - 1;
+ delta = atom_getfloat(argv++);
+ phi = atom_getfloat(argv);
+
+ if(index < 0)
+ index = 0;
+ if(ls0_ph1)
+ {
+ if(n_phls)
+ {
+ if(index >= n_phls)
+ index = n_phls - 1;
+ index += n_ls;
+ }
+ else
+ return;
+ }
+ else
+ {
+ if(index >= n_ls)
+ index = n_ls - 1;
+ }
+
+ delta *= x->x_pi_over_180;
+ phi *= x->x_pi_over_180;
+
+ dw += index * x->x_n_ambi;
+
+ cd = cos(delta);
+ sd = sin(delta);
+ cp = cos(phi);
+ sp = sin(phi);
+
+
+ *dw++ = 1.0;
+ *dw++ = cd * cp;
+ *dw++ = cd * sp;
+ *dw++ = sd;
+
+ if(order >= 2)
+ {
+ cp2 = cos(2.0*phi);
+ sp2 = sin(2.0*phi);
+ cd2 = cd * cd;
+ sd2 = sd * sd;
+ csd = cd * sd;
+ *dw++ = 0.5 * x->x_sqrt3 * cd2 * cp2;
+ *dw++ = 0.5 * x->x_sqrt3 * cd2 * sp2;
+ *dw++ = x->x_sqrt3 * csd * cp;
+ *dw++ = x->x_sqrt3 * csd * sp;
+ *dw++ = 0.5 * (3.0 * sd2 - 1.0);
+
+ if(order >= 3)
+ {
+ cp3 = cos(3.0*phi);
+ sp3 = sin(3.0*phi);
+ cd3 = cd2 * cd;
+ *dw++ = x->x_sqrt10_4 * cd3 * cp3;
+ *dw++ = x->x_sqrt10_4 * cd3 * sp3;
+ *dw++ = x->x_sqrt15_2 * cd * csd * cp2;
+ *dw++ = x->x_sqrt15_2 * cd * csd * sp2;
+ *dw++ = x->x_sqrt6_4 * cd * (5.0 * sd2 - 1.0) * cp;
+ *dw++ = x->x_sqrt6_4 * cd * (5.0 * sd2 - 1.0) * sp;
+ *dw++ = 0.5 * sd * (5.0 * sd2 - 3.0);
+
+ if(order >= 4)
+ {
+ cp4 = cos(4.0*phi);
+ sp4 = sin(4.0*phi);
+ *dw++ = x->x_sqrt35_8 * cd2 * cd2 * cp4;
+ *dw++ = x->x_sqrt35_8 * cd2 * cd2 * sp4;
+ *dw++ = x->x_sqrt70_4 * cd2 * csd * cp3;
+ *dw++ = x->x_sqrt70_4 * cd2 * csd * sp3;
+ *dw++ = 0.5 * x->x_sqrt5_2 * cd2 * (7.0 * sd2 - 1.0) * cp2;
+ *dw++ = 0.5 * x->x_sqrt5_2 * cd2 * (7.0 * sd2 - 1.0) * sp2;
+ *dw++ = x->x_sqrt10_4 * csd * (7.0 * sd2 - 3.0) * cp;
+ *dw++ = x->x_sqrt10_4 * csd * (7.0 * sd2 - 3.0) * sp;
+ *dw++ = 0.125 * (sd2 * (35.0 * sd2 - 30.0) + 3.0);
+
+ if(order >= 5)
+ {
+ *dw++ = x->x_sqrt126_16 * cd3 * cd2 * cos(5.0*phi);
+ *dw++ = x->x_sqrt126_16 * cd3 * cd2 * sin(5.0*phi);
+ *dw++ = x->x_sqrt315_8 * cd3 * csd * cp4;
+ *dw++ = x->x_sqrt315_8 * cd3 * csd * sp4;
+ *dw++ = 0.25 * x->x_sqrt70_4 * cd3 * (9.0 * sd2 - 1.0) * cp3;
+ *dw++ = 0.25 * x->x_sqrt70_4 * cd3 * (9.0 * sd2 - 1.0) * sp3;
+ *dw++ = x->x_sqrt105_4 * cd * csd * (3.0 * sd2 - 1.0) * cp2;
+ *dw++ = x->x_sqrt105_4 * cd * csd * (3.0 * sd2 - 1.0) * sp2;
+ *dw++ = 0.25 * x->x_sqrt15_2 * cd * (sd2 * (21.0 * sd2 - 14.0) + 1.0) * cp;
+ *dw++ = 0.25 * x->x_sqrt15_2 * cd * (sd2 * (21.0 * sd2 - 14.0) + 1.0) * sp;
+ *dw = 0.125 * sd * (sd2 * (63.0 * sd2 - 70.0) + 15.0);
+ }
+ }
+ }
+ }
+}
+
+static void ambi_decode_ls(t_ambi_decode *x, t_symbol *s, int argc, t_atom *argv)
+{
+ if(x->x_n_dim == 2)
+ ambi_decode_encode_ls_2d(x, argc, argv, 0);
+ else
+ ambi_decode_encode_ls_3d(x, argc, argv, 0);
+}
+
+static void ambi_decode_phls(t_ambi_decode *x, t_symbol *s, int argc, t_atom *argv)
+{
+ if(x->x_n_dim == 2)
+ ambi_decode_encode_ls_2d(x, argc, argv, 1);
+ else
+ ambi_decode_encode_ls_3d(x, argc, argv, 1);
+}
+
+static void ambi_decode_ambi_weight(t_ambi_decode *x, t_symbol *s, int argc, t_atom *argv)
+{
+ if(argc > x->x_n_order)
+ {
+ int i, k=0, n=x->x_n_order;
+ double d;
+
+ x->x_ambi_channel_weight[k] = atom_getfloat(argv++);
+ k++;
+ if(x->x_n_dim == 2)
+ {
+ for(i=1; i<=n; i++)
+ {
+ d = atom_getfloat(argv++);
+ x->x_ambi_channel_weight[k] = d;
+ k++;
+ x->x_ambi_channel_weight[k] = d;
+ k++;
+ }
+ }
+ else
+ {
+ int j, m;
+
+ for(i=1; i<=n; i++)
+ {
+ d = atom_getfloat(argv++);
+ m = 2*i + 1;
+ for(j=0; j<m; j++)
+ {
+ x->x_ambi_channel_weight[k] = d;
+ k++;
+ }
+ }
+ }
+ }
+ else
+ post("ambi_decode-ERROR: ambi_weight needs %d float weights", x->x_n_order+1);
+}
+
+static void ambi_decode_sing_range(t_ambi_decode *x, t_floatarg f)
+{
+ if(f < 0.0f)
+ x->x_sing_range = -(double)f;
+ else
+ x->x_sing_range = (double)f;
+}
+
+static void ambi_decode_free(t_ambi_decode *x)
+{
+ freebytes(x->x_inv_work1, x->x_n_ambi * x->x_n_ambi * sizeof(double));
+ freebytes(x->x_inv_work2, 2 * x->x_n_ambi * x->x_n_ambi * sizeof(double));
+ freebytes(x->x_inv_buf2, 2 * x->x_n_ambi * sizeof(double));
+ freebytes(x->x_transp, (x->x_n_ls+x->x_n_phls) * x->x_n_ambi * sizeof(double));
+ freebytes(x->x_ls_encode, (x->x_n_ls+x->x_n_phls) * x->x_n_ambi * sizeof(double));
+ freebytes(x->x_prod, (x->x_n_ls+x->x_n_phls) * x->x_n_ambi * sizeof(double));
+ freebytes(x->x_ambi_channel_weight, x->x_n_ambi * sizeof(double));
+ freebytes(x->x_at, (x->x_n_ls * x->x_n_ambi + 2) * sizeof(t_atom));
+}
+
+static void *ambi_decode_new(t_symbol *s, int argc, t_atom *argv)
+{
+ t_ambi_decode *x = (t_ambi_decode *)pd_new(ambi_decode_class);
+ int nls, order, dim, i;
+ int nphls=0;/* phantom_loudspeaker */
+
+ if(argc < 3)
+ {
+ post("ambi_decode-ERROR: need following arguments: ambi_order dimension number_of_loudspeakers (number_of_phantom_speakers)");
+ return(0);
+ }
+ else
+ {
+ order = (int)atom_getint(argv++);
+ dim = (int)atom_getint(argv++);
+ nls = (int)atom_getint(argv++);
+ if((argc > 3)&&IS_A_FLOAT(argv,0))
+ nphls=(int)atom_getint(argv);
+
+ if(order < 1)
+ order = 1;
+ if(dim != 3)
+ {
+ dim = 2;
+ if(order > 12)
+ order = 12;
+ x->x_n_ambi = 2*order + 1;
+ }
+ else
+ {
+ if(order > 5)
+ order = 5;
+ x->x_n_ambi = (order + 1)*(order + 1);
+ }
+ x->x_n_dim = dim;
+ x->x_n_order = order;
+ if(nls < 1)
+ nls = 1;
+ if(nphls < 0)
+ nphls = 0;
+ if(nls < x->x_n_ambi)
+ post("ambi_decode-WARNING: Number of Loudspeakers < Number of Ambisonic-Channels !!!!");
+ if(nphls > nls)
+ {
+ post("ambi_decode-WARNING: Number of Phantom-Loudspeakers > Number of Loudspeakers !!!!");
+ nphls = nls;
+ }
+ x->x_n_ls = nls;
+ x->x_n_phls = nphls;
+ x->x_inv_work1 = (double *)getbytes(x->x_n_ambi * x->x_n_ambi * sizeof(double));
+ x->x_inv_work2 = (double *)getbytes(2 * x->x_n_ambi * x->x_n_ambi * sizeof(double));
+ x->x_inv_buf2 = (double *)getbytes(2 * x->x_n_ambi * sizeof(double));
+ x->x_transp = (double *)getbytes((x->x_n_ls+x->x_n_phls) * x->x_n_ambi * sizeof(double));
+ x->x_ls_encode = (double *)getbytes((x->x_n_ls+x->x_n_phls) * x->x_n_ambi * sizeof(double));
+ x->x_prod = (double *)getbytes((x->x_n_ls+x->x_n_phls) * x->x_n_ambi * sizeof(double));
+ x->x_ambi_channel_weight = (double *)getbytes(x->x_n_ambi * sizeof(double));
+ x->x_at = (t_atom *)getbytes((x->x_n_ls * x->x_n_ambi + 2) * sizeof(t_atom));
+ x->x_s_matrix = gensym("matrix");
+ /*change*/
+ SETFLOAT(x->x_at, (float)x->x_n_ls);
+ SETFLOAT(x->x_at+1, (float)x->x_n_ambi);
+ x->x_sqrt3 = sqrt(3.0);
+ x->x_sqrt5_2 = sqrt(5.0) / 2.0;
+ x->x_sqrt6_4 = sqrt(6.0) / 4.0;
+ x->x_sqrt10_4 = sqrt(10.0) / 4.0;
+ x->x_sqrt15_2 = sqrt(15.0) / 2.0;
+ x->x_sqrt35_8 = sqrt(35.0) / 8.0;
+ x->x_sqrt70_4 = sqrt(70.0) / 4.0;
+ x->x_sqrt126_16 = sqrt(126.0) / 16.0;
+ x->x_sqrt315_8 = sqrt(315.0) / 8.0;
+ x->x_sqrt105_4 = sqrt(105.0) / 4.0;
+ x->x_pi_over_180 = 4.0 * atan(1.0) / 180.0;
+ x->x_sing_range = 1.0e-10;
+ for(i=0; i<x->x_n_ambi; i++)
+ x->x_ambi_channel_weight[i] = 1.0;
+ outlet_new(&x->x_obj, &s_list);
+ return (x);
+ }
+}
+
+void ambi_decode_setup(void)
+{
+ ambi_decode_class = class_new(gensym("ambi_decode"), (t_newmethod)ambi_decode_new, (t_method)ambi_decode_free,
+ sizeof(t_ambi_decode), 0, A_GIMME, 0);
+ class_addmethod(ambi_decode_class, (t_method)ambi_decode_ls, gensym("ls"), A_GIMME, 0);
+ class_addmethod(ambi_decode_class, (t_method)ambi_decode_phls, gensym("phls"), A_GIMME, 0);
+ class_addmethod(ambi_decode_class, (t_method)ambi_decode_ambi_weight, gensym("ambi_weight"), A_GIMME, 0);
+ class_addmethod(ambi_decode_class, (t_method)ambi_decode_sing_range, gensym("sing_range"), A_DEFFLOAT, 0);
+ class_addmethod(ambi_decode_class, (t_method)ambi_decode_pinv, gensym("pinv"), 0);
+ class_sethelpsymbol(ambi_decode_class, gensym("iemhelp2/help-ambi_decode"));
+}
diff --git a/src/ambi_decode2.c b/src/ambi_decode2.c
new file mode 100644
index 0000000..2e5caf9
--- /dev/null
+++ b/src/ambi_decode2.c
@@ -0,0 +1,824 @@
+/* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution.
+
+iem_ambi written by Thomas Musil, Copyright (c) IEM KUG Graz Austria 2000 - 2005 */
+
+#ifdef NT
+#pragma warning( disable : 4244 )
+#pragma warning( disable : 4305 )
+#endif
+
+
+#include "m_pd.h"
+#include "iemlib.h"
+#include "iem_ambi.h"
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+
+
+/* -------------------------- ambi_decode2 ------------------------------ */
+/*
+ ** berechnet ein reduziertes Ambisonic-Decoder-Set in die HRTF-Spektren **
+ ** Inputs: ls + Liste von 3 floats: Index [1 .. 25] + Elevation [-90 .. +90 degree] + Azimut [0 .. 360 degree] **
+ ** Inputs: calc_inv **
+ ** Inputs: load_HRIR + float index1..25 **
+ ** Outputs: List of 2 symbols: left-HRIR-File-name + HRIR-table-name **
+ ** Inputs: calc_reduced **
+ ** "output" ... writes the HRTF into tables **
+ ** **
+ ** **
+ ** setzt voraus , dass die HRIR-tabele-names von LS1_L_HRIR .. LS25_L_HRIR heissen und existieren **
+ ** setzt voraus , dass die HRTF-tabele-names von LS1_HRTF_re .. LS25_HRTF_re heissen und existieren **
+ ** setzt voraus , dass die HRTF-tabele-names von LS1_HRTF_im .. LS25_HRTF_im heissen und existieren **
+ */
+
+
+typedef struct _ambi_decode2
+{
+ t_object x_obj;
+ t_atom *x_at;
+ double *x_inv_work1;
+ double *x_inv_work2;
+ double *x_inv_buf2;
+ double *x_transp;
+ double *x_ls_encode;
+ double *x_prod;
+ double *x_ambi_channel_weight;
+ double x_mirror_weight;
+ double x_sing_range;
+ int x_n_ambi;
+ int x_n_order;
+ int x_n_ls;
+ int x_n_ph_ls;
+ int x_n_mir_ls;
+ int x_n_dim;
+ t_symbol *x_s_matrix;
+ double x_sqrt3;
+ double x_sqrt10_4;
+ double x_sqrt15_2;
+ double x_sqrt6_4;
+ double x_sqrt35_8;
+ double x_sqrt70_4;
+ double x_sqrt5_2;
+ double x_sqrt126_16;
+ double x_sqrt315_8;
+ double x_sqrt105_4;
+ double x_pi_over_180;
+} t_ambi_decode2;
+
+static t_class *ambi_decode2_class;
+
+static void ambi_decode2_copy_row2buf(t_ambi_decode2 *x, int row)
+{
+ int n_ambi2 = 2*x->x_n_ambi;
+ int i;
+ double *dw=x->x_inv_work2;
+ double *db=x->x_inv_buf2;
+
+ dw += row*n_ambi2;
+ for(i=0; i<n_ambi2; i++)
+ *db++ = *dw++;
+}
+
+static void ambi_decode2_copy_buf2row(t_ambi_decode2 *x, int row)
+{
+ int n_ambi2 = 2*x->x_n_ambi;
+ int i;
+ double *dw=x->x_inv_work2;
+ double *db=x->x_inv_buf2;
+
+ dw += row*n_ambi2;
+ for(i=0; i<n_ambi2; i++)
+ *dw++ = *db++;
+}
+
+static void ambi_decode2_copy_row2row(t_ambi_decode2 *x, int src_row, int dst_row)
+{
+ int n_ambi2 = 2*x->x_n_ambi;
+ int i;
+ double *dw_src=x->x_inv_work2;
+ double *dw_dst=x->x_inv_work2;
+
+ dw_src += src_row*n_ambi2;
+ dw_dst += dst_row*n_ambi2;
+ for(i=0; i<n_ambi2; i++)
+ *dw_dst++ = *dw_src++;
+}
+
+static void ambi_decode2_xch_rows(t_ambi_decode2 *x, int row1, int row2)
+{
+ ambi_decode2_copy_row2buf(x, row1);
+ ambi_decode2_copy_row2row(x, row2, row1);
+ ambi_decode2_copy_buf2row(x, row2);
+}
+
+static void ambi_decode2_mul_row(t_ambi_decode2 *x, int row, double mul)
+{
+ int n_ambi2 = 2*x->x_n_ambi;
+ int i;
+ double *dw=x->x_inv_work2;
+
+ dw += row*n_ambi2;
+ for(i=0; i<n_ambi2; i++)
+ {
+ (*dw) *= mul;
+ dw++;
+ }
+}
+
+static void ambi_decode2_mul_buf_and_add2row(t_ambi_decode2 *x, int row, double mul)
+{
+ int n_ambi2 = 2*x->x_n_ambi;
+ int i;
+ double *dw=x->x_inv_work2;
+ double *db=x->x_inv_buf2;
+
+ dw += row*n_ambi2;
+ for(i=0; i<n_ambi2; i++)
+ {
+ *dw += (*db)*mul;
+ dw++;
+ db++;
+ }
+}
+
+static int ambi_decode2_eval_which_element_of_col_not_zero(t_ambi_decode2 *x, int col, int start_row)
+{
+ int n_ambi = x->x_n_ambi;
+ int n_ambi2 = 2*n_ambi;
+ int i, j;
+ double *dw=x->x_inv_work2;
+ double singrange=x->x_sing_range;
+ int ret=-1;
+
+ dw += start_row*n_ambi2 + col;
+ j = 0;
+ for(i=start_row; i<n_ambi; i++)
+ {
+ if((*dw > singrange) || (*dw < -singrange))
+ {
+ ret = i;
+ i = n_ambi+1;
+ }
+ dw += n_ambi2;
+ }
+ return(ret);
+}
+
+static void ambi_decode2_mul1(t_ambi_decode2 *x)
+{
+ double *vec1, *beg1=x->x_ls_encode;
+ double *vec2, *beg2=x->x_ls_encode;
+ double *inv=x->x_inv_work1;
+ double sum;
+ int n_ls=x->x_n_ls+2*x->x_n_mir_ls+x->x_n_ph_ls;
+ int n_ambi=x->x_n_ambi;
+ int i, j, k;
+
+ for(k=0; k<n_ambi; k++)
+ {
+ beg2=x->x_ls_encode;
+ for(j=0; j<n_ambi; j++)
+ {
+ sum = 0.0;
+ vec1 = beg1;
+ vec2 = beg2;
+ for(i=0; i<n_ls; i++)
+ {
+ sum += *vec1++ * *vec2++;
+ }
+ beg2 += n_ls;
+ *inv++ = sum;
+ }
+ beg1 += n_ls;
+ }
+}
+
+static void ambi_decode2_mul2(t_ambi_decode2 *x)
+{
+ int n_ls=x->x_n_ls+2*x->x_n_mir_ls+x->x_n_ph_ls;
+ int n_ambi=x->x_n_ambi;
+ int n_ambi2=2*n_ambi;
+ int i, j, k;
+ double *vec1, *beg1=x->x_transp;
+ double *vec2, *beg2=x->x_inv_work2+n_ambi;
+ double *vec3=x->x_prod;
+ double *acw_vec=x->x_ambi_channel_weight;
+ double sum;
+
+ for(k=0; k<n_ls; k++)
+ {
+ beg2=x->x_inv_work2+n_ambi;
+ for(j=0; j<n_ambi; j++)
+ {
+ sum = 0.0;
+ vec1 = beg1;
+ vec2 = beg2;
+ for(i=0; i<n_ambi; i++)
+ {
+ sum += *vec1++ * *vec2;
+ vec2 += n_ambi2;
+ }
+ beg2++;
+ *vec3++ = sum * acw_vec[j];
+ }
+ beg1 += n_ambi;
+ }
+}
+
+static void ambi_decode2_transp_back(t_ambi_decode2 *x)
+{
+ double *vec, *transp=x->x_transp;
+ double *straight=x->x_ls_encode;
+ int n_ls=x->x_n_ls+2*x->x_n_mir_ls+x->x_n_ph_ls;
+ int n_ambi=x->x_n_ambi;
+ int i, j;
+
+ for(j=0; j<n_ambi; j++)
+ {
+ vec = transp;
+ for(i=0; i<n_ls; i++)
+ {
+ *straight++ = *vec;
+ vec += n_ambi;
+ }
+ transp++;
+ }
+}
+
+static void ambi_decode2_inverse(t_ambi_decode2 *x)
+{
+ int n_ambi = x->x_n_ambi;
+ int n_ambi2 = 2*n_ambi;
+ int i, j, nz;
+ int r,c;
+ double *src=x->x_inv_work1;
+ double *db=x->x_inv_work2;
+ double rcp, *dv;
+
+ dv = db;
+ for(i=0; i<n_ambi; i++) /* init */
+ {
+ for(j=0; j<n_ambi; j++)
+ {
+ *dv++ = *src++;
+ }
+ for(j=0; j<n_ambi; j++)
+ {
+ if(j == i)
+ *dv++ = 1.0;
+ else
+ *dv++ = 0.0;
+ }
+ }
+
+ /* make 1 in main-diagonale, and 0 below */
+ for(i=0; i<n_ambi; i++)
+ {
+ nz = ambi_decode2_eval_which_element_of_col_not_zero(x, i, i);
+ if(nz < 0)
+ {
+ post("ambi_decode2 ERROR: matrix not regular !!!!");
+ return;
+ }
+ else
+ {
+ if(nz != i)
+ ambi_decode2_xch_rows(x, i, nz);
+ dv = db + i*n_ambi2 + i;
+ rcp = 1.0 /(*dv);
+ ambi_decode2_mul_row(x, i, rcp);
+ ambi_decode2_copy_row2buf(x, i);
+ for(j=i+1; j<n_ambi; j++)
+ {
+ dv += n_ambi2;
+ rcp = -(*dv);
+ ambi_decode2_mul_buf_and_add2row(x, j, rcp);
+ }
+ }
+ }
+
+ /* make 0 above the main diagonale */
+ for(i=n_ambi-1; i>=0; i--)
+ {
+ dv = db + i*n_ambi2 + i;
+ ambi_decode2_copy_row2buf(x, i);
+ for(j=i-1; j>=0; j--)
+ {
+ dv -= n_ambi2;
+ rcp = -(*dv);
+ ambi_decode2_mul_buf_and_add2row(x, j, rcp);
+ }
+ }
+
+ post("matrix_inverse regular");
+}
+
+static void ambi_decode2_pseudo_inverse(t_ambi_decode2 *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_atom *at=x->x_at;
+ int i, n=x->x_n_ls*x->x_n_ambi;
+ double *dv1=x->x_prod;
+ double *dv2=x->x_prod;
+ double mw=x->x_mirror_weight;
+
+ ambi_decode2_transp_back(x);
+ ambi_decode2_mul1(x);
+ ambi_decode2_inverse(x);
+ ambi_decode2_mul2(x);
+ at += 2;
+ for(i=0; i<n; i++)
+ {
+ SETFLOAT(at, (float)(*dv1));
+ dv1++;
+ at++;
+ }
+
+ dv2 += n;
+ n=x->x_n_mir_ls*x->x_n_ambi;
+ dv2 += n;
+ for(i=0; i<n; i++)
+ {
+ SETFLOAT(at, (float)(*dv1 + *dv2*mw));
+ dv1++;
+ dv2++;
+ at++;
+ }
+
+ outlet_anything(x->x_obj.ob_outlet, x->x_s_matrix, x->x_n_ambi*(x->x_n_ls+x->x_n_mir_ls)+2, x->x_at);
+}
+
+static void ambi_decode2_encode_ls_2d(t_ambi_decode2 *x, int argc, t_atom *argv, int mode)
+{
+ double phi;
+ double *dw = x->x_transp;
+ int index;
+ int order=x->x_n_order;
+
+ if(argc < 2)
+ {
+ post("ambi_decode2 ERROR: ls-input needs 1 index and 1 angle: ls_index + phi [degree]");
+ return;
+ }
+ index = (int)atom_getint(argv++) - 1;
+ phi = (double)atom_getfloat(argv);
+
+ if(index < 0)
+ index = 0;
+
+ if(mode == AMBI_LS_IND)
+ {
+ if(index >= x->x_n_ls)
+ index = x->x_n_ls - 1;
+ }
+ else if(mode == AMBI_LS_MRG)
+ {
+ if(x->x_n_mir_ls)
+ {
+ if(index >= x->x_n_mir_ls)
+ index = x->x_n_mir_ls - 1;
+ index += x->x_n_ls;
+ }
+ else
+ return;
+ }
+ else if(mode == AMBI_LS_MIR)
+ {
+ if(x->x_n_mir_ls)
+ {
+ if(index >= x->x_n_mir_ls)
+ index = x->x_n_mir_ls - 1;
+ index += x->x_n_ls;
+ index += x->x_n_mir_ls;
+ }
+ else
+ return;
+ }
+ else if(mode == AMBI_LS_PHT)
+ {
+ if(x->x_n_ph_ls)
+ {
+ if(index >= x->x_n_ph_ls)
+ index = x->x_n_ph_ls - 1;
+ index += x->x_n_ls;
+ index += 2*x->x_n_mir_ls;
+ }
+ else
+ return;
+ }
+ else
+ return;
+
+ phi *= x->x_pi_over_180;
+
+ dw += index * x->x_n_ambi;
+
+ *dw++ = 1.0;
+ *dw++ = cos(phi);
+ *dw++ = sin(phi);
+
+ if(order >= 2)
+ {
+ *dw++ = cos(2.0*phi);
+ *dw++ = sin(2.0*phi);
+
+ if(order >= 3)
+ {
+ *dw++ = cos(3.0*phi);
+ *dw++ = sin(3.0*phi);
+ if(order >= 4)
+ {
+ *dw++ = cos(4.0*phi);
+ *dw++ = sin(4.0*phi);
+
+ if(order >= 5)
+ {
+ *dw++ = cos(5.0*phi);
+ *dw++ = sin(5.0*phi);
+
+ if(order >= 6)
+ {
+ *dw++ = cos(6.0*phi);
+ *dw++ = sin(6.0*phi);
+
+ if(order >= 7)
+ {
+ *dw++ = cos(7.0*phi);
+ *dw++ = sin(7.0*phi);
+
+ if(order >= 8)
+ {
+ *dw++ = cos(8.0*phi);
+ *dw++ = sin(8.0*phi);
+
+ if(order >= 9)
+ {
+ *dw++ = cos(9.0*phi);
+ *dw++ = sin(9.0*phi);
+
+ if(order >= 10)
+ {
+ *dw++ = cos(10.0*phi);
+ *dw++ = sin(10.0*phi);
+
+ if(order >= 11)
+ {
+ *dw++ = cos(11.0*phi);
+ *dw++ = sin(11.0*phi);
+
+ if(order >= 12)
+ {
+ *dw++ = cos(12.0*phi);
+ *dw++ = sin(12.0*phi);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+static void ambi_decode2_encode_ls_3d(t_ambi_decode2 *x, int argc, t_atom *argv, int mode)
+{
+ double delta, phi;
+ double cd, sd, cd2, cd3, sd2, csd, cp, sp, cp2, sp2, cp3, sp3, cp4, sp4;
+ double *dw = x->x_transp;
+ int index;
+ int order=x->x_n_order;
+
+ if(argc < 3)
+ {
+ post("ambi_decode2 ERROR: ls-input needs 1 index and 2 angles: ls index + delta [degree] + phi [degree]");
+ return;
+ }
+ index = (int)atom_getint(argv++) - 1;
+ delta = atom_getfloat(argv++);
+ phi = atom_getfloat(argv);
+
+ if(index < 0)
+ index = 0;
+
+ if(mode == AMBI_LS_IND)
+ {
+ if(index >= x->x_n_ls)
+ index = x->x_n_ls - 1;
+ }
+ else if(mode == AMBI_LS_MRG)
+ {
+ if(x->x_n_mir_ls)
+ {
+ if(index >= x->x_n_mir_ls)
+ index = x->x_n_mir_ls - 1;
+ index += x->x_n_ls;
+ }
+ else
+ return;
+ }
+ else if(mode == AMBI_LS_MIR)
+ {
+ if(x->x_n_mir_ls)
+ {
+ if(index >= x->x_n_mir_ls)
+ index = x->x_n_mir_ls - 1;
+ index += x->x_n_ls;
+ index += x->x_n_mir_ls;
+ }
+ else
+ return;
+ }
+ else if(mode == AMBI_LS_PHT)
+ {
+ if(x->x_n_ph_ls)
+ {
+ if(index >= x->x_n_ph_ls)
+ index = x->x_n_ph_ls - 1;
+ index += x->x_n_ls;
+ index += 2*x->x_n_mir_ls;
+ }
+ else
+ return;
+ }
+ else
+ return;
+
+ delta *= x->x_pi_over_180;
+ phi *= x->x_pi_over_180;
+
+ dw += index * x->x_n_ambi;
+
+ cd = cos(delta);
+ sd = sin(delta);
+ cp = cos(phi);
+ sp = sin(phi);
+
+
+ *dw++ = 1.0;
+ *dw++ = cd * cp;
+ *dw++ = cd * sp;
+ *dw++ = sd;
+
+ if(order >= 2)
+ {
+ cp2 = cos(2.0*phi);
+ sp2 = sin(2.0*phi);
+ cd2 = cd * cd;
+ sd2 = sd * sd;
+ csd = cd * sd;
+ *dw++ = 0.5 * x->x_sqrt3 * cd2 * cp2;
+ *dw++ = 0.5 * x->x_sqrt3 * cd2 * sp2;
+ *dw++ = x->x_sqrt3 * csd * cp;
+ *dw++ = x->x_sqrt3 * csd * sp;
+ *dw++ = 0.5 * (3.0 * sd2 - 1.0);
+
+ if(order >= 3)
+ {
+ cp3 = cos(3.0*phi);
+ sp3 = sin(3.0*phi);
+ cd3 = cd2 * cd;
+ *dw++ = x->x_sqrt10_4 * cd3 * cp3;
+ *dw++ = x->x_sqrt10_4 * cd3 * sp3;
+ *dw++ = x->x_sqrt15_2 * cd * csd * cp2;
+ *dw++ = x->x_sqrt15_2 * cd * csd * sp2;
+ *dw++ = x->x_sqrt6_4 * cd * (5.0 * sd2 - 1.0) * cp;
+ *dw++ = x->x_sqrt6_4 * cd * (5.0 * sd2 - 1.0) * sp;
+ *dw++ = 0.5 * sd * (5.0 * sd2 - 3.0);
+
+ if(order >= 4)
+ {
+ cp4 = cos(4.0*phi);
+ sp4 = sin(4.0*phi);
+ *dw++ = x->x_sqrt35_8 * cd2 * cd2 * cp4;
+ *dw++ = x->x_sqrt35_8 * cd2 * cd2 * sp4;
+ *dw++ = x->x_sqrt70_4 * cd2 * csd * cp3;
+ *dw++ = x->x_sqrt70_4 * cd2 * csd * sp3;
+ *dw++ = 0.5 * x->x_sqrt5_2 * cd2 * (7.0 * sd2 - 1.0) * cp2;
+ *dw++ = 0.5 * x->x_sqrt5_2 * cd2 * (7.0 * sd2 - 1.0) * sp2;
+ *dw++ = x->x_sqrt10_4 * csd * (7.0 * sd2 - 3.0) * cp;
+ *dw++ = x->x_sqrt10_4 * csd * (7.0 * sd2 - 3.0) * sp;
+ *dw++ = 0.125 * (sd2 * (35.0 * sd2 - 30.0) + 3.0);
+
+ if(order >= 5)
+ {
+ *dw++ = x->x_sqrt126_16 * cd3 * cd2 * cos(5.0*phi);
+ *dw++ = x->x_sqrt126_16 * cd3 * cd2 * sin(5.0*phi);
+ *dw++ = x->x_sqrt315_8 * cd3 * csd * cp4;
+ *dw++ = x->x_sqrt315_8 * cd3 * csd * sp4;
+ *dw++ = 0.25 * x->x_sqrt70_4 * cd3 * (9.0 * sd2 - 1.0) * cp3;
+ *dw++ = 0.25 * x->x_sqrt70_4 * cd3 * (9.0 * sd2 - 1.0) * sp3;
+ *dw++ = x->x_sqrt105_4 * cd * csd * (3.0 * sd2 - 1.0) * cp2;
+ *dw++ = x->x_sqrt105_4 * cd * csd * (3.0 * sd2 - 1.0) * sp2;
+ *dw++ = 0.25 * x->x_sqrt15_2 * cd * (sd2 * (21.0 * sd2 - 14.0) + 1.0) * cp;
+ *dw++ = 0.25 * x->x_sqrt15_2 * cd * (sd2 * (21.0 * sd2 - 14.0) + 1.0) * sp;
+ *dw = 0.125 * sd * (sd2 * (63.0 * sd2 - 70.0) + 15.0);
+ }
+ }
+ }
+ }
+}
+
+static void ambi_decode2_ind_ls(t_ambi_decode2 *x, t_symbol *s, int argc, t_atom *argv)
+{
+ if(x->x_n_dim == 2)
+ ambi_decode2_encode_ls_2d(x, argc, argv, AMBI_LS_IND);
+ else
+ ambi_decode2_encode_ls_3d(x, argc, argv, AMBI_LS_IND);
+}
+
+static void ambi_decode2_mrg_ls(t_ambi_decode2 *x, t_symbol *s, int argc, t_atom *argv)
+{
+ if(x->x_n_dim == 2)
+ ambi_decode2_encode_ls_2d(x, argc, argv, AMBI_LS_MRG);
+ else
+ ambi_decode2_encode_ls_3d(x, argc, argv, AMBI_LS_MRG);
+}
+
+static void ambi_decode2_mir_ls(t_ambi_decode2 *x, t_symbol *s, int argc, t_atom *argv)
+{
+ if(x->x_n_dim == 2)
+ ambi_decode2_encode_ls_2d(x, argc, argv, AMBI_LS_MIR);
+ else
+ ambi_decode2_encode_ls_3d(x, argc, argv, AMBI_LS_MIR);
+}
+
+static void ambi_decode2_pht_ls(t_ambi_decode2 *x, t_symbol *s, int argc, t_atom *argv)
+{
+ if(x->x_n_dim == 2)
+ ambi_decode2_encode_ls_2d(x, argc, argv, AMBI_LS_PHT);
+ else
+ ambi_decode2_encode_ls_3d(x, argc, argv, AMBI_LS_PHT);
+}
+
+static void ambi_decode2_ambi_weight(t_ambi_decode2 *x, t_symbol *s, int argc, t_atom *argv)
+{
+ if(argc > x->x_n_order)
+ {
+ int i, k=0, n=x->x_n_order;
+ double d;
+
+ x->x_ambi_channel_weight[k] = atom_getfloat(argv++);
+ k++;
+ if(x->x_n_dim == 2)
+ {
+ for(i=1; i<=n; i++)
+ {
+ d = atom_getfloat(argv++);
+ x->x_ambi_channel_weight[k] = d;
+ k++;
+ x->x_ambi_channel_weight[k] = d;
+ k++;
+ }
+ }
+ else
+ {
+ int j, m;
+
+ for(i=1; i<=n; i++)
+ {
+ d = atom_getfloat(argv++);
+ m = 2*i + 1;
+ for(j=0; j<m; j++)
+ {
+ x->x_ambi_channel_weight[k] = d;
+ k++;
+ }
+ }
+ }
+ }
+ else
+ post("ambi_decode2-ERROR: ambi_weight needs %d float weights", x->x_n_order+1);
+}
+
+static void ambi_decode2_mirror_weight(t_ambi_decode2 *x, t_floatarg f)
+{
+ x->x_mirror_weight = (double)f;
+}
+
+static void ambi_decode2_sing_range(t_ambi_decode2 *x, t_floatarg f)
+{
+ if(f < 0.0f)
+ x->x_sing_range = -(double)f;
+ else
+ x->x_sing_range = (double)f;
+}
+
+static void ambi_decode2_free(t_ambi_decode2 *x)
+{
+ freebytes(x->x_inv_work1, x->x_n_ambi * x->x_n_ambi * sizeof(double));
+ freebytes(x->x_inv_work2, 2 * x->x_n_ambi * x->x_n_ambi * sizeof(double));
+ freebytes(x->x_inv_buf2, 2 * x->x_n_ambi * sizeof(double));
+ freebytes(x->x_transp, (x->x_n_ls+2*x->x_n_mir_ls+x->x_n_ph_ls) * x->x_n_ambi * sizeof(double));
+ freebytes(x->x_ls_encode, (x->x_n_ls+2*x->x_n_mir_ls+x->x_n_ph_ls) * x->x_n_ambi * sizeof(double));
+ freebytes(x->x_prod, (x->x_n_ls+2*x->x_n_mir_ls+x->x_n_ph_ls) * x->x_n_ambi * sizeof(double));
+ freebytes(x->x_ambi_channel_weight, x->x_n_ambi * sizeof(double));
+ freebytes(x->x_at, ((x->x_n_ls+x->x_n_mir_ls) * x->x_n_ambi + 2) * sizeof(t_atom));
+}
+
+static void *ambi_decode2_new(t_symbol *s, int argc, t_atom *argv)
+{
+ t_ambi_decode2 *x = (t_ambi_decode2 *)pd_new(ambi_decode2_class);
+ int order, dim, i;
+ int n_ls=0;/* number of loudspeakers */
+ int n_mir_ls=0;/* number of mirror_loudspeakers */
+ int n_ph_ls=0;/* number of phantom_loudspeakers */
+
+ if((argc >= 5) &&
+ IS_A_FLOAT(argv,0) &&
+ IS_A_FLOAT(argv,1) &&
+ IS_A_FLOAT(argv,2) &&
+ IS_A_FLOAT(argv,3) &&
+ IS_A_FLOAT(argv,4))
+ {
+ order = (int)atom_getint(argv++);
+ dim = (int)atom_getint(argv++);
+ n_ls = (int)atom_getint(argv++);
+ n_mir_ls = (int)atom_getint(argv++);
+ n_ph_ls = (int)atom_getint(argv);
+
+ if(order < 1)
+ order = 1;
+ if(dim != 3)
+ {
+ dim = 2;
+ if(order > 12)
+ order = 12;
+ x->x_n_ambi = 2*order + 1;
+ }
+ else
+ {
+ if(order > 5)
+ order = 5;
+ x->x_n_ambi = (order + 1)*(order + 1);
+ }
+ x->x_n_dim = dim;
+ x->x_n_order = order;
+ if(n_ls < 1)
+ n_ls = 1;
+ if(n_mir_ls < 0)
+ n_mir_ls = 0;
+ if(n_ph_ls < 0)
+ n_ph_ls = 0;
+ if((n_ls + 2*n_mir_ls + n_ph_ls) < x->x_n_ambi)
+ post("ambi_decode2-WARNING: Number of Loudspeakers < Number of Ambisonic-Channels !!!!");
+
+ x->x_n_ls = n_ls;
+ x->x_n_mir_ls = n_mir_ls;
+ x->x_n_ph_ls = n_ph_ls;
+ x->x_inv_work1 = (double *)getbytes(x->x_n_ambi * x->x_n_ambi * sizeof(double));
+ x->x_inv_work2 = (double *)getbytes(2 * x->x_n_ambi * x->x_n_ambi * sizeof(double));
+ x->x_inv_buf2 = (double *)getbytes(2 * x->x_n_ambi * sizeof(double));
+ x->x_transp = (double *)getbytes((x->x_n_ls+2*x->x_n_mir_ls+x->x_n_ph_ls) * x->x_n_ambi * sizeof(double));
+ x->x_ls_encode = (double *)getbytes((x->x_n_ls+2*x->x_n_mir_ls+x->x_n_ph_ls) * x->x_n_ambi * sizeof(double));
+ x->x_prod = (double *)getbytes((x->x_n_ls+2*x->x_n_mir_ls+x->x_n_ph_ls) * x->x_n_ambi * sizeof(double));
+ x->x_ambi_channel_weight = (double *)getbytes(x->x_n_ambi * sizeof(double));
+ x->x_at = (t_atom *)getbytes(((x->x_n_ls+x->x_n_mir_ls) * x->x_n_ambi + 2) * sizeof(t_atom));
+ x->x_s_matrix = gensym("matrix");
+ /*change*/
+ SETFLOAT(x->x_at, (float)(x->x_n_ls+x->x_n_mir_ls));
+ SETFLOAT(x->x_at+1, (float)x->x_n_ambi);
+ x->x_mirror_weight = 0.0;
+
+ x->x_sqrt3 = sqrt(3.0);
+ x->x_sqrt5_2 = sqrt(5.0) / 2.0;
+ x->x_sqrt6_4 = sqrt(6.0) / 4.0;
+ x->x_sqrt10_4 = sqrt(10.0) / 4.0;
+ x->x_sqrt15_2 = sqrt(15.0) / 2.0;
+ x->x_sqrt35_8 = sqrt(35.0) / 8.0;
+ x->x_sqrt70_4 = sqrt(70.0) / 4.0;
+ x->x_sqrt126_16 = sqrt(126.0) / 16.0;
+ x->x_sqrt315_8 = sqrt(315.0) / 8.0;
+ x->x_sqrt105_4 = sqrt(105.0) / 4.0;
+ x->x_pi_over_180 = 4.0 * atan(1.0) / 180.0;
+ x->x_sing_range = 1.0e-10;
+ for(i=0; i<x->x_n_ambi; i++)
+ x->x_ambi_channel_weight[i] = 1.0;
+ outlet_new(&x->x_obj, &s_list);
+ return (x);
+ }
+ else
+ {
+ post("ambi_decode2-ERROR: need 5 float arguments: ambi_order dimension number_of_independent_loudspeakers number_of_merged_and_mirrored_speakers number_of_canceled_phantom_speakers");
+ return(0);
+ }
+}
+
+void ambi_decode2_setup(void)
+{
+ ambi_decode2_class = class_new(gensym("ambi_decode2"), (t_newmethod)ambi_decode2_new, (t_method)ambi_decode2_free,
+ sizeof(t_ambi_decode2), 0, A_GIMME, 0);
+ class_addmethod(ambi_decode2_class, (t_method)ambi_decode2_ind_ls, gensym("ind_ls"), A_GIMME, 0);
+ class_addmethod(ambi_decode2_class, (t_method)ambi_decode2_mrg_ls, gensym("mrg_ls"), A_GIMME, 0);
+ class_addmethod(ambi_decode2_class, (t_method)ambi_decode2_mir_ls, gensym("mir_ls"), A_GIMME, 0);
+ class_addmethod(ambi_decode2_class, (t_method)ambi_decode2_pht_ls, gensym("pht_ls"), A_GIMME, 0);
+ class_addmethod(ambi_decode2_class, (t_method)ambi_decode2_mirror_weight, gensym("mirror_weight"), A_DEFFLOAT, 0);
+ class_addmethod(ambi_decode2_class, (t_method)ambi_decode2_ambi_weight, gensym("ambi_weight"), A_GIMME, 0);
+ class_addmethod(ambi_decode2_class, (t_method)ambi_decode2_sing_range, gensym("sing_range"), A_DEFFLOAT, 0);
+ class_addmethod(ambi_decode2_class, (t_method)ambi_decode2_pseudo_inverse, gensym("pseudo_inverse"), A_GIMME, 0);
+ class_sethelpsymbol(ambi_decode2_class, gensym("iemhelp2/help-ambi_decode2"));
+}
diff --git a/src/ambi_decode3.c b/src/ambi_decode3.c
new file mode 100644
index 0000000..6724924
--- /dev/null
+++ b/src/ambi_decode3.c
@@ -0,0 +1,772 @@
+/* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution.
+
+iem_ambi written by Thomas Musil, Copyright (c) IEM KUG Graz Austria 2000 - 2005 */
+
+#ifdef NT
+#pragma warning( disable : 4244 )
+#pragma warning( disable : 4305 )
+#endif
+
+
+#include "m_pd.h"
+#include "iemlib.h"
+#include "iem_ambi.h"
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+
+
+/* -------------------------- ambi_decode3 ------------------------------ */
+/*
+ ** berechnet ein reduziertes Ambisonic-Decoder-Set in die HRTF-Spektren **
+ ** Inputs: ls + Liste von 3 floats: Index [1 .. 25] + Elevation [-90 .. +90 degree] + Azimut [0 .. 360 degree] **
+ ** Inputs: calc_inv **
+ ** Inputs: load_HRIR + float index1..25 **
+ ** Outputs: List of 2 symbols: left-HRIR-File-name + HRIR-table-name **
+ ** Inputs: calc_reduced **
+ ** "output" ... writes the HRTF into tables **
+ ** **
+ ** **
+ ** setzt voraus , dass die HRIR-tabele-names von LS1_L_HRIR .. LS25_L_HRIR heissen und existieren **
+ ** setzt voraus , dass die HRTF-tabele-names von LS1_HRTF_re .. LS25_HRTF_re heissen und existieren **
+ ** setzt voraus , dass die HRTF-tabele-names von LS1_HRTF_im .. LS25_HRTF_im heissen und existieren **
+ */
+
+typedef struct _ambi_decode3
+{
+ t_object x_obj;
+ t_atom *x_at;
+ double *x_inv_work1;
+ double *x_inv_work2;
+ double *x_inv_buf2;
+ double *x_transp;
+ double *x_ls_encode;
+ double *x_prod;
+ double *x_ambi_channel_weight;
+ double x_sing_range;
+ int x_n_ambi;
+ int x_n_order;
+ int x_n_real_ls;
+ int x_n_pht_ls;
+ int x_n_dim;
+ t_symbol *x_s_matrix;
+ double x_sqrt3;
+ double x_sqrt10_4;
+ double x_sqrt15_2;
+ double x_sqrt6_4;
+ double x_sqrt35_8;
+ double x_sqrt70_4;
+ double x_sqrt5_2;
+ double x_sqrt126_16;
+ double x_sqrt315_8;
+ double x_sqrt105_4;
+ double x_pi_over_180;
+} t_ambi_decode3;
+
+static t_class *ambi_decode3_class;
+
+static void ambi_decode3_copy_row2buf(t_ambi_decode3 *x, int row)
+{
+ int n_ambi2 = 2*x->x_n_ambi;
+ int i;
+ double *dw=x->x_inv_work2;
+ double *db=x->x_inv_buf2;
+
+ dw += row*n_ambi2;
+ for(i=0; i<n_ambi2; i++)
+ *db++ = *dw++;
+}
+
+static void ambi_decode3_copy_buf2row(t_ambi_decode3 *x, int row)
+{
+ int n_ambi2 = 2*x->x_n_ambi;
+ int i;
+ double *dw=x->x_inv_work2;
+ double *db=x->x_inv_buf2;
+
+ dw += row*n_ambi2;
+ for(i=0; i<n_ambi2; i++)
+ *dw++ = *db++;
+}
+
+static void ambi_decode3_copy_row2row(t_ambi_decode3 *x, int src_row, int dst_row)
+{
+ int n_ambi2 = 2*x->x_n_ambi;
+ int i;
+ double *dw_src=x->x_inv_work2;
+ double *dw_dst=x->x_inv_work2;
+
+ dw_src += src_row*n_ambi2;
+ dw_dst += dst_row*n_ambi2;
+ for(i=0; i<n_ambi2; i++)
+ *dw_dst++ = *dw_src++;
+}
+
+static void ambi_decode3_xch_rows(t_ambi_decode3 *x, int row1, int row2)
+{
+ ambi_decode3_copy_row2buf(x, row1);
+ ambi_decode3_copy_row2row(x, row2, row1);
+ ambi_decode3_copy_buf2row(x, row2);
+}
+
+static void ambi_decode3_mul_row(t_ambi_decode3 *x, int row, double mul)
+{
+ int n_ambi2 = 2*x->x_n_ambi;
+ int i;
+ double *dw=x->x_inv_work2;
+
+ dw += row*n_ambi2;
+ for(i=0; i<n_ambi2; i++)
+ {
+ (*dw) *= mul;
+ dw++;
+ }
+}
+
+static void ambi_decode3_mul_buf_and_add2row(t_ambi_decode3 *x, int row, double mul)
+{
+ int n_ambi2 = 2*x->x_n_ambi;
+ int i;
+ double *dw=x->x_inv_work2;
+ double *db=x->x_inv_buf2;
+
+ dw += row*n_ambi2;
+ for(i=0; i<n_ambi2; i++)
+ {
+ *dw += (*db)*mul;
+ dw++;
+ db++;
+ }
+}
+
+static int ambi_decode3_eval_which_element_of_col_not_zero(t_ambi_decode3 *x, int col, int start_row)
+{
+ int n_ambi = x->x_n_ambi;
+ int n_ambi2 = 2*n_ambi;
+ int i, j;
+ double *dw=x->x_inv_work2;
+ double singrange=x->x_sing_range;
+ int ret=-1;
+
+ dw += start_row*n_ambi2 + col;
+ j = 0;
+ for(i=start_row; i<n_ambi; i++)
+ {
+ if((*dw > singrange) || (*dw < -singrange))
+ {
+ ret = i;
+ i = n_ambi+1;
+ }
+ dw += n_ambi2;
+ }
+ return(ret);
+}
+
+static void ambi_decode3_mul1(t_ambi_decode3 *x)
+{
+ double *vec1, *beg1=x->x_ls_encode;
+ double *vec2, *beg2=x->x_ls_encode;
+ double *inv=x->x_inv_work1;
+ double sum;
+ int n_ls=x->x_n_real_ls+x->x_n_pht_ls;
+ int n_ambi=x->x_n_ambi;
+ int i, j, k;
+
+ for(k=0; k<n_ambi; k++)
+ {
+ beg2=x->x_ls_encode;
+ for(j=0; j<n_ambi; j++)
+ {
+ sum = 0.0;
+ vec1 = beg1;
+ vec2 = beg2;
+ for(i=0; i<n_ls; i++)
+ {
+ sum += *vec1++ * *vec2++;
+ }
+ beg2 += n_ls;
+ *inv++ = sum;
+ }
+ beg1 += n_ls;
+ }
+}
+
+static void ambi_decode3_mul2(t_ambi_decode3 *x)
+{
+ int n_ls=x->x_n_real_ls+x->x_n_pht_ls;
+ int n_ambi=x->x_n_ambi;
+ int n_ambi2=2*n_ambi;
+ int i, j, k;
+ double *vec1, *beg1=x->x_transp;
+ double *vec2, *beg2=x->x_inv_work2+n_ambi;
+ double *vec3=x->x_prod;
+ double *acw_vec=x->x_ambi_channel_weight;
+ double sum;
+
+ for(k=0; k<n_ls; k++)
+ {
+ beg2=x->x_inv_work2+n_ambi;
+ for(j=0; j<n_ambi; j++)
+ {
+ sum = 0.0;
+ vec1 = beg1;
+ vec2 = beg2;
+ for(i=0; i<n_ambi; i++)
+ {
+ sum += *vec1++ * *vec2;
+ vec2 += n_ambi2;
+ }
+ beg2++;
+ *vec3++ = sum * acw_vec[j];
+ }
+ beg1 += n_ambi;
+ }
+}
+
+static void ambi_decode3_transp_back(t_ambi_decode3 *x)
+{
+ double *vec, *transp=x->x_transp;
+ double *straight=x->x_ls_encode;
+ int n_ls=x->x_n_real_ls+x->x_n_pht_ls;
+ int n_ambi=x->x_n_ambi;
+ int i, j;
+
+ for(j=0; j<n_ambi; j++)
+ {
+ vec = transp;
+ for(i=0; i<n_ls; i++)
+ {
+ *straight++ = *vec;
+ vec += n_ambi;
+ }
+ transp++;
+ }
+}
+
+static void ambi_decode3_inverse(t_ambi_decode3 *x)
+{
+ int n_ambi = x->x_n_ambi;
+ int n_ambi2 = 2*n_ambi;
+ int i, j, nz;
+ int r,c;
+ double *src=x->x_inv_work1;
+ double *db=x->x_inv_work2;
+ double rcp, *dv;
+
+ dv = db;
+ for(i=0; i<n_ambi; i++) /* init */
+ {
+ for(j=0; j<n_ambi; j++)
+ {
+ *dv++ = *src++;
+ }
+ for(j=0; j<n_ambi; j++)
+ {
+ if(j == i)
+ *dv++ = 1.0;
+ else
+ *dv++ = 0.0;
+ }
+ }
+
+ /* make 1 in main-diagonale, and 0 below */
+ for(i=0; i<n_ambi; i++)
+ {
+ nz = ambi_decode3_eval_which_element_of_col_not_zero(x, i, i);
+ if(nz < 0)
+ {
+ post("ambi_decode3 ERROR: matrix not regular !!!!");
+ return;
+ }
+ else
+ {
+ if(nz != i)
+ ambi_decode3_xch_rows(x, i, nz);
+ dv = db + i*n_ambi2 + i;
+ rcp = 1.0 /(*dv);
+ ambi_decode3_mul_row(x, i, rcp);
+ ambi_decode3_copy_row2buf(x, i);
+ for(j=i+1; j<n_ambi; j++)
+ {
+ dv += n_ambi2;
+ rcp = -(*dv);
+ ambi_decode3_mul_buf_and_add2row(x, j, rcp);
+ }
+ }
+ }
+
+ /* make 0 above the main diagonale */
+ for(i=n_ambi-1; i>=0; i--)
+ {
+ dv = db + i*n_ambi2 + i;
+ ambi_decode3_copy_row2buf(x, i);
+ for(j=i-1; j>=0; j--)
+ {
+ dv -= n_ambi2;
+ rcp = -(*dv);
+ ambi_decode3_mul_buf_and_add2row(x, j, rcp);
+ }
+ }
+
+ post("matrix_inverse regular");
+}
+
+static void ambi_decode3_begin_pseudo_inverse(t_ambi_decode3 *x)
+{
+ t_atom *at=x->x_at;
+ int i, n=x->x_n_real_ls*x->x_n_ambi;
+ double *dv1=x->x_prod;
+
+ ambi_decode3_transp_back(x);
+ ambi_decode3_mul1(x);
+ ambi_decode3_inverse(x);
+ ambi_decode3_mul2(x);
+ at += 2;
+ for(i=0; i<n; i++)
+ {
+ SETFLOAT(at, (float)(*dv1));
+ dv1++;
+ at++;
+ }
+}
+
+static void ambi_decode3_ipht_ireal_muladd(t_ambi_decode3 *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_atom *at=x->x_at;
+ int i, n=x->x_n_ambi;
+ int pht_index, real_index;
+ double mw;
+ float dat1;
+ double *dv2=x->x_prod;
+
+ if(argc < 3)
+ {
+ post("ambi_decode3 ERROR: ipht_ireal_muladd needs 2 index and 1 mirrorweight: pht_ls_index + real_ls_index + mirror_weight_element");
+ return;
+ }
+ pht_index = (int)atom_getint(argv++) - 1;
+ real_index = (int)atom_getint(argv++) - 1;
+ mw = (double)atom_getfloat(argv);
+
+ if(pht_index < 0)
+ pht_index = 0;
+ if(real_index < 0)
+ real_index = 0;
+ if(real_index >= x->x_n_real_ls)
+ real_index = x->x_n_real_ls - 1;
+ if(pht_index >= x->x_n_pht_ls)
+ pht_index = x->x_n_pht_ls - 1;
+
+ at += 2 + (real_index)*x->x_n_ambi;
+ dv2 += (x->x_n_real_ls+pht_index)*x->x_n_ambi;
+ for(i=0; i<n; i++)
+ {
+ dat1 = atom_getfloat(at);
+ SETFLOAT(at, dat1 + (float)(*dv2*mw));
+ dv2++;
+ at++;
+ }
+}
+
+static void ambi_decode3_end_pseudo_inverse(t_ambi_decode3 *x)
+{
+ outlet_anything(x->x_obj.ob_outlet, x->x_s_matrix, x->x_n_ambi*x->x_n_real_ls+2, x->x_at);
+}
+
+static void ambi_decode3_encode_ls_2d(t_ambi_decode3 *x, int argc, t_atom *argv, int mode)
+{
+ double phi;
+ double *dw = x->x_transp;
+ int index;
+ int order=x->x_n_order;
+
+ if(argc < 2)
+ {
+ post("ambi_decode3 ERROR: ls-input needs 1 index and 1 angle: ls_index + phi [degree]");
+ return;
+ }
+ index = (int)atom_getint(argv++) - 1;
+ phi = (double)atom_getfloat(argv);
+
+ if(index < 0)
+ index = 0;
+
+ if(mode == AMBI_LS_REAL)
+ {
+ if(index >= x->x_n_real_ls)
+ index = x->x_n_real_ls - 1;
+ }
+ else if(mode == AMBI_LS_PHT)
+ {
+ if(x->x_n_pht_ls)
+ {
+ if(index >= x->x_n_pht_ls)
+ index = x->x_n_pht_ls - 1;
+ index += x->x_n_real_ls;
+ }
+ else
+ return;
+ }
+ else
+ return;
+
+ phi *= x->x_pi_over_180;
+
+ dw += index * x->x_n_ambi;
+
+ *dw++ = 1.0;
+ *dw++ = cos(phi);
+ *dw++ = sin(phi);
+
+ if(order >= 2)
+ {
+ *dw++ = cos(2.0*phi);
+ *dw++ = sin(2.0*phi);
+
+ if(order >= 3)
+ {
+ *dw++ = cos(3.0*phi);
+ *dw++ = sin(3.0*phi);
+ if(order >= 4)
+ {
+ *dw++ = cos(4.0*phi);
+ *dw++ = sin(4.0*phi);
+
+ if(order >= 5)
+ {
+ *dw++ = cos(5.0*phi);
+ *dw++ = sin(5.0*phi);
+
+ if(order >= 6)
+ {
+ *dw++ = cos(6.0*phi);
+ *dw++ = sin(6.0*phi);
+
+ if(order >= 7)
+ {
+ *dw++ = cos(7.0*phi);
+ *dw++ = sin(7.0*phi);
+
+ if(order >= 8)
+ {
+ *dw++ = cos(8.0*phi);
+ *dw++ = sin(8.0*phi);
+
+ if(order >= 9)
+ {
+ *dw++ = cos(9.0*phi);
+ *dw++ = sin(9.0*phi);
+
+ if(order >= 10)
+ {
+ *dw++ = cos(10.0*phi);
+ *dw++ = sin(10.0*phi);
+
+ if(order >= 11)
+ {
+ *dw++ = cos(11.0*phi);
+ *dw++ = sin(11.0*phi);
+
+ if(order >= 12)
+ {
+ *dw++ = cos(12.0*phi);
+ *dw++ = sin(12.0*phi);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+static void ambi_decode3_encode_ls_3d(t_ambi_decode3 *x, int argc, t_atom *argv, int mode)
+{
+ double delta, phi;
+ double cd, sd, cd2, cd3, sd2, csd, cp, sp, cp2, sp2, cp3, sp3, cp4, sp4;
+ double *dw = x->x_transp;
+ int index;
+ int order=x->x_n_order;
+
+ if(argc < 3)
+ {
+ post("ambi_decode3 ERROR: ls-input needs 1 index and 2 angles: ls index + delta [degree] + phi [degree]");
+ return;
+ }
+ index = (int)atom_getint(argv++) - 1;
+ delta = atom_getfloat(argv++);
+ phi = atom_getfloat(argv);
+
+ if(index < 0)
+ index = 0;
+
+ if(mode == AMBI_LS_REAL)
+ {
+ if(index >= x->x_n_real_ls)
+ index = x->x_n_real_ls - 1;
+ }
+ else if(mode == AMBI_LS_PHT)
+ {
+ if(x->x_n_pht_ls)
+ {
+ if(index >= x->x_n_pht_ls)
+ index = x->x_n_pht_ls - 1;
+ index += x->x_n_real_ls;
+ }
+ else
+ return;
+ }
+ else
+ return;
+
+ delta *= x->x_pi_over_180;
+ phi *= x->x_pi_over_180;
+
+ dw += index * x->x_n_ambi;
+
+ cd = cos(delta);
+ sd = sin(delta);
+ cp = cos(phi);
+ sp = sin(phi);
+
+
+ *dw++ = 1.0;
+ *dw++ = cd * cp;
+ *dw++ = cd * sp;
+ *dw++ = sd;
+
+ if(order >= 2)
+ {
+ cp2 = cos(2.0*phi);
+ sp2 = sin(2.0*phi);
+ cd2 = cd * cd;
+ sd2 = sd * sd;
+ csd = cd * sd;
+ *dw++ = 0.5 * x->x_sqrt3 * cd2 * cp2;
+ *dw++ = 0.5 * x->x_sqrt3 * cd2 * sp2;
+ *dw++ = x->x_sqrt3 * csd * cp;
+ *dw++ = x->x_sqrt3 * csd * sp;
+ *dw++ = 0.5 * (3.0 * sd2 - 1.0);
+
+ if(order >= 3)
+ {
+ cp3 = cos(3.0*phi);
+ sp3 = sin(3.0*phi);
+ cd3 = cd2 * cd;
+ *dw++ = x->x_sqrt10_4 * cd3 * cp3;
+ *dw++ = x->x_sqrt10_4 * cd3 * sp3;
+ *dw++ = x->x_sqrt15_2 * cd * csd * cp2;
+ *dw++ = x->x_sqrt15_2 * cd * csd * sp2;
+ *dw++ = x->x_sqrt6_4 * cd * (5.0 * sd2 - 1.0) * cp;
+ *dw++ = x->x_sqrt6_4 * cd * (5.0 * sd2 - 1.0) * sp;
+ *dw++ = 0.5 * sd * (5.0 * sd2 - 3.0);
+
+ if(order >= 4)
+ {
+ cp4 = cos(4.0*phi);
+ sp4 = sin(4.0*phi);
+ *dw++ = x->x_sqrt35_8 * cd2 * cd2 * cp4;
+ *dw++ = x->x_sqrt35_8 * cd2 * cd2 * sp4;
+ *dw++ = x->x_sqrt70_4 * cd2 * csd * cp3;
+ *dw++ = x->x_sqrt70_4 * cd2 * csd * sp3;
+ *dw++ = 0.5 * x->x_sqrt5_2 * cd2 * (7.0 * sd2 - 1.0) * cp2;
+ *dw++ = 0.5 * x->x_sqrt5_2 * cd2 * (7.0 * sd2 - 1.0) * sp2;
+ *dw++ = x->x_sqrt10_4 * csd * (7.0 * sd2 - 3.0) * cp;
+ *dw++ = x->x_sqrt10_4 * csd * (7.0 * sd2 - 3.0) * sp;
+ *dw++ = 0.125 * (sd2 * (35.0 * sd2 - 30.0) + 3.0);
+
+ if(order >= 5)
+ {
+ *dw++ = x->x_sqrt126_16 * cd3 * cd2 * cos(5.0*phi);
+ *dw++ = x->x_sqrt126_16 * cd3 * cd2 * sin(5.0*phi);
+ *dw++ = x->x_sqrt315_8 * cd3 * csd * cp4;
+ *dw++ = x->x_sqrt315_8 * cd3 * csd * sp4;
+ *dw++ = 0.25 * x->x_sqrt70_4 * cd3 * (9.0 * sd2 - 1.0) * cp3;
+ *dw++ = 0.25 * x->x_sqrt70_4 * cd3 * (9.0 * sd2 - 1.0) * sp3;
+ *dw++ = x->x_sqrt105_4 * cd * csd * (3.0 * sd2 - 1.0) * cp2;
+ *dw++ = x->x_sqrt105_4 * cd * csd * (3.0 * sd2 - 1.0) * sp2;
+ *dw++ = 0.25 * x->x_sqrt15_2 * cd * (sd2 * (21.0 * sd2 - 14.0) + 1.0) * cp;
+ *dw++ = 0.25 * x->x_sqrt15_2 * cd * (sd2 * (21.0 * sd2 - 14.0) + 1.0) * sp;
+ *dw = 0.125 * sd * (sd2 * (63.0 * sd2 - 70.0) + 15.0);
+ }
+ }
+ }
+ }
+}
+
+static void ambi_decode3_real_ls(t_ambi_decode3 *x, t_symbol *s, int argc, t_atom *argv)
+{
+ if(x->x_n_dim == 2)
+ ambi_decode3_encode_ls_2d(x, argc, argv, AMBI_LS_REAL);
+ else
+ ambi_decode3_encode_ls_3d(x, argc, argv, AMBI_LS_REAL);
+}
+
+static void ambi_decode3_pht_ls(t_ambi_decode3 *x, t_symbol *s, int argc, t_atom *argv)
+{
+ if(x->x_n_dim == 2)
+ ambi_decode3_encode_ls_2d(x, argc, argv, AMBI_LS_PHT);
+ else
+ ambi_decode3_encode_ls_3d(x, argc, argv, AMBI_LS_PHT);
+}
+
+static void ambi_decode3_ambi_weight(t_ambi_decode3 *x, t_symbol *s, int argc, t_atom *argv)
+{
+ if(argc > x->x_n_order)
+ {
+ int i, k=0, n=x->x_n_order;
+ double d;
+
+ x->x_ambi_channel_weight[k] = atom_getfloat(argv++);
+ k++;
+ if(x->x_n_dim == 2)
+ {
+ for(i=1; i<=n; i++)
+ {
+ d = atom_getfloat(argv++);
+ x->x_ambi_channel_weight[k] = d;
+ k++;
+ x->x_ambi_channel_weight[k] = d;
+ k++;
+ }
+ }
+ else
+ {
+ int j, m;
+
+ for(i=1; i<=n; i++)
+ {
+ d = atom_getfloat(argv++);
+ m = 2*i + 1;
+ for(j=0; j<m; j++)
+ {
+ x->x_ambi_channel_weight[k] = d;
+ k++;
+ }
+ }
+ }
+ }
+ else
+ post("ambi_decode3-ERROR: ambi_weight needs %d float weights", x->x_n_order+1);
+}
+
+static void ambi_decode3_sing_range(t_ambi_decode3 *x, t_floatarg f)
+{
+ if(f < 0.0f)
+ x->x_sing_range = -(double)f;
+ else
+ x->x_sing_range = (double)f;
+}
+
+static void ambi_decode3_free(t_ambi_decode3 *x)
+{
+ freebytes(x->x_inv_work1, x->x_n_ambi * x->x_n_ambi * sizeof(double));
+ freebytes(x->x_inv_work2, 2 * x->x_n_ambi * x->x_n_ambi * sizeof(double));
+ freebytes(x->x_inv_buf2, 2 * x->x_n_ambi * sizeof(double));
+ freebytes(x->x_transp, (x->x_n_real_ls+x->x_n_pht_ls) * x->x_n_ambi * sizeof(double));
+ freebytes(x->x_ls_encode, (x->x_n_real_ls+x->x_n_pht_ls) * x->x_n_ambi * sizeof(double));
+ freebytes(x->x_prod, (x->x_n_real_ls+x->x_n_pht_ls) * x->x_n_ambi * sizeof(double));
+ freebytes(x->x_ambi_channel_weight, x->x_n_ambi * sizeof(double));
+ freebytes(x->x_at, (x->x_n_real_ls * x->x_n_ambi + 2) * sizeof(t_atom));
+}
+
+static void *ambi_decode3_new(t_symbol *s, int argc, t_atom *argv)
+{
+ t_ambi_decode3 *x = (t_ambi_decode3 *)pd_new(ambi_decode3_class);
+ int order, dim, i;
+ int n_real_ls=0;/* number of loudspeakers */
+ int n_pht_ls=0;/* number of phantom_loudspeakers */
+
+ if((argc >= 4) &&
+ IS_A_FLOAT(argv,0) &&
+ IS_A_FLOAT(argv,1) &&
+ IS_A_FLOAT(argv,2) &&
+ IS_A_FLOAT(argv,3))
+ {
+ order = (int)atom_getint(argv++);
+ dim = (int)atom_getint(argv++);
+ n_real_ls = (int)atom_getint(argv++);
+ n_pht_ls = (int)atom_getint(argv);
+
+ if(order < 1)
+ order = 1;
+ if(dim != 3)
+ {
+ dim = 2;
+ if(order > 12)
+ order = 12;
+ x->x_n_ambi = 2*order + 1;
+ }
+ else
+ {
+ if(order > 5)
+ order = 5;
+ x->x_n_ambi = (order + 1)*(order + 1);
+ }
+ x->x_n_dim = dim;
+ x->x_n_order = order;
+ if(n_real_ls < 1)
+ n_real_ls = 1;
+ if(n_pht_ls < 0)
+ n_pht_ls = 0;
+ if((n_real_ls + n_pht_ls) < x->x_n_ambi)
+ post("ambi_decode3-WARNING: Number of Loudspeakers < Number of Ambisonic-Channels !!!!");
+
+ x->x_n_real_ls = n_real_ls;
+ x->x_n_pht_ls = n_pht_ls;
+ x->x_inv_work1 = (double *)getbytes(x->x_n_ambi * x->x_n_ambi * sizeof(double));
+ x->x_inv_work2 = (double *)getbytes(2 * x->x_n_ambi * x->x_n_ambi * sizeof(double));
+ x->x_inv_buf2 = (double *)getbytes(2 * x->x_n_ambi * sizeof(double));
+ x->x_transp = (double *)getbytes((x->x_n_real_ls+x->x_n_pht_ls) * x->x_n_ambi * sizeof(double));
+ x->x_ls_encode = (double *)getbytes((x->x_n_real_ls+x->x_n_pht_ls) * x->x_n_ambi * sizeof(double));
+ x->x_prod = (double *)getbytes((x->x_n_real_ls+x->x_n_pht_ls) * x->x_n_ambi * sizeof(double));
+ x->x_ambi_channel_weight = (double *)getbytes(x->x_n_ambi * sizeof(double));
+ x->x_at = (t_atom *)getbytes((x->x_n_real_ls * x->x_n_ambi + 2) * sizeof(t_atom));
+ x->x_s_matrix = gensym("matrix");
+ /*change*/
+ SETFLOAT(x->x_at, (float)x->x_n_real_ls);
+ SETFLOAT(x->x_at+1, (float)x->x_n_ambi);
+
+ x->x_sqrt3 = sqrt(3.0);
+ x->x_sqrt5_2 = sqrt(5.0) / 2.0;
+ x->x_sqrt6_4 = sqrt(6.0) / 4.0;
+ x->x_sqrt10_4 = sqrt(10.0) / 4.0;
+ x->x_sqrt15_2 = sqrt(15.0) / 2.0;
+ x->x_sqrt35_8 = sqrt(35.0) / 8.0;
+ x->x_sqrt70_4 = sqrt(70.0) / 4.0;
+ x->x_sqrt126_16 = sqrt(126.0) / 16.0;
+ x->x_sqrt315_8 = sqrt(315.0) / 8.0;
+ x->x_sqrt105_4 = sqrt(105.0) / 4.0;
+ x->x_pi_over_180 = 4.0 * atan(1.0) / 180.0;
+ x->x_sing_range = 1.0e-10;
+ for(i=0; i<x->x_n_ambi; i++)
+ x->x_ambi_channel_weight[i] = 1.0;
+ outlet_new(&x->x_obj, &s_list);
+ return (x);
+ }
+ else
+ {
+ post("ambi_decode3-ERROR: need 4 float arguments: ambi_order dimension number_of_real_loudspeakers number_of_canceled_phantom_speakers");
+ return(0);
+ }
+}
+
+void ambi_decode3_setup(void)
+{
+ ambi_decode3_class = class_new(gensym("ambi_decode3"), (t_newmethod)ambi_decode3_new, (t_method)ambi_decode3_free,
+ sizeof(t_ambi_decode3), 0, A_GIMME, 0);
+ class_addmethod(ambi_decode3_class, (t_method)ambi_decode3_real_ls, gensym("real_ls"), A_GIMME, 0);
+ class_addmethod(ambi_decode3_class, (t_method)ambi_decode3_pht_ls, gensym("pht_ls"), A_GIMME, 0);
+ class_addmethod(ambi_decode3_class, (t_method)ambi_decode3_ambi_weight, gensym("ambi_weight"), A_GIMME, 0);
+ class_addmethod(ambi_decode3_class, (t_method)ambi_decode3_sing_range, gensym("sing_range"), A_DEFFLOAT, 0);
+ class_addmethod(ambi_decode3_class, (t_method)ambi_decode3_begin_pseudo_inverse, gensym("begin_pseudo_inverse"), 0);
+ class_addmethod(ambi_decode3_class, (t_method)ambi_decode3_ipht_ireal_muladd, gensym("ipht_ireal_muladd"), A_GIMME, 0);
+ class_addmethod(ambi_decode3_class, (t_method)ambi_decode3_end_pseudo_inverse, gensym("end_pseudo_inverse"), 0);
+ class_sethelpsymbol(ambi_decode3_class, gensym("iemhelp2/help-ambi_decode3"));
+}
diff --git a/src/ambi_decode_cube.c b/src/ambi_decode_cube.c
new file mode 100644
index 0000000..741781d
--- /dev/null
+++ b/src/ambi_decode_cube.c
@@ -0,0 +1,799 @@
+/* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution.
+
+iem_ambi written by Thomas Musil, Copyright (c) IEM KUG Graz Austria 2000 - 2005 */
+
+#ifdef NT
+#pragma warning( disable : 4244 )
+#pragma warning( disable : 4305 )
+#endif
+
+
+#include "m_pd.h"
+#include "iemlib.h"
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+
+
+/* -------------------------- ambi_decode_cube ------------------------------ */
+/*
+ ** berechnet ein reduziertes Ambisonic-Decoder-Set in die HRTF-Spektren **
+ ** Inputs: ls + Liste von 3 floats: Index [1 .. 25] + Elevation [-90 .. +90 degree] + Azimut [0 .. 360 degree] **
+ ** Inputs: calc_inv **
+ ** Inputs: load_HRIR + float index1..25 **
+ ** Outputs: List of 2 symbols: left-HRIR-File-name + HRIR-table-name **
+ ** Inputs: calc_reduced **
+ ** "output" ... writes the HRTF into tables **
+ ** **
+ ** **
+ ** setzt voraus , dass die HRIR-tabele-names von LS1_L_HRIR .. LS25_L_HRIR heissen und existieren **
+ ** setzt voraus , dass die HRTF-tabele-names von LS1_HRTF_re .. LS25_HRTF_re heissen und existieren **
+ ** setzt voraus , dass die HRTF-tabele-names von LS1_HRTF_im .. LS25_HRTF_im heissen und existieren **
+ */
+
+typedef struct _ambi_decode_cube
+{
+ t_object x_obj;
+ t_atom *x_at;
+ double *x_inv_work1;
+ double *x_inv_work2;
+ double *x_inv_buf2;
+ double *x_transp;
+ double *x_ls_encode;
+ double *x_prod;
+ double *x_ambi_channel_weight;
+ double x_mir_wght;
+ int x_n_ambi;
+ int x_n_order;
+ int x_n_ls;
+ int x_n_phls;
+ int x_n_dim;
+ int x_realsum_beg;
+ int x_realsum_end;
+ int x_mirrorsum_beg;
+ int x_mirrorsum_end;
+ t_symbol *x_s_matrix;
+ double x_sqrt3;
+ double x_sqrt10_4;
+ double x_sqrt15_2;
+ double x_sqrt6_4;
+ double x_sqrt35_8;
+ double x_sqrt70_4;
+ double x_sqrt5_2;
+ double x_sqrt126_16;
+ double x_sqrt315_8;
+ double x_sqrt105_4;
+ double x_pi_over_180;
+} t_ambi_decode_cube;
+
+static t_class *ambi_decode_cube_class;
+
+static void ambi_decode_cube_copy_row2buf(t_ambi_decode_cube *x, int row)
+{
+ int n_ambi2 = 2*x->x_n_ambi;
+ int i;
+ double *dw=x->x_inv_work2;
+ double *db=x->x_inv_buf2;
+
+ dw += row*n_ambi2;
+ for(i=0; i<n_ambi2; i++)
+ *db++ = *dw++;
+}
+
+static void ambi_decode_cube_copy_buf2row(t_ambi_decode_cube *x, int row)
+{
+ int n_ambi2 = 2*x->x_n_ambi;
+ int i;
+ double *dw=x->x_inv_work2;
+ double *db=x->x_inv_buf2;
+
+ dw += row*n_ambi2;
+ for(i=0; i<n_ambi2; i++)
+ *dw++ = *db++;
+}
+
+static void ambi_decode_cube_copy_row2row(t_ambi_decode_cube *x, int src_row, int dst_row)
+{
+ int n_ambi2 = 2*x->x_n_ambi;
+ int i;
+ double *dw_src=x->x_inv_work2;
+ double *dw_dst=x->x_inv_work2;
+
+ dw_src += src_row*n_ambi2;
+ dw_dst += dst_row*n_ambi2;
+ for(i=0; i<n_ambi2; i++)
+ *dw_dst++ = *dw_src++;
+}
+
+static void ambi_decode_cube_xch_rows(t_ambi_decode_cube *x, int row1, int row2)
+{
+ ambi_decode_cube_copy_row2buf(x, row1);
+ ambi_decode_cube_copy_row2row(x, row2, row1);
+ ambi_decode_cube_copy_buf2row(x, row2);
+}
+
+static void ambi_decode_cube_mul_row(t_ambi_decode_cube *x, int row, double mul)
+{
+ int n_ambi2 = 2*x->x_n_ambi;
+ int i;
+ double *dw=x->x_inv_work2;
+
+ dw += row*n_ambi2;
+ for(i=0; i<n_ambi2; i++)
+ {
+ (*dw) *= mul;
+ dw++;
+ }
+}
+
+static void ambi_decode_cube_mul_buf_and_add2row(t_ambi_decode_cube *x, int row, double mul)
+{
+ int n_ambi2 = 2*x->x_n_ambi;
+ int i;
+ double *dw=x->x_inv_work2;
+ double *db=x->x_inv_buf2;
+
+ dw += row*n_ambi2;
+ for(i=0; i<n_ambi2; i++)
+ {
+ *dw += (*db)*mul;
+ dw++;
+ db++;
+ }
+}
+
+static int ambi_decode_cube_eval_which_element_of_col_not_zero(t_ambi_decode_cube *x, int col, int start_row)
+{
+ int n_ambi = x->x_n_ambi;
+ int n_ambi2 = 2*n_ambi;
+ int i, j;
+ double *dw=x->x_inv_work2;
+ int ret=-1;
+
+ dw += start_row*n_ambi2 + col;
+ j = 0;
+ for(i=start_row; i<n_ambi; i++)
+ {
+ if((*dw > 1.0e-10) || (*dw < -1.0e-10))
+ {
+ ret = i;
+ i = n_ambi+1;
+ }
+ dw += n_ambi2;
+ }
+ return(ret);
+}
+
+static void ambi_decode_cube_mul1(t_ambi_decode_cube *x)
+{
+ double *vec1, *beg1=x->x_ls_encode;
+ double *vec2, *beg2=x->x_ls_encode;
+ double *inv=x->x_inv_work1;
+ double sum;
+ int n_ls=x->x_n_ls+x->x_n_phls;
+ int n_ambi=x->x_n_ambi;
+ int i, j, k;
+
+ for(k=0; k<n_ambi; k++)
+ {
+ beg2=x->x_ls_encode;
+ for(j=0; j<n_ambi; j++)
+ {
+ sum = 0.0;
+ vec1 = beg1;
+ vec2 = beg2;
+ for(i=0; i<n_ls; i++)
+ {
+ sum += *vec1++ * *vec2++;
+ }
+ beg2 += n_ls;
+ *inv++ = sum;
+ }
+ beg1 += n_ls;
+ }
+}
+
+static void ambi_decode_cube_mul2(t_ambi_decode_cube *x)
+{
+ int n_ls=x->x_n_ls+x->x_n_phls;
+ int n_ambi=x->x_n_ambi;
+ int n_ambi2=2*n_ambi;
+ int i, j, k;
+ double *vec1, *beg1=x->x_transp;
+ double *vec2, *beg2=x->x_inv_work2+n_ambi;
+ double *vec3=x->x_prod;
+ double *acw_vec=x->x_ambi_channel_weight;
+ double sum;
+
+ for(k=0; k<n_ls; k++)
+ {
+ beg2=x->x_inv_work2+n_ambi;
+ for(j=0; j<n_ambi; j++)
+ {
+ sum = 0.0;
+ vec1 = beg1;
+ vec2 = beg2;
+ for(i=0; i<n_ambi; i++)
+ {
+ sum += *vec1++ * *vec2;
+ vec2 += n_ambi2;
+ }
+ beg2++;
+ *vec3++ = sum * acw_vec[j];
+ }
+ beg1 += n_ambi;
+ }
+}
+
+static void ambi_decode_cube_transp_back(t_ambi_decode_cube *x)
+{
+ double *vec, *transp=x->x_transp;
+ double *straight=x->x_ls_encode;
+ int n_ls=x->x_n_ls+x->x_n_phls;
+ int n_ambi=x->x_n_ambi;
+ int i, j;
+
+ for(j=0; j<n_ambi; j++)
+ {
+ vec = transp;
+ for(i=0; i<n_ls; i++)
+ {
+ *straight++ = *vec;
+ vec += n_ambi;
+ }
+ transp++;
+ }
+}
+
+static void ambi_decode_cube_inverse(t_ambi_decode_cube *x)
+{
+ int n_ambi = x->x_n_ambi;
+ int n_ambi2 = 2*n_ambi;
+ int i, j, nz;
+ int r,c;
+ double *src=x->x_inv_work1;
+ double *db=x->x_inv_work2;
+ double rcp, *dv;
+
+ dv = db;
+ for(i=0; i<n_ambi; i++) /* init */
+ {
+ for(j=0; j<n_ambi; j++)
+ {
+ *dv++ = *src++;
+ }
+ for(j=0; j<n_ambi; j++)
+ {
+ if(j == i)
+ *dv++ = 1.0;
+ else
+ *dv++ = 0.0;
+ }
+ }
+
+ /* make 1 in main-diagonale, and 0 below */
+ for(i=0; i<n_ambi; i++)
+ {
+ nz = ambi_decode_cube_eval_which_element_of_col_not_zero(x, i, i);
+ if(nz < 0)
+ {
+ post("ambi_decode_cube ERROR: matrix not regular !!!!");
+ return;
+ }
+ else
+ {
+ if(nz != i)
+ ambi_decode_cube_xch_rows(x, i, nz);
+ dv = db + i*n_ambi2 + i;
+ rcp = 1.0 /(*dv);
+ ambi_decode_cube_mul_row(x, i, rcp);
+ ambi_decode_cube_copy_row2buf(x, i);
+ for(j=i+1; j<n_ambi; j++)
+ {
+ dv += n_ambi2;
+ rcp = -(*dv);
+ ambi_decode_cube_mul_buf_and_add2row(x, j, rcp);
+ }
+ }
+ }
+
+ /* make 0 above the main diagonale */
+ for(i=n_ambi-1; i>=0; i--)
+ {
+ dv = db + i*n_ambi2 + i;
+ ambi_decode_cube_copy_row2buf(x, i);
+ for(j=i-1; j>=0; j--)
+ {
+ dv -= n_ambi2;
+ rcp = -(*dv);
+ ambi_decode_cube_mul_buf_and_add2row(x, j, rcp);
+ }
+ }
+
+ post("matrix_inverse regular");
+}
+
+static void ambi_decode_cube_pinv(t_ambi_decode_cube *x)
+{
+ t_atom *at=x->x_at;
+
+ ambi_decode_cube_transp_back(x);
+ ambi_decode_cube_mul1(x);
+ ambi_decode_cube_inverse(x);
+ ambi_decode_cube_mul2(x);
+ if((x->x_mirrorsum_end > x->x_mirrorsum_beg)&&
+ (x->x_realsum_end > x->x_realsum_beg)&&
+ ((x->x_mirrorsum_end - x->x_mirrorsum_beg) == (x->x_realsum_end - x->x_realsum_beg)))
+ {
+ double *mir=x->x_prod+x->x_mirrorsum_beg*x->x_n_ambi;
+ double *real=x->x_prod+x->x_realsum_beg*x->x_n_ambi;
+ double mwght=x->x_mir_wght;
+ int i, n=(x->x_mirrorsum_end - x->x_mirrorsum_beg)*x->x_n_ambi;
+
+// post("mirror");
+ for(i=0; i<n; i++)
+ real[i] += mir[i]*mwght;
+
+ n = x->x_mirrorsum_beg*x->x_n_ambi;
+ real=x->x_prod;
+ SETFLOAT(at, (float)x->x_n_ambi);
+ at++;
+ SETFLOAT(at, (float)x->x_mirrorsum_beg);
+ at++;
+ for(i=0; i<n; i++)
+ {
+ SETFLOAT(at, (float)(*real));
+ real++;
+ at++;
+ }
+ outlet_anything(x->x_obj.ob_outlet, x->x_s_matrix, n+2, x->x_at);
+ }
+ else
+ {
+ int i, n=x->x_n_ls*x->x_n_ambi;
+ double *dv=x->x_prod;
+
+// post("real");
+ SETFLOAT(at, (float)x->x_n_ambi);
+ at++;
+ SETFLOAT(at, (float)x->x_n_ls);
+ at++;
+ for(i=0; i<n; i++)
+ {
+ SETFLOAT(at, (float)(*dv));
+ dv++;
+ at++;
+ }
+ outlet_anything(x->x_obj.ob_outlet, x->x_s_matrix, n+2, x->x_at);
+ }
+}
+
+static void ambi_decode_cube_encode_ls_2d(t_ambi_decode_cube *x, int argc, t_atom *argv, int ls0_ph1)
+{
+ double phi;
+ double *dw = x->x_transp;
+ int index;
+ int n_ls=x->x_n_ls;
+ int n_phls=x->x_n_phls;
+ int order=x->x_n_order;
+
+ if(argc < 2)
+ {
+ post("ambi_decode_cube ERROR: ls-input needs 1 index and 1 angle: ls_index + phi [degree]");
+ return;
+ }
+ index = (int)atom_getint(argv++) - 1;
+ phi = (double)atom_getfloat(argv);
+
+ if(index < 0)
+ index = 0;
+ if(ls0_ph1)
+ {
+ if(n_phls)
+ {
+ if(index >= n_phls)
+ index = n_phls - 1;
+ index += n_ls;
+ }
+ else
+ return;
+ }
+ else
+ {
+ if(index >= n_ls)
+ index = n_ls - 1;
+ }
+
+ phi *= x->x_pi_over_180;
+
+ dw += index * x->x_n_ambi;
+
+ *dw++ = 1.0;
+ *dw++ = cos(phi);
+ *dw++ = sin(phi);
+
+ if(order >= 2)
+ {
+ *dw++ = cos(2.0*phi);
+ *dw++ = sin(2.0*phi);
+
+ if(order >= 3)
+ {
+ *dw++ = cos(3.0*phi);
+ *dw++ = sin(3.0*phi);
+
+ if(order >= 4)
+ {
+ *dw++ = cos(4.0*phi);
+ *dw++ = sin(4.0*phi);
+
+ if(order >= 5)
+ {
+ *dw++ = cos(5.0*phi);
+ *dw++ = sin(5.0*phi);
+
+ if(order >= 6)
+ {
+ *dw++ = cos(6.0*phi);
+ *dw++ = sin(6.0*phi);
+
+ if(order >= 7)
+ {
+ *dw++ = cos(7.0*phi);
+ *dw++ = sin(7.0*phi);
+
+ if(order >= 8)
+ {
+ *dw++ = cos(8.0*phi);
+ *dw++ = sin(8.0*phi);
+
+ if(order >= 9)
+ {
+ *dw++ = cos(9.0*phi);
+ *dw++ = sin(9.0*phi);
+
+ if(order >= 10)
+ {
+ *dw++ = cos(10.0*phi);
+ *dw++ = sin(10.0*phi);
+
+ if(order >= 11)
+ {
+ *dw++ = cos(11.0*phi);
+ *dw++ = sin(11.0*phi);
+
+ if(order >= 12)
+ {
+ *dw++ = cos(12.0*phi);
+ *dw++ = sin(12.0*phi);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+static void ambi_decode_cube_encode_ls_3d(t_ambi_decode_cube *x, int argc, t_atom *argv, int ls0_ph1)
+{
+ double delta, phi;
+ double cd, sd, cd2, cd3, sd2, csd, cp, sp, cp2, sp2, cp3, sp3, cp4, sp4;
+ double *dw = x->x_transp;
+ int index;
+ int n_ls=x->x_n_ls;
+ int n_phls=x->x_n_phls;
+ int order=x->x_n_order;
+
+ if(argc < 3)
+ {
+ post("ambi_decode_cube ERROR: ls-input needs 1 index and 2 angles: ls index + delta [degree] + phi [degree]");
+ return;
+ }
+ index = (int)atom_getint(argv++) - 1;
+ delta = atom_getfloat(argv++);
+ phi = atom_getfloat(argv);
+
+ if(index < 0)
+ index = 0;
+ if(ls0_ph1)
+ {
+ if(n_phls)
+ {
+ if(index >= n_phls)
+ index = n_phls - 1;
+ index += n_ls;
+ }
+ else
+ return;
+ }
+ else
+ {
+ if(index >= n_ls)
+ index = n_ls - 1;
+ }
+
+ delta *= x->x_pi_over_180;
+ phi *= x->x_pi_over_180;
+
+ dw += index * x->x_n_ambi;
+
+ cd = cos(delta);
+ sd = sin(delta);
+ cp = cos(phi);
+ sp = sin(phi);
+
+ *dw++ = 1.0;
+ *dw++ = cd * cp;
+ *dw++ = cd * sp;
+ *dw++ = sd;
+
+ if(order >= 2)
+ {
+ cp2 = cos(2.0*phi);
+ sp2 = sin(2.0*phi);
+ cd2 = cd * cd;
+ sd2 = sd * sd;
+ csd = cd * sd;
+ *dw++ = 0.5 * x->x_sqrt3 * cd2 * cp2;
+ *dw++ = 0.5 * x->x_sqrt3 * cd2 * sp2;
+ *dw++ = x->x_sqrt3 * csd * cp;
+ *dw++ = x->x_sqrt3 * csd * sp;
+ *dw++ = 0.5 * (3.0 * sd2 - 1.0);
+
+ if(order >= 3)
+ {
+ cp3 = cos(3.0*phi);
+ sp3 = sin(3.0*phi);
+ cd3 = cd2 * cd;
+ *dw++ = x->x_sqrt10_4 * cd3 * cp3;
+ *dw++ = x->x_sqrt10_4 * cd3 * sp3;
+ *dw++ = x->x_sqrt15_2 * cd * csd * cp2;
+ *dw++ = x->x_sqrt15_2 * cd * csd * sp2;
+ *dw++ = x->x_sqrt6_4 * cd * (5.0 * sd2 - 1.0) * cp;
+ *dw++ = x->x_sqrt6_4 * cd * (5.0 * sd2 - 1.0) * sp;
+ *dw++ = 0.5 * sd * (5.0 * sd2 - 3.0);
+
+ if(order >= 4)
+ {
+ cp4 = cos(4.0*phi);
+ sp4 = sin(4.0*phi);
+ *dw++ = x->x_sqrt35_8 * cd2 * cd2 * cp4;
+ *dw++ = x->x_sqrt35_8 * cd2 * cd2 * sp4;
+ *dw++ = x->x_sqrt70_4 * cd2 * csd * cp3;
+ *dw++ = x->x_sqrt70_4 * cd2 * csd * sp3;
+ *dw++ = 0.5 * x->x_sqrt5_2 * cd2 * (7.0 * sd2 - 1.0) * cp2;
+ *dw++ = 0.5 * x->x_sqrt5_2 * cd2 * (7.0 * sd2 - 1.0) * sp2;
+ *dw++ = x->x_sqrt10_4 * csd * (7.0 * sd2 - 3.0) * cp;
+ *dw++ = x->x_sqrt10_4 * csd * (7.0 * sd2 - 3.0) * sp;
+ *dw++ = 0.125 * (sd2 * (35.0 * sd2 - 30.0) + 3.0);
+
+ if(order >= 5)
+ {
+ *dw++ = x->x_sqrt126_16 * cd3 * cd2 * cos(5.0*phi);
+ *dw++ = x->x_sqrt126_16 * cd3 * cd2 * sin(5.0*phi);
+ *dw++ = x->x_sqrt315_8 * cd3 * csd * cp4;
+ *dw++ = x->x_sqrt315_8 * cd3 * csd * sp4;
+ *dw++ = 0.25 * x->x_sqrt70_4 * cd3 * (9.0 * sd2 - 1.0) * cp3;
+ *dw++ = 0.25 * x->x_sqrt70_4 * cd3 * (9.0 * sd2 - 1.0) * sp3;
+ *dw++ = x->x_sqrt105_4 * cd * csd * (3.0 * sd2 - 1.0) * cp2;
+ *dw++ = x->x_sqrt105_4 * cd * csd * (3.0 * sd2 - 1.0) * sp2;
+ *dw++ = 0.25 * x->x_sqrt15_2 * cd * (sd2 * (21.0 * sd2 - 14.0) + 1.0) * cp;
+ *dw++ = 0.25 * x->x_sqrt15_2 * cd * (sd2 * (21.0 * sd2 - 14.0) + 1.0) * sp;
+ *dw = 0.125 * sd * (sd2 * (63.0 * sd2 - 70.0) + 15.0);
+ }
+ }
+ }
+ }
+}
+
+static void ambi_decode_cube_ls(t_ambi_decode_cube *x, t_symbol *s, int argc, t_atom *argv)
+{
+ if(x->x_n_dim == 2)
+ ambi_decode_cube_encode_ls_2d(x, argc, argv, 0);
+ else
+ ambi_decode_cube_encode_ls_3d(x, argc, argv, 0);
+}
+
+static void ambi_decode_cube_phls(t_ambi_decode_cube *x, t_symbol *s, int argc, t_atom *argv)
+{
+ if(x->x_n_dim == 2)
+ ambi_decode_cube_encode_ls_2d(x, argc, argv, 1);
+ else
+ ambi_decode_cube_encode_ls_3d(x, argc, argv, 1);
+}
+
+static void ambi_decode_cube_ambi_weight(t_ambi_decode_cube *x, t_symbol *s, int argc, t_atom *argv)
+{
+ if(argc > x->x_n_order)
+ {
+ int i, k=0, n=x->x_n_order;
+ double d;
+
+ x->x_ambi_channel_weight[k] = atom_getfloat(argv++);
+ k++;
+ if(x->x_n_dim == 2)
+ {
+ for(i=1; i<=n; i++)
+ {
+ d = atom_getfloat(argv++);
+ x->x_ambi_channel_weight[k] = d;
+ k++;
+ x->x_ambi_channel_weight[k] = d;
+ k++;
+ }
+ }
+ else
+ {
+ int j, m;
+
+ for(i=1; i<=n; i++)
+ {
+ d = atom_getfloat(argv++);
+ m = 2*i + 1;
+ for(j=0; j<m; j++)
+ {
+ x->x_ambi_channel_weight[k] = d;
+ k++;
+ }
+ }
+ }
+ }
+ else
+ post("ambi_decode_cube-ERROR: ambi_weight needs %d float weights", x->x_n_order+1);
+}
+
+static void ambi_decode_cube_mirror_weight(t_ambi_decode_cube *x, t_floatarg mwght)
+{
+ x->x_mir_wght = mwght;
+}
+
+static void ambi_decode_cube_mirror_range(t_ambi_decode_cube *x, t_floatarg beg, t_floatarg end)
+{
+ int b=(int)beg;
+ int e=(int)end;
+
+ if(b < 0)
+ b = 0;
+ if(b > x->x_n_ls)
+ b = x->x_n_ls;
+ if(e < 0)
+ e = 0;
+ if(e > x->x_n_ls)
+ e = x->x_n_ls;
+ x->x_mirrorsum_beg = b;
+ x->x_mirrorsum_end = e;
+}
+
+static void ambi_decode_cube_real_sum_range(t_ambi_decode_cube *x, t_floatarg beg, t_floatarg end)
+{
+ int b=(int)beg;
+ int e=(int)end;
+
+ if(b < 0)
+ b = 0;
+ if(b > x->x_n_ls)
+ b = x->x_n_ls;
+ if(e < 0)
+ e = 0;
+ if(e > x->x_n_ls)
+ e = x->x_n_ls;
+ x->x_realsum_beg = b;
+ x->x_realsum_end = e;
+}
+
+static void ambi_decode_cube_free(t_ambi_decode_cube *x)
+{
+ freebytes(x->x_inv_work1, x->x_n_ambi * x->x_n_ambi * sizeof(double));
+ freebytes(x->x_inv_work2, 2 * x->x_n_ambi * x->x_n_ambi * sizeof(double));
+ freebytes(x->x_inv_buf2, 2 * x->x_n_ambi * sizeof(double));
+ freebytes(x->x_transp, (x->x_n_ls+x->x_n_phls) * x->x_n_ambi * sizeof(double));
+ freebytes(x->x_ls_encode, (x->x_n_ls+x->x_n_phls) * x->x_n_ambi * sizeof(double));
+ freebytes(x->x_prod, (x->x_n_ls+x->x_n_phls) * x->x_n_ambi * sizeof(double));
+ freebytes(x->x_ambi_channel_weight, x->x_n_ambi * sizeof(double));
+ freebytes(x->x_at, (x->x_n_ls * x->x_n_ambi + 2) * sizeof(t_atom));
+}
+
+static void *ambi_decode_cube_new(t_symbol *s, int argc, t_atom *argv)
+{
+ t_ambi_decode_cube *x = (t_ambi_decode_cube *)pd_new(ambi_decode_cube_class);
+ int nls, order, dim, i;
+ int nphls=0;/* phantom_loudspeaker */
+
+ if(argc < 3)
+ {
+ post("ambi_decode_cube-ERROR: need following arguments: ambi_order dimension number_of_loudspeakers (number_of_phantom_speakers)");
+ return(0);
+ }
+ else
+ {
+ order = (int)atom_getint(argv++);
+ dim = (int)atom_getint(argv++);
+ nls = (int)atom_getint(argv++);
+ if((argc > 3)&&IS_A_FLOAT(argv,0))
+ nphls=(int)atom_getint(argv);
+
+ if(order < 1)
+ order = 1;
+ if(dim != 3)
+ {
+ dim = 2;
+ if(order > 12)
+ order = 12;
+ x->x_n_ambi = 2*order + 1;
+ }
+ else
+ {
+ if(order > 5)
+ order = 5;
+ x->x_n_ambi = (order + 1)*(order + 1);
+ }
+ x->x_n_dim = dim;
+ x->x_n_order = order;
+ if(nls < 1)
+ nls = 1;
+ if(nphls < 0)
+ nphls = 0;
+ if(nls < x->x_n_ambi)
+ post("ambi_decode_cube-WARNING: Number of Loudspeakers < Number of Ambisonic-Channels !!!!");
+ if(nphls > nls)
+ {
+ post("ambi_decode_cube-WARNING: Number of Phantom-Loudspeakers > Number of Loudspeakers !!!!");
+ nphls = nls;
+ }
+ x->x_n_ls = nls;
+ x->x_n_phls = nphls;
+ x->x_inv_work1 = (double *)getbytes(x->x_n_ambi * x->x_n_ambi * sizeof(double));
+ x->x_inv_work2 = (double *)getbytes(2 * x->x_n_ambi * x->x_n_ambi * sizeof(double));
+ x->x_inv_buf2 = (double *)getbytes(2 * x->x_n_ambi * sizeof(double));
+ x->x_transp = (double *)getbytes((x->x_n_ls+x->x_n_phls) * x->x_n_ambi * sizeof(double));
+ x->x_ls_encode = (double *)getbytes((x->x_n_ls+x->x_n_phls) * x->x_n_ambi * sizeof(double));
+ x->x_prod = (double *)getbytes((x->x_n_ls+x->x_n_phls) * x->x_n_ambi * sizeof(double));
+ x->x_ambi_channel_weight = (double *)getbytes(x->x_n_ambi * sizeof(double));
+ x->x_at = (t_atom *)getbytes((x->x_n_ls * x->x_n_ambi + 2) * sizeof(t_atom));
+ x->x_s_matrix = gensym("matrix");
+ /*change*/
+ SETFLOAT(x->x_at, (float)x->x_n_ls);
+ SETFLOAT(x->x_at+1, (float)x->x_n_ambi);
+ x->x_sqrt3 = sqrt(3.0);
+ x->x_sqrt5_2 = sqrt(5.0) / 2.0;
+ x->x_sqrt6_4 = sqrt(6.0) / 4.0;
+ x->x_sqrt10_4 = sqrt(10.0) / 4.0;
+ x->x_sqrt15_2 = sqrt(15.0) / 2.0;
+ x->x_sqrt35_8 = sqrt(35.0) / 8.0;
+ x->x_sqrt70_4 = sqrt(70.0) / 4.0;
+ x->x_sqrt126_16 = sqrt(126.0) / 16.0;
+ x->x_sqrt315_8 = sqrt(315.0) / 8.0;
+ x->x_sqrt105_4 = sqrt(105.0) / 4.0;
+ x->x_pi_over_180 = 4.0 * atan(1.0) / 180.0;
+ x->x_mirrorsum_beg = x->x_n_ls;
+ x->x_mirrorsum_end = x->x_n_ls;
+ x->x_realsum_beg = 0;
+ x->x_realsum_end = 0;
+ for(i=0; i<x->x_n_ambi; i++)
+ x->x_ambi_channel_weight[i] = 1.0;
+ x->x_mir_wght = 1.0;
+ outlet_new(&x->x_obj, &s_list);
+ return (x);
+ }
+}
+
+void ambi_decode_cube_setup(void)
+{
+ ambi_decode_cube_class = class_new(gensym("ambi_decode_cube"), (t_newmethod)ambi_decode_cube_new, (t_method)ambi_decode_cube_free,
+ sizeof(t_ambi_decode_cube), 0, A_GIMME, 0);
+ class_addmethod(ambi_decode_cube_class, (t_method)ambi_decode_cube_ls, gensym("ls"), A_GIMME, 0);
+ class_addmethod(ambi_decode_cube_class, (t_method)ambi_decode_cube_phls, gensym("phls"), A_GIMME, 0);
+ class_addmethod(ambi_decode_cube_class, (t_method)ambi_decode_cube_ambi_weight, gensym("ambi_weight"), A_GIMME, 0);
+ class_addmethod(ambi_decode_cube_class, (t_method)ambi_decode_cube_pinv, gensym("pinv"), 0);
+ class_addmethod(ambi_decode_cube_class, (t_method)ambi_decode_cube_mirror_weight, gensym("mirror_weight"), A_DEFFLOAT, 0);
+ class_addmethod(ambi_decode_cube_class, (t_method)ambi_decode_cube_mirror_range, gensym("mirror_range"), A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addmethod(ambi_decode_cube_class, (t_method)ambi_decode_cube_real_sum_range, gensym("real_sum_range"), A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_sethelpsymbol(ambi_decode_cube_class, gensym("iemhelp/help-ambi_decode_cube"));
+}
diff --git a/src/ambi_encode.c b/src/ambi_encode.c
new file mode 100644
index 0000000..3ca69a2
--- /dev/null
+++ b/src/ambi_encode.c
@@ -0,0 +1,433 @@
+/* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution.
+
+iem_ambi written by Thomas Musil, Copyright (c) IEM KUG Graz Austria 2000 - 2005 */
+
+#ifdef NT
+#pragma warning( disable : 4244 )
+#pragma warning( disable : 4305 )
+#endif
+
+
+#include "m_pd.h"
+#include "iemlib.h"
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+/* -------------------------- ambi_encode ------------------------------ */
+
+typedef struct _ambi_encode
+{
+ t_object x_obj;
+ t_atom *x_at;
+ int x_size;
+ int x_size2d;
+ int x_size3d;
+ float x_sqrt3;
+ float x_sqrt10_4;
+ float x_sqrt15;
+ float x_sqrt6_4;
+ float x_sqrt35_2;
+ float x_sqrt70_4;
+ float x_sqrt5_2;
+ float x_sqrt126_16;
+ float x_sqrt315_2;
+ float x_sqrt105_2;
+ float x_pi_over_180;
+ float *x_ambi_order_weight;
+ int x_colrow;
+ int x_n_order;
+} t_ambi_encode;
+
+static t_class *ambi_encode_class;
+
+static void ambi_encode_ambi_weight(t_ambi_encode *x, t_symbol *s, int argc, t_atom *argv)
+{
+ if(argc > x->x_n_order)
+ {
+ int i, n=x->x_n_order;
+
+ for(i=0; i<=n; i++)
+ {
+ x->x_ambi_order_weight[i] = atom_getfloat(argv++);
+ }
+ }
+ else
+ post("ambi_encode-ERROR: ambi_weight needs %d float weights", x->x_n_order+1);
+}
+
+static void ambi_encode_do_2d(t_ambi_encode *x, t_floatarg phi)
+{
+ float c, s, cc, ss, c2, s2, c3, s3, s4, c4, s5, c5, s6, c6;
+ float *awght = x->x_ambi_order_weight;
+ t_atom *at=x->x_at;
+
+ phi *= x->x_pi_over_180;
+ c = cos(phi);
+ s = sin(phi);
+ cc = c*c;
+ ss = s*s;
+
+ SETFLOAT(at, (float)x->x_colrow);
+ at++;
+
+ SETFLOAT(at, awght[0]);
+ at++;
+
+ SETFLOAT(at, c*awght[1]);
+ at++;
+ SETFLOAT(at, s*awght[1]);
+ at++;
+
+ if(x->x_n_order >= 2)
+ {
+ c2 = cc - ss;
+ s2 = 2.0f*s*c;
+ SETFLOAT(at, c2*awght[2]);
+ at++;
+ SETFLOAT(at, s2*awght[2]);
+ at++;
+
+ if(x->x_n_order >= 3)
+ {
+ c3 = c*(4.0f*cc - 3.0f);
+ s3 = s*(3.0f - 4.0f*ss);
+ SETFLOAT(at, c3*awght[3]);
+ at++;
+ SETFLOAT(at, s3*awght[3]);
+ at++;
+
+ if(x->x_n_order >= 4)
+ {
+ c4 = 1.0f + 8.0f*cc*(cc - 1.0f);
+ s4 = 2.0f*s2*c2;
+ SETFLOAT(at, c4*awght[4]);
+ at++;
+ SETFLOAT(at, s4*awght[4]);
+ at++;
+
+ if(x->x_n_order >= 5)
+ {
+ c5 = c*(1.0f + 4.0f*ss*(ss - 3.0f*cc));
+ s5 = s*(1.0f + 4.0f*cc*(cc - 3.0f*ss));
+ SETFLOAT(at, c5*awght[5]);
+ at++;
+ SETFLOAT(at, s5*awght[5]);
+ at++;
+
+ if(x->x_n_order >= 6)
+ {
+ c6 = c3*c3 - s3*s3;
+ s6 = 2.0f*s3*c3;
+ SETFLOAT(at, c6*awght[6]);
+ at++;
+ SETFLOAT(at, s6*awght[6]);
+ at++;
+
+ if(x->x_n_order >= 7)
+ {
+ SETFLOAT(at, cos(7.0f*phi)*awght[7]);
+ at++;
+ SETFLOAT(at, sin(7.0f*phi)*awght[7]);
+ at++;
+
+ if(x->x_n_order >= 8)
+ {
+ SETFLOAT(at, (c4*c4 - s4*s4)*awght[8]);
+ at++;
+ SETFLOAT(at, 2.0f*s4*c4*awght[8]);
+ at++;
+
+ if(x->x_n_order >= 9)
+ {
+ SETFLOAT(at, cos(9.0f*phi)*awght[9]);
+ at++;
+ SETFLOAT(at, sin(9.0f*phi)*awght[9]);
+ at++;
+
+ if(x->x_n_order >= 10)
+ {
+ SETFLOAT(at, (c5*c5 - s5*s5)*awght[10]);
+ at++;
+ SETFLOAT(at, 2.0f*s5*c5*awght[10]);
+ at++;
+
+ if(x->x_n_order >= 11)
+ {
+ SETFLOAT(at, cos(11.0f*phi)*awght[11]);
+ at++;
+ SETFLOAT(at, sin(11.0f*phi)*awght[11]);
+ at++;
+
+ if(x->x_n_order >= 12)
+ {
+ SETFLOAT(at, (c6*c6 - s6*s6)*awght[12]);
+ at++;
+ SETFLOAT(at, 2.0f*s6*c6*awght[12]);
+ }
+
+ if(x->x_n_order >= 13)
+ post("ambi_encode-ERROR: do not support Ambisonic-Order greater than 12 in 2d !!!");
+
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+static void ambi_encode_do_3d(t_ambi_encode *x, t_symbol *s, int argc, t_atom *argv)
+{
+ float delta, phi;
+ float cd, x1, y, z, x2, y2, z2, x2my2, x2m3y2, p3x2my2, xy, xz, yz, m1p5z2, m1p7z2, m3p7z2;
+ float *awght = x->x_ambi_order_weight;
+ t_atom *at=x->x_at;
+
+ delta = atom_getfloat(argv++)*x->x_pi_over_180;
+ phi = atom_getfloat(argv)*x->x_pi_over_180;
+
+ cd = cos(delta);
+ x1 = cd * cos(phi);
+ y = cd * sin(phi);
+ z = sin(delta);
+
+ xy = x1*y;
+ xz = x1*z;
+ yz = y*z;
+ x2 = x1*x1;
+ y2 = y*y;
+ z2 = z*z;
+
+ x2my2 = x2 - y2;
+ x2m3y2 = x2my2 - 2.0f*y2;
+ p3x2my2 = 2.0f*x2 + x2my2;
+ m1p5z2 = 5.0f*z2 - 1.0f;
+ m1p7z2 = 2.0f*z2 + m1p5z2;
+ m3p7z2 = m1p7z2 - 2.0f;
+
+ SETFLOAT(at, (float)x->x_colrow);
+ at++;
+
+ SETFLOAT(at, awght[0]);
+ at++;
+
+ SETFLOAT(at, x1*awght[1]);
+ at++;
+ SETFLOAT(at, y*awght[1]);
+ at++;
+ SETFLOAT(at, z*awght[1]);
+ at++;
+
+ if(x->x_n_order >= 2)
+ {
+ SETFLOAT(at, 0.5f*x->x_sqrt3*x2my2*awght[2]);
+ at++;
+ SETFLOAT(at, x->x_sqrt3*xy*awght[2]);
+ at++;
+ SETFLOAT(at, x->x_sqrt3*xz*awght[2]);
+ at++;
+ SETFLOAT(at, x->x_sqrt3*yz*awght[2]);
+ at++;
+ SETFLOAT(at, 0.5f*(3.0f*z2 - 1.0f)*awght[2]);
+ at++;
+
+ if(x->x_n_order >= 3)
+ {
+ SETFLOAT(at, x->x_sqrt10_4*x1*x2m3y2*awght[3]);
+ at++;
+ SETFLOAT(at, x->x_sqrt10_4*y*p3x2my2*awght[3]);
+ at++;
+ SETFLOAT(at, 0.5f*x->x_sqrt15*z*x2my2*awght[3]);
+ at++;
+ SETFLOAT(at, x->x_sqrt15*xy*z*awght[3]);
+ at++;
+ SETFLOAT(at, x->x_sqrt6_4*x1*m1p5z2*awght[3]);
+ at++;
+ SETFLOAT(at, x->x_sqrt6_4*y*m1p5z2*awght[3]);
+ at++;
+ SETFLOAT(at, 0.5f*z*(m1p5z2 - 2.0f)*awght[3]);
+ at++;
+
+ if(x->x_n_order >= 4)
+ {
+ SETFLOAT(at, 0.25f*x->x_sqrt35_2*(x2my2*x2my2 - 4.0f*x2*y2)*awght[4]);
+ at++;
+ SETFLOAT(at, x->x_sqrt35_2*xy*x2my2*awght[4]);
+ at++;
+ SETFLOAT(at, x->x_sqrt70_4*xz*x2m3y2*awght[4]);
+ at++;
+ SETFLOAT(at, x->x_sqrt70_4*yz*p3x2my2*awght[4]);
+ at++;
+ SETFLOAT(at, 0.5f*x->x_sqrt5_2*x2my2*m1p7z2*awght[4]);
+ at++;
+ SETFLOAT(at, x->x_sqrt5_2*xy*m1p7z2*awght[4]);
+ at++;
+ SETFLOAT(at, x->x_sqrt10_4*xz*m3p7z2*awght[4]);
+ at++;
+ SETFLOAT(at, x->x_sqrt10_4*yz*m3p7z2*awght[4]);
+ at++;
+ SETFLOAT(at, 0.125f*(5.0f*(z2 - 1.0f)*(m1p7z2 + 2.0f) + 8.0f)*awght[4]);
+ at++;
+
+ if(x->x_n_order >= 5)
+ {
+ SETFLOAT(at, x->x_sqrt126_16*x1*(x2*(x2 - 10.0f*y2) + 5.0f*y2*y2)*awght[5]);
+ at++;
+ SETFLOAT(at, x->x_sqrt126_16*y*(y2*(y2 - 10.0f*x2) + 5.0f*x2*x2)*awght[5]);
+ at++;
+ SETFLOAT(at, 0.25f*x->x_sqrt315_2*z*(y2*(y2 - 6.0f*x2) + x2*x2)*awght[5]);
+ at++;
+ SETFLOAT(at, x->x_sqrt315_2*xy*z*x2my2*awght[5]);
+ at++;
+ SETFLOAT(at, 0.25f*x->x_sqrt70_4*x1*(9.0f*z2 - 1.0f)*x2m3y2*awght[5]);
+ at++;
+ SETFLOAT(at, 0.25f*x->x_sqrt70_4*y*(9.0f*z2 - 1.0f)*p3x2my2*awght[5]);
+ at++;
+ SETFLOAT(at, 0.5f*x->x_sqrt105_2*x2my2*z*(3.0f*z2 - 1.0f)*awght[5]);
+ at++;
+ SETFLOAT(at, x->x_sqrt105_2*xy*z*(3.0f*z2 - 1.0f)*awght[5]);
+ at++;
+ SETFLOAT(at, 0.125f*x->x_sqrt15*x1*(z2*(21.0f*z2 - 14.0f) + 1.0f)*awght[5]);
+ at++;
+ SETFLOAT(at, 0.125f*x->x_sqrt15*y*(z2*(21.0f*z2 - 14.0f) + 1.0f)*awght[5]);
+ at++;
+ SETFLOAT(at, 0.125f*z*(z2*(63.0f*z2 - 70.0f) + 15.0f)*awght[5]);
+ }
+
+ if(x->x_n_order > 5)
+ post("ambi_encode-ERROR: do not support Ambisonic-Order greater than 5 in 3d !!!");
+ }
+ }
+ }
+}
+
+static void ambi_encode_float(t_ambi_encode *x, t_floatarg phi)
+{
+ x->x_colrow = -1;
+ ambi_encode_do_2d(x, phi);
+ outlet_list(x->x_obj.ob_outlet, &s_list, x->x_size2d, x->x_at+1);
+}
+
+static void ambi_encode_list(t_ambi_encode *x, t_symbol *s, int argc, t_atom *argv)
+{
+ if(argc <= 0)
+ {
+ post("ambi_encode ERROR: list-input needs 2 angles: delta [rad] and phi [rad]");
+ return;
+ }
+ else if(argc == 1)
+ {
+ ambi_encode_float(x, atom_getfloat(argv));
+ }
+ else
+ {
+ x->x_colrow = -1;
+ ambi_encode_do_3d(x, &s_list, 2, argv);
+ outlet_list(x->x_obj.ob_outlet, &s_list, x->x_size3d, x->x_at+1);
+ }
+}
+
+static void ambi_encode_row(t_ambi_encode *x, t_symbol *s, int argc, t_atom *argv)
+{
+ if(argc == 2)
+ {
+ x->x_colrow = (int)atom_getint(argv++);
+ ambi_encode_do_2d(x, atom_getfloat(argv));
+ outlet_anything(x->x_obj.ob_outlet, s, x->x_size2d+1, x->x_at);
+ }
+ else if(argc >= 3)
+ {
+ x->x_colrow = (int)atom_getint(argv++);
+ ambi_encode_do_3d(x, &s_list, 2, argv);
+ outlet_anything(x->x_obj.ob_outlet, s, x->x_size3d+1, x->x_at);
+ }
+ else
+ {
+ post("ambi_encode-ERROR: row needs <float> row-index + <float> angle ( + <float> angle)");
+ }
+}
+
+static void ambi_encode_col(t_ambi_encode *x, t_symbol *s, int argc, t_atom *argv)
+{
+ if(argc == 2)
+ {
+ x->x_colrow = (int)atom_getint(argv++);
+ ambi_encode_do_2d(x, atom_getfloat(argv));
+ outlet_anything(x->x_obj.ob_outlet, s, x->x_size2d+1, x->x_at);
+ }
+ else if(argc >= 3)
+ {
+ x->x_colrow = (int)atom_getint(argv++);
+ ambi_encode_do_3d(x, &s_list, 2, argv);
+ outlet_anything(x->x_obj.ob_outlet, s, x->x_size3d+1, x->x_at);
+ }
+ else
+ {
+ post("ambi_encode-ERROR: col needs <float> col-index + <float> angle ( + <float> angle)");
+ }
+}
+
+static void ambi_encode_free(t_ambi_encode *x)
+{
+ freebytes(x->x_ambi_order_weight, (x->x_n_order+1) * sizeof(float));
+ freebytes(x->x_at, x->x_size * sizeof(t_atom));
+}
+
+static void *ambi_encode_new(t_floatarg forder)
+{
+ t_ambi_encode *x = (t_ambi_encode *)pd_new(ambi_encode_class);
+ t_atom *at;
+ int i=(int)forder;
+
+ if(i < 1)
+ i = 1;
+ if(i > 12)
+ i = 12;
+ x->x_n_order = i;
+ x->x_size = 6*6 + 1;
+ x->x_size2d = 2*i + 1;
+ x->x_size3d = (i + 1)*(i + 1);
+
+ x->x_sqrt3 = (float)(sqrt(3.0));
+ x->x_sqrt5_2 = (float)(sqrt(5.0) / 2.0);
+ x->x_sqrt6_4 = (float)(sqrt(6.0) / 4.0);
+ x->x_sqrt10_4 = (float)(sqrt(10.0) / 4.0);
+ x->x_sqrt15 = (float)(sqrt(15.0));
+ x->x_sqrt35_2 = (float)(sqrt(35.0) / 2.0);
+ x->x_sqrt70_4 = (float)(sqrt(70.0) / 4.0);
+ x->x_sqrt126_16 = (float)(sqrt(126.0) / 16.0);
+ x->x_sqrt315_2 = (float)(sqrt(315.0) / 2.0);
+ x->x_sqrt105_2 = (float)(sqrt(105.0) / 2.0);
+ x->x_pi_over_180 = (float)(4.0 * atan(1.0)/180.0);
+ x->x_colrow = 0;
+ x->x_ambi_order_weight = (float *)getbytes((x->x_n_order+1) * sizeof(float));
+ x->x_at = (t_atom *)getbytes(x->x_size * sizeof(t_atom));
+ at=x->x_at;
+ SETFLOAT(at, -1.0f);/*row index*/
+ at++;
+ SETFLOAT(at, 1.0f);/*W channel*/
+
+ for(i=0; i<=x->x_n_order; i++)
+ x->x_ambi_order_weight[i] = 1.0f;
+
+ outlet_new(&x->x_obj, &s_list);
+ return (x);
+}
+
+void ambi_encode_setup(void)
+{
+ ambi_encode_class = class_new(gensym("ambi_encode"), (t_newmethod)ambi_encode_new, (t_method)ambi_encode_free,
+ sizeof(t_ambi_encode), 0, A_DEFFLOAT, 0);
+ class_addlist(ambi_encode_class, (t_method)ambi_encode_list);
+ class_addfloat(ambi_encode_class, (t_method)ambi_encode_float);
+ class_addmethod(ambi_encode_class, (t_method)ambi_encode_row, gensym("row"), A_GIMME, 0);
+ class_addmethod(ambi_encode_class, (t_method)ambi_encode_col, gensym("col"), A_GIMME, 0);
+ class_addmethod(ambi_encode_class, (t_method)ambi_encode_ambi_weight, gensym("ambi_weight"), A_GIMME, 0);
+ class_sethelpsymbol(ambi_encode_class, gensym("iemhelp2/help-ambi_encode"));
+}
diff --git a/src/ambi_rot.c b/src/ambi_rot.c
new file mode 100644
index 0000000..2e23a10
--- /dev/null
+++ b/src/ambi_rot.c
@@ -0,0 +1,1534 @@
+/* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution.
+
+iem_ambi written by Thomas Musil, Copyright (c) IEM KUG Graz Austria 2000 - 2005 */
+
+#ifdef NT
+#pragma warning( disable : 4244 )
+#pragma warning( disable : 4305 )
+#endif
+
+
+#include "m_pd.h"
+#include "iemlib.h"
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+
+
+/* -------------------------- ambi_rot ------------------------------ */
+/*
+ambi_rot : 1. uebergabe-argument : ambisonic-ordnung 1 .. 4;
+
+ input: <float> nur z-rotation;
+ input: <list> mit 2 floats: nur z*y-rotation;
+ input: <list> mit 3 floats: z*y*x-rotation;
+
+ output: je nach ordnung: 1 .. 4 <list>-outputs mit selector "matrix" + row + col + ordnung*ordnung-coeff.;
+*/
+
+typedef struct _ambi_rot
+{
+ t_object x_obj;
+ t_atom *x_at2;
+ int x_size2;
+ t_atom *x_at3;
+ int x_size3;
+ void *x_out3;
+ t_atom *x_at5;
+ int x_size5;
+ void *x_out5;
+ t_atom *x_at7;
+ int x_size7;
+ void *x_out7;
+ t_atom *x_at9;
+ int x_size9;
+ void *x_out9;
+ t_atom *x_at11;
+ int x_size11;
+ void *x_out11;
+ void *x_out13;
+ void *x_out15;
+ void *x_out17;
+ void *x_out19;
+ void *x_out21;
+ void *x_out23;
+ void *x_out25;
+ float x_sqrt2_16;
+ float x_sqrt3_2;
+ float x_sqrt5_32;
+ float x_sqrt6_4;
+ float x_sqrt7_8;
+ float x_sqrt10_4;
+ float x_sqrt14_16;
+ float x_sqrt15_8;
+ float x_sqrt35_64;
+ float x_sqrt70_32;
+ float x_pi_over_180;
+ t_symbol *x_s_matrix;
+ int x_order;
+} t_ambi_rot;
+
+static t_class *ambi_rot_class;
+
+static void ambi_rot_float(t_ambi_rot *x, t_floatarg rho_z) /* = ambi_rot_z(); */
+{
+ float c, s, cc, ss, c2, s2, c3, s3, s4, c4, s5, c5, s6, c6, sx, cx;
+ t_atom *at;
+
+ rho_z *= x->x_pi_over_180;
+
+ c = cos(rho_z);
+ s = sin(rho_z);
+ cc = c*c;
+ ss = s*s;
+
+ if(x->x_order >= 2)
+ {
+ c2 = cc - ss;
+ s2 = 2.0f*s*c;
+ if(x->x_order >= 3)
+ {
+ c3 = c*(4.0f*cc - 3.0f);
+ s3 = s*(3.0f - 4.0f*ss);
+ if(x->x_order >= 4)
+ {
+ c4 = 1.0f + 8.0f*cc*(cc - 1.0f);
+ s4 = 2.0f*s2*c2;
+ if(x->x_order >= 5)
+ {
+ c5 = c*(1.0f + 4.0f*ss*(ss - 3.0f*cc));
+ s5 = s*(1.0f + 4.0f*cc*(cc - 3.0f*ss));
+ if(x->x_order >= 6)
+ {
+ c6 = c3*c3 - s3*s3;
+ s6 = 2.0f*s3*c3;
+ if(x->x_order >= 7)
+ {
+ if(x->x_order >= 8)
+ {
+ if(x->x_order >= 9)
+ {
+ if(x->x_order >= 10)
+ {
+ if(x->x_order >= 11)
+ {
+ if(x->x_order >= 12)
+ {
+ if(x->x_order >= 13)
+ post("ambi_rot-ERROR: do not support Ambisonic-Order greater than 12 in z-Rotation !!!");
+
+ at = x->x_at2;
+ at += 2;
+ cx = c6*c6 - s6*s6;
+ sx = 2.0f*s6*c6;
+ SETFLOAT(at, cx);
+ at++;
+ SETFLOAT(at, -sx);
+ at++;
+ SETFLOAT(at, sx);
+ at++;
+ SETFLOAT(at, cx);
+ outlet_anything(x->x_out25, x->x_s_matrix, x->x_size2, x->x_at2);
+ }
+ at = x->x_at2;
+ at += 2;
+ cx = cos(11.0f*rho_z);
+ sx = sin(11.0f*rho_z);
+ SETFLOAT(at, cx);
+ at++;
+ SETFLOAT(at, -sx);
+ at++;
+ SETFLOAT(at, sx);
+ at++;
+ SETFLOAT(at, cx);
+ outlet_anything(x->x_out23, x->x_s_matrix, x->x_size2, x->x_at2);
+ }
+ at = x->x_at2;
+ at += 2;
+ cx = c5*c5 - s5*s5;
+ sx = 2.0f*s5*c5;
+ SETFLOAT(at, cx);
+ at++;
+ SETFLOAT(at, -sx);
+ at++;
+ SETFLOAT(at, sx);
+ at++;
+ SETFLOAT(at, cx);
+ outlet_anything(x->x_out21, x->x_s_matrix, x->x_size2, x->x_at2);
+ }
+ at = x->x_at2;
+ at += 2;
+ cx = cos(9.0f*rho_z);
+ sx = sin(9.0f*rho_z);
+ SETFLOAT(at, cx);
+ at++;
+ SETFLOAT(at, -sx);
+ at++;
+ SETFLOAT(at, sx);
+ at++;
+ SETFLOAT(at, cx);
+ outlet_anything(x->x_out19, x->x_s_matrix, x->x_size2, x->x_at2);
+ }
+ at = x->x_at2;
+ at += 2;
+ cx = c4*c4 - s4*s4;
+ sx = 2.0f*s4*c4;
+ SETFLOAT(at, cx);
+ at++;
+ SETFLOAT(at, -sx);
+ at++;
+ SETFLOAT(at, sx);
+ at++;
+ SETFLOAT(at, cx);
+ outlet_anything(x->x_out17, x->x_s_matrix, x->x_size2, x->x_at2);
+ }
+ at = x->x_at2;
+ at += 2;
+ cx = cos(7.0f*rho_z);
+ sx = sin(7.0f*rho_z);
+ SETFLOAT(at, cx);
+ at++;
+ SETFLOAT(at, -sx);
+ at++;
+ SETFLOAT(at, sx);
+ at++;
+ SETFLOAT(at, cx);
+ outlet_anything(x->x_out15, x->x_s_matrix, x->x_size2, x->x_at2);
+ }
+ at = x->x_at2;
+ at += 2;
+ SETFLOAT(at, c6);
+ at++;
+ SETFLOAT(at, -s6);
+ at++;
+ SETFLOAT(at, s6);
+ at++;
+ SETFLOAT(at, c6);
+ outlet_anything(x->x_out13, x->x_s_matrix, x->x_size2, x->x_at2);
+ }
+ at = x->x_at2;
+ at += 2;
+ SETFLOAT(at, c5);
+ at++;
+ SETFLOAT(at, -s5);
+ at++;
+ SETFLOAT(at, s5);
+ at++;
+ SETFLOAT(at, c5);
+ outlet_anything(x->x_out11, x->x_s_matrix, x->x_size2, x->x_at2);
+ }
+ at = x->x_at2;
+ at += 2;
+ SETFLOAT(at, c4);
+ at++;
+ SETFLOAT(at, -s4);
+ at++;
+ SETFLOAT(at, s4);
+ at++;
+ SETFLOAT(at, c4);
+ outlet_anything(x->x_out9, x->x_s_matrix, x->x_size2, x->x_at2);
+ }
+ at = x->x_at2;
+ at += 2;
+ SETFLOAT(at, c3);
+ at++;
+ SETFLOAT(at, -s3);
+ at++;
+ SETFLOAT(at, s3);
+ at++;
+ SETFLOAT(at, c3);
+ outlet_anything(x->x_out7, x->x_s_matrix, x->x_size2, x->x_at2);
+ }
+ at = x->x_at2;
+ at += 2;
+ SETFLOAT(at, c2);
+ at++;
+ SETFLOAT(at, -s2);
+ at++;
+ SETFLOAT(at, s2);
+ at++;
+ SETFLOAT(at, c2);
+ outlet_anything(x->x_out5, x->x_s_matrix, x->x_size2, x->x_at2);
+ }
+ at = x->x_at2;
+ at += 2;
+ SETFLOAT(at, c);
+ at++;
+ SETFLOAT(at, -s);
+ at++;
+ SETFLOAT(at, s);
+ at++;
+ SETFLOAT(at, c);
+ outlet_anything(x->x_out3, x->x_s_matrix, x->x_size2, x->x_at2);
+}
+
+static void ambi_rot_zy(t_ambi_rot *x, float rho_z, float rho_y)
+{
+ float cy, sy, ccy, ssy, c2y, s2y, c3y, s3y, c4y, s4y;
+ float cz, sz, ccz, ssz, c2z, s2z, c3z, s3z, c4z, s4z;
+ float r9_y[9][9];
+ int i;
+ t_atom *at;
+
+ rho_z *= x->x_pi_over_180;
+ rho_y *= x->x_pi_over_180;
+
+ cz = cos(rho_z);
+ sz = sin(rho_z);
+ ccz = cz*cz;
+ ssz = sz*sz;
+
+ cy = cos(rho_y);
+ sy = sin(rho_y);
+ ccy = cy*cy;
+ ssy = sy*sy;
+
+ if(x->x_order >= 2)
+ {
+ c2z = ccz - ssz;
+ s2z = 2.0f*sz*cz;
+ c2y = ccy - ssy;
+ s2y = 2.0f*sy*cy;
+ if(x->x_order >= 3)
+ {
+ c3z = cz*(4.0f*ccz - 3.0f);
+ s3z = sz*(3.0f - 4.0f*ssz);
+ c3y = cy*(4.0f*ccy - 3.0f);
+ s3y = sy*(3.0f - 4.0f*ssy);
+ if(x->x_order >= 4)
+ {
+ if(x->x_order >= 5)
+ post("ambi_rot-ERROR: do not support Ambisonic-Order greater than 5 in zy-Rotation !!!");
+
+ /*y
+ r9_11=(35 + 28*c2 + c4)/64;
+ r9_22=(7c + c3)/8;
+ r9_31 = x->x_sqrt2*(14*s2 + s4)/32;
+ r9_33=(7*c2 + c4)/8;
+ r9_42 = x->x_sqrt2*(7*s + 3*s3)/16;
+ r9_44=(7*c + 9*c3)/16;
+ r9_51 = x->x_sqrt7*(5 - 4*c2 - c4)/32;
+ r9_53 = x->x_sqrt14*(2*s2 + s4)/16;
+ r9_55=(5 + 4*c2 + 7*c4)/16;
+ r9_62 = x->x_sqrt7*(c - c3)/8;
+ r9_64 = x->x_sqrt14*(-s + 3*s3)/16;
+ r9_66=(c + 7*c3)/8;
+ r9_71 = x->x_sqrt14*(2*s2 - s4)/32;
+ r9_73 = x->x_sqrt7*(c2 - c4)/8;
+ r9_75 = x->x_sqrt2*(-2*s2 + 7*s4)/16;
+ r9_77=(c2 + 7*c4)/8;
+ r9_82 = x->x_sqrt14*(3*s - s3)/16;
+ r9_84 = x->x_sqrt7*(3*c - 3*c3)/16;
+ r9_86 = x->x_sqrt2*(3*s + 7*s3)/16;
+ r9_88=(9*c + 7*c3)/16;
+ r9_91 = x->x_sqrt35*(3 - 4*c2 + c4)/64;
+ r9_93 = x->x_sqrt70*(2*s2 - s4)/32;
+ r9_95 = x->x_sqrt5*(3 + 4*c2 - 7*c4)/32;
+ r9_97 = x->x_sqrt10*(2*s2 + 7*s4)/32;
+ r9_99=(9 + 20*c2 + 35*c4)/64;
+ */
+
+ c4y = 1.0f + 8.0f*ccy*(ccy - 1.0f);
+ s4y = 2.0f*s2y*c2y;
+
+ c4z = 1.0f + 8.0f*ccz*(ccz - 1.0f);
+ s4z = 2.0f*s2z*c2z;
+
+ r9_y[0][0] = (35.0f + 28.0f*c2y + c4y)*0.015625f;/* -r9_31y, r9_51y, -r9_71y, r9_91y; */
+ r9_y[1][1] = (7.0f*cy + c3y)*0.125f;/* -r9_42y, r9_62y, -r9_82y;*/
+ r9_y[2][0] = x->x_sqrt2_16*(14.0f*s2y + s4y)*0.5f;
+ r9_y[2][2] = (7.0f*c2y + c4y)*0.125f;/* -r9_53y, r9_73y, -r9_93y;*/
+ r9_y[3][1] = x->x_sqrt2_16*(7.0f*sy + 3.0f*s3y);
+ r9_y[3][3] = (7.0f*cy + 9.0f*c3y)*0.0625f;/* -r9_64y, r9_84y;*/
+ r9_y[4][0] = x->x_sqrt7_8*(5.0f - 4.0f*c2y - c4y)*0.25f;
+ r9_y[4][2] = x->x_sqrt14_16*(2.0f*s2y + s4y);
+ r9_y[4][4] = (5.0f + 4.0f*c2y + 7.0f*c4y)*0.0625f;/* -r9_75y, r9_95y;*/
+ r9_y[5][1] = x->x_sqrt7_8*(cy - c3y);
+ r9_y[5][3] = x->x_sqrt14_16*(3.0f*s3y - sy);
+ r9_y[5][5] = (cy + 7.0f*c3y)*0.125f;/* -r9_86y;*/
+ r9_y[6][0] = x->x_sqrt14_16*(2.0f*s2y - s4y)*0.5f;
+ r9_y[6][2] = x->x_sqrt7_8*(c2y - c4y);
+ r9_y[6][4] = x->x_sqrt2_16*(7.0f*s4y - 2.0f*s2y);
+ r9_y[6][6] = (c2y + 7.0f*c4y)*0.125f;/* -r9_97y;*/
+ r9_y[7][1] = x->x_sqrt14_16*(3.0f*sy - s3y);
+ r9_y[7][3] = x->x_sqrt7_8*(cy - c3y)*1.5f;
+ r9_y[7][5] = x->x_sqrt2_16*(3.0f*sy + 7.0f*s3y);
+ r9_y[7][7] = (9.0f*cy + 7.0f*c3y)*0.0625f;
+ r9_y[8][0] = x->x_sqrt35_64*(3.0f - 4.0f*c2y + c4y);
+ r9_y[8][2] = x->x_sqrt70_32*(2.0f*s2y - s4y);
+ r9_y[8][4] = x->x_sqrt5_32*(3.0f + 4.0f*c2y - 7.0f*c4y);
+ r9_y[8][6] = x->x_sqrt10_4*(2.0f*s2y + 7.0f*s4y)*0.125f;
+ r9_y[8][8] = (9.0f + 20.0f*c2y + 35.0f*c4y)*0.015625f;
+
+ r9_y[0][2] = -r9_y[2][0];
+ r9_y[0][4] = r9_y[4][0];
+ r9_y[0][6] = -r9_y[6][0];
+ r9_y[0][8] = r9_y[8][0];
+ r9_y[1][3] = -r9_y[3][1];
+ r9_y[1][5] = r9_y[5][1];
+ r9_y[1][7] = -r9_y[7][1];
+ r9_y[2][4] = -r9_y[4][2];
+ r9_y[2][6] = r9_y[6][2];
+ r9_y[2][8] = -r9_y[8][2];
+ r9_y[3][5] = -r9_y[5][3];
+ r9_y[3][7] = r9_y[7][3];
+ r9_y[4][6] = -r9_y[6][4];
+ r9_y[4][8] = r9_y[8][4];
+ r9_y[5][7] = -r9_y[7][5];
+ r9_y[6][8] = -r9_y[8][6];
+
+ at = x->x_at9;
+ at += 2;
+
+ for(i=0; i<8; i+=2)
+ {
+ SETFLOAT(at, c4z*r9_y[0][i]);
+ at++;
+ SETFLOAT(at, -s4z*r9_y[1][i+1]);
+ at++;
+ }
+ SETFLOAT(at, c4z*r9_y[0][8]);
+ at++;
+
+ for(i=0; i<8; i+=2)
+ {
+ SETFLOAT(at, c4z*r9_y[0][i]);
+ at++;
+ SETFLOAT(at, s4z*r9_y[1][i+1]);
+ at++;
+ }
+ SETFLOAT(at, s4z*r9_y[0][8]);
+ at++;
+
+ for(i=0; i<8; i+=2)
+ {
+ SETFLOAT(at, c3z*r9_y[2][i]);
+ at++;
+ SETFLOAT(at, -s3z*r9_y[3][i+1]);
+ at++;
+ }
+ SETFLOAT(at, c3z*r9_y[2][8]);
+ at++;
+
+ for(i=0; i<8; i+=2)
+ {
+ SETFLOAT(at, c3z*r9_y[2][i]);
+ at++;
+ SETFLOAT(at, s3z*r9_y[3][i+1]);
+ at++;
+ }
+ SETFLOAT(at, s3z*r9_y[2][8]);
+ at++;
+
+ for(i=0; i<8; i+=2)
+ {
+ SETFLOAT(at, c2z*r9_y[4][i]);
+ at++;
+ SETFLOAT(at, -s2z*r9_y[5][i+1]);
+ at++;
+ }
+ SETFLOAT(at, c2z*r9_y[4][8]);
+ at++;
+
+ for(i=0; i<8; i+=2)
+ {
+ SETFLOAT(at, c2z*r9_y[4][i]);
+ at++;
+ SETFLOAT(at, s2z*r9_y[5][i+1]);
+ at++;
+ }
+ SETFLOAT(at, s2z*r9_y[4][8]);
+ at++;
+
+ for(i=0; i<8; i+=2)
+ {
+ SETFLOAT(at, cz*r9_y[6][i]);
+ at++;
+ SETFLOAT(at, -sz*r9_y[7][i+1]);
+ at++;
+ }
+ SETFLOAT(at, cz*r9_y[6][8]);
+ at++;
+
+ for(i=0; i<8; i+=2)
+ {
+ SETFLOAT(at, cz*r9_y[6][i]);
+ at++;
+ SETFLOAT(at, sz*r9_y[7][i+1]);
+ at++;
+ }
+ SETFLOAT(at, sz*r9_y[6][8]);
+ at++;
+
+ for(i=0; i<8; i+=2)
+ {
+ SETFLOAT(at, r9_y[8][i]);
+ at++;
+ SETFLOAT(at, 0.0f);
+ at++;
+ }
+ SETFLOAT(at, r9_y[8][8]);
+
+ outlet_anything(x->x_out9, x->x_s_matrix, x->x_size9, x->x_at9);
+ }
+
+ /*y
+ r7_11=(15*c + c3)/16;
+ r7_22=(5 + 3*c2)/8;
+ r7_31 = x->x_sqrt6*(5*s + s3)/16;
+ r7_33=(5*c + 3*c3)/8;
+ r7_42 = x->x_sqrt6*(s2)/4;
+ r7_44=(c2);
+ r7_51 = x->x_sqrt15*(c - c3)/16;
+ r7_53 = x->x_sqrt10*(-s + 3*s3)/16;
+ r7_55=(c + 15*c3)/16;
+ r7_62 = x->x_sqrt15*(1 - c2)/8;
+ r7_64 = x->x_sqrt10*(s2)/4;
+ r7_66=(3 + 5*c2)/8;
+ r7_71 = x->x_sqrt10*(3*s - s3)/16;
+ r7_73 = x->x_sqrt15*(c - c3)/8 = 2*r7_51;
+ r7_75 = x->x_sqrt6*(s + 5*s3)/16;
+ r7_77=(3*c + 5*c3)/8;
+
+ */
+ r9_y[0][0] = (15.0f*cy + c3y)*0.0625f;/* -r7_31y, r7_51y, -r7_71y;*/
+ r9_y[1][1] = (5.0f + 3.0f*c2y)*0.125f;/* -r7_42y, r7_62y;*/
+ r9_y[2][0] = x->x_sqrt6_4*(5.0f*sy + s3y)*0.25f;
+ r9_y[2][2] = (5.0f*cy + 3.0f*c3y)*0.125f;/* -r7_53y, r7_73y;*/
+ r9_y[3][1] = x->x_sqrt6_4*s2y;
+ r9_y[3][3] = c2y;/* -r7_64y;*/
+ r9_y[6][2] = x->x_sqrt15_8*(cy - c3y);
+ r9_y[4][0] = r9_y[6][2]*0.5f;
+ r9_y[4][2] = x->x_sqrt10_4*(3.0f*s3y - sy)*0.25f;
+ r9_y[4][4] = (cy + 15.0f*c3y)*0.0625f;/* -r7_75y;*/
+ r9_y[5][1] = x->x_sqrt15_8*(1.0f - c2y);
+ r9_y[5][3] = x->x_sqrt10_4*s2y;
+ r9_y[5][5] = (3.0f + 5.0f*c2y)*0.125f;
+ r9_y[6][0] = x->x_sqrt10_4*(3.0f*sy - s3y)*0.25f;
+
+ r9_y[6][4] = x->x_sqrt6_4*(sy + 5.0f*s3y)*0.25f;
+ r9_y[6][6] = (3.0f*cy + 5.0f*c3y)*0.125f;
+
+ r9_y[0][2] = -r9_y[2][0];
+ r9_y[0][4] = r9_y[4][0];
+ r9_y[0][6] = -r9_y[6][0];
+ r9_y[1][3] = -r9_y[3][1];
+ r9_y[1][5] = r9_y[5][1];
+ r9_y[2][4] = -r9_y[4][2];
+ r9_y[2][6] = r9_y[6][2];
+ r9_y[3][5] = -r9_y[5][3];
+ r9_y[4][6] = -r9_y[6][4];
+
+ at = x->x_at7;
+ at += 2;
+
+ for(i=0; i<6; i+=2)
+ {
+ SETFLOAT(at, c3z*r9_y[0][i]);
+ at++;
+ SETFLOAT(at, -s3z*r9_y[1][i+1]);
+ at++;
+ }
+ SETFLOAT(at, c3z*r9_y[0][6]);
+ at++;
+
+ for(i=0; i<6; i+=2)
+ {
+ SETFLOAT(at, c3z*r9_y[0][i]);
+ at++;
+ SETFLOAT(at, s3z*r9_y[1][i+1]);
+ at++;
+ }
+ SETFLOAT(at, s3z*r9_y[0][6]);
+ at++;
+
+ for(i=0; i<6; i+=2)
+ {
+ SETFLOAT(at, c2z*r9_y[2][i]);
+ at++;
+ SETFLOAT(at, -s2z*r9_y[3][i+1]);
+ at++;
+ }
+ SETFLOAT(at, c2z*r9_y[2][6]);
+ at++;
+
+ for(i=0; i<6; i+=2)
+ {
+ SETFLOAT(at, c2z*r9_y[2][i]);
+ at++;
+ SETFLOAT(at, s2z*r9_y[3][i+1]);
+ at++;
+ }
+ SETFLOAT(at, s2z*r9_y[2][6]);
+ at++;
+
+ for(i=0; i<6; i+=2)
+ {
+ SETFLOAT(at, cz*r9_y[4][i]);
+ at++;
+ SETFLOAT(at, -sz*r9_y[5][i+1]);
+ at++;
+ }
+ SETFLOAT(at, cz*r9_y[4][6]);
+ at++;
+
+ for(i=0; i<6; i+=2)
+ {
+ SETFLOAT(at, cz*r9_y[4][i]);
+ at++;
+ SETFLOAT(at, sz*r9_y[5][i+1]);
+ at++;
+ }
+ SETFLOAT(at, sz*r9_y[4][6]);
+ at++;
+
+ for(i=0; i<6; i+=2)
+ {
+ SETFLOAT(at, r9_y[6][i]);
+ at++;
+ SETFLOAT(at, 0.0f);
+ at++;
+ }
+ SETFLOAT(at, r9_y[6][6]);
+
+ outlet_anything(x->x_out7, x->x_s_matrix, x->x_size7, x->x_at7);
+ }
+
+ /*y
+ r5_11=(3 + c2)/4;
+ r5_22=(c);
+ r5_31 = (s2)/2;
+ r5_33=(c2);
+ r5_42 = (s);
+ r5_44=(c);
+ r5_51 = x->x_sqrt3*(1 - c2)/4;
+ r5_53 = x->x_sqrt3*(s2)/2;
+ r5_55=(1 + 3*c2)/4;
+ */
+ r9_y[0][0] = (3.0f + c2y)*0.25f;/* -r5_31y, r5_51y;*/
+ r9_y[1][1] = cy;/* -r5_42y;*/
+ r9_y[2][0] = s2y*0.5f;
+ r9_y[2][2] = c2y;/* -r5_53y;*/
+ r9_y[3][1] = sy;
+ r9_y[3][3] = cy;
+ r9_y[4][0] = x->x_sqrt3_2*(1.0f - c2y)*0.5f;
+ r9_y[4][2] = x->x_sqrt3_2*s2y;
+ r9_y[4][4] = (1.0f + 3.0f*c2y)*0.25f;
+
+ r9_y[0][2] = -r9_y[2][0];
+ r9_y[0][4] = r9_y[4][0];
+ r9_y[1][3] = -r9_y[3][1];
+ r9_y[2][4] = -r9_y[4][2];
+
+ at = x->x_at5;
+ at += 2;
+
+ for(i=0; i<4; i+=2)
+ {
+ SETFLOAT(at, c2z*r9_y[0][i]);
+ at++;
+ SETFLOAT(at, -s2z*r9_y[1][i+1]);
+ at++;
+ }
+ SETFLOAT(at, c2z*r9_y[0][4]);
+ at++;
+
+ for(i=0; i<4; i+=2)
+ {
+ SETFLOAT(at, c2z*r9_y[0][i]);
+ at++;
+ SETFLOAT(at, s2z*r9_y[1][i+1]);
+ at++;
+ }
+ SETFLOAT(at, s2z*r9_y[0][4]);
+ at++;
+
+ for(i=0; i<4; i+=2)
+ {
+ SETFLOAT(at, cz*r9_y[2][i]);
+ at++;
+ SETFLOAT(at, -sz*r9_y[3][i+1]);
+ at++;
+ }
+ SETFLOAT(at, cz*r9_y[2][4]);
+ at++;
+
+ for(i=0; i<4; i+=2)
+ {
+ SETFLOAT(at, cz*r9_y[2][i]);
+ at++;
+ SETFLOAT(at, sz*r9_y[3][i+1]);
+ at++;
+ }
+ SETFLOAT(at, sz*r9_y[2][4]);
+ at++;
+
+ for(i=0; i<4; i+=2)
+ {
+ SETFLOAT(at, r9_y[4][i]);
+ at++;
+ SETFLOAT(at, 0.0f);
+ at++;
+ }
+ SETFLOAT(at, r9_y[4][4]);
+
+ outlet_anything(x->x_out5, x->x_s_matrix, x->x_size5, x->x_at5);
+ }
+
+ /*y
+ r3_11=(c);
+ r3_22=(1);
+ r3_31 = (s);
+ r3_33=(c);
+ */
+ r9_y[0][0] = cy;/* -r3_31y;*/
+ r9_y[1][1] = 1.0f;
+ r9_y[2][0] = sy;
+ r9_y[2][2] = cy;
+ r9_y[0][2] = -r9_y[2][0];
+
+ at = x->x_at3;
+ at += 2;
+
+ SETFLOAT(at, cz*r9_y[0][0]);
+ at++;
+ SETFLOAT(at, -sz*r9_y[1][1]);
+ at++;
+ SETFLOAT(at, cz*r9_y[0][2]);
+ at++;
+
+ SETFLOAT(at, sz*r9_y[0][0]);
+ at++;
+ SETFLOAT(at, cz*r9_y[1][1]);
+ at++;
+ SETFLOAT(at, sz*r9_y[0][2]);
+ at++;
+
+ SETFLOAT(at, r9_y[2][0]);
+ at++;
+ SETFLOAT(at, 0.0f);
+ at++;
+ SETFLOAT(at, r9_y[2][2]);
+
+ outlet_anything(x->x_out3, x->x_s_matrix, x->x_size3, x->x_at3);
+}
+
+static void ambi_rot_zyx(t_ambi_rot *x, float rho_z, float rho_y, float rho_x)
+{
+ float cx, sx, ccx, ssx, c2x, s2x, c3x, s3x, c4x, s4x;
+ float cy, sy, ccy, ssy, c2y, s2y, c3y, s3y, c4y, s4y;
+ float cz, sz, ccz, ssz, c2z, s2z, c3z, s3z, c4z, s4z;
+ float r9_zy[9][9];
+ float r9_z[9][9];
+ float r9_y[9][9];
+ float r9_x[9][9];
+ int i, j;
+ t_atom *at;
+
+ rho_z *= x->x_pi_over_180;
+ rho_y *= x->x_pi_over_180;
+ rho_x *= x->x_pi_over_180;
+
+ cz = cos(rho_z);
+ sz = sin(rho_z);
+ ccz = cz*cz;
+ ssz = sz*sz;
+
+ cy = cos(rho_y);
+ sy = sin(rho_y);
+ ccy = cy*cy;
+ ssy = sy*sy;
+
+ cx = cos(rho_x);
+ sx = sin(rho_x);
+ ccx = cx*cx;
+ ssx = sx*sx;
+
+ if(x->x_order >= 2)
+ {
+ c2z = ccz - ssz;
+ s2z = 2.0f*sz*cz;
+ c2y = ccy - ssy;
+ s2y = 2.0f*sy*cy;
+ c2x = ccx - ssx;
+ s2x = 2.0f*sx*cx;
+
+ if(x->x_order >= 3)
+ {
+ c3z = cz*(4.0f*ccz - 3.0f);
+ s3z = sz*(3.0f - 4.0f*ssz);
+ c3y = cy*(4.0f*ccy - 3.0f);
+ s3y = sy*(3.0f - 4.0f*ssy);
+ c3x = cx*(4.0f*ccx - 3.0f);
+ s3x = sx*(3.0f - 4.0f*ssx);
+
+ if(x->x_order >= 4)
+ {
+ if(x->x_order >= 5)
+ post("ambi_rot-ERROR: do not support Ambisonic-Order greater than 5 in zyx-Rotation !!!");
+
+ c4z = 1.0f + 8.0f*ccz*(ccz - 1.0f);
+ s4z = 2.0f*s2z*c2z;
+
+ c4y = 1.0f + 8.0f*ccy*(ccy - 1.0f);
+ s4y = 2.0f*s2y*c2y;
+
+ c4x = 1.0f + 8.0f*ccx*(ccx - 1.0f);
+ s4x = 2.0f*s2x*c2x;
+
+ r9_z[0][0] = c4z;
+ r9_z[0][1] = -s4z;
+ r9_z[1][0] = s4z;
+ r9_z[1][1] = c4z;
+ r9_z[2][2] = c3z;
+ r9_z[2][3] = -s3z;
+ r9_z[3][2] = s3z;
+ r9_z[3][3] = c3z;
+ r9_z[4][4] = c2z;
+ r9_z[4][5] = -s2z;
+ r9_z[5][4] = s2z;
+ r9_z[5][5] = c2z;
+ r9_z[6][6] = cz;
+ r9_z[6][7] = -sz;
+ r9_z[7][6] = sz;
+ r9_z[7][7] = cz;
+ r9_z[8][8] = 1.0f;
+ /*y
+ r9_11=(35 + 28*c2 + c4)/64;
+ r9_22=(7c + c3)/8;
+ r9_31 = x->x_sqrt2*(14*s2 + s4)/32;
+ r9_33=(7*c2 + c4)/8;
+ r9_42 = x->x_sqrt2*(7*s + 3*s3)/16;
+ r9_44=(7*c + 9*c3)/16;
+ r9_51 = x->x_sqrt7*(5 - 4*c2 - c4)/32;
+ r9_53 = x->x_sqrt14*(2*s2 + s4)/16;
+ r9_55=(5 + 4*c2 + 7*c4)/16;
+ r9_62 = x->x_sqrt7*(c - c3)/8;
+ r9_64 = x->x_sqrt14*(-s + 3*s3)/16;
+ r9_66=(c + 7*c3)/8;
+ r9_71 = x->x_sqrt14*(2*s2 - s4)/32;
+ r9_73 = x->x_sqrt7*(c2 - c4)/8;
+ r9_75 = x->x_sqrt2*(-2*s2 + 7*s4)/16;
+ r9_77=(c2 + 7*c4)/8;
+ r9_82 = x->x_sqrt14*(3*s - s3)/16;
+ r9_84 = x->x_sqrt7*(3*c - 3*c3)/16;
+ r9_86 = x->x_sqrt2*(3*s + 7*s3)/16;
+ r9_88=(9*c + 7*c3)/16;
+ r9_91 = x->x_sqrt35*(3 - 4*c2 + c4)/64;
+ r9_93 = x->x_sqrt70*(2*s2 - s4)/32;
+ r9_95 = x->x_sqrt5*(3 + 4*c2 - 7*c4)/32;
+ r9_97 = x->x_sqrt10*(2*s2 + 7*s4)/32;
+ r9_99=(9 + 20*c2 + 35*c4)/64;
+ */
+ r9_y[0][0] = (35.0f + 28.0f*c2y + c4y)*0.015625f;/* -r9_31y, r9_51y, -r9_71y, r9_91y; */
+ r9_y[1][1] = (7.0f*cy + c3y)*0.125f;/* -r9_42y, r9_62y, -r9_82y;*/
+ r9_y[2][0] = x->x_sqrt2_16*(14.0f*s2y + s4y)*0.5f;
+ r9_y[2][2] = (7.0f*c2y + c4y)*0.125f;/* -r9_53y, r9_73y, -r9_93y;*/
+ r9_y[3][1] = x->x_sqrt2_16*(7.0f*sy + 3.0f*s3y);
+ r9_y[3][3] = (7.0f*cy + 9.0f*c3y)*0.0625f;/* -r9_64y, r9_84y;*/
+ r9_y[4][0] = x->x_sqrt7_8*(5.0f - 4.0f*c2y - c4y)*0.25f;
+ r9_y[4][2] = x->x_sqrt14_16*(2.0f*s2y + s4y);
+ r9_y[4][4] = (5.0f + 4.0f*c2y + 7.0f*c4y)*0.0625f;/* -r9_75y, r9_95y;*/
+ r9_y[5][1] = x->x_sqrt7_8*(cy - c3y);
+ r9_y[5][3] = x->x_sqrt14_16*(3.0f*s3y - sy);
+ r9_y[5][5] = (cy + 7.0f*c3y)*0.125f;/* -r9_86y;*/
+ r9_y[6][0] = x->x_sqrt14_16*(2.0f*s2y - s4y)*0.5f;
+ r9_y[6][2] = x->x_sqrt7_8*(c2y - c4y);
+ r9_y[6][4] = x->x_sqrt2_16*(7.0f*s4y - 2.0f*s2y);
+ r9_y[6][6] = (c2y + 7.0f*c4y)*0.125f;/* -r9_97y;*/
+ r9_y[7][1] = x->x_sqrt14_16*(3.0f*sy - s3y);
+ r9_y[7][3] = x->x_sqrt7_8*(cy - c3y)*1.5f;
+ r9_y[7][5] = x->x_sqrt2_16*(3.0f*sy + 7.0f*s3y);
+ r9_y[7][7] = (9.0f*cy + 7.0f*c3y)*0.0625f;
+ r9_y[8][0] = x->x_sqrt35_64*(3.0f - 4.0f*c2y + c4y);
+ r9_y[8][2] = x->x_sqrt70_32*(2.0f*s2y - s4y);
+ r9_y[8][4] = x->x_sqrt5_32*(3.0f + 4.0f*c2y - 7.0f*c4y);
+ r9_y[8][6] = x->x_sqrt10_4*(2.0f*s2y + 7.0f*s4y)*0.125f;
+ r9_y[8][8] = (9.0f + 20.0f*c2y + 35.0f*c4y)*0.015625f;
+
+ r9_y[0][2] = -r9_y[2][0];
+ r9_y[0][4] = r9_y[4][0];
+ r9_y[0][6] = -r9_y[6][0];
+ r9_y[0][8] = r9_y[8][0];
+ r9_y[1][3] = -r9_y[3][1];
+ r9_y[1][5] = r9_y[5][1];
+ r9_y[1][7] = -r9_y[7][1];
+ r9_y[2][4] = -r9_y[4][2];
+ r9_y[2][6] = r9_y[6][2];
+ r9_y[2][8] = -r9_y[8][2];
+ r9_y[3][5] = -r9_y[5][3];
+ r9_y[3][7] = r9_y[7][3];
+ r9_y[4][6] = -r9_y[6][4];
+ r9_y[4][8] = r9_y[8][4];
+ r9_y[5][7] = -r9_y[7][5];
+ r9_y[6][8] = -r9_y[8][6];
+
+ /*x
+ r9_11=(35 + 28*c2 + c4)/64;
+ r9_22=(7c + c3)/8;
+ r9_32 = x->x_sqrt2*(7*s + 3*s3)/16;
+ r9_33=(7*c + 9*c3)/16;
+ r9_41 = x->x_sqrt2*(-14*s2 - s4)/32;
+ r9_44=(7*c2 + c4)/8;
+ r9_51 = x->x_sqrt7*(-5 + 4*c2 + c4)/32;
+ r9_54 = x->x_sqrt14*(2*s2 + s4)/16;
+ r9_55=(5 + 4*c2 + 7*c4)/16;
+ r9_62 = x->x_sqrt7*(-c + c3)/8;
+ r9_63 = x->x_sqrt14*(s - 3*s3)/16;
+ r9_66=(c + 7*c3)/8;
+ r9_72 = x->x_sqrt14*(-3s + s3)/16;
+ r9_73 = x->x_sqrt7*(-3*c + 3*c3)/16;
+ r9_76 = x->x_sqrt2*(3*s + 7*s3)/16;
+ r9_77=(9*c + 7*c3)/16;
+ r9_81 = x->x_sqrt14*(2*s2 - s4)/32;
+ r9_84 = x->x_sqrt7*(-c2 + c4)/8;
+ r9_85 = x->x_sqrt2*(2*s2 - 7*s4)/16;
+ r9_88=(c2 + 7*c4)/8;
+ r9_91 = x->x_sqrt35*(3 - 4*c2 + c4)/64;
+ r9_94 = x->x_sqrt70*(-2*s2 + s4)/32;
+ r9_95 = x->x_sqrt5*(-3 - 4*c2 + 7*c4)/32;
+ r9_98 = x->x_sqrt10*(2*s2 + 7*s4)/32;
+ r9_99=(9 + 20*c2 + 35*c4)/64;
+ */
+
+ r9_x[0][0] = (35.0f + 28.0f*c2x + c4x)*0.015625f;/* -r9_41x, r9_51x, -r9_81x, r9_91x;*/
+ r9_x[1][1] = (7.0f*cx + c3x)*0.125f;/* -r9_32x, r9_62x, -r9_72x;*/
+ r9_x[2][1] = x->x_sqrt2_16*(7.0f*sx + 3.0f*s3x);
+ r9_x[2][2] = (7.0f*cx + 9.0f*c3x)*0.0625f;/* -r9_63x, r9_73x;*/
+ r9_x[3][0] = -x->x_sqrt2_16*(14.0f*s2x + s4x)*0.5f;
+ r9_x[3][3] = (7.0f*c2x + c4x)*0.125f;/* -r9_54x, r9_84x, -r9_94x;*/
+ r9_x[4][0] = x->x_sqrt7_8*(4.0f*c2x + c4x - 5.0f)*0.25f;
+ r9_x[4][3] = x->x_sqrt14_16*(2.0f*s2x + s4x);
+ r9_x[4][4] = (5.0f + 4.0f*c2x + 7.0f*c4x)*0.0625f;/* -r9_85x, r9_95x;*/
+ r9_x[5][1] = x->x_sqrt7_8*(c3x - cx);
+ r9_x[5][2] = x->x_sqrt14_16*(sx - 3.0f*s3x);
+ r9_x[5][5] = (cx + 7.0f*c3x)*0.125f;/* -r9_76x;*/
+ r9_x[6][1] = x->x_sqrt14_16*(s3x - 3.0f*sx);
+ r9_x[6][2] = x->x_sqrt7_8*(c3x - cx)*1.5f;
+ r9_x[6][5] = x->x_sqrt2_16*(3.0f*sx + 7.0f*s3x);
+ r9_x[6][6] = (9.0f*cx + 7.0f*c3x)*0.0625f;
+ r9_x[7][0] = x->x_sqrt14_16*(2.0f*s2x - s4x)*0.5f;
+ r9_x[7][3] = x->x_sqrt7_8*(c4x - c2x);
+ r9_x[7][4] = x->x_sqrt2_16*(2.0f*s2x - 7.0f*s4x);
+ r9_x[7][7] = (c2x + 7.0f*c4x)*0.125f;/* -r9_98x*/
+ r9_x[8][0] = x->x_sqrt35_64*(3.0f - 4.0f*c2x + c4x);
+ r9_x[8][3] = x->x_sqrt70_32*(s4x - 2.0f*s2x);
+ r9_x[8][4] = x->x_sqrt5_32*(7.0f*c4x - 3.0f - 4.0f*c2x);
+ r9_x[8][7] = x->x_sqrt10_4*(2.0f*s2x + 7.0f*s4x)*0.125f;
+ r9_x[8][8] = (9.0f + 20.0f*c2x + 35.0f*c4x)*0.015625f;
+
+ r9_x[0][3] = -r9_x[3][0];
+ r9_x[0][4] = r9_x[4][0];
+ r9_x[0][7] = -r9_x[7][0];
+ r9_x[0][8] = r9_x[8][0];
+ r9_x[1][2] = -r9_x[2][1];
+ r9_x[1][5] = r9_x[5][1];
+ r9_x[1][6] = -r9_x[6][1];
+ r9_x[2][5] = -r9_x[5][2];
+ r9_x[2][6] = r9_x[6][2];
+ r9_x[3][4] = -r9_x[4][3];
+ r9_x[3][7] = r9_x[7][3];
+ r9_x[3][8] = -r9_x[8][3];
+ r9_x[4][7] = -r9_x[7][4];
+ r9_x[4][8] = r9_x[8][4];
+ r9_x[5][6] = -r9_x[6][5];
+ r9_x[7][8] = -r9_x[8][7];
+
+ for(j=0; j<8; j+=2)
+ {
+ for(i=0; i<8; i+=2)
+ {
+ r9_zy[j][i] = r9_z[j][j]*r9_y[j][i];
+ r9_zy[j][i+1] = r9_z[j][j+1]*r9_y[j+1][i+1];
+
+ r9_zy[j+1][i] = r9_z[j+1][j]*r9_y[j][i];
+ r9_zy[j+1][i+1] = r9_z[j+1][j+1]*r9_y[j+1][i+1];
+ }
+ r9_zy[j][8] = r9_z[j][j]*r9_y[j][8];
+ r9_zy[j+1][8] = r9_z[j+1][j]*r9_y[j][8];
+ }
+ for(i=0; i<=8; i+=2)
+ {
+ r9_zy[8][i] = r9_y[8][i];
+ }
+
+ at = x->x_at9;
+ at += 2;
+
+ for(i=0; i<8; i++)
+ {
+ SETFLOAT(at, (r9_zy[i][0]*r9_x[0][0] + r9_zy[i][3]*r9_x[3][0] + r9_zy[i][4]*r9_x[4][0] + r9_zy[i][7]*r9_x[7][0] + r9_zy[i][8]*r9_x[8][0]));
+ at++;
+ SETFLOAT(at, (r9_zy[i][1]*r9_x[1][1] + r9_zy[i][2]*r9_x[2][1] + r9_zy[i][5]*r9_x[5][1] + r9_zy[i][6]*r9_x[6][1]));
+ at++;
+ SETFLOAT(at, (r9_zy[i][1]*r9_x[1][2] + r9_zy[i][2]*r9_x[2][2] + r9_zy[i][5]*r9_x[5][2] + r9_zy[i][6]*r9_x[6][2]));
+ at++;
+ SETFLOAT(at, (r9_zy[i][0]*r9_x[0][3] + r9_zy[i][3]*r9_x[3][3] + r9_zy[i][4]*r9_x[4][3] + r9_zy[i][7]*r9_x[7][3] + r9_zy[i][8]*r9_x[8][3]));
+ at++;
+ SETFLOAT(at, (r9_zy[i][0]*r9_x[0][4] + r9_zy[i][3]*r9_x[3][4] + r9_zy[i][4]*r9_x[4][4] + r9_zy[i][7]*r9_x[7][4] + r9_zy[i][8]*r9_x[8][4]));
+ at++;
+ SETFLOAT(at, (r9_zy[i][1]*r9_x[1][5] + r9_zy[i][2]*r9_x[2][5] + r9_zy[i][5]*r9_x[5][5] + r9_zy[i][6]*r9_x[6][5]));
+ at++;
+ SETFLOAT(at, (r9_zy[i][1]*r9_x[1][6] + r9_zy[i][2]*r9_x[2][6] + r9_zy[i][5]*r9_x[5][6] + r9_zy[i][6]*r9_x[6][6]));
+ at++;
+ SETFLOAT(at, (r9_zy[i][0]*r9_x[0][7] + r9_zy[i][3]*r9_x[3][7] + r9_zy[i][4]*r9_x[4][7] + r9_zy[i][7]*r9_x[7][7] + r9_zy[i][8]*r9_x[8][7]));
+ at++;
+ SETFLOAT(at, (r9_zy[i][0]*r9_x[0][8] + r9_zy[i][3]*r9_x[3][8] + r9_zy[i][4]*r9_x[4][8] + r9_zy[i][7]*r9_x[7][8] + r9_zy[i][8]*r9_x[8][8]));
+ at++;
+ }
+
+ SETFLOAT(at, (r9_zy[8][0]*r9_x[0][0] + r9_zy[8][4]*r9_x[4][0] + r9_zy[8][8]*r9_x[8][0]));
+ at++;
+ SETFLOAT(at, (r9_zy[8][2]*r9_x[2][1] + r9_zy[8][6]*r9_x[6][1]));
+ at++;
+ SETFLOAT(at, (r9_zy[8][2]*r9_x[2][2] + r9_zy[8][6]*r9_x[6][2]));
+ at++;
+ SETFLOAT(at, (r9_zy[8][0]*r9_x[0][3] + r9_zy[8][4]*r9_x[4][3] + r9_zy[8][8]*r9_x[8][3]));
+ at++;
+ SETFLOAT(at, (r9_zy[8][0]*r9_x[0][4] + r9_zy[8][4]*r9_x[4][4] + r9_zy[8][8]*r9_x[8][4]));
+ at++;
+ SETFLOAT(at, (r9_zy[8][2]*r9_x[2][5] + r9_zy[8][6]*r9_x[6][5]));
+ at++;
+ SETFLOAT(at, (r9_zy[8][2]*r9_x[2][6] + r9_zy[8][6]*r9_x[6][6]));
+ at++;
+ SETFLOAT(at, (r9_zy[8][0]*r9_x[0][7] + r9_zy[8][4]*r9_x[4][7] + r9_zy[8][8]*r9_x[8][7]));
+ at++;
+ SETFLOAT(at, (r9_zy[8][0]*r9_x[0][8] + r9_zy[8][4]*r9_x[4][8] + r9_zy[8][8]*r9_x[8][8]));
+
+ outlet_anything(x->x_out9, x->x_s_matrix, x->x_size9, x->x_at9);
+ }
+
+ r9_z[0][0] = c3z;
+ r9_z[0][1] = -s3z;
+ r9_z[1][0] = s3z;
+ r9_z[1][1] = c3z;
+ r9_z[2][2] = c2z;
+ r9_z[2][3] = -s2z;
+ r9_z[3][2] = s2z;
+ r9_z[3][3] = c2z;
+ r9_z[4][4] = cz;
+ r9_z[4][5] = -sz;
+ r9_z[5][4] = sz;
+ r9_z[5][5] = cz;
+ r9_z[6][6] = 1.0f;
+ /*y
+ r7_11=(15*c + c3)/16;
+ r7_22=(5 + 3*c2)/8;
+ r7_31 = x->x_sqrt6*(5*s + s3)/16;
+ r7_33=(5*c + 3*c3)/8;
+ r7_42 = x->x_sqrt6*(s2)/4;
+ r7_44=(c2);
+ r7_51 = x->x_sqrt15*(c - c3)/16;
+ r7_53 = x->x_sqrt10*(-s + 3*s3)/16;
+ r7_55=(c + 15*c3)/16;
+ r7_62 = x->x_sqrt15*(1 - c2)/8;
+ r7_64 = x->x_sqrt10*(s2)/4;
+ r7_66=(3 + 5*c2)/8;
+ r7_71 = x->x_sqrt10*(3*s - s3)/16;
+ r7_73 = x->x_sqrt15*(c - c3)/8 = 2*r7_51;
+ r7_75 = x->x_sqrt6*(s + 5*s3)/16;
+ r7_77=(3*c + 5*c3)/8;
+
+ */
+ r9_y[0][0] = (15.0f*cy + c3y)*0.0625f;/* -r7_31y, r7_51y, -r7_71y;*/
+ r9_y[1][1] = (5.0f + 3.0f*c2y)*0.125f;/* -r7_42y, r7_62y;*/
+ r9_y[2][0] = x->x_sqrt6_4*(5.0f*sy + s3y)*0.25f;
+ r9_y[2][2] = (5.0f*cy + 3.0f*c3y)*0.125f;/* -r7_53y, r7_73y;*/
+ r9_y[3][1] = x->x_sqrt6_4*s2y;
+ r9_y[3][3] = c2y;/* -r7_64y;*/
+ r9_y[6][2] = x->x_sqrt15_8*(cy - c3y);
+ r9_y[4][0] = r9_y[6][2]*0.5f;
+ r9_y[4][2] = x->x_sqrt10_4*(3.0f*s3y - sy)*0.25f;
+ r9_y[4][4] = (cy + 15.0f*c3y)*0.0625f;/* -r7_75y;*/
+ r9_y[5][1] = x->x_sqrt15_8*(1.0f - c2y);
+ r9_y[5][3] = x->x_sqrt10_4*s2y;
+ r9_y[5][5] = (3.0f + 5.0f*c2y)*0.125f;
+ r9_y[6][0] = x->x_sqrt10_4*(3.0f*sy - s3y)*0.25f;
+
+ r9_y[6][4] = x->x_sqrt6_4*(sy + 5.0f*s3y)*0.25f;
+ r9_y[6][6] = (3.0f*cy + 5.0f*c3y)*0.125f;
+
+ r9_y[0][2] = -r9_y[2][0];
+ r9_y[0][4] = r9_y[4][0];
+ r9_y[0][6] = -r9_y[6][0];
+ r9_y[1][3] = -r9_y[3][1];
+ r9_y[1][5] = r9_y[5][1];
+ r9_y[2][4] = -r9_y[4][2];
+ r9_y[2][6] = r9_y[6][2];
+ r9_y[3][5] = -r9_y[5][3];
+ r9_y[4][6] = -r9_y[6][4];
+
+ /*x
+ r7_11=(5 + 3*c2)/8;
+ r7_22=(15*c + c3)/16;
+ r7_32 = x->x_sqrt6*(5*s + s3)/16;
+ r7_33=(5*c + 3*c3)/8;
+ r7_41 = x->x_sqrt6*(-s2)/4;
+ r7_44=(c2);
+ r7_51 = x->x_sqrt15*(-1 + c2)/8;
+ r7_54 = x->x_sqrt10*(s2)/4;
+ r7_55=(3 + 5*c2)/8;
+ r7_62 = x->x_sqrt15*(-c + c3)/16;
+ r7_63 = x->x_sqrt10*(s - 3*s3)/16;
+ r7_66=(c + 15*c3)/16;
+ r7_72 = x->x_sqrt10*(-3*s + s3)/16;
+ r7_73 = x->x_sqrt15*(-c + c3)/8 = 2*r7_62;
+ r7_76 = x->x_sqrt6*(s + 5*s3)/16;
+ r7_77=(3*c + 5*c3)/8;
+ */
+
+ r9_x[0][0] = (5.0f + 3.0f*c2x)*0.125f;/* -r7_41, r7_51;*/
+ r9_x[1][1] = (15.0f*cx + c3x)*0.0625f;/* -r7_32, r7_62, -r7_72;*/
+ r9_x[2][1] = x->x_sqrt6_4*(5.0f*sx + s3x)*0.25f;
+ r9_x[2][2] = (5.0f*cx + 3.0f*c3x)*0.125f;/* */
+ r9_x[3][0] = -x->x_sqrt6_4*s2x;
+ r9_x[3][3] = c2x;
+ r9_x[4][0] = x->x_sqrt15_8*(c2x - 1.0f);
+ r9_x[4][3] = x->x_sqrt10_4*s2x;
+ r9_x[4][4] = (3.0f + 5.0f*c2x)*0.125f;
+ r9_x[6][2] = x->x_sqrt15_8*(c3x - cx);
+ r9_x[5][1] = r9_x[6][2]*0.5f;
+ r9_x[5][2] = x->x_sqrt10_4*(sx - 3.0f*s3x)*0.25f;
+ r9_x[5][5] = (cx + 15.0f*c3x)*0.0625f;
+ r9_x[6][1] = x->x_sqrt10_4*(s3x - 3.0f*sx)*0.25f;
+
+ r9_x[6][5] = x->x_sqrt6_4*(sx + 5.0f*s3x)*0.25f;
+ r9_x[6][6] = (3.0f*cx + 5.0f*c3x)*0.125f;
+
+ r9_x[0][3] = -r9_x[3][0];
+ r9_x[0][4] = r9_x[4][0];
+ r9_x[1][2] = -r9_x[2][1];
+ r9_x[1][5] = r9_x[5][1];
+ r9_x[1][6] = -r9_x[6][1];
+ r9_x[2][5] = -r9_x[5][2];
+ r9_x[2][6] = r9_x[6][2];
+ r9_x[3][4] = -r9_x[4][3];
+ r9_x[5][6] = -r9_x[6][5];
+
+ for(j=0; j<6; j+=2)
+ {
+ for(i=0; i<6; i+=2)
+ {
+ r9_zy[j][i] = r9_z[j][j]*r9_y[j][i];
+ r9_zy[j][i+1] = r9_z[j][j+1]*r9_y[j+1][i+1];
+
+ r9_zy[j+1][i] = r9_z[j+1][j]*r9_y[j][i];
+ r9_zy[j+1][i+1] = r9_z[j+1][j+1]*r9_y[j+1][i+1];
+ }
+ r9_zy[j][6] = r9_z[j][j]*r9_y[j][6];
+ r9_zy[j+1][6] = r9_z[j+1][j]*r9_y[j][6];
+ }
+ for(i=0; i<=6; i+=2)
+ {
+ r9_zy[6][i] = r9_y[6][i];
+ }
+
+ at = x->x_at7;
+ at += 2;
+
+ for(i=0; i<6; i++)
+ {
+ SETFLOAT(at, (r9_zy[i][0]*r9_x[0][0] + r9_zy[i][3]*r9_x[3][0] + r9_zy[i][4]*r9_x[4][0]));
+ at++;
+ SETFLOAT(at, (r9_zy[i][1]*r9_x[1][1] + r9_zy[i][2]*r9_x[2][1] + r9_zy[i][5]*r9_x[5][1] + r9_zy[i][6]*r9_x[6][1]));
+ at++;
+ SETFLOAT(at, (r9_zy[i][1]*r9_x[1][2] + r9_zy[i][2]*r9_x[2][2] + r9_zy[i][5]*r9_x[5][2] + r9_zy[i][6]*r9_x[6][2]));
+ at++;
+ SETFLOAT(at, (r9_zy[i][0]*r9_x[0][3] + r9_zy[i][3]*r9_x[3][3] + r9_zy[i][4]*r9_x[4][3]));
+ at++;
+ SETFLOAT(at, (r9_zy[i][0]*r9_x[0][4] + r9_zy[i][3]*r9_x[3][4] + r9_zy[i][4]*r9_x[4][4]));
+ at++;
+ SETFLOAT(at, (r9_zy[i][1]*r9_x[1][5] + r9_zy[i][2]*r9_x[2][5] + r9_zy[i][5]*r9_x[5][5] + r9_zy[i][6]*r9_x[6][5]));
+ at++;
+ SETFLOAT(at, (r9_zy[i][1]*r9_x[1][6] + r9_zy[i][2]*r9_x[2][6] + r9_zy[i][5]*r9_x[5][6] + r9_zy[i][6]*r9_x[6][6]));
+ at++;
+ }
+
+ SETFLOAT(at, (r9_zy[6][0]*r9_x[0][0] + r9_zy[6][4]*r9_x[4][0]));
+ at++;
+ SETFLOAT(at, (r9_zy[6][2]*r9_x[2][1] + r9_zy[6][6]*r9_x[6][1]));
+ at++;
+ SETFLOAT(at, (r9_zy[6][2]*r9_x[2][2] + r9_zy[6][6]*r9_x[6][2]));
+ at++;
+ SETFLOAT(at, (r9_zy[6][0]*r9_x[0][3] + r9_zy[6][4]*r9_x[4][3]));
+ at++;
+ SETFLOAT(at, (r9_zy[6][0]*r9_x[0][4] + r9_zy[6][4]*r9_x[4][4]));
+ at++;
+ SETFLOAT(at, (r9_zy[6][2]*r9_x[2][5] + r9_zy[6][6]*r9_x[6][5]));
+ at++;
+ SETFLOAT(at, (r9_zy[6][2]*r9_x[2][6] + r9_zy[6][6]*r9_x[6][6]));
+
+ outlet_anything(x->x_out7, x->x_s_matrix, x->x_size7, x->x_at7);
+ }
+
+ r9_z[0][0] = c2z;
+ r9_z[0][1] = -s2z;
+ r9_z[1][0] = s2z;
+ r9_z[1][1] = c2z;
+ r9_z[2][2] = cz;
+ r9_z[2][3] = -sz;
+ r9_z[3][2] = sz;
+ r9_z[3][3] = cz;
+ r9_z[4][4] = 1.0f;
+ /*y
+ r5_11=(3 + c2)/4;
+ r5_22=(c);
+ r5_31 = (s2)/2;
+ r5_33=(c2);
+ r5_42 = (s);
+ r5_44=(c);
+ r5_51 = x->x_sqrt3*(1 - c2)/4;
+ r5_53 = x->x_sqrt3*(s2)/2;
+ r5_55=(1 + 3*c2)/4;
+ */
+ r9_y[0][0] = (3.0f + c2y)*0.25f;/* -r5_31y, r5_51y;*/
+ r9_y[1][1] = cy;/* -r5_42y;*/
+ r9_y[2][0] = s2y*0.5f;
+ r9_y[2][2] = c2y;/* -r5_53y;*/
+ r9_y[3][1] = sy;
+ r9_y[3][3] = cy;
+ r9_y[4][0] = x->x_sqrt3_2*(1.0f - c2y)*0.5f;
+ r9_y[4][2] = x->x_sqrt3_2*s2y;
+ r9_y[4][4] = (1.0f + 3.0f*c2y)*0.25f;
+
+ r9_y[0][2] = -r9_y[2][0];
+ r9_y[0][4] = r9_y[4][0];
+ r9_y[1][3] = -r9_y[3][1];
+ r9_y[2][4] = -r9_y[4][2];
+
+ /*x
+ r5_11=(3 + c2)/4;
+ r5_22=(c);
+ r5_32 = (s);
+ r5_33=(c);
+ r5_41 = (-s2)/2;
+ r5_44=(c2);
+ r5_51 = x->x_sqrt3*(-1 + c2)/4;
+ r5_54 = x->x_sqrt3*(s2)/2;
+ r5_55=(1 + 3*c2)/4;
+ */
+
+ r9_x[0][0] = (3.0f + c2x)*0.25f;
+ r9_x[1][1] = cx;
+ r9_x[2][1] = sx;
+ r9_x[2][2] = cx;
+ r9_x[3][0] = -0.5f*s2x;
+ r9_x[3][3] = c2x;
+ r9_x[4][0] = x->x_sqrt3_2*(c2x - 1.0f)*0.5f;
+ r9_x[4][3] = x->x_sqrt3_2*s2x;
+ r9_x[4][4] = (1.0f + 3.0f*c2x)*0.25f;
+
+ r9_x[0][3] = -r9_x[3][0];
+ r9_x[0][4] = r9_x[4][0];
+ r9_x[1][2] = -r9_x[2][1];
+ r9_x[3][4] = -r9_x[4][3];
+
+ for(j=0; j<4; j+=2)
+ {
+ for(i=0; i<4; i+=2)
+ {
+ r9_zy[j][i] = r9_z[j][j]*r9_y[j][i];
+ r9_zy[j][i+1] = r9_z[j][j+1]*r9_y[j+1][i+1];
+
+ r9_zy[j+1][i] = r9_z[j+1][j]*r9_y[j][i];
+ r9_zy[j+1][i+1] = r9_z[j+1][j+1]*r9_y[j+1][i+1];
+ }
+ r9_zy[j][4] = r9_z[j][j]*r9_y[j][4];
+ r9_zy[j+1][4] = r9_z[j+1][j]*r9_y[j][4];
+ }
+ for(i=0; i<=4; i+=2)
+ {
+ r9_zy[4][i] = r9_y[4][i];
+ }
+
+ at = x->x_at5;
+ at += 2;
+
+ for(i=0; i<4; i++)
+ {
+ SETFLOAT(at, (r9_zy[i][0]*r9_x[0][0] + r9_zy[i][3]*r9_x[3][0] + r9_zy[i][4]*r9_x[4][0]));
+ at++;
+ SETFLOAT(at, (r9_zy[i][1]*r9_x[1][1] + r9_zy[i][2]*r9_x[2][1]));
+ at++;
+ SETFLOAT(at, (r9_zy[i][1]*r9_x[1][2] + r9_zy[i][2]*r9_x[2][2]));
+ at++;
+ SETFLOAT(at, (r9_zy[i][0]*r9_x[0][3] + r9_zy[i][3]*r9_x[3][3] + r9_zy[i][4]*r9_x[4][3]));
+ at++;
+ SETFLOAT(at, (r9_zy[i][0]*r9_x[0][4] + r9_zy[i][3]*r9_x[3][4] + r9_zy[i][4]*r9_x[4][4]));
+ at++;
+ }
+
+ SETFLOAT(at, (r9_zy[4][0]*r9_x[0][0] + r9_zy[4][4]*r9_x[4][0]));
+ at++;
+ SETFLOAT(at, (r9_zy[4][2]*r9_x[2][1]));
+ at++;
+ SETFLOAT(at, (r9_zy[4][2]*r9_x[2][2]));
+ at++;
+ SETFLOAT(at, (r9_zy[4][0]*r9_x[0][3] + r9_zy[4][4]*r9_x[4][3]));
+ at++;
+ SETFLOAT(at, (r9_zy[4][0]*r9_x[0][4] + r9_zy[4][4]*r9_x[4][4]));
+
+ outlet_anything(x->x_out5, x->x_s_matrix, x->x_size5, x->x_at5);
+ }
+
+ r9_z[0][0] = cz;
+ r9_z[0][1] = -sz;
+ r9_z[1][0] = sz;
+ r9_z[1][1] = cz;
+ r9_z[2][2] = 1.0f;
+ /*y
+ r3_11=(c);
+ r3_22=(1);
+ r3_31 = (s);
+ r3_33=(c);
+ */
+ r9_y[0][0] = cy;/* -r3_31y;*/
+ r9_y[1][1] = 1.0f;
+ r9_y[2][0] = sy;
+ r9_y[2][2] = cy;
+
+ r9_y[0][2] = -r9_y[2][0];
+
+ /*x
+ r3_11=(1);
+ r3_22=(c);
+ r3_32 = (s);
+ r3_33=(c);
+ */
+ r9_x[0][0] = 1.0f;
+ r9_x[1][1] = cx;/* -r3_32x;*/
+ r9_x[2][1] = sx;
+ r9_x[2][2] = cx;
+
+ r9_x[1][2] = -r9_x[2][1];
+
+ r9_zy[0][0] = cz*r9_y[0][0];
+ r9_zy[0][1] = -sz*r9_y[1][1];
+ r9_zy[0][2] = cz*r9_y[0][2];
+
+ r9_zy[1][0] = sz*r9_y[0][0];
+ r9_zy[1][1] = cz*r9_y[1][1];
+ r9_zy[1][2] = sz*r9_y[0][2];
+
+ r9_zy[2][0] = r9_y[2][0];
+ r9_zy[2][1] = 0.0f;
+ r9_zy[2][2] = r9_y[2][2];
+
+ at = x->x_at3;
+ at += 2;
+
+ for(i=0; i<2; i++)
+ {
+ SETFLOAT(at, (r9_zy[i][0]*r9_x[0][0]));
+ at++;
+ SETFLOAT(at, (r9_zy[i][1]*r9_x[1][1] + r9_zy[i][2]*r9_x[2][1]));
+ at++;
+ SETFLOAT(at, (r9_zy[i][1]*r9_x[1][2] + r9_zy[i][2]*r9_x[2][2]));
+ at++;
+ }
+
+ SETFLOAT(at, (r9_zy[2][0]*r9_x[0][0]));
+ at++;
+ SETFLOAT(at, (r9_zy[2][2]*r9_x[2][1]));
+ at++;
+ SETFLOAT(at, (r9_zy[2][2]*r9_x[2][2]));
+
+ outlet_anything(x->x_out3, x->x_s_matrix, x->x_size3, x->x_at3);
+}
+
+static void ambi_rot_list(t_ambi_rot *x, t_symbol *s, int argc, t_atom *argv)
+{
+ if(argc == 1)
+ ambi_rot_float(x, atom_getfloatarg(0, argc, argv));/* = ambi_rot_z(); */
+ else if(argc == 2)
+ ambi_rot_zy(x, atom_getfloatarg(0, argc, argv), atom_getfloatarg(1, argc, argv));
+ else if(argc >= 3)
+ ambi_rot_zyx(x, atom_getfloatarg(0, argc, argv), atom_getfloatarg(1, argc, argv), atom_getfloatarg(2, argc, argv));
+}
+
+static void ambi_rot_free(t_ambi_rot *x)
+{
+ if(x->x_size11)
+ freebytes(x->x_at11, x->x_size11 * sizeof(t_atom));
+ if(x->x_size9)
+ freebytes(x->x_at9, x->x_size9 * sizeof(t_atom));
+ if(x->x_size7)
+ freebytes(x->x_at7, x->x_size7 * sizeof(t_atom));
+ if(x->x_size5)
+ freebytes(x->x_at5, x->x_size5 * sizeof(t_atom));
+ if(x->x_size3)
+ freebytes(x->x_at3, x->x_size3 * sizeof(t_atom));
+ if(x->x_size2)
+ freebytes(x->x_at2, x->x_size2 * sizeof(t_atom));
+}
+
+static void *ambi_rot_new(t_floatarg forder)
+{
+ t_ambi_rot *x = (t_ambi_rot *)pd_new(ambi_rot_class);
+ t_atom *at;
+ int i=(int)forder;
+
+ if(i < 1)
+ i = 1;
+ if(i > 12)
+ i = 12;
+ x->x_order = i;
+ x->x_size2 = 2*2 + 2;
+ x->x_at2 = (t_atom *)getbytes(x->x_size2 * sizeof(t_atom));
+ at = x->x_at2;
+ SETFLOAT(at, 2.0f);
+ at++;
+ SETFLOAT(at, 2.0f);
+ at++;
+ for(i=0; i<4; i++)
+ {
+ SETFLOAT(at, 0.0f);
+ at++;
+ }
+ x->x_size3 = 3*3 + 2;
+ x->x_at3 = (t_atom *)getbytes(x->x_size3 * sizeof(t_atom));
+ at = x->x_at3;
+ SETFLOAT(at, 3.0f);
+ at++;
+ SETFLOAT(at, 3.0f);
+ at++;
+ for(i=0; i<9; i++)
+ {
+ SETFLOAT(at, 0.0f);
+ at++;
+ }
+ x->x_out3 = outlet_new(&x->x_obj, &s_list);
+ if(x->x_order >= 2)
+ {
+ x->x_size5 = 5*5 + 2;
+ x->x_at5 = (t_atom *)getbytes(x->x_size5 * sizeof(t_atom));
+ at = x->x_at5;
+ SETFLOAT(at, 5.0f);
+ at++;
+ SETFLOAT(at, 5.0f);
+ at++;
+ for(i=0; i<25; i++)
+ {
+ SETFLOAT(at, 0.0f);
+ at++;
+ }
+ x->x_out5 = outlet_new(&x->x_obj, &s_list);
+ }
+ else
+ {
+ x->x_size5 = 0;
+ x->x_at5 = (t_atom *)0;
+ }
+ if(x->x_order >= 3)
+ {
+ x->x_size7 = 7*7 + 2;
+ x->x_at7 = (t_atom *)getbytes(x->x_size7 * sizeof(t_atom));
+ at = x->x_at7;
+ SETFLOAT(at, 7.0f);
+ at++;
+ SETFLOAT(at, 7.0f);
+ at++;
+ for(i=0; i<49; i++)
+ {
+ SETFLOAT(at, 0.0f);
+ at++;
+ }
+ x->x_out7 = outlet_new(&x->x_obj, &s_list);
+ }
+ else
+ {
+ x->x_size7 = 0;
+ x->x_at7 = (t_atom *)0;
+ }
+ if(x->x_order >= 4)
+ {
+ x->x_size9 = 9*9 + 2;
+ x->x_at9 = (t_atom *)getbytes(x->x_size9 * sizeof(t_atom));
+ at = x->x_at9;
+ SETFLOAT(at, 9.0f);
+ at++;
+ SETFLOAT(at, 9.0f);
+ at++;
+ for(i=0; i<81; i++)
+ {
+ SETFLOAT(at, 0.0f);
+ at++;
+ }
+ x->x_out9 = outlet_new(&x->x_obj, &s_list);
+ }
+ else
+ {
+ x->x_size9 = 0;
+ x->x_at9 = (t_atom *)0;
+ }
+
+ if(x->x_order >= 5)
+ {
+ x->x_size11 = 11*11 + 2;
+ x->x_at11 = (t_atom *)getbytes(x->x_size11 * sizeof(t_atom));
+ at = x->x_at11;
+ SETFLOAT(at, 11.0f);
+ at++;
+ SETFLOAT(at, 11.0f);
+ at++;
+ for(i=0; i<121; i++)
+ {
+ SETFLOAT(at, 0.0f);
+ at++;
+ }
+ x->x_out11 = outlet_new(&x->x_obj, &s_list);
+ }
+ else
+ {
+ x->x_size11 = 0;
+ x->x_at11 = (t_atom *)0;
+ }
+
+ if(x->x_order >= 6)
+ x->x_out13 = outlet_new(&x->x_obj, &s_list);
+
+ if(x->x_order >= 7)
+ x->x_out15 = outlet_new(&x->x_obj, &s_list);
+
+ if(x->x_order >= 8)
+ x->x_out17 = outlet_new(&x->x_obj, &s_list);
+
+ if(x->x_order >= 9)
+ x->x_out19 = outlet_new(&x->x_obj, &s_list);
+
+ if(x->x_order >= 10)
+ x->x_out21 = outlet_new(&x->x_obj, &s_list);
+
+ if(x->x_order >= 11)
+ x->x_out23 = outlet_new(&x->x_obj, &s_list);
+
+ if(x->x_order >= 12)
+ x->x_out25 = outlet_new(&x->x_obj, &s_list);
+
+ x->x_sqrt2_16 = (float)(sqrt(2.0) / 16.0);
+ x->x_sqrt3_2 = (float)(sqrt(3.0) / 2.0);
+ x->x_sqrt5_32 = (float)(sqrt(5.0) / 32.0);
+ x->x_sqrt6_4 = (float)(sqrt(6.0) / 4.0);
+ x->x_sqrt7_8 = (float)(sqrt(7.0) / 8.0);
+ x->x_sqrt10_4 = (float)(sqrt(10.0) / 4.0);
+ x->x_sqrt14_16 = (float)(sqrt(14.0) / 16.0);
+ x->x_sqrt15_8 = (float)(sqrt(15.0) / 8.0);
+ x->x_sqrt35_64 = (float)(sqrt(35.0) / 64.0);
+ x->x_sqrt70_32 = (float)(sqrt(70.0) / 32.0);
+
+ x->x_pi_over_180 = (float)(4.0 * atan(1.0) / 180.0);
+
+ x->x_s_matrix = gensym("matrix");
+ return (x);
+}
+
+void ambi_rot_setup(void)
+{
+ ambi_rot_class = class_new(gensym("ambi_rot"), (t_newmethod)ambi_rot_new, (t_method)ambi_rot_free,
+ sizeof(t_ambi_rot), 0, A_DEFFLOAT, 0);
+ class_addfloat(ambi_rot_class, (t_method)ambi_rot_float);
+ class_addlist(ambi_rot_class, (t_method)ambi_rot_list);
+ class_sethelpsymbol(ambi_rot_class, gensym("iemhelp2/help-ambi_rot"));
+}
diff --git a/src/configure.ac b/src/configure.ac
new file mode 100644
index 0000000..937ec7f
--- /dev/null
+++ b/src/configure.ac
@@ -0,0 +1,292 @@
+dnl Process this file with autoconf to produce a configure script.
+AC_INIT(iem_bin_ambi.c)
+
+dnl Checks for programs.
+AC_PROG_CC
+
+AC_SUBST(STK)
+AC_SUBST(DFLAGS)
+AC_SUBST(LFLAGS)
+AC_SUBST(EXT)
+AC_SUBST(LD)
+AC_SUBST(STRIP)
+AC_SUBST(STRIPFLAGS)
+AC_SUBST(IEMBINAMBI_VERSION)
+AC_SUBST(REFERENCEPATH)
+AC_SUBST(PDLIBDIR)
+AC_SUBST(INCLUDES)
+
+
+AC_ARG_WITH(pdversion, [ --with-pdversion=<ver> enforce a certain pd-version (e.g. 0.37)])
+AC_ARG_WITH(version, [ --with-version=<ver> enforce a certain iem_bin_ambi-version (e.g. 0.1)])
+AC_ARG_WITH(extension, [ --with-extension=<ext> enforce a certain extension for the dynamic library (e.g. dll)])
+AC_ARG_WITH(pdpath, [ --with-pd=</path/to/pd> where to look for pd-headers and and -libs])
+AC_ARG_ENABLE(PIC, [ --disable-PIC disable compilation with PIC-flag])
+
+dnl Checks for libraries.
+dnl Replace `main' with a function in -lc:
+AC_CHECK_LIB(c, main)
+AC_CHECK_LIB(crtdll, fclose)
+
+dnl Replace `main' with a function in -lm:
+AC_CHECK_LIB(m, main)
+dnl Replace `main' with a function in -lpthread:
+dnl AC_CHECK_LIB(pthread, main)
+dnl Replace `main' with a function in -lstk:
+dnl AC_CHECK_LIB(stk, main, STK=yes)
+
+
+if test "x$with_pd" != "x"; then
+ if test -d "${with_pd}/src"; then
+ INCLUDES="-I${with_pd}/src ${INCLUDES}"
+ fi
+ if test -d "${with_pd}/bin"; then
+ LIBS="-L${with_pd}/bin ${LIBS}"
+ fi
+fi
+
+if test "x$includedir" != "x"; then
+ for id in $includedir
+ do
+ if test -d $id; then INCLUDES="-I$id $INCLUDES"; fi
+ done
+fi
+if test "x$libdir" != "x"; then
+ for id in $libdir
+ do
+ if test -d $id; then LIBS="-L$id $LIBS"; fi
+ done
+fi
+
+AC_CHECK_LIB(pd, nullfn)
+
+dnl Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS(stdlib.h stdio.h string.h math.h time.h sys/time.h)
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_HEADER_TIME
+
+dnl Checks for library functions.
+AC_FUNC_MMAP
+AC_CHECK_FUNCS(select socket strerror)
+
+
+### make-depend flags
+if test "x$ac_cv_c_compiler_gnu" = "xyes"; then
+ AC_SUBST(MAKEDEP_FLAGS, "-MM")
+else
+ AC_SUBST(MAKEDEP_FLAGS, "-M")
+fi
+
+dnl check for "-mms-bitfields" cflag
+dnl why is there no generic compiler-check for a given flag ?
+dnl it would make things so easy: AC_CHECK_FLAG([-mms-bitfields],,)
+AC_MSG_CHECKING("ms-bitfields")
+cat > conftest.c << EOF
+int main(){
+ return 0;
+}
+EOF
+if ${CC} ${INCLUDES} ${DFLAGS} -o conftest.o conftest.c ${CFLAGS} -mms-bitfields > /dev/null 2>&1
+then
+ echo "yes"
+ CFLAGS="${CFLAGS} -mms-bitfields"
+else
+ echo "no"
+fi
+
+
+
+
+dnl isn't there a better way to check for good linker/stripper ?
+
+dnl if we don't have $LD set, we set it to $(CC)
+dnl LD=${LD:=$CC}
+if test "x$LD" = "x"
+then
+ if test "x$host" != "x"
+ then
+ LD=${host}-ld
+ if $(which ${LD} > /dev/null)
+ then
+ :
+ else
+ LD=""
+ fi
+ fi
+fi
+LD=${LD:=$CC}
+
+dnl if we don't have $STRIP set, we set it to ${host}-strip or strip
+AC_CHECK_TOOL([STRIP], [strip], [true])
+AC_MSG_CHECKING([if strip is GNU strip])
+if $STRIP -V 2>&1 | grep GNU > /dev/null
+then
+ AC_SUBST(STRIPFLAGS, "--strip-unneeded")
+ AC_MSG_RESULT([yes])
+else
+ AC_SUBST(STRIPFLAGS,"-x")
+ AC_MSG_RESULT([no])
+fi
+
+DFLAGS=""
+
+
+if test "x$enable_PIC" != "xno"; then
+AC_MSG_CHECKING("PIC")
+cat > conftest.c << EOF
+int main(){
+ return 0;
+}
+EOF
+if ${CC} ${INCLUDES} ${DFLAGS} -o conftest.o conftest.c ${CFLAGS} -fPIC > /dev/null 2>&1
+then
+ echo "yes"
+ CFLAGS="${CFLAGS} -fPIC"
+else
+ echo "no"
+fi
+fi
+
+
+dnl
+dnl OK, checks for machines are here now
+dnl
+if test `uname -s` = Linux;
+then
+ LFLAGS="-export_dynamic -shared"
+ CFLAGS="$CFLAGS"
+ EXT=pd_linux
+fi
+
+dnl This should use '-bundle_loader /path/to/pd/bin/pd' instead of'-undefined suppress'
+dnl then strip might do something
+if test `uname -s` = Darwin;
+then
+ LD=cc
+ LFLAGS="-bundle -undefined suppress -flat_namespace"
+ EXT=pd_darwin
+fi
+
+if test `uname | sed -e 's/^MINGW.*/NT/'` = NT;
+then
+ LD=gcc
+ INCLUDES="-I@prefix@/src"
+ DFLAGS="-D__WIN32__"
+ LFLAGS="-shared @prefix@/bin/pd.dll"
+ EXT=dll
+else
+ PDLIBDIR="/lib/pd"
+fi
+
+if test `uname -s` = IRIX64;
+then
+ LFLAGS="-n32 -DUNIX -DIRIX -DN32 -woff 1080,1064,1185 \
+ -OPT:roundoff=3 -OPT:IEEE_arithmetic=3 -OPT:cray_ivdep=true \
+ -shared -rdata_shared"
+ EXT=pd_irix6
+ dnl DFLAGS="-DUNIX -DIRIX6"
+fi
+
+if test `uname -s` = IRIX32;
+then
+ LFLAGS="-o32 -DUNIX -DIRIX -O2
+ -shared -rdata_shared"
+ EXT=pd_irix5
+ dnl DFLAGS="-DUNIX -DIRIX5"
+fi
+
+
+if test "x$with_extension" != "x"
+then
+ EXT=$with_extension
+fi
+
+
+dnl Checks for pd-version, to set the correct help-path
+AC_MSG_CHECKING("pd\>=0.37")
+
+if test "$with_pdversion" != ""
+then
+echo -n "($with_pdversion)... "
+ PD_VERSION="$with_pdversion"
+else
+if test "x$cross_compiling" = "xno"
+then
+
+cat > conftest.c << EOF
+#include <stdio.h>
+#include "m_pd.h"
+int main(){
+ printf("%d.%d\n", PD_MAJOR_VERSION, PD_MINOR_VERSION);
+ return 0;
+}
+EOF
+
+ if $CC $INCLUDES -o conftest.o conftest.c > /dev/null 2>&1
+ then
+ PD_VERSION=`./conftest.o`
+ else
+ PD_VERSION=""
+ fi
+ echo -n $PD_VERSION
+else
+dnl we are cross-compiling...
+ echo -n "(X)..."
+ PD_VERSION="0.38"
+fi
+fi
+
+let PD_MAJORVERSION=`echo $PD_VERSION | cut -d"." -f1`+0
+let PD_MINORVERSION=`echo $PD_VERSION | cut -d"." -f2`+0
+
+
+
+if test "$PD_MAJORVERSION" -gt 0 || test "$PD_MINORVERSION" -ge 37
+then
+ REFERENCEPATH=extra/help-
+ echo " yes"
+else
+ REFERENCEPATH=doc/5.reference/
+ echo " no"
+fi
+
+
+dnl check for iem_bin_ambi-version (but why...)
+AC_MSG_CHECKING("iem_bin_ambi-version")
+
+if test "$with_version" != ""
+then
+ echo -n "($with_version)... "
+ IEMBINAMBI_VERSION="$with_version"
+else
+
+if test "x$cross_compiling" = "xno"
+then
+cat > conftest.c << EOF
+#include <stdio.h>
+#include "iem_bin_ambi.h"
+int main(){
+ printf("%s\n", VERSION);
+ return 0;
+}
+EOF
+
+if $CC $INCLUDES -o conftest.o conftest.c > /dev/null 2>&1
+then
+ IEMBINAMBI_VERSION=`./conftest.o`
+ echo "$IEMBINAMBI_VERSION"
+else
+ IEMBINAMBI_VERSION=""
+ echo "(unknown)"
+fi
+else
+ IEMBINAMBI_VERSION="X"
+ echo "(X)"
+fi
+fi
+
+AC_OUTPUT(Make.config)
+
+rm -f conftest.*
diff --git a/src/iem_ambi.c b/src/iem_ambi.c
new file mode 100644
index 0000000..7b06298
--- /dev/null
+++ b/src/iem_ambi.c
@@ -0,0 +1,44 @@
+/* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution.
+
+iem_ambi written by Thomas Musil, Copyright (c) IEM KUG Graz Austria 2000 - 2005 */
+
+#ifdef NT
+#pragma warning( disable : 4244 )
+#pragma warning( disable : 4305 )
+#endif
+
+
+#include "m_pd.h"
+#include "iemlib.h"
+
+static t_class *iem_ambi_class;
+
+static void *iem_ambi_new(void)
+{
+ t_object *x = (t_object *)pd_new(iem_ambi_class);
+
+ return (x);
+}
+
+void ambi_encode_setup(void);
+void ambi_decode_setup(void);
+void ambi_decode2_setup(void);
+void ambi_decode3_setup(void);
+void ambi_decode_cube_setup(void);
+void ambi_rot_setup(void);
+
+/* ------------------------ setup routine ------------------------- */
+
+void iem_ambi_setup(void)
+{
+ ambi_encode_setup();
+ ambi_decode_setup();
+ ambi_decode2_setup();
+ ambi_decode3_setup();
+ ambi_decode_cube_setup();
+ ambi_rot_setup();
+
+ post("iem_ambi (R-1.16) library loaded! (c) Thomas Musil 05.2005");
+ post(" musil%ciem.at iem KUG Graz Austria", '@');
+}
diff --git a/src/iem_ambi.dsp b/src/iem_ambi.dsp
new file mode 100644
index 0000000..4285328
--- /dev/null
+++ b/src/iem_ambi.dsp
@@ -0,0 +1,85 @@
+# Microsoft Developer Studio Project File - Name="iem_ambi" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** NICHT BEARBEITEN **
+
+# TARGTYPE "Win32 (x86) External Target" 0x0106
+
+CFG=iem_ambi - Win32 Debug
+!MESSAGE Dies ist kein gültiges Makefile. Zum Erstellen dieses Projekts mit NMAKE
+!MESSAGE verwenden Sie den Befehl "Makefile exportieren" und führen Sie den Befehl
+!MESSAGE
+!MESSAGE NMAKE /f "iem_ambi.mak".
+!MESSAGE
+!MESSAGE Sie können beim Ausführen von NMAKE eine Konfiguration angeben
+!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel:
+!MESSAGE
+!MESSAGE NMAKE /f "iem_ambi.mak" CFG="iem_ambi - Win32 Debug"
+!MESSAGE
+!MESSAGE Für die Konfiguration stehen zur Auswahl:
+!MESSAGE
+!MESSAGE "iem_ambi - Win32 Release" (basierend auf "Win32 (x86) External Target")
+!MESSAGE "iem_ambi - Win32 Debug" (basierend auf "Win32 (x86) External Target")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+
+!IF "$(CFG)" == "iem_ambi - Win32 Release"
+
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Cmd_Line "NMAKE /f makefile_win"
+# PROP BASE Rebuild_Opt "/a"
+# PROP BASE Target_File "makefile_win.exe"
+# PROP BASE Bsc_Name "makefile_win.bsc"
+# PROP BASE Target_Dir ""
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Cmd_Line "NMAKE /f makefile_win"
+# PROP Rebuild_Opt "/a"
+# PROP Target_File "iem_ambi.exe"
+# PROP Bsc_Name "iem_ambi.bsc"
+# PROP Target_Dir ""
+
+!ELSEIF "$(CFG)" == "iem_ambi - Win32 Debug"
+
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Cmd_Line "NMAKE /f makefile_win"
+# PROP BASE Rebuild_Opt "/a"
+# PROP BASE Target_File "makefile_win.exe"
+# PROP BASE Bsc_Name "makefile_win.bsc"
+# PROP BASE Target_Dir ""
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Cmd_Line "NMAKE /f makefile_win"
+# PROP Rebuild_Opt "/a"
+# PROP Target_File "iem_ambi.exe"
+# PROP Bsc_Name "iem_ambi.bsc"
+# PROP Target_Dir ""
+
+!ENDIF
+
+# Begin Target
+
+# Name "iem_ambi - Win32 Release"
+# Name "iem_ambi - Win32 Debug"
+
+!IF "$(CFG)" == "iem_ambi - Win32 Release"
+
+!ELSEIF "$(CFG)" == "iem_ambi - Win32 Debug"
+
+!ENDIF
+
+# Begin Source File
+
+SOURCE=.\makefile_win
+# End Source File
+# End Target
+# End Project
diff --git a/src/iem_ambi.dsw b/src/iem_ambi.dsw
new file mode 100644
index 0000000..7674a52
--- /dev/null
+++ b/src/iem_ambi.dsw
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNUNG: DIESE ARBEITSBEREICHSDATEI DARF NICHT BEARBEITET ODER GELÖSCHT WERDEN!
+
+###############################################################################
+
+Project: "iem_ambi"=.\iem_ambi.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/src/iem_ambi.h b/src/iem_ambi.h
new file mode 100644
index 0000000..3283c98
--- /dev/null
+++ b/src/iem_ambi.h
@@ -0,0 +1,15 @@
+/* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution.
+
+iem_ambi written by Thomas Musil, Copyright (c) IEM KUG Graz Austria 2000 - 2005 */
+
+#ifndef __IEMAMBI_H__
+#define __IEMAMBI_H__
+
+#define AMBI_LS_REAL 0
+#define AMBI_LS_IND 0
+#define AMBI_LS_MRG 1
+#define AMBI_LS_MIR 2
+#define AMBI_LS_PHT 3
+
+#endif
diff --git a/src/iem_ambi_sources.h b/src/iem_ambi_sources.h
new file mode 100644
index 0000000..cf24fb7
--- /dev/null
+++ b/src/iem_ambi_sources.h
@@ -0,0 +1,11 @@
+/* iem_bin_ambi-setup autogenerated header-file
+ * generated by "./makesource.sh"
+ * !! DO NOT MANUALLY EDIT !!
+ */
+
+#ifndef IEMAMBI_SOURCES_H__
+#define IEMAMBI_SOURCES_H__
+void bin_ambi_calc_HRTF_setup(void); /* bin_ambi_calc_HRTF.c */
+void bin_ambi_reduced_decode_setup(void); /* bin_ambi_reduced_decode.c */
+#endif /* IEMBINAMBI_SOURCES_H__ */
+
diff --git a/src/iem_bin_ambi_sources.c b/src/iem_bin_ambi_sources.c
new file mode 100644
index 0000000..6d45134
--- /dev/null
+++ b/src/iem_bin_ambi_sources.c
@@ -0,0 +1,13 @@
+/* iem_bin_ambi-setup autogenerated setup-file
+ * generated by "./makesource.sh"
+ * !! DO NOT MANUALLY EDIT !!
+ */
+
+#include "iem_bin_ambi_sources.h"
+
+void iem_bin_ambi_sources_setup(void)
+{
+ bin_ambi_calc_HRTF_setup(); /* bin_ambi_calc_HRTF.c */
+ bin_ambi_reduced_decode_setup(); /* bin_ambi_reduced_decode.c */
+}
+
diff --git a/src/iemlib.h b/src/iemlib.h
new file mode 100644
index 0000000..c71b0ed
--- /dev/null
+++ b/src/iemlib.h
@@ -0,0 +1,102 @@
+/* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution.
+
+iemlib.h written by Thomas Musil, Copyright (c) IEM KUG Graz Austria 2000 - 2005 */
+
+#ifndef __IEMLIB_H__
+#define __IEMLIB_H__
+
+
+#define IS_A_POINTER(atom,index) ((atom+index)->a_type == A_POINTER)
+#define IS_A_FLOAT(atom,index) ((atom+index)->a_type == A_FLOAT)
+#define IS_A_SYMBOL(atom,index) ((atom+index)->a_type == A_SYMBOL)
+#define IS_A_DOLLAR(atom,index) ((atom+index)->a_type == A_DOLLAR)
+#define IS_A_DOLLSYM(atom,index) ((atom+index)->a_type == A_DOLLSYM)
+#define IS_A_SEMI(atom,index) ((atom+index)->a_type == A_SEMI)
+#define IS_A_COMMA(atom,index) ((atom+index)->a_type == A_COMMA)
+
+
+#ifdef NT
+int sys_noloadbang;
+//t_symbol *iemgui_key_sym=0;
+#include <io.h>
+#else
+extern int sys_noloadbang;
+//extern t_symbol *iemgui_key_sym;
+#include <unistd.h>
+#endif
+
+#define DEFDELVS 64
+#define XTRASAMPS 4
+#define SAMPBLK 4
+
+
+#define UNITBIT32 1572864. /* 3*2^19; bit 32 has place value 1 */
+
+/* machine-dependent definitions. These ifdefs really
+should have been by CPU type and not by operating system! */
+#ifdef IRIX
+/* big-endian. Most significant byte is at low address in memory */
+#define HIOFFSET 0 /* word offset to find MSB */
+#define LOWOFFSET 1 /* word offset to find LSB */
+#define int32 long /* a data type that has 32 bits */
+#else
+#ifdef MSW
+/* little-endian; most significant byte is at highest address */
+#define HIOFFSET 1
+#define LOWOFFSET 0
+#define int32 long
+#else
+#ifdef __FreeBSD__
+#include <machine/endian.h>
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define HIOFFSET 1
+#define LOWOFFSET 0
+#else
+#define HIOFFSET 0 /* word offset to find MSB */
+#define LOWOFFSET 1 /* word offset to find LSB */
+#endif /* BYTE_ORDER */
+#include <sys/types.h>
+#define int32 int32_t
+#endif
+#ifdef __linux__
+
+#include <endian.h>
+
+#if !defined(__BYTE_ORDER) || !defined(__LITTLE_ENDIAN)
+#error No byte order defined
+#endif
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define HIOFFSET 1
+#define LOWOFFSET 0
+#else
+#define HIOFFSET 0 /* word offset to find MSB */
+#define LOWOFFSET 1 /* word offset to find LSB */
+#endif /* __BYTE_ORDER */
+
+#include <sys/types.h>
+#define int32 int32_t
+
+#else
+#ifdef __APPLE__
+#define HIOFFSET 0 /* word offset to find MSB */
+#define LOWOFFSET 1 /* word offset to find LSB */
+#define int32 int /* a data type that has 32 bits */
+
+#endif /* __APPLE__ */
+#endif /* __linux__ */
+#endif /* MSW */
+#endif /* SGI */
+
+union tabfudge
+{
+ double tf_d;
+ int32 tf_i[2];
+};
+
+#define IEM_DENORMAL(f) ((((*(unsigned int*)&(f))&0x60000000)==0) || \
+(((*(unsigned int*)&(f))&0x60000000)==0x60000000))
+/* more stringent test: anything not between 1e-19 and 1e19 in absolute val */
+
+#endif
diff --git a/src/makefile_win b/src/makefile_win
new file mode 100644
index 0000000..70a1bdb
--- /dev/null
+++ b/src/makefile_win
@@ -0,0 +1,42 @@
+
+all: iem_ambi.dll
+
+VIS_CPP_PATH = "C:\Programme\Microsoft Visual Studio\Vc98"
+
+PD_INST_PATH = "C:\Programme\pd"
+
+PD_WIN_INCLUDE_PATH = /I. /I$(PD_INST_PATH)\src /I$(VIS_CPP_PATH)\include
+
+PD_WIN_C_FLAGS = /nologo /W3 /WX /DMSW /DNT /DPD /DWIN32 /DWINDOWS /Ox -DPA_LITTLE_ENDIAN
+
+PD_WIN_L_FLAGS = /nologo
+
+PD_WIN_LIB = /NODEFAULTLIB:libc /NODEFAULTLIB:oldnames /NODEFAULTLIB:kernel /NODEFAULTLIB:uuid \
+ $(VIS_CPP_PATH)\lib\libc.lib \
+ $(VIS_CPP_PATH)\lib\oldnames.lib \
+ $(VIS_CPP_PATH)\lib\kernel32.lib \
+ $(VIS_CPP_PATH)\lib\wsock32.lib \
+ $(VIS_CPP_PATH)\lib\winmm.lib \
+ $(PD_INST_PATH)\bin\pd.lib
+
+
+SRC = ambi_decode.c \
+ ambi_decode2.c \
+ ambi_decode3.c \
+ ambi_decode_cube.c \
+ ambi_encode.c \
+ ambi_rot.c \
+ iem_ambi.c
+
+
+OBJ = $(SRC:.c=.obj)
+
+.c.obj:
+ cl $(PD_WIN_C_FLAGS) $(PD_WIN_INCLUDE_PATH) /c $*.c
+
+iem_ambi.dll: $(OBJ)
+ link $(PD_WIN_L_FLAGS) /dll /export:iem_ambi_setup \
+ /out:iem_ambi.dll $(OBJ) $(PD_WIN_LIB)
+
+clean:
+ del *.obj
diff --git a/src/makesource.sh b/src/makesource.sh
new file mode 100644
index 0000000..32703b1
--- /dev/null
+++ b/src/makesource.sh
@@ -0,0 +1,65 @@
+#!/bin/sh
+
+IEMAMBI_H=iem_ambi_sources.h
+IEMAMBI_C=iem_ambi_sources.c
+
+EGREP=egrep
+SED=sed
+LS=ls
+
+#################################
+## functions
+
+function head_h() {
+ echo "/* iem_ambi-setup autogenerated header-file"
+ echo " * generated by \"$0\""
+ echo " * !! DO NOT MANUALLY EDIT !!"
+ echo " */"
+ echo
+ echo "#ifndef IEMAMBI_SOURCES_H__"
+ echo "#define IEMAMBI_SOURCES_H__"
+}
+
+function foot_h() {
+ echo "#endif /* IEMAMBI_SOURCES_H__ */"
+ echo ""
+}
+
+function head_c() {
+ echo "/* iem_ambi-setup autogenerated setup-file"
+ echo " * generated by \"$0\""
+ echo " * !! DO NOT MANUALLY EDIT !!"
+ echo " */"
+ echo
+ echo "#include \"$IEMAMBI_H\""
+ echo
+ echo "void iem_ambi_sources_setup(void)"
+ echo "{"
+}
+
+function foot_c() {
+ echo "}"
+ echo
+}
+
+
+##################################
+## body
+
+head_h > $IEMAMBI_H
+head_c > $IEMAMBI_C
+
+for i in $(${LS} *.c | ${EGREP} -v "iem_bin_ambi.*\.c")
+do
+## each c-file in iem_ambi needs to have an <file>_setup()-function
+## that calls all needed setup-functions
+## any non-alpha-numeric-character is replaced by "_"
+## e.g. "bla~.c" -> "bla__setup()"
+ SETUPNAME=$(echo ${i%.c} | ${SED} -e 's/[^[:alnum:]]/_/g')_setup
+ echo "void ${SETUPNAME}(void); /* $i */" >> $IEMAMBI_H
+ echo " ${SETUPNAME}(); /* $i */" >> $IEMAMBI_C
+done
+
+foot_h >> $IEMAMBI_H
+foot_c >> $IEMAMBI_C
+