LCOV - code coverage report
Current view: top level - lib_rend - ivas_reflections_fx.c (source / functions) Hit Total Coverage
Test: Coverage on main enc/dec/rend @ 3b2f07138c61dcf997bbf4165d0882f794b2995f Lines: 229 355 64.5 %
Date: 2025-05-03 01:55:50 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             : #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             : }

Generated by: LCOV version 1.14