Skip to content

Commit 157f2d8

Browse files
committed
Update channel limits and VBAP 1.032
Adjustments ported from new PD code. LS amounts allocated dynamically. VBAP 1.0.3.2 Remove ls hardcoded limit Signed-off-by: Scott Wilson <[email protected]>
1 parent aff09e4 commit 157f2d8

File tree

3 files changed

+172
-133
lines changed

3 files changed

+172
-133
lines changed

source/VBAPUGens/VBAP.cpp

Lines changed: 120 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -87,19 +87,19 @@ using nova::wrap_argument;
8787

8888
#endif
8989

90-
#define RES_ID 9171 /* resource ID for assistance (we'll add that later) */
91-
#define MAX_LS_SETS 100 /* maximum number of loudspeaker sets (triplets or pairs) allowed */
92-
#define MAX_LS_AMOUNT 55 /* maximum amount of loudspeakers, can be increased */
9390

9491
static InterfaceTable *ft;
9592

93+
static float rad2ang = 360.0 / ( 2.0f * pi );
94+
static float atorad = (2.0f * pi) / 360.0f;
95+
9696
struct VBAP : Unit
9797
{
9898
float x_azi; /* panning direction azimuth */
9999
float x_ele; /* panning direction elevation */
100-
float x_set_inv_matx[MAX_LS_SETS][9]; /* inverse matrice for each loudspeaker set */
101-
float x_set_matx[MAX_LS_SETS][9]; /* matrice for each loudspeaker set */
102-
int x_lsset[MAX_LS_SETS][3]; /* channel numbers of loudspeakers in each LS set */
100+
float* *x_set_inv_matx; /* inverse matrice for each loudspeaker set */
101+
float* *x_set_matx; /* matrice for each loudspeaker set */
102+
int* *x_lsset; /* channel numbers of loudspeakers in each LS set */
103103
int x_lsset_available; /* have loudspeaker sets been defined with define_loudspeakers */
104104
int x_lsset_amount; /* amount of loudspeaker sets */
105105
int x_ls_amount; /* amount of loudspeakers */
@@ -108,7 +108,7 @@ struct VBAP : Unit
108108
float x_spread_base[3]; /* used to create uniform spreading */
109109
float *final_gs;
110110

111-
float m_chanamp[MAX_LS_AMOUNT]; // for smoothing amp changes max channels 55 at the moment
111+
float *m_chanamp;
112112
};
113113

114114
// for circular smoothing
@@ -140,7 +140,6 @@ extern "C"
140140
static void angle_to_cart(float azi, float ele, float res[3])
141141
/* converts angular coordinates to cartesian */
142142
{
143-
float atorad = (2 * 3.1415927 / 360) ;
144143
res[0] = cos((float) azi * atorad) * cos((float) ele * atorad);
145144
res[1] = sin((float) azi * atorad) * cos((float) ele * atorad);
146145
res[2] = sin((float) ele * atorad);
@@ -149,10 +148,6 @@ static void angle_to_cart(float azi, float ele, float res[3])
149148
static void cart_to_angle(float cvec[3], float avec[3])
150149
/* converts cartesian coordinates to angular */
151150
{
152-
// float tmp, tmp2, tmp3, tmp4; /* warning: unused variable */
153-
float atorad = (2 * 3.1415927 / 360) ;
154-
float pi = 3.1415927;
155-
// float power; /* warning: unused variable */
156151
float dist, atan_y_per_x, atan_x_pl_y_per_z;
157152
float azi, ele;
158153

@@ -187,14 +182,13 @@ static void new_spread_dir(VBAP *x, float spreaddir[3], float vscartdir[3], floa
187182
{
188183
float beta,gamma;
189184
float a,b;
190-
float pi = 3.1415927;
191185
float power;
192186

193187
gamma = acos(vscartdir[0] * spread_base[0] +
194188
vscartdir[1] * spread_base[1] +
195189
vscartdir[2] * spread_base[2])/pi*180;
196-
if(fabs(gamma) < 1){
197-
angle_to_cart(x->x_azi+90, 0, spread_base);
190+
if(fabs(gamma) < 1 || fabs(gamma) > 179 || fabs(gamma) < -179){
191+
angle_to_cart(x->x_azi+90.0, 0, spread_base);
198192
gamma = acos(vscartdir[0] * spread_base[0] +
199193
vscartdir[1] * spread_base[1] +
200194
vscartdir[2] * spread_base[2])/pi*180;
@@ -217,7 +211,6 @@ static void new_spread_base(VBAP *x, float spreaddir[3], float vscartdir[3])
217211
/* subroutine for spreading */
218212
{
219213
float d;
220-
float pi = 3.1415927;
221214
float power;
222215

223216
d = cos(x->x_spread/180*pi);
@@ -254,11 +247,9 @@ static void additive_vbap(float *final_gs, float cartdir[3], VBAP *x)
254247
float small_g;
255248
float big_sm_g, gtmp[3];
256249
int winner_set;
257-
// float new_cartdir[3]; /* warning: unused variable */
258-
// float new_angle_dir[3]; /* warning: unused variable */
259250
int dim = x->x_dimension;
260251
int neg_g_am, best_neg_g_am;
261-
float g[3];
252+
float g[3] = { 0, 0, 0 };
262253
int ls[3] = { 0, 0, 0 };
263254

264255
big_sm_g = -100000.0;
@@ -302,25 +293,19 @@ static void additive_vbap(float *final_gs, float cartdir[3], VBAP *x)
302293
if(g[i]<-0.01){
303294
gains_modified=1;
304295
}
305-
306-
if(gains_modified != 1){
307-
if(dim==3)
308-
power=sqrt(g[0]*g[0] + g[1]*g[1] + g[2]*g[2]);
309-
else
310-
power=sqrt(g[0]*g[0] + g[1]*g[1]);
311-
g[0] /= power;
312-
g[1] /= power;
313-
if(dim==3)
314-
g[2] /= power;
315-
316-
final_gs[ls[0]-1] += g[0];
317-
final_gs[ls[1]-1] += g[1];
318-
/* BUG FIX: this was causing negative indices with 2 dimensions so I
319-
* made it only try when using 3 dimensions.
320-
* 2006-08-13 <[email protected]> */
321-
if(dim==3)
322-
final_gs[ls[2]-1] += g[2];
323-
}
296+
297+
// new from PD
298+
if(gains_modified != 1){
299+
power=sqrt(g[0]*g[0] + g[1]*g[1] + g[2]*g[2]);
300+
g[0] /= power;
301+
g[1] /= power;
302+
g[2] /= power;
303+
304+
final_gs[ls[0]-1] += g[0];
305+
final_gs[ls[1]-1] += g[1];
306+
if (dim==3)
307+
final_gs[ls[2]-1] += g[2];
308+
}
324309
}
325310

326311
static void spread_it(VBAP *x, float *final_gs)
@@ -413,23 +398,28 @@ static void vbap(float g[3], int ls[3], VBAP *x)
413398
float new_angle_dir[3];
414399
int dim = x->x_dimension;
415400
int neg_g_am, best_neg_g_am;
416-
417-
/* transfering the azimuth angle to a decent value */
418-
while(x->x_azi > 180)
419-
x->x_azi -= 360;
420-
while(x->x_azi < -179)
421-
x->x_azi += 360;
422-
423-
/* transferring the elevation to a decent value */
424-
if(dim == 3){
425-
while(x->x_ele > 180)
426-
x->x_ele -= 360;
427-
while(x->x_ele < -179)
428-
x->x_ele += 360;
429-
} else
430-
x->x_ele = 0;
431-
432-
401+
402+
// new from PD
403+
// transfering the azimuth angle to a decent value
404+
if(x->x_azi > 360.0 || x->x_azi < -360.0)
405+
x->x_azi = fmod(x->x_azi, 360.0);
406+
if(x->x_azi > 180.0)
407+
x->x_azi -= 360.0;
408+
if(x->x_azi < -179.0)
409+
x->x_azi += 360.0;
410+
411+
412+
// transferring the elevation to a decent value
413+
if(dim == 3){
414+
if(x->x_ele > 360.0 || x->x_ele < -360.0)
415+
x->x_ele = fmod(x->x_ele, 360.0);
416+
if(x->x_ele > 180.0)
417+
x->x_ele -= 360.0;
418+
if(x->x_ele < -179.0)
419+
x->x_ele += 360.0;
420+
} else
421+
x->x_ele = 0.0;
422+
433423
/* go through all defined loudspeaker sets and find the set which
434424
// has all positive values. If such is not found, set with largest
435425
// minimum value is chosen. If at least one of gain factors of one LS set is negative
@@ -472,29 +462,30 @@ static void vbap(float g[3], int ls[3], VBAP *x)
472462
// calculate direction that corresponds to these new
473463
// gain values. This happens when the virtual source is outside of
474464
// all loudspeaker sets. */
475-
476-
if(dim==3){
477-
gains_modified=0;
478-
for(i=0;i<dim;i++)
479-
if(g[i]<-0.01){
480-
g[i]=0.0001;
481-
gains_modified=1;
482-
}
483-
if(gains_modified==1){
484-
new_cartdir[0] = x->x_set_matx[winner_set][0] * g[0]
485-
+ x->x_set_matx[winner_set][1] * g[1]
486-
+ x->x_set_matx[winner_set][2] * g[2];
487-
new_cartdir[1] = x->x_set_matx[winner_set][3] * g[0]
488-
+ x->x_set_matx[winner_set][4] * g[1]
489-
+ x->x_set_matx[winner_set][5] * g[2];
490-
new_cartdir[2] = x->x_set_matx[winner_set][6] * g[0]
491-
+ x->x_set_matx[winner_set][7] * g[1]
492-
+ x->x_set_matx[winner_set][8] * g[2];
493-
cart_to_angle(new_cartdir,new_angle_dir);
494-
x->x_azi = (float) (new_angle_dir[0] + 0.5);
495-
x->x_ele = (float) (new_angle_dir[1] + 0.5);
496-
}
497-
}
465+
466+
gains_modified=0;
467+
for(i=0;i<dim;i++)
468+
if(g[i]<-0.01){
469+
g[i]=0.0001;
470+
gains_modified=1;
471+
}
472+
473+
if(gains_modified==1){
474+
new_cartdir[0] = x->x_set_matx[winner_set][0] * g[0]
475+
+ x->x_set_matx[winner_set][1] * g[1]
476+
+ x->x_set_matx[winner_set][2] * g[2];
477+
new_cartdir[1] = x->x_set_matx[winner_set][3] * g[0]
478+
+ x->x_set_matx[winner_set][4] * g[1]
479+
+ x->x_set_matx[winner_set][5] * g[2];
480+
if (dim == 3) {
481+
new_cartdir[2] = x->x_set_matx[winner_set][6] * g[0]
482+
+ x->x_set_matx[winner_set][7] * g[1]
483+
+ x->x_set_matx[winner_set][8] * g[2];
484+
} else new_cartdir[2] = 0;
485+
cart_to_angle(new_cartdir,new_angle_dir);
486+
x->x_azi = (new_angle_dir[0]);
487+
x->x_ele = (new_angle_dir[1]);
488+
}
498489

499490
power=sqrt(g[0]*g[0] + g[1]*g[1] + g[2]*g[2]);
500491
g[0] /= power;
@@ -605,10 +596,14 @@ static inline_functions void VBAP_next_simd(VBAP *unit, int inNumSamples)
605596
}
606597
#endif
607598

599+
// needs to check that numOutputs and x_ls_amount match!!
608600
static void VBAP_Ctor(VBAP* unit)
609601
{
602+
//printf("VBAP-1.0.3.2\n");
610603
int numOutputs = unit->mNumOutputs, counter = 0, datapointer=0, setpointer=0, i;
611-
604+
605+
unit->m_chanamp = (float*)RTAlloc(unit->mWorld, numOutputs * sizeof(float));
606+
612607
// initialise interpolation levels and outputs
613608
for (int i=0; i<numOutputs; ++i) {
614609
unit->m_chanamp[i] = 0;
@@ -660,6 +655,15 @@ static void VBAP_Ctor(VBAP* unit)
660655
// return;
661656
}
662657

658+
unit->x_set_inv_matx = (float**)RTAlloc(unit->mWorld, counter * sizeof(float*));
659+
unit->x_set_matx = (float**)RTAlloc(unit->mWorld, counter * sizeof(float*));
660+
unit->x_lsset = (int**)RTAlloc(unit->mWorld, counter * sizeof(int*));
661+
662+
for(i=0; i<counter; i++){
663+
unit->x_set_inv_matx[i] = (float*)RTAlloc(unit->mWorld, 9 * sizeof(float));
664+
unit->x_set_matx[i] = (float*)RTAlloc(unit->mWorld, 9 * sizeof(float));
665+
unit->x_lsset[i] = (int*)RTAlloc(unit->mWorld, 3 * sizeof(int));
666+
}
663667
// probably sets should be created with rtalloc
664668
while(counter-- > 0){
665669
for(i=0; i < unit->x_dimension; i++){
@@ -688,23 +692,52 @@ static void VBAP_Ctor(VBAP* unit)
688692
#endif
689693
SETCALC(VBAP_next);
690694

691-
if (unit->x_lsset_available == 1) {
692-
unit->x_spread_base[0] = 0.0;
693-
unit->x_spread_base[1] = 1.0;
694-
unit->x_spread_base[2] = 0.0;
695-
VBAP_next(unit, 1); // calculate initial gain factors && compute initial sample
696-
} else {
697-
ZOUT0(0) = 0;
695+
ZOUT0(0) = ZIN0(0);
696+
unit->x_azi = ZIN0(2);
697+
unit->x_ele = ZIN0(3);
698+
unit->x_spread_base[0] = 0.0;
699+
unit->x_spread_base[1] = 1.0;
700+
unit->x_spread_base[2] = 0.0;
701+
unit->x_spread = ZIN0(4);
702+
703+
// calculate initial gain factors
704+
float g[3];
705+
int ls[3];
706+
float *final_gs = unit->final_gs;
707+
708+
if(unit->x_lsset_available ==1){
709+
vbap(g,ls, unit);
710+
for(i=0;i<unit->x_ls_amount;i++)
711+
final_gs[i]=0.0;
712+
for(i=0;i<unit->x_dimension;i++){
713+
final_gs[ls[i]-1]=g[i];
714+
}
715+
if(unit->x_spread != 0){
716+
spread_it(unit,final_gs);
717+
}
718+
719+
} else {
698720
// if the ls data was bad, just set every gain to 0 and bail
699721
for(i=0;i<unit->x_ls_amount;i++)
700-
unit->final_gs[i]=0.f;
722+
final_gs[i]=0.f;
701723
}
702724
}
703725

704726

705727
static void VBAP_Dtor(VBAP* unit)
706728
{
729+
int counter = unit->x_lsset_amount;
707730
RTFree(unit->mWorld, unit->final_gs);
731+
732+
for(int i=0; i<counter; i++){
733+
RTFree(unit->mWorld, unit->x_set_inv_matx[i]);
734+
RTFree(unit->mWorld, unit->x_set_matx[i]);
735+
RTFree(unit->mWorld, unit->x_lsset[i]);
736+
}
737+
738+
RTFree(unit->mWorld, unit->x_set_inv_matx);
739+
RTFree(unit->mWorld, unit->x_set_matx);
740+
RTFree(unit->mWorld, unit->x_lsset);
708741
}
709742

710743
//////////////////////////////////////////////////////////////////////////////////////////////////

source/VBAPUGens/sc/HelpSource/Classes/VBAP.schelp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ related:: Classes/VBAPSpeakerArray, Classes/CircleRamp
55

66
description::
77
An implementation of Vector Base Amplitude Panning. footnote::
8-
This version of VBAP for SC was ported from the ver. 0.99 PD code by Scott Wilson, as part of the BEASTMulch project. Development was partially funded by the Arts and Humanities Research Council: http://www.ahrc.ac.uk
8+
This version of VBAP for SC was ported from PD code by Scott Wilson, as part of the BEASTMulch project. Development was partially funded by the Arts and Humanities Research Council: http://www.ahrc.ac.uk
99
:: This allows for equal power panning of a source over an arbitrary array of equidistant speakers. Normally this would be a ring, a dome, or partial dome.
1010

1111
VBAP was created by Ville Pulkki. For more information on VBAP see http://www.acoustics.hut.fi/research/cat/vbap/

0 commit comments

Comments
 (0)