From 33cfd66d36e9ec07b80fc0a4675c5073494ced27 Mon Sep 17 00:00:00 2001 From: zacksettel Date: Sun, 18 May 2014 18:02:49 +0000 Subject: changed vbap to allocate memory dynamically, to eliminate crash-producing memory overwrites when larger speaker configurations were defined. Added CHANGELOG too svn path=/trunk/externals/vbap/; revision=17307 --- CHANGELOG.txt | 5 ++ define_loudspeakers.c | 41 ++++++++++--- vbap.c | 164 ++++++++++++++++++++++++++++++++++++++++++++------ vbap.h | 58 +++++++++++++----- 4 files changed, 225 insertions(+), 43 deletions(-) create mode 100644 CHANGELOG.txt diff --git a/CHANGELOG.txt b/CHANGELOG.txt new file mode 100644 index 0000000..132c66d --- /dev/null +++ b/CHANGELOG.txt @@ -0,0 +1,5 @@ +from version 1.0.3.2 to version 1.0.3.3 + +- changed vbap to allocate memory dynamically, to eliminate crash-producing memory overwrites when larger speaker configurations were defined (e.g. on OSX for speakers > 13 in 3D) +- eliminated a post to the console reporting azimuth updates + diff --git a/define_loudspeakers.c b/define_loudspeakers.c index 5c7e478..2d826c0 100644 --- a/define_loudspeakers.c +++ b/define_loudspeakers.c @@ -14,14 +14,14 @@ See copyright in file with name LICENSE.txt */ // 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_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 */ 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); + logpost(NULL,1, DFLS_VERSION); } # else /* Max */ void main(void) @@ -177,6 +177,11 @@ static void ls_angles_to_cart(t_ls *ls) /* create new instance of object... MUST send it an int even if you do nothing with this int!! */ static void *def_ls_new(t_symbol *s, int ac, Atom *av) { + + + //post("def_ls_new: AC = %d", ac); + + // s is object name (we ignore it) t_def_ls *x = (t_def_ls *)newobject(def_ls_class); @@ -195,6 +200,9 @@ static void *def_ls_new(t_symbol *s, int ac, Atom *av) 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 + + logpost(NULL,3, "vbap_def_ls: %ld-D configuration with %ld speakers", x->x_def_ls_dimension, x->x_def_ls_amount ); + def_ls_bang(x); // calculate and send matrix to vbap } @@ -205,7 +213,9 @@ static void initContent_ls_directions(t_def_ls *x,int ac,Atom*av) 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 */ + + 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) @@ -463,6 +473,9 @@ static void add_ldsp_triplet(int i, int j, int k, t_def_ls *x) trip_ptr = trip_ptr->next; } trip_ptr = (struct t_ls_set*) getbytes (sizeof (struct t_ls_set)); + + //post("add_ldsp_triplet getbytes: %ld", sizeof (struct t_ls_set)); + if(prev == NULL) x->x_ls_set = trip_ptr; else @@ -594,7 +607,10 @@ static void calculate_3x3_matrixes(t_def_ls *x) t_float *invmx; //t_float *ptr; struct t_ls_set *tr_ptr = x->x_ls_set; - int triplet_amount = 0, /*ftable_size,*/i,pointer,list_length=0; + + unsigned long triplet_amount = 0, /*ftable_size,*/i,pointer,list_length=0; // zack + + Atom *at; t_ls *lss = x->x_ls; @@ -613,7 +629,8 @@ static void calculate_3x3_matrixes(t_def_ls *x) tr_ptr = x->x_ls_set; list_length= triplet_amount * 21 + 3; at= (Atom *) getbytes(list_length*sizeof(Atom)); - + + SETLONG(&at[0], x->x_def_ls_dimension); SETLONG(&at[1], x->x_def_ls_amount); pointer=2; @@ -656,11 +673,14 @@ static void calculate_3x3_matrixes(t_def_ls *x) SETFLOAT(&at[pointer], lp2->z); pointer++; SETFLOAT(&at[pointer], lp3->z); pointer++; + + tr_ptr = tr_ptr->next; } + sendLoudspeakerMatrices(x,list_length, at); -// outlet_anything(x->x_outlet0, gensym("loudspeaker-matrices"), list_length, at); - freebytes(at, list_length*sizeof(Atom)); + + freebytes(at, list_length*sizeof(Atom)); } @@ -720,7 +740,8 @@ static void choose_ls_tuplets(t_def_ls *x) // Output list_length= amount * 10 + 2; at= (Atom *) getbytes(list_length*sizeof(Atom)); - + //post("choose_ls_tuplets getbytes: %ld", list_length*sizeof(Atom)); + SETLONG(&at[0], x->x_def_ls_dimension); SETLONG(&at[1], x->x_def_ls_amount); pointer=2; @@ -755,7 +776,9 @@ static void choose_ls_tuplets(t_def_ls *x) pointer++; } } - sendLoudspeakerMatrices(x,list_length, at); + //post("choose_ls_tuplets: before call to sendLoudspeakerMatrices"); + + sendLoudspeakerMatrices(x,list_length, at); //outlet_anything(x->x_outlet0, gensym("loudspeaker-matrices"), list_length, at); freebytes(at, list_length*sizeof(Atom)); } diff --git a/vbap.c b/vbap.c index ecd7ccb..d83fe02 100644 --- a/vbap.c +++ b/vbap.c @@ -20,6 +20,8 @@ static void *vbap_class; static void vect_cross_prod(t_float v1[3], t_float v2[3],t_float v3[3]); static void additive_vbap(t_float *final_gs, t_float cartdir[3], t_vbap *x); static void vbap_bang(t_vbap *x); +static int vbap_getmem(t_vbap *x, int lsSetCount ); +static void vbap_free(t_vbap *x); static void vbap_matrix(t_vbap *x, Symbol *s, int ac, Atom *av); #ifndef PD /* Max */ /* these are for getting data from a cold inlet on Max/MSP, in Pd you use t_floatinlet_new() in new() */ @@ -77,7 +79,7 @@ void vbap_assist(t_vbap *x, void *b, long m, long a, char *s) #ifdef PD void vbap_setup(void) { - vbap_class = class_new(gensym("vbap"), (t_newmethod)vbap_new, 0, (short)sizeof(t_vbap), 0, + vbap_class = class_new(gensym("vbap"), (t_newmethod)vbap_new, (t_method) vbap_free, (short)sizeof(t_vbap), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); class_addbang(vbap_class, (t_method)vbap_bang); @@ -95,7 +97,9 @@ void vbap_setup(void) 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); - logpost(NULL, 4, VBAP_VERSION); + logpost(NULL, 1, VBAP_VERSION); + //post(VBAP_VERSION); + } #else /* MAX */ void main(void) @@ -152,6 +156,14 @@ static void *vbap_new(t_float azi, t_float ele, t_float spread) x->x_outlet1 = outlet_new(&x->x_obj, &s_float); x->x_outlet2 = outlet_new(&x->x_obj, &s_float); x->x_outlet3 = outlet_new(&x->x_obj, &s_float); + + + + // allocate space for the runtime matricies +// if (!vbap_getmem(x, MAX_LS_SETS)) +// return( NULL ); +// + #else /* Max */ t_vbap *x = (t_vbap *)newobject(vbap_class); @@ -167,7 +179,9 @@ static void *vbap_new(t_float azi, t_float ele, t_float spread) x->x_outlet0 = listout(x); #endif /* PD */ - x->x_spread_base[0] = 0.0; + x->x_ls_setCount = 0; // refers to memory dynamically allocated when a define_loudspeakers config is received + + x->x_spread_base[0] = 0.0; x->x_spread_base[1] = 1.0; x->x_spread_base[2] = 0.0; x->x_lsset_available =0; @@ -180,6 +194,85 @@ static void *vbap_new(t_float azi, t_float ele, t_float spread) } +// currently can allocate upto 256K to support up to 44 channels in 3D +// note: to save memory, the required memory for a given configuration could instead, be dynamically allocated by calling this method from the vbap_matrix() method +static int vbap_getmem(t_vbap *x, int lsSetCount ) +{ + +#ifdef PD + + if ( x->x_ls_setCount ) vbap_free(x); + + //was t_float x_set_inv_matx[MAX_LS_SETS][9]; + x->x_set_inv_matx = getbytes( sizeof( t_float* ) * lsSetCount); + + if(!x->x_set_inv_matx) {error("vbap_getmem: can't allocate additional %ld bytes", sizeof( t_float* ) * lsSetCount); return(0);} + + for (int i = 0; i < lsSetCount; i++) + { + x->x_set_inv_matx[i] = getbytes( sizeof(t_float) * MATRIX_DIM ); + if(!x->x_set_inv_matx[i]) {error("vbap_getmem: can't allocate additional %ld bytes", sizeof(t_float) * MATRIX_DIM ); return(0);} + } + + + //was t_float x_set_matx[MAX_LS_SETS][9]; + x->x_set_matx = getbytes( sizeof( t_float* ) * lsSetCount); + + if(!x->x_set_matx) {error("vbap_getmem: can't allocate additional %ld bytes", sizeof( t_float* ) * lsSetCount); return(0);} + + for (int i = 0; i < lsSetCount; i++) + { + x->x_set_matx[i] = getbytes( sizeof(t_float) * MATRIX_DIM ); + if(!x->x_set_matx[i]) {error("vbap_getmem: can't allocate additional %ld bytes", sizeof(t_float) * MATRIX_DIM ); return(0);} + } + + + //was long x_lsset[MAX_LS_SETS][3]; + x->x_lsset = getbytes( sizeof( long * ) * lsSetCount); + + if(!x->x_lsset) {error("vbap_getmem: can't allocate additional %ld bytes", sizeof( long * ) * lsSetCount); return(0);} + + for (int i = 0; i < lsSetCount; i++) + { + x->x_lsset[i] = getbytes( sizeof( long ) * SPEAKER_SET_DIM ); + if(!x->x_lsset[i]) {error("vbap_getmem: can't allocate additional %ld bytes", sizeof(long) * SPEAKER_SET_DIM ); return(0);} + } + + unsigned long memallocd = 2 * ( sizeof(t_float *) * lsSetCount * sizeof(t_float) * MATRIX_DIM) + ( sizeof(long *) * lsSetCount * sizeof(long) * SPEAKER_SET_DIM); + + logpost(NULL, 3, "vbap_new: %ldK bytes allocated for instance", memallocd /1000); + + x->x_ls_setCount = lsSetCount; + +#endif + return(1); + +} + + +// free any allocated memory for instance +static void vbap_free(t_vbap *x) +{ + if (! x->x_ls_setCount) return; + + for (int i = 0; i < x->x_ls_setCount; i++) + { + freebytes( x->x_set_inv_matx[i], (sizeof(t_float) * MATRIX_DIM )); // = getbytes( sizeof(t_float) * MATRIX_DIM ); + freebytes( x->x_set_matx[i], sizeof(t_float) * MATRIX_DIM); + } + + freebytes(x->x_set_inv_matx, (sizeof( t_float* ) * x->x_ls_setCount)); + freebytes(x->x_set_matx, sizeof( t_float* ) * x->x_ls_setCount); + + + for (int i = 0; i < x->x_ls_setCount; i++) + { + freebytes(x->x_lsset[i], sizeof( long ) * SPEAKER_SET_DIM ); + } + + freebytes( x->x_lsset, sizeof( long * ) * x->x_ls_setCount); +} + static void angle_to_cart(t_float azi, t_float ele, t_float res[3]) // converts angular coordinates to cartesian { @@ -327,7 +420,7 @@ static void vbap(t_float g[3], long ls[3], t_vbap *x) } else new_cartdir[2] = 0; cart_to_angle(new_cartdir,new_angle_dir); x->x_azi = (new_angle_dir[0] ); - // post("[vbap] use azimuth %g",x->x_azi ); + //post("[vbap] use azimuth %g",x->x_azi ); x->x_ele = (new_angle_dir[1]); } //} @@ -550,6 +643,7 @@ static void vbap_bang(t_vbap *x) t_float g[3]; long ls[3]; long i; + t_float *final_gs = (t_float *) getbytes(x->x_ls_amount * sizeof(t_float)); if(x->x_lsset_available ==1) @@ -598,8 +692,14 @@ static void vbap_matrix(t_vbap *x, Symbol *s, int ac, Atom *av) { 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; } + 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; } @@ -617,25 +717,40 @@ static void vbap_matrix(t_vbap *x, Symbol *s, int ac, Atom *av) x->x_ls_amount = a; } - + long counter = (ac - 2) / ((x->x_dimension * x->x_dimension*2) + x->x_dimension); - x->x_lsset_amount=counter; + + + + if (counter-1 > MAX_LS_SETS) { error("vbap %s: loudspeaker definitions exceed maximum number of speakers",s->s_name); x->x_lsset_available=0; return; } + + vbap_getmem(x, counter); // PD only: allocate memory (frees any previously allocated memory automatically) + + x->x_lsset_amount=counter; + 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) + + long db_dim = x->x_dimension; + + while(counter-- > 0) { - for(i=0; i < x->x_dimension; i++) + + for(i=0; i < x->x_dimension; i++) { # ifdef PD - if(av[datapointer].a_type == A_FLOAT) + + if(av[datapointer].a_type == A_FLOAT) { x->x_lsset[setpointer][i]=(long)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; } + } + else { error("vbap AA %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) { @@ -644,26 +759,35 @@ static void vbap_matrix(t_vbap *x, Symbol *s, int ac, Atom *av) 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++) + + + for(i=0; i < x->x_dimension*x->x_dimension; i++) { - if(av[datapointer].a_type == A_FLOAT) + + if(av[datapointer].a_type == A_FLOAT) { x->x_set_inv_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; } + else { error("vbap BB %s: param %d is not a float",s->s_name,datapointer); 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; } + else { + error("vbap %s: param %d is not a float",s->s_name,datapointer); x->x_lsset_available=0; + return; + } } - + setpointer++; } if (_enable_trace) post("vbap: Loudspeaker setup configured!"); -} + } diff --git a/vbap.h b/vbap.h index 0429b0d..57146ac 100644 --- a/vbap.h +++ b/vbap.h @@ -10,21 +10,37 @@ #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 +#ifdef PD + #define MAX_LS_SETS 745 // maximum number of loudspeaker sets (triplets or pairs) allowed -- allows for up to 44 speakers in 3D config +//#define MAX_LS_SETS 100 // former maximum value, allowed for up to 13 speakers in 3D config +//#define MAX_LS_SETS 571 // example: for up to 32 speakers in 3D config + +#else // Max + +#define MAX_LS_SETS 100 // maximum number of loudspeaker sets (triplets or pairs) allowed - This can crash when too many speakers are defined + +#endif + +#define MATRIX_DIM 9 // hard-coded matrx dimension for the algorithm +#define SPEAKER_SET_DIM 3 // hard-coded speaker set dimension for the algorithm + +#define MAX_LS_AMOUNT 55 // maximum amount of loudspeakers, can be increased, but see comments next to MAX_LS_SETS above #define MIN_VOL_P_SIDE_LGTH 0.01 -#define VBAP_VERSION "vbap - v1.0.3.2 - 20 Nov 2010 - (c) Ville Pulkki 1999-2006 (Pd port by HCS)" +#define VBAP_VERSION "pdsheefa_vbap - v1.0.3.3 - 15 May 2014 - (c) Ville Pulkki 1999-2006 (Pd port by HCS, updated by ZS)" #define DFLS_VERSION "define_loudspeakers - v1.0.3.2 - 20 Nov 2010 - (c) Ville Pulkki 1999-2006" static t_float rad2ang = 360.0 / ( 2.0f * M_PI ); static t_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) + +//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) \ @@ -61,18 +77,31 @@ typedef struct t_ls_set void *x_outlet1; void *x_outlet2; void *x_outlet3; - void *x_outlet4; - t_float x_set_inv_matx[MAX_LS_SETS][9]; // inverse matrice for each loudspeaker set - t_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 + void *x_outlet4; + 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_ls_amount; // amount of loudspeakers long x_dimension; // 2 or 3 + # ifdef PD + // memory for data sets is now allocated dynamically in each instance + // WAS t_float x_set_inv_matx[MAX_LS_SETS][9]; + t_float **x_set_inv_matx; // inverse matrice for each loudspeaker set + // WAS t_float x_set_matx[MAX_LS_SETS][9]; + t_float **x_set_matx; // matrice for each loudspeaker set + // WAS long x_lsset[MAX_LS_SETS][3]; + long **x_lsset; // channel numbers of loudspeakers in each LS set + t_float x_spread; // speading amount of virtual source (0-100) -# else /* Max */ - long x_spread; // speading amount of virtual source (0-100) + +# else /* Max */ // memory allocation not tested for max, so it is allocated in the struct, as it was before + + t_float x_set_inv_matx[MAX_LS_SETS][9]; // inverse matrice for each loudspeaker set + t_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_spread; // speading amount of virtual source (0-100) double x_gain; // general gain control (0-2) # endif /* PD */ t_float x_spread_base[3]; // used to create uniform spreading @@ -84,6 +113,7 @@ typedef struct t_ls_set 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) + long x_ls_setCount; // the number of Loudspeaker sets used for an instance's current loudspeaker configuration } t_vbap; // define loudspeaker data type... -- cgit v1.2.1