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 "prot_fx.h"
37 : #include "rom_dec.h"
38 : #include "lib_rend.h"
39 : #include "ivas_prot_rend_fx.h"
40 : #include "ivas_stat_rend.h"
41 : #include "ivas_cnst.h"
42 : #include "ivas_rom_com.h"
43 : #include "wmc_auto.h"
44 : #include "debug.h"
45 :
46 :
47 : /*-----------------------------------------------------------------------------------------*
48 : * Local constants/tabels
49 : *-----------------------------------------------------------------------------------------*/
50 :
51 : #define ER_NUM_REF 6
52 :
53 : static UWord16 LC_mixing_5_1[5] = { 0, 1, 2, 0, 1 };
54 :
55 : static UWord16 LC_mixing_7_1[7] = { 0, 1, 2, 3, 4, 3, 4 };
56 :
57 : static UWord16 LC_mixing_5_1_2[7] = { 0, 1, 2, 3, 4, 0, 1 };
58 :
59 : static UWord16 LC_mixing_5_1_4[9] = { 0, 1, 2, 3, 4, 0, 1, 3, 4 };
60 :
61 : static UWord16 LC_mixing_7_1_4[11] = { 0, 1, 2, 3, 4, 3, 4, 0, 1, 3, 4 };
62 :
63 :
64 : /*-----------------------------------------------------------------------------------------*
65 : * Function ivas_er_init()
66 : *
67 : * Initializes the reflections data structure according to the requested input config.
68 : *-----------------------------------------------------------------------------------------*/
69 :
70 4 : ivas_error ivas_er_init(
71 : er_struct_t *reflections,
72 : const AUDIO_CONFIG inConfig )
73 : {
74 : ivas_error error;
75 : UWord8 i;
76 :
77 : /* Set to defaults for shoebox */
78 4 : reflections->is_ready = 0;
79 4 : move16();
80 4 : reflections->audio_config = IVAS_AUDIO_CONFIG_INVALID;
81 4 : move16();
82 4 : reflections->is_cartesian = 0;
83 4 : move16();
84 4 : reflections->is_relative = 1;
85 4 : move16();
86 4 : reflections->shoebox_data.n_ref = ER_NUM_REF;
87 4 : move16();
88 :
89 : /* Store scene origin if present */
90 :
91 16 : FOR( i = 0; i < 3; i++ )
92 : {
93 12 : reflections->user_origin_fx[i] = reflections->shoebox_lib.cal.list_orig_fx[i]; // Q.22
94 12 : move32();
95 : }
96 :
97 : /* Init Shoebox */
98 4 : ivas_shoebox_init( &reflections->shoebox_lib, &reflections->shoebox_lib.cal );
99 :
100 : /* Set mode */
101 4 : IF( NE_32( ( error = ivas_er_set_reflections_mode( reflections, inConfig ) ), IVAS_ERR_OK ) )
102 : {
103 0 : return error;
104 : }
105 :
106 : /* Compute the static reflections (first frame) */
107 4 : IF( NE_32( ( error = ivas_er_compute_reflections( reflections ) ), IVAS_ERR_OK ) )
108 : {
109 0 : return error;
110 : }
111 :
112 4 : IF( ( reflections->closest_ch_idx = (UWord16 *) malloc( reflections->n_total_reflections * sizeof( UWord16 ) ) ) == NULL )
113 : {
114 0 : return IVAS_ERR_FAILED_ALLOC;
115 : }
116 4 : set16_fx( (Word16 *) reflections->closest_ch_idx, 0, reflections->n_total_reflections );
117 :
118 4 : IF( NE_32( ( error = getAudioConfigNumChannels( reflections->audio_config, &( reflections->nchan_out ) ) ), IVAS_ERR_OK ) )
119 : {
120 0 : return error;
121 : }
122 :
123 : /* Initialize Encoder */
124 4 : IF( NE_32( ( error = ivas_er_encoder_init( reflections ) ), IVAS_ERR_OK ) )
125 : {
126 0 : return error;
127 : }
128 :
129 : /* Update flag to indicate that reflection module is ready to process */
130 4 : reflections->is_ready = 1;
131 4 : move16();
132 :
133 4 : return error;
134 : }
135 :
136 :
137 : /*-----------------------------------------------------------------------------------------*
138 : Function ivas_er_set_reflections_mode()
139 :
140 : Function sets the ER source positions based on the audio config
141 : *-----------------------------------------------------------------------------------------*/
142 :
143 4 : ivas_error ivas_er_set_reflections_mode(
144 : er_struct_t *reflections,
145 : const AUDIO_CONFIG inConfig )
146 : {
147 : ivas_error error;
148 : UWord16 ch;
149 4 : error = IVAS_ERR_OK;
150 4 : move32();
151 :
152 4 : IF( EQ_32( reflections->audio_config, inConfig ) )
153 : {
154 0 : return error;
155 : }
156 :
157 4 : reflections->is_ready = 0;
158 4 : move16();
159 4 : reflections->audio_config = inConfig;
160 :
161 4 : SWITCH( reflections->audio_config )
162 : {
163 0 : case IVAS_AUDIO_CONFIG_MONO:
164 0 : reflections->shoebox_data.n_sources = 1;
165 0 : reflections->n_LC_sources = 1;
166 0 : reflections->LC_mixing = LC_mixing_5_1; /*Q0*/
167 0 : move16();
168 0 : move16();
169 0 : move16();
170 :
171 0 : reflections->source_positions_fx[0] = 0;
172 0 : reflections->source_positions_fx[1] = 0;
173 0 : reflections->source_positions_fx[2] = ER_RADIUS_FX;
174 0 : move32();
175 0 : move32();
176 0 : move32();
177 0 : BREAK;
178 0 : case IVAS_AUDIO_CONFIG_STEREO:
179 0 : reflections->shoebox_data.n_sources = 2;
180 0 : reflections->n_LC_sources = 2;
181 0 : reflections->LC_mixing = LC_mixing_5_1; /*Q0*/
182 0 : move16();
183 0 : move16();
184 0 : move16();
185 :
186 0 : FOR( ch = 0; ch < reflections->shoebox_data.n_sources; ch++ )
187 : {
188 0 : reflections->source_positions_fx[i_mult( 3, ch )] = ls_azimuth_CICP2_idx[ch]; /*Q0*/
189 0 : reflections->source_positions_fx[add( 1, i_mult( 3, ch ) )] = ls_elevation_CICP2_idx[ch]; /*Q0*/
190 0 : reflections->source_positions_fx[add( 2, i_mult( 3, ch ) )] = ER_RADIUS_FX;
191 0 : move32();
192 0 : move32();
193 0 : move32();
194 : }
195 0 : BREAK;
196 1 : case IVAS_AUDIO_CONFIG_5_1:
197 1 : reflections->shoebox_data.n_sources = 5;
198 1 : reflections->n_LC_sources = 3;
199 1 : reflections->LC_mixing = LC_mixing_5_1; /*Q0*/
200 1 : move16();
201 1 : move16();
202 1 : move16();
203 :
204 6 : FOR( ch = 0; ch < reflections->shoebox_data.n_sources; ch++ )
205 : {
206 5 : reflections->source_positions_fx[i_mult( 3, ch )] = ls_azimuth_CICP6_idx[ch]; /*Q0*/
207 5 : reflections->source_positions_fx[add( 1, i_mult( 3, ch ) )] = ls_elevation_CICP6_idx[ch]; /*Q0*/
208 5 : reflections->source_positions_fx[add( 2, i_mult( 3, ch ) )] = ER_RADIUS_FX;
209 5 : move32();
210 5 : move32();
211 5 : move32();
212 : }
213 1 : BREAK;
214 0 : case IVAS_AUDIO_CONFIG_7_1:
215 0 : reflections->shoebox_data.n_sources = 7;
216 0 : reflections->n_LC_sources = 5;
217 0 : reflections->LC_mixing = LC_mixing_7_1; /*Q0*/
218 0 : move16();
219 0 : move16();
220 0 : move16();
221 0 : FOR( ch = 0; ch < reflections->shoebox_data.n_sources; ch++ )
222 : {
223 0 : reflections->source_positions_fx[i_mult( 3, ch )] = ls_azimuth_CICP12_idx[ch]; /*Q0*/
224 0 : reflections->source_positions_fx[add( 1, i_mult( 3, ch ) )] = ls_elevation_CICP12_idx[ch]; /*Q0*/
225 0 : reflections->source_positions_fx[add( 2, i_mult( 3, ch ) )] = ER_RADIUS_FX;
226 0 : move32();
227 0 : move32();
228 0 : move32();
229 : }
230 0 : BREAK;
231 0 : case IVAS_AUDIO_CONFIG_5_1_2:
232 0 : reflections->shoebox_data.n_sources = 7;
233 0 : reflections->n_LC_sources = 5;
234 0 : reflections->LC_mixing = LC_mixing_5_1_2; /*Q0*/
235 0 : move16();
236 0 : move16();
237 0 : move16();
238 0 : FOR( ch = 0; ch < reflections->shoebox_data.n_sources; ch++ )
239 : {
240 0 : reflections->source_positions_fx[i_mult( 3, ch )] = ls_azimuth_CICP14_idx[ch]; /*Q0*/
241 0 : reflections->source_positions_fx[add( 1, i_mult( 3, ch ) )] = ls_elevation_CICP14_idx[ch]; /*Q0*/
242 0 : reflections->source_positions_fx[add( 2, i_mult( 3, ch ) )] = ER_RADIUS_FX;
243 0 : move32();
244 0 : move32();
245 0 : move32();
246 : }
247 0 : BREAK;
248 0 : case IVAS_AUDIO_CONFIG_5_1_4:
249 0 : reflections->shoebox_data.n_sources = 9;
250 0 : reflections->n_LC_sources = 5;
251 0 : reflections->LC_mixing = LC_mixing_5_1_4; /*Q0*/
252 0 : move16();
253 0 : move16();
254 0 : move16();
255 0 : FOR( ch = 0; ch < reflections->shoebox_data.n_sources; ch++ )
256 : {
257 0 : reflections->source_positions_fx[i_mult( 3, ch )] = ls_azimuth_CICP16_idx[ch]; /*Q0*/
258 0 : reflections->source_positions_fx[add( 1, i_mult( 3, ch ) )] = ls_elevation_CICP16_idx[ch]; /*Q0*/
259 0 : reflections->source_positions_fx[add( 2, i_mult( 3, ch ) )] = ER_RADIUS_FX;
260 0 : move32();
261 0 : move32();
262 0 : move32();
263 : }
264 0 : BREAK;
265 3 : case IVAS_AUDIO_CONFIG_7_1_4:
266 3 : reflections->shoebox_data.n_sources = 11;
267 3 : reflections->n_LC_sources = 5;
268 3 : reflections->LC_mixing = LC_mixing_7_1_4; /*Q0*/
269 3 : move16();
270 3 : move16();
271 3 : move16();
272 36 : FOR( ch = 0; ch < reflections->shoebox_data.n_sources; ch++ )
273 : {
274 33 : reflections->source_positions_fx[i_mult( 3, ch )] = ls_azimuth_CICP19_idx[ch]; /*Q0*/
275 33 : reflections->source_positions_fx[add( 1, i_mult( 3, ch ) )] = ls_elevation_CICP19_idx[ch]; /*Q0*/
276 33 : reflections->source_positions_fx[add( 2, i_mult( 3, ch ) )] = ER_RADIUS_FX;
277 33 : move32();
278 33 : move32();
279 33 : move32();
280 : }
281 3 : BREAK;
282 0 : case IVAS_AUDIO_CONFIG_HOA3:
283 0 : reflections->use_er = 0;
284 0 : move16();
285 0 : BREAK;
286 0 : case IVAS_AUDIO_CONFIG_HOA2:
287 0 : reflections->use_er = 0;
288 0 : move16();
289 0 : BREAK;
290 0 : case IVAS_AUDIO_CONFIG_FOA:
291 0 : reflections->use_er = 0;
292 0 : move16();
293 0 : BREAK;
294 0 : default:
295 0 : reflections->audio_config = IVAS_AUDIO_CONFIG_INVALID;
296 0 : return IVAS_ERROR( IVAS_ERR_INVALID_ER_PARAM, "Unsupported reflections mode" );
297 : }
298 :
299 4 : return error;
300 : }
301 :
302 :
303 : /*-----------------------------------------------------------------------------------------*
304 : Function ivas_er_encoder_init()
305 :
306 : Function that initializes the er encoder
307 : *-----------------------------------------------------------------------------------------*/
308 :
309 4 : ivas_error ivas_er_encoder_init(
310 : er_struct_t *reflections )
311 : {
312 4 : ivas_error error = IVAS_ERR_OK;
313 : Word16 i, j, src_idx;
314 4 : Word16 min_index_fx = 0;
315 4 : move16();
316 :
317 : Word32 rad_el_angle, rad_az_angle, tmp_data_fx, p_x_src_fx, p_y_src_fx, p_z_src_fx;
318 : Word16 el_angle_cos, az_angle_cos, el_angle_sin, az_angle_sin;
319 4 : Word32 p_x_fx, p_y_fx, p_z_fx, tmp_fx, tmp_data, dist_fx, min_dist_fx = 0;
320 4 : move32();
321 : Word32 *src_pos_ptr_fx;
322 4 : Word16 q_format, tmp16, min_qformat = 0;
323 4 : move16();
324 :
325 :
326 4 : IF( reflections == NULL )
327 : {
328 0 : return IVAS_ERR_FAILED_ALLOC;
329 : }
330 :
331 4 : IF( EQ_32( getAudioConfigType( reflections->audio_config ), IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) )
332 : {
333 : /* Compute MC-snap location (closest channel position to reflection direction) */
334 232 : FOR( i = 0; i < reflections->n_total_reflections; i++ )
335 : {
336 : /* Compute cartesian points for reflection (from degrees) */
337 :
338 228 : p_x_fx = reflections->shoebox_data.el_angle.data_fx[i]; // Q23
339 228 : p_y_fx = reflections->shoebox_data.az_angle.data_fx[i]; // Q23
340 228 : move32();
341 228 : move32();
342 228 : p_x_fx = L_shr( p_x_fx, 1 ); // Q22
343 228 : p_y_fx = L_shr( p_y_fx, 1 ); // Q22
344 228 : rad_el_angle = deg2rad_fx( p_x_fx ); // Q22
345 228 : rad_az_angle = deg2rad_fx( p_y_fx ); // Q22
346 :
347 228 : rad_el_angle = L_shl( rad_el_angle, 1 ); // Q23
348 228 : rad_az_angle = L_shl( rad_az_angle, 1 ); // Q23
349 :
350 228 : rad_el_angle = L_shr( rad_el_angle, 10 ); // Q13
351 228 : rad_az_angle = L_shr( rad_az_angle, 10 ); // Q13
352 228 : el_angle_cos = getCosWord16( extract_l( rad_el_angle ) ); // Q14
353 228 : az_angle_cos = getCosWord16( extract_l( rad_az_angle ) ); // Q14
354 :
355 :
356 228 : el_angle_sin = getSinWord16( extract_l( rad_el_angle ) ); // In:Q13, O/p: Q:15
357 228 : az_angle_sin = getSinWord16( extract_l( rad_az_angle ) ); // In:Q13, O/p: Q:15
358 :
359 :
360 228 : p_x_fx = L_shl( mult( el_angle_cos, az_angle_cos ), 1 ); // Q.14 *Q.14= Q13
361 228 : p_y_fx = mult( el_angle_cos, az_angle_sin ); // Q.14 *Q.15= Q.14
362 : // Multiplicatio with ER_RADIUS is ignored , as ER_RADIUS=1;
363 228 : p_z_fx = L_shr( el_angle_sin, 1 ); //// Q.15
364 :
365 :
366 : /* Calculate the euclidean distance to each point in the config ls setup */
367 2784 : FOR( j = 0; j < reflections->nchan_out; j++ )
368 : {
369 : /* Ignore LFE */
370 2556 : IF( NE_16( j, LFE_CHANNEL ) )
371 : {
372 2328 : src_idx = GT_16( j, LFE_CHANNEL ) ? sub( j, 1 ) : j;
373 :
374 2328 : src_pos_ptr_fx = &reflections->source_positions_fx[src_idx * 3 + 0];
375 2328 : move32();
376 :
377 2328 : tmp_data_fx = Mpy_32_32( shoebox_sin_cos_tbl_fx[( src_pos_ptr_fx[1] )][1], shoebox_sin_cos_tbl_fx[( src_pos_ptr_fx[0] )][1] ); //.29 = .30 * .30
378 2328 : p_x_src_fx = Mpy_32_32( src_pos_ptr_fx[2], tmp_data_fx ); // .28 =.29*.30
379 2328 : tmp_data_fx = Mpy_32_32( shoebox_sin_cos_tbl_fx[( src_pos_ptr_fx[1] )][1], shoebox_sin_cos_tbl_fx[( src_pos_ptr_fx[0] )][0] ); //.29 = .30 * .30
380 2328 : p_y_src_fx = Mpy_32_32( src_pos_ptr_fx[2], tmp_data_fx ); // .28 =.29*.30
381 2328 : p_z_src_fx = Mpy_32_32( src_pos_ptr_fx[2], shoebox_sin_cos_tbl_fx[( src_pos_ptr_fx[1] )][0] ); //.29 = .30 * .30
382 :
383 2328 : p_x_src_fx = L_shr( p_x_src_fx, 14 ); // Q.14
384 2328 : p_y_src_fx = L_shr( p_y_src_fx, 14 ); // Q.14
385 2328 : p_z_src_fx = L_shr( p_z_src_fx, 15 ); // Q.14
386 :
387 2328 : tmp_data = L_sub( p_x_src_fx, p_x_fx );
388 2328 : tmp16 = extract_l( tmp_data ); // Q.14
389 2328 : tmp16 = shr( tmp16, 1 ); // Q.13
390 2328 : tmp_fx = L_mult( tmp16, tmp16 ); // Q.27
391 :
392 2328 : tmp_data = L_sub( p_y_src_fx, p_y_fx );
393 2328 : tmp16 = extract_l( tmp_data ); // Q.14
394 2328 : tmp16 = shr( tmp16, 1 ); // Q.13
395 2328 : tmp_fx = L_mac( tmp_fx, tmp16, tmp16 ); // Q.27
396 :
397 :
398 2328 : tmp_data = L_sub( p_z_src_fx, p_z_fx );
399 2328 : tmp16 = extract_l( tmp_data ); // Q.14
400 2328 : tmp16 = shr( tmp16, 1 ); // Q.13
401 2328 : tmp_fx = L_mac( tmp_fx, tmp16, tmp16 ); // Q.27
402 2328 : q_format = Q31 - Q27;
403 2328 : move16();
404 2328 : dist_fx = Sqrt32( tmp_fx, &q_format );
405 2328 : if ( dist_fx == 0 )
406 : {
407 14 : q_format = 0;
408 14 : move16();
409 : }
410 2328 : IF( q_format <= 0 )
411 : {
412 635 : dist_fx = L_shl( dist_fx, q_format ); // Q31
413 635 : q_format = 0;
414 635 : move16();
415 : }
416 : /* Save index of closest channel */
417 2328 : IF( src_idx == 0 )
418 : {
419 228 : min_dist_fx = dist_fx;
420 228 : min_qformat = q_format;
421 228 : min_index_fx = j;
422 228 : move32();
423 228 : move16();
424 228 : move16();
425 : }
426 : ELSE
427 : {
428 2100 : IF( LE_16( q_format, min_qformat ) )
429 : {
430 1292 : IF( EQ_16( q_format, min_qformat ) )
431 : {
432 1174 : IF( LT_32( dist_fx, min_dist_fx ) )
433 : {
434 333 : min_dist_fx = dist_fx;
435 333 : min_index_fx = j;
436 333 : move32();
437 333 : move16();
438 : }
439 : }
440 : ELSE
441 : {
442 118 : min_dist_fx = dist_fx;
443 118 : min_index_fx = j;
444 118 : min_qformat = q_format;
445 118 : move32();
446 118 : move16();
447 118 : move16();
448 : }
449 : }
450 : }
451 : }
452 : }
453 :
454 228 : reflections->closest_ch_idx[i] = (UWord16) min_index_fx;
455 228 : move16();
456 : }
457 : }
458 :
459 4 : return error;
460 : }
461 :
462 :
463 : /*-----------------------------------------------------------------------------------------*
464 : Function ivas_er_compute_reflections()
465 :
466 : Function computes reflections using the shoebox library and sets up the circular buffers
467 : structure for the early reflections process
468 : *-----------------------------------------------------------------------------------------*/
469 4 : ivas_error ivas_er_compute_reflections(
470 : er_struct_t *reflections )
471 : {
472 4 : ivas_error error = IVAS_ERR_OK;
473 : UWord16 circ_len, i, j;
474 : UWord32 tmp_fx, tmp_fx1;
475 : UWord16 tmp_fx_lo;
476 :
477 4 : reflections->is_ready = 0;
478 4 : move16();
479 :
480 : /* Disabled case */
481 4 : IF( EQ_32( reflections->audio_config, IVAS_AUDIO_CONFIG_INVALID ) )
482 : {
483 0 : return error;
484 : }
485 :
486 : /* Run shoebox with current reflection parameters */
487 4 : ivas_shoebox_set_scene( &( reflections->shoebox_lib ), &( reflections->shoebox_data ), reflections->shoebox_lib.cal.list_orig_fx,
488 4 : reflections->source_positions_fx, reflections->is_cartesian, reflections->is_relative );
489 : /* Convert reflection times in seconds to samples and keep track of max */
490 4 : circ_len = 0;
491 4 : move16();
492 :
493 42 : FOR( i = 0; i < reflections->shoebox_data.n_sources; i++ )
494 : {
495 266 : FOR( j = 0; j < reflections->shoebox_data.n_ref; j++ )
496 : {
497 228 : tmp_fx = reflections->shoebox_data.times.data_fx[add( j, i_mult( i, reflections->shoebox_data.n_ref ) )]; // Q23
498 228 : tmp_fx_lo = u_extract_l( tmp_fx );
499 228 : Mpy_32_16_uu( tmp_fx, (UWord16) reflections->output_Fs_fx, &tmp_fx1, &tmp_fx_lo );
500 228 : tmp_fx1 = (UWord32) L_add( tmp_fx1, 0x20 );
501 228 : tmp_fx1 = L_shr( tmp_fx1, 6 );
502 228 : reflections->shoebox_data.times.data_fx[add( j, i_mult( i, reflections->shoebox_data.n_ref ) )] = tmp_fx1;
503 228 : move32();
504 : // circ_len = ( (UWord16) tmp_fx1 > circ_len ) ? (UWord16) tmp_fx1 : circ_len;
505 228 : IF( GT_32( u_extract_l( tmp_fx1 ), circ_len ) )
506 : {
507 12 : circ_len = u_extract_l( tmp_fx1 );
508 : }
509 : }
510 : }
511 :
512 :
513 : /* If max delay is less than max frame size, use max frame size to compute circ buffer length */
514 4 : IF( LE_32( circ_len, u_extract_l( reflections->max_frame_size ) ) )
515 : {
516 2 : circ_len = u_extract_l( reflections->max_frame_size );
517 : }
518 :
519 4 : circ_len = u_extract_l( UL_addNsD( circ_len, reflections->max_frame_size ) );
520 :
521 : /* If circ buffers exist and size is the same, reset memory to all zeros */
522 : /* If size is different, reallocate circ buffers */
523 : /* Otherwise allocate new circ buffers */
524 :
525 604 : FOR( i = 0; i < 150; i++ )
526 : {
527 600 : reflections->shoebox_data.gains.data_fx[i] = L_shl( reflections->shoebox_data.gains.data_fx[i], 9 );
528 : }
529 4 : IF( reflections->circ_buffers )
530 : {
531 0 : IF( EQ_32( reflections->circ_len, circ_len ) )
532 : {
533 : /* circ buffers exist and size is the same */
534 0 : set32_fx( reflections->circ_buffers, 0, i_mult( reflections->shoebox_data.n_sources, reflections->circ_len ) );
535 : }
536 : ELSE
537 : {
538 : /* circ buffers exist but size is different */
539 0 : reflections->circ_len = circ_len;
540 0 : move16();
541 0 : free( reflections->circ_buffers );
542 0 : IF( ( reflections->circ_buffers = (Word32 *) malloc( i_mult( reflections->shoebox_data.n_sources, reflections->circ_len ) * sizeof( Word32 ) ) ) == NULL )
543 : {
544 0 : return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Early Reflections buffers" );
545 : }
546 0 : set32_fx( reflections->circ_buffers, 0, reflections->shoebox_data.n_sources * reflections->circ_len );
547 : }
548 : }
549 : ELSE
550 : {
551 : /* circ buffers do not exist */
552 4 : reflections->circ_len = circ_len;
553 4 : move16();
554 4 : IF( ( reflections->circ_buffers = (Word32 *) malloc( i_mult( reflections->shoebox_data.n_sources, reflections->circ_len ) * sizeof( Word32 ) ) ) == NULL )
555 : {
556 0 : return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Early Reflections buffers" );
557 : }
558 4 : set32_fx( reflections->circ_buffers, 0, reflections->shoebox_data.n_sources * reflections->circ_len );
559 : }
560 :
561 : /* Initialize circular buffer insertion point */
562 4 : reflections->circ_insert = u_extract_l( UL_subNsD( reflections->circ_len, reflections->max_frame_size ) );
563 :
564 : /* Get total reflections number */
565 4 : reflections->n_total_reflections = (UWord16) i_mult( reflections->shoebox_data.n_sources, reflections->shoebox_data.n_ref );
566 4 : move16();
567 :
568 : /* Check that reflection buffers were allocated */
569 4 : IF( NE_32( error, IVAS_ERR_OK ) )
570 : {
571 0 : return error;
572 : }
573 :
574 4 : return error;
575 : }
576 :
577 :
578 : /*-----------------------------------------------------------------------------------------*
579 : Function ivas_er_process()
580 :
581 : Takes a buffer of N channels, returns a buffer of N*6 channels containing the early
582 : reflections (one per wall). The process is a delay line architecture
583 : *-----------------------------------------------------------------------------------------*/
584 :
585 :
586 5800 : ivas_error ivas_er_process(
587 : er_struct_t *reflections,
588 : const Word16 subframe_size,
589 : const Word16 subframe_idx,
590 : Word32 **io, /*Q11*/
591 : const AUDIO_CONFIG inConfig )
592 : {
593 5800 : ivas_error error = IVAS_ERR_OK;
594 : UWord16 i, j, k, subframe_offset;
595 : UWord16 ref_no, ref_delay;
596 : UWord16 n_ref_sources, n_ref;
597 : Word16 samp_idx, in_ch_idx, buf_ch_idx, ref_out_idx;
598 : Word32 ref_gain;
599 : Word32 *buffer_ch;
600 : Word32 temp;
601 :
602 5800 : IF( !reflections )
603 : {
604 0 : return IVAS_ERR_INIT_ERROR;
605 : }
606 :
607 : /* should not arrive here if reflections are disabled but in case it does just do nothing */
608 5800 : IF( NE_32( reflections->use_er, 1 ) )
609 : {
610 0 : return error;
611 : }
612 :
613 : /* Ensure all reflection memory is allocated */
614 5800 : test();
615 5800 : IF( !reflections->circ_buffers || !reflections->is_ready )
616 : {
617 0 : return IVAS_ERR_INIT_ERROR;
618 : }
619 5800 : subframe_offset = subframe_idx * subframe_size;
620 5800 : move16();
621 5800 : n_ref = reflections->shoebox_data.n_ref;
622 5800 : move16();
623 :
624 : /* If low complexity ER are requested only compute ER for n_LC_sources */
625 5800 : IF( reflections->lowComplexity )
626 : {
627 4600 : n_ref_sources = reflections->n_LC_sources; // Q0
628 4600 : move16();
629 : }
630 : ELSE
631 : {
632 1200 : n_ref_sources = reflections->shoebox_data.n_sources; // Q0
633 1200 : move16();
634 : }
635 :
636 : /* Channel case, copy input into buffers panning for LC mode and skipping LFE */
637 5800 : IF( EQ_32( getAudioConfigType( inConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) )
638 : {
639 : /* Loop through all input sources filling circular buffers */
640 45600 : FOR( i = 0; i < reflections->shoebox_data.n_sources; i++ )
641 : {
642 : /* Pull correct circular buffer depending on complexity mode */
643 : // buf_ch_idx = ( reflections->lowComplexity == 1 ) ? reflections->LC_mixing[i] : i;
644 39800 : IF( EQ_32( reflections->lowComplexity, 1 ) )
645 : {
646 26600 : buf_ch_idx = reflections->LC_mixing[i]; // Q0
647 26600 : move16();
648 : }
649 : ELSE
650 : {
651 13200 : buf_ch_idx = i;
652 13200 : move16();
653 : }
654 39800 : buffer_ch = &( reflections->circ_buffers[i_mult( buf_ch_idx, reflections->circ_len )] );
655 :
656 : /* Skip LFE from input buffer */
657 : // in_ch_idx = ( i >= LFE_CHANNEL ) ? i + 1 : i;
658 39800 : IF( GE_32( i, LFE_CHANNEL ) )
659 : {
660 22400 : in_ch_idx = add( i, 1 );
661 : }
662 : ELSE
663 : {
664 17400 : in_ch_idx = i;
665 17400 : move16();
666 : }
667 39800 : samp_idx = reflections->circ_insert;
668 39800 : move16();
669 :
670 : /* If less than number of reflection sources, overwrite buffer */
671 39800 : IF( EQ_32( i, buf_ch_idx ) )
672 : {
673 6796200 : FOR( j = 0; j < subframe_size; j++ )
674 : {
675 6768000 : buffer_ch[samp_idx] = io[in_ch_idx][add( j, subframe_offset )];
676 6768000 : move32();
677 6768000 : samp_idx = add( samp_idx, 1 );
678 6768000 : samp_idx = samp_idx % reflections->circ_len;
679 : }
680 : }
681 : /* Accumulate with buffer for low complexity mixed sources */
682 : ELSE
683 : {
684 2795600 : FOR( j = 0; j < subframe_size; j++ )
685 : {
686 2784000 : buffer_ch[samp_idx] = L_add( io[in_ch_idx][add( j, subframe_offset )], buffer_ch[samp_idx] );
687 2784000 : move32();
688 2784000 : samp_idx = add( samp_idx, 1 );
689 2784000 : samp_idx = samp_idx % reflections->circ_len;
690 : }
691 : }
692 : }
693 : }
694 : ELSE
695 : {
696 0 : return IVAS_ERR_INVALID_INPUT_FORMAT;
697 : }
698 :
699 : /* Loop through sources retrieve reflections from circ buffers */
700 34000 : FOR( i = 0; i < n_ref_sources; i++ )
701 : {
702 : /* Access correct row of input circ buffer */
703 28200 : buffer_ch = &( reflections->circ_buffers[i_mult( i, reflections->circ_len )] );
704 :
705 : /* Loop through reflections */
706 197400 : FOR( j = 0; j < n_ref; j++ )
707 : {
708 169200 : ref_no = (UWord16) add( j, i_mult( i, n_ref ) );
709 169200 : move16();
710 169200 : ref_gain = (Word32) reflections->shoebox_data.gains.data_fx[ref_no];
711 169200 : move32();
712 169200 : ref_delay = (UWord16) reflections->shoebox_data.times.data_fx[ref_no];
713 169200 : move16();
714 169200 : ref_out_idx = reflections->closest_ch_idx[ref_no];
715 169200 : move16();
716 :
717 : /* Determine start idx of reflection in circ buffer based on
718 : current insert idx and reflection delay */
719 169200 : samp_idx = sub( reflections->circ_insert, ref_delay );
720 169200 : if ( LT_16( samp_idx, 0 ) )
721 : {
722 52758 : samp_idx = add( reflections->circ_len, samp_idx );
723 : }
724 :
725 : /* Pull reflection from circ buffer and apply gain */
726 40777200 : FOR( k = 0; k < subframe_size; k++ )
727 : {
728 40608000 : temp = Mpy_32_32( buffer_ch[samp_idx], ref_gain );
729 40608000 : io[ref_out_idx][add( k, subframe_offset )] = L_add( temp, io[ref_out_idx][add( k, subframe_offset )] );
730 40608000 : samp_idx = add( samp_idx, 1 );
731 40608000 : samp_idx = samp_idx % reflections->circ_len;
732 : }
733 : }
734 : }
735 :
736 : /* Increment circular buffer start index */
737 5800 : reflections->circ_insert = (UWord16) ( add( reflections->circ_insert, subframe_size ) ) % reflections->circ_len;
738 5800 : move16();
739 5800 : return error;
740 : }
|