38#define ENABLE_VBAP_DEBUGGING_CODE 0
39#if ENABLE_VBAP_DEBUGGING_CODE
41# define SAVE_PATH "../faces.txt"
43# define SAVE_PATH2 "../vbapGains_compressed.txt"
45# define SAVE_PATH3 "../vbapGains_table.txt"
58 int omitLargeTriangles,
66 int N_points, numOutVertices, numOutFaces;
68 float *out_vertices, *layoutInvMtx;
70 int needDummy[2] = {1, 1};
84 if(needDummy[0] || needDummy[1]){
86 L_d = L+needDummy[0]+needDummy[1];
87 ls_dirs_d_deg =
malloc1d(L_d*2*
sizeof(
float));
88 memcpy(ls_dirs_d_deg, ls_dirs_deg, L*2*
sizeof(
float));
90 ls_dirs_d_deg[i*2+0] = 0.0f;
91 ls_dirs_d_deg[i*2+1] = -90.0f;
95 ls_dirs_d_deg[i*2+0] = 0.0f;
96 ls_dirs_d_deg[i*2+1] = 90.0f;
100 findLsTriplets(ls_dirs_d_deg, L_d, omitLargeTriangles, &out_vertices, &numOutVertices, &out_faces, &numOutFaces);
104 findLsTriplets(ls_dirs_deg, L, omitLargeTriangles, &out_vertices, &numOutVertices, &out_faces, &numOutFaces);
107 findLsTriplets(ls_dirs_deg, L, omitLargeTriangles, &out_vertices, &numOutVertices, &out_faces, &numOutFaces);
108#if ENABLE_VBAP_DEBUGGING_CODE
110 FILE* objfile = fopen(SAVE_PATH,
"wt");
111 fprintf(objfile,
"faces = [\n");
112 for (i = 0; i < numOutFaces; i++) {
113 fprintf(objfile,
" %u, %u, %u;\n",
118 fprintf(objfile,
"];\n\n\n");
119 fprintf(objfile,
"vert = [\n");
120 for (i = 0; i < numOutVertices; i++) {
121 fprintf(objfile,
" %f, %f, %f;\n",
124 out_vertices[3*i+2]);
126 fprintf(objfile,
"];\n\n\n");
132 invertLsMtx3D(out_vertices, out_faces, numOutFaces, &layoutInvMtx);
136 vbap3D(src_dirs_deg, N_points, numOutVertices, out_faces, numOutFaces, spread, layoutInvMtx, gtable);
138 if(needDummy[0] || needDummy[1]){
140 for(i=0; i<N_points; i++)
141 memmove(&(*gtable)[i*L], &(*gtable)[i*numOutVertices], L*
sizeof(
float));
142 (*gtable) = realloc((*gtable), N_points*L*
sizeof(
float));
147 (*N_gtable) = N_points;
148 (*nTriangles) = numOutFaces;
149#if ENABLE_VBAP_DEBUGGING_CODE
151 FILE* objfile2 = fopen(SAVE_PATH3,
"wt");
152 fprintf(objfile2,
"vbap_gtable = [\n");
153 for (i = 0; i < N_points; i++) {
154 for (j = 0; j < L; j++) {
155 fprintf(objfile2,
" %f", (*gtable)[3*L+j] );
157 fprintf(objfile2,
",");
159 fprintf(objfile2,
";\n");
161 fprintf(objfile2,
"];\n\n\n");
177 int omitLargeTriangles,
185 int i, j, N_azi, N_ele, N_points, numOutVertices, numOutFaces;
188 float* azi, *ele, *src_dirs, *out_vertices, *layoutInvMtx;
190 int needDummy[2] = {1, 1};
191 float* ls_dirs_d_deg;
194 N_azi = (int)((360.0f/(
float)az_res_deg) + 1.5f);
195 N_ele = (int)((180.0f/(
float)el_res_deg) + 1.5f);
196 azi =
malloc1d(N_azi *
sizeof(
float));
197 ele =
malloc1d(N_ele *
sizeof(
float));
198 for(fi = -180.0f, i = 0; i<N_azi; fi+=(float)az_res_deg, i++)
200 for(fi = -90.0f, i = 0; i<N_ele; fi+=(float)el_res_deg, i++)
202 src_dirs =
malloc1d((N_azi*N_ele)*2*
sizeof(
float));
203 for(i = 0; i<N_ele; i++){
204 for(j=0; j<N_azi; j++){
205 src_dirs[(i*N_azi + j)*2] = azi[j];
206 src_dirs[(i*N_azi + j)*2+1] = ele[i];
221 if(needDummy[0] || needDummy[1]){
223 L_d = L+needDummy[0]+needDummy[1];
224 ls_dirs_d_deg =
malloc1d(L_d*2*
sizeof(
float));
225 memcpy(ls_dirs_d_deg, ls_dirs_deg, L*2*
sizeof(
float));
227 ls_dirs_d_deg[i*2+0] = 0.0f;
228 ls_dirs_d_deg[i*2+1] = -90.0f;
232 ls_dirs_d_deg[i*2+0] = 0.0f;
233 ls_dirs_d_deg[i*2+1] = 90.0f;
237 findLsTriplets(ls_dirs_d_deg, L_d, omitLargeTriangles, &out_vertices, &numOutVertices, &out_faces, &numOutFaces);
241 findLsTriplets(ls_dirs_deg, L, omitLargeTriangles, &out_vertices, &numOutVertices, &out_faces, &numOutFaces);
244 findLsTriplets(ls_dirs_deg, L, omitLargeTriangles, &out_vertices, &numOutVertices, &out_faces, &numOutFaces);
245#if ENABLE_VBAP_DEBUGGING_CODE
247 FILE* objfile = fopen(SAVE_PATH,
"wt");
248 fprintf(objfile,
"faces = [\n");
249 for (i = 0; i < numOutFaces; i++) {
250 fprintf(objfile,
" %u, %u, %u;\n",
255 fprintf(objfile,
"];\n\n\n");
256 fprintf(objfile,
"vert = [\n");
257 for (i = 0; i < numOutVertices; i++) {
258 fprintf(objfile,
" %f, %f, %f;\n",
261 out_vertices[3*i+2]);
263 fprintf(objfile,
"];\n\n\n");
269 invertLsMtx3D(out_vertices, out_faces, numOutFaces, &layoutInvMtx);
272 N_points = N_azi*N_ele;
273 vbap3D(src_dirs, N_points, numOutVertices, out_faces, numOutFaces, spread, layoutInvMtx, gtable);
277 if(needDummy[0] || needDummy[1]){
278 for(i=0; i<N_points; i++)
279 memmove(&(*gtable)[i*L], &(*gtable)[i*numOutVertices], L*
sizeof(
float));
280 (*gtable) = realloc((*gtable), N_points*L*
sizeof(
float));
285 (*N_gtable) = N_points;
286 (*nTriangles) = numOutFaces;
287#if ENABLE_VBAP_DEBUGGING_CODE
289 FILE* objfile2 = fopen(SAVE_PATH3,
"wt");
290 fprintf(objfile2,
"vbap_gtable = [\n");
291 for (i = 0; i < N_points; i++) {
292 for (j = 0; j < L; j++) {
293 fprintf(objfile2,
" %f", (*gtable)[i*L+j] );
295 fprintf(objfile2,
",");
297 fprintf(objfile2,
";\n");
299 fprintf(objfile2,
"];\n\n\n");
317 float* vbap_gtableComp,
326 memset(vbap_gtableComp, 0, nTable*3*
sizeof(
float));
327 memset(vbap_gtableIdx, 0, nTable*3*
sizeof(
int));
330 for(nt=0; nt<nTable; nt++){
332 for(i=0, j=0; i<nDirs; i++){
333 if(vbap_gtable[nt*nDirs+i]>0.0000001f){
334 gains_nt[j] = vbap_gtable[nt*nDirs+i];
335 gains_sum += gains_nt[j];
342 vbap_gtableComp[nt*3+i] =
SAF_MAX(gains_nt[i]/gains_sum, 0.0f);
343 vbap_gtableIdx[nt*3+i] = idx_nt[i];
346#if ENABLE_VBAP_DEBUGGING_CODE
348 FILE* objfile = fopen(SAVE_PATH2,
"wt");
349 fprintf(objfile,
"vbap_gtableComp = [\n");
350 for (i = 0; i < nTable; i++) {
351 fprintf(objfile,
" %f, %f, %f;\n",
352 vbap_gtableComp[3*i+0],
353 vbap_gtableComp[3*i+1],
354 vbap_gtableComp[3*i+2]);
356 fprintf(objfile,
"];\n\n\n");
357 fprintf(objfile,
"vbap_gtableIdx = [\n");
358 for (i = 0; i < nTable; i++) {
359 fprintf(objfile,
" %u, %u, %u;\n",
360 vbap_gtableIdx[3*i+0],
361 vbap_gtableIdx[3*i+1],
362 vbap_gtableIdx[3*i+2]);
364 fprintf(objfile,
"];\n\n\n");
379 gains_sum =
calloc1d(nTable,
sizeof(
float));
380 for(i=0; i<nTable; i++)
381 for(j=0; j<nDirs; j++)
382 gains_sum[i] += vbap_gtable[i*nDirs+j];
383 for(i=0; i<nTable; i++)
384 for(j=0; j<nDirs; j++)
385 vbap_gtable[i*nDirs+j] /= gains_sum[i];
401 int i, N_points, numOutPairs;
403 float *layoutInvMtx, *ls_vertices;
406 findLsPairs(ls_dirs_deg, L, &out_pairs, &numOutPairs);
407 ls_vertices =
malloc1d(L*2*
sizeof(
float));
409 ls_vertices[i*2+0] = cosf(ls_dirs_deg[i*2]*
SAF_PI/180.0f);
410 ls_vertices[i*2+1] = sinf(ls_dirs_deg[i*2]*
SAF_PI/180.0f);
415 invertLsMtx2D(ls_vertices, out_pairs, numOutPairs, &layoutInvMtx);
419 vbap2D(src_dirs_deg, N_points, L, out_pairs, numOutPairs, layoutInvMtx, gtable);
420 (*nPairs) = numOutPairs;
421 (*N_gtable) = N_points;
438 int i, N_azi, N_points, numOutPairs;
441 float *src_dirs, *layoutInvMtx, *ls_vertices;
444 N_azi = (int)((360.0f/(
float)az_res_deg) + 1.5f);
445 src_dirs =
malloc1d(N_azi *
sizeof(
float));
446 for(fi = -180.0f, i = 0; i<N_azi; fi+=(float)az_res_deg, i++)
449 findLsPairs(ls_dirs_deg, L, &out_pairs, &numOutPairs);
450 ls_vertices =
malloc1d(L*2*
sizeof(
float));
452 ls_vertices[i*2+0] = cosf(ls_dirs_deg[i*2]*
SAF_PI/180.0f);
453 ls_vertices[i*2+1] = sinf(ls_dirs_deg[i*2]*
SAF_PI/180.0f);
458 invertLsMtx2D(ls_vertices, out_pairs, numOutPairs, &layoutInvMtx);
462 vbap2D(src_dirs, N_points, L, out_pairs, numOutPairs, layoutInvMtx, gtable);
463 (*nPairs) = numOutPairs;
464 (*N_gtable) = N_points;
488 for(i=0; i<nFreq; i++){
489 p0 = 1.5f - 0.5f * cosf(4.7f*tanhf(a1*freq[i])) *
SAF_MAX(0.0f, 1.0f-a2*freq[i]);
490 pValues[i] = (p0-2.0f)*sqrtf(DTT)+2.0f;
503 int omitLargeTriangles,
504 float** out_vertices,
510 int i, j, numValidFaces, nFaces;
511 int* validFacesID, *valid_faces, *valid_faces2, *faces;
512 float dotcc, aperture_lim;
513 float vecs[3][3], cvec[3], centroid[3], a[3], b[3], abc[3];
520 (*numOutVertices) = L;
521 (*out_vertices) = (
float*)
malloc1d(L*3*
sizeof(
float));
522 for ( i = 0; i < L; i++) {
523 (*out_vertices)[i*3+2] = (float)((CH_FLOAT)sin((
double)ls_dirs_deg[i*2+1]*
SAF_PId/180.0));
524 rcoselev = (CH_FLOAT)cos((
double)ls_dirs_deg[i*2+1]*
SAF_PId/180.0);
525 (*out_vertices)[i*3+0] = (float)(rcoselev * (CH_FLOAT)cos((
double)ls_dirs_deg[i*2+0]*
SAF_PId/180.0));
526 (*out_vertices)[i*3+1] = (float)(rcoselev * (CH_FLOAT)sin((
double)ls_dirs_deg[i*2+0]*
SAF_PId/180.0));
527 vertices[i].x = (*out_vertices)[i*3+0];
528 vertices[i].y = (*out_vertices)[i*3+1];
529 vertices[i].z = (*out_vertices)[i*3+2];
535 saf_print_error(
"Failed to compute the Convex Hull of the specified vertices.");
539 int k, minIntVal, minIdx, nFaces;
540 int tmp3[3], circface[3];
543 for(i=0; i<nFaces; i++){
547 if (faces[i*3+j] < minIntVal){
548 minIntVal = faces[i*3+j];
552 for(j=minIdx, k=0; j<minIdx+3; j++, k++)
553 circface[k] = faces[i*3+(j % 3)];
555 faces[i*3+j] = circface[j];
559 for (j=0; j<nFaces - 1; j++) {
560 for (i=0; i<nFaces - 1; i++) {
561 if (faces[(i+1)*3+0] < faces[i*3+0]) {
563 tmp3[k] = faces[i*3+k];
564 faces[i*3+k] = faces[(i+1)*3+k];
565 faces[(i+1)*3+k] = tmp3[k];
572 for (j=0; j<nFaces - 1; j++) {
573 for (i=0; i<nFaces - 1; i++) {
574 if ( (faces[(i+1)*3+1] < faces[i*3+1]) && (faces[(i+1)*3+0] == faces[i*3+0]) ) {
576 tmp3[k] = faces[i*3+k];
577 faces[i*3+k] = faces[(i+1)*3+k];
578 faces[(i+1)*3+k] = tmp3[k];
587 validFacesID =
malloc1d(nFaces*
sizeof(
int));
588 for(i=0; i<nFaces; i++){
590 vecs[0][j] = (*out_vertices)[faces[i*3+0]*3+j];
591 vecs[1][j] = (*out_vertices)[faces[i*3+1]*3+j];
592 vecs[2][j] = (*out_vertices)[faces[i*3+2]*3+j];
595 a[j] = vecs[1][j]-vecs[0][j];
596 b[j] = vecs[2][j]-vecs[1][j];
600 centroid[j] = (vecs[0][j] + vecs[1][j] + vecs[2][j])/3.0f;
601 dotcc = cvec[0] * centroid[0] + cvec[1] * centroid[1] + cvec[2] * centroid[2];
610 valid_faces =
malloc1d(numValidFaces*3*
sizeof(
int));
611 for(i=0, j=0; i<nFaces; i++){
612 if(validFacesID[i]==1){
613 valid_faces[j*3+0] = faces[i*3+0];
614 valid_faces[j*3+1] = faces[i*3+1];
615 valid_faces[j*3+2] = faces[i*3+2];
623 if(omitLargeTriangles) {
625 nFaces = numValidFaces;
627 validFacesID =
malloc1d(nFaces*
sizeof(
int));
628 for(i=0; i<nFaces; i++){
630 vecs[0][j] = (*out_vertices)[valid_faces[i*3+0]*3+j];
631 vecs[1][j] = (*out_vertices)[valid_faces[i*3+1]*3+j];
632 vecs[2][j] = (*out_vertices)[valid_faces[i*3+2]*3+j];
634 dotcc = vecs[0][0] * vecs[1][0] + vecs[0][1] * vecs[1][1] + vecs[0][2] * vecs[1][2];
635 abc[0] = acosf(dotcc);
636 dotcc = vecs[1][0] * vecs[2][0] + vecs[1][1] * vecs[2][1] + vecs[1][2] * vecs[2][2];
637 abc[1] = acosf(dotcc);
638 dotcc = vecs[2][0] * vecs[0][0] + vecs[2][1] * vecs[0][1] + vecs[2][2] * vecs[0][2];
639 abc[2] = acosf(dotcc);
640 if(abc[0]<aperture_lim && abc[1]<aperture_lim && abc[2]<aperture_lim){
648 valid_faces2 =
malloc1d(numValidFaces*3*
sizeof(
int));
649 for(i=0, j=0; i<nFaces; i++){
650 if(validFacesID[i]==1){
651 valid_faces2[j*3+0] = valid_faces[i*3+0];
652 valid_faces2[j*3+1] = valid_faces[i*3+1];
653 valid_faces2[j*3+2] = valid_faces[i*3+2];
661 (*numOutFaces) = numValidFaces;
662 (*out_faces) = (
int*)
malloc1d(numValidFaces*3*
sizeof(
int));
663 if(omitLargeTriangles)
664 memcpy((*out_faces), valid_faces2, numValidFaces*3*
sizeof(
int));
666 memcpy((*out_faces), valid_faces, numValidFaces*3*
sizeof(
int));
672 if(omitLargeTriangles)
690 (*layoutInvMtx) =
malloc1d(N_group * 9 *
sizeof(
float));
692 for(n=0; n<N_group; n++){
696 tempGroup[j*3+i] = U_spkr[ls_groups[n*3+i]*3 + j];
702 cblas_scopy(9, tempInv, 1, (*layoutInvMtx) + n*9, 1);
718 float theta, sin_theta, cos_theta, scale, spread_rad, ring_rad, U_spread_norm;
719 float u[3], u_x_u[3][3], u_x[3][3], R_theta[3][3], uu2[3], spreadbase_ns[3];
723 u[0] = cosf(src_elev_rad) * cosf(src_azi_rad);
724 u[1] = cosf(src_elev_rad) * sinf(src_azi_rad);
725 u[2] = sinf(src_elev_rad);
726 u_x_u[0][0] = powf(u[0],2.0f); u_x_u[0][1] = u[0]*u[1]; u_x_u[0][2] = u[0]*u[2];
727 u_x_u[1][0] = u[0]*u[1]; u_x_u[1][1] = powf(u[1],2.0f); u_x_u[1][2] = u[1]*u[2];
728 u_x_u[2][0] = u[0]*u[2]; u_x_u[2][1] = u[1]*u[2]; u_x_u[2][2] = powf(u[2],2.0f);
729 u_x[0][0] = 0.0f; u_x[0][1] = -u[2]; u_x[0][2] = u[1];
730 u_x[1][0] = u[2]; u_x[1][1] = 0.0f; u_x[1][2] = -u[0];
731 u_x[2][0] = -u[1]; u_x[2][1] = u[0]; u_x[2][2] = 0.0f;
732 theta = 2.0f*
SAF_PI/(float)num_src;
733 sin_theta = sinf(theta);
734 cos_theta = cosf(theta);
737 R_theta[i][j] = sin_theta*u_x[i][j] + (1.0f-cos_theta)*u_x_u[i][j] + (i==j ? cos_theta : 0.0f);
740 spreadbase =
calloc1d(num_src*3,
sizeof(
float));
741 if ((src_elev_rad >
SAF_PI/2.0f-0.01f ) || (src_elev_rad<-(
SAF_PI/2.0f-0.01f)))
742 spreadbase[0] = 1.0f;
744 const float u2[3] = {0.0f, 0.0f, 1.0f};
745 ccross(u, (
float*)u2, uu2);
748 scale += powf(uu2[i],2.0f);
749 scale = sqrtf(scale);
751 spreadbase[i] = uu2[i]/scale;
755 for (ns = 1; ns<num_src; ns++){
757 spreadbase_ns[i] = spreadbase[(ns-1)*3+i];
758 cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 1, 3, 1.0f,
759 (
const float*)R_theta, 3,
760 spreadbase_ns, 1, 0.0f,
761 &spreadbase[ns*3], 1);
765 spread_rad = (spread/2.0f)*
SAF_PI/180.0f;
766 ring_rad = spread_rad/(float)num_rings_3d;
767 memset(U_spread, 0, num_rings_3d*num_src*3*
sizeof(
float));
768 for(nr=0; nr<num_rings_3d; nr++)
769 for (ns = 0; ns<num_src; ns++)
771 U_spread[(nr*num_src + ns)*3 + i] = u[i] + spreadbase[ns*3+i]*tanf(ring_rad*(
float)(nr+1));
774 U_spread_norm = sqrtf(powf(U_spread[0],2.0f) + powf(U_spread[1],2.0f) + powf(U_spread[2],2.0f));
775 for(i=0; i<num_rings_3d*num_src*3; i++)
776 U_spread[i] /= U_spread_norm;
780 U_spread[(num_rings_3d*num_src)*3 + i] = u[i];
799 float azi_rad, elev_rad, min_val, g_tmp_rms, gains_rms;
800 float u[3], g_tmp[3], ls_invMtx_s[3];
803 (*GainMtx) =
malloc1d(src_num*ls_num*
sizeof(
float));
804 gains =
malloc1d(ls_num*
sizeof(
float));
808 const int nSpreadSrcs = 8;
809 const int nRings = 1;
811 U_spread =
malloc1d((nRings*nSpreadSrcs+1)*3*
sizeof(
float));
812 for(ns=0; ns<src_num; ns++){
813 azi_rad = src_dirs[ns*2+0]*
SAF_PI/180.0f;
814 elev_rad = src_dirs[ns*2+1]*
SAF_PI/180.0f;
816 memset(gains, 0, ls_num*
sizeof(
float));
817 for(nspr=0; nspr<(nRings*nSpreadSrcs+1); nspr++){
818 u[0] = U_spread[nspr*3+0];
819 u[1] = U_spread[nspr*3+1];
820 u[2] = U_spread[nspr*3+2];
821 for(i=0; i<nFaces; i++){
823 ls_invMtx_s[j] = layoutInvMtx[i*9+j];
826 ls_invMtx_s[j] = layoutInvMtx[i*9+j+3];
829 ls_invMtx_s[j] = layoutInvMtx[i*9+j+6];
834 min_val =
SAF_MIN(min_val, g_tmp[j]);
835 g_tmp_rms += powf(g_tmp[j], 2.0f);
837 g_tmp_rms = sqrtf(g_tmp_rms);
840 gains[ls_groups[i*3+j]] += g_tmp[j]/g_tmp_rms;
845 for(i=0; i<ls_num; i++)
846 gains_rms += powf(gains[i], 2.0f);
847 gains_rms = sqrtf(gains_rms);
848 for(i=0; i<ls_num; i++)
849 (*GainMtx)[ns*ls_num+i] =
SAF_MAX(gains[i]/gains_rms, 0.0f);
856 for(ns=0; ns<src_num; ns++){
857 azi_rad = src_dirs[ns*2+0]*
SAF_PI/180.0f;
858 elev_rad = src_dirs[ns*2+1]*
SAF_PI/180.0f;
859 u[0] = cosf(azi_rad)*cosf(elev_rad);
860 u[1] = sinf(azi_rad)*cosf(elev_rad);
861 u[2] = sinf(elev_rad);
862 memset(gains, 0, ls_num*
sizeof(
float));
863 for(i=0; i<nFaces; i++){
865 ls_invMtx_s[j] = layoutInvMtx[i*9+j];
868 ls_invMtx_s[j] = layoutInvMtx[i*9+j+3];
871 ls_invMtx_s[j] = layoutInvMtx[i*9+j+6];
876 min_val =
SAF_MIN(min_val, g_tmp[j]);
877 g_tmp_rms += powf(g_tmp[j], 2.0f);
879 g_tmp_rms = sqrtf(g_tmp_rms);
882 gains[ls_groups[i*3+j]] = g_tmp[j]/g_tmp_rms;
887 for(i=0; i<ls_num; i++)
888 gains_rms += powf(gains[i], 2.0f);
889 gains_rms = sqrtf(gains_rms);
890 for(i=0; i<ls_num; i++)
891 (*GainMtx)[ns*ls_num+i] =
SAF_MAX(gains[i]/gains_rms, 0.0f);
907 float* ls_dirs_deg_tmp;
910 ls_dirs_deg_tmp =
malloc1d(L*
sizeof(
float));
911 idx_sorted =
malloc1d(L*
sizeof(
int));
913 ls_dirs_deg_tmp[n] = ls_dirs_deg[n*2];
916 sortf(ls_dirs_deg_tmp, NULL, idx_sorted, L, 0);
917 idx_sorted = realloc(idx_sorted, (L+1)*
sizeof(
int));
918 idx_sorted[L] = idx_sorted[0];
919 (*out_pairs) =
malloc1d(L*2*
sizeof(
int));
921 (*out_pairs)[n*2] = idx_sorted[n];
922 (*out_pairs)[n*2+1] = idx_sorted[n+1];
926 free(ls_dirs_deg_tmp);
944 (*layoutInvMtx) =
malloc1d(N_pairs * 4 *
sizeof(
float));
946 for(n=0; n<N_pairs; n++){
950 tempGroup[j*2+i] = U_spkr[ls_pairs[n*2+i]*2 + j];
956 cblas_scopy(4, tempInv, 1, (*layoutInvMtx) + n*4, 1);
974 float azi_rad, min_val, g_tmp_rms, gains_rms;
975 float u[2], g_tmp[2], ls_invMtx_s[2];
978 (*GainMtx) =
malloc1d(src_num*ls_num*
sizeof(
float));
979 gains =
malloc1d(ls_num*
sizeof(
float));
980 for(ns=0; ns<src_num; ns++){
981 azi_rad = src_dirs[ns]*
SAF_PI/180.0f;
982 u[0] = cosf(azi_rad);
983 u[1] = sinf(azi_rad);
984 memset(gains, 0, ls_num*
sizeof(
float));
985 for(i=0; i<N_pairs; i++){
987 ls_invMtx_s[j] = layoutInvMtx[i*4+j];
988 cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 1, 1, 2, 1.0,
993 ls_invMtx_s[j] = layoutInvMtx[i*4+j+2];
994 cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 1, 1, 2, 1.0,
1001 min_val =
SAF_MIN(min_val, g_tmp[j]);
1002 g_tmp_rms += powf(g_tmp[j], 2.0f);
1004 g_tmp_rms = sqrtf(g_tmp_rms);
1007 gains[ls_pairs[i*2+j]] = g_tmp[j]/g_tmp_rms;
1011 for(i=0; i<ls_num; i++)
1012 gains_rms += powf(gains[i], 2.0f);
1013 gains_rms = sqrtf(gains_rms);
1014 for(i=0; i<ls_num; i++)
1015 (*GainMtx)[ns*ls_num+i] =
SAF_MAX(gains[i]/gains_rms, 0.0f);
void convhull_3d_build(ch_vertex *const in_vertices, const int nVert, int **out_faces, CH_FLOAT **out_cf, CH_FLOAT **out_df, int *nOut_faces)
Builds the 3-D convexhull using the quickhull algorithm [1].
#define saf_print_error(message)
Macro to print a error message along with the filename and line number.
#define SAF_PI
pi constant (single precision)
void sortf(float *in_vec, float *out_vec, int *new_idices, int len, int descendFLAG)
Sort a vector of floating-point values into ascending/decending order (optionally returning the new i...
#define SAF_MAX(a, b)
Returns the maximum of the two values.
#define SAF_PId
pi constant (double precision)
void utility_sinv_create(void **const phWork, int maxN)
(Optional) Pre-allocate the working struct used by utility_sinv()
void utility_sinv(void *const hWork, float *A, float *B, const int N)
Matrix inversion: single precision, i.e.
#define SAF_MIN(a, b)
Returns the minimum of the two values.
void utility_svvdot(const float *a, const float *b, const int len, float *c)
Single-precision, vector-vector dot product, i.e.
void utility_sinv_destroy(void **const phWork)
De-allocate the working struct used by utility_sinv()
void findLsTriplets(float *ls_dirs_deg, int L, int omitLargeTriangles, float **out_vertices, int *numOutVertices, int **out_faces, int *numOutFaces)
Computes the 3D convex-hull of a spherical grid of loudspeaker directions.
void vbap2D(float *src_dirs, int src_num, int ls_num, int *ls_pairs, int N_pairs, float *layoutInvMtx, float **GainMtx)
Calculates 2D VBAP gains for pre-calculated loudspeaker pairs and predefined source positions.
void invertLsMtx3D(float *U_spkr, int *ls_groups, int N_group, float **layoutInvMtx)
Inverts a 3x3 loudspeaker matrix.
void getSpreadSrcDirs3D(float src_azi_rad, float src_elev_rad, float spread, int num_src, int num_rings_3d, float *U_spread)
Computes a set of points which surround the source direction given a specific degree of spread.
void findLsPairs(float *ls_dirs_deg, int L, int **out_pairs, int *numOutPairs)
Calculates loudspeaker pairs for a circular grid of loudspeaker directions.
void generateVBAPgainTable3D(float *ls_dirs_deg, int L, int az_res_deg, int el_res_deg, int omitLargeTriangles, int enableDummies, float spread, float **gtable, int *N_gtable, int *nTriangles)
Generates a 3-D VBAP gain table based on specified loudspeaker directions, with optional spreading [2...
void generateVBAPgainTable3D_srcs(float *src_dirs_deg, int S, float *ls_dirs_deg, int L, int omitLargeTriangles, int enableDummies, float spread, float **gtable, int *N_gtable, int *nTriangles)
Generates a 3-D VBAP [1] gain table based on specified source and loudspeaker directions,...
void VBAPgainTable2InterpTable(float *vbap_gtable, int nTable, int nDirs)
Renormalises a VBAP gain table (in-place) so it may be utilised for interpolation of data (for exampl...
void generateVBAPgainTable2D_srcs(float *src_dirs_deg, int S, float *ls_dirs_deg, int L, float **gtable, int *N_gtable, int *nPairs)
Generates a 2-D VBAP gain table based on specified source and loudspeaker directions.
void generateVBAPgainTable2D(float *ls_dirs_deg, int L, int az_res_deg, float **gtable, int *N_gtable, int *nPairs)
Generates a 2-D VBAP gain table based on specified loudspeaker directions.
void vbap3D(float *src_dirs, int src_num, int ls_num, int *ls_groups, int nFaces, float spread, float *layoutInvMtx, float **GainMtx)
Calculates 3D VBAP gains given pre-computed loudspeaker triangles for each source direction.
void invertLsMtx2D(float *U_spkr, int *ls_pairs, int N_pairs, float **layoutInvMtx)
Inverts a 2x2 loudspeaker matrix.
void compressVBAPgainTable3D(float *vbap_gtable, int nTable, int nDirs, float *vbap_gtableComp, int *vbap_gtableIdx)
Compresses a VBAP gain table to use less memory and CPU (by removing the elements which are just zero...
void getPvalues(float DTT, float *freq, int nFreq, float *pValues)
Calculates the frequency dependent pValues, which can be applied to ENERGY normalised VBAP gains,...
void * malloc1d(size_t dim1_data_size)
1-D malloc (same as malloc, but with error checking)
void * calloc1d(size_t dim1, size_t data_size)
1-D calloc (same as calloc, but with error checking)
Main header for the VBAP/MDAP module (SAF_VBAP_MODULE)
void ccross(float a[3], float b[3], float c[3])
Cross product between two 3-element floating point vectors.
Internal header for the VBAP/MDAP module (SAF_VBAP_MODULE)
#define APERTURE_LIMIT_DEG
if omitLargeTriangles==1, triangles with an aperture larger than this are discarded
#define ADD_DUMMY_LIMIT
In degrees, if no ls_dirs have elevation +/- this value, dummies are placed at +/- 90 elevation.
vertex structure, used by convhull_3d