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