aboutsummaryrefslogtreecommitdiff
path: root/src
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 /src
initial version JAN_06 with all sourcessvn2git-root
svn path=/trunk/externals/iem/iem_ambi/; revision=4668
Diffstat (limited to 'src')
-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
18 files changed, 5900 insertions, 0 deletions
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
+