aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans-Christoph Steiner <eighthave@users.sourceforge.net>2009-04-23 22:00:49 +0000
committerHans-Christoph Steiner <eighthave@users.sourceforge.net>2009-04-23 22:00:49 +0000
commited884cfd2d33f197c7c4625f05b84e8a9e9597c3 (patch)
tree66f72e7fc07c024c20603fa926e00fd6215444d5
parent2816ecbd4002c8260de586b5fc2e73515010fcbb (diff)
took VBAP v1.0.3 Max/MSP source that I got via email from Ville Pulkki and got it to build for Pd. Now let's test it and see what happens
svn path=/trunk/externals/vbap/; revision=11102
-rw-r--r--define_loudspeakers.c680
-rwxr-xr-xdefine_loudspeakers.h37
-rw-r--r--max2pd.h46
-rw-r--r--vbap.c677
-rw-r--r--vbap.h113
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()
diff --git a/vbap.c b/vbap.c
index a923841..8eba0c1 100644
--- a/vbap.c
+++ b/vbap.c
@@ -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 */
-}
-
diff --git a/vbap.h b/vbap.h
new file mode 100644
index 0000000..dc9858b
--- /dev/null
+++ b/vbap.h
@@ -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