51 float* Y_ls, *U, *V, *U_tr, *V_tr;
57 Y_ls =
malloc1d(nSH*nLS*
sizeof(
float));
60 getRSH(order, ls_dirs_deg, nLS, Y_ls);
61 cblas_sscal(nLS*nSH, scale, Y_ls, 1);
67 U_tr =
malloc1d(nSH*nLS*
sizeof(
float));
70 U_tr[i*nLS+j] = U[i*nSH+j];
71 cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasTrans, nLS, nSH, nLS, 1.0f,
79 V_tr =
malloc1d(nLS*nSH*
sizeof(
float));
82 V_tr[i*nSH+j] = V[i*nLS+j];
83 cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasTrans, nLS, nSH, nSH, 1.0f,
91 scale = sqrtf(4.0f*
SAF_PI/(
float)nLS);
108 int nDirs_td, N_gtable, nGroups, nSH;
110 float* Y_td, *G_td, *t_dirs;
142 Y_td =
malloc1d(nSH*nDirs_td*
sizeof(
float));
143 getRSH(order, t_dirs, nDirs_td, Y_td);
144 cblas_sscal(nDirs_td*nSH, scale, Y_td, 1);
147 cblas_sgemm(CblasRowMajor, CblasTrans, CblasTrans, nLS, nSH, nDirs_td, 1.0f,
149 Y_td, nDirs_td, 0.0f,
151 cblas_sscal(nLS*nSH, (4.0f*
SAF_PI)/(
float)nDirs_td, decMtx, 1);
164 float_complex* hrtfs,
165 float* hrtf_dirs_deg,
170 float_complex* decMtx
175 float_complex* W, *Y_na, *Yna_W, *Yna_W_Yna, *Yna_W_H, *B;
176 const float_complex calpha = cmplxf(1.0f, 0.0f), cbeta = cmplxf(0.0f, 0.0f);
181 Y_tmp =
malloc1d(nSH*N_dirs*
sizeof(
float));
182 Y_na =
malloc1d(nSH*N_dirs*
sizeof(float_complex));
183 B =
malloc1d(nSH * 2 *
sizeof(float_complex));
184 getRSH(order, hrtf_dirs_deg, N_dirs, Y_tmp);
185 for(i=0; i<nSH*N_dirs; i++)
186 Y_na[i] = cmplxf(Y_tmp[i], 0.0f);
190 W =
calloc1d(N_dirs*N_dirs,
sizeof(float_complex));
192 for(i=0; i<N_dirs; i++)
193 W[i*N_dirs+i] = cmplxf(weights[i], 0.0f);
195 for(i=0; i<N_dirs; i++)
196 W[i*N_dirs+i] = cmplxf(1.0f/(
float)N_dirs, 0.0f);
199 Yna_W =
malloc1d(nSH * N_dirs*
sizeof(float_complex));
200 Yna_W_Yna =
malloc1d(nSH * nSH *
sizeof(float_complex));
201 Yna_W_H =
malloc1d(nSH * 2 *
sizeof(float_complex));
202 cblas_cgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, nSH, N_dirs, N_dirs, &calpha,
206 cblas_cgemm(CblasRowMajor, CblasNoTrans, CblasTrans, nSH, nSH, N_dirs, &calpha,
208 Y_na, N_dirs, &cbeta,
210 for(band=0; band<N_bands; band++){
211 cblas_cgemm(CblasRowMajor, CblasNoTrans, CblasConjTrans, nSH, 2, N_dirs, &calpha,
213 &hrtfs[band*2*N_dirs], N_dirs, &cbeta,
218 decMtx[band*2*nSH + j*nSH + i] = conjf(B[i*2+j]);
232 float_complex* hrtfs,
233 float* hrtf_dirs_deg,
238 float_complex* decMtx
244 float_complex* W, *Y_na, *Yna_W, *Yna_W_Yna, *Yna_W_H, *B_ls, *hrtfs_ls, *H_W;
245 float_complex C_ref[2][2], C_ls[2][2];
246 const float_complex calpha = cmplxf(1.0f, 0.0f), cbeta = cmplxf(0.0f, 0.0f);
251 W =
calloc1d(N_dirs*N_dirs,
sizeof(float_complex));
253 for(i=0; i<N_dirs; i++)
254 W[i*N_dirs+i] = cmplxf(weights[i], 0.0f);
256 for(i=0; i<N_dirs; i++)
257 W[i*N_dirs+i] = cmplxf(1.0f/(
float)N_dirs, 0.0f);
260 Y_tmp =
malloc1d(nSH*N_dirs*
sizeof(
float));
261 Y_na =
malloc1d(nSH*N_dirs*
sizeof(float_complex));
262 getRSH(order, hrtf_dirs_deg, N_dirs, Y_tmp);
263 for(i=0; i<nSH*N_dirs; i++)
264 Y_na[i] = cmplxf(Y_tmp[i], 0.0f);
268 Yna_W =
malloc1d(nSH * N_dirs*
sizeof(float_complex));
269 Yna_W_Yna =
malloc1d(nSH * nSH *
sizeof(float_complex));
270 Yna_W_H =
malloc1d(nSH * 2 *
sizeof(float_complex));
271 B_ls =
malloc1d(nSH * 2 *
sizeof(float_complex));
272 hrtfs_ls =
malloc1d(2*N_dirs*
sizeof(float_complex));
273 H_W =
malloc1d(2*N_dirs*
sizeof(float_complex));
274 cblas_cgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, nSH, N_dirs, N_dirs, &calpha,
278 cblas_cgemm(CblasRowMajor, CblasNoTrans, CblasTrans, nSH, nSH, N_dirs, &calpha,
280 Y_na, N_dirs, &cbeta,
282 for(band=0; band<N_bands; band++){
284 cblas_cgemm(CblasRowMajor, CblasNoTrans, CblasConjTrans, nSH, 2, N_dirs, &calpha,
286 &hrtfs[band*2*N_dirs], N_dirs, &cbeta,
289 cblas_cgemm(CblasRowMajor, CblasConjTrans, CblasNoTrans, 2, N_dirs, nSH, &calpha,
291 Y_na, N_dirs, &cbeta,
295 cblas_cgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 2, N_dirs, N_dirs, &calpha,
296 &hrtfs[band*2*N_dirs], N_dirs,
299 cblas_cgemm(CblasRowMajor, CblasNoTrans, CblasConjTrans, 2, 2, N_dirs, &calpha,
301 &hrtfs[band*2*N_dirs], N_dirs, &cbeta,
302 (float_complex*)C_ref, 2);
303 cblas_cgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 2, N_dirs, N_dirs, &calpha,
307 cblas_cgemm(CblasRowMajor, CblasNoTrans, CblasConjTrans, 2, 2, N_dirs, &calpha,
309 hrtfs_ls, N_dirs, &cbeta,
310 (float_complex*)C_ls, 2);
313 Gh = (sqrtf(crealf(C_ref[0][0])/(crealf(C_ls[0][0])+2.23e-7f)) +
314 sqrtf(crealf(C_ref[1][1])/(crealf(C_ls[1][1])+2.23e-7f))) /2.0f;
319 decMtx[band*2*nSH + j*nSH + i] = crmulf(conjf(B_ls[i*2+j]), Gh);
334 float_complex* hrtfs,
335 float* hrtf_dirs_deg,
340 float_complex* decMtx
343 int band, i, j, nSH, nSH_nh, Nh_max, Nh, K_td;
344 float* hrtf_dirs_rad, *W, *cnd_num, *Y_nh, *Y_na, *tdirs_deg, *Y_td, *Ynh_Ytd, *tmp;
345 float_complex* Y_td_cmplx, *W_Ynh_Ytd, *hrtfs_td, *B;
346 const float_complex calpha = cmplxf(1.0f, 0.0f), cbeta = cmplxf(0.0f, 0.0f);
351 W =
calloc1d(N_dirs*N_dirs,
sizeof(
float));
353 for(i=0; i<N_dirs; i++)
354 W[i*N_dirs+i] = weights[i]/(4.0f*
SAF_PI);
356 for(i=0; i<N_dirs; i++)
357 W[i*N_dirs+i] = 1.0f/(
float)N_dirs;
360 Nh_max =
SAF_MIN((
int)(sqrtf((
float)N_dirs)-1.0f), 20);
361 hrtf_dirs_rad =
malloc1d(N_dirs*2*
sizeof(
float));
362 cnd_num =
malloc1d((Nh_max+1)*
sizeof(
float));
363 for(i=0; i<N_dirs; i++){
364 hrtf_dirs_rad[i*2] = hrtf_dirs_deg[i*2]*(
SAF_PI/180.0f);
365 hrtf_dirs_rad[i*2+1] =
SAF_PI/2.0f - hrtf_dirs_deg[i*2+1]*(
SAF_PI/180.0f);
368 for(i=0, Nh=0; i<Nh_max+1; i++)
369 Nh = cnd_num[i] < 100.0f ? i : Nh;
370 saf_assert(Nh>=order,
"Input order exceeds the modal order of the spatial grid");
371 nSH_nh = (Nh+1)*(Nh+1);
372 Y_nh =
malloc1d(nSH_nh*N_dirs*
sizeof(
float));
373 getRSH(Nh, hrtf_dirs_deg, N_dirs, Y_nh);
374 Y_na =
malloc1d(nSH * N_dirs *
sizeof(
float));
376 for(j=0; j<N_dirs; j++)
377 Y_na[i*N_dirs+j] = Y_nh[i*N_dirs+j];
382 Y_td =
malloc1d(nSH_nh*K_td*
sizeof(
float));
383 getRSH(Nh, tdirs_deg, K_td, Y_td);
384 Y_td_cmplx =
malloc1d(nSH_nh*K_td*
sizeof(float_complex));
385 for(i=0; i<nSH_nh*K_td; i++)
386 Y_td_cmplx[i] = cmplxf(Y_td[i], 0.0f);
389 Ynh_Ytd =
malloc1d(N_dirs * K_td *
sizeof(
float));
390 tmp =
malloc1d(N_dirs * K_td *
sizeof(
float));
391 W_Ynh_Ytd =
malloc1d(N_dirs * K_td *
sizeof(float_complex));
392 hrtfs_td =
malloc1d(2*K_td*
sizeof(float_complex));
393 B =
malloc1d(nSH * 2 *
sizeof(float_complex));
394 for(band=0; band<N_bands; band++){
395 cblas_sgemm(CblasRowMajor, CblasTrans, CblasNoTrans, N_dirs, K_td, nSH_nh, 1.0f,
399 cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, N_dirs, K_td, N_dirs, 1.0f,
403 for(i=0; i<N_dirs*K_td; i++)
404 W_Ynh_Ytd[i] = cmplxf(tmp[i], 0.0f);
405 cblas_cgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 2, K_td, N_dirs, &calpha,
406 &hrtfs[band*2*N_dirs], N_dirs,
407 W_Ynh_Ytd, K_td, &cbeta,
409 cblas_cgemm(CblasRowMajor, CblasNoTrans, CblasConjTrans, nSH, 2, K_td, &calpha,
411 hrtfs_td, K_td, &cbeta,
415 decMtx[band*2*nSH + j*nSH + i] = crmulf(conjf(B[i*2+j]), 1.0f/(
float)K_td);
434 float_complex* hrtfs,
435 float* hrtf_dirs_deg,
442 float_complex* decMtx
445 int i, j, nSH, band, band_cutoff;
446 float cutoff, minVal;
448 float_complex* W, *Y_na, *hrtfs_mod, *Yna_W, *Yna_W_Yna, *Yna_W_H, *B;
449 const float_complex calpha = cmplxf(1.0f, 0.0f), cbeta = cmplxf(0.0f, 0.0f);
454 W =
calloc1d(N_dirs*N_dirs,
sizeof(float_complex));
456 for(i=0; i<N_dirs; i++)
457 W[i*N_dirs+i] = cmplxf(weights[i], 0.0f);
459 for(i=0; i<N_dirs; i++)
460 W[i*N_dirs+i] = cmplxf(1.0f/(
float)N_dirs, 0.0f);
463 Y_tmp =
malloc1d(nSH*N_dirs*
sizeof(
float));
464 Y_na =
malloc1d(nSH*N_dirs*
sizeof(float_complex));
465 getRSH(order, hrtf_dirs_deg, N_dirs, Y_tmp);
466 for(i=0; i<nSH*N_dirs; i++)
467 Y_na[i] = cmplxf(Y_tmp[i], 0.0f);
473 for(band=0, band_cutoff=0; band<N_bands; band++){
474 if(minVal>fabsf(freqVector[band]-cutoff)){
475 minVal = fabsf(freqVector[band]-cutoff);
479 saf_assert(band_cutoff>0,
"Frequency vector is wrong!");
482 Yna_W =
malloc1d(nSH * N_dirs*
sizeof(float_complex));
483 Yna_W_Yna =
malloc1d(nSH * nSH *
sizeof(float_complex));
484 Yna_W_H =
malloc1d(nSH * 2 *
sizeof(float_complex));
485 B =
malloc1d(nSH * 2 *
sizeof(float_complex));
486 hrtfs_mod =
malloc1d(2*N_dirs*
sizeof(float_complex));
487 cblas_cgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, nSH, N_dirs, N_dirs, &calpha,
491 cblas_cgemm(CblasRowMajor, CblasNoTrans, CblasTrans, nSH, nSH, N_dirs, &calpha,
493 Y_na, N_dirs, &cbeta,
495 for(band=0; band < N_bands; band++){
497 if(band>=band_cutoff){
498 for(j=0; j<N_dirs; j++){
499 hrtfs_mod[0*N_dirs+j] = ccmulf(hrtfs[band_cutoff*2*N_dirs + 0*N_dirs + j],
500 cexpf( crmulf(cmplxf(0.0f, 0.0f), (itd_s[j]/2.0f))));
501 hrtfs_mod[1*N_dirs+j] = ccmulf(hrtfs[band_cutoff*2*N_dirs + 1*N_dirs + j],
502 cexpf( crmulf(cmplxf(0.0f, 0.0f), (-itd_s[j]/2.0f))));
506 memcpy(hrtfs_mod, &hrtfs[band*2*N_dirs], 2*N_dirs*
sizeof(float_complex));
507 cblas_cgemm(CblasRowMajor, CblasNoTrans, CblasConjTrans, nSH, 2, N_dirs, &calpha,
509 hrtfs_mod, N_dirs, &cbeta,
514 decMtx[band*2*nSH + j*nSH + i] = conjf(B[i*2+j]);
528 float_complex* hrtfs,
529 float* hrtf_dirs_deg,
535 float_complex* decMtx
538 int i, j, nSH, band, band_cutoff;
539 float cutoff, minVal;
541 float_complex* W, *Y_na, *hrtfs_ls, *Yna_W, *Yna_W_Yna, *Yna_W_H, *H_mod, *B_magls;
542 const float_complex calpha = cmplxf(1.0f, 0.0f), cbeta = cmplxf(0.0f, 0.0f);
547 W =
calloc1d(N_dirs*N_dirs,
sizeof(float_complex));
549 for(i=0; i<N_dirs; i++)
550 W[i*N_dirs+i] = cmplxf(weights[i], 0.0f);
552 for(i=0; i<N_dirs; i++)
553 W[i*N_dirs+i] = cmplxf(1.0f/(
float)N_dirs, 0.0f);
556 Y_tmp =
malloc1d(nSH*N_dirs*
sizeof(
float));
557 Y_na =
malloc1d(nSH*N_dirs*
sizeof(float_complex));
558 getRSH(order, hrtf_dirs_deg, N_dirs, Y_tmp);
559 for(i=0; i<nSH*N_dirs; i++)
560 Y_na[i] = cmplxf(Y_tmp[i], 0.0f);
566 for(band=0, band_cutoff=0; band<N_bands; band++){
567 if(minVal>fabsf(freqVector[band]-cutoff)){
568 minVal = fabsf(freqVector[band]-cutoff);
574 Yna_W =
malloc1d(nSH * N_dirs*
sizeof(float_complex));
575 Yna_W_Yna =
malloc1d(nSH * nSH *
sizeof(float_complex));
576 Yna_W_H =
malloc1d(nSH * 2 *
sizeof(float_complex));
577 B_magls =
malloc1d(nSH * 2 *
sizeof(float_complex));
578 hrtfs_ls =
malloc1d(2*N_dirs*
sizeof(float_complex));
579 H_mod =
malloc1d(2*N_dirs*
sizeof(float_complex));
580 cblas_cgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, nSH, N_dirs, N_dirs, &calpha,
584 cblas_cgemm(CblasRowMajor, CblasNoTrans, CblasTrans, nSH, nSH, N_dirs, &calpha,
586 Y_na, N_dirs, &cbeta,
588 for (band=0; band<N_bands; band++){
589 if(band<=band_cutoff){
590 cblas_cgemm(CblasRowMajor, CblasNoTrans, CblasConjTrans, nSH, 2, N_dirs, &calpha,
592 &hrtfs[band*2*N_dirs], N_dirs, &cbeta,
598 cblas_cgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 2, N_dirs, nSH, &calpha,
599 &decMtx[(band-1)*2*nSH] , nSH,
600 Y_na, N_dirs, &cbeta,
602 for(i=0; i<2*N_dirs; i++)
603 H_mod[i] = ccmulf(cmplxf(cabsf(hrtfs[band*2*N_dirs + i]), 0.0f), cexpf(cmplxf(0.0f, atan2f(cimagf(H_mod[i]), crealf(H_mod[i])))));
604 cblas_cgemm(CblasRowMajor, CblasNoTrans, CblasConjTrans, nSH, 2, N_dirs, &calpha,
606 H_mod, N_dirs, &cbeta,
613 decMtx[band*2*nSH + j*nSH + i] = conjf(B_magls[i*2+j]);
void getRSH(int N, float *dirs_deg, int nDirs, float *Y)
Computes real-valued spherical harmonics [1] for each given direction on the unit sphere.
#define ORDER2NSH(order)
Converts spherical harmonic order to number of spherical harmonic components i.e: (order+1)^2.
void checkCondNumberSHTReal(int order, float *dirs_rad, int nDirs, float *w, float *cond_N)
Computes the condition numbers for a least-squares SHT.
#define saf_assert(x, message)
Macro to make an assertion, along with a string explaining its purpose.
#define SAF_PI
pi constant (single precision)
void utility_cglslv(void *const hWork, const float_complex *A, const int dim, float_complex *B, int nCol, float_complex *X)
General linear solver: single precision complex, i.e.
const float * __HANDLES_Tdesign_dirs_deg[21]
minimum T-design HANDLES (up to degree 21 only).
void utility_ssvd(void *const hWork, const float *A, const int dim1, const int dim2, float *U, float *S, float *V, float *sing)
Singular value decomposition: single precision, i.e.
const float __Tdesign_degree_30_dirs_deg[480][2]
Directions [azimuth, Elevation] in degrees, for minimum Tdesign degree: 30.
const float __Tdesign_degree_100_dirs_deg[5100][2]
Directions [azimuth, Elevation] in degrees, for minimum Tdesign degree: 100.
#define SAF_MIN(a, b)
Returns the minimum of the two values.
const int __Tdesign_nPoints_per_degree[21]
Number of points in each t-design (up to degree 21 only).
#define SQRT4PI
sqrt(4pi) (single precision)
void utility_svsmul(float *a, const float *s, const int len, float *c)
Single-precision, multiplies each element in vector 'a' with a scalar 's', i.e.
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 * 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 higher-order Ambisonics module (SAF_HOA_MODULE)
void getBinDecoder_TA(float_complex *hrtfs, float *hrtf_dirs_deg, int N_dirs, int N_bands, int order, float *freqVector, float *itd_s, float *weights, float_complex *decMtx)
Computes a binaural ambisonic decoder based on the time-alignment (TA) method described in [1].
void getEPAD(int order, float *ls_dirs_deg, int nLS, float *decMtx)
Computes the Energy preserving Ambisonic decoder (EPAD), as detailed in [1].
void getBinDecoder_LSDIFFEQ(float_complex *hrtfs, float *hrtf_dirs_deg, int N_dirs, int N_bands, int order, float *weights, float_complex *decMtx)
Computes a least-squares (LS) binaural ambisonic decoder with diffuse-field equalisation [1].
void getBinDecoder_SPR(float_complex *hrtfs, float *hrtf_dirs_deg, int N_dirs, int N_bands, int order, float *weights, float_complex *decMtx)
Computes a binaural ambisonic decoder based on spatial resampling (i.e, virtual loudspeaker decoding)...
void getBinDecoder_LS(float_complex *hrtfs, float *hrtf_dirs_deg, int N_dirs, int N_bands, int order, float *weights, float_complex *decMtx)
Computes a standard least-squares (LS) binaural ambisonic decoder.
void getBinDecoder_MAGLS(float_complex *hrtfs, float *hrtf_dirs_deg, int N_dirs, int N_bands, int order, float *freqVector, float *weights, float_complex *decMtx)
Computes a binaural ambisonic decoder based on the magnitude least-squares (MagLS) method,...
void getAllRAD(int order, float *ls_dirs_deg, int nLS, float *decMtx)
Computes the All-round Ambisonics decoder (AllRAD), as detailed in [1], which is essentially a spheri...
Internal header for the higher-order Ambisonics module (SAF_HOA_MODULE)