diff options
author | Juha Vehviläinen <jusu@users.sourceforge.net> | 2002-06-20 11:32:15 +0000 |
---|---|---|
committer | Juha Vehviläinen <jusu@users.sourceforge.net> | 2002-06-20 11:32:15 +0000 |
commit | f0c2ea083dbe6b3c8491dbd151430892ec5584b0 (patch) | |
tree | b1f74be3d93198881aedca5db835e78a66d680d4 /define_loudspeakers.c |
This commit was generated by cvs2svn to compensate for changes in r17,svn2git-root
which included commits to RCS files with non-trunk default branches.
svn path=/trunk/externals/vbap/; revision=18
Diffstat (limited to 'define_loudspeakers.c')
-rw-r--r-- | define_loudspeakers.c | 852 |
1 files changed, 852 insertions, 0 deletions
diff --git a/define_loudspeakers.c b/define_loudspeakers.c new file mode 100644 index 0000000..1b1c757 --- /dev/null +++ b/define_loudspeakers.c @@ -0,0 +1,852 @@ +/* define_loudspeakers.c + +written by Ville Pulkki 1999 +Helsinki University of Technology +and +Unversity of California at Berkeley + +See copyright in file with name COPYRIGHT */ + +#include <math.h> +#include "m_pd.h" /* you must include this - it contains the external object's link to pure data */ + +#define RES_ID 9172 /* resource ID for assistance (we'll add that later) */ +#define MAX_LS_AMOUNT 55 /* maximum amount of loudspeakers, can be raised */ +#define MIN_VOL_P_SIDE_LGTH 0.01 + +#ifndef NT +#define NULL 0L +#endif +#ifdef NT +#define fabsf fabs +#endif + +/* A struct for a loudspeaker instance */ +typedef struct { /* distance value is 1.0 == unit vectors */ + float x; /* cartesian coordinates */ + float y; + float z; + float azi; /* polar coordinates */ + float ele; + int channel_nbr; /* which speaker channel number */ +} t_ls; + +/* A struct for all loudspeaker sets */ +typedef struct t_ls_set { + int ls_nos[3]; /* channel numbers */ + float inv_mx[9]; /* inverse 3x3 or 2x2 matrix */ + struct t_ls_set *next; /* next set (triplet or pair) */ +} t_ls_set; + +typedef struct /* This defines the object as an entity made up of other things */ +{ + t_object x_ob; /* gotta say this... it creates a reference to your object */ + long x_ls_read; /* 1 if loudspeaker directions have been read */ + long x_triplets_specified; /* 1 if loudspeaker triplets have been chosen */ + t_ls x_ls[MAX_LS_AMOUNT]; /* loudspeakers */ + t_ls_set *x_ls_set; /* loudspeaker sets */ + void *x_outlet0; /* outlet creation - inlets are automatic */ + long x_ls_amount; /* number of loudspeakers */ + long x_dimension; /* 2 (horizontal arrays) or 3 (3d setups) */ +} t_def_ls; + +static t_class *def_ls_class; /* so max can identify your object */ +void def_ls_bang(t_def_ls *x); +void def_ls_int(t_def_ls *x, t_float n); +void def_ls_read_directions(t_def_ls *x, t_symbol *s, int ac, t_atom *av); +void def_ls_read_triplets(t_def_ls *x, t_symbol *s, int ac, t_atom *av); +static void *def_ls_new(t_symbol *s, int ac, t_atom *av); /* using A_GIMME - typed message list */ +void def_ls(float g[3], long ls[3], t_def_ls *x); +void ls_angles_to_cart(t_ls *ls); +void choose_ls_triplets(t_def_ls *x); +int any_ls_inside_triplet(int a, int b, int c,t_ls lss[MAX_LS_AMOUNT],int ls_amount); +void add_ldsp_triplet(int i, int j, int k, t_def_ls *x); +float vec_angle(t_ls v1, t_ls v2); +float vec_length(t_ls v1); +float vec_prod(t_ls v1, t_ls v2); +float vec_prod(t_ls v1, t_ls v2); +float vol_p_side_lgth(int i, int j,int k, t_ls lss[MAX_LS_AMOUNT] ); +void unq_cross_prod(t_ls v1,t_ls v2, t_ls *res); +int lines_intersect(int i,int j,int k,int l,t_ls lss[MAX_LS_AMOUNT]); +void calculate_3x3_matrixes(t_def_ls *x); +void choose_ls_tuplets(t_def_ls *x); +int calc_2D_inv_tmatrix(float azi1,float azi2, float inv_mat[4]); +void sort_2D_lss(t_ls lss[MAX_LS_AMOUNT], int sorted_lss[MAX_LS_AMOUNT], + int ls_amount); + +/* above are the prototypes for the methods/procedures/functions you will use */ + +void define_loudspeakers_setup(void) +{ + def_ls_class = class_new(gensym("define_loudspeakers"), (t_newmethod)def_ls_new, 0, (short)sizeof(t_def_ls), 0, A_GIMME, 0); + /* def_ls_new = creation function, A_DEFLONG = its (optional) arguement is a long (32-bit) int */ +/* +/* addbang((method)def_ls_bang); /* the procedure it uses when it gets a bang in the left inlet */ +/* addint((method)def_ls_int); /* the rocedure for an int in the left inlet (inlet 0) */ +/* addmess((method)def_ls_read_directions, "ls-directions", A_GIMME, 0); +/* addmess((method)def_ls_read_triplets, "ls-triplets", A_GIMME, 0); +*/ + class_addbang(def_ls_class, def_ls_bang); + class_addfloat(def_ls_class, def_ls_int); + class_addmethod(def_ls_class, (t_method)def_ls_read_directions, gensym("ls-directions"), A_GIMME, 0); + class_addmethod(def_ls_class, (t_method)def_ls_read_triplets, gensym("ls-triplets"), A_GIMME, 0); +} + + +void def_ls_bang(t_def_ls *x) /* x = reference to this instance of the object */ +{ /* calculate and print out chosen loudspeaker sets and corresponding matrices */ + t_atom at[MAX_LS_AMOUNT*2+1]; + float g[3]; + long ls[3]; + long i; + + if(x->x_ls_read == 1){ + if(x->x_ls_amount < x->x_dimension){ + post("define-loudspeakers: Too few loudspeakers!",0); + return; + } else if(x->x_dimension == 3){ + if(x->x_triplets_specified==0) + choose_ls_triplets(x); + calculate_3x3_matrixes(x); + } else if(x->x_dimension == 2) + choose_ls_tuplets(x); + else { + post("define-loudspeakers: Error in loudspeaker direction data"); + post("dimension azimuth1 [elevation1] azimuth2 [elevation2]..."); + post("dimension == 2 for horizontal ls arrays"); + post("dimension == 3 for 3-D ls arrays (speakers also upward and/or downward ",0); + } + } else{ + post("define-loudspeakers: Error in loudspeaker direction data",0); + post("dimension azimuth1 [elevation1] azimuth2 [elevation2]...",0); + post("dimension == 2 for horizontal ls arrays",0); + post("dimension == 3 for 3-D ls arrays (speakers also upward and/or downward ",0); + } +} + +/*--------------------------------------------------------------------------*/ + +void def_ls_int(t_def_ls *x, t_float n) /* x = the instance of the object, n = the int received in the right inlet */ +{ + /* do something if an int comes in the left inlet??? */ +} + +void def_ls_read_triplets(t_def_ls *x, t_symbol *s, int ac, t_atom *av) +/* when loudspeaker triplets come in a message */ +{ + long l1,l2,l3,i; + t_ls_set *trip_ptr, *tmp_ptr, *prev; + if(x->x_ls_read == 0){ + post("define_loudspeakers: Define loudspeaker directions first!",0); + return; + } + + if(x->x_dimension == 2){ + post("define_loudspeakers: Can't specify loudspeaker triplets in 2-D setup!",0); + return; + } + + trip_ptr = x->x_ls_set; + prev = NULL; + while (trip_ptr != NULL){ + tmp_ptr = trip_ptr; + trip_ptr = trip_ptr->next; + freebytes(tmp_ptr, sizeof (struct t_ls_set)); + } + x->x_ls_set = NULL; + + for(i=0;i<ac;i+=3){ +/* if(av[i].a_type == A_LONG) + l1 = av[i].a_w.w_long; + else */ + if(av[i].a_type == A_FLOAT) + l1 = (long) av[i].a_w.w_float; +/* if(av[i+1].a_type == A_LONG) + l2 = av[i+1].a_w.w_long; + else */ + if(av[i+1].a_type == A_FLOAT) + l2 = (long) av[i+1].a_w.w_float; +/* if(av[i+2].a_type == A_LONG) + l3 = av[i+2].a_w.w_long; + else */ + if(av[i+2].a_type == A_FLOAT) + l3 = (long) av[i+2].a_w.w_float; + add_ldsp_triplet(l1-1,l2-1,l3-1,x); + } + x->x_triplets_specified=1; +} + + + +void def_ls_read_directions(t_def_ls *x, t_symbol *s, int ac, t_atom *av) +/* when loudspeaker directions come in a message */ +{ + t_ls_set *trip_ptr, *prev, *tmp_ptr; + long i,pointer,newlyread; + newlyread = 0; +/* if(av[0].a_type == A_LONG){ + x->x_dimension= av[0].a_w.w_long; + newlyread = 1; + } else */ + if(av[0].a_type == A_FLOAT) { + x->x_dimension= (int) av[0].a_w.w_float; + newlyread = 1; + } else x->x_dimension= 0; + + if(x->x_dimension <2 || x->x_dimension >3){ + post("define-loudspeakers: Dimension has to be 2 or 3!",0); + return; + } + + pointer = 1; + x->x_ls_amount= (ac-1) / (x->x_dimension - 1); + for(i=0; i < x->x_ls_amount;i++){ +/* if(av[0].a_type == A_LONG) + x->x_ls[i].azi = (float) av[pointer].a_w.w_long; + else */ + if(av[0].a_type == A_FLOAT) + x->x_ls[i].azi = av[pointer].a_w.w_float; + else { + post("define-loudspeakers: Error in loudspeaker data!",0); + newlyread =0; + return; + } + pointer++; + if(x->x_dimension == 3){ +/* if(av[0].a_type == A_LONG) + x->x_ls[i].ele = (float) av[pointer].a_w.w_long; + else */ + if(av[0].a_type == A_FLOAT) + x->x_ls[i].ele = av[pointer].a_w.w_float; + else { + post("define-loudspeakers: Error in loudspeaker data!",0); + newlyread =0; + return; + } + pointer++; + } else + x->x_ls[i].ele = 0.0; /* 2-D case */ + } + + if(newlyread == 1){ + x->x_ls_read = 1; /* preprocess data */ + for(i=0;i<x->x_ls_amount;i++) + ls_angles_to_cart(&x->x_ls[i]); + trip_ptr = x->x_ls_set; + prev = NULL; + while (trip_ptr != NULL){ /* remove old matrices */ + tmp_ptr = trip_ptr; + trip_ptr = trip_ptr->next; + freebytes(tmp_ptr, sizeof (struct t_ls_set)); + } + x->x_ls_set = NULL; + } + x->x_triplets_specified=0; +} + +/*--------------------------------------------------------------------------*/ + +void ls_angles_to_cart(t_ls *ls) +/* convert angular direction to cartesian */ +{ + float atorad = (2 * 3.1415927 / 360) ; + float azi = ls->azi; + float ele = ls->ele; + ls->x = cos((float) azi * atorad) * cos((float) ele * atorad); + ls->y = sin((float) azi * atorad) * cos((float) ele * atorad); + ls->z = sin((float) ele * atorad); +} + +static void *def_ls_new(t_symbol *s, int ac, t_atom *av) /* create new instance of object... MUST + send it an int even if you do nothing with this int!! */ +{ + long i,pointer; + t_def_ls *x; + + x = (t_def_ls *)pd_new(def_ls_class); + + x->x_ls_read = 0; +/* if(av[0].a_type == A_LONG){ + x->x_dimension= av[0].a_w.w_long; + x->x_ls_read = 1; + } else */ + if(av[0].a_type == A_FLOAT) { + x->x_dimension= (int) av[0].a_w.w_float; + x->x_ls_read = 1; + } else x->x_dimension= 0; + + if(x->x_dimension <2 || x->x_dimension >3){ + post("define-loudspeakers: Dimension has to be 2 or 3!",0); + return(0); + } + + + pointer = 1; + x->x_ls_amount= (ac-1) / (x->x_dimension - 1); + + /* read loudspeaker direction angles */ + for(i=0; i < x->x_ls_amount;i++){ +/* if(av[0].a_type == A_LONG) + x->x_ls[i].azi = (float) av[pointer].a_w.w_long; + else */ + if(av[0].a_type == A_FLOAT) + x->x_ls[i].azi = av[pointer].a_w.w_float; + else { + post("define-loudspeakers: Error in loudspeaker data!",0); + x->x_ls_read =0; + return; + } + pointer++; + if(x->x_dimension == 3){ /* 3-D */ +/* if(av[0].a_type == A_LONG) + x->x_ls[i].ele = (float) av[pointer].a_w.w_long; + else */ + if(av[0].a_type == A_FLOAT) + x->x_ls[i].ele = av[pointer].a_w.w_float; + else { + post("define-loudspeakers: Error in loudspeaker data!",0); + x->x_ls_read =0; + return; + } + pointer++; + } else + x->x_ls[i].ele = 0.0; /* in 2d elevation is zero */ + } + + if(x->x_ls_read == 1) + for(i=0;i<x->x_ls_amount;i++) + ls_angles_to_cart(&x->x_ls[i]); + x->x_triplets_specified=0; + x->x_outlet0 = outlet_new(&x->x_ob, gensym("list")); /* create a (list) outlet */ + x->x_ls_set = NULL; + return(x); /* return a reference to the object instance */ +} + + + +void choose_ls_triplets(t_def_ls *x) + /* Selects the loudspeaker triplets, and + calculates the inversion matrices for each selected triplet. + A line (connection) is drawn between each loudspeaker. The lines + denote the sides of the triangles. The triangles should not be + intersecting. All crossing connections are searched and the + longer connection is erased. This yields non-intesecting triangles, + which can be used in panning. + See theory in paper Pulkki, V. Lokki, T. "Creating Auditory Displays + with Multiple Loudspeakers Using VBAP: A Case Study with + DIVA Project" in International Conference on + Auditory Displays -98.*/ +{ + int i,j,k,l,m,li, table_size; + int *i_ptr; + t_ls vb1,vb2,tmp_vec; + int connections[MAX_LS_AMOUNT][MAX_LS_AMOUNT]; + float angles[MAX_LS_AMOUNT]; + int sorted_angles[MAX_LS_AMOUNT]; + float distance_table[((MAX_LS_AMOUNT * (MAX_LS_AMOUNT - 1)) / 2)]; + int distance_table_i[((MAX_LS_AMOUNT * (MAX_LS_AMOUNT - 1)) / 2)]; + int distance_table_j[((MAX_LS_AMOUNT * (MAX_LS_AMOUNT - 1)) / 2)]; + float distance; + t_ls_set *trip_ptr, *prev, *tmp_ptr; + int ls_amount = x->x_ls_amount; + t_ls *lss = x->x_ls; + if (ls_amount == 0) { + post("define-loudspeakers: Number of loudspeakers is zero",0); + return; + } + + for(i=0;i<ls_amount;i++) + for(j=i+1;j<ls_amount;j++) + for(k=j+1;k<ls_amount;k++){ + if(vol_p_side_lgth(i,j,k, x->x_ls) > MIN_VOL_P_SIDE_LGTH){ + connections[i][j]=1; + connections[j][i]=1; + connections[i][k]=1; + connections[k][i]=1; + connections[j][k]=1; + connections[k][j]=1; + add_ldsp_triplet(i,j,k,x); + } + } + + /*calculate distancies between all lss and sorting them*/ + table_size =(((ls_amount - 1) * (ls_amount)) / 2); + for(i=0;i<table_size; i++) + distance_table[i] = 100000.0; + for(i=0;i<ls_amount;i++){ + for(j=(i+1);j<ls_amount; j++){ + if(connections[i][j] == 1) { + distance = fabs(vec_angle(lss[i],lss[j])); + k=0; + while(distance_table[k] < distance) + k++; + for(l=(table_size - 1);l > k ;l--){ + distance_table[l] = distance_table[l-1]; + distance_table_i[l] = distance_table_i[l-1]; + distance_table_j[l] = distance_table_j[l-1]; + } + distance_table[k] = distance; + distance_table_i[k] = i; + distance_table_j[k] = j; + } else + table_size--; + } + } + + /* disconnecting connections which are crossing shorter ones, + starting from shortest one and removing all that cross it, + and proceeding to next shortest */ + for(i=0; i<(table_size); i++){ + int fst_ls = distance_table_i[i]; + int sec_ls = distance_table_j[i]; + if(connections[fst_ls][sec_ls] == 1) + for(j=0; j<ls_amount ; j++) + for(k=j+1; k<ls_amount; k++) + if( (j!=fst_ls) && (k != sec_ls) && (k!=fst_ls) && (j != sec_ls)){ + if(lines_intersect(fst_ls, sec_ls, j,k,x->x_ls) == 1){ + connections[j][k] = 0; + connections[k][j] = 0; + } + } + } + + /* remove triangles which had crossing sides + with smaller triangles or include loudspeakers*/ + trip_ptr = x->x_ls_set; + prev = NULL; + while (trip_ptr != NULL){ + i = trip_ptr->ls_nos[0]; + j = trip_ptr->ls_nos[1]; + k = trip_ptr->ls_nos[2]; + if(connections[i][j] == 0 || + connections[i][k] == 0 || + connections[j][k] == 0 || + any_ls_inside_triplet(i,j,k,x->x_ls,ls_amount) == 1 ){ + if(prev != NULL) { + prev->next = trip_ptr->next; + tmp_ptr = trip_ptr; + trip_ptr = trip_ptr->next; + freebytes(tmp_ptr, sizeof (struct t_ls_set)); + } else { + x->x_ls_set = trip_ptr->next; + tmp_ptr = trip_ptr; + trip_ptr = trip_ptr->next; + freebytes(tmp_ptr, sizeof (struct t_ls_set)); + } + } else { + prev = trip_ptr; + trip_ptr = trip_ptr->next; + + } + } + x->x_triplets_specified=1; +} + + +int any_ls_inside_triplet(int a, int b, int c,t_ls lss[MAX_LS_AMOUNT],int ls_amount) + /* returns 1 if there is loudspeaker(s) inside given ls triplet */ +{ + float invdet; + t_ls *lp1, *lp2, *lp3; + float invmx[9]; + int i,j,k; + float tmp; + int any_ls_inside, this_inside; + + lp1 = &(lss[a]); + lp2 = &(lss[b]); + lp3 = &(lss[c]); + + /* matrix inversion */ + invdet = 1.0 / ( lp1->x * ((lp2->y * lp3->z) - (lp2->z * lp3->y)) + - lp1->y * ((lp2->x * lp3->z) - (lp2->z * lp3->x)) + + lp1->z * ((lp2->x * lp3->y) - (lp2->y * lp3->x))); + + invmx[0] = ((lp2->y * lp3->z) - (lp2->z * lp3->y)) * invdet; + invmx[3] = ((lp1->y * lp3->z) - (lp1->z * lp3->y)) * -invdet; + invmx[6] = ((lp1->y * lp2->z) - (lp1->z * lp2->y)) * invdet; + invmx[1] = ((lp2->x * lp3->z) - (lp2->z * lp3->x)) * -invdet; + invmx[4] = ((lp1->x * lp3->z) - (lp1->z * lp3->x)) * invdet; + invmx[7] = ((lp1->x * lp2->z) - (lp1->z * lp2->x)) * -invdet; + invmx[2] = ((lp2->x * lp3->y) - (lp2->y * lp3->x)) * invdet; + invmx[5] = ((lp1->x * lp3->y) - (lp1->y * lp3->x)) * -invdet; + invmx[8] = ((lp1->x * lp2->y) - (lp1->y * lp2->x)) * invdet; + + any_ls_inside = 0; + for(i=0; i< ls_amount; i++) { + if (i != a && i!=b && i != c){ + this_inside = 1; + for(j=0; j< 3; j++){ + tmp = lss[i].x * invmx[0 + j*3]; + tmp += lss[i].y * invmx[1 + j*3]; + tmp += lss[i].z * invmx[2 + j*3]; + if(tmp < -0.001) + this_inside = 0; + } + if(this_inside == 1) + any_ls_inside=1; + } + } + return any_ls_inside; +} + +void add_ldsp_triplet(int i, int j, int k, t_def_ls *x) + /* adds i,j,k triplet to structure*/ +{ + struct t_ls_set *trip_ptr, *prev; + trip_ptr = x->x_ls_set; + prev = NULL; + while (trip_ptr != NULL){ + prev = trip_ptr; + trip_ptr = trip_ptr->next; + } + trip_ptr = (struct t_ls_set*) + getbytes (sizeof (struct t_ls_set)); + if(prev == NULL) + x->x_ls_set = trip_ptr; + else + prev->next = trip_ptr; + trip_ptr->next = NULL; + trip_ptr->ls_nos[0] = i; + trip_ptr->ls_nos[1] = j; + trip_ptr->ls_nos[2] = k; +} + + + + +float vec_angle(t_ls v1, t_ls v2) +/* angle between two loudspeakers */ +{ + float inner= ((v1.x*v2.x + v1.y*v2.y + v1.z*v2.z)/ + (vec_length(v1) * vec_length(v2))); + if(inner > 1.0) + inner= 1.0; + if (inner < -1.0) + inner = -1.0; + return fabs( acos( inner)); +} + +float vec_length(t_ls v1) +/* length of a vector */ +{ + return (sqrt(v1.x*v1.x + v1.y*v1.y + v1.z*v1.z)); +} + +float vec_prod(t_ls v1, t_ls v2) +/* vector dot product */ +{ + return (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z); +} + + +float vol_p_side_lgth(int i, int j,int k, t_ls lss[MAX_LS_AMOUNT] ){ + /* calculate volume of the parallelepiped defined by the loudspeaker + direction vectors and divide it with total length of the triangle sides. + This is used when removing too narrow triangles. */ + + float volper, lgth; + t_ls xprod; + unq_cross_prod(lss[i], lss[j], &xprod); + volper = fabsf(vec_prod(xprod, lss[k])); + lgth = (fabsf(vec_angle(lss[i],lss[j])) + + fabsf(vec_angle(lss[i],lss[k])) + + fabsf(vec_angle(lss[j],lss[k]))); + if(lgth>0.00001) + return volper / lgth; + else + return 0.0; +} + +void unq_cross_prod(t_ls v1,t_ls v2, + t_ls *res) +/* vector cross product */ +{ + float length; + res->x = (v1.y * v2.z ) - (v1.z * v2.y); + res->y = (v1.z * v2.x ) - (v1.x * v2.z); + res->z = (v1.x * v2.y ) - (v1.y * v2.x); + length= vec_length(*res); + res->x /= length; + res->y /= length; + res->z /= length; +} + + +int lines_intersect(int i,int j,int k,int l,t_ls lss[MAX_LS_AMOUNT]) + /* checks if two lines intersect on 3D sphere + */ +{ + t_ls v1; + t_ls v2; + t_ls v3, neg_v3; + float angle; + float dist_ij,dist_kl,dist_iv3,dist_jv3,dist_inv3,dist_jnv3; + float dist_kv3,dist_lv3,dist_knv3,dist_lnv3; + + unq_cross_prod(lss[i],lss[j],&v1); + unq_cross_prod(lss[k],lss[l],&v2); + unq_cross_prod(v1,v2,&v3); + + neg_v3.x= 0.0 - v3.x; + neg_v3.y= 0.0 - v3.y; + neg_v3.z= 0.0 - v3.z; + + dist_ij = (vec_angle(lss[i],lss[j])); + dist_kl = (vec_angle(lss[k],lss[l])); + dist_iv3 = (vec_angle(lss[i],v3)); + dist_jv3 = (vec_angle(v3,lss[j])); + dist_inv3 = (vec_angle(lss[i],neg_v3)); + dist_jnv3 = (vec_angle(neg_v3,lss[j])); + dist_kv3 = (vec_angle(lss[k],v3)); + dist_lv3 = (vec_angle(v3,lss[l])); + dist_knv3 = (vec_angle(lss[k],neg_v3)); + dist_lnv3 = (vec_angle(neg_v3,lss[l])); + + /* if one of loudspeakers is close to crossing point, don't do anything*/ + if(fabsf(dist_iv3) <= 0.01 || fabsf(dist_jv3) <= 0.01 || + fabsf(dist_kv3) <= 0.01 || fabsf(dist_lv3) <= 0.01 || + fabsf(dist_inv3) <= 0.01 || fabsf(dist_jnv3) <= 0.01 || + fabsf(dist_knv3) <= 0.01 || fabsf(dist_lnv3) <= 0.01 ) + return(0); + + /* if crossing point is on line between both loudspeakers return 1 */ + if (((fabsf(dist_ij - (dist_iv3 + dist_jv3)) <= 0.01 ) && + (fabsf(dist_kl - (dist_kv3 + dist_lv3)) <= 0.01)) || + ((fabsf(dist_ij - (dist_inv3 + dist_jnv3)) <= 0.01) && + (fabsf(dist_kl - (dist_knv3 + dist_lnv3)) <= 0.01 ))) { + return (1); + } else { + return (0); + } +} + +void calculate_3x3_matrixes(t_def_ls *x) + /* Calculates the inverse matrices for 3D */ +{ + float invdet; + t_ls *lp1, *lp2, *lp3; + float *invmx; + float *ptr; + struct t_ls_set *tr_ptr = x->x_ls_set; + int triplet_amount = 0, ftable_size,i,j,k, pointer,list_length=0; + t_atom *at; + t_ls *lss = x->x_ls; + + if (tr_ptr == NULL){ + post("define-loudspeakers: Not valid 3-D configuration\n",1); + return; + } + + /* counting triplet amount */ + while(tr_ptr != NULL){ + triplet_amount++; + tr_ptr = tr_ptr->next; + } + tr_ptr = x->x_ls_set; + list_length= triplet_amount * 21 + 2; /* was: + 3, pure data doesn't like errors on list_length */ + at= (t_atom *) getbytes(list_length*sizeof(t_atom)); + + SETFLOAT(&at[0], x->x_dimension); + SETFLOAT(&at[1], x->x_ls_amount); + pointer=2; + + while(tr_ptr != NULL){ + lp1 = &(lss[tr_ptr->ls_nos[0]]); + lp2 = &(lss[tr_ptr->ls_nos[1]]); + lp3 = &(lss[tr_ptr->ls_nos[2]]); + + /* matrix inversion */ + invmx = tr_ptr->inv_mx; + invdet = 1.0 / ( lp1->x * ((lp2->y * lp3->z) - (lp2->z * lp3->y)) + - lp1->y * ((lp2->x * lp3->z) - (lp2->z * lp3->x)) + + lp1->z * ((lp2->x * lp3->y) - (lp2->y * lp3->x))); + + invmx[0] = ((lp2->y * lp3->z) - (lp2->z * lp3->y)) * invdet; + invmx[3] = ((lp1->y * lp3->z) - (lp1->z * lp3->y)) * -invdet; + invmx[6] = ((lp1->y * lp2->z) - (lp1->z * lp2->y)) * invdet; + invmx[1] = ((lp2->x * lp3->z) - (lp2->z * lp3->x)) * -invdet; + invmx[4] = ((lp1->x * lp3->z) - (lp1->z * lp3->x)) * invdet; + invmx[7] = ((lp1->x * lp2->z) - (lp1->z * lp2->x)) * -invdet; + invmx[2] = ((lp2->x * lp3->y) - (lp2->y * lp3->x)) * invdet; + invmx[5] = ((lp1->x * lp3->y) - (lp1->y * lp3->x)) * -invdet; + invmx[8] = ((lp1->x * lp2->y) - (lp1->y * lp2->x)) * invdet; + for(i=0;i<3;i++){ + SETFLOAT(&at[pointer], tr_ptr->ls_nos[i]+1); + pointer++; + } + for(i=0;i<9;i++){ + SETFLOAT(&at[pointer], invmx[i]); + pointer++; + } + SETFLOAT(&at[pointer], lp1->x); pointer++; + SETFLOAT(&at[pointer], lp2->x); pointer++; + SETFLOAT(&at[pointer], lp3->x); pointer++; + SETFLOAT(&at[pointer], lp1->y); pointer++; + SETFLOAT(&at[pointer], lp2->y); pointer++; + SETFLOAT(&at[pointer], lp3->y); pointer++; + SETFLOAT(&at[pointer], lp1->z); pointer++; + SETFLOAT(&at[pointer], lp2->z); pointer++; + SETFLOAT(&at[pointer], lp3->z); pointer++; + + tr_ptr = tr_ptr->next; + } + outlet_anything(x->x_outlet0, gensym("loudspeaker-matrices"), list_length, at); + freebytes(at, list_length*sizeof(t_atom)); +} + + + +void choose_ls_tuplets(t_def_ls *x) + /* selects the loudspeaker pairs, calculates the inversion + matrices and stores the data to a global array*/ +{ + float atorad = (2 * 3.1415927 / 360) ; + int i,j,k; + float w1,w2; + float p1,p2; + int sorted_lss[MAX_LS_AMOUNT]; + int exist[MAX_LS_AMOUNT]; + int amount=0; + float inv_mat[MAX_LS_AMOUNT][4]; /* In 2-D ls amount == max amount of LS pairs */ + float *ptr; + float *ls_table; + t_ls *lss = x->x_ls; + long ls_amount=x->x_ls_amount; + long list_length; + t_atom *at; + long pointer; + + for(i=0;i<MAX_LS_AMOUNT;i++){ + exist[i]=0; + } + + /* sort loudspeakers according their aximuth angle */ + sort_2D_lss(x->x_ls,sorted_lss,ls_amount); + + /* adjacent loudspeakers are the loudspeaker pairs to be used.*/ + for(i=0;i<(ls_amount-1);i++){ + if((lss[sorted_lss[i+1]].azi - + lss[sorted_lss[i]].azi) <= (180 - 10)){ + if (calc_2D_inv_tmatrix( lss[sorted_lss[i]].azi, + lss[sorted_lss[i+1]].azi, + inv_mat[i]) != 0){ + exist[i]=1; + amount++; + } + } + } + + if(((6.283 - lss[sorted_lss[ls_amount-1]].azi) + +lss[sorted_lss[0]].azi) <= (180 - 10)) { + if(calc_2D_inv_tmatrix(lss[sorted_lss[ls_amount-1]].azi, + lss[sorted_lss[0]].azi, + inv_mat[ls_amount-1]) != 0) { + exist[ls_amount-1]=1; + amount++; + } + } + + + /* Output */ + list_length= amount * 6 + 2; + at= (t_atom *) getbytes(list_length*sizeof(t_atom)); + + SETFLOAT(&at[0], x->x_dimension); + SETFLOAT(&at[1], x->x_ls_amount); + pointer=2; + + for (i=0;i<ls_amount - 1;i++){ + if(exist[i] == 1) { + SETFLOAT(&at[pointer], sorted_lss[i]+1); + pointer++; + SETFLOAT(&at[pointer], sorted_lss[i+1]+1); + pointer++; + for(j=0;j<4;j++) { + SETFLOAT(&at[pointer], inv_mat[i][j]); + pointer++; + } + } + } + if(exist[ls_amount-1] == 1) { + SETFLOAT(&at[pointer], sorted_lss[ls_amount-1]+1); + pointer++; + SETFLOAT(&at[pointer], sorted_lss[0]+1); + pointer++; + for(j=0;j<4;j++) { + SETFLOAT(&at[pointer], inv_mat[ls_amount-1][j]); + pointer++; + } + } + outlet_anything(x->x_outlet0, gensym("loudspeaker-matrices"), list_length, at); + freebytes(at, list_length*sizeof(t_atom)); +} + +void sort_2D_lss(t_ls lss[MAX_LS_AMOUNT], int sorted_lss[MAX_LS_AMOUNT], + int ls_amount) +/* sort loudspeakers according to azimuth angle */ +{ + int i,j,index; + float tmp, tmp_azi; + float rad2ang = 360.0 / ( 2 * 3.141592 ); + + float x,y; + /* Transforming angles between -180 and 180 */ + for (i=0;i<ls_amount;i++) { + ls_angles_to_cart(&lss[i]); + lss[i].azi = acos( lss[i].x) * rad2ang; + if (fabs(lss[i].y) <= 0.001) + tmp = 1.0; + else + tmp = lss[i].y / fabs(lss[i].y); + lss[i].azi *= tmp; + } + for (i=0;i<ls_amount;i++){ + tmp = 2000; + for (j=0 ; j<ls_amount;j++){ + if (lss[j].azi <= tmp){ + tmp=lss[j].azi; + index = j; + } + } + sorted_lss[i]=index; + tmp_azi = (lss[index].azi); + lss[index].azi = (tmp_azi + (float) 4000.0); + } + for (i=0;i<ls_amount;i++) { + tmp_azi = (lss[i].azi); + lss[i].azi = (tmp_azi - (float) 4000.0); + } +} + + +int calc_2D_inv_tmatrix(float azi1,float azi2, float inv_mat[4]) +/* calculate inverse 2x2 matrix */ +{ + float x1,x2,x3,x4; /* x1 x3 */ + float y1,y2,y3,y4; /* x2 x4 */ + float det; + float rad2ang = 360.0 / ( 2 * 3.141592 ); + + x1 = cos(azi1 / rad2ang); + x2 = sin(azi1 / rad2ang); + x3 = cos(azi2 / rad2ang); + x4 = sin(azi2 / rad2ang); + det = (x1 * x4) - ( x3 * x2 ); + if(fabsf(det) <= 0.001) { + + inv_mat[0] = 0.0; + inv_mat[1] = 0.0; + inv_mat[2] = 0.0; + inv_mat[3] = 0.0; + return 0; + } else { + inv_mat[0] = (x4 / det); + inv_mat[1] = (-x3 / det); + inv_mat[2] = (-x2 / det); + inv_mat[3] = (x1 / det); + return 1; + } +} + + |