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