diff options
-rw-r--r-- | define_loudspeakers.c | 680 | ||||
-rwxr-xr-x | define_loudspeakers.h | 37 | ||||
-rw-r--r-- | max2pd.h | 46 | ||||
-rw-r--r-- | vbap.c | 677 | ||||
-rw-r--r-- | vbap.h | 113 |
5 files changed, 854 insertions, 699 deletions
diff --git a/define_loudspeakers.c b/define_loudspeakers.c index 34561d3..ce064f1 100644 --- a/define_loudspeakers.c +++ b/define_loudspeakers.c @@ -1,255 +1,172 @@ -/* define_loudspeakers.c +/* define_loudspeakers.c 1.00b1----> x-max4.2 -written by Ville Pulkki 1999 +written by Ville Pulkki 1999-2003 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 -#ifndef IRIX -#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 */ +#include "define_loudspeakers.h" +#ifndef VBAP_OBJECT +# ifdef PD +// If we are within VBAP (which includes define_loudspeakers), then don't create a main for define_loudspeakres 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_addbang(def_ls_class, (t_method)def_ls_bang); /* the procedure it uses when it gets a bang in the left inlet */ + 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); + + post(DFLS_VERSION); } +# else /* Max */ +void main(void) +{ + setup((t_messlist **)&def_ls_class, (method)def_ls_new, 0L, (short)sizeof(t_def_ls), 0L, 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 */ + addmess((method)def_ls_read_directions, "ls-directions", A_GIMME, 0); + addmess((method)def_ls_read_triplets, "ls-triplets", A_GIMME, 0); + addmess((method)traces, "enabletrace", A_LONG, 0); + post(DFLS_VERSION); +} +# endif /* PD */ +#endif /* ! VBAP_OBJECT */ 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; +{ // calculate and print out chosen loudspeaker sets and corresponding matrices - if(x->x_ls_read == 1){ - if(x->x_ls_amount < x->x_dimension){ - post("define-loudspeakers: Too few loudspeakers!",0); + if(x->x_ls_read == 1) + { + if(x->x_def_ls_amount < x->x_def_ls_dimension) + { + error("define-loudspeakers: Too few loudspeakers!"); 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) + } + else + { + if(x->x_def_ls_dimension == 3) + { + if(x->x_triplets_specified==0) choose_ls_triplets(x); + calculate_3x3_matrixes(x); + } + else if(x->x_def_ls_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 + { + error("define-loudspeakers: Error in loudspeaker direction data"); + error("dimension azimuth1 [elevation1] azimuth2 [elevation2]..."); + error("dimension == 2 for horizontal ls arrays"); + error("dimension == 3 for 3-D ls arrays (speakers also upward and/or downward "); } - } 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); + } + } + else + { + error("define-loudspeakers: Error in loudspeaker direction data"); + error("dimension azimuth1 [elevation1] azimuth2 [elevation2]..."); + error("dimension == 2 for horizontal ls arrays"); + error("dimension == 3 for 3-D ls arrays (speakers also upward and/or downward "); } } /*--------------------------------------------------------------------------*/ -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 */ +/* +void def_ls_int(t_def_ls *x, long 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??? */ + // 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 */ +void def_ls_read_triplets(t_def_ls *x, t_symbol *s, int ac, 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); + if(x->x_ls_read == 0) + { + error("define_loudspeakers: Define loudspeaker directions first!"); return; } - if(x->x_dimension == 2){ - post("define_loudspeakers: Can't specify loudspeaker triplets in 2-D setup!",0); + if(x->x_def_ls_dimension == 2) + { + error("define_loudspeakers: Can't specify loudspeaker triplets in 2-D setup!"); 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; + 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) + int i; + for(i=0;i<ac;i+=3) + { + long l1 = 0,l2 = 0,l3 = 0; + +/* + if(av[i].a_type == A_LONG) l1 = av[i].a_w.w_long; - else */ - if(av[i].a_type == A_FLOAT) + else */ if(av[i].a_type == A_FLOAT) l1 = (long) av[i].a_w.w_float; -/* if(av[i+1].a_type == A_LONG) + +/* + 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) + 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) + +/* + 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) + 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; + + 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 */ +void def_ls_read_directions(t_def_ls *x, t_symbol *s, int ac, 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; + if (x->x_ls_read) + { + // Remove old matrices + t_ls_set* trip_ptr = x->x_ls_set; + while (trip_ptr != NULL) + { // remove old matrices + t_ls_set* tmp_ptr = trip_ptr; + trip_ptr = trip_ptr->next; + freebytes(tmp_ptr, sizeof (struct t_ls_set)); } - 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; + x->x_ls_set = NULL; + + initContent_ls_directions(x,ac,av); } /*--------------------------------------------------------------------------*/ void ls_angles_to_cart(t_ls *ls) -/* convert angular direction to cartesian */ +// 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); @@ -257,73 +174,92 @@ void ls_angles_to_cart(t_ls *ls) 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!! */ +/* create new instance of object... MUST send it an int even if you do nothing with this int!! */ +void *def_ls_new(t_symbol *s, int ac, Atom *av) { - long i,pointer; - t_def_ls *x; + // s is object name (we ignore it) + t_def_ls *x = (t_def_ls *)newobject(def_ls_class); - x = (t_def_ls *)pd_new(def_ls_class); - +#ifdef PD + x->x_outlet0 = outlet_new(&x->x_obj, gensym("list")); /* create a (list) outlet */ +#else /* Max */ + x->x_outlet0 = outlet_new(x, 0L); /* create a (list) outlet */ +#endif /* PD */ + + initContent_ls_directions(x,ac,av); // Initialize object internal data from a ls-directions list + + return x; /* return a reference to the object instance */ +} + +/* define-loudspeakers message integrated into vbap object */ +void vbap_def_ls(t_def_ls *x, t_symbol *s, int ac, Atom *av) +{ + initContent_ls_directions(x,ac,av); // Initialize object internal data from a ls-directions list + def_ls_bang(x); // calculate and send matrix to vbap +} + +/** Initialize the object content from parameters : ls-directions list */ +void initContent_ls_directions(t_def_ls *x,int ac,Atom*av) +{ x->x_ls_read = 0; -/* if(av[0].a_type == A_LONG){ - x->x_dimension= av[0].a_w.w_long; + + long d = 0; +/* if (av[0].a_type == A_LONG) d = av[0].a_w.w_long; + else */ if(av[0].a_type == A_FLOAT) d = (long)av[0].a_w.w_float; + else { error("define-loudspeakers: dimension NaN"); return; } + + if (d==2 || d==3) + { + x->x_def_ls_dimension= d; 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; + } + else + { + x->x_def_ls_dimension= 0; + error("define-loudspeakers: Dimension has to be 2 or 3!"); + return; + } + + int pointer = 1; + x->x_def_ls_amount= (ac-1) / (x->x_def_ls_dimension - 1); + + // read loudspeaker direction angles + int i; + for(i=0; i < x->x_def_ls_amount;i++) + { + float azi = 0; +/* if(av[pointer].a_type == A_LONG) azi = (float) av[pointer].a_w.w_long; + else */ if(av[pointer].a_type == A_FLOAT) azi = av[pointer].a_w.w_float; + else { error("define-loudspeakers: direction angle #%d NaN",i+1); x->x_ls_read = 0; return; } + + x->x_ls[i].azi = azi; - 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(0); - } 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(0); - } + + float ele = 0; // in 2d elevation is zero + if(x->x_def_ls_dimension == 3) + { // 3-D +/* if(av[pointer].a_type == A_LONG) ele = (float) av[pointer].a_w.w_long; + else */ if(av[pointer].a_type == A_FLOAT) ele = av[pointer].a_w.w_float; + else { error("define-loudspeakers: elevation #%d NaN",i+1); x->x_ls_read = 0; return; } + pointer++; - } else - x->x_ls[i].ele = 0.0; /* in 2d elevation is zero */ + } + x->x_ls[i].ele = ele; } if(x->x_ls_read == 1) - for(i=0;i<x->x_ls_amount;i++) + { + int i; + for(i=0;i<x->x_def_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. @@ -337,28 +273,27 @@ void choose_ls_triplets(t_def_ls *x) 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 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 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; + int ls_amount = x->x_def_ls_amount; t_ls *lss = x->x_ls; - if (ls_amount == 0) { - post("define-loudspeakers: Number of loudspeakers is zero",0); - return; - } - + if (ls_amount == 0) { post("define-loudspeakers: Number of loudspeakers is zero"); 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){ + 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; @@ -369,18 +304,23 @@ void choose_ls_triplets(t_def_ls *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) { + 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--){ + 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]; @@ -388,55 +328,73 @@ void choose_ls_triplets(t_def_ls *x) distance_table[k] = distance; distance_table_i[k] = i; distance_table_j[k] = j; - } else + } + 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++){ + for(i=0; i<(table_size); i++) + { int fst_ls = distance_table_i[i]; - int sec_ls = distance_table_j[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){ + { + 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){ + 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) { + 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 { + } + 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 { + } + else + { prev = trip_ptr; trip_ptr = trip_ptr->next; - } } x->x_triplets_specified=1; @@ -449,7 +407,7 @@ int any_ls_inside_triplet(int a, int b, int c,t_ls lss[MAX_LS_AMOUNT],int ls_amo float invdet; t_ls *lp1, *lp2, *lp3; float invmx[9]; - int i,j,k; + int i,j; float tmp; int any_ls_inside, this_inside; @@ -473,10 +431,13 @@ int any_ls_inside_triplet(int a, int b, int c,t_ls lss[MAX_LS_AMOUNT],int ls_amo 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){ + for(i=0; i< ls_amount; i++) + { + if (i != a && i!=b && i != c) + { this_inside = 1; - for(j=0; j< 3; j++){ + 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]; @@ -496,12 +457,12 @@ void add_ldsp_triplet(int i, int j, int k, t_def_ls *x) struct t_ls_set *trip_ptr, *prev; trip_ptr = x->x_ls_set; prev = NULL; - while (trip_ptr != 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)); + trip_ptr = (struct t_ls_set*) getbytes (sizeof (struct t_ls_set)); if(prev == NULL) x->x_ls_set = trip_ptr; else @@ -509,14 +470,14 @@ void add_ldsp_triplet(int i, int j, int k, t_def_ls *x) trip_ptr->next = NULL; trip_ptr->ls_nos[0] = i; trip_ptr->ls_nos[1] = j; - trip_ptr->ls_nos[2] = k; + trip_ptr->ls_nos[2] = k; } float vec_angle(t_ls v1, t_ls v2) -/* angle between two loudspeakers */ +// angle between two loudspeakers { float inner= ((v1.x*v2.x + v1.y*v2.y + v1.z*v2.z)/ (vec_length(v1) * vec_length(v2))); @@ -528,26 +489,27 @@ float vec_angle(t_ls v1, t_ls v2) } float vec_length(t_ls v1) -/* length of a vector */ +// 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 */ +// 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] ){ +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); + ls_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])) @@ -558,14 +520,15 @@ float vol_p_side_lgth(int i, int j,int k, t_ls lss[MAX_LS_AMOUNT] ){ return 0.0; } -void unq_cross_prod(t_ls v1,t_ls v2, +void ls_cross_prod(t_ls v1,t_ls v2, t_ls *res) -/* vector cross product */ +// 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; @@ -580,13 +543,13 @@ int lines_intersect(int i,int j,int k,int l,t_ls lss[MAX_LS_AMOUNT]) t_ls v1; t_ls v2; t_ls v3, neg_v3; - float angle; + //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); + ls_cross_prod(lss[i],lss[j],&v1); + ls_cross_prod(lss[k],lss[l],&v2); + ls_cross_prod(v1,v2,&v3); neg_v3.x= 0.0 - v3.x; neg_v3.y= 0.0 - v3.y; @@ -605,12 +568,12 @@ int lines_intersect(int i,int j,int k,int l,t_ls lss[MAX_LS_AMOUNT]) /* 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_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 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) && @@ -627,28 +590,30 @@ void calculate_3x3_matrixes(t_def_ls *x) float invdet; t_ls *lp1, *lp2, *lp3; float *invmx; - float *ptr; + //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; + int triplet_amount = 0, /*ftable_size,*/i,pointer,list_length=0; + Atom *at; t_ls *lss = x->x_ls; - if (tr_ptr == NULL){ - post("define-loudspeakers: Not valid 3-D configuration\n",1); + if (tr_ptr == NULL) + { + error("define-loudspeakers: Not valid 3-D configuration\n"); return; } /* counting triplet amount */ - while(tr_ptr != NULL){ + 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)); + list_length= triplet_amount * 21 + 3; + at= (Atom *) getbytes(list_length*sizeof(Atom)); - SETFLOAT(&at[0], x->x_dimension); - SETFLOAT(&at[1], x->x_ls_amount); + SETLONG(&at[0], x->x_def_ls_dimension); + SETLONG(&at[1], x->x_def_ls_amount); pointer=2; while(tr_ptr != NULL){ @@ -672,7 +637,7 @@ void calculate_3x3_matrixes(t_def_ls *x) 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); + SETLONG(&at[pointer], tr_ptr->ls_nos[i]+1); pointer++; } for(i=0;i<9;i++){ @@ -691,8 +656,9 @@ void calculate_3x3_matrixes(t_def_ls *x) tr_ptr = tr_ptr->next; } - outlet_anything(x->x_outlet0, gensym("loudspeaker-matrices"), list_length, at); - freebytes(at, list_length*sizeof(t_atom)); + sendLoudspeakerMatrices(x,list_length, at); +// outlet_anything(x->x_outlet0, gensym("loudspeaker-matrices"), list_length, at); + freebytes(at, list_length*sizeof(Atom)); } @@ -701,20 +667,21 @@ 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; + //float atorad = (2 * 3.1415927 / 360) ; + int i,j; + //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; + float inv_mat[MAX_LS_AMOUNT][4]; // In 2-D ls amount == max amount of LS pairs + float mat[MAX_LS_AMOUNT][4]; + //float *ptr; + //float *ls_table; t_ls *lss = x->x_ls; - long ls_amount=x->x_ls_amount; + long ls_amount=x->x_def_ls_amount; long list_length; - t_atom *at; + Atom *at; long pointer; for(i=0;i<MAX_LS_AMOUNT;i++){ @@ -730,69 +697,79 @@ void choose_ls_tuplets(t_def_ls *x) 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){ + inv_mat[i],mat[i]) != 0){ exist[i]=1; amount++; } } } - if(((6.283 - lss[sorted_lss[ls_amount-1]].azi) + if(((360 - 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) { + inv_mat[ls_amount-1],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)); + // Output + list_length= amount * 10 + 2; + at= (Atom *) getbytes(list_length*sizeof(Atom)); - SETFLOAT(&at[0], x->x_dimension); - SETFLOAT(&at[1], x->x_ls_amount); + SETLONG(&at[0], x->x_def_ls_dimension); + SETLONG(&at[1], x->x_def_ls_amount); pointer=2; for (i=0;i<ls_amount - 1;i++){ if(exist[i] == 1) { - SETFLOAT(&at[pointer], sorted_lss[i]+1); + SETLONG(&at[pointer], sorted_lss[i]+1); pointer++; - SETFLOAT(&at[pointer], sorted_lss[i+1]+1); + SETLONG(&at[pointer], sorted_lss[i+1]+1); pointer++; for(j=0;j<4;j++) { SETFLOAT(&at[pointer], inv_mat[i][j]); pointer++; } + for(j=0;j<4;j++) { + SETFLOAT(&at[pointer], mat[i][j]); + pointer++; + } } } if(exist[ls_amount-1] == 1) { - SETFLOAT(&at[pointer], sorted_lss[ls_amount-1]+1); + SETLONG(&at[pointer], sorted_lss[ls_amount-1]+1); pointer++; - SETFLOAT(&at[pointer], sorted_lss[0]+1); + SETLONG(&at[pointer], sorted_lss[0]+1); pointer++; for(j=0;j<4;j++) { SETFLOAT(&at[pointer], inv_mat[ls_amount-1][j]); pointer++; } + for(j=0;j<4;j++) { + SETFLOAT(&at[pointer], mat[ls_amount-1][j]); + pointer++; + } } - outlet_anything(x->x_outlet0, gensym("loudspeaker-matrices"), list_length, at); - freebytes(at, list_length*sizeof(t_atom)); + sendLoudspeakerMatrices(x,list_length, at); + //outlet_anything(x->x_outlet0, gensym("loudspeaker-matrices"), list_length, at); + freebytes(at, list_length*sizeof(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 */ +// sort loudspeakers according to azimuth angle { - int i,j,index; float tmp, tmp_azi; - float rad2ang = 360.0 / ( 2 * 3.141592 ); +// float rad2ang = 360.0f / ( 2.0f * M_PI ); - float x,y; + //float x,y; /* Transforming angles between -180 and 180 */ - for (i=0;i<ls_amount;i++) { + int i; + 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) @@ -801,10 +778,15 @@ void sort_2D_lss(t_ls lss[MAX_LS_AMOUNT], int sorted_lss[MAX_LS_AMOUNT], tmp = lss[i].y / fabs(lss[i].y); lss[i].azi *= tmp; } - for (i=0;i<ls_amount;i++){ +for (i=0;i<ls_amount;i++) + { tmp = 2000; - for (j=0 ; j<ls_amount;j++){ - if (lss[j].azi <= tmp){ + int index = 0; + int j; + for (j=0 ; j<ls_amount;j++) + { + if (lss[j].azi <= tmp) + { tmp=lss[j].azi; index = j; } @@ -813,25 +795,25 @@ void sort_2D_lss(t_ls lss[MAX_LS_AMOUNT], int sorted_lss[MAX_LS_AMOUNT], tmp_azi = (lss[index].azi); lss[index].azi = (tmp_azi + (float) 4000.0); } - for (i=0;i<ls_amount;i++) { + 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 */ +int calc_2D_inv_tmatrix(float azi1,float azi2, float inv_mat[4],float mat[4]) +// calculate inverse 2x2 matrix { float x1,x2,x3,x4; /* x1 x3 */ - float y1,y2,y3,y4; /* x2 x4 */ + //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); + mat[0]=x1 = cos(azi1 / rad2ang); + mat[1]=x2 = sin(azi1 / rad2ang); + mat[2]=x3 = cos(azi2 / rad2ang); + mat[3]=x4 = sin(azi2 / rad2ang); det = (x1 * x4) - ( x3 * x2 ); if(fabsf(det) <= 0.001) { @@ -848,5 +830,3 @@ int calc_2D_inv_tmatrix(float azi1,float azi2, float inv_mat[4]) return 1; } } - - diff --git a/define_loudspeakers.h b/define_loudspeakers.h new file mode 100755 index 0000000..52a8e88 --- /dev/null +++ b/define_loudspeakers.h @@ -0,0 +1,37 @@ +/* define_loudspeakers.c 1.00b1----> x-max4.2 + +written by Ville Pulkki 1999-2003 +Helsinki University of Technology +and +Unversity of California at Berkeley + +See copyright in file with name COPYRIGHT */ + +#include "vbap.h" + +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, long n); +void def_ls_read_directions(t_def_ls *x, t_symbol *s, int ac, Atom *av); +void def_ls_read_triplets(t_def_ls *x, t_symbol *s, int ac, Atom *av); +void *def_ls_new(t_symbol *s, int ac, Atom *av); +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 ls_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],float mat[4]); +void sort_2D_lss(t_ls lss[MAX_LS_AMOUNT], int sorted_lss[MAX_LS_AMOUNT], + int ls_amount); +void initContent_ls_directions(t_def_ls *x,int ac,Atom*av); + +void vbap_def_ls(t_def_ls *x, t_symbol *s, int ac, Atom *av); diff --git a/max2pd.h b/max2pd.h new file mode 100644 index 0000000..2f06217 --- /dev/null +++ b/max2pd.h @@ -0,0 +1,46 @@ +/* + * this header aims to make it easy to port Max objects to Pd + */ + +/* name changes */ +#define SETSYM SETSYMBOL + +/* Pd doesn't have longs */ +#define SETLONG SETFLOAT + +/* different names for the same thing */ +#define Atom t_atom +#define Symbol t_symbol + +/* allocate memory */ +#define sysmem_newptr(size) getbytes(128) +#define sysmem_freeptr(ptr) freebytes(ptr, 128) + +/* standard object API functions */ +#define atom_getlong(atom) atom_getfloatarg(0, 1, atom) +#define atom_getsym(atom) atom_getsymbolarg(0, 1, atom) +#define object_alloc(obj_class) pd_new(obj_class) +#define object_free(obj) pd_free((t_pd*)obj) +#define newobject(class) pd_new(class) +#define outlet_int(outlet, number) outlet_float(outlet, number) + +/* debug things */ +#define _enable_trace sys_verbose + +/* these are NOT included here because they would cause more problems than + * they would solve. Usually, they are used in the setup() and new() + * functions, where most of the differences are between the Max and PD APIs */ + +/* macros */ +// A_DEFLONG + +/* types */ +// method +// Object + +/* functions */ +// addint() +// addmess() +// newobject() +// outlet_new() +// setup() @@ -1,129 +1,217 @@ -/* vbap.c vers 0.99 for max4.0 +/* vbap.c vers 1.00b1 for ------ > xmax4.2 -written by Ville Pulkki 1999-2001 +written by Ville Pulkki 1999-2003 Helsinki University of Technology and -Unversity of California at Berkeley +University 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 9171 /* resource ID for assistance (we'll add that later) */ -#define MAX_LS_SETS 100 /* maximum number of loudspeaker sets (triplets or pairs) allowed */ -#define MAX_LS_AMOUNT 55 /* maximum amount of loudspeakers, can be increased */ - -#ifndef IRIX -#define sqrtf sqrt -#endif - -typedef struct vbap /* This defines the object as an entity made up of other things */ -{ - t_object x_ob; - t_float x_azi; /* panning direction azimuth */ - t_float x_ele; /* panning direction elevation */ - void *x_outlet0; /* outlet creation - inlets are automatic */ - void *x_outlet1; - void *x_outlet2; - void *x_outlet3; - float x_set_inv_matx[MAX_LS_SETS][9]; /* inverse matrice for each loudspeaker set */ - float x_set_matx[MAX_LS_SETS][9]; /* matrice for each loudspeaker set */ - long x_lsset[MAX_LS_SETS][3]; /* channel numbers of loudspeakers in each LS set */ - long x_lsset_available; /* have loudspeaker sets been defined with define_loudspeakers */ - long x_lsset_amount; /* amount of loudspeaker sets */ - long x_ls_amount; /* amount of loudspeakers */ - long x_dimension; /* 2 or 3 */ - t_float x_spread; /* speading amount of virtual source (0-100) */ - float x_spread_base[3]; /* used to create uniform spreading */ -} t_vbap; - -/* Globals */ - -static void new_spread_dir(t_vbap *x, float spreaddir[3], float vscartdir[3], float spread_base[3]); -static void new_spread_base(t_vbap *x, float spreaddir[3], float vscartdir[3]); -static t_class *vbap_class; -static void cross_prod(float v1[3], float v2[3], - float v3[3]); -static void additive_vbap(float *final_gs, float cartdir[3], t_vbap *x); -static void vbap_bang(t_vbap *x); -/* static void vbap_int(t_vbap *x, t_float n); */ -static void vbap_matrix(t_vbap *x, t_symbol *s, int ac, t_atom *av); -/* - * unused 2006-08-13 <hans@at.or.at> -static void vbap_in1(t_vbap *x, long n); -static void vbap_in2(t_vbap *x, long n); -static void vbap_in3(t_vbap *x, long n); +// Indicate that we are within VBAP object (specific to include define_loudspeakers content within vbap) +#define VBAP_OBJECT + +#include "vbap.h" +#include "s_stuff.h" + +// Function prototypes +void new_spread_dir(t_vbap *x, float spreaddir[3], float vscartdir[3], float spread_base[3]); +void new_spread_base(t_vbap *x, float spreaddir[3], float vscartdir[3]); +void *vbap_class; +void vect_cross_prod(float v1[3], float v2[3],float v3[3]); +void additive_vbap(float *final_gs, float cartdir[3], t_vbap *x); +void vbap_bang(t_vbap *x); +void vbap_matrix(t_vbap *x, Symbol *s, int ac, Atom *av); +/* these are for getting data from a cold inlet on Max/MSP, in Pd you use floatinlet_new() in new() +void vbap_ft1(t_vbap *x, double n); +void vbap_ft2(t_vbap *x, double n); +void vbap_in3(t_vbap *x, long n); +void vbap_ft4(t_vbap *x, double g); */ -static void spread_it(t_vbap *x, float *final_gs); -static void *vbap_new(t_symbol *s, int ac, t_atom *av); /* using A_GIMME - typed message list */ -static void vbap(float g[3], long ls[3], t_vbap *x); -static void angle_to_cart(long azi, long ele, float res[3]); -static void cart_to_angle(float cvec[3], float avec[3]); +void spread_it(t_vbap *x, float *final_gs); +void *vbap_new(float azi,float ele); +void vbap(float g[3], long ls[3], t_vbap *x); +void angle_to_cart(float azi, float ele, float res[3]); +void cart_to_angle(float cvec[3], float avec[3]); + +/***************************************************** + INCLUDE ALL define_loudspeakers functions directly into VBAP +******************************************************/ +#include "define_loudspeakers.c" + +/***************************************************** + Max Object Assist +******************************************************/ +#ifndef PD /* Max */ +void vbap_assist(t_vbap *x, void *b, long m, long a, char *s) +{ + char*mess = "unknown"; + if (m == ASSIST_INLET) + { + switch(a) + { + case 0 : mess = "bang to calc and output vbap gains. loudspeakers definition"; break; + case 1 : mess = "panning angle azimuth"; break; + case 2 : mess = "panning angle elevation"; break; + case 3 : mess = "spread amount"; break; + case 4 : mess = "gain control"; break; + } + } + else + { + switch(a) + { + case 0 : mess = "vbap gains"; break; + case 1 : mess = "panning angle azimuth"; break; + case 2 : mess = "panning angle elevation"; break; + case 3 : mess = "spread amount"; break; + case 4 : mess = "gain control"; break; + } + } + sprintf(s,mess); +} +#endif /* Max */ /* above are the prototypes for the methods/procedures/functions you will use */ - +/*--------------------------------------------------------------------------*/ +#ifdef PD void vbap_setup(void) { vbap_class = class_new(gensym("vbap"), (t_newmethod)vbap_new, 0, (short)sizeof(t_vbap), 0, A_GIMME, 0); - /* vbap_new = creation function, A_DEFLONG = its (optional) arguement is a long (32-bit) int */ - -#ifdef MAXMSP -/* max methods ... */ - - addbang((method)vbap_bang); /* the procedure it uses when it gets a bang in the left inlet */ - addint((method)vbap_int); /* the rocedure for an int in the left inlet (inlet 0) */ - addinx((method)vbap_in1, 1); /* the rocedure for an int in the right inlet (inlet 1) */ - addinx((method)vbap_in2, 2); /* the rocedure for an int in the right inlet (inlet 2) */ - addinx((method)vbap_in3, 3); - addmess((method)vbap_matrix, "loudspeaker-matrices", A_GIMME, 0); */ - - pure data: -#endif - class_addbang(vbap_class, vbap_bang); -/* class_addfloat(vbap_class, vbap_int); */ + + class_addbang(vbap_class, (t_method)vbap_bang); +/* these are for getting data from a cold inlet on Max/MSP, in Pd you use floatinlet_new() in new() + addftx((t_method)vbap_ft1, 1); + addftx((t_method)vbap_ft2, 2); + addftx((t_method)vbap_in3, 3); + addftx((t_method)vbap_ft4, 4); +*/ class_addmethod(vbap_class, (t_method)vbap_matrix, gensym("loudspeaker-matrices"), A_GIMME, 0); + + // define_loudspeaker messages + class_addmethod(vbap_class, (t_method)vbap_def_ls, gensym("define-loudspeakers"), A_GIMME, 0); + class_addmethod(vbap_class, (t_method)vbap_def_ls, gensym("define_loudspeakers"), A_GIMME, 0); + class_addmethod(vbap_class, (t_method)def_ls_read_directions, gensym("ls-directions"), A_GIMME, 0); + class_addmethod(vbap_class, (t_method)def_ls_read_triplets, gensym("ls-triplets"), A_GIMME, 0); + + post(VBAP_VERSION); } +#else /* MAX */ +void main(void) +{ + setup((t_messlist **)&vbap_class, (method)vbap_new, 0L, (short)sizeof(t_vbap), 0L, A_DEFLONG,A_DEFLONG, 0); + + addbang((method)vbap_bang); + addftx((method)vbap_ft1, 1); + addftx((method)vbap_ft2, 2); + addftx((method)vbap_in3, 3); + addftx((method)vbap_ft4, 4); + addmess((method)vbap_matrix, "loudspeaker-matrices", A_GIMME, 0); + addmess((method)traces, "enabletrace", A_LONG, 0); + + // define_loudspeaker messages + addmess((method)vbap_def_ls, "define-loudspeakers", A_GIMME, 0); + addmess((method)vbap_def_ls, "define_loudspeakers", A_GIMME, 0); + addmess((method)def_ls_read_directions, "ls-directions", A_GIMME, 0); + addmess((method)def_ls_read_triplets, "ls-triplets", A_GIMME, 0); + addmess((method)vbap_assist,"assist",A_CANT,0); -static void angle_to_cart(long azi, long ele, float res[3]) -/* converts angular coordinates to cartesian */ + post(VBAP_VERSION); +} + +/* these are for getting data from a cold inlet on Max/MSP, in Pd you use floatinlet_new() in new() */ +/*--------------------------------------------------------------------------*/ +// panning angle azimuth +void vbap_ft1(t_vbap *x, double n) { x->x_azi = (float) n; } +/*--------------------------------------------------------------------------*/ +// panning angle elevation +void vbap_ft2(t_vbap *x, double n) { x->x_ele = (float) n; } +/*--------------------------------------------------------------------------*/ +// spread amount +void vbap_in3(t_vbap *x, long n) { x->x_spread = (n<0) ? 0 : (n>100) ? 100 : n; } +/*--------------------------------------------------------------------------*/ +// gain control +void vbap_ft4(t_vbap *x, double g) { x->x_gain = g; } +#endif /* MAX */ + +/*--------------------------------------------------------------------------*/ +// create new instance of object... +void *vbap_new(float azi,float ele) +{ + t_vbap *x = (t_vbap *)newobject(vbap_class); + +#ifdef PD + floatinlet_new(&x->x_obj, &x->x_azi); + floatinlet_new(&x->x_obj, &x->x_ele); + floatinlet_new(&x->x_obj, &x->x_spread); + + x->x_outlet4 = outlet_new(&x->x_obj, gensym("float")); + x->x_outlet3 = outlet_new(&x->x_obj, gensym("float")); + x->x_outlet2 = outlet_new(&x->x_obj, gensym("float")); + x->x_outlet1 = outlet_new(&x->x_obj, gensym("float")); + x->x_outlet0 = outlet_new(&x->x_obj, gensym("list")); +#else /* Max */ + floatin(x,4); + floatin(x,3); + floatin(x,2); + floatin(x,1); + + x->x_outlet4 = floatout(x); + x->x_outlet3 = floatout(x); + x->x_outlet2 = floatout(x); + x->x_outlet1 = floatout(x); + x->x_outlet0 = listout(x); +#endif /* PD */ + + x->x_spread_base[0] = 0.0; + x->x_spread_base[1] = 1.0; + x->x_spread_base[2] = 0.0; + x->x_spread = 0; + x->x_lsset_available =0; + + x->x_azi = azi; + x->x_ele = ele; + x->x_gain = 1.0; + + return(x); /* return a reference to the object instance */ +} + + +void angle_to_cart(float azi, float ele, float res[3]) +// converts angular coordinates to cartesian { - float atorad = (2 * 3.1415927 / 360) ; - res[0] = cos((float) azi * atorad) * cos((float) ele * atorad); - res[1] = sin((float) azi * atorad) * cos((float) ele * atorad); - res[2] = sin((float) ele * atorad); + res[0] = cos(azi * atorad) * cos( ele * atorad); + res[1] = sin( azi * atorad) * cos( ele * atorad); + res[2] = sin( ele * atorad); } -static void cart_to_angle(float cvec[3], float avec[3]) -/* converts cartesian coordinates to angular */ +void cart_to_angle(float cvec[3], float avec[3]) +// converts cartesian coordinates to angular { -// float tmp, tmp2, tmp3, tmp4; /* warning: unused variable */ - float atorad = (2 * 3.1415927 / 360) ; - float pi = 3.1415927; -// float power; /* warning: unused variable */ + //float tmp, tmp2, tmp3, tmp4; + //float power; float dist, atan_y_per_x, atan_x_pl_y_per_z; float azi, ele; if(cvec[0]==0.0) - atan_y_per_x = pi / 2; + atan_y_per_x = M_PI / 2; else atan_y_per_x = atan(cvec[1] / cvec[0]); azi = atan_y_per_x / atorad; if(cvec[0]<0.0) - azi +=180; + azi +=180.0; dist = sqrt(cvec[0]*cvec[0] + cvec[1]*cvec[1]); if(cvec[2]==0.0) atan_x_pl_y_per_z = 0.0; else atan_x_pl_y_per_z = atan(cvec[2] / dist); if(dist == 0.0) - { + { if(cvec[2]<0.0) - atan_x_pl_y_per_z = -pi/2.0; + atan_x_pl_y_per_z = -M_PI/2.0; else - atan_x_pl_y_per_z = pi/2.0; - } + atan_x_pl_y_per_z = M_PI/2.0; + } ele = atan_x_pl_y_per_z / atorad; dist = sqrtf(cvec[0] * cvec[0] +cvec[1] * cvec[1] +cvec[2]*cvec[2]); avec[0]=azi; @@ -132,50 +220,51 @@ static void cart_to_angle(float cvec[3], float avec[3]) } -static void vbap(float g[3], long ls[3], t_vbap *x) +void vbap(float g[3], long ls[3], t_vbap *x) { /* calculates gain factors using loudspeaker setup and given direction */ float power; int i,j,k, gains_modified; float small_g; float big_sm_g, gtmp[3]; - long winner_set=0; + long winner_set = 0; float cartdir[3]; float new_cartdir[3]; float new_angle_dir[3]; long dim = x->x_dimension; long neg_g_am, best_neg_g_am; - /* transfering the azimuth angle to a decent value */ - while(x->x_azi > 180) - x->x_azi -= 360; - while(x->x_azi < -179) - x->x_azi += 360; + // transfering the azimuth angle to a decent value + while(x->x_azi > 180.0) + x->x_azi -= 360.0; + while(x->x_azi < -179.0) + x->x_azi += 360.0; - /* transferring the elevation to a decent value */ + // transferring the elevation to a decent value if(dim == 3){ - while(x->x_ele > 180) - x->x_ele -= 360; - while(x->x_ele < -179) - x->x_ele += 360; + while(x->x_ele > 180.0) + x->x_ele -= 360.0; + while(x->x_ele < -179.0) + x->x_ele += 360.0; } else - x->x_ele = 0; + x->x_ele = 0.0; - /* go through all defined loudspeaker sets and find the set which + // go through all defined loudspeaker sets and find the set which // has all positive values. If such is not found, set with largest // minimum value is chosen. If at least one of gain factors of one LS set is negative - // it means that the virtual source does not lie in that LS set. */ + // it means that the virtual source does not lie in that LS set. angle_to_cart(x->x_azi,x->x_ele,cartdir); - big_sm_g = -100000.0; /* initial value for largest minimum gain value */ - best_neg_g_am=3; /* how many negative values in this set */ - + big_sm_g = -100000.0; // initial value for largest minimum gain value + best_neg_g_am=3; // how many negative values in this set - for(i=0;i<x->x_lsset_amount;i++){ + for(i=0;i<x->x_lsset_amount;i++) + { small_g = 10000000.0; neg_g_am = 3; - for(j=0;j<dim;j++){ + for(j=0;j<dim;j++) + { gtmp[j]=0.0; for(k=0;k<dim;k++) gtmp[j]+=cartdir[k]* x->x_set_inv_matx[i][k+j*dim]; @@ -184,28 +273,32 @@ static void vbap(float g[3], long ls[3], t_vbap *x) if(gtmp[j]>= -0.01) neg_g_am--; } - if(small_g > big_sm_g && neg_g_am <= best_neg_g_am){ + if(small_g > big_sm_g && neg_g_am <= best_neg_g_am) + { big_sm_g = small_g; best_neg_g_am = neg_g_am; winner_set=i; g[0]=gtmp[0]; g[1]=gtmp[1]; ls[0]= x->x_lsset[i][0]; ls[1]= x->x_lsset[i][1]; - if(dim==3){ + if(dim==3) + { g[2]=gtmp[2]; ls[2]= x->x_lsset[i][2]; - } else { + } + else + { g[2]=0.0; ls[2]=0; } } } - /* If chosen set produced a negative value, make it zero and + // If chosen set produced a negative value, make it zero and // calculate direction that corresponds to these new // gain values. This happens when the virtual source is outside of - // all loudspeaker sets. */ + // all loudspeaker sets. - if(dim==3){ + // gains_modified=0; for(i=0;i<dim;i++) if(g[i]<-0.01){ @@ -219,14 +312,17 @@ static void vbap(float g[3], long ls[3], t_vbap *x) new_cartdir[1] = x->x_set_matx[winner_set][3] * g[0] + x->x_set_matx[winner_set][4] * g[1] + x->x_set_matx[winner_set][5] * g[2]; - new_cartdir[2] = x->x_set_matx[winner_set][6] * g[0] - + x->x_set_matx[winner_set][7] * g[1] - + x->x_set_matx[winner_set][8] * g[2]; + if(dim==3){ + new_cartdir[2] = x->x_set_matx[winner_set][6] * g[0] + + x->x_set_matx[winner_set][7] * g[1] + + x->x_set_matx[winner_set][8] * g[2]; + } else new_cartdir[2] = 0; cart_to_angle(new_cartdir,new_angle_dir); - x->x_azi = (long) (new_angle_dir[0] + 0.5); - x->x_ele = (long) (new_angle_dir[1] + 0.5); + x->x_azi = (new_angle_dir[0] ); + post("uus azi %g",x->x_azi ); + x->x_ele = (new_angle_dir[1]); } - } + //} power=sqrt(g[0]*g[0] + g[1]*g[1] + g[2]*g[2]); g[0] /= power; @@ -235,9 +331,9 @@ static void vbap(float g[3], long ls[3], t_vbap *x) } -static void cross_prod(float v1[3], float v2[3], +void vect_cross_prod(float v1[3], float v2[3], float v3[3]) -/* vector cross product */ +// vector cross product { float length; v3[0] = (v1[1] * v2[2] ) - (v1[2] * v2[1]); @@ -250,30 +346,25 @@ static void cross_prod(float v1[3], float v2[3], v3[2] /= length; } -static void additive_vbap(float *final_gs, float cartdir[3], t_vbap *x) -/* calculates gains to be added to previous gains, used in -// multiple direction panning (source spreading) */ +void additive_vbap(float *final_gs, float cartdir[3], t_vbap *x) +// calculates gains to be added to previous gains, used in +// multiple direction panning (source spreading) { float power; int i,j,k, gains_modified; float small_g; float big_sm_g, gtmp[3]; long winner_set; -// float new_cartdir[3]; /* warning: unused variable */ -// float new_angle_dir[3]; /* warning: unused variable */ + //float new_cartdir[3]; + //float new_angle_dir[3]; long dim = x->x_dimension; long neg_g_am, best_neg_g_am; - float g[3]; - long ls[3] = { 0, 0, 0 }; + float g[3] = {0,0,0}; + long ls[3] = {0,0,0}; big_sm_g = -100000.0; best_neg_g_am=3; - -/* BUG: there is a bug that sometimes causes x->x_lsset_amount to be a massive - * number. I haven't tracked it down yet, but its probably an init - * bug. 2006-08-13 <hans@at.or.at> - */ -// post("x_lsset_amount: %li", x->x_lsset_amount); + for(i=0;i<x->x_lsset_amount;i++){ small_g = 10000000.0; neg_g_am = 3; @@ -309,46 +400,37 @@ static void additive_vbap(float *final_gs, float cartdir[3], t_vbap *x) } if(gains_modified != 1){ - if(dim==3) - power=sqrt(g[0]*g[0] + g[1]*g[1] + g[2]*g[2]); - else - power=sqrt(g[0]*g[0] + g[1]*g[1]); + power=sqrt(g[0]*g[0] + g[1]*g[1] + g[2]*g[2]); g[0] /= power; g[1] /= power; - if(dim==3) - g[2] /= power; + g[2] /= power; final_gs[ls[0]-1] += g[0]; final_gs[ls[1]-1] += g[1]; - /* BUG FIX: this was causing negative indices with 2 dimensions so I - * made it only try when using 3 dimensions. - * 2006-08-13 <hans@at.or.at> */ - if(dim==3) - final_gs[ls[2]-1] += g[2]; + final_gs[ls[2]-1] += g[2]; } } -static void new_spread_dir(t_vbap *x, float spreaddir[3], float vscartdir[3], float spread_base[3]) -/* subroutine for spreading */ +void new_spread_dir(t_vbap *x, float spreaddir[3], float vscartdir[3], float spread_base[3]) +// subroutine for spreading { float beta,gamma; float a,b; - float pi = 3.1415927; float power; gamma = acos(vscartdir[0] * spread_base[0] + vscartdir[1] * spread_base[1] + - vscartdir[2] * spread_base[2])/pi*180; + vscartdir[2] * spread_base[2])/M_PI*180; if(fabs(gamma) < 1){ - angle_to_cart(x->x_azi+90, 0, spread_base); + angle_to_cart(x->x_azi+90.0, 0, spread_base); gamma = acos(vscartdir[0] * spread_base[0] + vscartdir[1] * spread_base[1] + - vscartdir[2] * spread_base[2])/pi*180; + vscartdir[2] * spread_base[2])/M_PI*180; } beta = 180 - gamma; - b=sin(x->x_spread * pi / 180) / sin(beta * pi / 180); - a=sin((180- x->x_spread - beta) * pi / 180) / sin (beta * pi / 180); + b=sin(x->x_spread * M_PI / 180) / sin(beta * M_PI / 180); + a=sin((180- x->x_spread - beta) * M_PI / 180) / sin (beta * M_PI / 180); spreaddir[0] = a * vscartdir[0] + b * spread_base[0]; spreaddir[1] = a * vscartdir[1] + b * spread_base[1]; spreaddir[2] = a * vscartdir[2] + b * spread_base[2]; @@ -360,14 +442,13 @@ static void new_spread_dir(t_vbap *x, float spreaddir[3], float vscartdir[3], fl spreaddir[2] /= power; } -static void new_spread_base(t_vbap *x, float spreaddir[3], float vscartdir[3]) -/* subroutine for spreading */ +void new_spread_base(t_vbap *x, float spreaddir[3], float vscartdir[3]) +// subroutine for spreading { float d; - float pi = 3.1415927; float power; - d = cos(x->x_spread/180*pi); + d = cos(x->x_spread/180*M_PI); x->x_spread_base[0] = spreaddir[0] - d * vscartdir[0]; x->x_spread_base[1] = spreaddir[1] - d * vscartdir[1]; x->x_spread_base[2] = spreaddir[2] - d * vscartdir[2]; @@ -378,13 +459,12 @@ static void new_spread_base(t_vbap *x, float spreaddir[3], float vscartdir[3]) x->x_spread_base[2] /= power; } -static void spread_it(t_vbap *x, float *final_gs) -/* +void spread_it(t_vbap *x, float *final_gs) // apply the sound signal to multiple panning directions // that causes some spreading. // See theory in paper V. Pulkki "Uniform spreading of amplitude panned // virtual sources" in WASPAA 99 -*/ + { float vscartdir[3]; float spreaddir[16][3]; @@ -396,23 +476,23 @@ static void spread_it(t_vbap *x, float *final_gs) angle_to_cart(x->x_azi,x->x_ele,vscartdir); new_spread_dir(x, spreaddir[0], vscartdir, x->x_spread_base); new_spread_base(x, spreaddir[0], vscartdir); - cross_prod(x->x_spread_base, vscartdir, spreadbase[1]); /* four orthogonal dirs */ - cross_prod(spreadbase[1], vscartdir, spreadbase[2]); - cross_prod(spreadbase[2], vscartdir, spreadbase[3]); + vect_cross_prod(x->x_spread_base, vscartdir, spreadbase[1]); // four orthogonal dirs + vect_cross_prod(spreadbase[1], vscartdir, spreadbase[2]); + vect_cross_prod(spreadbase[2], vscartdir, spreadbase[3]); - /* four between them */ + // four between them for(i=0;i<3;i++) spreadbase[4][i] = (x->x_spread_base[i] + spreadbase[1][i]) / 2.0; for(i=0;i<3;i++) spreadbase[5][i] = (spreadbase[1][i] + spreadbase[2][i]) / 2.0; for(i=0;i<3;i++) spreadbase[6][i] = (spreadbase[2][i] + spreadbase[3][i]) / 2.0; for(i=0;i<3;i++) spreadbase[7][i] = (spreadbase[3][i] + x->x_spread_base[i]) / 2.0; - /* four at half spreadangle */ + // four at half spreadangle for(i=0;i<3;i++) spreadbase[8][i] = (vscartdir[i] + x->x_spread_base[i]) / 2.0; for(i=0;i<3;i++) spreadbase[9][i] = (vscartdir[i] + spreadbase[1][i]) / 2.0; for(i=0;i<3;i++) spreadbase[10][i] = (vscartdir[i] + spreadbase[2][i]) / 2.0; for(i=0;i<3;i++) spreadbase[11][i] = (vscartdir[i] + spreadbase[3][i]) / 2.0; - /* four at quarter spreadangle */ + // four at quarter spreadangle for(i=0;i<3;i++) spreadbase[12][i] = (vscartdir[i] + spreadbase[8][i]) / 2.0; for(i=0;i<3;i++) spreadbase[13][i] = (vscartdir[i] + spreadbase[9][i]) / 2.0; for(i=0;i<3;i++) spreadbase[14][i] = (vscartdir[i] + spreadbase[10][i]) / 2.0; @@ -454,222 +534,121 @@ static void spread_it(t_vbap *x, float *final_gs) } -static void vbap_bang(t_vbap *x) -/* top level, vbap gains are calculated and outputted */ +void vbap_bang(t_vbap *x) +// top level, vbap gains are calculated and outputted { - t_atom at[MAX_LS_AMOUNT]; + Atom at[MAX_LS_AMOUNT]; float g[3]; long ls[3]; long i; - float *final_gs; - - final_gs = (float *) getbytes(x->x_ls_amount * sizeof(float)); - if(x->x_lsset_available ==1){ + float *final_gs = (float *) getbytes(x->x_ls_amount * sizeof(float)); + + if(x->x_lsset_available ==1) + { vbap(g,ls, x); for(i=0;i<x->x_ls_amount;i++) final_gs[i]=0.0; - for(i=0;i<x->x_dimension;i++){ + for(i=0;i<x->x_dimension;i++) + { final_gs[ls[i]-1]=g[i]; - } - if(x->x_spread != 0){ + } + if(x->x_spread != 0) + { spread_it(x,final_gs); } - for(i=0;i<x->x_ls_amount;i++) { - SETFLOAT(&at[0], (t_float)i); - SETFLOAT(&at[1], (t_float)final_gs[i]); - outlet_list(x->x_outlet0, gensym("list") /* was: 0L */, 2, at); + for(i=0;i<x->x_ls_amount;i++) + { + SETLONG(&at[0], i); + SETFLOAT(&at[1], final_gs[i]*x->x_gain); // gain is applied here + outlet_list(x->x_outlet0, 0L, 2, at); } outlet_float(x->x_outlet1, x->x_azi); outlet_float(x->x_outlet2, x->x_ele); - outlet_float(x->x_outlet3, x->x_spread); + outlet_int(x->x_outlet3, x->x_spread); + outlet_int(x->x_outlet4, x->x_gain); } else - post("vbap: Configure loudspeakers first!",0); -/* freebytes(final_gs, x->x_ls_amount * sizeof(float)); bug fix added 9/00 */ + error("vbap: Configure loudspeakers first!"); + + freebytes(final_gs, x->x_ls_amount * sizeof(float)); // bug fix added 9/00 } /*--------------------------------------------------------------------------*/ -/* -static void vbap_int(t_vbap *x, t_float n) // x = the instance of the object, n = the int received in the right inlet +void vbap_matrix(t_vbap *x, Symbol *s, int ac, Atom *av) +// read in loudspeaker matrices { - // do something if an int comes in the left inlet??? -} -*/ - -static void vbap_matrix(t_vbap *x, t_symbol *s, int ac, t_atom *av) -/* read in loudspeaker matrices */ -{ - long counter=0; - long datapointer=0; - long setpointer=0; - long i; -// long deb=0; - - if(ac>0) { -/* if(av[datapointer].a_type == A_LONG){ - x->x_dimension = av[datapointer++].a_w.w_long; - x->x_lsset_available=1; - } else */ - if(av[datapointer].a_type == A_FLOAT){ - x->x_dimension = (long) av[datapointer++].a_w.w_float; - x->x_lsset_available=1; - } else { - post("Error in loudspeaker data!",0); - x->x_lsset_available=0; - return; - } + int datapointer = 0; + if(ac>0) + { + int d = 0; + /*if(av[datapointer].a_type == A_LONG) d = av[datapointer++].a_w.w_long; + else*/ if(av[datapointer].a_type == A_FLOAT) d = (long)av[datapointer++].a_w.w_float; + else { error("vbap: Dimension NaN"); x->x_lsset_available=0; return; } + + if (d!=2 && d!=3) { error("vbap %s: Dimension can be only 2 or 3",s->s_name); x->x_lsset_available=0; return; } + + x->x_dimension = d; + x->x_lsset_available=1; } -/* post("%d",deb++); */ - if(ac>1) { -/* if(av[datapointer].a_type == A_LONG) - x->x_ls_amount = av[datapointer++].a_w.w_long; - else */ - if(av[datapointer].a_type == A_FLOAT) - x->x_ls_amount = (long) av[datapointer++].a_w.w_float; - else { - post("vbap: Error in loudspeaker data!",0); - x->x_lsset_available=0; - return; - } + else { error("vbap %s: bad empty parameter list",s->s_name); x->x_lsset_available=0; return; } + + if(ac>1) + { + long a = 0; + /*if(av[datapointer].a_type == A_LONG) a = av[datapointer++].a_w.w_long; + else*/ if(av[datapointer].a_type == A_FLOAT) a = (long) av[datapointer++].a_w.w_float; + else { error("vbap: ls_amount NaN"); x->x_lsset_available=0; return; } + + x->x_ls_amount = a; } - else - x->x_lsset_available=0; -/* post("%d",deb++); */ - if(x->x_dimension == 3) - counter = (ac - 2) / ((x->x_dimension * x->x_dimension*2) + x->x_dimension); - if(x->x_dimension == 2) - counter = (ac - 2) / ((x->x_dimension * x->x_dimension) + x->x_dimension); + long counter = (ac - 2) / ((x->x_dimension * x->x_dimension*2) + x->x_dimension); x->x_lsset_amount=counter; - if(counter<=0) { - post("vbap: Error in loudspeaker data!",0); - x->x_lsset_available=0; - return; - } + if(counter==0) { error("vbap %s: not enough parameters",s->s_name); x->x_lsset_available=0; return; } + long setpointer=0; + long i; - while(counter-- > 0){ - for(i=0; i < x->x_dimension; i++){ - if(av[datapointer].a_type == A_FLOAT){ - x->x_lsset[setpointer][i]=(long)av[datapointer++].a_w.w_float; -/* post("%d",deb++); */ + while(counter-- > 0) + { + for(i=0; i < x->x_dimension; i++) + { +# ifdef PD + if(av[datapointer].a_type == A_FLOAT) + { + x->x_lsset[setpointer][i]=(long)av[datapointer++].a_w.w_float; } - else{ - post("vbap: Error in loudspeaker data!",0); - x->x_lsset_available=0; - return; + else { error("vbap %s: param %d is not a float",s->s_name,datapointer); x->x_lsset_available=0; return; } +# else /* Max */ + if(av[datapointer].a_type == A_LONG) + { + x->x_lsset[setpointer][i]=av[datapointer++].a_w.w_long; } + else { error("vbap %s: param %d is not an in",s->s_name,datapointer); x->x_lsset_available=0; return; } +# endif /* PD */ } - - for(i=0; i < x->x_dimension*x->x_dimension; i++){ - if(av[datapointer].a_type == A_FLOAT){ + for(i=0; i < x->x_dimension*x->x_dimension; i++) + { + if(av[datapointer].a_type == A_FLOAT) + { x->x_set_inv_matx[setpointer][i]=av[datapointer++].a_w.w_float; -/* post("%d",deb++); */ - } - else { - post("vbap: Error in loudspeaker data!",0); - x->x_lsset_available=0; - return; } + else { error("vbap %s: param %d is not a float",s->s_name,datapointer); x->x_lsset_available=0; return; } } - if(x->x_dimension == 3){ - for(i=0; i < x->x_dimension*x->x_dimension; i++){ - if(av[datapointer].a_type == A_FLOAT){ - x->x_set_matx[setpointer][i]=av[datapointer++].a_w.w_float; -/* post("%d",deb++); */ - } - else { - post("vbap: Error in loudspeaker data!",0); - x->x_lsset_available=0; - return; - } + + for(i=0; i < x->x_dimension*x->x_dimension; i++) + { + if(av[datapointer].a_type == A_FLOAT) + { + x->x_set_matx[setpointer][i]=av[datapointer++].a_w.w_float; } + else { error("vbap %s: param %d is not a float",s->s_name,datapointer); x->x_lsset_available=0; return; } + } setpointer++; } - post("vbap: Loudspeaker setup configured!",0); -} - -/* - * unused 2006-08-13 <hans@at.or.at> -static void vbap_in1(t_vbap *x, long n) // x = the instance of the object, n = the int received in the right inlet -// panning angle azimuth -{ - x->x_azi = n; // store n in a global variable - + if (_enable_trace) post("vbap: Loudspeaker setup configured!"); } - -static void vbap_in2(t_vbap *x, long n) // x = the instance of the object, n = the int received in the right inlet -// panning angle elevation -{ - x->x_ele = n; // store n in a global variable - -} - -static void vbap_in3(t_vbap *x, long n) // x = the instance of the object, n = the int received in the right inlet -// spread amount -{ - if (n<0) n = 0; - if (n>100) n = 100; - x->x_spread = n; // store n in a global variable - -} -*/ - -static void *vbap_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!! */ -{ - t_vbap *x; - x = (t_vbap *)pd_new(vbap_class); - -#if 0 - MAX: - intin(x,3); - intin(x,2); /* create a second (int) inlet... remember right-to-left ordering in Max */ - intin(x,1); /* create a second (int) inlet... remember right-to-left ordering in Max */ - x->x_outlet3 = intout(x); - x->x_outlet2 = intout(x); /* create an (int) outlet - rightmost outlet first... */ - x->x_outlet1 = intout(x); /* create an (int) outlet */ - x->x_outlet0 = listout(x); /* create a (list) outlet */ - - pure data: -#endif - floatinlet_new(&x->x_ob, &x->x_azi); - floatinlet_new(&x->x_ob, &x->x_ele); - floatinlet_new(&x->x_ob, &x->x_spread); - - x->x_outlet0 = outlet_new(&x->x_ob, gensym("list")); - x->x_outlet1 = outlet_new(&x->x_ob, gensym("float")); - x->x_outlet2 = outlet_new(&x->x_ob, gensym("float")); - x->x_outlet3 = outlet_new(&x->x_ob, gensym("float")); - -/* - */ - - - x->x_azi = 0; - x->x_ele = 0; - x->x_spread_base[0] = 0.0; - x->x_spread_base[1] = 1.0; - x->x_spread_base[2] = 0.0; - x->x_spread = 0; - x->x_lsset_available =0; - if (ac>0) { -/* if (av[0].a_type == A_LONG) - x->x_azi = av[0].a_w.w_long; - else */ - if (av[0].a_type == A_FLOAT) - x->x_azi = (long)av[0].a_w.w_float; - } - if (ac>1) { -/* if (av[1].a_type == A_LONG) - x->x_ele = av[1].a_w.w_long; - else */ - if (av[1].a_type == A_FLOAT) - x->x_ele = (long)av[1].a_w.w_float; - } - return(x); /* return a reference to the object instance */ -} - @@ -0,0 +1,113 @@ +#ifndef VBAP_H +#define VBAP_H + +#include <math.h> +#include "m_pd.h" +#include "max2pd.h" + +#ifndef M_PI + // don't know where it is in win32, so add it here + #define M_PI 3.14159265358979323846264338327950288 /* pi */ +#endif + +#define MAX_LS_SETS 100 // maximum number of loudspeaker sets (triplets or pairs) allowed +#define MAX_LS_AMOUNT 55 // maximum amount of loudspeakers, can be increased +#define MIN_VOL_P_SIDE_LGTH 0.01 + +#define VBAP_VERSION "vbap - v1.0.3 - 12 Aug 2006 - (c) Ville Pulkki 1999-2006" +#define DFLS_VERSION "define_loudspeakers - v1.0.3 - 12 Aug 2006 - (c) Ville Pulkki 1999-2006" + +static float rad2ang = 360.0 / ( 2.0f * M_PI ); +static float atorad = (2.0f * M_PI) / 360.0f ; + +#ifdef VBAP_OBJECT + // We are inside vbap object, so sending matrix from define_loudspeakers is a simple call to the vbap receiver... + #define sendLoudspeakerMatrices(x,list_length, at) \ + vbap_matrix(x, gensym("loudspeaker-matrices"),list_length, at); \ + vbap_bang(x) +#else + // We are inside define_loudspeaker object, send matrix to outlet + #define sendLoudspeakerMatrices(x,list_length, at) \ + outlet_anything(x->x_outlet0, gensym("loudspeaker-matrices"), list_length, at); +#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; + +#ifdef VBAP_OBJECT + typedef struct vbap /* This defines the object as an entity made up of other things */ + { + t_object x_obj; + float x_azi; // panning direction azimuth + float x_ele; // panning direction elevation + void *x_outlet0; /* outlet creation - inlets are automatic */ + void *x_outlet1; + void *x_outlet2; + void *x_outlet3; + void *x_outlet4; + float x_set_inv_matx[MAX_LS_SETS][9]; // inverse matrice for each loudspeaker set + float x_set_matx[MAX_LS_SETS][9]; // matrice for each loudspeaker set + long x_lsset[MAX_LS_SETS][3]; // channel numbers of loudspeakers in each LS set + long x_lsset_available; // have loudspeaker sets been defined with define_loudspeakers + long x_lsset_amount; // amount of loudspeaker sets + long x_ls_amount; // amount of loudspeakers + long x_dimension; // 2 or 3 +# ifdef PD + t_float x_spread; // speading amount of virtual source (0-100) + t_float x_gain; // general gain control (0-2) +# else /* Max */ + long x_spread; // speading amount of virtual source (0-100) + double x_gain; // general gain control (0-2) +# endif /* PD */ + float x_spread_base[3]; // used to create uniform spreading + + // define_loudspeaker data + 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 + long x_def_ls_amount; // number of loudspeakers + long x_def_ls_dimension; // 2 (horizontal arrays) or 3 (3d setups) + } t_vbap; + + // define loudspeaker data type... + typedef t_vbap t_def_ls; +#else + /* define_loudspeakers maxmsp object */ + typedef struct + { + t_object x_obj; /* 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_def_ls_amount; // number of loudspeakers + long x_def_ls_dimension; // 2 (horizontal arrays) or 3 (3d setups) + } t_def_ls; +#endif /* VBAP_OBJECT */ + +# ifndef PD +/** Enable/Disable traces */ +static bool _enable_trace = false; +void traces(t_def_ls *x, long n) { _enable_trace = n ? true : false;} +#endif /* ! PD */ + +#endif |