[PD-cvs] externals/iem/iem_ambi/src Make.config.in, NONE, 1.1 Makefile, NONE, 1.1 ambi_decode.c, NONE, 1.1 ambi_decode2.c, NONE, 1.1 ambi_decode3.c, NONE, 1.1 ambi_decode_cube.c, NONE, 1.1 ambi_encode.c, NONE, 1.1 ambi_rot.c, NONE, 1.1 configure.ac, NONE, 1.1 iem_ambi.c, NONE, 1.1 iem_ambi.dsp, NONE, 1.1 iem_ambi.dsw, NONE, 1.1 iem_ambi.h, NONE, 1.1 iem_ambi_sources.h, NONE, 1.1 iem_bin_ambi_sources.c, NONE, 1.1 iemlib.h, NONE, 1.1 makefile_win, NONE, 1.1 makesource.sh, NONE, 1.1

musil tmusil at users.sourceforge.net
Thu Mar 9 18:05:45 CET 2006


Update of /cvsroot/pure-data/externals/iem/iem_ambi/src
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21232/iem/iem_ambi/src

Added Files:
	Make.config.in Makefile ambi_decode.c ambi_decode2.c 
	ambi_decode3.c ambi_decode_cube.c ambi_encode.c ambi_rot.c 
	configure.ac iem_ambi.c iem_ambi.dsp iem_ambi.dsw iem_ambi.h 
	iem_ambi_sources.h iem_bin_ambi_sources.c iemlib.h 
	makefile_win makesource.sh 
Log Message:
initial version JAN_06 with all sources

--- NEW FILE: iem_ambi.dsp ---
# 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

--- NEW FILE: iem_ambi.c ---
/* 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", '@');
}

--- NEW FILE: iem_ambi.h ---
/* 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

--- NEW FILE: ambi_encode.c ---
/* 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"));
}

--- NEW FILE: iem_ambi.dsw ---
(This appears to be a binary file; contents omitted.)

--- NEW FILE: iem_bin_ambi_sources.c ---
/* 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 */
}


--- NEW FILE: makefile_win ---

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

--- NEW FILE: ambi_rot.c ---
/* 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>



[...1495 lines suppressed...]
	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"));
}

--- NEW FILE: makesource.sh ---
#!/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


--- NEW FILE: Makefile ---
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


--- NEW FILE: configure.ac ---
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 at 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.*

--- NEW FILE: ambi_decode2.c ---
/* 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"));
}

--- NEW FILE: iemlib.h ---
/* 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

--- NEW FILE: iem_ambi_sources.h ---
/* 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__ */


--- NEW FILE: ambi_decode_cube.c ---
/* 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"));
}

--- NEW FILE: Make.config.in ---
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)- at IEMBINAMBI_VERSION@.tgz

# ICCFLAGS=-march=pentiumiii -axK
Z_CFLAGS = $(IFLAGS) $(DEFS) -DPD $(WFLAGS) @CFLAGS@ $(CFLAGS)

MAKEDEP_FLAGS = @MAKEDEP_FLAGS@

LIBS = @LIBS@

--- NEW FILE: ambi_decode.c ---
/* 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"));
}

--- NEW FILE: ambi_decode3.c ---
/* 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"));
}





More information about the Pd-cvs mailing list