LCOV - code coverage report
Current view: top level - lib_rend - ivas_reflections_fx.c (source / functions) Hit Total Coverage
Test: Coverage on main @ 22b74eaeaa63d28e0fcc8ed21c8f7c451f461847 Lines: 248 359 69.1 %
Date: 2025-10-19 02:52:40 Functions: 5 5 100.0 %

          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             : }

Generated by: LCOV version 1.14