Line data Source code
1 : /******************************************************************************************************
2 :
3 : (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB,
4 : Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
5 : Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
6 : Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
7 : contributors to this repository. All Rights Reserved.
8 :
9 : This software is protected by copyright law and by international treaties.
10 : The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB,
11 : Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
12 : Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
13 : Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
14 : contributors to this repository retain full ownership rights in their respective contributions in
15 : the software. This notice grants no license of any kind, including but not limited to patent
16 : license, nor is any license granted by implication, estoppel or otherwise.
17 :
18 : Contributors are required to enter into the IVAS codec Public Collaboration agreement before making
19 : contributions.
20 :
21 : This software is provided "AS IS", without any express or implied warranties. The software is in the
22 : development stage. It is intended exclusively for experts who have experience with such software and
23 : solely for the purpose of inspection. All implied warranties of non-infringement, merchantability
24 : and fitness for a particular purpose are hereby disclaimed and excluded.
25 :
26 : Any dispute, controversy or claim arising under or in relation to providing this software shall be
27 : submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in
28 : accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and
29 : the United Nations Convention on Contracts on the International Sales of Goods.
30 :
31 : *******************************************************************************************************/
32 :
33 : #include "options.h"
34 : #include <stdint.h>
35 : #include <math.h>
36 : #include "ivas_prot_rend_fx.h"
37 : #include "ivas_stat_rend.h"
38 : #include "ivas_cnst.h"
39 : #include "prot_fx.h"
40 : #include "wmc_auto.h"
41 : #include "ivas_rom_com.h"
42 : #include "ivas_rom_com_fx.h"
43 :
44 :
45 : /*-------------------------------------------------------------------------
46 : * Local constants
47 : *------------------------------------------------------------------------*/
48 :
49 : #define ER_MAX_SOURCES 25
50 : #define ER_REF_ORDER 1
51 : #define ER_AIR_COEFF_FX ( Word32 )( 2942053 ) // 0.00137f in Q.31
52 : #define ER_SOUND_SPEED_FX ( Word32 )( 6260885 ) // 1/343.0f in Q1.31
53 : #define ER_MIN_WALL_DIST_FX ( Word32 )( 419430 ) // Q.22
54 : #define ER_EUCLIDEAN_SCALE_FX ( 0x1 ) // Q.22
55 : #define ER_RECIPROCAL_EUCLIDEAN_SCALE_FX ( 0x1 ) // Q.22
56 :
57 :
58 : /*-----------------------------------------------------------------------------------------*
59 : * Function ivas_shoebox_config_init
60 : *
61 : * Function transfer the parameters from the reverb config handle to the shoebox
62 : * calibration data structure.
63 : *-----------------------------------------------------------------------------------------*/
64 :
65 3 : void ivas_shoebox_config_init(
66 : shoebox_config_t *cal,
67 : RENDER_CONFIG_HANDLE hRenderConfig /* i : Renderer configuration handle */
68 : )
69 : {
70 : UWord16 wall_idx;
71 :
72 :
73 3 : cal->room_L_fx = hRenderConfig->roomAcoustics.dimensions.x_fx; // Q.22
74 3 : cal->room_W_fx = hRenderConfig->roomAcoustics.dimensions.y_fx; // Q.22
75 3 : cal->room_H_fx = hRenderConfig->roomAcoustics.dimensions.z_fx; // Q.22
76 3 : move32();
77 3 : move32();
78 3 : move32();
79 :
80 : /* Absorption Coefficients */
81 : /* Convention: [Front wall, Back wall, Left wall, Right wall, Ceiling, Floor] */
82 21 : FOR( wall_idx = 0; wall_idx < 6; wall_idx++ )
83 : {
84 18 : cal->abs_coeff_fx[wall_idx] = hRenderConfig->roomAcoustics.AbsCoeff_fx[wall_idx]; // Q2.30
85 18 : move32();
86 : }
87 :
88 : /* Listener position (only X and Y can be pos. or neg. ) */
89 3 : cal->list_orig_fx[0] = hRenderConfig->roomAcoustics.ListenerOrigin.x_fx; // Q.22
90 3 : cal->list_orig_fx[1] = hRenderConfig->roomAcoustics.ListenerOrigin.y_fx; // Q.22
91 3 : cal->list_orig_fx[2] = hRenderConfig->roomAcoustics.ListenerOrigin.z_fx; // Q.22
92 3 : move32();
93 3 : move32();
94 3 : move32();
95 :
96 3 : return;
97 : }
98 :
99 :
100 : /*-----------------------------------------------------------------------------------------*
101 : * Function ivas_shoebox_init()
102 : *
103 : * Function initializes the shoebox operating parameters by setting limits and defaults,
104 : * also contains the calibration structure.
105 : *-----------------------------------------------------------------------------------------*/
106 3 : void ivas_shoebox_init(
107 : shoebox_obj_t *obj,
108 : shoebox_config_t *cal )
109 : {
110 : UWord16 i;
111 :
112 : /* Add cal to obj struct */
113 3 : obj->cal = *cal;
114 3 : move32();
115 : /* Add defaults */
116 3 : obj->max_bands = 1;
117 3 : obj->MAX_SOURCES = ER_MAX_SOURCES; // Q0
118 3 : obj->REF_ORDER = ER_REF_ORDER; // Q0
119 3 : move16();
120 3 : move16();
121 3 : move16();
122 :
123 : /* Positions */
124 :
125 3 : set32_fx( &obj->src_pos_fx[0], 0, 75U );
126 3 : set32_fx( &obj->src_dist_fx[0], 0, 25U );
127 :
128 12 : FOR( i = 0; i < 3; i++ )
129 : {
130 9 : obj->list_pos_fx[i] = cal->list_orig_fx[i]; // Q.22
131 9 : move32();
132 : }
133 :
134 : /* Pointer */
135 3 : obj->nSrc = 0;
136 3 : move16();
137 :
138 : /* Flags */
139 3 : obj->isCartesian = 1;
140 3 : obj->isRelative = 1;
141 3 : obj->isZHeight = 1;
142 3 : obj->isRadians = 1;
143 3 : move16();
144 3 : move16();
145 3 : move16();
146 3 : move16();
147 :
148 : /* Params */
149 3 : obj->radius_fx = ER_RADIUS_FX; // Q30
150 3 : obj->min_wall_dist_fx = ER_MIN_WALL_DIST_FX; // Q22
151 3 : obj->soundspeed_fx = ER_SOUND_SPEED_FX; // Q31
152 3 : obj->air_coeff_fx = ER_AIR_COEFF_FX; // Q31
153 3 : move32();
154 3 : move32();
155 3 : move32();
156 3 : move32();
157 :
158 3 : return;
159 : }
160 :
161 :
162 : /*-----------------------------------------------------------------------------------------*
163 : * Function shoebox_bound()
164 : *
165 : * SHOEBOX_BOUND takes in CARTESIAN coordinates of either a receiver or
166 : * source and checks if it is within the virtual room boundaries established
167 : * by the surface parameters. If object is out of bounds, then new cartesian
168 : * coordinates are established to collapse the object position.
169 : *-----------------------------------------------------------------------------------------*/
170 36 : static void shoebox_bound_fx(
171 : shoebox_obj_t *obj,
172 : Word32 *out_pos // Q22
173 : )
174 : {
175 : Word32 out_tmp, out_tmp1;
176 : Word32 i;
177 :
178 36 : out_tmp = L_sub( L_shr( obj->cal.room_L_fx, 1 ), obj->min_wall_dist_fx ); // Q.22
179 36 : out_tmp1 = L_add( L_shr( L_negate( obj->cal.room_L_fx ), 1 ), obj->min_wall_dist_fx ); // Q.22
180 36 : test();
181 36 : IF( GT_32( out_pos[0], out_tmp ) || LT_32( out_pos[0], out_tmp1 ) )
182 : {
183 1 : IF( out_pos[0] < 0 )
184 : {
185 0 : i = -1;
186 0 : move32();
187 : }
188 : ELSE
189 : {
190 1 : IF( out_pos[0] > 0 )
191 : {
192 1 : i = (Word32) 1;
193 : }
194 : ELSE
195 : {
196 0 : i = (Word32) 0;
197 : }
198 1 : move32();
199 : }
200 :
201 1 : out_pos[0] = W_extract_l( W_mult0_32_32( out_tmp, i ) );
202 1 : move32();
203 : }
204 :
205 36 : out_tmp = L_sub( L_shr( obj->cal.room_W_fx, 1 ), obj->min_wall_dist_fx ); // Q.22
206 36 : out_tmp1 = L_add( L_shr( L_negate( obj->cal.room_W_fx ), 1 ), obj->min_wall_dist_fx ); // Q.22
207 :
208 36 : test();
209 36 : IF( GT_32( out_pos[1], out_tmp ) || LT_32( out_pos[1], out_tmp1 ) )
210 : {
211 1 : IF( out_pos[1] < 0 )
212 : {
213 1 : i = -1;
214 1 : move32();
215 : }
216 : ELSE
217 : {
218 0 : IF( out_pos[1] > 0 )
219 : {
220 0 : i = (Word32) 1;
221 : }
222 : ELSE
223 : {
224 0 : i = (Word32) 0;
225 : }
226 0 : move32();
227 : }
228 1 : out_pos[1] = W_extract_l( W_mult0_32_32( out_tmp, i ) ); // Q22
229 1 : move32();
230 : }
231 :
232 36 : out_tmp = L_sub( L_shr( obj->cal.room_H_fx, 1 ), obj->min_wall_dist_fx ); // Q.22
233 36 : out_tmp1 = L_add( L_shr( L_negate( obj->cal.room_H_fx ), 1 ), obj->min_wall_dist_fx ); // Q.22
234 :
235 36 : test();
236 36 : IF( GT_32( out_pos[2], out_tmp ) || LT_32( out_pos[2], out_tmp1 ) )
237 : {
238 0 : IF( out_pos[2] < 0 )
239 : {
240 0 : i = -1;
241 0 : move32();
242 : }
243 : ELSE
244 : {
245 0 : IF( out_pos[2] > 0 )
246 : {
247 0 : i = (Word32) 1;
248 : }
249 : ELSE
250 : {
251 0 : i = (Word32) 0;
252 : }
253 0 : move32();
254 : }
255 0 : out_pos[2] = W_extract_l( W_mult0_32_32( out_tmp, (Word32) i ) ); // Q22
256 0 : move32();
257 : }
258 :
259 36 : return;
260 : }
261 :
262 :
263 : /*-----------------------------------------------------------------------------------------*
264 : * Function shoebox_get_coord()
265 : *
266 : * Transform relative spherical coordinate to 3D cartesian point
267 : *-----------------------------------------------------------------------------------------*/
268 :
269 :
270 33 : static void shoebox_get_coord_fx(
271 : shoebox_obj_t *obj,
272 : Word32 *fcnOutput_data, // 0th and 1st idx in Q0 and 2nd idx in Q30
273 : const Word32 src_pos_data[], // Q22
274 : Word32 *tmp_pos, // Q22
275 : Word32 out_tmp,
276 : Word32 coord,
277 : Word32 loop_ub,
278 : Word32 k,
279 : UWord16 isRelative )
280 : {
281 : Word32 tmp_data[3];
282 : Word32 rcoselev;
283 : Word32 tmp_size_idx_1;
284 : Word32 n;
285 :
286 33 : tmp_size_idx_1 = 3;
287 33 : move32();
288 33 : IF( obj->isCartesian == 0 )
289 : {
290 : /* Convert Spherical to Cartesian */
291 33 : tmp_data[2] = Mpy_32_32( fcnOutput_data[2] /* Q30 */, shoebox_sin_cos_tbl_fx[fcnOutput_data[1] /* Q0 */][0] ); // Q29 = .Q30 * Q30
292 33 : move32();
293 33 : rcoselev = Mpy_32_32( fcnOutput_data[2] /* Q30 */, shoebox_sin_cos_tbl_fx[fcnOutput_data[1] /* Q0 */][1] ); // Q29 = Q30 * Q30
294 33 : tmp_data[0] = Mpy_32_32( rcoselev, shoebox_sin_cos_tbl_fx[fcnOutput_data[0] /* Q0 */][1] ); // Q28 =Q29*Q30
295 33 : move32();
296 33 : tmp_data[1] = Mpy_32_32( rcoselev, shoebox_sin_cos_tbl_fx[fcnOutput_data[0] /* Q0 */][0] ); // Q28 = Q29*Q30
297 33 : move32();
298 33 : tmp_data[0] = L_shr( tmp_data[0], 6 ); // Q28 -> Q22
299 33 : move32();
300 33 : tmp_data[1] = L_shr( tmp_data[1], 6 ); // Q28 -> Q22
301 33 : move32();
302 33 : tmp_data[2] = L_shr( tmp_data[2], 7 ); // Q29 -> Q22
303 33 : move32();
304 : }
305 : ELSE
306 : {
307 : /* CARTESIAN CASE */
308 0 : tmp_size_idx_1 = loop_ub;
309 0 : move32();
310 0 : FOR( n = 0; n < loop_ub; n++ )
311 : {
312 0 : tmp_data[n] = src_pos_data[k + n];
313 0 : move32();
314 : }
315 0 : IF( obj->isZHeight != 0 )
316 : {
317 : /* FIX Z COORDINATE */
318 0 : tmp_data[2] = L_sub( src_pos_data[k + 2] /* Q22 */, L_shr( obj->cal.room_H_fx, 1 ) ); // Q22
319 0 : move32();
320 : }
321 : }
322 :
323 132 : FOR( k = 0; k < tmp_size_idx_1; k++ )
324 : {
325 99 : obj->src_pos_fx[coord + k - 1] = tmp_data[k]; // Q22
326 99 : move32();
327 : }
328 :
329 : /* CENTER TO LISTENER */
330 :
331 33 : k = L_add( out_tmp, 1 );
332 :
333 33 : tmp_pos[0] = obj->src_pos_fx[k - 1]; // Q22
334 33 : tmp_pos[1] = obj->src_pos_fx[k]; // Q22
335 33 : tmp_pos[2] = obj->src_pos_fx[k + 1]; // Q22
336 33 : move32();
337 33 : move32();
338 33 : move32();
339 :
340 33 : IF( isRelative != 0 )
341 : {
342 33 : tmp_pos[0] = L_add( tmp_pos[0], obj->list_pos_fx[0] ); // Q22
343 33 : tmp_pos[1] = L_add( tmp_pos[1], obj->list_pos_fx[1] ); // Q22
344 33 : tmp_pos[2] = L_add( tmp_pos[2], obj->list_pos_fx[2] ); // Q22
345 :
346 33 : move32();
347 33 : move32();
348 33 : move32();
349 : }
350 :
351 33 : return;
352 : }
353 :
354 :
355 : /*-----------------------------------------------------------------------------------------*
356 : * Function shoebox_get_euclidian_distance_internal()
357 : *
358 : * Get 3D source distance from receiver
359 : *-----------------------------------------------------------------------------------------*/
360 231 : static Word32 shoebox_get_euclidian_distance_internal_fx(
361 : shoebox_obj_t *obj,
362 : Word32 *tmp_pos, // Q22
363 : Word32 *scale // Q22
364 : )
365 : {
366 : Word32 absxk, out_tmp, t;
367 : Word16 q;
368 :
369 231 : absxk = L_abs( L_sub( obj->list_pos_fx[0], tmp_pos[0] ) ); // Q22-Q22
370 :
371 231 : IF( GT_32( absxk, ER_EUCLIDEAN_SCALE_FX ) )
372 : {
373 201 : out_tmp = ONE_IN_Q22; // 1 in Q22
374 201 : *scale = absxk; // Q22
375 201 : move32();
376 201 : move32();
377 : }
378 : ELSE
379 : {
380 30 : t = (Word32) W_mult0_32_32( absxk, ER_RECIPROCAL_EUCLIDEAN_SCALE_FX ); // Q22
381 30 : out_tmp = W_extract_h( W_shl( W_mult_32_32( t, t ), 9 ) ); // Q22 + Q22 + Q1 + Q9 - 32 = Q22
382 : }
383 :
384 231 : absxk = L_abs( L_sub( obj->list_pos_fx[1], tmp_pos[1] ) );
385 :
386 231 : IF( GT_32( absxk, *scale ) )
387 : {
388 84 : q = Q22;
389 84 : move16();
390 84 : t = (Word32) BASOP_Util_Divide3232_Scale_newton( *scale, absxk, &q );
391 :
392 84 : out_tmp = W_extract_h( W_shl( W_mult_32_32( out_tmp, t ), q ) ); // Q22 + Q31 + Q1 - 32 = Q22
393 84 : out_tmp = W_extract_h( W_shl( W_mult_32_32( out_tmp, t ), q ) ); // Q22 + Q31 + Q1 - 32 = Q22
394 84 : out_tmp = L_add( out_tmp, ONE_IN_Q22 ); // Q22
395 84 : *scale = absxk; // Q22
396 84 : move32();
397 : }
398 : ELSE
399 : {
400 147 : t = (Word32) BASOP_Util_Divide3232_Scale_newton( absxk, *scale, &q );
401 147 : t = W_extract_h( W_shl( W_mult_32_32( t, t ), sub( shl( q, 1 ), 9 ) ) ); // Q31 + Q31 + Q1 - 9 - 32 = Q22
402 147 : out_tmp = L_add( out_tmp, t ); // Q22
403 147 : move32();
404 : }
405 :
406 231 : absxk = L_abs( L_sub( obj->list_pos_fx[2], tmp_pos[2] ) );
407 :
408 231 : IF( GE_32( absxk, *scale ) )
409 : {
410 66 : t = (Word32) BASOP_Util_Divide3232_Scale_newton( *scale, absxk, &q );
411 :
412 66 : out_tmp = W_extract_h( W_shl( W_mult_32_32( out_tmp, t ), q ) ); // Q22 + Q31 + Q1 - 32 = Q22
413 66 : out_tmp = W_extract_h( W_shl( W_mult_32_32( out_tmp, t ), q ) ); // Q22 + Q31 + Q1 - 32 = Q22
414 66 : out_tmp = L_add( out_tmp, ONE_IN_Q22 ); // Q22
415 66 : *scale = absxk; // Q22
416 66 : move32();
417 : }
418 : ELSE
419 : {
420 165 : t = (Word32) BASOP_Util_Divide3232_Scale_newton( absxk, *scale, &q );
421 165 : t = W_extract_h( W_shl( W_mult_32_32( t, t ), sub( shl( q, 1 ), 9 ) ) ); // Q31 + Q31 + Q1 - 9 - 32 = Q22
422 165 : out_tmp = L_add( out_tmp, t ); // Q22
423 : }
424 :
425 231 : return out_tmp;
426 : }
427 :
428 :
429 : /*-----------------------------------------------------------------------------------------*
430 : * Function ivas_shoebox_set_scene()
431 : *
432 : * Initial scene setup returning computed reflection (arrival times, DOA and gain).
433 : *-----------------------------------------------------------------------------------------*/
434 :
435 3 : void ivas_shoebox_set_scene(
436 : shoebox_obj_t *obj,
437 : shoebox_output_t *ER_PARAMS,
438 : const Word32 list_pos_fx[3], // Q22
439 : const Word32 src_pos_data[], // 0th and 1st idx in Q0 and 2nd idx in Q30
440 : const UWord16 isCartesian,
441 : const UWord16 isRelative )
442 : {
443 :
444 : Word32 tmp_pos_fx[3];
445 : Word32 out_tmp;
446 : Word32 k, n;
447 : Word32 loop_ub, out_tmp_fx;
448 : Word16 q_format1, q_format, i, j;
449 :
450 : /* ------------- SET FLAGS ------------- */
451 3 : obj->isCartesian = isCartesian;
452 3 : obj->isRelative = isRelative;
453 3 : move16();
454 3 : move16();
455 : /* ------------- CHECK DIMENSIONS ------------- */
456 3 : IF( GE_16( ER_PARAMS->n_sources, obj->MAX_SOURCES ) )
457 : {
458 0 : obj->nSrc = obj->MAX_SOURCES;
459 : }
460 : ELSE
461 : {
462 3 : obj->nSrc = ER_PARAMS->n_sources;
463 : }
464 3 : move16();
465 :
466 3 : set32_fx( &obj->src_pos_fx[0], 0, 75U );
467 :
468 3 : obj->list_pos_fx[0] = list_pos_fx[0]; // Q22
469 3 : obj->list_pos_fx[1] = list_pos_fx[1]; // Q22
470 3 : obj->list_pos_fx[2] = list_pos_fx[2]; // Q22
471 3 : move32();
472 3 : move32();
473 3 : move32();
474 : /* ---------- ADJUST LISTENER ------------- */
475 3 : IF( obj->isZHeight != 0 )
476 : {
477 3 : obj->list_pos_fx[2] = L_sub( list_pos_fx[2], L_shr( obj->cal.room_H_fx, 1 ) ); // Q22
478 3 : move32();
479 : }
480 3 : tmp_pos_fx[1] = obj->list_pos_fx[1]; // Q22
481 3 : tmp_pos_fx[2] = obj->list_pos_fx[2]; // Q22
482 3 : move32();
483 3 : move32();
484 :
485 3 : shoebox_bound_fx( obj, obj->list_pos_fx );
486 :
487 :
488 : /* ---------- SOURCE LOOP ------------- */
489 3 : i = obj->nSrc;
490 3 : move32();
491 36 : FOR( j = 0; j < i; j++ )
492 : {
493 : Word32 fcnOutput_data_fx[3], scale_fx;
494 : Word32 rcoselev;
495 : Word32 coord;
496 :
497 : /* idx = single(i); */
498 33 : out_tmp = L_mult0( 3, j );
499 : /* GET COORDINATE IN CARTESIAN ABSOLUTE FORMAT */
500 33 : k = out_tmp;
501 33 : move32();
502 33 : n = L_add( out_tmp, 3 );
503 33 : coord = L_add( out_tmp, 1 );
504 :
505 33 : loop_ub = L_sub( n, k );
506 :
507 132 : FOR( n = 0; n < loop_ub; n++ )
508 : {
509 99 : fcnOutput_data_fx[n] = src_pos_data[k + n];
510 99 : move32();
511 : }
512 :
513 33 : shoebox_get_coord_fx( obj, fcnOutput_data_fx, src_pos_data, tmp_pos_fx, out_tmp, coord, loop_ub, k, isRelative );
514 33 : shoebox_bound_fx( obj, tmp_pos_fx );
515 :
516 33 : scale_fx = ER_EUCLIDEAN_SCALE_FX; // Q22
517 33 : move32();
518 33 : out_tmp_fx = shoebox_get_euclidian_distance_internal_fx( obj, tmp_pos_fx, &scale_fx );
519 33 : q_format = Q31 - Q22;
520 33 : move16();
521 33 : out_tmp_fx = Sqrt32( out_tmp_fx, &q_format );
522 33 : out_tmp_fx = Mpy_32_32( scale_fx, out_tmp_fx );
523 33 : obj->src_dist_fx[j] = L_shl( out_tmp_fx, q_format ); // Q22
524 33 : move32();
525 :
526 :
527 : /* COMPUTE PATTERNS */
528 :
529 : /* SHOEBOX_COMPUTE: fills an input structure (4 array fields of length NxR ) with the */
530 : /* Early reflection metadata (time of arrival, gain, az, el). */
531 : /* */
532 : /* Input: */
533 : /* 1. obj : Module data holder */
534 : /* 2. ER_struct : Early reflection structure */
535 : /* 3. src_num : Index of source to compute patterns for */
536 : /* ------ */
537 33 : out_tmp_fx = obj->src_dist_fx[j]; // Q22
538 33 : move32();
539 :
540 231 : FOR( loop_ub = 0; loop_ub < 6; loop_ub++ )
541 : {
542 :
543 : Word32 im_pos_fx[3];
544 : Word32 path_dist_fx;
545 : Word32 asin_val;
546 : Word32 sub_im_nd_list_pos_1, sub_im_nd_list_pos_0, atan_pos, az_angle_d;
547 : Word32 one_minus_abs_coeff, out_tmp_div_path_dist, product, pro_pd_air_coeff, result_gain;
548 : Word32 sub_im_nd_list_div_path, one_minus_sub_im_nd_list_div_path_sq, sub_im_nd_list_div_path_sq, one_minus_sub_im_nd_list_div_path_sq_rt, asin_val_deg;
549 : Word16 q_format_n;
550 :
551 : /* Retrieve coordinate and surface sign */
552 198 : coord = L_shr( loop_ub, 1 ); // tbl
553 198 : rcoselev = L_add( L_add( loop_ub, 1 ), L_mult0( (Word16) ER_PARAMS->n_ref, j ) );
554 :
555 : /* Initialize image position coordinates */
556 198 : im_pos_fx[0] = tmp_pos_fx[0]; // Q:22
557 198 : im_pos_fx[1] = tmp_pos_fx[1]; // Q:22
558 198 : im_pos_fx[2] = tmp_pos_fx[2]; // Q:22
559 198 : move32();
560 198 : move32();
561 198 : move32();
562 :
563 : /* Calculate image projection coordinate based on current surface axis */
564 198 : IF( LT_32( L_add( loop_ub, 1 ), 3 ) )
565 : {
566 66 : scale_fx = obj->cal.room_L_fx; // Q:22
567 66 : move32();
568 : }
569 132 : ELSE IF( LT_32( L_add( loop_ub, 1 ), 5 ) )
570 : {
571 66 : scale_fx = obj->cal.room_W_fx; // Q:22
572 66 : move32();
573 : }
574 : ELSE
575 : {
576 66 : scale_fx = obj->cal.room_H_fx; // Q:22
577 66 : move32();
578 : }
579 :
580 :
581 198 : im_pos_fx[coord] =
582 198 : L_add( tmp_pos_fx[coord],
583 : L_shl( L_sub( L_shr( W_extract_l( W_mult0_32_32( ( L_negate( L_sub( 1, L_shl( L_and( L_add( loop_ub, 1 ), 1 ), 1 ) ) ) ), scale_fx ) ), 1 ), tmp_pos_fx[coord] ), 1 ) ); // Q:22
584 198 : move32();
585 :
586 : /* 0. Get euclidean distance from IMAGE SOURCE [N,W] to LIST */
587 198 : scale_fx = ER_EUCLIDEAN_SCALE_FX; // Q:22
588 198 : move32();
589 198 : path_dist_fx = shoebox_get_euclidian_distance_internal_fx( obj, im_pos_fx, &scale_fx ); // Uutput :Q:22
590 :
591 198 : q_format = Q31 - Q22;
592 198 : move16();
593 198 : path_dist_fx = Sqrt32( path_dist_fx, &q_format ); // Input: Q:22, Output : Q30
594 :
595 198 : path_dist_fx = Mpy_32_32( scale_fx, path_dist_fx ); // Q22 + (31 - q_format) - 31 = Q22 - q_format
596 198 : path_dist_fx = L_shl( path_dist_fx, q_format ); // Q22 - q_format + (q_format) = Q22
597 :
598 :
599 : /* 1. Compute time-of arrival (TOA) */
600 198 : ER_PARAMS->times.data_fx[rcoselev - 1] = Mpy_32_32( path_dist_fx, obj->soundspeed_fx ); // Q22
601 198 : move32();
602 :
603 : /* 2./3. DOA */
604 198 : sub_im_nd_list_pos_1 = L_sub( im_pos_fx[1], obj->list_pos_fx[1] ); // Q22
605 198 : sub_im_nd_list_pos_0 = L_sub( im_pos_fx[0], obj->list_pos_fx[0] ); // Q22
606 198 : q_format = Q22 - Q22;
607 198 : move16();
608 198 : atan_pos = BASOP_util_atan2( sub_im_nd_list_pos_1, sub_im_nd_list_pos_0, q_format ); // Q13
609 198 : az_angle_d = rad2deg_fx( atan_pos ); // Q23
610 198 : ER_PARAMS->az_angle.data_fx[rcoselev - 1] = az_angle_d;
611 198 : move32();
612 :
613 :
614 198 : q_format = Q22;
615 198 : move16();
616 198 : sub_im_nd_list_div_path = BASOP_Util_Divide3232_Scale( ( L_sub( im_pos_fx[2], obj->list_pos_fx[2] ) ), path_dist_fx, &q_format );
617 198 : sub_im_nd_list_div_path = L_shl( sub_im_nd_list_div_path, q_format );
618 198 : sub_im_nd_list_div_path = L_deposit_h( (Word16) sub_im_nd_list_div_path );
619 198 : sub_im_nd_list_div_path_sq = Mpy_32_32( sub_im_nd_list_div_path, sub_im_nd_list_div_path );
620 198 : sub_im_nd_list_div_path_sq = L_shr( sub_im_nd_list_div_path_sq, 1 );
621 198 : one_minus_sub_im_nd_list_div_path_sq = L_sub( L_shl( 1, Q30 ), sub_im_nd_list_div_path_sq );
622 198 : q_format1 = Q31 - Q30;
623 198 : move16();
624 :
625 198 : one_minus_sub_im_nd_list_div_path_sq_rt = Sqrt32( one_minus_sub_im_nd_list_div_path_sq, &q_format1 );
626 198 : one_minus_sub_im_nd_list_div_path_sq_rt = L_shl( one_minus_sub_im_nd_list_div_path_sq_rt, q_format1 );
627 :
628 :
629 198 : q_format_n = Q31 - Q31;
630 198 : asin_val = BASOP_util_atan2( sub_im_nd_list_div_path, one_minus_sub_im_nd_list_div_path_sq_rt, q_format_n ); // Q13
631 :
632 198 : asin_val_deg = rad2deg_fx( asin_val ); // Q23
633 198 : ER_PARAMS->el_angle.data_fx[rcoselev - 1] = asin_val_deg;
634 198 : move32();
635 :
636 :
637 : /* 4. Compute gain taking into account air and surface absorption */
638 : /* and propagation loss */
639 198 : if ( LT_32( path_dist_fx, out_tmp_fx ) )
640 : {
641 0 : path_dist_fx = out_tmp_fx; // Q22
642 0 : move32();
643 : }
644 :
645 198 : one_minus_abs_coeff = L_sub( ( ONE_IN_Q30 ), obj->cal.abs_coeff_fx[loop_ub] ); // Q30=Q30-Q30
646 198 : q_format_n = Q22;
647 198 : move16();
648 198 : out_tmp_div_path_dist = BASOP_Util_Divide3232_Scale( out_tmp_fx, path_dist_fx, &q_format_n ); // Q22/Q.22
649 198 : product = Mpy_32_32( one_minus_abs_coeff, out_tmp_div_path_dist ); // Q.30 *Q.15
650 198 : product = L_shl( product, q_format_n ); // Q14
651 198 : product = L_shl( product, Q8 ); // Q22
652 :
653 198 : pro_pd_air_coeff = Mpy_32_32( path_dist_fx, obj->air_coeff_fx ); // Q.22 *Q.31 =Q.22
654 198 : result_gain = L_sub( product, pro_pd_air_coeff );
655 198 : ER_PARAMS->gains.data_fx[rcoselev - 1] = result_gain; // Q22
656 198 : move32();
657 : }
658 : }
659 3 : return;
660 : }
|