@@ -48,12 +48,12 @@ static const double p23[19] = { -0.67, 0.142, 3404., -0.91, -0.67, -1.21, -1.76,
4848static const double p33 [19 ] = { 0.174 , -0.11 , -1699. , 0.437 , 0.658 , 2.02 , 6.815 , 0.614 , 589.3 , 16818. , -9.39 , -44.1 , -23.6 , -92.3 , -1.81 , 10.54 , 0.532 , 0.285 , -2.08 };
4949static const double q13 [19 ] = { -1.75 , -0.01 , 7354. , -2.18 , -1.2 , -1.59 , -1.23 , -0.89 , 29.23 , 1945. , -0.06 , 5.635 , 3.308 , 13.88 , -0.88 , -2.23 , -0.96 , -0.9 , -0.57 };
5050static const double q23 [19 ] = { 0.699 , -0.35 , -5350. , 1.188 , 0.256 , 0.816 , 1.166 , 0.76 , 59.51 , 1707. , -1.12 , -6.18 , -3.39 , -12.7 , -0.19 , 1.295 , -0.02 , -0.08 , -0.4 };
51-
5251static const int numAz_table = sizeof (q23 );
53- //static const float a_0 = 0.0875f; /**< Reference head size, 8.75 centimeters, used in the generation of the coeff lookup table. */
54- //static const float a_head = 0.09096f; /**< This head size, See note for head_radius in binauraliser_nf. */
55- static const float headDim = SAF_PI * (0.0875f /*a_0*/ / 0.09096f /*a_head*/ );
56- static const float sosDiv2PiA = 343.0f / (2.0f * SAF_PI * 0.09096f /*a_head*/ );
52+
53+ /* a_0 = 0.0875f; Reference head size, 8.75 centimeters, used in the generation of the coeff lookup table. */
54+ /* a_head = 0.09096f; This head size, see note for head_radius in binauraliser_nf. */
55+ static const float headDim = SAF_PI * (0.0875f / 0.09096f ); /* pi * (a_0 / a_head) */
56+ static const float sosDiv2PiA = 343.0f / (2.0f * SAF_PI * 0.09096f ); /* c / (2pi * a_head) */
5757
5858/** Linear interpolation between two values */
5959static float interpolate_lin
@@ -78,18 +78,18 @@ static float db2mag
7878/*
7979 * Calculate high-shelf parameters, g0, gInf, fc, from the lookup table coefficients (10 degree steps).
8080 * Called twice per update as the returned values are subsequently interpolated to exact azimuth. */
81- void calcHighShelfParams
81+ void calcDVFShelfParams
8282(
83- int i , /* index into the coefficient table, dictated by azimuth */
84- float rhoIn , /* normalized source distance */
85- float * g0 , /* high shelf gain at DC */
86- float * gInf , /* high shelf gain at inf */
87- float * fc /* high shelf cutoff frequency */
83+ int i , /* Index into the coefficient table, dictated by azimuth. */
84+ float rhoIn , /* Normalized source distance. */
85+ float * g0 , /* High shelf gain at DC. */
86+ float * gInf , /* High shelf gain at inf. */
87+ float * fc /* High shelf cutoff frequency. */
8888)
8989{
9090 float fc_tmp ;
9191 double rho = (double )rhoIn ;
92- double rhoSq = rho * rho ;
92+ double rhoSq = rho * rho ;
9393
9494 /* Eq (8), (13) and (14) */
9595 * g0 = (float )((p11 [i ] * rho + p21 [i ]) / (rhoSq + q11 [i ] * rho + q21 [i ]));
@@ -101,69 +101,65 @@ void calcHighShelfParams
101101}
102102
103103/*
104- * Interpolate (linear ) the high shelf parameters generated by calcHighShelfParams()
105- * which is called twice to generate the high shelf parameters for the nearest thetas
106- * in the lookup table. */
107- void interpHighShelfParams
104+ * Interpolate (linearly ) the high shelf parameters generated by
105+ * calcDVFShelfParams() which is called twice to generate the high shelf
106+ * parameters for the nearest thetas in the lookup table. */
107+ void interpDVFShelfParams
108108(
109- float theta , /* ipsilateral azimuth, on the inter-aural axis [0, 180] (deg) */
110- float rho , /* distance , normalized to head radius, >= 1 */
109+ float theta , /* Ipsilateral azimuth, on the inter-aural axis [0, 180] (deg). */
110+ float rho , /* Distance , normalized to head radius, >= 1. */
111111 /* output */
112112 float * iG0 ,
113113 float * iGInf ,
114114 float * iFc
115115)
116116{
117117 int theta_idx_lower , theta_idx_upper ;
118- float ifac ;
119- float thetaDiv10 ;
118+ float ifac , thetaDiv10 ;
120119 float g0_1 , g0_2 ; /* high shelf gain at DC */
121120 float gInf_1 , gInf_2 ; /* high shelf gain at inf */
122121 float fc_1 , fc_2 ; /* high shelf cutoff frequency */
123122
124- // TBD: add range checking? - clip theta and rho to valid range
123+ // TBD: could add range checking, clipping theta and rho to valid range
125124
126- /* linearly interpolate DC gain, HF gain, center freq at theta */
125+ /* Linearly interpolate DC gain, HF gain, center freq at theta.
126+ * Table is in 10 degree steps, floor(x/10) gets lower index. */
127127 thetaDiv10 = theta / 10.f ;
128- theta_idx_lower = (int )thetaDiv10 ; /* Table is in 10 degree steps, floor(x/10) gets lower index */
128+ theta_idx_lower = (int )thetaDiv10 ;
129129 theta_idx_upper = theta_idx_lower + 1 ;
130- if (theta_idx_upper == numAz_table ) { // alternatively, instead check theta_idx_upper => numAz_table, could clip the value > 180 here
130+ if (theta_idx_upper == numAz_table ) { // could alternatively check theta_idx_upper => numAz_table, clip the value > 180 here
131131 theta_idx_upper = theta_idx_lower ;
132132 theta_idx_lower = theta_idx_lower - 1 ;
133133 }
134134
135- calcHighShelfParams (theta_idx_lower , rho , & g0_1 , & gInf_1 , & fc_1 );
136- calcHighShelfParams (theta_idx_upper , rho , & g0_2 , & gInf_2 , & fc_2 );
135+ calcDVFShelfParams (theta_idx_lower , rho , & g0_1 , & gInf_1 , & fc_1 );
136+ calcDVFShelfParams (theta_idx_upper , rho , & g0_2 , & gInf_2 , & fc_2 );
137137
138- ifac = thetaDiv10 - theta_idx_lower ; /* interpolation factor between table steps */
138+ /* interpolation factor between table steps */
139+ ifac = thetaDiv10 - theta_idx_lower ;
139140 * iG0 = interpolate_lin (g0_1 , g0_2 , ifac );
140141 * iGInf = interpolate_lin (gInf_1 , gInf_2 , ifac );
141142 * iFc = interpolate_lin (fc_1 , fc_2 , ifac );
142143}
143144
144145/*
145- * Generate IIR coefficients from the shelf parameters generated by calcHighShelfParams() and
146- * interpHighShelfParams(). * /
147- void calcIIRCoeffs
146+ * Calculate the DVF filter coefficients from shelving filter parameters.
147+ */
148+ void dvfShelfCoeffs
148149(
149150 /* Input */
150- float g0 , /* high shelf dc gain */
151- float gInf , /* high shelf high gain */
152- float fc , /* high shelf center freq */
153- float fs , /* sample rate */
151+ float g0 , /* High shelf dc gain */
152+ float gInf , /* High shelf high gain */
153+ float fc , /* High shelf center freq */
154+ float fs , /* Sample rate */
154155 /* Output */
155156 float * b0 , /* IIR coeffs */
156157 float * b1 ,
157158 float * a1
158159)
159160{
160- float v0 ;
161- float g0_mag ;
162- float tanF ;
163- float v0tanF ;
164- float a_c ;
165- float v ;
166- float va_c ;
161+ float v0 , g0_mag , tanF , v0tanF ;
162+ float a_c , v , va_c ;
167163
168164 v0 = db2mag (gInf ); /* Eq. (12), (10), and (11) */
169165 g0_mag = db2mag (g0 ); // optim TBD: revisit; does g0, gInf need to be in dB?
@@ -178,40 +174,56 @@ void calcIIRCoeffs
178174 * a1 = a_c ;
179175}
180176
181- void applyDVF
177+ void calcDVFCoeffs
182178(
183- float theta , /* ipsilateral azimuth, on the inter-aural axis [0, 180] (deg) */
184- float rho , /* distance, normalized to head radius, >= 1 */
185- float * in_signal ,
186- int nSamples , /* Number of samples to process */
187- float fs , /* Sample rate */
188- float * wz , /* (&) Filter coefficients to be passed to the next block */
189- float * out_signal
179+ float alpha , /* Lateral angle, on the inter-aural axis [0, 180] (deg) */
180+ float rho , /* Distance, normalized to head radius, >= 1 */
181+ float fs , /* Sample rate */
182+ float * b ,
183+ float * a
190184)
191185{
192- float b [2 ] = {0.f , 0.f };
193- float a [2 ] = {1.f , 0.f };
194186 float iG0 , iGInf , iFc ;
195-
196- interpHighShelfParams (theta , rho , & iG0 , & iGInf , & iFc );
197- calcIIRCoeffs (iG0 , iGInf , iFc , fs , & b [0 ], & b [1 ], & a [1 ]);
198- applyIIR (in_signal , nSamples , 2 , & b [0 ], & a [0 ], wz , out_signal );
187+ interpDVFShelfParams (alpha , rho , & iG0 , & iGInf , & iFc );
188+ dvfShelfCoeffs (iG0 , iGInf , iFc , fs , & b [0 ], & b [1 ], & a [1 ]);
199189}
200190
201- void convertFrontalDoAToIpsilateral
191+ void doaToIpsiInteraural
202192(
203- float thetaFront , /* DOA wrt 0˚ forward-facing [deg, (-180, 180)] */
204- float * ipsiDoaLR /* pointer to 2-element array of left and right ear DoAs wrt interaural axis */
193+ float azimuth , /* azimuth wrt 0˚ forward-facing (deg, [-360, 360]) */
194+ float elevation , /* elevation from the horizontal plane (deg, [-180, 180]) */
195+ float * alphaLR , /* (&) 2-element array of lateral angle alpha for left and right ear (deg, [0,180]) */
196+ float * betaLR /* (&) 2-element array of vertical angle beta for left and right ear (deg, [0,90]) */
205197)
206198{
207- float thetaL ;
199+ float az_rad , el_rad , alpha_ipsi , beta_ipsi , alpha_ipsi_deg , beta_ipsi_deg ;
200+ float sinaz , sinel , cosaz , cosel ;
208201
209- thetaFront = SAF_CLAMP (thetaFront , -180.f , 180.f );
210- thetaL = fabsf (90.f - thetaFront );
211- if (thetaL > 180.f ) {
212- thetaL = 360.f - thetaL ;
202+ az_rad = DEG2RAD (azimuth );
203+ el_rad = DEG2RAD (elevation );
204+ sinaz = sinf (az_rad );
205+ sinel = sinf (el_rad );
206+ cosaz = cosf (az_rad );
207+ cosel = cosf (el_rad );
208+ alpha_ipsi = SAF_PI /2.f - acosf (sinaz * cosel );
209+ beta_ipsi = asinf (sinel / sqrtf (powf (sinel ,2.f ) + (powf (cosaz ,2.f ) * powf (cosel ,2.f ))));
210+
211+ /* Convert interaural-polar coordinates back to spherical _ranges_. */
212+ if (beta_ipsi > SAF_PI /2.f ) {
213+ alpha_ipsi = SAF_PI - alpha_ipsi ; /* [0,pi] */
214+ beta_ipsi = SAF_PI - beta_ipsi ; /* [0,pi/2] */
213215 }
216+
217+ /* Convert to ipsilateral offset from the left ear: [-360, 360]->[0, 180] */
218+ alpha_ipsi = fabsf (SAF_PI /2.f - alpha_ipsi );
219+ if (alpha_ipsi > SAF_PI )
220+ alpha_ipsi = 2 * SAF_PI - alpha_ipsi ;
214221
215- ipsiDoaLR [0 ] = thetaL ;
216- ipsiDoaLR [1 ] = 180.f - thetaL ; // thetaR
222+ alphaLR [0 ] = alpha_ipsi_deg = RAD2DEG (alpha_ipsi );
223+ alphaLR [1 ] = 180.f - alpha_ipsi_deg ;
224+
225+ if (betaLR != NULL ) {
226+ betaLR [0 ] = beta_ipsi_deg = RAD2DEG (beta_ipsi );
227+ betaLR [1 ] = 180.f - beta_ipsi_deg ;
228+ }
217229}
0 commit comments