66 for(n=0; n<order+2; n++)
69 for(n=0; n < order+1; n++)
70 for(i=o[n]; i < o[n+1]; i++)
85 if(pData->
hSTFT==NULL)
87 else if(arraySpecs->
newQ != arraySpecs->
Q || nSH != new_nSH){
92 arraySpecs->
Q = arraySpecs->
newQ;
102 int i, j, band, n, order, nSH;
103 double alpha, beta, g_lim, regPar;
105 float* Y_mic, *pinv_Y_mic;
106 float_complex* pinv_Y_mic_cmplx, *diag_bN_inv_R;
107 const float_complex calpha = cmplxf(1.0f, 0.0f);
const float_complex cbeta = cmplxf(0.0f, 0.0f);
111 nSH = (order+1)*(order+1);
112 arraySpecs->
R =
SAF_MIN(arraySpecs->
R, arraySpecs->
r);
119 Y_mic =
malloc1d(nSH*(arraySpecs->
Q)*
sizeof(
float));
121 pinv_Y_mic =
malloc1d( arraySpecs->
Q * nSH *
sizeof(
float));
123 pinv_Y_mic_cmplx =
malloc1d((arraySpecs->
Q) * nSH *
sizeof(float_complex));
124 for(i=0; i<(arraySpecs->
Q)*nSH; i++)
125 pinv_Y_mic_cmplx[i] = cmplxf(pinv_Y_mic[i], 0.0f);
154 if(arraySpecs->
R == arraySpecs->
r )
172 for(n=0; n < order+1; n++)
173 pData->
bN[band*(order+1)+n] = ccdiv(pData->
bN[band*(order+1)+n], cmplx(4.0*
SAF_PId, 0.0));
178 for(n=0; n < order+1; n++)
179 pData->
bN_modal[band][n] = ccdiv(cmplx(1.0,0.0), (pData->
bN[band*(order+1)+n]));
186 g_lim = sqrt(arraySpecs->
Q)*pow(10.0,(regPar/20.0));
188 for(n=0; n < order+1; n++)
189 pData->
bN_inv[band][n] = crmul(pData->
bN_modal[band][n], (2.0*g_lim*cabs(pData->
bN[band*(order+1)+n]) /
SAF_PId)
190 * atan(
SAF_PId / (2.0*g_lim*cabs(pData->
bN[band*(order+1)+n]))) );
195 alpha = sqrt(arraySpecs->
Q)*pow(10.0,(regPar/20.0));
197 for(n=0; n < order+1; n++){
198 beta = sqrt((1.0-sqrt(1.0-1.0/ pow(alpha,2.0)))/(1.0+sqrt(1.0-1.0/pow(alpha,2.0))));
199 pData->
bN_inv[band][n] = ccdiv(conj(pData->
bN[band*(order+1)+n]), cmplx((pow(cabs(pData->
bN[band*(order+1)+n]), 2.0) + pow(beta, 2.0)),0.0));
207 diag_bN_inv_R =
calloc1d(nSH*nSH,
sizeof(float_complex));
210 diag_bN_inv_R[i*nSH+i] = cmplxf((
float)creal(pData->
bN_inv_R[band][i]), (
float)cimag(pData->
bN_inv_R[band][i]));
211 cblas_cgemm(CblasRowMajor, CblasNoTrans, CblasTrans, nSH, (arraySpecs->
Q), nSH, &calpha,
213 pinv_Y_mic_cmplx, nSH, &cbeta,
244 for (n=0; n<order+1; n++){
246 H[band][n] = 1.0/(1.0+ pow((
double)(pData->
freqVector[band]/f_lim[n]),2.0));
248 H[band][n] = pow((
double)(pData->
freqVector[band]/f_lim[n-1]), (
double)order+1.0 ) /
249 (1.0 + pow((
double)(pData->
freqVector[band]/f_lim[n-1]), (
double)order+1.0));
251 H[band][n] = pow((
double)(pData->
freqVector[band]/f_lim[n-1]), (
double)n+1.0 ) /
252 (1.0 + pow((
double)(pData->
freqVector[band]/f_lim[n-1]), (
double)n+1.0)) *
253 (1.0 / (1.0 + pow((
double)(pData->
freqVector[band]/f_lim[n]), (
double)n+2.0)));
257 for (n=0; n<order+1; n++)
258 H[band][n] = H[band][n]/normH;
284 if(arraySpecs->
R == arraySpecs->
r )
303 for(n=0; n < order+1; n++)
304 pData->
bN_modal[band][n] = ccdiv(cmplx(4.0*
SAF_PId, 0.0), pData->
bN[band*(order+1)+n]);
308 for (n=0; n<order+1; n++)
309 Hs[band][n] = ccmul(cexp(cmplx(0.0, kr[band])), ccdiv(cmplx(4.0*
SAF_PId, 0.0), pData->
bN[band*(order+1)+n]));
317 for (n=0; n<order+1; n++){
319 wn =
calloc1d(nSH_n*nSH_n,
sizeof(
float));
321 for (i=0; i<n+1; i++)
322 wn[(i*i)*nSH_n+(i*i)] = 1.0f;
326 for (i=0; i<n+1; i++)
327 scale += (
double)(2*i+1)*pow((
double)wn[(i*i)*nSH_n + (i*i)], 2.0);
328 for (i=0; i<n+1; i++)
329 W[i][n] = (
double)wn[(i*i)*nSH_n + (i*i)]/ sqrt(scale);
333 for (n=0; n<order+1; n++)
334 for (i=0; i<order+1; i++)
341 for (n=0; n<order+1; n++){
343 for (i=n, j=0; i<order+1; i++, j++)
344 H_np[band][j] = H[band][i];
345 for (i=n, j=0; i<order+1; i++, j++)
347 cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans,
HYBRID_BANDS, 1, order+1-n, 1.0,
352 pData->
bN_inv[band][n] = crmul(Hs[band][n], HW[band]);
357 diag_bN_inv_R =
calloc1d(nSH*nSH,
sizeof(float_complex));
360 diag_bN_inv_R[i*nSH+i] = cmplxf((
float)creal(pData->
bN_inv_R[band][i]), (
float)cimag(pData->
bN_inv_R[band][i]));
361 cblas_cgemm(CblasRowMajor, CblasNoTrans, CblasTrans, nSH, (arraySpecs->
Q), nSH, &calpha,
363 pinv_Y_mic_cmplx, nSH, &cbeta,
369 pData->
order = order;
376 free(pinv_Y_mic_cmplx);
384 int i, j, band, array_order, idxf_alias, nSH;
385 float f_max, kR_max, f_alias, f_f_alias;
386 double_complex* dM_diffcoh_s;
387 const double_complex calpha = cmplx(1.0, 0.0);
const double_complex cbeta = cmplx(0.0, 0.0);
397 dM_diffcoh_s =
malloc1d((arraySpecs->
Q)*(arraySpecs->
Q) *
sizeof(double_complex));
399 kR_max = 2.0f*
SAF_PI*f_max*(arraySpecs->
r)/pData->
c;
400 array_order =
SAF_MIN((
int)(ceilf(2.0f*kR_max)+0.01f), 28);
438 if( fabsf(pData->
freqVector[band]-f_alias) < f_f_alias){
439 f_f_alias = fabsf(pData->
freqVector[band]-f_alias);
445 for(i=0; i<arraySpecs->
Q; i++)
446 for(j=0; j<arraySpecs->
Q; j++)
447 dM_diffcoh_s[i*(arraySpecs->
Q)+j] = cmplx(dM_diffcoh[i*(arraySpecs->
Q)* (
HYBRID_BANDS) + j*(
HYBRID_BANDS) + (idxf_alias)], 0.0);
449 for(j=0; j<arraySpecs->
Q; j++)
450 pData->W_tmp[i*
MAX_NUM_SENSORS+j]= cmplx((
double)crealf(pData->
W[idxf_alias][i][j]), (
double)cimagf(pData->
W[idxf_alias][i][j]));
451 cblas_zgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, nSH, (arraySpecs->
Q), (arraySpecs->
Q), &calpha,
453 dM_diffcoh_s, (arraySpecs->
Q), &cbeta,
455 cblas_zgemm(CblasRowMajor, CblasNoTrans, CblasConjTrans, nSH, nSH, (arraySpecs->
Q), &calpha,
464 for(i=0; i<arraySpecs->
Q; i++)
465 for(j=0; j<arraySpecs->
Q; j++)
468 for(j=0; j<arraySpecs->
Q; j++)
469 pData->W_tmp[i*
MAX_NUM_SENSORS+j]= cmplx((
double)crealf(pData->
W[band][i][j]), (
double)cimagf(pData->
W[band][i][j]));
470 cblas_zgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, nSH, (arraySpecs->
Q), (arraySpecs->
Q), &calpha,
472 dM_diffcoh_s, (arraySpecs->
Q), &cbeta,
474 cblas_zgemm(CblasRowMajor, CblasNoTrans, CblasConjTrans, nSH, nSH, (arraySpecs->
Q), &calpha,
481 cblas_zgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, nSH, (arraySpecs->
Q), nSH, &calpha,
486 for(j=0; j<arraySpecs->
Q; j++)
502 for(n = 0; n <pData->
order+1; n++){
503 pData->
bN_inv_dB[band][n] = 20.0f * (float)log10(cabs(pData->
bN_inv[band][n]));
513 int band, i, j, simOrder, order, nSH;
517 float_complex* Y_grid, *H_array, *Wshort;
519 saf_assert(pData->
W != NULL,
"The initCodec function must have been called prior to calling array2sh_evaluateSHTfilters()");
584 order = pData->
order;
585 nSH = (order+1)*(order+1);
586 Y_grid_real =
malloc1d(nSH*812*
sizeof(
float));
588 Y_grid =
malloc1d(nSH*812*
sizeof(float_complex));
589 for(i=0; i<nSH*812; i++)
590 Y_grid[i] = cmplxf(Y_grid_real[i], 0.0f);
596 for(j=0; j<(arraySpecs->
Q); j++)
597 Wshort[band*nSH*(arraySpecs->
Q) + i*(arraySpecs->
Q) + j] = pData->
W[band][i][j];
609 *hPars = (
void*)pars;
634 case MICROPHONE_ARRAY_PRESET_DEFAULT:
641 for(ch=0; ch<Q; ch++){
648 case MICROPHONE_ARRAY_PRESET_AALTO_HYDROPHONE:
655 for(ch=0; ch<Q; ch++){
662 case MICROPHONE_ARRAY_PRESET_SENNHEISER_AMBEO:
669 for(ch=0; ch<Q; ch++){
676 case MICROPHONE_ARRAY_PRESET_CORE_SOUND_TETRAMIC:
683 for(ch=0; ch<Q; ch++){
690 case MICROPHONE_ARRAY_PRESET_ZOOM_H3VR_PRESET:
697 for(ch=0; ch<Q; ch++){
704 case MICROPHONE_ARRAY_PRESET_SOUND_FIELD_SPS200:
711 for(ch=0; ch<Q; ch++){
718 case MICROPHONE_ARRAY_PRESET_ZYLIA_1D:
725 for(ch=0; ch<Q; ch++){
732 case MICROPHONE_ARRAY_PRESET_EIGENMIKE32:
739 for(ch=0; ch<Q; ch++){
746 case MICROPHONE_ARRAY_PRESET_EIGENMIKE64:
753 for(ch=0; ch<Q; ch++){
760 case MICROPHONE_ARRAY_PRESET_DTU_MIC:
767 for(ch=0; ch<Q; ch++){
785 if(firstInitFlag==1){
787 pars->
newQ = pars->
Q;
#define MAX_SH_ORDER
Maximum supported Ambisonic order.
#define MAX_NUM_SH_SIGNALS
Maximum number of spherical harmonic components/signals supported.
void afSTFT_clearBuffers(void *const hSTFT)
Flushes time-domain buffers with zeros.
void afSTFT_create(void **const phSTFT, int nCHin, int nCHout, int hopsize, int lowDelayMode, int hybridmode, AFSTFT_FDDATA_FORMAT format)
Creates an instance of afSTFT.
void afSTFT_channelChange(void *const hSTFT, int new_nCHin, int new_nCHout)
Re-allocates memory to support a change in the number of input/output channels.
@ AFSTFT_BANDS_CH_TIME
nBands x nChannels x nTimeHops
#define HOP_SIZE
STFT hop size.
#define HYBRID_BANDS
Number of frequency bands.
ARRAY2SH_MICROPHONE_ARRAY_PRESETS
Available microphone array presets.
@ FILTER_Z_STYLE
Encoding filters based on a linear-phase filter- bank approach [3].
@ FILTER_SOFT_LIM
Encoding filters based on a 'soft-limiting' regularised inversion of the modal responses [1].
@ FILTER_Z_STYLE_MAXRE
Same as FILTER_Z_STYLE, only it also has max_rE weights baked in.
@ FILTER_TIKHONOV
Encoding filters based on a 'Tikhonov' regularised inversion of the modal responses [2].
@ WEIGHT_RIGID_OMNI
Rigid baffle construction with omni sensors.
@ WEIGHT_OPEN_OMNI
Open array construction with omni sensors.
@ WEIGHT_OPEN_DIPOLE
Open array construction with dipole sensors.
@ WEIGHT_RIGID_CARD
Rigid baffle construction with cardioid sensors.
@ WEIGHT_RIGID_DIPOLE
Rigid baffle construction with dipole sensors.
@ WEIGHT_OPEN_CARD
Open array construction with cardioid sensors.
@ ARRAY_CYLINDRICAL
Cylindrial arrangement of sensors (open/rigid)
@ ARRAY_SPHERICAL
Spherical arrangement of sensors (open/rigid)
@ EVAL_STATUS_NOT_EVALUATED
Encoder has not been evaluated.
void array2sh_evaluateSHTfilters(void *hA2sh)
Evaluates the spherical harmonic transform performance with the currently configured microphone/hydro...
void array2sh_calculate_sht_matrix(void *const hA2sh)
Computes the spherical harmonic transform (SHT) matrix, to spatially encode input microphone/hydropho...
void array2sh_initTFT(void *const hA2sh)
Initialise the filterbank used by array2sh.
void array2sh_calculate_mag_curves(void *const hA2sh)
Computes the magnitude responses of the equalisation filters; the absolute values of the regularised ...
void array2sh_initArray(void *const hPars, ARRAY2SH_MICROPHONE_ARRAY_PRESETS preset, int *arrayOrder, int firstInitFlag)
Intialises an instance of a struct based on a preset, which contains the array configuration data.
void array2sh_apply_diff_EQ(void *const hA2sh)
Applies diffuse-field equalisation at frequencies above the spatial aliasing limit.
void array2sh_destroyArray(void **const hPars)
Destroys an instance of a struct, which contains the array configuration data.
static void array2sh_replicate_order(void *const hA2sh, int order)
Takes the bNs computed up to N+1, and replicates them to be of length (N+1)^2 (replicating the 1st or...
void array2sh_createArray(void **const hPars)
Creates an instance of a struct, which contains the array configuration data.
Spatially encodes spherical microphone array signals into spherical harmonic signals (aka: Ambisonic ...
#define MAX_NUM_SENSORS
Maximum permitted number of inputs/sensors.
#define MAX_NUM_SENSORS_IN_PRESET
Maximum permitted number of inputs/sensors.
#define MAX_EVAL_FREQ_HZ
Up to which frequency should the evaluation be accurate.
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.
void getMaxREweights(int order, int diagMtxFlag, float *a_n)
Computes the weights required to manipulate a hyper-cardioid beam-pattern, such that it has maximum e...
void cylModalCoeffs(int order, double *kr, int nBands, ARRAY_CONSTRUCTION_TYPES arrayType, double_complex *b_N)
Calculates the modal coefficients for open/rigid cylindrical arrays.
void evaluateSHTfilters(int order, float_complex *M_array2SH, int nSensors, int nBands, float_complex *H_array, int nDirs, float_complex *Y_grid, float *cSH, float *lSH)
Generates some objective measures, which evaluate the performance of spatial encoding filters.
void sphModalCoeffs(int order, double *kr, int nBands, ARRAY_CONSTRUCTION_TYPES arrayType, double dirCoeff, double_complex *b_N)
Calculates the modal coefficients for open/rigid spherical arrays.
float sphArrayAliasLim(float r, float c, int maxN)
Returns a simple estimate of the spatial aliasing limit (the kR = maxN rule)
void sphArrayNoiseThreshold(int maxN, int Nsensors, float r, float c, ARRAY_CONSTRUCTION_TYPES arrayType, double dirCoeff, float maxG_db, float *f_lim)
Computes the frequencies (per order), at which the noise of a SHT of a SMA exceeds a specified maximu...
void simulateCylArray(int order, double *kr, int nBands, float *sensor_dirs_rad, int N_sensors, float *src_dirs_deg, int N_srcs, ARRAY_CONSTRUCTION_TYPES arrayType, float_complex *H_array)
Simulates a cylindrical microphone array, returning the transfer functions for each (plane wave) sour...
void simulateSphArray(int order, double *kr, double *kR, int nBands, float *sensor_dirs_rad, int N_sensors, float *src_dirs_deg, int N_srcs, ARRAY_CONSTRUCTION_TYPES arrayType, double dirCoeff, float_complex *H_array)
Simulates a spherical microphone array, returning the transfer functions for each (plane wave) source...
void sphDiffCohMtxTheory(int order, float *sensor_dirs_rad, int N_sensors, ARRAY_CONSTRUCTION_TYPES arrayType, double dirCoeff, double *kr, int nBands, double *M_diffcoh)
Calculates the theoretical diffuse coherence matrix for a spherical array.
void sphScattererModalCoeffs(int order, double *kr, double *kR, int nBands, double_complex *b_N)
Calculates the modal coefficients for a rigid spherical scatterer with omni-directional sensors.
void sphScattererDirModalCoeffs(int order, double *kr, double *kR, int nBands, double dirCoeff, double_complex *b_N)
Calculates the modal coefficients for a rigid spherical scatterer with directional sensors.
@ ARRAY_CONSTRUCTION_RIGID_DIRECTIONAL
Rigid baffle, directional sensors.
@ ARRAY_CONSTRUCTION_RIGID
Rigid baffle, omni-directional sensors.
@ ARRAY_CONSTRUCTION_OPEN_DIRECTIONAL
Open array, directional sensors.
@ ARRAY_CONSTRUCTION_OPEN
Open array, omni-directional sensors.
#define saf_print_error(message)
Macro to print a error message along with the filename and line number.
const float __Aalto_Hydrophone_coords_rad[4][2]
Sensor array coordinates for the custom hydrophone array made at Aalto University [1].
#define saf_assert(x, message)
Macro to make an assertion, along with a string explaining its purpose.
#define SAF_PI
pi constant (single precision)
const float __Eigenmike64_coords_rad[64][2]
Sensor array coordinates for the Eigenmike64.
const float __Sennheiser_Ambeo_coords_rad[4][2]
Sensor array coordinates for the Sennheiser Ambeo.
const float __Eigenmike32_coords_rad[32][2]
Sensor array coordinates for the Eigenmike32.
#define SAF_MAX(a, b)
Returns the maximum of the two values.
const float __default_SENSORcoords128_deg[128][2]
Default sensor array coordinates.
#define SAF_PId
pi constant (double precision)
const float __geosphere_ico_9_0_dirs_deg[812][2]
Directions [azimuth, Elevation] in degrees, for ico geosphere, degree: 9.
void utility_spinv(void *const hWork, const float *inM, const int dim1, const int dim2, float *outM)
General matrix pseudo-inverse (the svd way): single precision, i.e.
const float __Sound_field_SPS200_coords_rad[4][2]
Sensor array coordinates for the Sound-field SPS200.
#define SAF_MIN(a, b)
Returns the minimum of the two values.
const float __Zylia1D_coords_rad[19][2]
Sensor array coordinates for the Zylia mic.
const float __Zoom_H3VR_coords_rad[4][2]
Sensor array coordinates for the Zoom H3VR.
const float __Core_Sound_TetraMic_coords_rad[4][2]
Sensor array coordinates for the Core Sound TetraMic.
const float __DTU_mic_coords_rad[52][2]
Sensor array coordinates for the custom 52-sensor array built at the Technical University of Denmark ...
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)
Contains variables for describing the microphone/hydrophone array.
float sensorCoords_deg[MAX_NUM_SENSORS][2]
Sensor directions in degrees.
int Q
Current number of sensors.
float R
radius of scatterer (only for rigid arrays)
ARRAY2SH_ARRAY_TYPES arrayType
see ARRAY2SH_ARRAY_TYPES
ARRAY2SH_WEIGHT_TYPES weightType
see ARRAY2SH_WEIGHT_TYPES
int newQ
New number of sensors (current value replaced by this after next re-init)
float sensorCoords_rad[MAX_NUM_SENSORS][2]
Sensor directions in radians.
Main structure for array2sh.
float progressBar0_1
Current (re)initialisation progress, between [0..1].
float freqVector[HYBRID_BANDS]
frequency vector
double_complex * bN
Temp vector for the modal coefficients.
char * progressBarText
Current (re)initialisation step, string.
double_complex bN_inv[HYBRID_BANDS][MAX_SH_ORDER+1]
1/bN_modal
float c
speed of sound, m/s
void * hSTFT
filterbank handle
float ** bN_modal_dB
modal responses / no regulaisation; HYBRID_BANDS x (MAX_SH_ORDER +1)
void * arraySpecs
array configuration
double_complex bN_modal[HYBRID_BANDS][MAX_SH_ORDER+1]
Current modal coeffients.
double_complex bN_inv_R[HYBRID_BANDS][MAX_NUM_SH_SIGNALS]
1/bN_modal with regularisation
ARRAY2SH_EVAL_STATUS evalStatus
see ARRAY2SH_EVAL_STATUS
float * cSH
spatial correlation; HYBRID_BANDS x 1
int reinitSHTmatrixFLAG
0: do not reinit; 1: reinit;
int new_order
new encoding order (current value will be replaced by this after next re-init)
float ** bN_inv_dB
modal responses / with regularisation; HYBRID_BANDS x (MAX_SH_ORDER +1)
float regPar
regularisation upper gain limit, dB;
float * lSH
level difference; HYBRID_BANDS x 1
ARRAY2SH_FILTER_TYPES filterType
encoding filter approach
int enableDiffEQpastAliasing
0: disabled, 1: enabled
int order
current encoding order
float_complex W[HYBRID_BANDS][MAX_NUM_SH_SIGNALS][MAX_NUM_SENSORS]
Encoding weights.