LCOV - code coverage report
Current view: top level - lib_enc - ivas_masa_enc_fx.c (source / functions) Hit Total Coverage
Test: Coverage on main @ e95243e9e67ddeb69dddf129509de1b3d95b402e Lines: 2303 2585 89.1 %
Date: 2025-09-14 03:13:15 Functions: 33 34 97.1 %

          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 <stdint.h>
      34             : #include <math.h>
      35             : #include "options.h"
      36             : #include "ivas_cnst.h"
      37             : #include "ivas_rom_com.h"
      38             : #include "ivas_stat_enc.h"
      39             : #include "wmc_auto.h"
      40             : #include "prot_fx.h"
      41             : #include "prot_fx_enc.h"
      42             : #include "ivas_prot_fx.h"
      43             : #include "ivas_rom_com_fx.h"
      44             : 
      45             : 
      46             : /*-----------------------------------------------------------------------*
      47             :  * Local function prototypes
      48             :  *-----------------------------------------------------------------------*/
      49             : 
      50             : static void combine_freqbands_and_subframes_fx( MASA_ENCODER_HANDLE hMasa );
      51             : 
      52             : static void find_n_largest_fx( const Word32 *input_fx, Word16 exp_input, Word16 *largestIndices, const Word16 numElements, const Word16 numLargest );
      53             : 
      54             : static void move_metadata_to_qmetadata_fx( const MASA_ENCODER_HANDLE hMasa, IVAS_QMETADATA_HANDLE hQMeta );
      55             : 
      56             : static void detect_metadata_composition_fx(
      57             :     const MASA_ENCODER_HANDLE hMasa, /* i  : MASA encoder data              */
      58             :     UWord8 *joinedSubframes,         /* o  : Result of subframe composition */
      59             :     UWord8 *coherencePresent,        /* o  : Result of coherence presence   */
      60             :     UWord8 *isTwoDir                 /* o  : Result of two direction check  */
      61             : );
      62             : 
      63             : static void compensate_energy_ratios_fx( MASA_ENCODER_HANDLE hMasa );
      64             : 
      65             : static Word16 encode_lfe_to_total_energy_ratio_fx( MASA_ENCODER_HANDLE hMasa, BSTR_ENC_HANDLE hMetaData, const Word32 ivas_total_brate );
      66             : 
      67             : static void ivas_encode_masaism_metadata_fx( MASA_ENCODER_HANDLE hMasa, IVAS_QMETADATA_HANDLE hQMetaData, BSTR_ENC_HANDLE hMetaData, ISM_METADATA_HANDLE hIsmMeta[], const Word16 nchan_ism, const Word16 low_bitrate_mode, const Word16 omasa_nbands, const Word16 omasa_nblocks, const Word16 idx_separated_object, const Word16 ism_imp );
      68             : 
      69             : static void reduce_metadata_further_fx( MASA_ENCODER_HANDLE hMasa, IVAS_QMETADATA_HANDLE hqmetadata, const IVAS_FORMAT ivas_format );
      70             : 
      71             : static void average_masa_metadata_fx(
      72             :     MASA_METADATA_FRAME *hMeta,
      73             :     Word32 energy[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS],
      74             :     Word16 energy_e[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS],
      75             :     const SPHERICAL_GRID_DATA *Sph_Grid16,
      76             :     const UWord8 useSphGrid );
      77             : 
      78             : static void copy_masa_metadata_subframe_fx(
      79             :     const MASA_METADATA_HANDLE hMetaFrom, /* i  : MASA frame metdata to be copied      */
      80             :     const UWord8 sfFrom,                  /* i  : subframe index of the copy source    */
      81             :     MASA_METADATA_HANDLE hMetaTo,         /* o  : MASA frame metadata copy destination */
      82             :     const UWord8 sfTo                     /* i  : subframe index of the copy target    */
      83             : );
      84             : 
      85             : static void copy_masa_metadata_fx( const MASA_METADATA_HANDLE hMetaFrom, MASA_METADATA_HANDLE hMetaTo );
      86             : 
      87             : static UWord8 are_masa_subframes_similar_fx(
      88             :     const MASA_METADATA_HANDLE frame1, /* i  : MASA metadata frame 1                      */
      89             :     const UWord8 sf1_idx,              /* i  : index of the subframe of frame1 to inspect */
      90             :     const MASA_METADATA_HANDLE frame2, /* i  : MASA metadata frame 2                      */
      91             :     const UWord8 sf2_idx               /* i  : index of the subframe of frame2 to inspect */
      92             : );
      93             : 
      94             : static void detect_framing_async_fx(
      95             :     MASA_ENCODER_HANDLE hMasa /* i/o: MASA encoder structure */
      96             : );
      97             : 
      98             : static void masa_metadata_direction_alignment_fx( MASA_ENCODER_HANDLE hMasa );
      99             : 
     100             : 
     101             : /*-----------------------------------------------------------------------*
     102             :  * Local constants
     103             :  *-----------------------------------------------------------------------*/
     104             : 
     105             : #define LOWBITRATE_ONSET_ALPHA     0.2f /* Onset values are for processing in frames */
     106             : #define LOWBITRATE_ONSET_BETA      0.92f
     107             : #define LOWBITRATE_ONSET_GAIN      1.4f
     108             : #define LOWBITRATE_ONSET_ALPHA_Q31 429496730 /* Onset values are for processing in frames */
     109             : #define LOWBITRATE_ONSET_BETA_Q31  1975684956
     110             : #define LOWBITRATE_ONSET_GAIN_Q30  1503238554
     111             : #define LOWBITRATE_NUM_BANDS       5
     112             : 
     113             : 
     114             : /*-----------------------------------------------------------------------*
     115             :  * ivas_masa_enc_open()
     116             :  *
     117             :  * open and initialize MASA encoder
     118             :  *-----------------------------------------------------------------------*/
     119             : 
     120         416 : ivas_error ivas_masa_enc_open_fx(
     121             :     Encoder_Struct *st_ivas /* i/o: IVAS encoder handle          */
     122             : )
     123             : {
     124             :     Word16 i;
     125             :     MASA_ENCODER_HANDLE hMasa;
     126             :     ENCODER_CONFIG_HANDLE hEncoderConfig;
     127             :     ivas_error error;
     128             :     Word32 ism_total_brate;
     129             : 
     130         416 :     error = IVAS_ERR_OK;
     131         416 :     move32();
     132             : 
     133         416 :     IF( ( hMasa = (MASA_ENCODER_HANDLE) malloc( sizeof( MASA_ENCODER ) ) ) == NULL )
     134             :     {
     135           0 :         return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for MASA encoder\n" ) );
     136             :     }
     137             : 
     138         416 :     hEncoderConfig = st_ivas->hEncoderConfig;
     139             : 
     140         416 :     generate_gridEq_fx( &( hMasa->data.Sph_Grid16 ) );
     141             : 
     142         416 :     test();
     143         416 :     IF( EQ_32( hEncoderConfig->ivas_format, MASA_FORMAT ) || EQ_32( hEncoderConfig->ivas_format, MASA_ISM_FORMAT ) )
     144             :     {
     145         119 :         hMasa->data.num_Cldfb_instances = st_ivas->nchan_transport;
     146         119 :         move16();
     147             :     }
     148             :     ELSE
     149             :     {
     150         297 :         hMasa->data.num_Cldfb_instances = 0;
     151         297 :         move16();
     152             :     }
     153             : 
     154         623 :     FOR( i = 0; i < hMasa->data.num_Cldfb_instances; i++ )
     155             :     {
     156         207 :         IF( NE_32( ( error = openCldfb_ivas_fx( &( hMasa->data.cldfbAnaEnc[i] ), CLDFB_ANALYSIS, hEncoderConfig->input_Fs, CLDFB_PROTOTYPE_5_00MS, ENC ) ), IVAS_ERR_OK ) )
     157             :         {
     158           0 :             return error;
     159             :         }
     160             :     }
     161             : 
     162         416 :     ism_total_brate = 0;
     163         416 :     move32();
     164         416 :     test();
     165         416 :     test();
     166         416 :     test();
     167         416 :     test();
     168         416 :     IF( EQ_32( hEncoderConfig->ivas_format, MASA_ISM_FORMAT ) && st_ivas->nSCE > 0 && ( EQ_32( st_ivas->ism_mode, ISM_MASA_MODE_DISC ) || EQ_32( st_ivas->ism_mode, ISM_MASA_MODE_PARAM_ONE_OBJ ) || EQ_32( st_ivas->ism_mode, ISM_MASA_MODE_MASA_ONE_OBJ ) ) )
     169             :     {
     170         104 :         FOR( i = 0; i < st_ivas->nSCE; i++ )
     171             :         {
     172          67 :             ism_total_brate = L_add( ism_total_brate, st_ivas->hSCE[i]->element_brate );
     173             :         }
     174             :     }
     175             : 
     176         416 :     ivas_masa_set_elements_fx( st_ivas->hEncoderConfig->ivas_total_brate, st_ivas->mc_mode, st_ivas->nchan_transport, st_ivas->hQMetaData, &hEncoderConfig->element_mode_init, &st_ivas->nSCE, &st_ivas->nCPE, hEncoderConfig->ivas_format, st_ivas->ism_mode, ism_total_brate );
     177             : 
     178         416 :     Copy( DirAC_block_grouping, hMasa->config.block_grouping, MAX_PARAM_SPATIAL_SUBFRAMES + 1 );
     179         416 :     Copy( MASA_band_grouping_24, hMasa->config.band_grouping, MASA_FREQUENCY_BANDS + 1 );
     180             : 
     181         416 :     hMasa->data.onset_detector_1_fx = 0; // hMasa->data.q_onset_detector
     182         416 :     hMasa->data.onset_detector_2_fx = 0; // hMasa->data.q_onset_detector
     183         416 :     hMasa->data.q_onset_detector = 0;
     184         416 :     move32();
     185         416 :     move32();
     186         416 :     move16();
     187             : 
     188         416 :     set32_fx( hMasa->data.lfeToTotalEnergyRatio_fx, 0, MAX_PARAM_SPATIAL_SUBFRAMES ); // hMasa->data.lfeToTotalEnergyRatio_e
     189         416 :     set16_fx( hMasa->data.lfeToTotalEnergyRatio_e, 0, MAX_PARAM_SPATIAL_SUBFRAMES );
     190         416 :     hMasa->data.prevq_lfeToTotalEnergyRatio_fx = 0; // Q31
     191         416 :     move32();
     192             : 
     193         416 :     hMasa->data.prevq_lfeIndex = 0;
     194         416 :     move16();
     195             : 
     196         416 :     hMasa->data.sync_state.prev_sim_stop = 0;
     197         416 :     hMasa->data.sync_state.prev_offset = 0;
     198         416 :     hMasa->data.sync_state.frame_mode = MASA_FRAME_4SF;
     199         416 :     move16();
     200         416 :     move16();
     201         416 :     move32();
     202             : 
     203         416 :     set_zero_fx( hMasa->data.dir_align_state.previous_azi_dir1_fx, MASA_FREQUENCY_BANDS ); // Q22
     204         416 :     set_zero_fx( hMasa->data.dir_align_state.previous_ele_dir1_fx, MASA_FREQUENCY_BANDS ); // Q22
     205         416 :     set_zero_fx( hMasa->data.dir_align_state.previous_azi_dir2_fx, MASA_FREQUENCY_BANDS ); // Q22
     206         416 :     set_zero_fx( hMasa->data.dir_align_state.previous_ele_dir2_fx, MASA_FREQUENCY_BANDS ); // Q22
     207             : 
     208         416 :     IF( EQ_32( hEncoderConfig->ivas_format, MASA_ISM_FORMAT ) )
     209             :     {
     210             :         OMASA_ENCODER_DATA_HANDLE hOmasaData;
     211             : 
     212          44 :         IF( ( hOmasaData = (OMASA_ENCODER_DATA_HANDLE) malloc( sizeof( OMASA_ENCODER_DATA_STATE ) ) ) == NULL )
     213             :         {
     214           0 :             return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for OMASA data encoder\n" ) );
     215             :         }
     216             : 
     217         220 :         FOR( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ )
     218             :         {
     219         176 :             set32_fx( hOmasaData->masa_to_total_energy_ratio_fx[i], 0, MASA_FREQUENCY_BANDS ); // Q30
     220             :         }
     221             : 
     222          44 :         hOmasaData->lp_noise_CPE_fx = -256; /* -1 in Q8 */
     223          44 :         move16();
     224          44 :         hOmasaData->omasa_stereo_sw_cnt = OMASA_STEREO_SW_CNT_MAX;
     225          44 :         move16();
     226             : 
     227          44 :         IF( NE_32( st_ivas->ism_mode, ISM_MASA_MODE_DISC ) )
     228             :         {
     229          27 :             IF( ( hOmasaData->hOmasaEnergy = (OMASA_ENCODER_ENERGY_HANDLE) malloc( sizeof( OMASA_ENCODER_ENERGY_STATE ) ) ) == NULL )
     230             :             {
     231           0 :                 return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for OMASA energy handle\n" ) );
     232             :             }
     233             : 
     234         135 :             FOR( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ )
     235             :             {
     236         108 :                 set_zero_fx( hOmasaData->hOmasaEnergy->energy_ism_fx[i], MASA_FREQUENCY_BANDS ); // hOmasaData->energy_ism_fx_e
     237         108 :                 set16_fx( hOmasaData->hOmasaEnergy->energy_ism_fx_e[i], 0, MASA_FREQUENCY_BANDS );
     238             :             }
     239             :         }
     240             :         else
     241             :         {
     242          17 :             hOmasaData->hOmasaEnergy = NULL;
     243             :         }
     244             : 
     245          44 :         hMasa->data.hOmasaData = hOmasaData;
     246             :     }
     247             :     ELSE
     248             :     {
     249         372 :         hMasa->data.hOmasaData = NULL;
     250             :     }
     251             : 
     252         416 :     st_ivas->hMasa = hMasa;
     253             : 
     254         416 :     return error;
     255             : }
     256             : 
     257             : 
     258             : /*-----------------------------------------------------------------------*
     259             :  * ivas_masa_enc_close()
     260             :  *
     261             :  * close MASA encoder
     262             :  *-----------------------------------------------------------------------*/
     263             : 
     264        1086 : void ivas_masa_enc_close_fx(
     265             :     MASA_ENCODER_HANDLE *hMasa /* i/o: MASA metadata structure      */
     266             : )
     267             : {
     268             :     Word16 i;
     269             : 
     270        1086 :     test();
     271        1086 :     IF( hMasa == NULL || *hMasa == NULL )
     272             :     {
     273         670 :         return;
     274             :     }
     275             : 
     276         623 :     FOR( i = 0; i < ( *hMasa )->data.num_Cldfb_instances; i++ )
     277             :     {
     278         207 :         deleteCldfb_ivas_fx( &( ( *hMasa )->data.cldfbAnaEnc[i] ) );
     279             :     }
     280             : 
     281         416 :     IF( ( *hMasa )->data.hOmasaData != NULL )
     282             :     {
     283          44 :         IF( ( *hMasa )->data.hOmasaData->hOmasaEnergy != NULL )
     284             :         {
     285          25 :             free( ( *hMasa )->data.hOmasaData->hOmasaEnergy );
     286          25 :             ( *hMasa )->data.hOmasaData->hOmasaEnergy = NULL;
     287             :         }
     288             : 
     289          44 :         free( ( *hMasa )->data.hOmasaData );
     290          44 :         ( *hMasa )->data.hOmasaData = NULL;
     291             :     }
     292             : 
     293         416 :     free( ( *hMasa ) );
     294         416 :     ( *hMasa ) = NULL;
     295             : 
     296         416 :     return;
     297             : }
     298             : 
     299             : 
     300             : /*-----------------------------------------------------------------------*
     301             :  * ivas_masa_encode()
     302             :  *
     303             :  * main MASA encoder function
     304             :  *-----------------------------------------------------------------------*/
     305             : 
     306       51306 : ivas_error ivas_masa_encode_fx(
     307             :     MASA_ENCODER_HANDLE hMasa,                         /* i/o: MASA encoder structure                  */
     308             :     IVAS_QMETADATA_HANDLE hQMetaData,                  /* i/o: q_metadata handle                       */
     309             :     BSTR_ENC_HANDLE hMetaData,                         /* i/o: Metadata bitstream handle               */
     310             :     Word16 *nb_bits_metadata,                          /* o  : number of metadata bits written         */
     311             :     const Word16 nchan_transport,                      /* i  : number of MASA input/transport channels */
     312             :     const IVAS_FORMAT ivas_format,                     /* i  : IVAS format                             */
     313             :     const Word32 ivas_total_brate,                     /* i  : IVAS total bitrate                      */
     314             :     const Word16 Opt_DTX_ON,                           /* i  : DTX on flag                             */
     315             :     const Word16 element_mode,                         /* i  : element mode                            */
     316             :     const ISM_MODE ism_mode,                           /* i  : ISM format mode                         */
     317             :     const Word16 nchan_ism,                            /* i  : number of ISM channels                  */
     318             :     ISM_METADATA_HANDLE hIsmMetaData[MAX_NUM_OBJECTS], /* i  : ISM metadata handle                     */
     319             :     const Word16 idx_separated_object,                 /* i  : index of the separated object           */
     320             :     OMASA_ENC_HANDLE hOMasa,                           /* i  : OMASA encoder handle                    */
     321             :     const Word16 ism_imp,                              /* i  : importance of separated object          */
     322             :     const Word16 flag_omasa_ener_brate                 /* i  : less bitrate for objects in OMASA flag  */
     323             : )
     324             : {
     325             :     MASA_DIRECTIONAL_SPATIAL_META *h_orig_metadata;
     326             :     Word16 i, j, s;
     327             :     Word16 masa_sid_descriptor;
     328             :     Word16 low_bitrate_mode;
     329             :     Word32 masa_total_brate;
     330             :     ivas_error error;
     331             :     Word16 guard_bits, tmp;
     332             : 
     333       51306 :     guard_bits = find_guarded_bits_fx( 9 );
     334             : 
     335       51306 :     masa_sid_descriptor = -1;
     336       51306 :     h_orig_metadata = NULL;
     337       51306 :     low_bitrate_mode = 0;
     338       51306 :     move16();
     339       51306 :     move16();
     340             : 
     341       51306 :     test();
     342       51306 :     IF( EQ_32( ivas_format, MASA_FORMAT ) || EQ_32( ivas_format, MASA_ISM_FORMAT ) )
     343             :     {
     344             :         /* Create the MASA SID descriptor for the metadata and CPE mode, in order to have the SID frame self-contained. */
     345       39626 :         IF( Opt_DTX_ON && hQMetaData != NULL )
     346             :         {
     347        7028 :             IF( EQ_16( nchan_transport, 2 ) ) /* this is MASA format in CPE only */
     348             :             {
     349        4016 :                 masa_sid_descriptor = 0; /* for IVAS_CPE_DFT */
     350        4016 :                 move16();
     351        4016 :                 if ( EQ_16( element_mode, IVAS_CPE_MDCT ) )
     352             :                 {
     353        1648 :                     masa_sid_descriptor = 1;
     354        1648 :                     move16();
     355             :                 }
     356             :             }
     357             :         }
     358             : 
     359             :         /* Validate and compensate ratios as necessary */
     360       39626 :         compensate_energy_ratios_fx( hMasa );
     361             : 
     362       39626 :         IF( Opt_DTX_ON )
     363             :         {
     364        7028 :             IF( ( h_orig_metadata = (MASA_DIRECTIONAL_SPATIAL_META *) malloc( MASA_MAXIMUM_DIRECTIONS * sizeof( MASA_DIRECTIONAL_SPATIAL_META ) ) ) == NULL )
     365             :             {
     366           0 :                 return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for MASA encoder\n" ) );
     367             :             }
     368             : 
     369       21084 :             FOR( i = 0; i < MASA_MAXIMUM_DIRECTIONS; i++ )
     370             :             {
     371       70280 :                 FOR( j = 0; j < MAX_PARAM_SPATIAL_SUBFRAMES; j++ )
     372             :                 {
     373       56224 :                     Copy32( hMasa->masaMetadata.directional_meta[i].azimuth_fx[j], h_orig_metadata[i].azimuth_fx[j], MASA_FREQUENCY_BANDS );           // Q22
     374       56224 :                     Copy32( hMasa->masaMetadata.directional_meta[i].elevation_fx[j], h_orig_metadata[i].elevation_fx[j], MASA_FREQUENCY_BANDS );       // Q22
     375       56224 :                     Copy32( hMasa->masaMetadata.directional_meta[i].energy_ratio_fx[j], h_orig_metadata[i].energy_ratio_fx[j], MASA_FREQUENCY_BANDS ); // Q30
     376       56224 :                     Copy( (Word16 *) ( hMasa->masaMetadata.directional_meta[i].spherical_index[j] ), (Word16 *) ( h_orig_metadata[i].spherical_index[j] ), MASA_FREQUENCY_BANDS );
     377             :                 }
     378             :             }
     379             :         }
     380             : 
     381       39626 :         test();
     382       39626 :         test();
     383       39626 :         if ( ( EQ_32( ivas_format, MASA_FORMAT ) || EQ_32( ivas_format, MASA_ISM_FORMAT ) ) && GE_32( ivas_total_brate, IVAS_384k ) )
     384             :         {
     385        2636 :             hMasa->config.mergeRatiosOverSubframes = 0;
     386        2636 :             move16();
     387             :         }
     388             : 
     389             :         /* Combine frequency bands and sub-frames */
     390       39626 :         combine_freqbands_and_subframes_fx( hMasa );
     391             :     }
     392             : 
     393             :     /* aligning the exponents of energy_fx */
     394       51306 :     s = 0;
     395       51306 :     move16();
     396      256530 :     FOR( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ )
     397             :     {
     398      205224 :         maximum_s( hMasa->data.energy_e[i], MASA_FREQUENCY_BANDS, &tmp );
     399      205224 :         s = s_max( s, tmp );
     400             :     }
     401       51306 :     s = add( s, guard_bits );
     402      256530 :     FOR( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ )
     403             :     {
     404     5130600 :         FOR( j = 0; j < MASA_FREQUENCY_BANDS; j++ )
     405             :         {
     406     4925376 :             hMasa->data.energy_fx[i][j] = L_shr( hMasa->data.energy_fx[i][j], sub( s, hMasa->data.energy_e[i][j] ) ); // hMasa->data.energy_e[i][j] -> s
     407     4925376 :             hMasa->data.energy_e[i][j] = s;
     408     4925376 :             move32();
     409     4925376 :             move16();
     410             :         }
     411             :     }
     412       51306 :     hMasa->data.q_energy = sub( 31, s );
     413       51306 :     move16();
     414             : 
     415       51306 :     test();
     416       51306 :     test();
     417       51306 :     test();
     418       51306 :     IF( EQ_16( hMasa->config.numberOfDirections, 2 ) && LT_16( hMasa->config.numTwoDirBands, hMasa->config.numCodingBands ) && ( EQ_32( ivas_format, MASA_FORMAT ) || EQ_32( ivas_format, MASA_ISM_FORMAT ) ) )
     419             :     {
     420        9520 :         test();
     421        9520 :         test();
     422        9520 :         test();
     423        9520 :         IF( ( EQ_32( ivas_format, MASA_ISM_FORMAT ) && NE_32( ism_mode, ISM_MODE_NONE ) && NE_32( ism_mode, ISM_MASA_MODE_MASA_ONE_OBJ ) ) || NE_32( ivas_format, MASA_ISM_FORMAT ) )
     424             :         {
     425             :             /* Combine directions */
     426        7322 :             ivas_masa_combine_directions_fx( hMasa );
     427             :         }
     428             : 
     429             :         /* If we joined all bands, then metadata is now one directional. */
     430        9520 :         IF( hMasa->config.numTwoDirBands == 0 )
     431             :         {
     432        4064 :             hMasa->config.numberOfDirections = 1;
     433        4064 :             hMasa->masaMetadata.descriptive_meta.numberOfDirections = 0;
     434        4064 :             hQMetaData->no_directions = 1;
     435        4064 :             move16();
     436        4064 :             move16();
     437        4064 :             move16();
     438             :         }
     439             :     }
     440             : 
     441             :     /* Reset qmetadata bit budget */
     442       51306 :     hQMetaData->metadata_max_bits = hMasa->config.max_metadata_bits;
     443       51306 :     move16();
     444       51306 :     test();
     445       51306 :     IF( EQ_32( ivas_format, MASA_FORMAT ) || EQ_32( ivas_format, MASA_ISM_FORMAT ) )
     446             :     {
     447       39626 :         test();
     448       39626 :         IF( EQ_32( ivas_format, MASA_ISM_FORMAT ) && NE_32( ism_mode, ISM_MODE_NONE ) )
     449             :         {
     450             :             /* write the number of objects in ISM_MASA format*/
     451        7058 :             push_next_indice( hMetaData, sub( nchan_ism, 1 ), NO_BITS_MASA_ISM_NO_OBJ );
     452        7058 :             hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, NO_BITS_MASA_ISM_NO_OBJ );
     453        7058 :             move16();
     454             : 
     455             :             /* write index of separated object if needed */
     456        7058 :             test();
     457        7058 :             IF( EQ_32( ism_mode, ISM_MASA_MODE_PARAM_ONE_OBJ ) && GT_16( nchan_ism, 1 ) )
     458             :             {
     459        1862 :                 push_next_indice( hMetaData, idx_separated_object, NO_BITS_MASA_ISM_NO_OBJ );
     460        1862 :                 hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, NO_BITS_MASA_ISM_NO_OBJ );
     461        1862 :                 move16();
     462             :             }
     463             : 
     464             :             /* write ISM importance flag (one per object) */
     465        7058 :             IF( EQ_32( ism_mode, ISM_MASA_MODE_PARAM_ONE_OBJ ) )
     466             :             {
     467        1862 :                 push_next_indice( hMetaData, hIsmMetaData[0]->ism_imp, ISM_METADATA_FLAG_BITS );
     468        1862 :                 hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, ISM_METADATA_FLAG_BITS );
     469        1862 :                 move16();
     470             :             }
     471        5196 :             ELSE IF( EQ_32( ism_mode, ISM_MASA_MODE_MASA_ONE_OBJ ) )
     472             :             {
     473        2054 :                 IF( hIsmMetaData[0]->ism_md_null_flag )
     474             :                 {
     475             :                     /* signal NULL metadata frame */
     476           0 :                     push_next_indice( hMetaData, 1, ISM_METADATA_MD_FLAG_BITS );
     477           0 :                     hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, ISM_METADATA_MD_FLAG_BITS );
     478           0 :                     move16();
     479             : 
     480             :                     /* write the ISM class to ISM_NO_META and again the true ISM class */
     481           0 :                     push_next_indice( hMetaData, ISM_NO_META, ISM_METADATA_FLAG_BITS );
     482           0 :                     hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, ISM_METADATA_FLAG_BITS );
     483           0 :                     move16();
     484           0 :                     push_next_indice( hMetaData, hIsmMetaData[0]->ism_imp, ISM_METADATA_FLAG_BITS );
     485           0 :                     hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, ISM_METADATA_FLAG_BITS );
     486           0 :                     move16();
     487             :                 }
     488             :                 ELSE
     489             :                 {
     490        2054 :                     push_next_indice( hMetaData, hIsmMetaData[0]->ism_imp, ISM_METADATA_FLAG_BITS );
     491        2054 :                     hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, ISM_METADATA_FLAG_BITS );
     492        2054 :                     move16();
     493             : 
     494        2054 :                     IF( EQ_16( hIsmMetaData[0]->ism_imp, ISM_NO_META ) )
     495             :                     {
     496             :                         /* signal low-rate ISM_NO_META frame */
     497           0 :                         push_next_indice( hMetaData, 0, ISM_METADATA_MD_FLAG_BITS );
     498           0 :                         hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, ISM_METADATA_MD_FLAG_BITS );
     499           0 :                         move16();
     500             : 
     501             :                         /* signal presence of MD in low-rate ISM_NO_META frame */
     502           0 :                         push_next_indice( hMetaData, hIsmMetaData[0]->ism_md_lowrate_flag, ISM_METADATA_INACTIVE_FLAG_BITS );
     503           0 :                         hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, ISM_METADATA_INACTIVE_FLAG_BITS );
     504           0 :                         move16();
     505             :                     }
     506             :                 }
     507             :             }
     508        3142 :             ELSE IF( EQ_32( ism_mode, ISM_MASA_MODE_DISC ) )
     509             :             {
     510       11602 :                 FOR( i = 0; i < nchan_ism; i++ )
     511             :                 {
     512        8460 :                     IF( hIsmMetaData[i]->ism_md_null_flag )
     513             :                     {
     514             :                         /* signal NULL metadata frame */
     515           0 :                         push_next_indice( hMetaData, 1, ISM_METADATA_MD_FLAG_BITS );
     516           0 :                         hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, ISM_METADATA_MD_FLAG_BITS );
     517           0 :                         move16();
     518             : 
     519             :                         /* write the ISM class to ISM_NO_META and again the true ISM class */
     520           0 :                         push_next_indice( hMetaData, ISM_NO_META, ISM_METADATA_FLAG_BITS );
     521           0 :                         hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, ISM_METADATA_FLAG_BITS );
     522           0 :                         move16();
     523           0 :                         push_next_indice( hMetaData, hIsmMetaData[i]->ism_imp, ISM_METADATA_FLAG_BITS );
     524           0 :                         hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, ISM_METADATA_FLAG_BITS );
     525           0 :                         move16();
     526             :                     }
     527             :                     ELSE
     528             :                     {
     529        8460 :                         push_next_indice( hMetaData, hIsmMetaData[i]->ism_imp, ISM_METADATA_FLAG_BITS );
     530        8460 :                         hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, ISM_METADATA_FLAG_BITS );
     531        8460 :                         move16();
     532             : 
     533        8460 :                         IF( EQ_16( hIsmMetaData[i]->ism_imp, ISM_NO_META ) )
     534             :                         {
     535             :                             /* signal low-rate ISM_NO_META frame */
     536           0 :                             push_next_indice( hMetaData, 0, ISM_METADATA_MD_FLAG_BITS );
     537           0 :                             hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, ISM_METADATA_MD_FLAG_BITS );
     538           0 :                             move16();
     539             : 
     540             :                             /* signal presence of MD in low-rate ISM_NO_META frame */
     541           0 :                             push_next_indice( hMetaData, hIsmMetaData[i]->ism_md_lowrate_flag, ISM_METADATA_INACTIVE_FLAG_BITS );
     542           0 :                             hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, ISM_METADATA_INACTIVE_FLAG_BITS );
     543           0 :                             move16();
     544             :                         }
     545             :                     }
     546             :                 }
     547        3142 :                 test();
     548        3142 :                 IF( EQ_32( ivas_total_brate, IVAS_128k ) && GE_16( nchan_ism, 3 ) )
     549             :                 {
     550         126 :                     push_next_indice( hMetaData, flag_omasa_ener_brate, 1 );
     551         126 :                     hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, 1 );
     552         126 :                     move16();
     553             :                 }
     554             :             }
     555             :         }
     556             :         ELSE
     557             :         {
     558       32568 :             test();
     559       32568 :             IF( EQ_32( ivas_format, MASA_ISM_FORMAT ) && EQ_32( ism_mode, ISM_MODE_NONE ) )
     560             :             {
     561             :                 /* use the MASA number of transport channels bit to signal if there are 1 or 2 objects */
     562        1942 :                 test();
     563        1942 :                 IF( EQ_16( nchan_ism, 1 ) || EQ_16( nchan_ism, 2 ) )
     564             :                 {
     565         474 :                     push_next_indice( hMetaData, sub( nchan_ism, 1 ), MASA_TRANSP_BITS );
     566             :                 }
     567             :                 ELSE
     568             :                 {
     569             :                     /* for 3 or 4 objects write already the number of MASA directions */
     570        1468 :                     push_next_indice( hMetaData, sub( hQMetaData->no_directions, 1 ), MASA_TRANSP_BITS );
     571             :                 }
     572             :             }
     573             :             ELSE
     574             :             {
     575             :                 /* write the number of MASA transport channels */
     576       30626 :                 push_next_indice( hMetaData, sub( nchan_transport, 1 ), MASA_TRANSP_BITS );
     577             :             }
     578       32568 :             hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, MASA_TRANSP_BITS );
     579       32568 :             move16();
     580             :         }
     581             : 
     582       39626 :         test();
     583       39626 :         IF( EQ_32( ivas_format, MASA_ISM_FORMAT ) && EQ_32( ism_mode, ISM_MODE_NONE ) )
     584             :         {
     585        1942 :             IF( GE_16( nchan_ism, 3 ) ) /* if 3 or 4 objects */
     586             :             {
     587        1468 :                 push_next_indice( hMetaData, sub( 5, nchan_ism ), MASA_HEADER_BITS );
     588             :             }
     589             :             ELSE
     590             :             {
     591         474 :                 push_next_indice( hMetaData, 3, MASA_HEADER_BITS );
     592             :             }
     593        1942 :             hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, MASA_HEADER_BITS );
     594        1942 :             move16();
     595             :         }
     596             :         ELSE
     597             :         {
     598             :             /* the MASA_ISM_FORMAT is not signalled here */
     599             :             /* write reserved bits */
     600       37684 :             push_next_indice( hMetaData, 0, MASA_HEADER_BITS );
     601       37684 :             hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, MASA_HEADER_BITS );
     602       37684 :             move16();
     603             :         }
     604       39626 :         test();
     605       39626 :         test();
     606       39626 :         test();
     607       39626 :         IF( !( EQ_32( ivas_format, MASA_ISM_FORMAT ) && EQ_32( ism_mode, ISM_MODE_NONE ) && GT_16( nchan_ism, 2 ) ) )
     608             :         {
     609             :             /* write number of directions */
     610       38158 :             push_next_indice( hMetaData, sub( hQMetaData->no_directions, 1 ), 1 );
     611       38158 :             hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, 1 );
     612       38158 :             move16();
     613             :         }
     614             : 
     615             :         /* write subframe mode */
     616       39626 :         IF( EQ_16( hQMetaData->q_direction[0].cfg.nblocks, 1 ) )
     617             :         {
     618        5550 :             push_next_indice( hMetaData, 1, MASA_SUBFRAME_BITS );
     619             :         }
     620             :         ELSE
     621             :         {
     622       34076 :             push_next_indice( hMetaData, 0, MASA_SUBFRAME_BITS );
     623             :         }
     624       39626 :         hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, MASA_SUBFRAME_BITS );
     625       39626 :         move16();
     626             :     }
     627             : 
     628             : 
     629       51306 :     IF( EQ_32( ivas_format, MC_FORMAT ) )
     630             :     {
     631             :         Word16 lfeBitsWritten;
     632             : 
     633       11680 :         lfeBitsWritten = encode_lfe_to_total_energy_ratio_fx( hMasa, hMetaData, ivas_total_brate );
     634             : 
     635       11680 :         hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, lfeBitsWritten );
     636       11680 :         move16();
     637             :     }
     638             : 
     639             :     /* Move data from encoder to qmetadata */
     640       51306 :     test();
     641       51306 :     IF( EQ_32( ivas_format, MASA_FORMAT ) || EQ_32( ivas_format, MASA_ISM_FORMAT ) )
     642             :     {
     643       39626 :         move_metadata_to_qmetadata_fx( hMasa, hQMetaData );
     644             :     }
     645             : 
     646       51306 :     test();
     647       51306 :     IF( LT_16( hMasa->config.max_metadata_bits, MINIMUM_BIT_BUDGET_NORMAL_META ) && !hMasa->config.joinedSubframes )
     648             :     {
     649       25011 :         reduce_metadata_further_fx( hMasa, hQMetaData, ivas_format );
     650             : 
     651       25011 :         low_bitrate_mode = (Word16) LE_32( ivas_total_brate, 32000 );
     652             : 
     653             :         /* Write low bitrate mode. 1 signals that we have merged through time, 0 signals merge through frequency. */
     654       25011 :         IF( EQ_16( hQMetaData->q_direction[0].cfg.nblocks, 1 ) )
     655             :         {
     656       21010 :             push_next_indice( hMetaData, 1, MASA_LOWBITRATE_MODE_BITS );
     657             :         }
     658             :         ELSE
     659             :         {
     660        4001 :             push_next_indice( hMetaData, 0, MASA_LOWBITRATE_MODE_BITS );
     661             :         }
     662       25011 :         hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, MASA_LOWBITRATE_MODE_BITS );
     663       25011 :         move16();
     664             :     }
     665             : 
     666             :     /* Encode MASA+ISM metadata */
     667       51306 :     test();
     668       51306 :     IF( EQ_32( ivas_format, MASA_ISM_FORMAT ) && EQ_32( ism_mode, ISM_MASA_MODE_PARAM_ONE_OBJ ) )
     669             :     {
     670             :         /* encode MASA/ISM energy ratios */
     671        1862 :         ivas_encode_masaism_metadata_fx( hMasa, hQMetaData, hMetaData, hIsmMetaData, nchan_ism, low_bitrate_mode, hOMasa->nCodingBands, hOMasa->nSubframes, idx_separated_object, ism_imp );
     672             :     }
     673             :     ELSE
     674             :     {
     675       49444 :         if ( EQ_32( ivas_format, MASA_ISM_FORMAT ) )
     676             :         {
     677        7138 :             hMasa->data.hOmasaData->masa_to_total_energy_ratio_fx[0][0] = -ONE_IN_Q30; /* signals NOT to adjust the energy ratios */
     678        7138 :             move32();
     679             :         }
     680             :     }
     681             : 
     682             :     /* Encode metadata */
     683       51306 :     masa_total_brate = ivas_total_brate;
     684       51306 :     move32();
     685       51306 :     test();
     686       51306 :     IF( EQ_32( ivas_format, MASA_ISM_FORMAT ) && EQ_32( ism_mode, ISM_MASA_MODE_DISC ) )
     687             :     {
     688        3142 :         masa_total_brate = calculate_cpe_brate_MASA_ISM_fx( ism_mode, ivas_total_brate, nchan_ism );
     689             :     }
     690             : 
     691       51306 :     IF( GE_32( masa_total_brate, IVAS_384k ) )
     692             :     {
     693        2276 :         IF( GE_32( masa_total_brate, IVAS_512k ) )
     694             :         {
     695         800 :             IF( NE_32( ( error = ivas_qmetadata_enc_encode_hr_384_512_fx( hMetaData, hQMetaData, 16, 4 ) ), IVAS_ERR_OK ) )
     696             :             {
     697           0 :                 return error;
     698             :             }
     699             :         }
     700             :         ELSE
     701             :         {
     702        1476 :             IF( NE_32( ( error = ivas_qmetadata_enc_encode_hr_384_512_fx( hMetaData, hQMetaData, 11, 3 ) ), IVAS_ERR_OK ) )
     703             :             {
     704           0 :                 return error;
     705             :             }
     706             :         }
     707             :     }
     708             :     ELSE
     709             :     {
     710       49030 :         IF( NE_32( ( error = ivas_qmetadata_enc_encode_fx( hMetaData, hQMetaData, 0 ) ), IVAS_ERR_OK ) )
     711             :         {
     712           0 :             return error;
     713             :         }
     714             :     }
     715             : 
     716       51306 :     test();
     717       51306 :     IF( EQ_32( ivas_format, MASA_ISM_FORMAT ) && EQ_32( ism_mode, ISM_MASA_MODE_PARAM_ONE_OBJ ) )
     718             :     {
     719             :         /* Modify spatial metadata based on the MASA-to-total energy ratios */
     720        1862 :         ivas_omasa_modify_masa_energy_ratios_fx( hQMetaData, hMasa->data.hOmasaData->masa_to_total_energy_ratio_fx );
     721             :     }
     722             : 
     723       51306 :     *nb_bits_metadata = hMetaData->nb_bits_tot;
     724       51306 :     move16();
     725             : 
     726       51306 :     test();
     727       51306 :     IF( EQ_32( ivas_format, MASA_FORMAT ) && Opt_DTX_ON )
     728             :     {
     729             :         /* save old values */
     730        7028 :         UWord8 numCodingBands = hMasa->config.numCodingBands;
     731        7028 :         UWord8 numTwoDirBands = hMasa->config.numTwoDirBands;
     732        7028 :         Word16 nbands = hQMetaData->q_direction[0].cfg.nbands;
     733        7028 :         UWord8 numberOfDirections = hMasa->config.numberOfDirections;
     734        7028 :         UWord8 numberOfDirectionsMeta = hMasa->masaMetadata.descriptive_meta.numberOfDirections;
     735        7028 :         UWord16 numberOfDirectionsQMetaData = hQMetaData->no_directions;
     736        7028 :         move16();
     737        7028 :         move16();
     738        7028 :         move16();
     739        7028 :         move16();
     740        7028 :         move16();
     741        7028 :         move16();
     742             : 
     743        7028 :         test();
     744        7028 :         IF( !( EQ_16( hMasa->config.numberOfDirections, 1 ) && EQ_16( hQMetaData->q_direction->cfg.nbands, 5 ) ) )
     745             :         {
     746        5937 :             FOR( i = 0; i < MASA_MAXIMUM_DIRECTIONS; i++ )
     747             :             {
     748       19790 :                 FOR( j = 0; j < MAX_PARAM_SPATIAL_SUBFRAMES; j++ )
     749             :                 {
     750       15832 :                     Copy32( h_orig_metadata[i].azimuth_fx[j], hMasa->masaMetadata.directional_meta[i].azimuth_fx[j], MASA_FREQUENCY_BANDS );           // Q22
     751       15832 :                     Copy32( h_orig_metadata[i].elevation_fx[j], hMasa->masaMetadata.directional_meta[i].elevation_fx[j], MASA_FREQUENCY_BANDS );       // Q22
     752       15832 :                     Copy32( h_orig_metadata[i].energy_ratio_fx[j], hMasa->masaMetadata.directional_meta[i].energy_ratio_fx[j], MASA_FREQUENCY_BANDS ); // Q30
     753             :                 }
     754             :             }
     755             : 
     756             :             /* Force to have 5 bands and 1 direction */
     757        1979 :             hMasa->config.numCodingBands = 5;
     758        1979 :             hMasa->config.numTwoDirBands = 0;
     759        1979 :             move16();
     760        1979 :             move16();
     761             : 
     762        1979 :             combine_freqbands_and_subframes_fx( hMasa );
     763             : 
     764        1979 :             hQMetaData->q_direction[0].cfg.nbands = 5;
     765        1979 :             move16();
     766             : 
     767        1979 :             test();
     768        1979 :             IF( EQ_16( hMasa->config.numberOfDirections, 2 ) && LT_16( hMasa->config.numTwoDirBands, hMasa->config.numCodingBands ) )
     769             :             {
     770             :                 /* Combine directions */
     771           0 :                 ivas_masa_combine_directions_fx( hMasa );
     772             : 
     773             :                 /* If we joined all bands, then metadata is now one directional. */
     774           0 :                 IF( hMasa->config.numTwoDirBands == 0 )
     775             :                 {
     776           0 :                     hMasa->config.numberOfDirections = 1;
     777           0 :                     hMasa->masaMetadata.descriptive_meta.numberOfDirections = 0;
     778           0 :                     hQMetaData->no_directions = 1;
     779           0 :                     move16();
     780           0 :                     move16();
     781           0 :                     move16();
     782             :                 }
     783             :             }
     784             : 
     785        1979 :             move_metadata_to_qmetadata_fx( hMasa, hQMetaData );
     786             : 
     787       11874 :             FOR( j = hQMetaData->q_direction[0].cfg.start_band; j < hQMetaData->q_direction[0].cfg.nbands; ++j )
     788             :             {
     789        9895 :                 hQMetaData->q_direction[0].band_data[j].energy_ratio_index[0] = masa_sq_fx( L_sub( ONE_IN_Q30, hQMetaData->q_direction[0].band_data[j].energy_ratio_fx[0] ), diffuseness_thresholds_fx, DIRAC_DIFFUSE_LEVELS );
     790        9895 :                 move32();
     791             :             }
     792             :         }
     793             : 
     794        7028 :         free( h_orig_metadata );
     795             : 
     796        7028 :         ivas_qmetadata_enc_sid_encode_fx( hMetaData, hQMetaData, masa_sid_descriptor, 0, ivas_format );
     797             : 
     798             :         /* restore old values */
     799        7028 :         hMasa->config.numCodingBands = numCodingBands;
     800        7028 :         hMasa->config.numTwoDirBands = numTwoDirBands;
     801        7028 :         hQMetaData->q_direction[0].cfg.nbands = nbands;
     802        7028 :         hMasa->config.numberOfDirections = numberOfDirections;
     803        7028 :         hMasa->masaMetadata.descriptive_meta.numberOfDirections = numberOfDirectionsMeta;
     804        7028 :         hQMetaData->no_directions = numberOfDirectionsQMetaData;
     805        7028 :         move16();
     806        7028 :         move16();
     807        7028 :         move16();
     808        7028 :         move16();
     809        7028 :         move16();
     810        7028 :         move16();
     811             :     }
     812             : 
     813       51306 :     return IVAS_ERR_OK;
     814             : }
     815             : 
     816             : 
     817             : /*-----------------------------------------------------------------------*
     818             :  * ivas_masa_estimate_energy_fx()
     819             :  *
     820             :  *
     821             :  *-----------------------------------------------------------------------*/
     822             : 
     823       39626 : void ivas_masa_estimate_energy_fx(
     824             :     MASA_ENCODER_HANDLE hMasa,    /* i/o: MASA encoder structure                    */
     825             :     Word32 *data_fx[],            /* i  : Input audio channels        Q(q_data)     */
     826             :     const Word16 input_frame,     /* i  : frame length                              */
     827             :     const Word16 nchan_transport, /* i  : number of MASA input/transport channels   */
     828             :     Word16 q_data                 /* i  : q for data_fx                             */
     829             : )
     830             : {
     831             :     Word32 Input_RealBuffer[MASA_MAX_TRANSPORT_CHANNELS][CLDFB_NO_CHANNELS_MAX];
     832             :     Word32 Input_ImagBuffer[MASA_MAX_TRANSPORT_CHANNELS][CLDFB_NO_CHANNELS_MAX];
     833             :     Word16 block_m_idx, band_m_idx;
     834             :     Word16 mrange[2], brange[2];
     835             :     Word16 i, j, ts, l_ts, maxBin;
     836             :     Word64 energy_fx_temp[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
     837       39626 :     Word16 scale = 63;
     838       39626 :     move16();
     839             :     Word16 q_buf;
     840       39626 :     maxBin = extract_l( Mpy_32_32( 134217728 /*CLDFB_NO_CHANNELS_MAX / L_FRAME48k in Q31*/, input_frame ) );
     841       39626 :     l_ts = shr( input_frame, CLDFB_NO_COL_MAX_LOG2 );
     842             : 
     843      198130 :     FOR( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ )
     844             :     {
     845     3962600 :         FOR( j = 0; j < MASA_FREQUENCY_BANDS; j++ )
     846             :         {
     847     3804096 :             energy_fx_temp[i][j] = 0;
     848     3804096 :             move64();
     849             :         }
     850             :     }
     851             : 
     852      198130 :     FOR( block_m_idx = 0; block_m_idx < MAX_PARAM_SPATIAL_SUBFRAMES; block_m_idx++ )
     853             :     {
     854      158504 :         mrange[0] = hMasa->config.block_grouping[block_m_idx];
     855      158504 :         move16();
     856      158504 :         mrange[1] = hMasa->config.block_grouping[block_m_idx + 1];
     857      158504 :         move16();
     858      158504 :         set_zero_fx( hMasa->data.energy_fx[block_m_idx], MASA_FREQUENCY_BANDS );
     859      158504 :         set16_fx( hMasa->data.energy_e[block_m_idx], 0, MASA_FREQUENCY_BANDS );
     860             : 
     861      792520 :         FOR( ts = mrange[0]; ts < mrange[1]; ts++ )
     862             :         {
     863     1676608 :             FOR( i = 0; i < nchan_transport; i++ )
     864             :             {
     865     1042592 :                 q_buf = q_data;
     866     1042592 :                 move16();
     867     1042592 :                 scale_sig32( hMasa->data.cldfbAnaEnc[i]->cldfb_state_fx, hMasa->data.cldfbAnaEnc[i]->cldfb_state_length, sub( q_buf, hMasa->data.cldfbAnaEnc[i]->Q_cldfb_state ) );
     868     1042592 :                 hMasa->data.cldfbAnaEnc[i]->Q_cldfb_state = q_buf;
     869     1042592 :                 move16();
     870     1042592 :                 cldfbAnalysis_ts_fx_fixed_q( &( data_fx[i][l_ts * ts] ), Input_RealBuffer[i], Input_ImagBuffer[i], l_ts, hMasa->data.cldfbAnaEnc[i], &q_buf ); // (q_data - 5)  for Input_RealBuffer[i], Input_ImagBuffer[i]
     871             :             }
     872             : 
     873    15850400 :             FOR( band_m_idx = 0; band_m_idx < MASA_FREQUENCY_BANDS; band_m_idx++ )
     874             :             {
     875    15216384 :                 brange[0] = hMasa->config.band_grouping[band_m_idx];
     876    15216384 :                 move16();
     877    15216384 :                 brange[1] = hMasa->config.band_grouping[band_m_idx + 1];
     878    15216384 :                 move16();
     879             : 
     880    40238592 :                 FOR( i = 0; i < nchan_transport; i++ )
     881             :                 {
     882    25022208 :                     IF( GT_16( brange[0], maxBin ) )
     883             :                     {
     884       72000 :                         hMasa->data.energy_fx[block_m_idx][band_m_idx] = 0;
     885       72000 :                         move32();
     886       72000 :                         CONTINUE;
     887             :                     }
     888    24950208 :                     ELSE IF( GE_16( brange[1], maxBin ) )
     889             :                     {
     890     1116992 :                         brange[1] = maxBin;
     891     1116992 :                         move16();
     892             :                     }
     893             : 
     894    85537728 :                     FOR( j = brange[0]; j < brange[1]; j++ )
     895             :                     {
     896    60587520 :                         energy_fx_temp[block_m_idx][band_m_idx] = W_add( energy_fx_temp[block_m_idx][band_m_idx], W_mac_32_32( W_mult_32_32( Input_RealBuffer[i][j], Input_RealBuffer[i][j] ), Input_ImagBuffer[i][j], Input_ImagBuffer[i][j] ) ); // Q: 2 * (q_data - 5) + 1 for energy_fx_temp
     897    60587520 :                         move64();
     898             :                     }
     899    24950208 :                     IF( energy_fx_temp[block_m_idx][band_m_idx] != 0 )
     900             :                     {
     901    24875808 :                         scale = s_min( scale, W_norm( energy_fx_temp[block_m_idx][band_m_idx] ) ); // scale calculates minimum shift can be done across a buffer
     902             :                     }
     903             :                 }
     904             :             }
     905             :         }
     906             :     }
     907             : 
     908      198130 :     FOR( block_m_idx = 0; block_m_idx < MAX_PARAM_SPATIAL_SUBFRAMES; block_m_idx++ )
     909             :     {
     910     3962600 :         FOR( band_m_idx = 0; band_m_idx < MASA_FREQUENCY_BANDS; band_m_idx++ )
     911             :         {
     912     3804096 :             energy_fx_temp[block_m_idx][band_m_idx] = W_shl( energy_fx_temp[block_m_idx][band_m_idx], scale ); //  Q: 2 * (q_data - 5) + 1 + scale
     913     3804096 :             move64();
     914     3804096 :             hMasa->data.energy_fx[block_m_idx][band_m_idx] = W_extract_h( energy_fx_temp[block_m_idx][band_m_idx] ); // Q: 2 * (q_data - 5) + 1 + scale - 32
     915     3804096 :             move32();
     916     3804096 :             hMasa->data.energy_e[block_m_idx][band_m_idx] = sub( 31, add( add( imult1616( 2, q_data ), scale ), 1 - 10 - 32 ) );
     917     3804096 :             move16();
     918             :         }
     919             :     }
     920       39626 :     hMasa->data.q_energy = add( add( imult1616( 2, q_data ), scale ), 1 - 10 - 32 );
     921       39626 :     move16();
     922             : 
     923       39626 :     return;
     924             : }
     925             : 
     926             : 
     927             : /*-----------------------------------------------------------------------*
     928             :  * ivas_masa_enc_config()
     929             :  *
     930             :  * Frame-by-frame configuration of MASA encoder
     931             :  *-----------------------------------------------------------------------*/
     932             : 
     933       39923 : ivas_error ivas_masa_enc_config_fx(
     934             :     Encoder_Struct *st_ivas /* i/o: IVAS encoder structure */
     935             : )
     936             : {
     937             :     Word16 i;
     938             :     MASA_ENCODER_HANDLE hMasa;
     939             :     IVAS_QMETADATA_HANDLE hQMetaData;
     940             :     IVAS_FORMAT ivas_format;
     941             :     UWord8 joinedSubframes;
     942             :     UWord8 coherencePresent;
     943             :     UWord8 isActualTwoDir; /* Flag to tell that when there are two directions present in metadata, they both contain meaningful information. */
     944             :     Word32 ivas_total_brate;
     945             :     UWord8 maxBand;
     946             :     Word16 maxBin, sf;
     947             :     ivas_error error;
     948             :     Word32 ism_total_brate;
     949             :     Word32 masa_total_brate;
     950             : 
     951       39923 :     error = IVAS_ERR_OK;
     952       39923 :     move16();
     953             : 
     954       39923 :     hMasa = st_ivas->hMasa;
     955       39923 :     hQMetaData = st_ivas->hQMetaData;
     956       39923 :     ivas_format = st_ivas->hEncoderConfig->ivas_format;
     957       39923 :     ivas_total_brate = st_ivas->hEncoderConfig->ivas_total_brate;
     958       39923 :     move16();
     959       39923 :     move32();
     960             : 
     961       39923 :     ism_total_brate = 0;
     962       39923 :     move32();
     963       39923 :     test();
     964       39923 :     test();
     965       39923 :     test();
     966       39923 :     test();
     967       39923 :     IF( EQ_16( ivas_format, MASA_ISM_FORMAT ) && st_ivas->nSCE > 0 && ( EQ_16( st_ivas->ism_mode, ISM_MASA_MODE_DISC ) || EQ_16( st_ivas->ism_mode, ISM_MASA_MODE_PARAM_ONE_OBJ ) || EQ_16( st_ivas->ism_mode, ISM_MASA_MODE_MASA_ONE_OBJ ) ) )
     968             :     {
     969       19434 :         FOR( i = 0; i < st_ivas->nSCE; i++ )
     970             :         {
     971       12376 :             ism_total_brate = L_add( ism_total_brate, st_ivas->hSCE[i]->element_brate );
     972             :         }
     973             :     }
     974             : 
     975       39923 :     ivas_masa_set_elements_fx( ivas_total_brate, st_ivas->mc_mode, st_ivas->nchan_transport, hQMetaData, &st_ivas->hEncoderConfig->element_mode_init, &st_ivas->nSCE, &st_ivas->nCPE, ivas_format, st_ivas->ism_mode, ism_total_brate );
     976             : 
     977       39923 :     hQMetaData->is_masa_ivas_format = 1;
     978       39923 :     move16();
     979             : 
     980       39923 :     test();
     981       39923 :     test();
     982       39923 :     IF( EQ_16( ivas_format, MASA_FORMAT ) || EQ_16( ivas_format, MASA_ISM_FORMAT ) )
     983             :     {
     984       39626 :         masa_metadata_direction_alignment_fx( hMasa );
     985             : 
     986       39626 :         detect_framing_async_fx( hMasa ); /* detect the offset, set 1sf/4sf mode based on this. potentially also shift the metadata using a history buffer */
     987       39626 :         test();
     988       39626 :         IF( EQ_16( hMasa->data.sync_state.frame_mode, MASA_FRAME_1SF ) && hMasa->data.sync_state.prev_offset != 0 )
     989             :         {
     990             :             /* average over sub-frames */
     991           0 :             IF( EQ_32( ivas_total_brate, IVAS_512k ) )
     992             :             {
     993           0 :                 average_masa_metadata_fx( &( hMasa->masaMetadata ), hMasa->data.energy_fx, hMasa->data.energy_e, &( hMasa->data.Sph_Grid16 ), TRUE );
     994             :             }
     995             :             ELSE
     996             :             {
     997           0 :                 average_masa_metadata_fx( &( hMasa->masaMetadata ), hMasa->data.energy_fx, hMasa->data.energy_e, &( hMasa->data.Sph_Grid16 ), FALSE );
     998             :             }
     999             :         }
    1000             : 
    1001             :         /* Inspect metadata for parameter changes that affect coding. */
    1002       39626 :         detect_metadata_composition_fx( hMasa, &joinedSubframes, &coherencePresent, &isActualTwoDir );
    1003             : 
    1004       39626 :         hMasa->config.joinedSubframes = joinedSubframes;
    1005       39626 :         hMasa->config.coherencePresent = coherencePresent;
    1006       39626 :         move16();
    1007       39626 :         move16();
    1008       39626 :         test();
    1009       39626 :         IF( EQ_16( add( hMasa->masaMetadata.descriptive_meta.numberOfDirections, 1 ), 2 ) && isActualTwoDir )
    1010             :         {
    1011        9900 :             hMasa->config.numberOfDirections = 2;
    1012             :         }
    1013             :         ELSE
    1014             :         {
    1015       29726 :             hMasa->config.numberOfDirections = 1;
    1016             :         }
    1017       39626 :         move16();
    1018             :     }
    1019         297 :     ELSE IF( EQ_16( ivas_format, MC_FORMAT ) && EQ_16( st_ivas->mc_mode, MC_MODE_MCMASA ) )
    1020             :     {
    1021             :         /* For McMASA, these are set only once as this function is called only once. */
    1022         297 :         hMasa->config.joinedSubframes = 0;
    1023         297 :         hMasa->config.numberOfDirections = 1;
    1024         297 :         move16();
    1025         297 :         move16();
    1026             :     }
    1027             : 
    1028       39923 :     IF( EQ_32( ivas_format, MASA_ISM_FORMAT ) )
    1029             :     {
    1030        9000 :         ivas_masa_set_coding_config_fx( &( hMasa->config ), hMasa->data.band_mapping, st_ivas->hCPE[0]->element_brate, st_ivas->nchan_transport, MC_MODE_NONE );
    1031             :     }
    1032             :     ELSE
    1033             :     {
    1034       30923 :         test();
    1035       30923 :         ivas_masa_set_coding_config_fx( &( hMasa->config ), hMasa->data.band_mapping, ivas_total_brate, st_ivas->nchan_transport, ( EQ_16( ivas_format, MC_FORMAT ) && EQ_16( st_ivas->mc_mode, MC_MODE_MCMASA ) ) );
    1036             :     }
    1037             : 
    1038             :     /* Setup importance weights for two-direction band selection. */
    1039       39923 :     IF( EQ_16( hMasa->config.numberOfDirections, 2 ) )
    1040             :     {
    1041        9900 :         set32_fx( hMasa->data.importanceWeight_fx, ONE_IN_Q30 /*1.0f Q30*/, MASA_FREQUENCY_BANDS );
    1042             : 
    1043        9900 :         IF( EQ_16( hMasa->config.numCodingBands, 5 ) )
    1044             :         {
    1045        6670 :             hMasa->data.importanceWeight_fx[4] = 751619277 /*0.7f q30*/;
    1046        6670 :             move32();
    1047             :         }
    1048        3230 :         ELSE IF( EQ_16( hMasa->config.numCodingBands, 8 ) )
    1049             :         {
    1050         354 :             hMasa->data.importanceWeight_fx[7] = 751619277 /*0.7f q30*/;
    1051         354 :             move32();
    1052             :         }
    1053        2876 :         ELSE IF( EQ_16( hMasa->config.numCodingBands, 10 ) )
    1054             :         {
    1055           0 :             hMasa->data.importanceWeight_fx[8] = 751619277 /*0.7f q30*/;
    1056           0 :             hMasa->data.importanceWeight_fx[9] = 107374182 /*0.1f q30*/;
    1057           0 :             move32();
    1058           0 :             move32();
    1059             :         }
    1060        2876 :         ELSE IF( EQ_16( hMasa->config.numCodingBands, 12 ) )
    1061             :         {
    1062         794 :             hMasa->data.importanceWeight_fx[10] = 751619277 /*0.7f q30*/;
    1063         794 :             hMasa->data.importanceWeight_fx[11] = 107374182 /*0.1f q30*/;
    1064         794 :             move32();
    1065         794 :             move32();
    1066             :         }
    1067        2082 :         ELSE IF( EQ_16( hMasa->config.numCodingBands, 18 ) )
    1068             :         {
    1069         798 :             hMasa->data.importanceWeight_fx[14] = 858993459 /*0.8f q30*/;
    1070         798 :             hMasa->data.importanceWeight_fx[15] = 536870912 /*0.5f q30*/;
    1071         798 :             hMasa->data.importanceWeight_fx[16] = 214748365 /*0.2f q30*/;
    1072         798 :             hMasa->data.importanceWeight_fx[17] = 0 /*0 q30*/;
    1073         798 :             move32();
    1074         798 :             move32();
    1075         798 :             move32();
    1076         798 :             move32();
    1077             :         }
    1078        1284 :         ELSE IF( EQ_16( hMasa->config.numCodingBands, 24 ) )
    1079             :         {
    1080        1284 :             hMasa->data.importanceWeight_fx[20] = 858993459 /*0.8f q30*/;
    1081        1284 :             hMasa->data.importanceWeight_fx[21] = 536870912 /*0.5f q30*/;
    1082        1284 :             hMasa->data.importanceWeight_fx[22] = 214748365 /*0.2f q30*/;
    1083        1284 :             hMasa->data.importanceWeight_fx[23] = 0 /*0 q30*/;
    1084        1284 :             move32();
    1085        1284 :             move32();
    1086        1284 :             move32();
    1087        1284 :             move32();
    1088             :         }
    1089             : 
    1090        9900 :         IF( EQ_16( hMasa->config.numTwoDirBands, hMasa->config.numCodingBands ) )
    1091             :         {
    1092         380 :             set8_fx( (Word8 *) hMasa->data.twoDirBands, 1, hMasa->config.numCodingBands );
    1093             :         }
    1094             :     }
    1095             :     ELSE
    1096             :     {
    1097       30023 :         set8_fx( (Word8 *) hMasa->data.twoDirBands, 0, hMasa->config.numCodingBands );
    1098             :     }
    1099             : 
    1100             :     /* Set qmeta to correct values */
    1101       39923 :     test();
    1102       39923 :     IF( EQ_16( hMasa->config.numberOfDirections, 2 ) && hMasa->config.numTwoDirBands != 0 )
    1103             :     {
    1104        5836 :         IF( NE_32( ( error = ivas_qmetadata_allocate_memory_fx( hQMetaData, hMasa->config.numCodingBands, 2, hMasa->config.useCoherence ) ), IVAS_ERR_OK ) )
    1105             :         {
    1106           0 :             return error;
    1107             :         }
    1108             :     }
    1109             :     ELSE
    1110             :     {
    1111       34087 :         IF( NE_32( ( error = ivas_qmetadata_allocate_memory_fx( hQMetaData, hMasa->config.numCodingBands, 1, hMasa->config.useCoherence ) ), IVAS_ERR_OK ) )
    1112             :         {
    1113           0 :             return error;
    1114             :         }
    1115             :     }
    1116             : 
    1117       85682 :     FOR( i = 0; i < hQMetaData->no_directions; i++ )
    1118             :     {
    1119       45759 :         hQMetaData->q_direction[i].cfg.nbands = hMasa->config.numCodingBands;
    1120       45759 :         move16();
    1121       45759 :         IF( EQ_16( hMasa->config.joinedSubframes, TRUE ) )
    1122             :         {
    1123        6546 :             hQMetaData->q_direction[i].cfg.nblocks = 1;
    1124             :         }
    1125             :         ELSE
    1126             :         {
    1127       39213 :             hQMetaData->q_direction[i].cfg.nblocks = MAX_PARAM_SPATIAL_SUBFRAMES;
    1128             :         }
    1129       45759 :         move16();
    1130             : 
    1131       45759 :         IF( EQ_16( ivas_format, MC_FORMAT ) )
    1132             :         {
    1133         297 :             hQMetaData->q_direction[i].cfg.mc_ls_setup = st_ivas->hEncoderConfig->mc_input_setup;
    1134         297 :             move16();
    1135             :         }
    1136             :         ELSE
    1137             :         {
    1138             :             /* Just to be sure that this default value is maintained */
    1139       45462 :             hQMetaData->q_direction[i].cfg.mc_ls_setup = MC_LS_SETUP_INVALID;
    1140       45462 :             move16();
    1141             :         }
    1142             :     }
    1143             : 
    1144       39923 :     hQMetaData->all_coherence_zero = !hMasa->config.coherencePresent;
    1145       39923 :     move16();
    1146             : 
    1147       39923 :     ivas_set_qmetadata_maxbit_req_fx( hQMetaData, ivas_format );
    1148             : 
    1149             :     /* Find maximum band usable */
    1150       39923 :     maxBin = extract_l( Mpy_32_32( st_ivas->hEncoderConfig->input_Fs /*q0*/, INV_CLDFB_BANDWIDTH_Q31 /*Q31*/ ) ); /*q0+q31-q31->q0*/
    1151       39923 :     maxBand = 0;
    1152       39923 :     move16();
    1153       39923 :     test();
    1154     1033308 :     WHILE( ( maxBand <= MASA_FREQUENCY_BANDS ) && ( MASA_band_grouping_24[maxBand] <= maxBin ) )
    1155             :     {
    1156      993385 :         test();
    1157      993385 :         maxBand = (UWord8) add( maxBand, 1 );
    1158      993385 :         move16(); /*because typecasting word16 to uword8*/
    1159             :     }
    1160       39923 :     maxBand = (UWord8) sub( maxBand, 1 );
    1161       39923 :     move16(); /*because typecasting word16 to uword8*/
    1162             : 
    1163       39923 :     st_ivas->hQMetaData->q_direction->cfg.inactiveBands = 0;
    1164       39923 :     masa_total_brate = ivas_total_brate;
    1165       39923 :     move16();
    1166       39923 :     move32();
    1167       39923 :     test();
    1168       39923 :     IF( EQ_32( ivas_format, MASA_ISM_FORMAT ) && EQ_32( st_ivas->ism_mode, ISM_MASA_MODE_DISC ) )
    1169             :     {
    1170        3142 :         masa_total_brate = calculate_cpe_brate_MASA_ISM_fx( st_ivas->ism_mode, ivas_total_brate, st_ivas->hEncoderConfig->nchan_ism ); /*q0*/
    1171             :     }
    1172       39923 :     test();
    1173       39923 :     test();
    1174       39923 :     IF( GE_32( masa_total_brate, IVAS_384k ) && ( EQ_16( ivas_format, MASA_FORMAT ) || EQ_16( ivas_format, MASA_ISM_FORMAT ) ) )
    1175             :     {
    1176             :         Word16 continueLoop;
    1177        2276 :         continueLoop = 1;
    1178        2276 :         move16();
    1179        2276 :         test();
    1180        4552 :         WHILE( ( maxBand > 5 ) && continueLoop )
    1181             :         {
    1182        2276 :             test();
    1183        2276 :             FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1184             :             {
    1185        2276 :                 IF( EQ_16( BASOP_Util_Cmp_Mant32Exp( hMasa->data.energy_fx[sf][maxBand - 1], hMasa->data.energy_e[sf][maxBand - 1], 100000 /*q0*/, 31 ), 1 ) )
    1186             :                 {
    1187        2276 :                     continueLoop = 0;
    1188        2276 :                     move16();
    1189        2276 :                     BREAK;
    1190             :                 }
    1191             :             }
    1192        2276 :             IF( continueLoop )
    1193             :             {
    1194           0 :                 maxBand = (UWord8) sub( maxBand, 1 );
    1195           0 :                 move16(); /*because typecasting word16 to uword8*/
    1196             :             }
    1197             :         }
    1198             : 
    1199        2276 :         IF( LT_16( maxBand, MASA_MAXIMUM_CODING_SUBBANDS ) )
    1200             :         {
    1201         300 :             st_ivas->hQMetaData->q_direction->cfg.inactiveBands = (UWord8) sub( MASA_MAXIMUM_CODING_SUBBANDS, maxBand );
    1202         300 :             move16(); /*because typecasting word16 to uword8*/
    1203             :         }
    1204             :         ELSE
    1205             :         {
    1206        1976 :             st_ivas->hQMetaData->q_direction->cfg.inactiveBands = 0;
    1207        1976 :             move16();
    1208             :         }
    1209             :     }
    1210             : 
    1211       39923 :     masa_sample_rate_band_correction_fx( &( hMasa->config ), hMasa->data.band_mapping, hQMetaData, maxBand, (UWord8) GE_32( masa_total_brate, IVAS_384k ), NULL );
    1212             : 
    1213       39923 :     IF( GE_16( hMasa->config.numTwoDirBands, hMasa->config.numCodingBands ) )
    1214             :     {
    1215         380 :         hMasa->config.numTwoDirBands = hMasa->config.numCodingBands;
    1216         380 :         move16();
    1217         380 :         set8_fx( (Word8 *) hMasa->data.twoDirBands, 1, hMasa->config.numCodingBands );
    1218             :     }
    1219             : 
    1220       39923 :     test();
    1221       39923 :     test();
    1222       39923 :     test();
    1223       39923 :     test();
    1224             :     /* Transmit stereo signals using a mono downmix at lowest bitrates */
    1225       39923 :     IF( ( EQ_16( ivas_format, MASA_FORMAT ) || EQ_16( ivas_format, MASA_ISM_FORMAT ) ) && EQ_16( st_ivas->nCPE, 1 ) && st_ivas->hCPE[0]->hStereoDft != NULL && st_ivas->hCPE[0]->hStereoDft->hConfig != NULL )
    1226             :     {
    1227       11938 :         IF( LT_32( L_sub( ivas_total_brate, ism_total_brate ), MASA_STEREO_MIN_BITRATE ) )
    1228             :         {
    1229        5484 :             st_ivas->hCPE[0]->hStereoDft->hConfig->force_mono_transmission = 1;
    1230             :         }
    1231             :         ELSE
    1232             :         {
    1233        6454 :             st_ivas->hCPE[0]->hStereoDft->hConfig->force_mono_transmission = 0;
    1234             :         }
    1235       11938 :         move16();
    1236             :     }
    1237             : 
    1238       39923 :     test();
    1239       39923 :     test();
    1240       39923 :     test();
    1241       39923 :     IF( EQ_16( ivas_format, MASA_ISM_FORMAT ) && ( EQ_16( st_ivas->ism_mode, ISM_MASA_MODE_MASA_ONE_OBJ ) || EQ_16( st_ivas->ism_mode, ISM_MASA_MODE_PARAM_ONE_OBJ ) || EQ_16( st_ivas->ism_mode, ISM_MASA_MODE_DISC ) ) )
    1242             :     {
    1243        7058 :         test();
    1244        7058 :         IF( EQ_16( st_ivas->hCPE[0]->element_mode, IVAS_CPE_DFT ) || LT_16( st_ivas->hMasa->data.hOmasaData->omasa_stereo_sw_cnt, OMASA_STEREO_SW_CNT_MAX ) )
    1245             :         {
    1246        3051 :             st_ivas->hMasa->data.hOmasaData->lp_noise_CPE_fx = extract_h( st_ivas->hCPE[0]->hCoreCoder[0]->lp_noise_32fx ); /*Q8*/
    1247             :         }
    1248             :         ELSE
    1249             :         {
    1250             :             /* ( st_ivas->hCPE[0]->hCoreCoder[0]->lp_noise + st_ivas->hCPE[0]->hCoreCoder[1]->lp_noise ) / CPE_CHANNELS; */
    1251        4007 :             st_ivas->hMasa->data.hOmasaData->lp_noise_CPE_fx = extract_h( L_mac( L_mult( extract_h( st_ivas->hCPE[0]->hCoreCoder[0]->lp_noise_32fx ), ONE_IN_Q14 ), extract_h( st_ivas->hCPE[0]->hCoreCoder[1]->lp_noise_32fx ), ONE_IN_Q14 ) ); /*Q8*/
    1252             :         }
    1253        7058 :         move16();
    1254             :     }
    1255             : 
    1256       39923 :     return error;
    1257             : }
    1258             : 
    1259             : 
    1260             : /*-----------------------------------------------------------------------*
    1261             :  * ivas_masa_surrcoh_signicant()
    1262             :  *
    1263             :  * Determine if surrounding coherence is significant in this frame and should be encoded
    1264             :  *-----------------------------------------------------------------------*/
    1265             : 
    1266        2589 : UWord8 ivas_masa_surrcoh_signicant_fx(
    1267             :     Word32 surroundingCoherence[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS],   /* i  : Surround coherence     Q31 */
    1268             :     Word32 diffuse_to_total_ratio[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS], /* i  : Diffuse to total ratio Q31 */
    1269             :     const Word16 nSubFrames,                                                          /* i  : Number of sub frames       */
    1270             :     const Word16 nBands                                                               /* i  : Number of frequency bands  */
    1271             : )
    1272             : {
    1273             :     Word32 significanceMeasure1, significanceMeasure2, significanceMeasure;
    1274             :     Word32 surrCohToTotal, surrCohToTotalSum, surrCohToTotalTimesDiffSum, diffSum;
    1275             :     Word32 sf, band;
    1276             :     Word16 surrCohToTotalSum_e, surrCohToTotalTimesDiffSum_e, diffSum_e;
    1277             : 
    1278             :     // input buffers Q=31
    1279        2589 :     Word32 surrCohSignificanceCoef = 858993459; //( 0.4 * ( 1 << q ) ) 0.4 scaled to Q=31
    1280        2589 :     move32();
    1281        2589 :     Word32 threshold = 214748365; //( 0.1 * ( 1 << q ) )  0.1 scaled to Q=31
    1282        2589 :     move32();
    1283        5802 :     FOR( sf = 0; sf < nSubFrames; sf++ )
    1284             :     {
    1285        3630 :         surrCohToTotalSum = 0;
    1286        3630 :         move32();
    1287        3630 :         surrCohToTotalSum_e = 0;
    1288        3630 :         move16();
    1289        3630 :         surrCohToTotalTimesDiffSum = 0;
    1290        3630 :         move32();
    1291        3630 :         surrCohToTotalTimesDiffSum_e = 0;
    1292        3630 :         move16();
    1293        3630 :         diffSum = 0;
    1294        3630 :         move32();
    1295        3630 :         diffSum_e = 0;
    1296        3630 :         move16();
    1297             : 
    1298       75702 :         FOR( band = 0; band < nBands; band++ )
    1299             :         {
    1300       72072 :             surrCohToTotal = Mpy_32_32( diffuse_to_total_ratio[sf][band], surroundingCoherence[sf][band] ); // Q31
    1301       72072 :             surrCohToTotalSum = BASOP_Util_Add_Mant32Exp( surrCohToTotalSum, surrCohToTotalSum_e, surrCohToTotal, 0, &surrCohToTotalSum_e );
    1302       72072 :             surrCohToTotalTimesDiffSum = BASOP_Util_Add_Mant32Exp( surrCohToTotalTimesDiffSum, surrCohToTotalTimesDiffSum_e, Mpy_32_32( (Word32) diffuse_to_total_ratio[sf][band], surrCohToTotal ), 0, &surrCohToTotalTimesDiffSum_e );
    1303       72072 :             diffSum = BASOP_Util_Add_Mant32Exp( diffSum, diffSum_e, diffuse_to_total_ratio[sf][band], 0, &diffSum_e );
    1304             :         }
    1305             : 
    1306             :         Word16 significanceMeasure1_e, significanceMeasure2_e;
    1307             :         Word16 significanceMeasure_e;
    1308        3630 :         significanceMeasure1 = L_deposit_h( BASOP_Util_Divide3216_Scale( surrCohToTotalSum, nBands, &significanceMeasure1_e ) );
    1309        3630 :         significanceMeasure1_e = add( significanceMeasure1_e, sub( surrCohToTotalSum_e, 15 ) );
    1310        3630 :         significanceMeasure2 = L_deposit_h( BASOP_Util_Divide3232_Scale( Mpy_32_32( surrCohSignificanceCoef, surrCohToTotalTimesDiffSum ), L_add( diffSum, EPSILON_FX ), &significanceMeasure2_e ) );
    1311        3630 :         significanceMeasure2_e = add( significanceMeasure2_e, sub( surrCohToTotalTimesDiffSum_e, diffSum_e ) );
    1312             : 
    1313        3630 :         IF( BASOP_Util_Cmp_Mant32Exp( significanceMeasure1, significanceMeasure1_e, significanceMeasure2, significanceMeasure2_e ) > 0 )
    1314             :         {
    1315        3605 :             significanceMeasure = significanceMeasure1;
    1316        3605 :             move32();
    1317        3605 :             significanceMeasure_e = significanceMeasure1_e;
    1318        3605 :             move16();
    1319             :         }
    1320             :         ELSE
    1321             :         {
    1322          25 :             significanceMeasure = significanceMeasure2;
    1323          25 :             move32();
    1324          25 :             significanceMeasure_e = significanceMeasure2_e;
    1325          25 :             move16();
    1326             :         }
    1327        3630 :         IF( BASOP_Util_Cmp_Mant32Exp( significanceMeasure, significanceMeasure_e, threshold, 0 ) > 0 )
    1328             :         {
    1329         417 :             return 1;
    1330             :         }
    1331             :     }
    1332             : 
    1333        2172 :     return 0;
    1334             : }
    1335             : 
    1336             : 
    1337             : /*-----------------------------------------------------------------------*
    1338             :  * Local functions
    1339             :  *-----------------------------------------------------------------------*/
    1340             : 
    1341       41605 : static void combine_freqbands_and_subframes_fx(
    1342             :     MASA_ENCODER_HANDLE hMasa )
    1343             : {
    1344             :     Word16 i, j, k, m;
    1345             :     Word16 aziRad, eleRad;
    1346             :     Word32 x[MASA_MAXIMUM_DIRECTIONS][MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
    1347             :     Word32 y[MASA_MAXIMUM_DIRECTIONS][MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
    1348             :     Word32 z[MASA_MAXIMUM_DIRECTIONS][MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
    1349             :     Word16 x_e[MASA_MAXIMUM_DIRECTIONS][MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
    1350             :     Word16 y_e[MASA_MAXIMUM_DIRECTIONS][MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
    1351             :     Word16 z_e[MASA_MAXIMUM_DIRECTIONS][MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
    1352             :     Word32 vecLen;
    1353             :     Word16 vecLen_e;
    1354             :     Word32 xSum, ySum, zSum;
    1355             :     Word16 xSum_e, ySum_e, zSum_e, common_e;
    1356             :     Word64 xSum_sq, ySum_sq, zSum_sq;
    1357             :     Word32 energySum;
    1358             :     Word16 energySum_e;
    1359             :     Word32 spreadCohSum;
    1360             :     Word16 spreadCohSum_e;
    1361             :     Word32 surrCohSum;
    1362             :     Word16 surrCohSum_e;
    1363             :     Word32 energyRatioSum;
    1364             :     Word16 energyRatioSum_e;
    1365             :     Word16 surrCohTemp;
    1366             :     Word32 energyRatioTemp;
    1367             :     Word32 energy[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
    1368             :     Word16 energy_e[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
    1369             :     Word16 brange[2];
    1370             :     UWord8 numCodingBands;
    1371             :     UWord8 numSf;
    1372             :     UWord8 numDirections;
    1373             :     MASA_METADATA_HANDLE hMeta;
    1374             :     UWord8 mergeRatiosOverSubframes;
    1375             :     UWord8 computeCoherence;
    1376             :     Word16 exp_diff;
    1377             :     Word32 L_tmp;
    1378             :     Word64 W_tmp;
    1379             :     Word16 q_shift;
    1380             : 
    1381       41605 :     numCodingBands = hMasa->config.numCodingBands;
    1382       41605 :     move16();
    1383       41605 :     numDirections = hMasa->config.numberOfDirections;
    1384       41605 :     move16();
    1385       41605 :     IF( EQ_16( hMasa->config.joinedSubframes, TRUE ) )
    1386             :     {
    1387        5550 :         numSf = 1;
    1388        5550 :         move16();
    1389             :     }
    1390             :     ELSE
    1391             :     {
    1392       36055 :         numSf = MAX_PARAM_SPATIAL_SUBFRAMES;
    1393       36055 :         move16();
    1394             :     }
    1395       41605 :     hMeta = &( hMasa->masaMetadata );
    1396             : 
    1397       41605 :     mergeRatiosOverSubframes = hMasa->config.mergeRatiosOverSubframes;
    1398       41605 :     move16();
    1399       41605 :     test();
    1400       41605 :     IF( hMasa->config.useCoherence && hMasa->config.coherencePresent )
    1401             :     {
    1402       20604 :         computeCoherence = 1;
    1403       20604 :         move16();
    1404             :     }
    1405             :     ELSE
    1406             :     {
    1407       21001 :         computeCoherence = 0;
    1408       21001 :         move16();
    1409             :     }
    1410             : 
    1411             :     /* If metadata subframes are joined then we need all energy to be in the first subframe for combining.
    1412             :      * This optimizes following computations a bit.
    1413             :      * Note: If energy is used elsewhere, then this can cause problems and local energy should be used. */
    1414       41605 :     IF( EQ_16( numSf, 1 ) )
    1415             :     {
    1416       22200 :         FOR( j = 1; j < MAX_PARAM_SPATIAL_SUBFRAMES; j++ )
    1417             :         {
    1418      416250 :             FOR( k = 0; k < MASA_FREQUENCY_BANDS; k++ )
    1419             :             {
    1420      399600 :                 hMasa->data.energy_fx[0][k] = BASOP_Util_Add_Mant32Exp( hMasa->data.energy_fx[0][k], hMasa->data.energy_e[0][k], hMasa->data.energy_fx[j][k], hMasa->data.energy_e[j][k], &hMasa->data.energy_e[0][k] ); // 31-hMasa->data.energy_e[0][k]
    1421      399600 :                 move32();
    1422             :             }
    1423             :         }
    1424             :     }
    1425             : 
    1426       41605 :     IF( LE_16( numCodingBands, MAX_REDUCED_NBANDS ) )
    1427             :     {
    1428             :         /* reduce metadata *frequency* resolution. time resolution is not touched */
    1429       84542 :         FOR( i = 0; i < numDirections; i++ )
    1430             :         {
    1431      212303 :             FOR( j = 0; j < numSf; j++ ) /* NB: for numSf==1, operates only on first sub-frame */
    1432             :             {
    1433     4143100 :                 FOR( k = 0; k < MASA_FREQUENCY_BANDS; k++ )
    1434             :                 {
    1435     3977376 :                     aziRad = extract_l( L_shl( Mpy_32_32( hMeta->directional_meta[i].azimuth_fx[j][k], PI_OVER_180_FX ), Q13 - Q22 ) );   // ((Q22, Q31) -> Q22) >> Q9 -> Q13
    1436     3977376 :                     eleRad = extract_l( L_shl( Mpy_32_32( hMeta->directional_meta[i].elevation_fx[j][k], PI_OVER_180_FX ), Q13 - Q22 ) ); // ((Q22, Q31) -> Q22) >> Q9 -> Q13
    1437     3977376 :                     vecLen = Mpy_32_32( hMeta->directional_meta[i].energy_ratio_fx[j][k], hMasa->data.energy_fx[j][k] );                  // (Q30, 31-hMasa->data.energy_e[j][k]) -> (31-hMasa->data.energy_e[j][k]) - Q1
    1438             : 
    1439             :                     /* Need more precision for some DTX cases with low energy frames */
    1440     3977376 :                     W_tmp = W_mult0_32_32( L_mult( getCosWord16( aziRad ), getCosWord16( eleRad ) ), vecLen ); // (Q29, (31-hMasa->data.energy_e[j][k]) - Q1) -> (Q59 - hMasa->data.energy_e[j][k])
    1441     3977376 :                     q_shift = W_norm( W_tmp );
    1442     3977376 :                     x[i][j][k] = W_extract_h( W_shl( W_tmp, q_shift ) );
    1443     3977376 :                     move32();
    1444     3977376 :                     x_e[i][j][k] = sub( Q31, add( sub( 59, hMasa->data.energy_e[j][k] ), sub( q_shift, 32 ) ) );
    1445     3977376 :                     move16();
    1446             : 
    1447     3977376 :                     W_tmp = W_mult0_32_32( L_mult0( getSinWord16( aziRad ), getCosWord16( eleRad ) ), vecLen ); // (Q29, (31-hMasa->data.energy_e[j][k]) - Q1) -> (Q59 - hMasa->data.energy_e[j][k])
    1448     3977376 :                     q_shift = W_norm( W_tmp );
    1449     3977376 :                     y[i][j][k] = W_extract_h( W_shl( W_tmp, q_shift ) );
    1450     3977376 :                     move32();
    1451     3977376 :                     y_e[i][j][k] = sub( Q31, add( sub( 59, hMasa->data.energy_e[j][k] ), sub( q_shift, 32 ) ) );
    1452     3977376 :                     move16();
    1453             : 
    1454     3977376 :                     W_tmp = W_mult0_32_32( L_mult0( getSinWord16( eleRad ), ONE_IN_Q14 ), vecLen ); // (Q29, (31-hMasa->data.energy_e[j][k]) - Q1) -> (Q59 - hMasa->data.energy_e[j][k])
    1455     3977376 :                     q_shift = W_norm( W_tmp );
    1456     3977376 :                     z[i][j][k] = W_extract_h( W_shl( W_tmp, q_shift ) );
    1457     3977376 :                     move32();
    1458     3977376 :                     z_e[i][j][k] = sub( Q31, add( sub( 59, hMasa->data.energy_e[j][k] ), sub( q_shift, 32 ) ) );
    1459     3977376 :                     move16();
    1460             :                 }
    1461             :             }
    1462             :         }
    1463             : 
    1464       84542 :         FOR( i = 0; i < numDirections; i++ )
    1465             :         {
    1466      212303 :             FOR( j = 0; j < numSf; j++ )
    1467             :             {
    1468     1155432 :                 FOR( k = 0; k < numCodingBands; k++ )
    1469             :                 {
    1470      989708 :                     brange[0] = hMasa->data.band_mapping[k];
    1471      989708 :                     move16();
    1472      989708 :                     brange[1] = hMasa->data.band_mapping[k + 1];
    1473      989708 :                     move16();
    1474             : 
    1475      989708 :                     xSum = 0;
    1476      989708 :                     ySum = 0;
    1477      989708 :                     zSum = 0;
    1478      989708 :                     energySum = 0;
    1479      989708 :                     spreadCohSum = 0;
    1480      989708 :                     xSum_e = 0;
    1481      989708 :                     ySum_e = 0;
    1482      989708 :                     zSum_e = 0;
    1483      989708 :                     energySum_e = 0;
    1484      989708 :                     spreadCohSum_e = 0;
    1485      989708 :                     move32();
    1486      989708 :                     move32();
    1487      989708 :                     move32();
    1488      989708 :                     move32();
    1489      989708 :                     move32();
    1490      989708 :                     move16();
    1491      989708 :                     move16();
    1492      989708 :                     move16();
    1493      989708 :                     move16();
    1494      989708 :                     move16();
    1495             : 
    1496     4860002 :                     FOR( m = brange[0]; m < brange[1]; m++ )
    1497             :                     {
    1498     3870294 :                         xSum = BASOP_Util_Add_Mant32Exp( xSum, xSum_e, x[i][j][m], x_e[i][j][m], &xSum_e );                                                    // xSum_e
    1499     3870294 :                         ySum = BASOP_Util_Add_Mant32Exp( ySum, ySum_e, y[i][j][m], y_e[i][j][m], &ySum_e );                                                    // ySum_e
    1500     3870294 :                         zSum = BASOP_Util_Add_Mant32Exp( zSum, zSum_e, z[i][j][m], z_e[i][j][m], &zSum_e );                                                    // zSum_e
    1501     3870294 :                         energySum = BASOP_Util_Add_Mant32Exp( energySum, energySum_e, hMasa->data.energy_fx[j][m], hMasa->data.energy_e[j][m], &energySum_e ); // energySum_e
    1502             :                     }
    1503      989708 :                     common_e = add( s_max( xSum_e, s_max( ySum_e, zSum_e ) ), 2 ); /*2 is guard bit for addition operations*/
    1504      989708 :                     xSum = L_shr( xSum, sub( common_e, xSum_e ) );                 /*common_e*/
    1505      989708 :                     ySum = L_shr( ySum, sub( common_e, ySum_e ) );                 /*common_e*/
    1506      989708 :                     zSum = L_shr( zSum, sub( common_e, zSum_e ) );                 /*common_e*/
    1507      989708 :                     aziRad = BASOP_util_atan2( ySum, xSum, 0 );                    // Q13
    1508      989708 :                     xSum_sq = W_mult0_32_32( xSum, xSum );                         // 2 * (31-common_e)
    1509      989708 :                     ySum_sq = W_mult0_32_32( ySum, ySum );                         // 2 *  (31-common_e)
    1510      989708 :                     zSum_sq = W_mult0_32_32( zSum, zSum );                         // 2 * (31-common_e)
    1511      989708 :                     W_tmp = W_add( xSum_sq, ySum_sq );                             // 2 *  (31-common_e)
    1512      989708 :                     q_shift = W_norm( W_tmp );
    1513      989708 :                     L_tmp = W_extract_h( W_shl( W_tmp, q_shift ) ); // 2 *  (31-common_e) + (q_shift -32)
    1514      989708 :                     exp_diff = sub( Q31, add( imult1616( 2, sub( 31, common_e ) ), sub( q_shift, 32 ) ) );
    1515      989708 :                     L_tmp = Sqrt32( L_tmp, &exp_diff );
    1516      989708 :                     eleRad = BASOP_util_atan2( zSum, L_tmp, sub( common_e, exp_diff ) ); // Q13
    1517             : 
    1518      989708 :                     hMeta->directional_meta[i].azimuth_fx[j][k] = L_shr( Mpy_32_16_1( _180_OVER_PI_Q25, aziRad ), Q1 ); // ((Q25, Q13) -> Q23) >> Q1 -> Q22
    1519      989708 :                     move32();
    1520      989708 :                     hMeta->directional_meta[i].elevation_fx[j][k] = L_shr( Mpy_32_16_1( _180_OVER_PI_Q25, eleRad ), Q1 ); // ((Q25, Q13) -> Q23) >> Q1 -> Q22
    1521      989708 :                     move32();
    1522             : 
    1523      989708 :                     W_tmp = W_add( xSum_sq, ySum_sq ); // 2 *  (31-common_e)
    1524      989708 :                     W_tmp = W_add( W_tmp, zSum_sq );   // 2 *  (31-common_e)
    1525      989708 :                     q_shift = W_norm( W_tmp );
    1526      989708 :                     vecLen = W_extract_h( W_shl( W_tmp, q_shift ) ); // 2 *  (31-common_e) + (q_shift -32)
    1527      989708 :                     exp_diff = sub( Q31, add( imult1616( 2, sub( 31, common_e ) ), sub( q_shift, 32 ) ) );
    1528      989708 :                     vecLen = Sqrt32( vecLen, &exp_diff );
    1529      989708 :                     vecLen_e = exp_diff;
    1530      989708 :                     move16();
    1531             : 
    1532     1979416 :                     hMeta->directional_meta[i].energy_ratio_fx[j][k] =
    1533      989708 :                         BASOP_Util_Divide3232_Scale_newton( vecLen, L_add( energySum, EPSILON_FX ), &exp_diff ); /*exp_diff+vecLen_e-energySum_e*/
    1534      989708 :                     move32();
    1535      989708 :                     exp_diff = add( exp_diff, sub( vecLen_e, energySum_e ) );
    1536     1979416 :                     hMeta->directional_meta[i].energy_ratio_fx[j][k] =
    1537      989708 :                         L_shl( hMeta->directional_meta[i].energy_ratio_fx[j][k], sub( exp_diff, Q1 ) ); // (Q31 - exp_diff ) -> Q30
    1538      989708 :                     move32();
    1539             : 
    1540      989708 :                     IF( computeCoherence )
    1541             :                     {
    1542     2379466 :                         FOR( m = brange[0]; m < brange[1]; m++ )
    1543             :                         {
    1544     1827408 :                             spreadCohSum = BASOP_Util_Add_Mant32Exp( spreadCohSum, spreadCohSum_e, Mpy_32_16_1( hMasa->data.energy_fx[j][m], hMeta->directional_meta[i].spread_coherence_fx[j][m] ), hMasa->data.energy_e[j][m], &spreadCohSum_e ); // 31-spreadCohSum_e
    1545             :                         }
    1546      552058 :                         hMeta->directional_meta[i].spread_coherence_fx[j][k] = BASOP_Util_Divide3232_Scale( spreadCohSum, L_add( energySum, EPSILON_FX ), &exp_diff ); /*exp_diff+spreadCohSum_e-energySum_e*/
    1547      552058 :                         exp_diff = add( exp_diff, sub( spreadCohSum_e, energySum_e ) );
    1548      552058 :                         move16();
    1549             :                         /* Saturation - LTV fix for values close to 1.0f+ */
    1550      552058 :                         hMeta->directional_meta[i].spread_coherence_fx[j][k] = shl_sat( hMeta->directional_meta[i].spread_coherence_fx[j][k], exp_diff ); // Q15
    1551      552058 :                         move16();
    1552             : 
    1553      552058 :                         IF( i == 0 )
    1554             :                         {
    1555      427914 :                             surrCohSum = 0;
    1556      427914 :                             surrCohSum_e = 0;
    1557      427914 :                             move32();
    1558      427914 :                             move16();
    1559     1833186 :                             FOR( m = brange[0]; m < brange[1]; m++ )
    1560             :                             {
    1561     1405272 :                                 surrCohSum = BASOP_Util_Add_Mant32Exp( surrCohSum, surrCohSum_e, Mpy_32_16_1( hMasa->data.energy_fx[j][m], hMeta->common_meta.surround_coherence_fx[j][m] ), hMasa->data.energy_e[j][m], &surrCohSum_e ); // 31-surrCohSum_e
    1562             :                             }
    1563      427914 :                             hMeta->common_meta.surround_coherence_fx[j][k] = BASOP_Util_Divide3232_Scale( surrCohSum, L_add( energySum, EPSILON_FX ), &exp_diff ); /*exp_diff+surrCohSum_e-energySum_e*/
    1564      427914 :                             move16();
    1565      427914 :                             exp_diff = add( exp_diff, sub( surrCohSum_e, energySum_e ) );
    1566             :                             /* Saturation - LTV fix for values close to 1.0f+ */
    1567      427914 :                             hMeta->common_meta.surround_coherence_fx[j][k] = shl_sat( hMeta->common_meta.surround_coherence_fx[j][k], exp_diff ); // Q15
    1568      427914 :                             move16();
    1569             :                         }
    1570             :                     }
    1571             : 
    1572      989708 :                     IF( i == 0 )
    1573             :                     {
    1574      805350 :                         energy[j][k] = energySum; // 31-energySum_e
    1575      805350 :                         energy_e[j][k] = energySum_e;
    1576      805350 :                         move32();
    1577      805350 :                         move16();
    1578             :                     }
    1579             :                 }
    1580             :             }
    1581             :         }
    1582             :     }
    1583        3642 :     ELSE IF( mergeRatiosOverSubframes ) /* keep frequency resolution */
    1584             :     {
    1585        5700 :         FOR( j = 0; j < numSf; j++ )
    1586             :         {
    1587      114000 :             FOR( k = 0; k < numCodingBands; k++ )
    1588             :             {
    1589      109440 :                 energy[j][k] = hMasa->data.energy_fx[j][k]; // 31-hMasa->data.energy_e[j][k]
    1590      109440 :                 energy_e[j][k] = hMasa->data.energy_e[j][k];
    1591      109440 :                 move32();
    1592      109440 :                 move16();
    1593             :             }
    1594             :         }
    1595             :     }
    1596             : 
    1597       41605 :     IF( mergeRatiosOverSubframes )
    1598             :     {
    1599      244114 :         FOR( k = 0; k < numCodingBands; k++ )
    1600             :         {
    1601      210663 :             energySum = 0;
    1602      210663 :             move32();
    1603      210663 :             energySum_e = 0;
    1604      210663 :             move16();
    1605     1053315 :             FOR( j = 0; j < numSf; j++ )
    1606             :             {
    1607      842652 :                 energySum = BASOP_Util_Add_Mant32Exp( energySum, energySum_e, energy[j][k], energy_e[j][k], &energySum_e ); // 31-energySum_e
    1608             :             }
    1609             : 
    1610      210663 :             IF( computeCoherence )
    1611             :             {
    1612      122333 :                 surrCohSum = 0;
    1613      122333 :                 surrCohSum_e = 0;
    1614      122333 :                 move32();
    1615      122333 :                 move16();
    1616      611665 :                 FOR( j = 0; j < numSf; j++ )
    1617             :                 {
    1618      489332 :                     surrCohSum = BASOP_Util_Add_Mant32Exp( surrCohSum, surrCohSum_e, Mpy_32_16_1( energy[j][k], hMeta->common_meta.surround_coherence_fx[j][k] ), energy_e[j][k], &surrCohSum_e ); // 31-surrCohSum_e
    1619             :                 }
    1620      122333 :                 surrCohTemp = BASOP_Util_Divide3232_Scale( surrCohSum, L_add( energySum, EPSILON_FX ), &exp_diff );
    1621      122333 :                 exp_diff = add( exp_diff, sub( surrCohSum_e, energySum_e ) );
    1622      122333 :                 surrCohTemp = shl_sat( surrCohTemp, exp_diff ); // Q15
    1623             : 
    1624      611665 :                 FOR( j = 0; j < numSf; j++ )
    1625             :                 {
    1626      489332 :                     hMeta->common_meta.surround_coherence_fx[j][k] = surrCohTemp; // Q15
    1627      489332 :                     move16();
    1628             :                 }
    1629             :             }
    1630             : 
    1631      459874 :             FOR( i = 0; i < numDirections; i++ )
    1632             :             {
    1633      249211 :                 energyRatioSum = 0;
    1634      249211 :                 energyRatioSum_e = 0;
    1635      249211 :                 move32();
    1636      249211 :                 move16();
    1637     1246055 :                 FOR( j = 0; j < numSf; j++ )
    1638             :                 {
    1639      996844 :                     energyRatioSum = BASOP_Util_Add_Mant32Exp( energyRatioSum, energyRatioSum_e, Mpy_32_32( energy[j][k], hMeta->directional_meta[i].energy_ratio_fx[j][k] ), add( energy_e[j][k], 1 ), &energyRatioSum_e ); // 31-energyRatioSum_e
    1640             :                 }
    1641      249211 :                 energyRatioTemp = BASOP_Util_Divide3232_Scale_newton( energyRatioSum, L_add( energySum, EPSILON_FX ), &exp_diff );
    1642      249211 :                 exp_diff = add( exp_diff, sub( energyRatioSum_e, energySum_e ) );
    1643      249211 :                 energyRatioTemp = L_shl( energyRatioTemp, sub( exp_diff, 1 ) ); // Q30
    1644             : 
    1645     1246055 :                 FOR( j = 0; j < numSf; j++ )
    1646             :                 {
    1647      996844 :                     hMeta->directional_meta[i].energy_ratio_fx[j][k] = energyRatioTemp; // Q30
    1648      996844 :                     move32();
    1649             :                 }
    1650             :             }
    1651             :         }
    1652             :     }
    1653             : 
    1654       41605 :     return;
    1655             : }
    1656             : 
    1657             : 
    1658             : /*-------------------------------------------------------------------*
    1659             :  * ivas_masa_combine_directions()
    1660             :  *
    1661             :  *
    1662             :  *-------------------------------------------------------------------*/
    1663             : 
    1664        9520 : void ivas_masa_combine_directions_fx(
    1665             :     MASA_ENCODER_HANDLE hMasa )
    1666             : {
    1667             :     Word16 i, j, k;
    1668             :     UWord8 numCodingBands;
    1669             :     UWord8 numSf;
    1670             :     UWord8 numDirections;
    1671             :     UWord8 computeCoherence;
    1672             :     MASA_METADATA_HANDLE hMeta;
    1673             : 
    1674             :     Word16 aziRad_fx;
    1675             :     Word16 eleRad_fx;
    1676             :     Word32 x_fx[MASA_MAXIMUM_DIRECTIONS][MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
    1677             :     Word32 y_fx[MASA_MAXIMUM_DIRECTIONS][MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
    1678             :     Word32 z_fx[MASA_MAXIMUM_DIRECTIONS][MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
    1679             :     Word32 vecLen_fx;
    1680             :     Word32 xSum_fx[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
    1681             :     Word32 ySum_fx[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
    1682             :     Word32 zSum_fx[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
    1683             :     Word32 sumVecLen_fx[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
    1684        9520 :     Word16 exp_sumVecLen_buff[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS], exp_sumVecLen = MIN16B_FLT_FX;
    1685        9520 :     move16();
    1686             :     Word32 tempImportance_fx;
    1687             :     Word32 importance_fx[MASA_FREQUENCY_BANDS];
    1688             :     Word16 exp_importance;
    1689             :     Word16 indicesOfLargest[MASA_FREQUENCY_BANDS];
    1690             : 
    1691             :     Word32 ratioSum_fx;
    1692             :     Word32 ambience1dir_fx;
    1693             :     Word32 ambience2dir_fx;
    1694             :     Word32 ambienceIncrease_fx;
    1695             :     Word32 origSurrCohEne_fx;
    1696             :     Word32 newSurrCohEne_fx;
    1697             : 
    1698        9520 :     numCodingBands = hMasa->config.numCodingBands;
    1699        9520 :     numDirections = hMasa->config.numberOfDirections;
    1700        9520 :     move16();
    1701        9520 :     move16();
    1702             : 
    1703        9520 :     IF( EQ_16( hMasa->config.joinedSubframes, TRUE ) )
    1704             :     {
    1705        1800 :         numSf = 1;
    1706             :     }
    1707             :     ELSE
    1708             :     {
    1709        7720 :         numSf = MAX_PARAM_SPATIAL_SUBFRAMES;
    1710             :     }
    1711        9520 :     move16();
    1712        9520 :     hMeta = &( hMasa->masaMetadata );
    1713             : 
    1714        9520 :     computeCoherence = hMasa->config.useCoherence && hMasa->config.coherencePresent;
    1715        9520 :     move16();
    1716        9520 :     Word16 azi_cos = 0, azi_sine = 0, ele_cos = 0, ele_sine = 0;
    1717        9520 :     move16();
    1718        9520 :     move16();
    1719        9520 :     move16();
    1720        9520 :     move16();
    1721       28560 :     FOR( i = 0; i < numDirections; i++ )
    1722             :     {
    1723       84400 :         FOR( j = 0; j < numSf; j++ )
    1724             :         {
    1725      865744 :             FOR( k = 0; k < numCodingBands; k++ )
    1726             :             {
    1727      800384 :                 aziRad_fx = extract_l( L_shr( Mpy_32_32( hMeta->directional_meta[i].azimuth_fx[j][k], PI_OVER_180_Q25 ), 3 ) ); // (Q22 + Q25 - 31) - 3 = Q13
    1728      800384 :                 azi_cos = getCosWord16( aziRad_fx );                                                                            // Q14
    1729      800384 :                 azi_sine = getSinWord16( aziRad_fx );                                                                           // Q15
    1730             : 
    1731      800384 :                 eleRad_fx = extract_l( L_shr( Mpy_32_32( hMeta->directional_meta[i].elevation_fx[j][k], PI_OVER_180_Q25 ), 3 ) ); // (Q22 + Q25 - 31) - 3 = Q13
    1732      800384 :                 ele_sine = getSinWord16( eleRad_fx );                                                                             // Q15
    1733      800384 :                 ele_cos = getCosWord16( eleRad_fx );                                                                              // Q14
    1734             : 
    1735      800384 :                 vecLen_fx = hMeta->directional_meta[i].energy_ratio_fx[j][k];
    1736      800384 :                 move32();
    1737             : 
    1738      800384 :                 x_fx[i][j][k] = L_mult0( azi_cos, ele_cos );                     // Q14+Q14
    1739      800384 :                 x_fx[i][j][k] = Mpy_32_32( x_fx[i][j][k], vecLen_fx );           // Q28+Q30-31
    1740      800384 :                 y_fx[i][j][k] = L_mult0( azi_sine, ele_cos );                    // Q15+Q14
    1741      800384 :                 y_fx[i][j][k] = Mpy_32_32( y_fx[i][j][k], vecLen_fx );           // Q29+Q30-31
    1742      800384 :                 z_fx[i][j][k] = Mpy_32_32( L_deposit_h( ele_sine ), vecLen_fx ); // Q16+Q15+Q30 - 31
    1743      800384 :                 move32();
    1744      800384 :                 move32();
    1745      800384 :                 move32();
    1746      800384 :                 move32();
    1747      800384 :                 move32();
    1748             :             }
    1749             :         }
    1750             :     }
    1751             : 
    1752             :     /* Compute sum vector */
    1753       42200 :     FOR( j = 0; j < numSf; j++ )
    1754             :     {
    1755      432872 :         FOR( k = 0; k < numCodingBands; k++ )
    1756             :         {
    1757      400192 :             xSum_fx[j][k] = L_add( x_fx[0][j][k], x_fx[1][j][k] ); // Q27
    1758      400192 :             ySum_fx[j][k] = L_add( y_fx[0][j][k], y_fx[1][j][k] ); // Q28
    1759      400192 :             zSum_fx[j][k] = L_add( z_fx[0][j][k], z_fx[1][j][k] ); // Q30
    1760      400192 :             move32();
    1761      400192 :             move32();
    1762      400192 :             move32();
    1763             : 
    1764      400192 :             Word32 var1 = Mpy_32_32( xSum_fx[j][k], xSum_fx[j][k] );                  // Q27 + Q27 - 31 //Q23
    1765      400192 :             Word32 var2 = Mpy_32_32( ySum_fx[j][k], ySum_fx[j][k] );                  // Q28 + Q28 - 31 //Q25
    1766      400192 :             Word32 var3 = Mpy_32_32( zSum_fx[j][k], zSum_fx[j][k] );                  // Q30 + Q30 - 31 //Q29
    1767      400192 :             Word32 var4 = L_add( L_add( var1, L_shr( var2, 2 ) ), L_shr( var3, 6 ) ); // Q23
    1768      400192 :             Word16 exp_var4 = 31 - Q23;
    1769      400192 :             move16();
    1770             : 
    1771      400192 :             Word16 exp_var5 = exp_var4;
    1772      400192 :             move16();
    1773      400192 :             Word32 var5 = 0;
    1774      400192 :             move32();
    1775             : 
    1776      400192 :             IF( var4 != 0 )
    1777             :             {
    1778      400192 :                 var5 = Sqrt32( var4, &exp_var5 );
    1779             :             }
    1780      400192 :             sumVecLen_fx[j][k] = var5;
    1781      400192 :             move32();
    1782      400192 :             exp_sumVecLen_buff[j][k] = exp_var5;
    1783      400192 :             move16();
    1784             :         }
    1785             :     }
    1786             : 
    1787             :     /*make commen exp for sumVecLen_fx buffer*/
    1788       42200 :     FOR( j = 0; j < numSf; j++ )
    1789             :     {
    1790      432872 :         FOR( k = 0; k < numCodingBands; k++ )
    1791             :         {
    1792      400192 :             exp_sumVecLen = s_max( exp_sumVecLen_buff[j][k], exp_sumVecLen );
    1793             :         }
    1794             :     }
    1795             : 
    1796       42200 :     FOR( j = 0; j < numSf; j++ )
    1797             :     {
    1798      432872 :         FOR( k = 0; k < numCodingBands; k++ )
    1799             :         {
    1800      400192 :             sumVecLen_fx[j][k] = L_shr( sumVecLen_fx[j][k], sub( exp_sumVecLen, exp_sumVecLen_buff[j][k] ) );
    1801      400192 :             move32();
    1802             :         }
    1803             :     }
    1804             : 
    1805             :     /* Estimate the importance of having two directions instead of one */
    1806             :     /* Reduced precision of importance_fx intentionally to Q13 to maintatin 0.0001f resolution */
    1807      132644 :     FOR( i = 0; i < numCodingBands; i++ )
    1808             :     {
    1809      123124 :         importance_fx[i] = 0;
    1810      123124 :         move32();
    1811      523316 :         FOR( j = 0; j < numSf; j++ )
    1812             :         {
    1813      400192 :             tempImportance_fx = L_shr( L_add( hMeta->directional_meta[0].energy_ratio_fx[j][i], hMeta->directional_meta[1].energy_ratio_fx[j][i] ), Q30 - Q13 ); // Q13
    1814      400192 :             tempImportance_fx = L_sub( tempImportance_fx, L_shr( sumVecLen_fx[j][i], sub( sub( Q31, exp_sumVecLen ), Q13 ) ) );                                  // Q13
    1815      400192 :             importance_fx[i] = L_add( importance_fx[i], tempImportance_fx );                                                                                     // Q13
    1816      400192 :             move32();
    1817             :         }
    1818             : 
    1819      123124 :         IF( NE_16( numSf, 1 ) )
    1820             :         {
    1821       92356 :             importance_fx[i] = L_shr( importance_fx[i], 2 ); // Q13
    1822       92356 :             move32();
    1823             :         }
    1824      123124 :         importance_fx[i] = Mpy_32_32( importance_fx[i], hMasa->data.importanceWeight_fx[i] ); //(Q13, Q30) -> Q12
    1825      123124 :         move32();
    1826             :     }
    1827        9520 :     exp_importance = Q31 - Q12;
    1828        9520 :     move16();
    1829             : 
    1830             :     /* Determine bands where to use two directions */
    1831        9520 :     find_n_largest_fx( importance_fx, exp_importance, indicesOfLargest, numCodingBands, hMasa->config.numTwoDirBands );
    1832             : 
    1833      132644 :     FOR( i = 0; i < numCodingBands; i++ )
    1834             :     {
    1835      123124 :         hMasa->data.twoDirBands[i] = 0;
    1836      123124 :         move16();
    1837             :     }
    1838             : 
    1839       31054 :     FOR( i = 0; i < hMasa->config.numTwoDirBands; i++ )
    1840             :     {
    1841       21534 :         hMasa->data.twoDirBands[indicesOfLargest[i]] = 1;
    1842       21534 :         move16();
    1843             :     }
    1844             : 
    1845             :     /* Combine directions on the remaining bands */
    1846      132644 :     FOR( i = 0; i < numCodingBands; i++ )
    1847             :     {
    1848      123124 :         IF( hMasa->data.twoDirBands[i] == 0 )
    1849             :         {
    1850      430178 :             FOR( j = 0; j < numSf; j++ )
    1851             :             {
    1852      328588 :                 aziRad_fx = BASOP_util_atan2( ySum_fx[j][i], xSum_fx[j][i], Q27 - Q28 ); // Q13
    1853      328588 :                 Word32 tmp1 = Mpy_32_32( xSum_fx[j][i], xSum_fx[j][i] );                 // Q27+Q27-31 //Q23
    1854      328588 :                 Word32 tmp2 = Mpy_32_32( ySum_fx[j][i], ySum_fx[j][i] );                 // Q28+Q28-31 //Q25
    1855      328588 :                 Word32 tmp3 = L_add( tmp1, L_shr( tmp2, 2 ) );                           // Q23
    1856      328588 :                 Word16 exp_tmp3 = 31 - Q23;
    1857      328588 :                 move16();
    1858      328588 :                 Word32 tmp4 = Sqrt32( tmp3, &exp_tmp3 );
    1859      328588 :                 eleRad_fx = BASOP_util_atan2( zSum_fx[j][i], tmp4, sub( sub( 31, Q30 ), exp_tmp3 ) );
    1860             : 
    1861      328588 :                 Word16 exp_tmp5 = 0;
    1862      328588 :                 move16();
    1863      328588 :                 Word16 tmp5 = BASOP_Util_Divide1616_Scale( aziRad_fx, EVS_PI_FX, &exp_tmp5 );
    1864      328588 :                 Word16 Q_tmp6 = 0;
    1865      328588 :                 move16();
    1866      328588 :                 Word32 tmp6 = L_mult( tmp5, 23040 /*180.0f in Q7*/ );
    1867      328588 :                 Q_tmp6 = sub( 31, add( exp_tmp5, 8 ) );
    1868             : 
    1869      328588 :                 Word16 exp_tmp7 = 0;
    1870      328588 :                 move16();
    1871      328588 :                 Word16 tmp7 = BASOP_Util_Divide1616_Scale( eleRad_fx, EVS_PI_FX, &exp_tmp7 );
    1872      328588 :                 Word16 Q_tmp8 = 0;
    1873      328588 :                 move16();
    1874      328588 :                 Word32 tmp8 = L_mult( tmp7, 23040 /*180.0f in Q7*/ );
    1875      328588 :                 Q_tmp8 = sub( 31, add( exp_tmp7, 8 ) );
    1876             : 
    1877      328588 :                 Scale_sig32( &tmp6, 1, Q22 - Q_tmp6 );
    1878      328588 :                 Scale_sig32( &tmp8, 1, Q22 - Q_tmp8 );
    1879             : 
    1880      328588 :                 hMeta->directional_meta[0].azimuth_fx[j][i] = tmp6;   // Q22
    1881      328588 :                 hMeta->directional_meta[0].elevation_fx[j][i] = tmp8; // Q22
    1882      328588 :                 move32();
    1883      328588 :                 move32();
    1884      328588 :                 ratioSum_fx = L_add( hMeta->directional_meta[0].energy_ratio_fx[j][i], hMeta->directional_meta[1].energy_ratio_fx[j][i] ); // Q30
    1885      328588 :                 IF( computeCoherence )
    1886             :                 {
    1887      127198 :                     Word32 var1 = Mpy_32_16_1( hMeta->directional_meta[0].energy_ratio_fx[j][i], hMeta->directional_meta[0].spread_coherence_fx[j][i] );
    1888      127198 :                     Word32 var2 = Mpy_32_16_1( hMeta->directional_meta[1].energy_ratio_fx[j][i], hMeta->directional_meta[1].spread_coherence_fx[j][i] );
    1889      127198 :                     Word32 var3 = L_add( var1, var2 ); // Q30
    1890      127198 :                     Word16 exp_var4 = 0;
    1891      127198 :                     move16();
    1892      127198 :                     Word32 var4 = BASOP_Util_Add_Mant32Exp( ratioSum_fx, 31 - Q30, EPSILON_FX_M, EPSILON_FX_E, &exp_var4 );
    1893      127198 :                     Word16 exp_var5 = 0;
    1894      127198 :                     move16();
    1895      127198 :                     Word16 var5 = BASOP_Util_Divide3232_Scale( var3, var4, &exp_var5 );
    1896      127198 :                     exp_var5 = add( exp_var5, ( sub( sub( 31, Q30 ), exp_var4 ) ) );
    1897      127198 :                     Scale_sig( &var5, 1, sub( Q15, sub( 15, exp_var5 ) ) );
    1898      127198 :                     hMeta->directional_meta[0].spread_coherence_fx[j][i] = var5; // Q15
    1899      127198 :                     move16();
    1900             :                 }
    1901             : 
    1902      328588 :                 ambience2dir_fx = L_sub( ONE_IN_Q30, ratioSum_fx ); // Q30
    1903      328588 :                 Word32 ambience2dir_fx_by_2 = L_shr( ambience2dir_fx, 1 );
    1904      328588 :                 Word32 var_a = L_add( L_add( hMeta->directional_meta[0].energy_ratio_fx[j][i], hMeta->directional_meta[1].energy_ratio_fx[j][i] ), ambience2dir_fx_by_2 ); // Q30
    1905      328588 :                 Word16 exp_var_b = 0;
    1906      328588 :                 move16();
    1907      328588 :                 Word16 var_b = BASOP_Util_Divide3232_Scale( sumVecLen_fx[j][i], var_a, &exp_var_b );
    1908      328588 :                 exp_var_b = add( exp_var_b, sub( exp_sumVecLen, 1 ) );
    1909      328588 :                 Word32 var_b_32 = L_deposit_h( var_b );
    1910      328588 :                 hMeta->directional_meta[0].energy_ratio_fx[j][i] = L_shr( var_b_32, 1 - exp_var_b ); // Q30
    1911      328588 :                 hMeta->directional_meta[1].energy_ratio_fx[j][i] = 0;                                // Q30
    1912      328588 :                 move16();
    1913      328588 :                 move16();
    1914      328588 :                 hMeta->common_meta.diffuse_to_total_ratio_fx[j][i] = L_sub( ONE_IN_Q30, hMeta->directional_meta[0].energy_ratio_fx[j][i] ); // Q30
    1915             : 
    1916      328588 :                 IF( computeCoherence )
    1917             :                 {
    1918      127198 :                     ambience1dir_fx = L_sub( ONE_IN_Q30, hMeta->directional_meta[0].energy_ratio_fx[j][i] );                                     // Q30
    1919      127198 :                     ambienceIncrease_fx = L_max( L_sub( ambience1dir_fx, ambience2dir_fx ), 0 );                                                 // Q30
    1920      127198 :                     origSurrCohEne_fx = Mpy_32_16_1( ambience2dir_fx /*Q30*/, hMeta->common_meta.surround_coherence_fx[j][i] /*Q15*/ );          // Q30
    1921      127198 :                     newSurrCohEne_fx = Mpy_32_16_1( ambienceIncrease_fx /*Q30*/, hMeta->directional_meta[0].spread_coherence_fx[j][i] /*Q15*/ ); // Q30
    1922             : 
    1923      127198 :                     Word16 exp_y = 0, exp_z = 0;
    1924      127198 :                     move16();
    1925      127198 :                     move16();
    1926      127198 :                     Word32 x = L_add( origSurrCohEne_fx, newSurrCohEne_fx ); // Q30
    1927      127198 :                     Word32 y = BASOP_Util_Add_Mant32Exp( ambience1dir_fx, 1, EPSILON_FX_M, EPSILON_FX_E, &exp_y );
    1928      127198 :                     Word16 z = BASOP_Util_Divide3232_Scale( x, y, &exp_z );
    1929      127198 :                     exp_z = add( exp_z, ( sub( 31 - Q30, exp_y ) ) );
    1930      127198 :                     z = shl_sat( z, exp_z ); // Q15
    1931      127198 :                     hMeta->common_meta.surround_coherence_fx[j][i] = s_min( MAX16B, z );
    1932      127198 :                     move16();
    1933             :                 }
    1934             :             }
    1935             :         }
    1936             :     }
    1937             : 
    1938        9520 :     return;
    1939             : }
    1940             : 
    1941        9520 : static void find_n_largest_fx(
    1942             :     const Word32 *input_fx, // Q(31 - exp_input)
    1943             :     Word16 exp_input,
    1944             :     Word16 *largestIndices,
    1945             :     const Word16 numElements,
    1946             :     const Word16 numLargest )
    1947             : {
    1948             :     Word16 i, j;
    1949             :     Word32 largestValue;
    1950             :     Word16 largestIndex;
    1951             :     Word32 values[MASA_FREQUENCY_BANDS];
    1952             : 
    1953      132644 :     FOR( j = 0; j < numElements; j++ )
    1954             :     {
    1955      123124 :         values[j] = input_fx[j]; // Q(31 - exp_input)
    1956      123124 :         move32();
    1957             :     }
    1958             : 
    1959       31054 :     FOR( i = 0; i < numLargest; i++ )
    1960             :     {
    1961       21534 :         largestValue = values[0]; // Q(31 - exp_input)
    1962       21534 :         move32();
    1963       21534 :         largestIndex = 0;
    1964       21534 :         move16();
    1965      342038 :         FOR( j = 1; j < numElements; j++ )
    1966             :         {
    1967      320504 :             IF( GT_32( values[j], largestValue ) )
    1968             :             {
    1969       41074 :                 largestValue = values[j]; // Q(31 - exp_input)
    1970       41074 :                 largestIndex = j;
    1971       41074 :                 move32();
    1972       41074 :                 move16();
    1973             :             }
    1974             :         }
    1975       21534 :         largestIndices[i] = largestIndex;
    1976       21534 :         move16();
    1977       21534 :         IF( exp_input != 0 )
    1978             :         {
    1979       21534 :             values[largestIndex] = L_negate( 1 << ( sub( 31, exp_input ) ) ); // Q(31 - exp_input)
    1980       21534 :             move32();
    1981             :         }
    1982             :         ELSE
    1983             :         {
    1984           0 :             values[largestIndex] = 1 << ( sub( 31, exp_input ) ); // Q(31 - exp_input)
    1985           0 :             move32();
    1986             :         }
    1987             :     }
    1988             : 
    1989        9520 :     return;
    1990             : }
    1991             : 
    1992       41605 : static void move_metadata_to_qmetadata_fx(
    1993             :     const MASA_ENCODER_HANDLE hMasa,
    1994             :     IVAS_QMETADATA_HANDLE hQMeta )
    1995             : {
    1996             :     Word16 dir, sf, band;
    1997             :     UWord8 numCodingBands;
    1998             :     UWord8 numDirections;
    1999             :     UWord8 numSf;
    2000             :     MASA_METADATA_HANDLE hMeta;
    2001             : 
    2002       41605 :     numCodingBands = hMasa->config.numCodingBands;
    2003       41605 :     numDirections = hMasa->config.numberOfDirections;
    2004       41605 :     move16();
    2005       41605 :     move16();
    2006       41605 :     move16();
    2007       41605 :     numSf = MAX_PARAM_SPATIAL_SUBFRAMES;
    2008       41605 :     if ( EQ_16( hMasa->config.joinedSubframes, TRUE ) )
    2009             :     {
    2010        5550 :         numSf = 1;
    2011        5550 :         move16();
    2012             :     }
    2013       41605 :     hMeta = &( hMasa->masaMetadata );
    2014             : 
    2015       89046 :     FOR( dir = 0; dir < numDirections; dir++ )
    2016             :     {
    2017      217567 :         FOR( sf = 0; sf < numSf; sf++ )
    2018             :         {
    2019     1526120 :             FOR( band = 0; band < numCodingBands; band++ )
    2020             :             {
    2021     1355994 :                 hQMeta->q_direction[dir].band_data[band].azimuth_fx[sf] = hMeta->directional_meta[dir].azimuth_fx[sf][band];           // Q22
    2022     1355994 :                 hQMeta->q_direction[dir].band_data[band].elevation_fx[sf] = hMeta->directional_meta[dir].elevation_fx[sf][band];       // Q22
    2023     1355994 :                 hQMeta->q_direction[dir].band_data[band].energy_ratio_fx[sf] = hMeta->directional_meta[dir].energy_ratio_fx[sf][band]; // Q30
    2024     1355994 :                 hQMeta->q_direction[dir].band_data[band].spherical_index[sf] = hMeta->directional_meta[dir].spherical_index[sf][band];
    2025     1355994 :                 move32();
    2026     1355994 :                 move32();
    2027     1355994 :                 move32();
    2028     1355994 :                 move16();
    2029             : 
    2030     1355994 :                 IF( hQMeta->q_direction[dir].coherence_band_data != NULL )
    2031             :                 {
    2032      990540 :                     hQMeta->q_direction[dir].coherence_band_data[band].spread_coherence[sf] = (UWord8) mult_r( hMeta->directional_meta[dir].spread_coherence_fx[sf][band], UINT8_MAX ); // Q15
    2033      990540 :                     move16();
    2034             :                 }
    2035             :             }
    2036             :         }
    2037             :     }
    2038             : 
    2039      191375 :     FOR( sf = 0; sf < numSf; sf++ )
    2040             :     {
    2041     1280362 :         FOR( band = 0; band < numCodingBands; band++ )
    2042             :         {
    2043     1130592 :             IF( hQMeta->surcoh_band_data != NULL )
    2044             :             {
    2045      765138 :                 hQMeta->surcoh_band_data[band].surround_coherence[sf] = (UWord8) mult_r( hMeta->common_meta.surround_coherence_fx[sf][band], UINT8_MAX ); // Q15
    2046      765138 :                 move16();
    2047             :             }
    2048             :         }
    2049             :     }
    2050             : 
    2051       41605 :     IF( GT_16( numDirections, 1 ) )
    2052             :     {
    2053       75232 :         FOR( band = 0; band < numCodingBands; band++ )
    2054             :         {
    2055       69396 :             hQMeta->twoDirBands[band] = hMasa->data.twoDirBands[band];
    2056       69396 :             move16();
    2057             :         }
    2058        5836 :         hQMeta->numTwoDirBands = hMasa->config.numTwoDirBands;
    2059        5836 :         move16();
    2060             :     }
    2061             : 
    2062             :     /* Copy spread coherence for DCT-based coding */
    2063       41605 :     test();
    2064       41605 :     IF( EQ_16( numSf, 1 ) && hMasa->config.useCoherence )
    2065             :     {
    2066        6620 :         FOR( dir = 0; dir < numDirections; dir++ )
    2067             :         {
    2068       15232 :             FOR( sf = 1; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    2069             :             {
    2070      200268 :                 FOR( band = 0; band < numCodingBands; band++ )
    2071             :                 {
    2072      188844 :                     hQMeta->q_direction[dir].coherence_band_data[band].spread_coherence[sf] = hQMeta->q_direction[dir].coherence_band_data[band].spread_coherence[0];
    2073      188844 :                     move16();
    2074             :                 }
    2075             :             }
    2076             :         }
    2077             :     }
    2078             : 
    2079       41605 :     return;
    2080             : }
    2081             : 
    2082             : 
    2083             : /* This function studies parametric MASA metadata to provide information for codec configuration */
    2084       39626 : static void detect_metadata_composition_fx(
    2085             :     const MASA_ENCODER_HANDLE hMasa, /* i  : MASA encoder data              */
    2086             :     UWord8 *joinedSubframes,         /* o  : Result of subframe composition */
    2087             :     UWord8 *coherencePresent,        /* o  : Result of coherence presence   */
    2088             :     UWord8 *isTwoDir                 /* o  : Result of two direction check  */
    2089             : )
    2090             : {
    2091             :     MASA_METADATA_FRAME *hMeta;
    2092             :     Word8 sf, band, dir, numDir;
    2093             :     Word16 nSubFrames;
    2094       39626 :     UWord8 dirValid[2] = { FALSE, FALSE };
    2095       39626 :     UWord8 cohPresent = FALSE;
    2096       39626 :     UWord8 sfDiffer = FALSE;
    2097             :     UWord8 sfSimilar;
    2098       39626 :     move16(); /*dirValid[0]*/
    2099       39626 :     move16(); /*dirValid[1]*/
    2100       39626 :     move16(); /*cohPresent*/
    2101       39626 :     move16(); /*sfDiffer*/
    2102             : 
    2103       39626 :     hMeta = &( hMasa->masaMetadata );
    2104       39626 :     numDir = (Word8) add( hMeta->descriptive_meta.numberOfDirections, 1 );
    2105       39626 :     move16();
    2106             : 
    2107       39626 :     *isTwoDir = FALSE;
    2108       39626 :     move16();
    2109             : 
    2110             :     /* First check for valid two directions */
    2111       39626 :     IF( EQ_16( numDir, 1 ) )
    2112             :     {
    2113       29726 :         dirValid[0] = TRUE;
    2114       29726 :         move16();
    2115             :     }
    2116             :     ELSE
    2117             :     {
    2118             :         /* Default assumption */
    2119        9900 :         *isTwoDir = TRUE;
    2120        9900 :         move16();
    2121             : 
    2122             :         /* Check for direct-to-total ratio values */
    2123       29700 :         FOR( dir = 0; dir < numDir; dir++ )
    2124             :         {
    2125       19800 :             sf = 0;
    2126       19800 :             move16();
    2127       39600 :             WHILE( !dirValid[dir] && ( sf < MAX_PARAM_SPATIAL_SUBFRAMES ) )
    2128             :             {
    2129       19800 :                 test();
    2130       19800 :                 band = 0;
    2131       19800 :                 move16();
    2132       39600 :                 WHILE( !dirValid[dir] && ( band < MASA_FREQUENCY_BANDS ) )
    2133             :                 {
    2134       19800 :                     test();
    2135       19800 :                     IF( GE_32( hMeta->directional_meta[dir].energy_ratio_fx[sf][band] /*q30*/, MASA_RATIO_THRESHOLD_FX >> 1 /*q30*/ ) )
    2136             :                     {
    2137       19800 :                         dirValid[dir] = TRUE;
    2138       19800 :                         move16();
    2139             :                     }
    2140       19800 :                     band = (Word8) add( band, 1 );
    2141             :                 }
    2142       19800 :                 sf = (Word8) add( sf, 1 );
    2143             :             }
    2144             :         }
    2145             : 
    2146        9900 :         test();
    2147        9900 :         IF( dirValid[1] == FALSE )
    2148             :         {
    2149             :             /* This handles also case where both are false. Then we just use first dir metadata. */
    2150           0 :             *isTwoDir = FALSE;
    2151           0 :             move16();
    2152             :         }
    2153        9900 :         ELSE IF( dirValid[0] == FALSE && EQ_16( dirValid[1], TRUE ) )
    2154             :         {
    2155           0 :             *isTwoDir = FALSE;
    2156           0 :             move16();
    2157             :             /* Copy data to first direction */
    2158           0 :             FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    2159             :             {
    2160           0 :                 FOR( band = 0; band < MASA_FREQUENCY_BANDS; band++ )
    2161             :                 {
    2162           0 :                     hMeta->directional_meta[0].spherical_index[sf][band] = hMeta->directional_meta[1].spherical_index[sf][band];
    2163           0 :                     move16();
    2164           0 :                     hMeta->directional_meta[0].azimuth_fx[sf][band] = hMeta->directional_meta[1].azimuth_fx[sf][band];                   /*q22*/
    2165           0 :                     hMeta->directional_meta[0].elevation_fx[sf][band] = hMeta->directional_meta[1].elevation_fx[sf][band];               /*q22*/
    2166           0 :                     hMeta->directional_meta[0].energy_ratio_fx[sf][band] = hMeta->directional_meta[1].energy_ratio_fx[sf][band];         /*q30*/
    2167           0 :                     hMeta->directional_meta[0].spread_coherence_fx[sf][band] = hMeta->directional_meta[1].spread_coherence_fx[sf][band]; /*q15*/
    2168           0 :                     move32();
    2169           0 :                     move16();
    2170           0 :                     move16();
    2171           0 :                     move16();
    2172             :                 }
    2173             :             }
    2174             :         }
    2175             : 
    2176        9900 :         if ( *isTwoDir == FALSE )
    2177             :         {
    2178             :             /* Further checks will be done with just one direction */
    2179           0 :             numDir = 1;
    2180           0 :             move16();
    2181             :         }
    2182             :     }
    2183             : 
    2184             :     /* Check if data over subframes is identical. Check is done by comparing to first subframe. */
    2185       39626 :     sfSimilar = TRUE;
    2186       39626 :     sf = 1;
    2187       39626 :     move16();
    2188       39626 :     move16();
    2189             : 
    2190       39626 :     test();
    2191       90352 :     WHILE( ( sfSimilar == TRUE ) && ( sf < MAX_PARAM_SPATIAL_SUBFRAMES ) )
    2192             :     {
    2193       50726 :         sfSimilar = are_masa_subframes_similar_fx( hMeta, 0, hMeta, sf );
    2194       50726 :         sf = (Word8) add( sf, 1 );
    2195       50726 :         move16();
    2196             :     }
    2197       39626 :     IF( sfSimilar == TRUE )
    2198        5550 :     sfDiffer = FALSE;
    2199             :     ELSE
    2200       34076 :         sfDiffer = TRUE;
    2201       39626 :     move16();
    2202             : 
    2203             :     /* Further checks can be done with just one subframe if they are identical */
    2204       39626 :     IF( EQ_16( sfDiffer, TRUE ) )
    2205       34076 :     nSubFrames = MAX_PARAM_SPATIAL_SUBFRAMES;
    2206             :     ELSE
    2207        5550 :         nSubFrames = 1;
    2208       39626 :     move16();
    2209             : 
    2210             :     /* Check spread coherence */
    2211       39626 :     dir = 0;
    2212       39626 :     move16();
    2213       39626 :     test();
    2214       79252 :     WHILE( cohPresent == FALSE && ( dir < numDir ) )
    2215             :     {
    2216       39626 :         sf = 0;
    2217       39626 :         move16();
    2218       39626 :         test();
    2219       82138 :         WHILE( cohPresent == FALSE && ( sf < nSubFrames ) )
    2220             :         {
    2221       42512 :             band = 0;
    2222       42512 :             move16();
    2223       42512 :             test();
    2224      277843 :             WHILE( cohPresent == FALSE /*has value zero*/ && ( band < MASA_FREQUENCY_BANDS ) )
    2225             :             {
    2226             :                 /* Check coherences for presence of coherence */
    2227      235331 :                 IF( GT_16( hMeta->directional_meta[dir].spread_coherence_fx[sf][band] /*Q15*/, MASA_COHERENCE_THRESHOLD_FX >> 16 ) ) /*Q15*/
    2228             :                 {
    2229       37829 :                     cohPresent = TRUE;
    2230       37829 :                     move16();
    2231             :                 }
    2232      235331 :                 band = (Word8) add( band, 1 );
    2233      235331 :                 move16();
    2234             :             }
    2235       42512 :             sf = (Word8) add( sf, 1 );
    2236       42512 :             move16();
    2237             :         }
    2238       39626 :         dir = (Word8) add( dir, 1 );
    2239       39626 :         move16();
    2240             :     }
    2241             : 
    2242             :     /* Check surround coherence separately if we do not have already knowledge of coherence */
    2243       39626 :     IF( cohPresent == FALSE )
    2244             :     {
    2245             :         Word32 surround_coherence_fx[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
    2246             :         Word32 diffuse_to_total_ratio_fx[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
    2247             :         Word16 i, j;
    2248        8985 :         FOR( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ )
    2249             :         {
    2250      179700 :             FOR( j = 0; j < MASA_FREQUENCY_BANDS; j++ )
    2251             :             {
    2252      172512 :                 surround_coherence_fx[i][j] = L_deposit_h( hMeta->common_meta.surround_coherence_fx[i][j] );          /*q31*/
    2253      172512 :                 diffuse_to_total_ratio_fx[i][j] = L_shl_sat( hMeta->common_meta.diffuse_to_total_ratio_fx[i][j], 1 ); /*q31*/
    2254             :             }
    2255             :         }
    2256        1797 :         cohPresent = ivas_masa_surrcoh_signicant_fx( surround_coherence_fx, diffuse_to_total_ratio_fx, nSubFrames, MASA_FREQUENCY_BANDS );
    2257             :     }
    2258             : 
    2259             :     /* Set output flags */
    2260       39626 :     IF( EQ_16( sfDiffer, TRUE ) )
    2261             :     {
    2262       34076 :         *joinedSubframes = FALSE;
    2263             :     }
    2264             :     ELSE
    2265             :     {
    2266        5550 :         *joinedSubframes = TRUE;
    2267             :     }
    2268       39626 :     move16();
    2269       39626 :     *coherencePresent = cohPresent;
    2270       39626 :     move16();
    2271             : 
    2272       39626 :     return;
    2273             : }
    2274             : 
    2275             : 
    2276             : /* Check and compensate energy ratios. This function verifies that energy ratios follow the principle of summing to one.
    2277             :  * In addition, it implements simple remainder-to-total handling where remainder energy is proportionally added to other
    2278             :  * ratios. */
    2279       39626 : static void compensate_energy_ratios_fx(
    2280             :     MASA_ENCODER_HANDLE hMasa )
    2281             : {
    2282             :     Word16 sf, band, dir;
    2283             :     Word32 ratioSum;
    2284             :     MASA_METADATA_HANDLE hMeta;
    2285             :     UWord8 numDirs;
    2286             : 
    2287       39626 :     hMeta = &( hMasa->masaMetadata );
    2288       39626 :     numDirs = hMasa->config.numberOfDirections;
    2289       39626 :     move16();
    2290             : 
    2291      198130 :     FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    2292             :     {
    2293     3962600 :         FOR( band = 0; band < MASA_FREQUENCY_BANDS; band++ )
    2294             :         {
    2295             :             /* Remainder is always set to zero and energy removal is compensated in following steps
    2296             :              * to other ratios. */
    2297     3804096 :             hMeta->common_meta.remainder_to_total_ratio_fx[sf][band] = 0; // Q30
    2298     3804096 :             move32();
    2299             : 
    2300     3804096 :             ratioSum = 0;
    2301     3804096 :             move32();
    2302     8558592 :             FOR( dir = 0; dir < numDirs; dir++ )
    2303             :             {
    2304     4754496 :                 ratioSum = L_add( ratioSum, hMeta->directional_meta[dir].energy_ratio_fx[sf][band] ); // Q30
    2305             :             }
    2306     3804096 :             ratioSum = L_add( ratioSum, hMeta->common_meta.diffuse_to_total_ratio_fx[sf][band] ); // Q30
    2307             : 
    2308     3804096 :             IF( ratioSum == 0 )
    2309             :             {
    2310           0 :                 FOR( dir = 0; dir < numDirs; dir++ )
    2311             :                 {
    2312           0 :                     hMeta->directional_meta[dir].energy_ratio_fx[sf][band] = 0; // Q30
    2313           0 :                     move32();
    2314             :                 }
    2315           0 :                 hMeta->common_meta.diffuse_to_total_ratio_fx[sf][band] = ONE_IN_Q30; // Q30
    2316           0 :                 move32();
    2317             :             }
    2318             :             // ELSE IF( NE_32( ratioSum, ONE_IN_Q30 ) )
    2319             :             ELSE /* Removing the check against 1 works well!!! */
    2320             :             {
    2321             :                 Word16 exp_diff;
    2322     8558592 :                 FOR( dir = 0; dir < numDirs; dir++ )
    2323             :                 {
    2324     9508992 :                     hMeta->directional_meta[dir].energy_ratio_fx[sf][band] =
    2325     4754496 :                         BASOP_Util_Divide3232_Scale_newton( hMeta->directional_meta[dir].energy_ratio_fx[sf][band], ratioSum, &exp_diff );
    2326     4754496 :                     move32();
    2327     4754496 :                     hMeta->directional_meta[dir].energy_ratio_fx[sf][band] = L_shl( hMeta->directional_meta[dir].energy_ratio_fx[sf][band], sub( exp_diff, Q1 ) ); // Q30
    2328     4754496 :                     move32();
    2329             :                 }
    2330     7608192 :                 hMeta->common_meta.diffuse_to_total_ratio_fx[sf][band] =
    2331     3804096 :                     BASOP_Util_Divide3232_Scale_newton( hMeta->common_meta.diffuse_to_total_ratio_fx[sf][band], ratioSum, &exp_diff );
    2332     3804096 :                 move32();
    2333     3804096 :                 hMeta->common_meta.diffuse_to_total_ratio_fx[sf][band] = L_shl( hMeta->common_meta.diffuse_to_total_ratio_fx[sf][band], sub( exp_diff, Q1 ) ); // Q30
    2334     3804096 :                 move32();
    2335             :             }
    2336             :         }
    2337             :     }
    2338             : 
    2339       39626 :     return;
    2340             : }
    2341             : 
    2342             : 
    2343             : /* If the bit budget is very low, reduce metadata further to either 1 subframe and 5 bands, or 1 band and 4 subframes, based on which works better */
    2344       25011 : static void reduce_metadata_further_fx(
    2345             :     MASA_ENCODER_HANDLE hMasa,
    2346             :     IVAS_QMETADATA_HANDLE hqmetadata,
    2347             :     const IVAS_FORMAT ivas_format )
    2348             : {
    2349             :     Word16 sf;
    2350             :     Word16 band;
    2351             :     Word16 selectedBand;
    2352             :     Word32 energy[MAX_PARAM_SPATIAL_SUBFRAMES][LOWBITRATE_NUM_BANDS];
    2353             :     Word64 W_tmp;
    2354             :     Word32 totalEnergySum;
    2355             :     UWord8 numCodingBands;
    2356             :     UWord8 computeCoherence;
    2357             :     Word32 onset_filter;
    2358             :     Word16 onset_filter_e, exp;
    2359             :     Word64 bandEnergy;
    2360             :     Word32 bandEnergy32;
    2361             :     Word16 bandEnergy_exp, shift;
    2362             :     UWord8 mergeOverFreqBands;
    2363             :     Word32 meanRatio;
    2364             :     Word16 tmp, tmp2, q_totalEnergySum;
    2365             : 
    2366       25011 :     numCodingBands = hMasa->config.numCodingBands;
    2367       25011 :     test();
    2368       25011 :     computeCoherence = hMasa->config.useCoherence && hMasa->config.coherencePresent;
    2369       25011 :     move16();
    2370       25011 :     move16();
    2371             : 
    2372             :     /* Set default values */
    2373       25011 :     selectedBand = 0;
    2374       25011 :     mergeOverFreqBands = 0;
    2375       25011 :     move16();
    2376       25011 :     move16();
    2377             : 
    2378             :     /* Get energy for the input data in 4-subframe, 5-band format */
    2379       25011 :     W_tmp = 0;
    2380       25011 :     move64();
    2381       25011 :     test();
    2382       25011 :     IF( EQ_32( ivas_format, MASA_FORMAT ) || EQ_32( ivas_format, MASA_ISM_FORMAT ) ) /* Energy data is in 4-subframe, 24-band format */
    2383             :     {
    2384       84280 :         FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    2385             :         {
    2386             :             Word16 brange[2];
    2387             :             Word32 eneSum;
    2388             :             Word16 m;
    2389             : 
    2390      404544 :             FOR( band = 0; band < numCodingBands; band++ )
    2391             :             {
    2392      337120 :                 brange[0] = hMasa->data.band_mapping[band];
    2393      337120 :                 brange[1] = hMasa->data.band_mapping[band + 1];
    2394      337120 :                 move16();
    2395      337120 :                 move16();
    2396             : 
    2397      337120 :                 eneSum = 0;
    2398      337120 :                 move32();
    2399     1949840 :                 FOR( m = brange[0]; m < brange[1]; m++ )
    2400             :                 {
    2401     1612720 :                     eneSum = L_add( eneSum, hMasa->data.energy_fx[sf][m] ); // hMasa->data.q_energy
    2402             :                 }
    2403      337120 :                 energy[sf][band] = eneSum; // hMasa->data.q_energy
    2404      337120 :                 move32();
    2405      337120 :                 W_tmp = W_add( W_tmp, eneSum ); // hMasa->data.q_energy
    2406             :             }
    2407             :         }
    2408             :     }
    2409             :     ELSE /* Energy data is already in 4-subframe, 5-band format */
    2410             :     {
    2411       40775 :         FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    2412             :         {
    2413      195720 :             FOR( band = 0; band < numCodingBands; band++ )
    2414             :             {
    2415      163100 :                 energy[sf][band] = hMasa->data.energy_fx[sf][band]; // hMasa->data.q_energy
    2416      163100 :                 move32();
    2417      163100 :                 W_tmp = W_add( W_tmp, energy[sf][band] ); // hMasa->data.q_energy
    2418             :             }
    2419             :         }
    2420             :     }
    2421             : 
    2422       25011 :     IF( W_tmp != 0 )
    2423             :     {
    2424       25011 :         tmp2 = sub( W_norm( W_tmp ), 1 ); // Usage of guard bits to avoid the large values of onset_detector in multiplication
    2425             :     }
    2426             :     ELSE
    2427             :     {
    2428           0 :         tmp2 = 0;
    2429           0 :         move16();
    2430             :     }
    2431             : 
    2432       25011 :     tmp2 = s_min( 32, tmp2 );
    2433       25011 :     totalEnergySum = W_extract_h( W_shl( W_tmp, tmp2 ) );
    2434       25011 :     tmp2 = sub( tmp2, 32 );
    2435       25011 :     q_totalEnergySum = add( hMasa->data.q_energy, tmp2 );
    2436             : 
    2437             :     /* Determine onsets */
    2438       25011 :     hMasa->data.onset_detector_1_fx = Mpy_32_32( hMasa->data.onset_detector_1_fx, LOWBITRATE_ONSET_ALPHA_Q31 );
    2439       25011 :     move32();
    2440             : 
    2441       25011 :     tmp = hMasa->data.q_onset_detector;
    2442       25011 :     move16();
    2443       25011 :     IF( BASOP_Util_Cmp_Mant32Exp( hMasa->data.onset_detector_1_fx, sub( 31, hMasa->data.q_onset_detector ), totalEnergySum, sub( 31, q_totalEnergySum ) ) < 0 )
    2444             :     {
    2445       24488 :         hMasa->data.onset_detector_1_fx = totalEnergySum; // hMasa->data.q_energy
    2446       24488 :         hMasa->data.q_onset_detector = add( hMasa->data.q_energy, tmp2 );
    2447       24488 :         move32();
    2448       24488 :         move16();
    2449             : 
    2450       24488 :         shift = norm_l( hMasa->data.onset_detector_2_fx );
    2451       24488 :         hMasa->data.onset_detector_2_fx = L_shl( hMasa->data.onset_detector_2_fx, shift );
    2452       24488 :         move32();
    2453       24488 :         tmp = add( tmp, shift );
    2454             :     }
    2455       25011 :     IF( LT_16( tmp, hMasa->data.q_onset_detector ) )
    2456             :     {
    2457         234 :         hMasa->data.onset_detector_1_fx = L_shr( hMasa->data.onset_detector_1_fx, sub( hMasa->data.q_onset_detector, tmp ) );                                                                                         // tmp
    2458         234 :         hMasa->data.onset_detector_2_fx = L_add( Mpy_32_32( LOWBITRATE_ONSET_BETA_Q31, hMasa->data.onset_detector_2_fx ), Mpy_32_32( ( ONE_IN_Q31 - LOWBITRATE_ONSET_BETA_Q31 ), hMasa->data.onset_detector_1_fx ) ); // tmp
    2459         234 :         hMasa->data.q_onset_detector = tmp;
    2460         234 :         move32();
    2461         234 :         move32();
    2462         234 :         move16();
    2463             :     }
    2464             :     ELSE
    2465             :     {
    2466       24777 :         hMasa->data.onset_detector_2_fx = L_add( L_shr( Mpy_32_32( LOWBITRATE_ONSET_BETA_Q31, hMasa->data.onset_detector_2_fx ), sub( tmp, hMasa->data.q_onset_detector ) ), Mpy_32_32( ( ONE_IN_Q31 - LOWBITRATE_ONSET_BETA_Q31 ), hMasa->data.onset_detector_1_fx ) ); // hMasa->data.q_onset_detector
    2467       24777 :         move32();
    2468             :     }
    2469       25011 :     hMasa->data.onset_detector_2_fx = L_shl( Mpy_32_32( LOWBITRATE_ONSET_GAIN_Q30, L_min( hMasa->data.onset_detector_1_fx, hMasa->data.onset_detector_2_fx ) ), 1 ); // hMasa->data.q_onset_detector
    2470       25011 :     move32();
    2471             : 
    2472       25011 :     IF( hMasa->data.onset_detector_1_fx != 0 )
    2473             :     {
    2474       25011 :         onset_filter = L_max( BASOP_Util_Divide3232_Scale_newton( hMasa->data.onset_detector_2_fx, hMasa->data.onset_detector_1_fx, &onset_filter_e ), 0 );
    2475             : 
    2476       25011 :         IF( BASOP_Util_Cmp_Mant32Exp( onset_filter, onset_filter_e, ONE_IN_Q31, 0 ) > 0 )
    2477             :         {
    2478       19273 :             onset_filter = ONE_IN_Q31;
    2479       19273 :             onset_filter_e = 0;
    2480       19273 :             move32();
    2481       19273 :             move16();
    2482             :         }
    2483             :     }
    2484             :     ELSE
    2485             :     {
    2486           0 :         onset_filter = ONE_IN_Q31;
    2487           0 :         onset_filter_e = 0;
    2488           0 :         move32();
    2489           0 :         move16();
    2490             :     }
    2491             :     /* If we have onset, continue checking if we should reduce in frequency instead of time. */
    2492       25011 :     IF( BASOP_Util_Cmp_Mant32Exp( onset_filter, onset_filter_e, 2126008812 /* 0.99f in Q31 */, 0 ) < 0 )
    2493             :     {
    2494             :         /* Determine one frequency band to use to represent all frequency bands */
    2495       23519 :         FOR( band = numCodingBands - 1; band >= 0; band-- )
    2496             :         {
    2497             :             Word32 threshold;
    2498             :             Word32 bandRatio;
    2499             : 
    2500             :             // threshold = totalEnergySum / ( MAX_PARAM_SPATIAL_SUBFRAMES * LOWBITRATE_NUM_BANDS ) * 0.5f; /* Average energy multiplied with energy ratio of 0.5f */
    2501       23440 :             threshold = BASOP_Util_Divide3232_Scale_newton( totalEnergySum, ( MAX_PARAM_SPATIAL_SUBFRAMES * LOWBITRATE_NUM_BANDS ) * 2, &exp ); /* Average energy multiplied with energy ratio of 0.5f */
    2502       23440 :             exp = add( exp, sub( sub( 31, add( hMasa->data.q_energy, tmp2 ) ), 31 ) );
    2503       23440 :             bandRatio = hqmetadata->q_direction[0].band_data[band].energy_ratio_fx[0]; // Q30
    2504       23440 :             move32();
    2505             : 
    2506       23440 :             bandEnergy = 0;
    2507       23440 :             move64();
    2508      117200 :             FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    2509             :             {
    2510       93760 :                 bandEnergy = W_mac_32_32( bandEnergy, energy[sf][band], 1 );
    2511             :             }
    2512       23440 :             shift = W_norm( bandEnergy );
    2513       23440 :             bandEnergy32 = W_extract_h( W_shl( bandEnergy, shift ) );
    2514       23440 :             bandEnergy_exp = sub( 63, add( add( hMasa->data.q_energy, 1 ), shift ) );
    2515             : 
    2516       23440 :             IF( BASOP_Util_Cmp_Mant32Exp( Mpy_32_32( L_shr( bandEnergy32, 2 ), bandRatio ), add( 1, bandEnergy_exp ), threshold, exp ) > 0 )
    2517             :             {
    2518        5600 :                 selectedBand = band;
    2519        5600 :                 move16();
    2520        5600 :                 BREAK;
    2521             :             }
    2522             :         }
    2523             : 
    2524             :         /* Determine if to merge over frequency instead of time */
    2525        5679 :         W_tmp = 0;
    2526        5679 :         move64();
    2527       28395 :         FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    2528             :         {
    2529      136296 :             FOR( band = 0; band < numCodingBands; band++ )
    2530             :             {
    2531      113580 :                 W_tmp = W_mac_32_16( W_tmp, Mpy_32_32( hqmetadata->q_direction[0].band_data[band].energy_ratio_fx[sf], energy[sf][band] ), 1 ); // hMasa->data.q_energy
    2532             :             }
    2533             :         }
    2534        5679 :         shift = W_norm( W_tmp );
    2535        5679 :         meanRatio = W_extract_h( W_shl( W_tmp, shift ) ); // Q:sub( add( hMasa->data.q_energy, shift ), 32 )
    2536        5679 :         shift = sub( 31, sub( add( hMasa->data.q_energy, shift ), 32 ) );
    2537             : 
    2538        5679 :         IF( totalEnergySum != 0 )
    2539             :         {
    2540        5679 :             meanRatio = BASOP_Util_Divide3232_Scale_newton( meanRatio, totalEnergySum, &exp );
    2541        5679 :             exp = add( exp, sub( shift, sub( 31, add( hMasa->data.q_energy, tmp2 ) ) ) ); // exp + (shift - (31 - hMasa->data.q_energy - tmp2)) => 1 + tmp2
    2542             :         }
    2543             :         ELSE
    2544             :         {
    2545           0 :             meanRatio = MAX_32;
    2546           0 :             exp = 31;
    2547           0 :             move32();
    2548           0 :             move16();
    2549             :         }
    2550             : 
    2551             :         /* If the ratio of the selected band is larger than the average ratio of all bands and if there is an onset, merge over frequency bands.
    2552             :          * Otherwise, merge over subframes. */
    2553        5679 :         IF( BASOP_Util_Cmp_Mant32Exp( hqmetadata->q_direction[0].band_data[selectedBand].energy_ratio_fx[0], 1, meanRatio, exp ) > 0 )
    2554             :         {
    2555        4001 :             mergeOverFreqBands = 1;
    2556        4001 :             move16();
    2557             :         }
    2558             :         ELSE
    2559             :         {
    2560        1678 :             mergeOverFreqBands = 0;
    2561        1678 :             move16();
    2562             :         }
    2563             :     }
    2564             :     ELSE
    2565             :     {
    2566       19332 :         mergeOverFreqBands = 0;
    2567       19332 :         move16();
    2568             :     }
    2569             : 
    2570             :     /* Merge values over subframes or frequency bands, depending on which one is less important */
    2571       25011 :     IF( !mergeOverFreqBands ) /* Merge values over subframes */
    2572             :     {
    2573             :         Word32 xSum, ySum, zSum;
    2574             :         Word64 W_xSum_sq, W_ySum_sq;
    2575             :         Word32 bandSumEnergy;
    2576             :         Word16 aziRad, eleRad, q_shift, exp_diff;
    2577             :         Word32 x, y, z;
    2578             :         Word32 veclen, L_tmp;
    2579             : 
    2580       21010 :         W_tmp = 0;
    2581       21010 :         move64();
    2582      126060 :         FOR( band = 0; band < numCodingBands; band++ )
    2583             :         {
    2584      105050 :             xSum = 0;
    2585      105050 :             ySum = 0;
    2586      105050 :             zSum = 0;
    2587      105050 :             bandSumEnergy = 0;
    2588      105050 :             move32();
    2589      105050 :             move32();
    2590      105050 :             move32();
    2591      105050 :             move32();
    2592             : 
    2593      525250 :             FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    2594             :             {
    2595      420200 :                 aziRad = extract_l( Mpy_32_32( hqmetadata->q_direction[0].band_data[band].azimuth_fx[sf], PI_OVER_180_Q22 ) );
    2596      420200 :                 eleRad = extract_l( Mpy_32_32( hqmetadata->q_direction[0].band_data[band].elevation_fx[sf], PI_OVER_180_Q22 ) );
    2597      420200 :                 veclen = Mpy_32_32( hqmetadata->q_direction[0].band_data[band].energy_ratio_fx[sf], energy[sf][band] ); // hMasa->data.q_energy - 1
    2598             : 
    2599      420200 :                 x = Mpy_32_32( L_mult( getCosWord16( aziRad ), getCosWord16( eleRad ) ), veclen ); // (Q29, hMasa->data.q_energy - Q1) -> hMasa->data.q_energy - Q3
    2600      420200 :                 move32();
    2601      420200 :                 y = Mpy_32_32( L_mult0( getSinWord16( aziRad ), getCosWord16( eleRad ) ), veclen ); // (Q29, hMasa->data.q_energy - Q1) -> hMasa->data.q_energy - Q3
    2602      420200 :                 move32();
    2603      420200 :                 z = Mpy_32_32( L_mult0( getSinWord16( eleRad ), ONE_IN_Q14 ), veclen ); // (Q29, hMasa->data.q_energy - Q1) -> hMasa->data.q_energy - Q3
    2604      420200 :                 move32();
    2605             : 
    2606      420200 :                 xSum = L_add( xSum, x );
    2607      420200 :                 ySum = L_add( ySum, y );
    2608      420200 :                 zSum = L_add( zSum, z );
    2609             : 
    2610      420200 :                 W_tmp = W_add( W_tmp, energy[sf][band] );
    2611             :             }
    2612             : 
    2613      105050 :             tmp2 = W_norm( W_tmp );
    2614      105050 :             tmp2 = s_min( 32, tmp2 );
    2615      105050 :             bandSumEnergy = W_extract_h( W_shl( W_tmp, tmp2 ) );
    2616      105050 :             tmp2 = sub( add( hMasa->data.q_energy, tmp2 ), 32 );
    2617             : 
    2618      105050 :             aziRad = BASOP_util_atan2( ySum, xSum, 0 ); // Q13
    2619      105050 :             W_xSum_sq = W_mult0_32_32( xSum, xSum );    // 2 * hMasa->data.q_energy - Q6
    2620      105050 :             W_ySum_sq = W_mult0_32_32( ySum, ySum );    // 2 * hMasa->data.q_energy - Q6
    2621      105050 :             W_tmp = W_add( W_xSum_sq, W_ySum_sq );      // 2 * hMasa->data.q_energy - Q6
    2622      105050 :             q_shift = W_norm( W_tmp );
    2623      105050 :             L_tmp = W_extract_h( W_shl( W_tmp, q_shift ) ); // 2 * hMasa->data.q_energy - Q6 + (q_shift -32)
    2624      105050 :             exp_diff = sub( Q31, add( sub( imult1616( 2, hMasa->data.q_energy ), Q6 ), sub( q_shift, 32 ) ) );
    2625      105050 :             L_tmp = Sqrt32( L_tmp, &exp_diff );
    2626      105050 :             eleRad = BASOP_util_atan2( zSum, L_tmp, sub( sub( 34, hMasa->data.q_energy ), exp_diff ) ); // Q13
    2627             : 
    2628      105050 :             hqmetadata->q_direction[0].band_data[band].azimuth_fx[0] = L_shr( Mpy_32_16_1( _180_OVER_PI_Q25, aziRad ), Q1 );   // ((Q25, Q13) -> Q23) >> Q1 -> Q22
    2629      105050 :             hqmetadata->q_direction[0].band_data[band].elevation_fx[0] = L_shr( Mpy_32_16_1( _180_OVER_PI_Q25, eleRad ), Q1 ); // ((Q25, Q13) -> Q23) >> Q1 -> Q22
    2630             : 
    2631             :             /* Energy ratio is already merged through time */
    2632      105050 :             test();
    2633      105050 :             IF( computeCoherence && hqmetadata->q_direction[0].coherence_band_data != NULL )
    2634             :             {
    2635             :                 Word16 spreadCoh;
    2636       27180 :                 Word32 spreadCohSum = 0;
    2637       27180 :                 move32();
    2638      135900 :                 FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    2639             :                 {
    2640      108720 :                     spreadCoh = div_s( (Word16) hqmetadata->q_direction[0].coherence_band_data[band].spread_coherence[sf], 255 ); // Q15
    2641      108720 :                     spreadCohSum = L_add( spreadCohSum, Mpy_32_16_1( energy[sf][band], spreadCoh ) );
    2642             :                 }
    2643             :                 // hqmetadata->q_direction[0].coherence_band_data[band].spread_coherence[0] = (uint8_t) roundf( spreadCohSum / ( bandSumEnergy + EPSILON ) * 255.0f );
    2644       27180 :                 tmp = BASOP_Util_Divide3232_Scale( spreadCohSum, bandSumEnergy, &exp );
    2645       27180 :                 exp = add( exp, sub( tmp2, hMasa->data.q_energy ) );
    2646       27180 :                 tmp = mult_r( tmp, 32640 /* 255 in Q7 */ );                                                                    // 15 - exp + 7 - 15 => 7 - exp
    2647       27180 :                 hqmetadata->q_direction[0].coherence_band_data[band].spread_coherence[0] = (UWord8) shr( tmp, sub( 7, exp ) ); // Q0
    2648       27180 :                 move16();
    2649             : 
    2650             :                 /* Copy spread coherence to the rest of subframes for the coherence coding algorithm. */
    2651      108720 :                 FOR( sf = 1; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    2652             :                 {
    2653       81540 :                     hqmetadata->q_direction[0].coherence_band_data[band].spread_coherence[sf] = hqmetadata->q_direction[0].coherence_band_data[band].spread_coherence[0]; // Q0
    2654       81540 :                     move16();
    2655             :                 }
    2656             : 
    2657             :                 /* Surround coherence is already merged through time */
    2658             :             }
    2659             :         }
    2660             : 
    2661       21010 :         hqmetadata->q_direction->cfg.nblocks = 1;
    2662       21010 :         hMasa->config.joinedSubframes = 1;
    2663       21010 :         move16();
    2664       21010 :         move16();
    2665             :     }
    2666             :     ELSE /* Merge values over frequency bands */
    2667             :     {
    2668             :         /* Use the selected frequency band to represent all data */
    2669       20005 :         FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    2670             :         {
    2671       16004 :             hqmetadata->q_direction[0].band_data[0].azimuth_fx[sf] = hqmetadata->q_direction[0].band_data[selectedBand].azimuth_fx[sf];           // Q22
    2672       16004 :             hqmetadata->q_direction[0].band_data[0].elevation_fx[sf] = hqmetadata->q_direction[0].band_data[selectedBand].elevation_fx[sf];       // Q22
    2673       16004 :             hqmetadata->q_direction[0].band_data[0].energy_ratio_fx[sf] = hqmetadata->q_direction[0].band_data[selectedBand].energy_ratio_fx[sf]; // Q30
    2674       16004 :             move32();
    2675       16004 :             move32();
    2676       16004 :             move32();
    2677       16004 :             IF( hqmetadata->q_direction[0].coherence_band_data != NULL )
    2678             :             {
    2679        5408 :                 hqmetadata->q_direction[0].coherence_band_data[0].spread_coherence[sf] = hqmetadata->q_direction[0].coherence_band_data[selectedBand].spread_coherence[sf]; // Q0
    2680        5408 :                 move16();
    2681             :             }
    2682       16004 :             IF( hqmetadata->surcoh_band_data != NULL )
    2683             :             {
    2684        5408 :                 hqmetadata->surcoh_band_data[0].surround_coherence[sf] = hqmetadata->surcoh_band_data[selectedBand].surround_coherence[sf];
    2685        5408 :                 move16();
    2686             :             }
    2687             :         }
    2688             : 
    2689             :         /* Copy coherence to rest of bands for the coherence coding algorithm. */
    2690       20005 :         FOR( band = 1; band < numCodingBands; band++ )
    2691             :         {
    2692       16004 :             IF( hqmetadata->q_direction[0].coherence_band_data != NULL )
    2693             :             {
    2694       27040 :                 FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    2695             :                 {
    2696       21632 :                     hqmetadata->q_direction[0].coherence_band_data[band].spread_coherence[sf] = hqmetadata->q_direction[0].coherence_band_data[0].spread_coherence[sf]; // Q0
    2697       21632 :                     move16();
    2698             :                 }
    2699             :             }
    2700       16004 :             IF( hqmetadata->q_direction[0].coherence_band_data != NULL )
    2701             :             {
    2702       27040 :                 FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    2703             :                 {
    2704       21632 :                     hqmetadata->surcoh_band_data[band].surround_coherence[sf] = hqmetadata->surcoh_band_data[0].surround_coherence[sf];
    2705       21632 :                     move16();
    2706             :                 }
    2707             :             }
    2708             :         }
    2709             : 
    2710        4001 :         hqmetadata->q_direction[0].cfg.nbands = 1;
    2711        4001 :         move16();
    2712             :     }
    2713             : 
    2714       25011 :     return;
    2715             : }
    2716             : 
    2717             : 
    2718       11680 : static Word16 encode_lfe_to_total_energy_ratio_fx(
    2719             :     MASA_ENCODER_HANDLE hMasa,    /* i/o: MASA encoder structure       */
    2720             :     BSTR_ENC_HANDLE hMetaData,    /* i/o: Metadata bitstream handle    */
    2721             :     const Word32 ivas_total_brate /* i  : IVAS total bitrate           */
    2722             : )
    2723             : {
    2724             :     Word16 i;
    2725             :     Word16 xq;
    2726             :     Word16 VQLevels;
    2727             :     Word32 maxLFESubFrameEner;
    2728             :     Word16 maxLFESubFrameEner_e;
    2729             :     Word32 log2LFEaverage;
    2730             :     Word32 log2LFEratio[4];
    2731             :     Word32 xqv[4];
    2732             :     Word32 linearLFEaverage;
    2733             :     Word16 linearLFEaverage_e;
    2734             :     Word16 lfeToTotalEnergyRatioIndices[3];
    2735             :     Word16 lfeAdaptiveVQBits;
    2736             :     Word16 lfeBitsWritten;
    2737             :     Word32 maxVal;
    2738             :     Word16 maxVal_e;
    2739             : 
    2740       11680 :     VQLevels = 0;
    2741       11680 :     move16();
    2742       11680 :     lfeAdaptiveVQBits = 0;
    2743       11680 :     move16();
    2744             : 
    2745             :     /* Determine maximum amount of LFE energy in any subframe */
    2746       11680 :     maxLFESubFrameEner = 0; // maxLFESubFrameEner_e
    2747       11680 :     move32();
    2748       11680 :     maxLFESubFrameEner_e = 0;
    2749       11680 :     move16();
    2750       58400 :     FOR( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ )
    2751             :     {
    2752       46720 :         IF( BASOP_Util_Cmp_Mant32Exp( hMasa->data.lfeToTotalEnergyRatio_fx[i], hMasa->data.lfeToTotalEnergyRatio_e[i], maxLFESubFrameEner, maxLFESubFrameEner_e ) > 0 )
    2753             :         {
    2754        4607 :             maxLFESubFrameEner = hMasa->data.lfeToTotalEnergyRatio_fx[i]; // hMasa->data.lfeToTotalEnergyRatio_e[i]
    2755        4607 :             move32();
    2756        4607 :             maxLFESubFrameEner_e = hMasa->data.lfeToTotalEnergyRatio_e[i];
    2757        4607 :             move16();
    2758             :         }
    2759             :     }
    2760             : 
    2761             :     /* Set default values for the indices */
    2762       46720 :     FOR( i = 0; i < 3; i++ )
    2763             :     {
    2764       35040 :         lfeToTotalEnergyRatioIndices[i] = 0;
    2765       35040 :         move16();
    2766             :     }
    2767             : 
    2768             :     /* Check if there is enough energy in any subframe. If not, send only 1 bit (0) and abort. */
    2769             :     /* If there is enough LFE energy at least in one subframe, quantize it. */
    2770       11680 :     IF( BASOP_Util_Cmp_Mant32Exp( maxLFESubFrameEner, maxLFESubFrameEner_e, 10737418 /* 0.005f in Q31 */, 0 ) > 0 )
    2771             :     {
    2772             :         /* Convert energy to log2 domain, and clamp it to reasonable values */
    2773        1904 :         log2LFEaverage = 0; // Q25
    2774        1904 :         move32();
    2775        9520 :         FOR( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ )
    2776             :         {
    2777             :             // log2LFEratio[i] = log2f( max( 0.001f, hMasa->data.lfeToTotalEnergyRatio[i] ) );
    2778        7616 :             maxVal = 2147484 /* 0.001f in Q31 */;
    2779        7616 :             move32();
    2780        7616 :             maxVal_e = 0;
    2781        7616 :             move16();
    2782        7616 :             IF( BASOP_Util_Cmp_Mant32Exp( hMasa->data.lfeToTotalEnergyRatio_fx[i], hMasa->data.lfeToTotalEnergyRatio_e[i], maxVal, maxVal_e ) > 0 )
    2783             :             {
    2784        7374 :                 maxVal = hMasa->data.lfeToTotalEnergyRatio_fx[i];
    2785        7374 :                 move32();
    2786        7374 :                 maxVal_e = hMasa->data.lfeToTotalEnergyRatio_e[i];
    2787        7374 :                 move16();
    2788             :             }
    2789        7616 :             log2LFEratio[i] = L_add( BASOP_Util_Log2( maxVal ), L_shl( maxVal_e, Q25 ) ); // Q25
    2790        7616 :             move32();
    2791        7616 :             IF( GT_32( log2LFEratio[i], ONE_IN_Q25 ) ) /* Corresponds to linear value 2.0f */
    2792             :             {
    2793           0 :                 log2LFEratio[i] = ONE_IN_Q25; // Q25
    2794           0 :                 move32();
    2795             :             }
    2796        7616 :             ELSE IF( LT_32( log2LFEratio[i], -301989888 /* -9.0f in Q25 */ ) )
    2797             :             {
    2798         289 :                 log2LFEratio[i] = -301989888 /* -9.0f in Q25 */; // Q25
    2799         289 :                 move32();
    2800             :             }
    2801        7616 :             log2LFEaverage = L_add( log2LFEaverage, Mpy_32_32( 536870912 /* 0.25f in Q31 */, log2LFEratio[i] ) ); // Q25
    2802             :         }
    2803             : 
    2804        1904 :         IF( EQ_32( ivas_total_brate, IVAS_13k2 ) )
    2805             :         {
    2806             :             /* Calculate adaptive 1-bit LFE quantizer index */
    2807             :             // linearLFEaverage = exp2f( log2LFEaverage ); /* Convert back to linear domain */
    2808         175 :             linearLFEaverage = BASOP_util_Pow2( log2LFEaverage, Q31 - Q25, &linearLFEaverage_e ); /* Convert back to linear domain */
    2809         175 :             linearLFEaverage = L_shl_sat( linearLFEaverage, sub( linearLFEaverage_e, Q1 ) );      // Q30
    2810         175 :             test();
    2811         175 :             IF( GT_32( linearLFEaverage, MCMASA_LFE_1BIT_THRES_Q30 ) &&
    2812             :                 GT_32( linearLFEaverage, L_add( L_add( MCMASA_LFE_BETA_Q30 >> Q1, L_shr( hMasa->data.prevq_lfeToTotalEnergyRatio_fx, Q2 ) ),
    2813             :                                                 L_shr( Mpy_32_32( MCMASA_LFE_ALPHA_Q30, hMasa->data.prevq_lfeToTotalEnergyRatio_fx ), Q1 ) ) ) )
    2814             :             {
    2815         128 :                 lfeToTotalEnergyRatioIndices[0] = 1;
    2816         128 :                 move16();
    2817         128 :                 IF( EQ_16( hMasa->data.prevq_lfeIndex, 1 ) )
    2818             :                 {
    2819          86 :                     hMasa->data.prevq_lfeToTotalEnergyRatio_fx = L_add( L_shr( hMasa->data.prevq_lfeToTotalEnergyRatio_fx, Q1 ), 125627793 /* MCMASA_LFE_THETA * MCMASA_LFE_BETA in Q30 */ ); /* larger "bump-up" to LFE-to-total energy ratio */ // Q30
    2820          86 :                     move32();
    2821             :                 }
    2822             :                 ELSE
    2823             :                 {
    2824          42 :                     hMasa->data.prevq_lfeToTotalEnergyRatio_fx = L_add( L_shr( hMasa->data.prevq_lfeToTotalEnergyRatio_fx, Q1 ), MCMASA_LFE_BETA_Q30 ); /* default "bump-up" to LFE-to-total energy ratio */ // Q30
    2825          42 :                     move32();
    2826             :                 }
    2827             :             }
    2828             :             ELSE
    2829             :             {
    2830          47 :                 hMasa->data.prevq_lfeToTotalEnergyRatio_fx = Mpy_32_32( MCMASA_LFE_ALPHA_Q30, hMasa->data.prevq_lfeToTotalEnergyRatio_fx ); /* exponential decay */ // Q30
    2831          47 :                 move32();
    2832             :             }
    2833             : 
    2834         175 :             IF( GE_32( hMasa->data.prevq_lfeToTotalEnergyRatio_fx, ONE_IN_Q30 ) )
    2835             :             {
    2836           0 :                 hMasa->data.prevq_lfeToTotalEnergyRatio_fx = ONE_IN_Q31; // Q31
    2837           0 :                 move32();
    2838             :             }
    2839             :             ELSE
    2840             :             {
    2841         175 :                 hMasa->data.prevq_lfeToTotalEnergyRatio_fx = L_shl( hMasa->data.prevq_lfeToTotalEnergyRatio_fx, Q1 ); // Q31
    2842         175 :                 move32();
    2843             :             }
    2844         175 :             hMasa->data.prevq_lfeIndex = lfeToTotalEnergyRatioIndices[0]; /* Update to previous frame's index memories */
    2845         175 :             move16();
    2846             :         }
    2847             :         ELSE /* Bitrate >= 16.4 kbps */
    2848             :         {
    2849             :             /* Do 1st stage scalar quantization */
    2850        1729 :             lfeToTotalEnergyRatioIndices[0] = 1;
    2851        1729 :             move16();
    2852        1729 :             lfeToTotalEnergyRatioIndices[1] = usquant_fx( extract_l( L_shr( log2LFEaverage, Q14 ) ), &xq, MCMASA_LFE_QLOW_Q11, MCMASA_LFE_DELTA_Q10, 8 );
    2853        1729 :             move16();
    2854             : 
    2855        1729 :             IF( GE_32( ivas_total_brate, IVAS_24k4 ) ) /* Vector quantization is applied if bitrate >= 24.4 kbps */
    2856             :             {
    2857             :                 /* Remove scalar value from the vector*/
    2858        8120 :                 FOR( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ )
    2859             :                 {
    2860        6496 :                     log2LFEratio[i] = L_sub( log2LFEratio[i], L_shl( xq, Q14 ) ); // Q25
    2861        6496 :                     move32();
    2862             :                 }
    2863             : 
    2864             :                 /* Vector quantize residual with energy adaptive bit allocation */
    2865        1624 :                 SWITCH( lfeToTotalEnergyRatioIndices[1] )
    2866             :                 {
    2867         222 :                     case 0:
    2868             :                     case 1:
    2869         222 :                         VQLevels = 0;
    2870         222 :                         move16();
    2871         222 :                         lfeAdaptiveVQBits = 0;
    2872         222 :                         move16();
    2873         222 :                         BREAK;
    2874          98 :                     case 2:
    2875          98 :                         VQLevels = 2;
    2876          98 :                         move16();
    2877          98 :                         lfeAdaptiveVQBits = 1;
    2878          98 :                         move16();
    2879          98 :                         BREAK;
    2880          97 :                     case 3:
    2881          97 :                         VQLevels = 4;
    2882          97 :                         move16();
    2883          97 :                         lfeAdaptiveVQBits = 2;
    2884          97 :                         move16();
    2885          97 :                         BREAK;
    2886         246 :                     case 4:
    2887         246 :                         VQLevels = 8;
    2888         246 :                         move16();
    2889         246 :                         lfeAdaptiveVQBits = 3;
    2890         246 :                         move16();
    2891         246 :                         BREAK;
    2892         961 :                     default:
    2893         961 :                         VQLevels = 16;
    2894         961 :                         move16();
    2895         961 :                         lfeAdaptiveVQBits = 4;
    2896         961 :                         move16();
    2897             :                 }
    2898             : 
    2899        1624 :                 IF( VQLevels > 0 )
    2900             :                 {
    2901        1402 :                     lfeToTotalEnergyRatioIndices[2] = vquant_ivas_fx( log2LFEratio, 0, xqv, McMASA_LFEGain_vectors_fx, 4, VQLevels );
    2902        1402 :                     move16();
    2903             :                 }
    2904             :             }
    2905             :         }
    2906             :     }
    2907             : 
    2908             :     /* Write first LFE bit */
    2909       11680 :     lfeBitsWritten = 0;
    2910       11680 :     move16();
    2911       11680 :     push_next_indice( hMetaData, lfeToTotalEnergyRatioIndices[0], 1 );
    2912       11680 :     lfeBitsWritten = add( lfeBitsWritten, 1 );
    2913             : 
    2914       11680 :     test();
    2915       11680 :     IF( EQ_16( lfeToTotalEnergyRatioIndices[0], 1 ) && GE_32( ivas_total_brate, IVAS_16k4 ) )
    2916             :     {
    2917             :         /* If bitrate >= 16.4kbit/s, send 1-bit on/off + 3-bit scalar */
    2918        1729 :         push_next_indice( hMetaData, lfeToTotalEnergyRatioIndices[1], 3 );
    2919        1729 :         lfeBitsWritten = add( lfeBitsWritten, 3 );
    2920             : 
    2921             :         /*  If bitrate >= 24.4kbit/s, use adaptive 1 + (3.. 7) bit quantizer */
    2922        1729 :         IF( GE_32( ivas_total_brate, IVAS_24k4 ) )
    2923             :         {
    2924             :             /* Vector quantize residual with energy adaptive bit allocation */
    2925        1624 :             IF( lfeAdaptiveVQBits > 0 )
    2926             :             {
    2927        1402 :                 push_next_indice( hMetaData, lfeToTotalEnergyRatioIndices[2], lfeAdaptiveVQBits );
    2928        1402 :                 lfeBitsWritten = add( lfeBitsWritten, lfeAdaptiveVQBits );
    2929             :             }
    2930             :         }
    2931             :     }
    2932             : 
    2933       11680 :     return lfeBitsWritten;
    2934             : }
    2935             : 
    2936             : 
    2937             : /*-------------------------------------------------------------------*
    2938             :  * ivas_masa_enc_reconfigure()
    2939             :  *
    2940             :  * Reconfigure IVAS MASA encoder
    2941             :  *-------------------------------------------------------------------*/
    2942             : 
    2943       30626 : void ivas_masa_enc_reconfigure_fx(
    2944             :     Encoder_Struct *st_ivas /* i/o: IVAS encoder structure */
    2945             : )
    2946             : {
    2947             :     Word16 n, tmp;
    2948             :     Word16 sce_id, cpe_id;
    2949             :     Word32 ivas_total_brate;
    2950             :     Word32 ism_total_brate;
    2951             :     Word32 tmp_br, tmp_mod;
    2952             : 
    2953       30626 :     ivas_total_brate = st_ivas->hEncoderConfig->ivas_total_brate;
    2954       30626 :     move32();
    2955             : 
    2956       30626 :     ism_total_brate = 0;
    2957       30626 :     move32();
    2958       30626 :     test();
    2959       30626 :     test();
    2960       30626 :     test();
    2961       30626 :     test();
    2962       30626 :     IF( EQ_32( st_ivas->hEncoderConfig->ivas_format, MASA_ISM_FORMAT ) && st_ivas->nSCE > 0 && ( EQ_32( st_ivas->ism_mode, ISM_MASA_MODE_DISC ) || EQ_32( st_ivas->ism_mode, ISM_MASA_MODE_PARAM_ONE_OBJ ) || EQ_32( st_ivas->ism_mode, ISM_MASA_MODE_MASA_ONE_OBJ ) ) )
    2963             :     {
    2964           0 :         FOR( sce_id = 0; sce_id < st_ivas->nSCE; sce_id++ )
    2965             :         {
    2966           0 :             ism_total_brate = L_add( ism_total_brate, st_ivas->hSCE[sce_id]->element_brate );
    2967             :         }
    2968             :     }
    2969             : 
    2970       30626 :     IF( NE_32( ivas_total_brate, st_ivas->hEncoderConfig->last_ivas_total_brate ) )
    2971             :     {
    2972        1269 :         iDiv_and_mod_32( ivas_total_brate, st_ivas->nchan_transport, &tmp_br, &tmp_mod, 0 );
    2973        1934 :         FOR( sce_id = 0; sce_id < st_ivas->nSCE; sce_id++ )
    2974             :         {
    2975         665 :             copy_encoder_config_fx( st_ivas, st_ivas->hSCE[sce_id]->hCoreCoder[0], 0 );
    2976         665 :             st_ivas->hSCE[sce_id]->element_brate = tmp_br;
    2977         665 :             st_ivas->hSCE[sce_id]->hCoreCoder[0]->total_brate = st_ivas->hSCE[sce_id]->element_brate; /* dummy initialization for getting right pointers initialization of input buffers in init_coder_ace_plus() */
    2978         665 :             move32();
    2979         665 :             move32();
    2980             :         }
    2981             : 
    2982        1873 :         FOR( cpe_id = 0; cpe_id < st_ivas->nCPE; cpe_id++ )
    2983             :         {
    2984         604 :             st_ivas->hCPE[cpe_id]->element_brate = imult3216( tmp_br, 2 ); //( ivas_total_brate / st_ivas->nchan_transport ) * CPE_CHANNELS;
    2985         604 :             move32();
    2986             : 
    2987         604 :             IF( GT_16( st_ivas->nCPE, 1 ) )
    2988             :             {
    2989           0 :                 tmp = 1;
    2990             :             }
    2991             :             ELSE
    2992             :             {
    2993         604 :                 tmp = CPE_CHANNELS;
    2994             :             }
    2995         604 :             move16();
    2996             :             /* prepare bitstream buffers */
    2997        1812 :             FOR( n = 0; n < CPE_CHANNELS; n++ )
    2998             :             {
    2999        1208 :                 copy_encoder_config_fx( st_ivas, st_ivas->hCPE[cpe_id]->hCoreCoder[n], 0 );
    3000             :                 /* st_ivas->hCPE[cpe_id]->hCoreCoder[n]->total_brate = st_ivas->hCPE[cpe_id]->element_brate / ( st_ivas->nCPE > 1 ? 1 : CPE_CHANNELS ); */
    3001        1208 :                 st_ivas->hCPE[cpe_id]->hCoreCoder[n]->total_brate = L_shr( st_ivas->hCPE[cpe_id]->element_brate, sub( tmp, 1 ) ); /* dummy initialization for getting right pointers initialization of input buffers in init_coder_ace_plus() */
    3002        1208 :                 move32();
    3003             :             }
    3004             : 
    3005         604 :             IF( LT_32( L_sub( ivas_total_brate, ism_total_brate ), MIN_BRATE_MDCT_STEREO ) )
    3006             :             {
    3007         218 :                 st_ivas->hCPE[cpe_id]->element_mode = IVAS_CPE_DFT;
    3008             :             }
    3009             :             ELSE
    3010             :             {
    3011         386 :                 st_ivas->hCPE[cpe_id]->element_mode = IVAS_CPE_MDCT;
    3012             :             }
    3013         604 :             move16();
    3014             :         }
    3015             : 
    3016        1269 :         ivas_masa_set_elements_fx( ivas_total_brate, st_ivas->mc_mode, st_ivas->nchan_transport, st_ivas->hQMetaData, &tmp, &tmp, &tmp, st_ivas->hEncoderConfig->ivas_format, st_ivas->ism_mode, ism_total_brate );
    3017             :     }
    3018             : 
    3019       30626 :     return;
    3020             : }
    3021             : 
    3022             : 
    3023             : /*-------------------------------------------------------------------*
    3024             :  * average_masa_metadata()
    3025             :  *
    3026             :  * Average MASA metadata frame subframe contents: applies aggregation over time
    3027             :  *-------------------------------------------------------------------*/
    3028             : 
    3029           0 : static void average_masa_metadata_fx(
    3030             :     MASA_METADATA_FRAME *hMeta,
    3031             :     Word32 energy[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS],   /*i Q(31 - energy_e) */
    3032             :     Word16 energy_e[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS], /*i:stores exponent values for energy_e*/
    3033             :     const SPHERICAL_GRID_DATA *Sph_Grid16,
    3034             :     const UWord8 useSphGrid )
    3035             : {
    3036             :     Word16 i, j, k;
    3037             :     Word16 azi_rad_fx, ele_rad_fx;
    3038             :     UWord8 numDirections;
    3039             : 
    3040             :     /* use the nominal values without data-adaptivity */
    3041           0 :     numDirections = (UWord8) add( hMeta->descriptive_meta.numberOfDirections, 1 );
    3042           0 :     move16();
    3043             : 
    3044             :     /* azi/ele/nrg into vectors for each sub-frame and band */
    3045           0 :     FOR( i = 0; i < numDirections; i++ )
    3046             :     {
    3047           0 :         FOR( k = 0; k < MASA_FREQUENCY_BANDS; k++ )
    3048             :         {
    3049             :             Word32 x_sum_fx, y_sum_fx, z_sum_fx, energy_sum_fx, vec_len_fx, spread_coh_sum_fx, surr_coh_sum_fx, temp1, temp2;
    3050             :             Word16 vec_len_e, x_sum_e, y_sum_e, z_sum_e, energy_sum_e, spread_coh_sum_e, surr_coh_sum_e, temp1_e, temp2_e;
    3051           0 :             x_sum_fx = 0;
    3052           0 :             y_sum_fx = 0;
    3053           0 :             z_sum_fx = 0;
    3054           0 :             energy_sum_fx = 0;
    3055           0 :             spread_coh_sum_fx = 0;
    3056           0 :             surr_coh_sum_fx = 0;
    3057           0 :             x_sum_e = 0;          /*exponent for x_sum_fx*/
    3058           0 :             y_sum_e = 0;          /*exponent for y_sum_fx*/
    3059           0 :             z_sum_e = 0;          /*exponent for z_sum_fx*/
    3060           0 :             energy_sum_e = 0;     /*exponent for energy_sum_fx*/
    3061           0 :             spread_coh_sum_e = 0; /*exponent for spread_coh_sum_fx*/
    3062           0 :             surr_coh_sum_e = 0;   /*exponent for surr_coh_sum_fx*/
    3063           0 :             temp1 = 0;            /* to store temporary computations*/
    3064           0 :             temp2 = 0;            /* to store temporary computations*/
    3065           0 :             temp1_e = 0;          /*to store temporary exponents*/
    3066           0 :             temp2_e = 0;          /*to store temporary exponents*/
    3067           0 :             move32();
    3068           0 :             move32();
    3069           0 :             move32();
    3070           0 :             move32();
    3071           0 :             move32();
    3072           0 :             move32();
    3073           0 :             move32();
    3074           0 :             move32();
    3075           0 :             move16();
    3076           0 :             move16();
    3077           0 :             move16();
    3078           0 :             move16();
    3079           0 :             move16();
    3080           0 :             move16();
    3081           0 :             move16();
    3082           0 :             move16();
    3083             : 
    3084           0 :             FOR( j = 0; j < MAX_PARAM_SPATIAL_SUBFRAMES; j++ )
    3085             :             {
    3086           0 :                 azi_rad_fx = extract_l( Mpy_32_32( hMeta->directional_meta[i].azimuth_fx[j][k], 46603 /*1/(360) in Q24*/ ) ); /*=angle *(1/2pi) brings the azi_rad_fx in -32767 to 32767 in q15 (this argument is further passed in cos and sin functions)*/   /*22+24-31=15*/
    3087           0 :                 ele_rad_fx = extract_l( Mpy_32_32( hMeta->directional_meta[i].elevation_fx[j][k], 46603 /*1/(360) in Q24*/ ) ); /*=angle *(1/2pi) brings the azi_rad_fx in -32767 to 32767 in q15 (this argument is further passed in cos and sin functions)*/ /*22+24-31=15*/
    3088           0 :                 vec_len_fx = Mpy_32_32( hMeta->directional_meta[i].energy_ratio_fx[j][k] /*q30*/, energy[j][k] );                                                                                                                                              /*exponent=energy_e+1*/
    3089           0 :                 vec_len_e = add( energy_e[j][k], 1 );
    3090             : 
    3091             :                 /* energy-weighted sum over subframes */
    3092           0 :                 x_sum_fx = BASOP_Util_Add_Mant32Exp( x_sum_fx, x_sum_e, Mpy_32_32( L_mult( getCosWord16R2( azi_rad_fx ), getCosWord16R2( ele_rad_fx ) ) /*q31*/, vec_len_fx ), vec_len_e, &x_sum_e );  /*x_sum_e*/
    3093           0 :                 y_sum_fx = BASOP_Util_Add_Mant32Exp( y_sum_fx, y_sum_e, Mpy_32_32( L_mult( getSineWord16R2( azi_rad_fx ), getCosWord16R2( ele_rad_fx ) ) /*q31*/, vec_len_fx ), vec_len_e, &y_sum_e ); /*y_sum_e*/
    3094           0 :                 z_sum_fx = BASOP_Util_Add_Mant32Exp( z_sum_fx, z_sum_e, Mpy_32_16_1( vec_len_fx, getSineWord16R2( ele_rad_fx ) /*q15*/ ), vec_len_e, &z_sum_e );                                       /*z_sum_e*/
    3095             : 
    3096           0 :                 energy_sum_fx = BASOP_Util_Add_Mant32Exp( energy_sum_fx, energy_sum_e, energy[j][k], energy_e[j][k], &energy_sum_e ); /*energy_sum_e*/
    3097             : 
    3098           0 :                 spread_coh_sum_fx = BASOP_Util_Add_Mant32Exp( spread_coh_sum_fx, spread_coh_sum_e, Mpy_32_16_1( energy[j][k], hMeta->directional_meta[i].spread_coherence_fx[j][k] ), energy_e[j][k], &spread_coh_sum_e ); /*spread_coh_sum_e*/
    3099           0 :                 IF( i == 0 )
    3100             :                 {
    3101             :                     /* this is in common metadata and not in each direction */
    3102           0 :                     surr_coh_sum_fx = BASOP_Util_Add_Mant32Exp( surr_coh_sum_fx, surr_coh_sum_e, Mpy_32_16_1( energy[j][k], hMeta->common_meta.surround_coherence_fx[j][k] ), energy_e[j][k], &surr_coh_sum_e ); /*surr_coh_sum_e*/
    3103             :                 }
    3104             :             }
    3105             : 
    3106             :             /* the data from the combined sub-frames is written into the first sub-frame band */
    3107           0 :             j = 0;
    3108           0 :             move16();
    3109           0 :             hMeta->directional_meta[i].azimuth_fx[j][k] = Mpy_32_16_1( 961263669 /*(1/ EVS_PI * 180.0f) in Q24*/, BASOP_util_atan2( y_sum_fx, x_sum_fx, sub( y_sum_e, x_sum_e ) ) /*q13*/ ); /*24+13-15=22*/
    3110           0 :             move32();
    3111           0 :             temp1 = BASOP_Util_Add_Mant32Exp( Mpy_32_32( x_sum_fx, x_sum_fx ), shl( x_sum_e, 1 ), Mpy_32_32( y_sum_fx, y_sum_fx ), shl( y_sum_e, 1 ), &temp1_e ); /*temp1_e*/
    3112           0 :             temp2_e = temp1_e;
    3113           0 :             temp2 = Sqrt32( temp1, &temp2_e );                                                                                                                                              /*temp2_e*/
    3114           0 :             hMeta->directional_meta[i].elevation_fx[j][k] = Mpy_32_16_1( 961263669 /*(1/ EVS_PI * 180.0f) in Q24*/, BASOP_util_atan2( z_sum_fx, temp2, sub( z_sum_e, temp2_e ) ) /*q13*/ ); /*24+13-15=22*/
    3115           0 :             move32();
    3116           0 :             IF( EQ_16( useSphGrid, TRUE ) )
    3117             :             {
    3118             : 
    3119           0 :                 hMeta->directional_meta[i].spherical_index[j][k] = index_theta_phi_16_fx( &( hMeta->directional_meta[i].elevation_fx[j][k] ),
    3120           0 :                                                                                           &( hMeta->directional_meta[i].azimuth_fx[j][k] ), Sph_Grid16 );
    3121           0 :                 move16();
    3122             :             }
    3123           0 :             vec_len_fx = BASOP_Util_Add_Mant32Exp( temp1, temp1_e, Mpy_32_32( z_sum_fx, z_sum_fx ), shl( z_sum_e, 1 ), &vec_len_e ); /*vec_len_e*/      /*x_sum * x_sum + y_sum * y_sum + z_sum * z_sum*/
    3124           0 :             vec_len_fx = Sqrt32( vec_len_fx, &vec_len_e );                                                                                              /*vec_len_e*/
    3125           0 :             hMeta->directional_meta[i].energy_ratio_fx[j][k] = BASOP_Util_Divide3232_Scale( vec_len_fx, L_add( energy_sum_fx, EPSILON_FX ), &temp2_e ); /*temp2_e*/
    3126           0 :             move32();
    3127           0 :             temp2_e = add( temp2_e, sub( vec_len_e, energy_sum_e ) );
    3128           0 :             hMeta->directional_meta[i].energy_ratio_fx[j][k] = L_shl( hMeta->directional_meta[i].energy_ratio_fx[j][k], add( temp2_e, 15 ) ); /*changing q from 15-temp2_e to q30*/
    3129           0 :             move32();
    3130           0 :             hMeta->directional_meta[i].spread_coherence_fx[j][k] = BASOP_Util_Divide3232_Scale( spread_coh_sum_fx, L_add( energy_sum_fx, EPSILON_FX ), &temp2_e );
    3131           0 :             move16();
    3132           0 :             temp2_e = add( temp2_e, sub( spread_coh_sum_e, energy_sum_e ) );
    3133           0 :             hMeta->directional_meta[i].spread_coherence_fx[j][k] = shl( hMeta->directional_meta[i].spread_coherence_fx[j][k], temp2_e ); /*changing q from 15-temp2_e to q15*/
    3134           0 :             move16();
    3135           0 :             IF( i == 0 )
    3136             :             {
    3137           0 :                 hMeta->common_meta.surround_coherence_fx[j][k] = BASOP_Util_Divide3232_Scale( surr_coh_sum_fx, L_add( energy_sum_fx, EPSILON_FX ), &temp2_e );
    3138           0 :                 move16();
    3139           0 :                 temp2_e = add( temp2_e, sub( surr_coh_sum_e, energy_sum_e ) );
    3140           0 :                 hMeta->common_meta.surround_coherence_fx[j][k] = shl_sat( hMeta->common_meta.surround_coherence_fx[j][k], temp2_e ); /*changing q from 15-temp2_e to q15*/
    3141           0 :                 move16();
    3142             :             }
    3143             : 
    3144             :             /* copy the same value to all subframes */
    3145           0 :             FOR( j = 1; j < MAX_PARAM_SPATIAL_SUBFRAMES; j++ )
    3146             :             {
    3147           0 :                 hMeta->directional_meta[i].azimuth_fx[j][k] = hMeta->directional_meta[i].azimuth_fx[0][k];                   /*q22*/
    3148           0 :                 hMeta->directional_meta[i].elevation_fx[j][k] = hMeta->directional_meta[i].elevation_fx[0][k];               /*q22*/
    3149           0 :                 hMeta->directional_meta[i].energy_ratio_fx[j][k] = hMeta->directional_meta[i].energy_ratio_fx[0][k];         /*q30*/
    3150           0 :                 hMeta->directional_meta[i].spread_coherence_fx[j][k] = hMeta->directional_meta[i].spread_coherence_fx[0][k]; /*q15*/
    3151           0 :                 move32();
    3152           0 :                 move32();
    3153           0 :                 move32();
    3154           0 :                 move16();
    3155           0 :                 IF( i == 0 )
    3156             :                 {
    3157           0 :                     hMeta->common_meta.surround_coherence_fx[j][k] = hMeta->common_meta.surround_coherence_fx[0][k]; /*q15*/
    3158           0 :                     move16();
    3159             :                 }
    3160             :             }
    3161             :         }
    3162             :     }
    3163             : 
    3164           0 :     FOR( k = 0; k < MASA_FREQUENCY_BANDS; k++ )
    3165             :     {
    3166           0 :         FOR( j = 0; j < MAX_PARAM_SPATIAL_SUBFRAMES; j++ )
    3167             :         {
    3168           0 :             IF( EQ_16( numDirections, 2 ) )
    3169             :             {
    3170           0 :                 hMeta->common_meta.diffuse_to_total_ratio_fx[j][k] = L_max( 0, L_sub( L_sub( ONE_IN_Q30, hMeta->directional_meta[1].energy_ratio_fx[j][k] ), hMeta->directional_meta[0].energy_ratio_fx[j][k] ) ); /*q30*/
    3171             :             }
    3172             :             ELSE
    3173             :             {
    3174           0 :                 hMeta->common_meta.diffuse_to_total_ratio_fx[j][k] = L_max( 0, L_sub( ONE_IN_Q30, hMeta->directional_meta[0].energy_ratio_fx[j][k] ) ); /*q30*/
    3175             :             }
    3176           0 :             move32();
    3177           0 :             hMeta->common_meta.remainder_to_total_ratio_fx[j][k] = 0; /*q30*/
    3178           0 :             move32();
    3179             :         }
    3180             :     }
    3181             : 
    3182           0 :     return;
    3183             : }
    3184             : 
    3185             : 
    3186             : /*-------------------------------------------------------------------*
    3187             :  * copy_masa_metadata_subframe()
    3188             :  *
    3189             :  * Copy MASA metadata frame subframe contents
    3190             :  *-------------------------------------------------------------------*/
    3191             : 
    3192      158504 : static void copy_masa_metadata_subframe_fx(
    3193             :     const MASA_METADATA_HANDLE hMetaFrom, /* i  : MASA frame metdata to be copied      */
    3194             :     const UWord8 sfFrom,                  /* i  : subframe index of the copy source    */
    3195             :     MASA_METADATA_HANDLE hMetaTo,         /* o  : MASA frame metadata copy destination */
    3196             :     const UWord8 sfTo                     /* i  : subframe index of the copy target    */
    3197             : )
    3198             : {
    3199             :     UWord8 dir;
    3200             :     UWord8 band;
    3201             : 
    3202             :     /* directional metadata */
    3203      475512 :     FOR( dir = 0; dir < MASA_MAXIMUM_DIRECTIONS; dir++ )
    3204             :     {
    3205     7925200 :         FOR( band = 0; band < MASA_FREQUENCY_BANDS; band++ )
    3206             :         {
    3207     7608192 :             hMetaTo->directional_meta[dir].spherical_index[sfTo][band] = hMetaFrom->directional_meta[dir].spherical_index[sfFrom][band];
    3208     7608192 :             move16();
    3209             :         }
    3210      317008 :         Copy32( hMetaFrom->directional_meta[dir].azimuth_fx[sfFrom], hMetaTo->directional_meta[dir].azimuth_fx[sfTo], MASA_FREQUENCY_BANDS );                 // Q22
    3211      317008 :         Copy32( hMetaFrom->directional_meta[dir].elevation_fx[sfFrom], hMetaTo->directional_meta[dir].elevation_fx[sfTo], MASA_FREQUENCY_BANDS );             // Q22
    3212      317008 :         Copy32( hMetaFrom->directional_meta[dir].energy_ratio_fx[sfFrom], hMetaTo->directional_meta[dir].energy_ratio_fx[sfTo], MASA_FREQUENCY_BANDS );       // Q30
    3213      317008 :         Copy( hMetaFrom->directional_meta[dir].spread_coherence_fx[sfFrom], hMetaTo->directional_meta[dir].spread_coherence_fx[sfTo], MASA_FREQUENCY_BANDS ); // Q15
    3214             :     }
    3215             : 
    3216             :     /* common metadata */
    3217      158504 :     Copy32( hMetaFrom->common_meta.diffuse_to_total_ratio_fx[sfFrom], hMetaTo->common_meta.diffuse_to_total_ratio_fx[sfTo], MASA_FREQUENCY_BANDS );     // Q30
    3218      158504 :     Copy( hMetaFrom->common_meta.surround_coherence_fx[sfFrom], hMetaTo->common_meta.surround_coherence_fx[sfTo], MASA_FREQUENCY_BANDS );               // Q15
    3219      158504 :     Copy32( hMetaFrom->common_meta.remainder_to_total_ratio_fx[sfFrom], hMetaTo->common_meta.remainder_to_total_ratio_fx[sfTo], MASA_FREQUENCY_BANDS ); // Q30
    3220             : 
    3221      158504 :     return;
    3222             : }
    3223             : 
    3224             : 
    3225             : /*-------------------------------------------------------------------*
    3226             :  * copy_masa_metadata()
    3227             :  *
    3228             :  * Copy MASA metada frame contents
    3229             :  *-------------------------------------------------------------------*/
    3230             : 
    3231       39626 : static void copy_masa_metadata_fx(
    3232             :     const MASA_METADATA_HANDLE hMetaFrom, /* i  : MASA frame metadata to be copied     */
    3233             :     MASA_METADATA_HANDLE hMetaTo          /* o  : MASA frame metadata copy destination */
    3234             : )
    3235             : {
    3236             :     UWord8 sf, byte_idx;
    3237             : 
    3238             :     /* descriptive metadata */
    3239      356634 :     FOR( byte_idx = 0; byte_idx < 8; byte_idx++ )
    3240             :     {
    3241      317008 :         hMetaTo->descriptive_meta.formatDescriptor[byte_idx] = hMetaFrom->descriptive_meta.formatDescriptor[byte_idx];
    3242      317008 :         move16();
    3243             :     }
    3244             : 
    3245       39626 :     hMetaTo->descriptive_meta.numberOfDirections = hMetaFrom->descriptive_meta.numberOfDirections;
    3246       39626 :     hMetaTo->descriptive_meta.numberOfChannels = hMetaFrom->descriptive_meta.numberOfChannels;
    3247       39626 :     hMetaTo->descriptive_meta.sourceFormat = hMetaFrom->descriptive_meta.sourceFormat;
    3248       39626 :     hMetaTo->descriptive_meta.transportDefinition = hMetaFrom->descriptive_meta.transportDefinition;
    3249       39626 :     hMetaTo->descriptive_meta.channelAngle = hMetaFrom->descriptive_meta.channelAngle;
    3250       39626 :     hMetaTo->descriptive_meta.channelDistance = hMetaFrom->descriptive_meta.channelDistance;
    3251       39626 :     hMetaTo->descriptive_meta.channelLayout = hMetaFrom->descriptive_meta.channelLayout;
    3252       39626 :     move16();
    3253       39626 :     move16();
    3254       39626 :     move16();
    3255       39626 :     move16();
    3256       39626 :     move16();
    3257       39626 :     move16();
    3258       39626 :     move16();
    3259             : 
    3260             :     /* directional and common metadata */
    3261      198130 :     FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    3262             :     {
    3263      158504 :         copy_masa_metadata_subframe_fx( hMetaFrom, sf, hMetaTo, sf );
    3264             :     }
    3265             : 
    3266       39626 :     return;
    3267             : }
    3268             : 
    3269             : 
    3270             : /*-------------------------------------------------------------------*
    3271             :  * are_masa_subframes_similar()
    3272             :  *
    3273             :  * Compare the similarity of MASA metadata in two sub-frames
    3274             :  *-------------------------------------------------------------------*/
    3275             : 
    3276             : /* r: similarity decision */
    3277      175035 : static UWord8 are_masa_subframes_similar_fx(
    3278             :     const MASA_METADATA_HANDLE frame1, /* i  : MASA metadata frame 1                      */
    3279             :     const UWord8 sf1_idx,              /* i  : index of the subframe of frame1 to inspect */
    3280             :     const MASA_METADATA_HANDLE frame2, /* i  : MASA metadata frame 2                      */
    3281             :     const UWord8 sf2_idx               /* i  : index of the subframe of frame2 to inspect */
    3282             : )
    3283             : {
    3284             :     UWord8 num_dir;
    3285             :     UWord8 dir;
    3286             :     UWord8 band_idx;
    3287             :     UWord8 sf_differ;
    3288             : 
    3289      175035 :     num_dir = frame1->descriptive_meta.numberOfDirections;
    3290      175035 :     dir = 0;
    3291      175035 :     band_idx = 0;
    3292      175035 :     sf_differ = FALSE;
    3293      175035 :     move16();
    3294      175035 :     move16();
    3295      175035 :     move16();
    3296      175035 :     move16();
    3297             : 
    3298      175035 :     IF( NE_16( num_dir, frame2->descriptive_meta.numberOfDirections ) )
    3299             :     {
    3300           0 :         sf_differ = TRUE;
    3301           0 :         move16();
    3302             :     }
    3303             :     ELSE
    3304             :     {
    3305             :         /* check per-direction metadata */
    3306      175035 :         dir = 0;
    3307      175035 :         band_idx = 0;
    3308      175035 :         move16();
    3309      175035 :         move16();
    3310             : 
    3311      360870 :         WHILE( ( sf_differ == FALSE ) && ( dir <= num_dir ) )
    3312             :         {
    3313      185835 :             test();
    3314      185835 :             band_idx = 0;
    3315      185835 :             move16();
    3316     1244235 :             WHILE( ( sf_differ == FALSE ) && ( band_idx < MASA_FREQUENCY_BANDS ) )
    3317             :             {
    3318     1200135 :                 test();
    3319             :                 Word32 azi_dif_fx;
    3320     1200135 :                 azi_dif_fx = L_abs( L_sub( frame1->directional_meta[dir].azimuth_fx[sf1_idx][band_idx], frame2->directional_meta[dir].azimuth_fx[sf2_idx][band_idx] ) ); // Q22
    3321     1200135 :                 IF( GT_32( azi_dif_fx, 180 << Q22 ) )
    3322       16892 :                 azi_dif_fx = L_sub( 360 << Q22, azi_dif_fx ); // Q22
    3323             : 
    3324     1200135 :                 IF( GT_32( azi_dif_fx, ONE_IN_Q21 /*0.5 in Q22*/ ) )
    3325             :                 {
    3326      139100 :                     sf_differ = TRUE;
    3327      139100 :                     move16();
    3328      139100 :                     BREAK;
    3329             :                 }
    3330             : 
    3331     1061035 :                 IF( GT_32( L_abs( L_sub( frame1->directional_meta[dir].elevation_fx[sf1_idx][band_idx], frame2->directional_meta[dir].elevation_fx[sf2_idx][band_idx] ) ), MASA_ANGLE_TOLERANCE_FX ) )
    3332             :                 {
    3333        2616 :                     sf_differ = TRUE;
    3334        2616 :                     move16();
    3335        2616 :                     BREAK;
    3336             :                 }
    3337             : 
    3338     1058419 :                 IF( GT_32( L_abs( L_sub( frame1->directional_meta[dir].energy_ratio_fx[sf1_idx][band_idx], frame2->directional_meta[dir].energy_ratio_fx[sf2_idx][band_idx] ) ), MASA_RATIO_TOLERANCE_FX ) )
    3339             :                 {
    3340          19 :                     sf_differ = TRUE;
    3341          19 :                     move16();
    3342          19 :                     BREAK;
    3343             :                 }
    3344             : 
    3345     1058400 :                 IF( GT_32( L_abs( L_sub( frame1->directional_meta[dir].spread_coherence_fx[sf1_idx][band_idx], frame2->directional_meta[dir].spread_coherence_fx[sf2_idx][band_idx] ) ), MASA_COHERENCE_TOLERANCE_FX ) )
    3346             :                 {
    3347           0 :                     sf_differ = TRUE;
    3348           0 :                     move16();
    3349           0 :                     BREAK;
    3350             :                 }
    3351             : 
    3352     1058400 :                 band_idx = (UWord8) add( band_idx, 1 );
    3353     1058400 :                 move16();
    3354             :             }
    3355      185835 :             dir = (UWord8) add( dir, 1 );
    3356      185835 :             move16();
    3357             :         }
    3358             : 
    3359             :         /* check the common metadata */
    3360      175035 :         WHILE( ( sf_differ == FALSE ) && ( band_idx < MASA_FREQUENCY_BANDS ) )
    3361             :         {
    3362           0 :             test();
    3363           0 :             IF( GT_32( L_abs( L_sub( frame1->common_meta.surround_coherence_fx[sf1_idx][band_idx], frame2->common_meta.surround_coherence_fx[sf2_idx][band_idx] ) ), MASA_COHERENCE_TOLERANCE_FX ) )
    3364             :             {
    3365           0 :                 sf_differ = TRUE;
    3366           0 :                 move16();
    3367           0 :                 BREAK;
    3368             :             }
    3369             : 
    3370           0 :             band_idx = (UWord8) add( band_idx, 1 );
    3371           0 :             move16();
    3372             :         }
    3373             :     }
    3374             : 
    3375      175035 :     IF( sf_differ )
    3376             :     {
    3377      141735 :         return FALSE;
    3378             :     }
    3379             :     ELSE
    3380             :     {
    3381       33300 :         return TRUE;
    3382             :     }
    3383             : }
    3384             : 
    3385             : 
    3386             : /*-------------------------------------------------------------------*
    3387             :  * detect_framing_async()
    3388             :  *
    3389             :  * Compare the similarity of MASA metadata in two sub-frames
    3390             :  * Analysis result is stored in hMasa->data.sync_state, and
    3391             :  * potentially hMasa->masaMetadata is modified
    3392             :  *-------------------------------------------------------------------*/
    3393             : 
    3394       39626 : static void detect_framing_async_fx(
    3395             :     MASA_ENCODER_HANDLE hMasa /* i/o: MASA encoder structure */
    3396             : )
    3397             : {
    3398             :     MASA_METADATA_HANDLE current_meta;
    3399             :     MASA_METADATA_HANDLE previous_meta;
    3400             :     MASA_SYNC_HANDLE sync_state;
    3401             :     MASA_FRAME_MODE frame_mode;
    3402             :     UWord8 n_sim_start, n_sim_stop, sf_idx;
    3403             :     UWord8 found_offset;
    3404             : 
    3405       39626 :     current_meta = &( hMasa->masaMetadata );  /* metadata from current frame */
    3406       39626 :     sync_state = &( hMasa->data.sync_state ); /* synchronization structure */
    3407       39626 :     previous_meta = &( sync_state->previous_metadata );
    3408             : 
    3409             :     /* check current frame, how many are similar from the start and from the end */
    3410       39626 :     n_sim_start = 1;
    3411       39626 :     move16();
    3412       56276 :     FOR( sf_idx = n_sim_start; sf_idx < MAX_PARAM_SPATIAL_SUBFRAMES; sf_idx++ )
    3413             :     {
    3414       50726 :         IF( EQ_16( are_masa_subframes_similar_fx( current_meta, 0, current_meta, sf_idx ), TRUE ) )
    3415             :         {
    3416       16650 :             n_sim_start = (UWord8) add( sf_idx, 1 );
    3417       16650 :             move16();
    3418             :         }
    3419             :         ELSE
    3420             :         {
    3421       34076 :             BREAK;
    3422             :         }
    3423             :     }
    3424             : 
    3425             :     /* number of similar sub-frames starting from the end of the frame */
    3426       39626 :     IF( EQ_16( n_sim_start, MAX_PARAM_SPATIAL_SUBFRAMES ) ) /* shortcut */
    3427             :     {
    3428        5550 :         n_sim_stop = n_sim_start;
    3429        5550 :         move16();
    3430             :     }
    3431             :     ELSE
    3432             :     {
    3433       34076 :         n_sim_stop = 1;
    3434       34076 :         move16();
    3435       34076 :         FOR( sf_idx = 2; sf_idx < MAX_PARAM_SPATIAL_SUBFRAMES; sf_idx++ )
    3436             :         {
    3437             :             /* we need to check only the two middle sub-frames, as all being the same would have taken the shortcut above */
    3438       34076 :             IF( EQ_16( are_masa_subframes_similar_fx( current_meta, MAX_PARAM_SPATIAL_SUBFRAMES - 1, current_meta, (UWord8) sub( MAX_PARAM_SPATIAL_SUBFRAMES, sf_idx ) ), TRUE ) )
    3439             :             {
    3440           0 :                 n_sim_stop = sf_idx;
    3441           0 :                 move16();
    3442             :             }
    3443             :             ELSE
    3444             :             {
    3445       34076 :                 BREAK;
    3446             :             }
    3447             :         }
    3448             :     }
    3449             : 
    3450       39626 :     frame_mode = MASA_FRAME_4SF; /* default mode: 4sf */
    3451       39626 :     move16();
    3452       39626 :     IF( GT_16( sync_state->prev_offset, MAX_PARAM_SPATIAL_SUBFRAMES - 2 ) )
    3453             :     {
    3454             :         /* earlier offset was large => reset the offset */
    3455           0 :         found_offset = 0;
    3456             :     }
    3457             :     ELSE
    3458             :     {
    3459             :         /* keep previous offset unless something else is found. alternatively, we could reset always */
    3460       39626 :         found_offset = sync_state->prev_offset;
    3461             :     }
    3462       39626 :     move16();
    3463             : 
    3464       39626 :     test();
    3465       39626 :     test();
    3466       39626 :     IF( EQ_16( n_sim_start, MAX_PARAM_SPATIAL_SUBFRAMES ) && EQ_16( n_sim_stop, MAX_PARAM_SPATIAL_SUBFRAMES ) )
    3467             :     {
    3468             :         /* full frame consists of similar sub-frames */
    3469        5550 :         frame_mode = MASA_FRAME_1SF;
    3470        5550 :         move16();
    3471        5550 :         test();
    3472        5550 :         IF( ( sync_state->prev_sim_stop != 0 ) && EQ_16( are_masa_subframes_similar_fx( current_meta, 0, previous_meta, MAX_PARAM_SPATIAL_SUBFRAMES - 1 ), TRUE ) )
    3473             :         {
    3474             :             /* > 4 sub-frames of similar data */
    3475           0 :             IF( LT_16( sync_state->prev_sim_stop, 3 ) )
    3476             :             {
    3477             :                 /* can nicely align the framing with the earlier data and a small offset */
    3478           0 :                 found_offset = sync_state->prev_sim_stop;
    3479             :             }
    3480             :             ELSE
    3481             :             {
    3482             :                 /* too many similar sub-frames to determine the offset accurately => keep earlier value */
    3483           0 :                 found_offset = sync_state->prev_offset;
    3484             :             }
    3485           0 :             move16();
    3486             :         }
    3487             :         ELSE
    3488             :         {
    3489             :             /* earlier window was different => reset the offset */
    3490        5550 :             found_offset = 0;
    3491        5550 :             move16();
    3492             :         }
    3493             :     }
    3494       34076 :     ELSE IF( EQ_16( n_sim_stop, 3 ) )
    3495             :     {
    3496             :         /* first sub-frame different that the rest 3
    3497             :                        => make a risky guess that the future sf would be the same too and we're in an offset case */
    3498           0 :         frame_mode = MASA_FRAME_1SF;
    3499           0 :         found_offset = 3;
    3500           0 :         move16();
    3501           0 :         move16();
    3502             :     }
    3503       34076 :     ELSE IF( ( sync_state->prev_sim_stop > 0 ) && EQ_16( are_masa_subframes_similar_fx( current_meta, 0, previous_meta, MAX_PARAM_SPATIAL_SUBFRAMES - 1 ), TRUE ) )
    3504             :     {
    3505             :         /* seeing data similar to past */
    3506           0 :         test();
    3507           0 :         IF( GT_16( n_sim_start, 1 ) && ( GE_16( add( n_sim_start, sync_state->prev_sim_stop ), MAX_PARAM_SPATIAL_SUBFRAMES ) ) )
    3508             :         {
    3509             :             /* with the past, would have at least one long frame similar subframes */
    3510           0 :             frame_mode = MASA_FRAME_1SF;
    3511           0 :             move16();
    3512             : 
    3513           0 :             IF( sync_state->prev_offset == 0 )
    3514             :             {
    3515           0 :                 found_offset = (UWord8) s_min( 2, sync_state->prev_sim_stop );
    3516             :             }
    3517             :             ELSE
    3518             :             {
    3519           0 :                 found_offset = sync_state->prev_offset;
    3520           0 :                 move16();
    3521             :             }
    3522             :         }
    3523             :     }
    3524             : 
    3525             :     /* keep the original contents of the frame, but then perform interpolation later */
    3526             :     /* just copy current frame to storage */
    3527       39626 :     copy_masa_metadata_fx( current_meta, previous_meta );
    3528             : 
    3529       39626 :     sync_state->prev_sim_stop = n_sim_stop;
    3530       39626 :     sync_state->prev_offset = found_offset;
    3531       39626 :     sync_state->frame_mode = frame_mode;
    3532       39626 :     move16();
    3533       39626 :     move16();
    3534       39626 :     move16();
    3535             : 
    3536       39626 :     return;
    3537             : }
    3538             : 
    3539             : 
    3540             : /*-------------------------------------------------------------------*
    3541             :  * masa_metadata_direction_alignment()
    3542             :  *
    3543             :  * In 2dir MASA metadata, determine the ordering of the directional
    3544             :  * fields such that the azi/ele change across time is minimized.
    3545             :  *-------------------------------------------------------------------*/
    3546             : 
    3547       39626 : static void masa_metadata_direction_alignment_fx(
    3548             :     MASA_ENCODER_HANDLE hMasa /* i/o: MASA encoder handle */
    3549             : )
    3550             : {
    3551             :     UWord8 band, n_dirs;
    3552             :     MASA_DIR_ALIGN_HANDLE hAlignState;
    3553             :     MASA_METADATA_HANDLE hMeta;
    3554       39626 :     hAlignState = &( hMasa->data.dir_align_state );
    3555       39626 :     hMeta = &( hMasa->masaMetadata );
    3556             : 
    3557       39626 :     n_dirs = (UWord8) add( hMeta->descriptive_meta.numberOfDirections, 1 ); /* 1-based */
    3558       39626 :     move16();
    3559      990650 :     FOR( band = 0; band < MASA_FREQUENCY_BANDS; band++ )
    3560             :     {
    3561             :         UWord8 sf;
    3562             :         Word32 diff_swap_fx;
    3563             :         Word32 diff_no_swap_fx;
    3564             : 
    3565             :         /* trade 2*(cos+sin) against storing the values between frames */
    3566             :         Word16 prev_ele_dir1_sin_fx, prev_ele_dir2_sin_fx;
    3567             :         Word16 prev_ele_dir1_cos_fx, prev_ele_dir2_cos_fx;
    3568             : 
    3569      951024 :         prev_ele_dir1_sin_fx = getSineWord16R2( extract_l( Mpy_32_32( hAlignState->previous_ele_dir1_fx[band], 2670177 /*2^24/(2*pi)*/ ) ) ); /*q15*/
    3570      951024 :         prev_ele_dir2_sin_fx = getSineWord16R2( extract_l( Mpy_32_32( hAlignState->previous_ele_dir2_fx[band], 2670177 /*2^24/(2*pi)*/ ) ) ); /*q15*/
    3571             : 
    3572      951024 :         prev_ele_dir1_cos_fx = getCosWord16R2( extract_l( Mpy_32_32( hAlignState->previous_ele_dir1_fx[band], 2670177 /*2^24/(2*pi)*/ ) ) ); /*q15*/
    3573      951024 :         prev_ele_dir2_cos_fx = getCosWord16R2( extract_l( Mpy_32_32( hAlignState->previous_ele_dir2_fx[band], 2670177 /*2^24/(2*pi)*/ ) ) ); /*q15*/
    3574             : 
    3575     4755120 :         FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    3576             :         {
    3577             :             Word32 azi_rad1_fx, ele_rad1_fx;
    3578             :             Word32 azi_rad2_fx, ele_rad2_fx;
    3579             :             Word16 cos_ele1_fx, cos_ele2_fx;
    3580             :             Word16 sin_ele1_fx, sin_ele2_fx;
    3581             :             Word16 temp1;
    3582             :             Word32 temp2;
    3583             :             Word16 temp1_e;
    3584             : 
    3585             : 
    3586     3804096 :             azi_rad1_fx = Mpy_32_16_1( hMeta->directional_meta[0].azimuth_fx[sf][band], 572 /*PI_OVER_180 q15*/ );   /*q22*/
    3587     3804096 :             ele_rad1_fx = Mpy_32_16_1( hMeta->directional_meta[0].elevation_fx[sf][band], 572 /*PI_OVER_180 q15*/ ); /*q22*/
    3588             : 
    3589     3804096 :             IF( GT_16( n_dirs, 1 ) )
    3590             :             {
    3591      950400 :                 azi_rad2_fx = Mpy_32_16_1( hMeta->directional_meta[1].azimuth_fx[sf][band], 572 /*PI_OVER_180 q15*/ );   /*q22*/
    3592      950400 :                 ele_rad2_fx = Mpy_32_16_1( hMeta->directional_meta[1].elevation_fx[sf][band], 572 /*PI_OVER_180 q15*/ ); /*q22*/
    3593             : 
    3594      950400 :                 test();
    3595      950400 :                 test();
    3596      950400 :                 test();
    3597      950400 :                 test();
    3598      950400 :                 test();
    3599      950400 :                 test();
    3600             :                 /* quick checks to detect constant data and earlier flip */
    3601      950400 :                 IF( LT_32( L_abs( L_sub( azi_rad1_fx, hAlignState->previous_azi_dir1_fx[band] ) ), EPSILON_FX ) &&
    3602             :                     LT_32( L_abs( L_sub( azi_rad2_fx, hAlignState->previous_azi_dir2_fx[band] ) ), EPSILON_FX ) &&
    3603             :                     LT_32( L_abs( L_sub( ele_rad1_fx, hAlignState->previous_ele_dir1_fx[band] ) ), EPSILON_FX ) &&
    3604             :                     LT_32( L_abs( L_sub( ele_rad2_fx, hAlignState->previous_ele_dir2_fx[band] ) ), EPSILON_FX ) )
    3605             :                 {
    3606       91800 :                     diff_swap_fx = ONE_IN_Q13; /*1 q13*/
    3607       91800 :                     move32();
    3608       91800 :                     diff_no_swap_fx = 0;
    3609       91800 :                     move32();
    3610             :                     /* cached values that will be used for the short-cuts and over-written by the real computations, if done */
    3611       91800 :                     sin_ele1_fx = prev_ele_dir1_sin_fx; /*q15*/
    3612       91800 :                     sin_ele2_fx = prev_ele_dir2_sin_fx; /*q15*/
    3613       91800 :                     cos_ele1_fx = prev_ele_dir1_cos_fx; /*q15*/
    3614       91800 :                     cos_ele2_fx = prev_ele_dir2_cos_fx; /*q15*/
    3615       91800 :                     move16();
    3616       91800 :                     move16();
    3617       91800 :                     move16();
    3618       91800 :                     move16();
    3619             :                 }
    3620      858600 :                 ELSE IF( LT_32( L_abs( L_sub( azi_rad1_fx, hAlignState->previous_azi_dir2_fx[band] ) ), EPSILON_FX ) &&
    3621             :                          LT_32( L_abs( L_sub( azi_rad2_fx, hAlignState->previous_azi_dir1_fx[band] ) ), EPSILON_FX ) &&
    3622             :                          LT_32( L_abs( L_sub( ele_rad1_fx, hAlignState->previous_ele_dir2_fx[band] ) ), EPSILON_FX ) &&
    3623             :                          LT_32( L_abs( L_sub( ele_rad2_fx, hAlignState->previous_ele_dir1_fx[band] ) ), EPSILON_FX ) )
    3624             :                 {
    3625       37800 :                     diff_swap_fx = 0;
    3626       37800 :                     move32();
    3627       37800 :                     diff_no_swap_fx = ONE_IN_Q13; /*1.0 q13*/
    3628       37800 :                     move32();
    3629             :                     /* cached values that will be used for the short-cuts and over-written by the real computations, if done */
    3630       37800 :                     sin_ele1_fx = prev_ele_dir2_sin_fx; /*q15*/
    3631       37800 :                     sin_ele2_fx = prev_ele_dir1_sin_fx; /*q15*/
    3632       37800 :                     cos_ele1_fx = prev_ele_dir2_cos_fx; /*q15*/
    3633       37800 :                     cos_ele2_fx = prev_ele_dir1_cos_fx; /*q15*/
    3634       37800 :                     move16();
    3635       37800 :                     move16();
    3636       37800 :                     move16();
    3637       37800 :                     move16();
    3638             :                 }
    3639             :                 ELSE
    3640             :                 {
    3641             :                     /* angular distance of the two vectors */
    3642             :                     /* pre-compute values for re-use */
    3643      820800 :                     sin_ele1_fx = getSineWord16R2( extract_l( Mpy_32_32( ele_rad1_fx, 2670177 /*2^24/(2*pi)*/ ) ) ); /*q15*/
    3644      820800 :                     sin_ele2_fx = getSineWord16R2( extract_l( Mpy_32_32( ele_rad2_fx, 2670177 /*2^24/(2*pi)*/ ) ) ); /*q15*/
    3645             : 
    3646      820800 :                     cos_ele1_fx = getCosWord16R2( extract_l( Mpy_32_32( ele_rad1_fx, 2670177 /*2^24/(2*pi)*/ ) ) ); /*q15*/
    3647      820800 :                     cos_ele2_fx = getCosWord16R2( extract_l( Mpy_32_32( ele_rad2_fx, 2670177 /*2^24/(2*pi)*/ ) ) ); /*q15*/
    3648             : 
    3649      820800 :                     temp1 = getCosWord16R2( extract_l( Mpy_32_32( L_sub( azi_rad1_fx, hAlignState->previous_azi_dir1_fx[band] ), 2670177 /*2^24/(2*pi)*/ ) ) ); /*q15*/
    3650      820800 :                     temp1 = mult( mult( temp1, cos_ele1_fx ) /*q31*/, prev_ele_dir1_cos_fx /*q15*/ );                                                           /*q15*/
    3651      820800 :                     temp1 = add_sat( mult( sin_ele1_fx, prev_ele_dir1_sin_fx ), temp1 );                                                                        /*q15*/
    3652      820800 :                     temp1_e = 1;                                                                                                                                /*stores expoenent for square root operation*/
    3653      820800 :                     move16();
    3654      820800 :                     temp2 = Sqrt32( L_sub( ONE_IN_Q30, L_mult0( temp1, temp1 ) ), &temp1_e ); /*31-temp1_e*/
    3655      820800 :                     temp1 = BASOP_util_atan2( temp2, temp1, sub( temp1_e, 16 ) );             /*q13*/
    3656      820800 :                     diff_no_swap_fx = L_deposit_l( temp1 );                                   /*q13*/
    3657             : 
    3658      820800 :                     temp1 = getCosWord16R2( extract_l( Mpy_32_32( L_sub( azi_rad2_fx, hAlignState->previous_azi_dir2_fx[band] ), 2670177 /*2^24/(2*pi)*/ ) ) ); /*q15*/
    3659      820800 :                     temp1 = mult( mult( temp1, cos_ele2_fx ) /*q31*/, prev_ele_dir2_cos_fx /*q15*/ );                                                           /*q15*/
    3660      820800 :                     temp1 = add_sat( mult( sin_ele2_fx, prev_ele_dir2_sin_fx ), temp1 );                                                                        /*q15*/
    3661      820800 :                     temp1_e = 1;                                                                                                                                /*stores expoenent for square root operation*/
    3662      820800 :                     move16();
    3663      820800 :                     temp2 = Sqrt32( L_sub( ONE_IN_Q30, L_mult0( temp1, temp1 ) ), &temp1_e ); /*31-temp1_e*/
    3664      820800 :                     temp1 = BASOP_util_atan2( temp2, temp1, sub( temp1_e, 16 ) );             /*q13*/
    3665      820800 :                     diff_no_swap_fx = L_add( diff_no_swap_fx, temp1 );                        /*q13*/
    3666             : 
    3667      820800 :                     temp1 = getCosWord16R2( extract_l( Mpy_32_32( L_sub( azi_rad1_fx, hAlignState->previous_azi_dir2_fx[band] ), 2670177 /*2^24/(2*pi)*/ ) ) ); /*q15*/
    3668      820800 :                     temp1 = mult( mult( temp1, cos_ele1_fx ) /*q31*/, prev_ele_dir2_cos_fx /*q15*/ );                                                           /*q15*/
    3669      820800 :                     temp1 = add_sat( mult( sin_ele1_fx, prev_ele_dir2_sin_fx ), temp1 );                                                                        /*q15*/
    3670      820800 :                     temp1_e = 1;                                                                                                                                /*stores expoenent for square root operation*/
    3671      820800 :                     move16();
    3672      820800 :                     temp2 = Sqrt32( L_sub( ONE_IN_Q30, L_mult0( temp1, temp1 ) ), &temp1_e ); /*31-temp1_e*/
    3673      820800 :                     temp1 = BASOP_util_atan2( temp2, temp1, sub( temp1_e, 16 ) );             /*q13*/
    3674      820800 :                     diff_swap_fx = L_deposit_l( temp1 );                                      /*q13*/
    3675             : 
    3676      820800 :                     temp1 = getCosWord16R2( extract_l( Mpy_32_32( L_sub( azi_rad2_fx, hAlignState->previous_azi_dir1_fx[band] ), 2670177 /*2^24/(2*pi)*/ ) ) ); /*q15*/
    3677      820800 :                     temp1 = mult( mult( temp1, cos_ele2_fx ) /*q31*/, prev_ele_dir1_cos_fx /*q15*/ );                                                           /*q15*/
    3678      820800 :                     temp1 = add_sat( mult( sin_ele2_fx, prev_ele_dir1_sin_fx ), temp1 );                                                                        /*q15*/
    3679      820800 :                     temp1_e = 1;                                                                                                                                /*stores expoenent for square root operation*/
    3680      820800 :                     move16();
    3681      820800 :                     temp2 = Sqrt32( L_sub( ONE_IN_Q30, L_mult0( temp1, temp1 ) ), &temp1_e ); /*31-temp1_e*/
    3682      820800 :                     temp1 = BASOP_util_atan2( temp2, temp1, sub( temp1_e, 16 ) );             /*q13*/
    3683      820800 :                     diff_swap_fx = L_add( diff_swap_fx, temp1 );                              /*q13*/
    3684             :                 }
    3685             :             }
    3686             :             ELSE
    3687             :             {
    3688             :                 /* 1dir */
    3689     2853696 :                 sin_ele1_fx = getSineWord16R2( extract_l( Mpy_32_32( ele_rad1_fx, 2670177 /*2^24/(2*pi)*/ ) ) ); /*q15*/
    3690     2853696 :                 cos_ele1_fx = getCosWord16R2( extract_l( Mpy_32_32( ele_rad1_fx, 2670177 /*2^24/(2*pi)*/ ) ) );  /*q15*/
    3691             : 
    3692     2853696 :                 azi_rad2_fx = 0;
    3693     2853696 :                 ele_rad2_fx = 0;
    3694     2853696 :                 move32();
    3695     2853696 :                 move32();
    3696             : 
    3697     2853696 :                 sin_ele2_fx = 0;      /* sin(0) */
    3698     2853696 :                 cos_ele2_fx = MAX_16; /* cos(0) in Q15*/
    3699     2853696 :                 move16();
    3700     2853696 :                 move16();
    3701             : 
    3702     2853696 :                 diff_swap_fx = ONE_IN_Q13; /*1.0 in Q13*/
    3703     2853696 :                 diff_no_swap_fx = 0;
    3704     2853696 :                 move32();
    3705     2853696 :                 move32();
    3706             :             }
    3707             : 
    3708     3804096 :             test();
    3709     3804096 :             IF( GT_16( n_dirs, 1 ) && GT_32( diff_no_swap_fx, diff_swap_fx ) )
    3710      121788 :             {
    3711             :                 /* swap the metadata of the two directions in this TF-tile */
    3712             :                 Word32 tmp_val;
    3713             :                 Word16 tmp_val_16;
    3714             :                 UWord16 tmp_int_val;
    3715      121788 :                 tmp_val = hMeta->directional_meta[0].azimuth_fx[sf][band];                                         /*q22*/
    3716      121788 :                 hMeta->directional_meta[0].azimuth_fx[sf][band] = hMeta->directional_meta[1].azimuth_fx[sf][band]; /*q22*/
    3717      121788 :                 hMeta->directional_meta[1].azimuth_fx[sf][band] = tmp_val;                                         /*q22*/
    3718      121788 :                 move32();
    3719      121788 :                 move32();
    3720      121788 :                 move32();
    3721             : 
    3722      121788 :                 tmp_val = hMeta->directional_meta[0].elevation_fx[sf][band];                                           /*q22*/
    3723      121788 :                 hMeta->directional_meta[0].elevation_fx[sf][band] = hMeta->directional_meta[1].elevation_fx[sf][band]; /*q22*/
    3724      121788 :                 hMeta->directional_meta[1].elevation_fx[sf][band] = tmp_val;                                           /*q22*/
    3725      121788 :                 move32();
    3726      121788 :                 move32();
    3727      121788 :                 move32();
    3728             : 
    3729      121788 :                 tmp_int_val = hMeta->directional_meta[0].spherical_index[sf][band];                                          /*q0*/
    3730      121788 :                 hMeta->directional_meta[0].spherical_index[sf][band] = hMeta->directional_meta[1].spherical_index[sf][band]; /*q0*/
    3731      121788 :                 hMeta->directional_meta[1].spherical_index[sf][band] = tmp_int_val;                                          /*q0*/
    3732      121788 :                 move32();
    3733      121788 :                 move32();
    3734      121788 :                 move32();
    3735             : 
    3736      121788 :                 tmp_val = hMeta->directional_meta[0].energy_ratio_fx[sf][band];                                              /*q30*/
    3737      121788 :                 hMeta->directional_meta[0].energy_ratio_fx[sf][band] = hMeta->directional_meta[1].energy_ratio_fx[sf][band]; /*q30*/
    3738      121788 :                 hMeta->directional_meta[1].energy_ratio_fx[sf][band] = tmp_val;                                              /*q30*/
    3739      121788 :                 move32();
    3740      121788 :                 move32();
    3741      121788 :                 move32();
    3742             : 
    3743      121788 :                 tmp_val_16 = hMeta->directional_meta[0].spread_coherence_fx[sf][band];                                               /*q15*/
    3744      121788 :                 hMeta->directional_meta[0].spread_coherence_fx[sf][band] = hMeta->directional_meta[1].spread_coherence_fx[sf][band]; /*q15*/
    3745      121788 :                 hMeta->directional_meta[1].spread_coherence_fx[sf][band] = tmp_val_16;                                               /*q15*/
    3746      121788 :                 move16();
    3747      121788 :                 move16();
    3748      121788 :                 move16();
    3749             : 
    3750      121788 :                 hAlignState->previous_azi_dir1_fx[band] = azi_rad2_fx; /*q22*/
    3751      121788 :                 hAlignState->previous_ele_dir1_fx[band] = ele_rad2_fx; /*q22*/
    3752      121788 :                 move32();
    3753      121788 :                 move32();
    3754             : 
    3755      121788 :                 hAlignState->previous_azi_dir2_fx[band] = azi_rad1_fx; /*q22*/
    3756      121788 :                 hAlignState->previous_ele_dir2_fx[band] = ele_rad1_fx; /*q22*/
    3757      121788 :                 move32();
    3758      121788 :                 move32();
    3759             : 
    3760      121788 :                 prev_ele_dir1_cos_fx = cos_ele2_fx; /*q15*/
    3761      121788 :                 prev_ele_dir1_sin_fx = sin_ele2_fx; /*q15*/
    3762      121788 :                 move16();
    3763      121788 :                 move16();
    3764             : 
    3765      121788 :                 prev_ele_dir2_cos_fx = cos_ele1_fx; /*q15*/
    3766      121788 :                 prev_ele_dir2_sin_fx = sin_ele1_fx; /*q15*/
    3767      121788 :                 move16();
    3768      121788 :                 move16();
    3769             :             }
    3770             :             ELSE
    3771             :             {
    3772     3682308 :                 hAlignState->previous_azi_dir1_fx[band] = azi_rad1_fx; /*q22*/
    3773     3682308 :                 hAlignState->previous_ele_dir1_fx[band] = ele_rad1_fx; /*q22*/
    3774     3682308 :                 move32();
    3775     3682308 :                 move32();
    3776             : 
    3777     3682308 :                 hAlignState->previous_azi_dir2_fx[band] = azi_rad2_fx; /*q22*/
    3778     3682308 :                 hAlignState->previous_ele_dir2_fx[band] = ele_rad2_fx; /*q22*/
    3779     3682308 :                 move32();
    3780     3682308 :                 move32();
    3781             : 
    3782     3682308 :                 prev_ele_dir1_cos_fx = cos_ele1_fx; /*q15*/
    3783     3682308 :                 prev_ele_dir1_sin_fx = sin_ele1_fx; /*q15*/
    3784     3682308 :                 move16();
    3785     3682308 :                 move16();
    3786             : 
    3787     3682308 :                 prev_ele_dir2_cos_fx = cos_ele2_fx; /*q15*/
    3788     3682308 :                 prev_ele_dir2_sin_fx = sin_ele2_fx; /*q15*/
    3789     3682308 :                 move16();
    3790     3682308 :                 move16();
    3791             :             }
    3792             :         } /* sf */
    3793             :     }     /* band */
    3794             : 
    3795       39626 :     return;
    3796             : }
    3797             : 
    3798             : 
    3799             : /*-------------------------------------------------------------------*
    3800             :  * ivas_merge_masa_metadata()
    3801             :  *
    3802             :  *
    3803             :  *-------------------------------------------------------------------*/
    3804             : 
    3805        3996 : void ivas_merge_masa_metadata_fx(
    3806             :     MASA_ENCODER_HANDLE hMasa,           /* i/o: MASA enc handle. source for MASA metadata and combined metadata will be here */
    3807             :     OMASA_SPATIAL_META_HANDLE hOMasaMeta /* i  : ISM-object metadata to be merged with the MASA metadata                      */
    3808             : )
    3809             : {
    3810             :     Word16 sf, band;
    3811             :     UWord8 numCodingBands;
    3812             :     UWord8 numDirections;
    3813             :     UWord8 numSf;
    3814             :     MASA_METADATA_HANDLE hMeta;
    3815             :     Word16 energyTimesRatioMASA_e[2];
    3816             :     Word16 total_diff_nrg_e;
    3817             :     Word16 energyMerged_e[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
    3818             :     Word32 energyTimesRatioISM_fx; /*energyTimesRatioISM_e*/
    3819             :     Word16 energyTimesRatioISM_e;
    3820             :     Word32 energyTimesRatioMASA_fx[2]; /*energyTimesRatioMASA_e*/
    3821             :     Word32 total_diff_nrg_fx;
    3822             :     Word32 eneBand_fx; /*eneBand_e*/
    3823             :     Word16 eneBand_e;
    3824             :     Word32 energyMerged_fx[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS]; /*energyMerged_e*/
    3825        3996 :     OMASA_ENCODER_ENERGY_HANDLE hOmasaEnergy = hMasa->data.hOmasaData->hOmasaEnergy;
    3826             :     Word32 temp1 /*temp1_e*/, temp2 /*temp2_e*/;
    3827             :     Word16 temp1_e, temp2_e;
    3828             : 
    3829        3996 :     numCodingBands = hMasa->config.numCodingBands;
    3830        3996 :     numDirections = hMasa->config.numberOfDirections;
    3831        3996 :     IF( EQ_16( hMasa->config.joinedSubframes, TRUE ) )
    3832             :     {
    3833           0 :         numSf = 1;
    3834             :     }
    3835             :     ELSE
    3836             :     {
    3837        3996 :         numSf = MAX_PARAM_SPATIAL_SUBFRAMES;
    3838             :     }
    3839        3996 :     move16();
    3840        3996 :     move16();
    3841        3996 :     move16();
    3842        3996 :     hMeta = &( hMasa->masaMetadata );
    3843             : 
    3844       19980 :     FOR( sf = 0; sf < numSf; sf++ )
    3845             :     {
    3846      396000 :         FOR( band = 0; band < numCodingBands; band++ )
    3847             :         {
    3848             :             Word16 merge_dest;
    3849             :             Word32 dir_sum_fx; /*dir_sum_e*/
    3850             :             Word16 dir_sum_e;
    3851             :             UWord8 band_n_dirs;
    3852      380016 :             test();
    3853      380016 :             test();
    3854      380016 :             IF( EQ_16( numDirections, 1 ) || ( EQ_16( numDirections, 2 ) && hMasa->data.twoDirBands[band] == 0 ) )
    3855             :             {
    3856      380016 :                 band_n_dirs = 1;
    3857             :             }
    3858             :             ELSE
    3859             :             {
    3860           0 :                 band_n_dirs = 2;
    3861             :             }
    3862      380016 :             move16();
    3863             : 
    3864             :             /* Compute energies */
    3865      380016 :             eneBand_fx = hMasa->data.energy_fx[sf][band];
    3866      380016 :             eneBand_e = hMasa->data.energy_e[sf][band];
    3867      380016 :             move32();
    3868      380016 :             move16();
    3869      380016 :             energyMerged_fx[sf][band] = BASOP_Util_Add_Mant32Exp( eneBand_fx, eneBand_e, hOmasaEnergy->energy_ism_fx[sf][band], hOmasaEnergy->energy_ism_fx_e[sf][band], &energyMerged_e[sf][band] );
    3870      380016 :             move32();
    3871             : 
    3872             :             /* Compute weights */
    3873      380016 :             energyTimesRatioMASA_fx[0] = Mpy_32_32( eneBand_fx, hMeta->directional_meta[0].energy_ratio_fx[sf][band] );
    3874      380016 :             energyTimesRatioMASA_e[0] = add( eneBand_e, 1 );
    3875      380016 :             move32();
    3876      380016 :             move16();
    3877      380016 :             IF( EQ_16( band_n_dirs, 2 ) )
    3878             :             {
    3879           0 :                 energyTimesRatioMASA_fx[1] = Mpy_32_32( eneBand_fx, hMeta->directional_meta[1].energy_ratio_fx[sf][band] ); // energyTimesRatioMASA_e
    3880           0 :                 energyTimesRatioMASA_e[1] = add( eneBand_e, 1 );
    3881             :             }
    3882             :             ELSE
    3883             :             {
    3884      380016 :                 energyTimesRatioMASA_fx[1] = 0; // energyTimesRatioMASA_e
    3885      380016 :                 energyTimesRatioMASA_e[1] = 0;
    3886             :             }
    3887      380016 :             move32();
    3888      380016 :             move16();
    3889             : 
    3890             :             /* target is original MASA diffuseness */
    3891      380016 :             total_diff_nrg_fx = Mpy_32_32( eneBand_fx, hMeta->common_meta.diffuse_to_total_ratio_fx[sf][band] ); // total_diff_nrg_e
    3892      380016 :             total_diff_nrg_e = add( eneBand_e, 1 );
    3893             : 
    3894             :             /* criterion is mean of ISM ratio and new ratio */
    3895      380016 :             temp1 = BASOP_Util_Add_Mant32Exp( L_add( EPSILON_FX, eneBand_fx ), eneBand_e, hOmasaEnergy->energy_ism_fx[sf][band], hOmasaEnergy->energy_ism_fx_e[sf][band], &temp1_e ); /* EPSILON + eneBand + hMasa->data.hOmasaData->energy_ism[sf][band]*/
    3896      380016 :             temp2 = L_deposit_h( BASOP_Util_Divide3232_Scale( total_diff_nrg_fx, temp1, &temp2_e ) ); /*temp2_e*/                                                                     /*total_diff_nrg / ( EPSILON + eneBand + hMasa->data.hOmasaData->energy_ism[sf][band] )*/
    3897      380016 :             temp2_e = add( temp2_e, sub( total_diff_nrg_e, temp1_e ) );
    3898      380016 :             IF( temp2_e < 0 )
    3899             :             {
    3900      283974 :                 temp2 = L_shl( temp2, temp2_e );
    3901      283974 :                 temp2_e = 0;
    3902      283974 :                 move16();
    3903             :             }
    3904      380016 :             temp2 = L_sub( L_shl_sat( 1, sub( 31, temp2_e ) ), temp2 );                                                                 /*( 1.0f - total_diff_nrg / ( EPSILON + eneBand + hOmasaEnergy->energy_ism[sf][band] ) )*/
    3905      380016 :             temp2 = BASOP_Util_Add_Mant32Exp( hOMasaMeta->directional_meta[0].energy_ratio_fx[sf][band], 1, temp2, temp2_e, &temp2_e ); /*( 1.0f - total_diff_nrg / ( EPSILON + eneBand + hOmasaEnergy->energy_ism[sf][band] ) )*/
    3906      380016 :             energyTimesRatioISM_fx = Mpy_32_32( L_shr( temp2, 1 ), hOmasaEnergy->energy_ism_fx[sf][band] );                             /*energyTimesRatioISM_e*/
    3907      380016 :             energyTimesRatioISM_e = add( temp2_e, hOmasaEnergy->energy_ism_fx_e[sf][band] );
    3908             :             /*energyTimesRatioISM = ( hOMasaMeta->directional_meta[0].energy_ratio[sf][band] + ( 1.0f - total_diff_nrg / ( EPSILON + eneBand + hOmasaEnergy->energy_ism[sf][band] ) ) ) / 2.0f * hOmasaEnergy->energy_ism[sf][band];*/
    3909             : 
    3910             :             /* Determine combined metadata based on the weights */
    3911      380016 :             merge_dest = -1;
    3912      380016 :             move16();
    3913      380016 :             test();
    3914      380016 :             test();
    3915      380016 :             test();
    3916      380016 :             test();
    3917      380016 :             test();
    3918      380016 :             test();
    3919      380016 :             IF( ( EQ_16( band_n_dirs, 1 ) && EQ_16( BASOP_Util_Cmp_Mant32Exp( energyTimesRatioMASA_fx[0], energyTimesRatioMASA_e[0], energyTimesRatioISM_fx, energyTimesRatioISM_e ), -1 ) ) ||
    3920             :                 ( EQ_16( band_n_dirs, 2 ) && EQ_16( BASOP_Util_Cmp_Mant32Exp( energyTimesRatioMASA_fx[0], energyTimesRatioMASA_e[0], energyTimesRatioMASA_fx[1], energyTimesRatioMASA_e[1] ), -1 ) && EQ_16( BASOP_Util_Cmp_Mant32Exp( energyTimesRatioMASA_fx[0], energyTimesRatioMASA_e[0], energyTimesRatioISM_fx, energyTimesRatioISM_e ), -1 ) ) )
    3921             :             {
    3922             :                 /* 1dir and ISM the most energetic, or 2dir and ISM the more energetic than MASA1 */
    3923      143404 :                 merge_dest = 0;
    3924             :             }
    3925      236612 :             ELSE IF( EQ_16( band_n_dirs, 2 ) && NE_16( BASOP_Util_Cmp_Mant32Exp( energyTimesRatioMASA_fx[1], energyTimesRatioMASA_e[1], energyTimesRatioMASA_fx[0], energyTimesRatioMASA_e[0] ), 1 ) && EQ_16( BASOP_Util_Cmp_Mant32Exp( energyTimesRatioMASA_fx[1], energyTimesRatioMASA_e[1], energyTimesRatioISM_fx, energyTimesRatioISM_e ), -1 ) )
    3926             :             {
    3927             :                 /* 2dir and ISM the most energetic and MASA2 the least energetic */
    3928           0 :                 merge_dest = 1;
    3929             :             }
    3930      380016 :             move16();
    3931             : 
    3932      380016 :             IF( merge_dest >= 0 ) /* replace one MASA with ISM */
    3933             :             {
    3934      143404 :                 hMeta->directional_meta[merge_dest].azimuth_fx[sf][band] = hOMasaMeta->directional_meta[0].azimuth_fx[sf][band];     /*q22*/
    3935      143404 :                 hMeta->directional_meta[merge_dest].elevation_fx[sf][band] = hOMasaMeta->directional_meta[0].elevation_fx[sf][band]; /*q22*/
    3936      143404 :                 move32();
    3937      143404 :                 move32();
    3938             :                 /* limit with the earlier direct-energy ratio */
    3939      143404 :                 dir_sum_fx = temp2; /* new dir ratio */
    3940      143404 :                 dir_sum_e = temp2_e;
    3941      143404 :                 move32();
    3942      143404 :                 move16();
    3943             :                 /*dir_sum = 1.0f - total_diff_nrg / ( EPSILON + eneBand + hOmasaEnergy->energy_ism[sf][band] )*/
    3944      143404 :                 IF( EQ_16( BASOP_Util_Cmp_Mant32Exp( dir_sum_fx, dir_sum_e, hOMasaMeta->directional_meta[0].energy_ratio_fx[sf][band], 1 ), -1 ) )
    3945             :                 {
    3946           0 :                     hMeta->directional_meta[merge_dest].energy_ratio_fx[sf][band] = L_shl( dir_sum_fx, sub( dir_sum_e, 1 ) ); /*scaling to Q30*/
    3947             :                 }
    3948             :                 ELSE
    3949             :                 {
    3950      143404 :                     hMeta->directional_meta[merge_dest].energy_ratio_fx[sf][band] = hOMasaMeta->directional_meta[0].energy_ratio_fx[sf][band]; /*q30*/
    3951      143404 :                     move32();
    3952             :                 }
    3953             :                 /* clip with original ISM dir */
    3954      143404 :                 hMeta->common_meta.diffuse_to_total_ratio_fx[sf][band] = L_sub( ONE_IN_Q30, hMeta->directional_meta[merge_dest].energy_ratio_fx[sf][band] ); /*q30*/
    3955      143404 :                 move32();
    3956      143404 :                 move32(); /*hMeta->directional_meta[merge_dest].energy_ratio_fx*/
    3957             : 
    3958      143404 :                 IF( hMasa->config.useCoherence )
    3959             :                 {
    3960           0 :                     hMeta->directional_meta[merge_dest].spread_coherence_fx[sf][band] = hOMasaMeta->directional_meta[0].spread_coherence_fx[sf][band]; /*q15*/
    3961           0 :                     hMeta->common_meta.surround_coherence_fx[sf][band] = hOMasaMeta->common_meta.surround_coherence_fx[sf][band];                      /*q15*/
    3962           0 :                     move16();
    3963           0 :                     move16();
    3964             :                 }
    3965             : 
    3966             :                 /* recompute direct energy ratios to match the diffuse ratio */
    3967             :                 Word32 direct_quota_fx, direct_scaler_fx;
    3968             :                 Word16 direct_scaler_e;
    3969      143404 :                 direct_quota_fx = L_sub( ONE_IN_Q30, hMeta->common_meta.diffuse_to_total_ratio_fx[sf][band] );
    3970      143404 :                 IF( EQ_16( band_n_dirs, 1 ) )
    3971             :                 {
    3972      143404 :                     hMeta->directional_meta[0].energy_ratio_fx[sf][band] = direct_quota_fx; /*q30*/
    3973      143404 :                     move32();
    3974             :                 }
    3975             :                 ELSE
    3976             :                 {
    3977           0 :                     dir_sum_fx = L_add( hMeta->directional_meta[0].energy_ratio_fx[sf][band], hMeta->directional_meta[1].energy_ratio_fx[sf][band] ); /*q30*/
    3978           0 :                     direct_scaler_fx = BASOP_Util_Divide3232_Scale( direct_quota_fx, L_add( EPSILON_FX, dir_sum_fx ), &direct_scaler_e );
    3979           0 :                     direct_scaler_fx = L_shl( direct_scaler_fx, direct_scaler_e ); /*q31*/
    3980           0 :                     direct_scaler_e = 0;
    3981           0 :                     move16();
    3982           0 :                     hMeta->directional_meta[0].energy_ratio_fx[sf][band] = Mpy_32_32( direct_scaler_fx, hMeta->directional_meta[0].energy_ratio_fx[sf][band] ); /*q30*/
    3983           0 :                     hMeta->directional_meta[1].energy_ratio_fx[sf][band] = Mpy_32_32( direct_scaler_fx, hMeta->directional_meta[0].energy_ratio_fx[sf][band] ); /*q30*/
    3984           0 :                     move32();
    3985           0 :                     move32();
    3986             :                 }
    3987             :             }
    3988             :         }
    3989             :     }
    3990             : 
    3991       19980 :     FOR( sf = 0; sf < numSf; sf++ )
    3992             :     {
    3993      396000 :         FOR( band = 0; band < numCodingBands; band++ )
    3994             :         {
    3995      380016 :             hMasa->data.energy_fx[sf][band] = energyMerged_fx[sf][band];
    3996      380016 :             hMasa->data.energy_e[sf][band] = energyMerged_e[sf][band];
    3997      380016 :             move32();
    3998      380016 :             move16();
    3999             :         }
    4000             :     }
    4001             : 
    4002        3996 :     return;
    4003             : }
    4004             : 
    4005             : 
    4006       30442 : static void quantize_ratio_ism_vector_ivas_fx(
    4007             :     const Word16 *ratio_ism, /* ratio_ism_e */
    4008             :     Word16 ratio_ism_e,
    4009             :     Word16 *idx, /* Q0 */
    4010             :     const Word16 nchan_ism,
    4011             :     const Word32 masa_to_total_energy_ratio,
    4012             :     const Word16 idx_sep_object )
    4013             : {
    4014             :     Word16 i, j, best_i, best_i2;
    4015             :     Word16 dist, div, tmp, dist2, best_dist, temp, temp_e, tmp_e, idx_e, best_dist_e, dist_e, dist2_e;
    4016             :     Word16 part_idx_sum, max_sum_idx;
    4017             :     Word16 ratio_ism_loc[MAX_NUM_OBJECTS];
    4018             :     Word16 no_ism_loc;
    4019             : 
    4020       30442 :     max_sum_idx = sub( shl( 1, PARAM_ISM_POW_RATIO_NBITS ), 1 );
    4021             : 
    4022       30442 :     test();
    4023       30442 :     IF( GT_16( idx_sep_object, -1 ) )
    4024             :     {
    4025       30442 :         temp = BASOP_Util_Divide1616_Scale( 1, max_sum_idx, &temp_e );
    4026       30442 :         BASOP_Util_Add_MantExp( ratio_ism[idx_sep_object], ratio_ism_e, negate( temp ), temp_e, &tmp );
    4027             : 
    4028       30442 :         test();
    4029       30442 :         IF( tmp < 0 )
    4030             :         {
    4031             :             /* take it out from quantize function  */
    4032       28839 :             Copy( ratio_ism, ratio_ism_loc, idx_sep_object ); // Q(15 - ratio_ism_e)
    4033       28839 :             Copy( &ratio_ism[idx_sep_object + 1], &ratio_ism_loc[idx_sep_object], nchan_ism - idx_sep_object - 1 );
    4034       28839 :             no_ism_loc = sub( nchan_ism, 1 );
    4035             :         }
    4036             :         ELSE
    4037             :         {
    4038        1603 :             no_ism_loc = nchan_ism;
    4039        1603 :             move16();
    4040        1603 :             Copy( ratio_ism, ratio_ism_loc, nchan_ism );
    4041             :         }
    4042             :     }
    4043             :     ELSE
    4044             :     {
    4045           0 :         no_ism_loc = nchan_ism;
    4046           0 :         move16();
    4047           0 :         Copy( ratio_ism, ratio_ism_loc, nchan_ism );
    4048             :     }
    4049             : 
    4050       30442 :     test();
    4051       30442 :     IF( GT_16( nchan_ism, 1 ) )
    4052             :     {
    4053       30442 :         test();
    4054       30442 :         IF( GE_32( masa_to_total_energy_ratio, MASA2TOTAL_THR_Q30 ) )
    4055             :         {
    4056        3593 :             distribute_evenly_ism_fx( idx, max_sum_idx, nchan_ism );
    4057             :         }
    4058             :         ELSE
    4059             :         {
    4060       26849 :             test();
    4061       26849 :             IF( GT_16( no_ism_loc, 1 ) )
    4062             :             {
    4063             : 
    4064       26135 :                 dist = 0;
    4065       26135 :                 dist_e = 0;
    4066       26135 :                 div = div_s( 1, max_sum_idx ); // Q15
    4067       26135 :                 move16();
    4068       26135 :                 move16();
    4069             : 
    4070       26135 :                 part_idx_sum = 0;
    4071       26135 :                 move16();
    4072             : 
    4073       95154 :                 FOR( i = 0; i < no_ism_loc; i++ )
    4074             :                 {
    4075       69019 :                     idx[i] = extract_l( L_shr( L_mult0( ratio_ism_loc[i], max_sum_idx ), sub( 15, ratio_ism_e ) ) ); // Q0
    4076       69019 :                     move16();
    4077       69019 :                     part_idx_sum = add( part_idx_sum, idx[i] );
    4078             : 
    4079       69019 :                     tmp_e = BASOP_Util_Add_MantExp( ratio_ism_loc[i], ratio_ism_e, negate( imult1616( idx[i], div ) ), 0, &tmp ); // tmp_e
    4080       69019 :                     dist_e = BASOP_Util_Add_MantExp( dist, dist_e, mult( tmp, tmp ), add( tmp_e, tmp_e ), &dist );                // dist_e
    4081             :                 }
    4082             : 
    4083       26135 :                 best_dist = dist;
    4084       26135 :                 best_dist_e = dist_e;
    4085       26135 :                 best_i2 = -1;
    4086       26135 :                 move16();
    4087       26135 :                 move16();
    4088       26135 :                 move16();
    4089             : 
    4090       54125 :                 WHILE( ( part_idx_sum < max_sum_idx ) )
    4091             :                 {
    4092       27990 :                     best_i = -1;
    4093       27990 :                     move16();
    4094             :                     /* check which index to increase by 1 for a possible improvement */
    4095             : 
    4096      102694 :                     FOR( i = 0; i < no_ism_loc; i++ )
    4097             :                     {
    4098       74704 :                         idx[i] = add( idx[i], 1 );
    4099       74704 :                         move16();
    4100       74704 :                         dist2 = 0;
    4101       74704 :                         dist2_e = 0;
    4102       74704 :                         move16();
    4103       74704 :                         move16();
    4104             : 
    4105      282160 :                         FOR( j = 0; j < no_ism_loc; j++ )
    4106             :                         {
    4107      207456 :                             Word32 temp1 = L_mult( idx[i], div ); // Q : 15 + 0 + 1
    4108      207456 :                             Word16 temp1_n = norm_l( temp1 );
    4109      207456 :                             Word16 temp1_16 = extract_h( L_shl( temp1, temp1_n ) );                                                        // Q : Q + temp1_n - 16
    4110      207456 :                             tmp_e = BASOP_Util_Add_MantExp( ratio_ism_loc[i], ratio_ism_e, negate( temp1_16 ), sub( 15, temp1_n ), &tmp ); // tmp_e
    4111      207456 :                             dist2_e = BASOP_Util_Add_MantExp( dist2, dist2_e, mult_sat( tmp, tmp ), add( tmp_e, tmp_e ), &dist2 );         // dist_e
    4112             :                         }
    4113             : 
    4114       74704 :                         BASOP_Util_Add_MantExp( dist2, dist2_e, negate( best_dist ), best_dist_e, &tmp );
    4115       74704 :                         test();
    4116       74704 :                         IF( tmp < 0 )
    4117             :                         {
    4118       22940 :                             best_i2 = best_i;
    4119       22940 :                             best_i = i;
    4120       22940 :                             best_dist = dist2;
    4121       22940 :                             best_dist_e = dist2_e;
    4122       22940 :                             move16();
    4123       22940 :                             move16();
    4124       22940 :                             move16();
    4125       22940 :                             move16();
    4126             :                         }
    4127       74704 :                         idx[i] = sub( idx[i], 1 );
    4128       74704 :                         move16();
    4129             :                     }
    4130             : 
    4131       27990 :                     test();
    4132       27990 :                     IF( GT_16( best_i, -1 ) )
    4133             :                     {
    4134       21734 :                         idx[best_i] = add( idx[best_i], 1 );
    4135       21734 :                         move16();
    4136       21734 :                         part_idx_sum = add( part_idx_sum, 1 );
    4137             :                     }
    4138             :                     ELSE
    4139             :                     {
    4140        6256 :                         test();
    4141        6256 :                         IF( GT_16( best_i2, -1 ) )
    4142             :                         {
    4143        1043 :                             idx[best_i2] = add( idx[best_i2], 1 );
    4144        1043 :                             move16();
    4145        1043 :                             part_idx_sum = add( part_idx_sum, 1 );
    4146             :                         }
    4147             :                         ELSE
    4148             :                         {
    4149        5213 :                             idx[no_ism_loc - 1] = add( idx[no_ism_loc - 1], sub( max_sum_idx, part_idx_sum ) );
    4150        5213 :                             move16();
    4151        5213 :                             part_idx_sum = max_sum_idx;
    4152        5213 :                             move16();
    4153             :                         }
    4154             :                     }
    4155             :                 }
    4156       26135 :                 assert( sum_s( idx, no_ism_loc ) == max_sum_idx );
    4157             :             }
    4158             :             ELSE
    4159             :             {
    4160         714 :                 idx[0] = max_sum_idx;
    4161         714 :                 move16();
    4162             :             }
    4163             : 
    4164       26849 :             test();
    4165       26849 :             IF( LT_16( no_ism_loc, nchan_ism ) )
    4166             :             {
    4167             :                 /*  insert back the ratio of the separated object  */
    4168       70971 :                 FOR( i = nchan_ism - 1; i > idx_sep_object; i-- )
    4169             :                 {
    4170       45655 :                     idx[i] = idx[i - 1];
    4171       45655 :                     move16();
    4172             :                 }
    4173       25316 :                 idx[idx_sep_object] = 0;
    4174       25316 :                 move16();
    4175             :             }
    4176             :         }
    4177             :     }
    4178             :     ELSE
    4179             :     {
    4180             :         // idx[0] = (int16_t) ( ( ratio_ism[0] ) * ( ( 1 << PARAM_ISM_POW_RATIO_NBITS ) - 1 ) + 0.5f );
    4181           0 :         tmp = imult1616( ratio_ism[0], sub( shl( 1, PARAM_ISM_POW_RATIO_NBITS ), 1 ) ); // tmp_e
    4182           0 :         tmp_e = ratio_ism_e;
    4183           0 :         move16();
    4184           0 :         idx_e = BASOP_Util_Add_MantExp( tmp, tmp_e, 16384 /* 0.5 in Q15 */, 0, &idx[0] ); // idx_e
    4185           0 :         idx[0] = shl( idx[0], sub( idx_e, 15 ) );                                         // Q0
    4186           0 :         move16();
    4187             :     }
    4188             : 
    4189       30442 :     return;
    4190             : }
    4191             : 
    4192             : 
    4193        6665 : static Word16 index_slice_enum_fx(
    4194             :     const Word16 *ratio_ism_idx,
    4195             :     const Word16 nchan_ism )
    4196             : {
    4197             :     Word16 i;
    4198             :     Word16 x, index;
    4199             :     Word16 base;
    4200             : 
    4201        6665 :     IF( EQ_16( nchan_ism, 2 ) )
    4202             :     {
    4203         308 :         index = ratio_ism_idx[0];
    4204         308 :         move16();
    4205             :     }
    4206             :     ELSE
    4207             :     {
    4208        6357 :         x = ratio_ism_idx[nchan_ism - 2];
    4209        6357 :         base = 10;
    4210        6357 :         move16();
    4211        6357 :         move16();
    4212       17248 :         FOR( i = nchan_ism - 3; i >= 0; i-- )
    4213             :         {
    4214       10891 :             x = add( x, imult1616( ratio_ism_idx[i], base ) );
    4215       10891 :             base = imult1616( base, 10 );
    4216             :         }
    4217             : 
    4218        6357 :         index = 0;
    4219        6357 :         i = 0;
    4220        6357 :         move16();
    4221        6357 :         move16();
    4222      928866 :         WHILE( LE_16( i, x ) )
    4223             :         {
    4224      922509 :             IF( valid_ratio_index_fx( i, 7, nchan_ism - 1 ) )
    4225             :             {
    4226      252718 :                 index = add( index, 1 );
    4227             :             }
    4228      922509 :             i = add( i, 1 );
    4229             :         }
    4230        6357 :         index = sub( index, 1 );
    4231             :     }
    4232             : 
    4233        6665 :     return index;
    4234             : }
    4235             : 
    4236       61502 : static void transform_difference_index_ivas_fx(
    4237             :     const Word16 *diff_idx,
    4238             :     Word16 *idx,
    4239             :     const Word16 len )
    4240             : {
    4241             :     Word16 i;
    4242      189070 :     FOR( i = 0; i < len; i++ )
    4243             :     {
    4244      127568 :         IF( diff_idx[i] <= 0 )
    4245             :         {
    4246       99618 :             idx[i] = negate( shl( diff_idx[i], 1 ) );
    4247       99618 :             move16();
    4248             :         }
    4249             :         ELSE
    4250             :         {
    4251       27950 :             idx[i] = sub( shl( diff_idx[i], 1 ), 1 );
    4252       27950 :             move16();
    4253             :         }
    4254             :     }
    4255             : 
    4256       61502 :     return;
    4257             : }
    4258             : 
    4259             : 
    4260       20139 : static void transform_index_and_GR_encode_ivas_fx(
    4261             :     Word16 *diff_idx,         /* i  : differenc eindex to encode    */
    4262             :     const Word16 len,         /* i  : input length                  */
    4263             :     const Word16 GR_order,    /* i  : GR order                      */
    4264             :     BSTR_ENC_HANDLE hMetaData /* i/o: metadata bitstream handle     */
    4265             : )
    4266             : {
    4267             :     Word16 i;
    4268             :     Word16 idx[IVAS_MAX_NUM_OBJECTS];
    4269             : 
    4270             :     /* transform difference index into positive */
    4271       20139 :     transform_difference_index_ivas_fx( diff_idx, idx, len );
    4272             : 
    4273             :     /* GR encoding */
    4274       61030 :     FOR( i = 0; i < len; i++ )
    4275             :     {
    4276       40891 :         ivas_qmetadata_encode_extended_gr_fx( hMetaData, idx[i], 100, GR_order );
    4277             :     }
    4278             : 
    4279       20139 :     return;
    4280             : }
    4281             : 
    4282             : 
    4283        1862 : static Word16 try_differential_fx(
    4284             :     const Word16 numCodingBands,
    4285             :     const Word32 *masa_to_total_energy_ratio, /* Q30 */
    4286             :     Word16 ratio_ism_idx[MASA_FREQUENCY_BANDS][MAX_NUM_OBJECTS],
    4287             :     const Word16 nchan_ism,
    4288             :     const Word16 bits_index,
    4289             :     Word16 *p_b_signif )
    4290             : {
    4291             :     Word16 b, i;
    4292             :     Word16 nbits0;
    4293             :     Word16 b_signif;
    4294             :     Word16 ratio_ism_idx_ref[MAX_NUM_OBJECTS];
    4295             :     Word16 diff_idx[MAX_NUM_OBJECTS];
    4296             : 
    4297        1862 :     b_signif = 0;
    4298        1862 :     move16();
    4299        2162 :     WHILE( ( b_signif < numCodingBands ) && ( masa_to_total_energy_ratio[b_signif] >= MASA2TOTAL_THR_Q30 ) )
    4300             :     {
    4301         300 :         test();
    4302         300 :         b_signif = add( b_signif, 1 );
    4303             :     }
    4304             : 
    4305        1862 :     nbits0 = 0;
    4306        1862 :     move16();
    4307             : 
    4308        1862 :     IF( LT_16( b_signif, numCodingBands ) )
    4309             :     {
    4310        1806 :         nbits0 = bits_index;
    4311        1806 :         move16();
    4312        1806 :         Copy( ratio_ism_idx[b_signif], ratio_ism_idx_ref, nchan_ism );
    4313             : 
    4314       11560 :         FOR( b = b_signif + 1; b < numCodingBands; b++ )
    4315             :         {
    4316        9754 :             IF( LT_32( masa_to_total_energy_ratio[b], MASA2TOTAL_THR_Q30 ) )
    4317             :             {
    4318        8627 :                 v_sub_s16_fx( ratio_ism_idx[b], ratio_ism_idx_ref, diff_idx, nchan_ism );
    4319        8627 :                 Copy( ratio_ism_idx[b], ratio_ism_idx_ref, nchan_ism );
    4320             : 
    4321             :                 /* transform difference index into positive */
    4322        8627 :                 transform_difference_index_ivas_fx( diff_idx, diff_idx, sub( nchan_ism, 1 ) );
    4323             : 
    4324             :                 /* GR encoding */
    4325       30122 :                 FOR( i = 0; i < nchan_ism - 1; i++ )
    4326             :                 {
    4327       21495 :                     nbits0 = add( nbits0, ivas_qmetadata_encode_extended_gr_length_fx( diff_idx[i], 100, 0 ) );
    4328             :                 }
    4329             :             }
    4330             :         }
    4331             :     }
    4332        1862 :     *p_b_signif = b_signif;
    4333        1862 :     move16();
    4334             : 
    4335        1862 :     return nbits0;
    4336             : }
    4337             : 
    4338             : 
    4339         666 : static void differential_coding_first_subframe_ivas_fx(
    4340             :     BSTR_ENC_HANDLE hMetaData,
    4341             :     const Word32 *masa_to_total_energy_ratio, // Q30
    4342             :     const Word16 b_signif,
    4343             :     Word16 ratio_ism_idx[MASA_FREQUENCY_BANDS][MAX_NUM_OBJECTS],
    4344             :     const Word16 nchan_ism,
    4345             :     const Word16 numCodingBands,
    4346             :     const Word16 bits_index )
    4347             : {
    4348             :     Word16 index, b;
    4349             :     Word16 ratio_ism_idx_ref[MAX_NUM_OBJECTS];
    4350             :     Word16 diff_idx[MAX_NUM_OBJECTS];
    4351             : 
    4352             :     /* differential encoding*/
    4353         666 :     push_next_indice( hMetaData, 0, 1 );
    4354             : 
    4355         666 :     IF( LT_16( b_signif, numCodingBands ) )
    4356             :     {
    4357         666 :         index = index_slice_enum_fx( ratio_ism_idx[b_signif], nchan_ism );
    4358         666 :         push_next_indice( hMetaData, index, bits_index );
    4359             : 
    4360         666 :         Copy( ratio_ism_idx[b_signif], ratio_ism_idx_ref, nchan_ism );
    4361             : 
    4362        4892 :         FOR( b = b_signif + 1; b < numCodingBands; b++ )
    4363             :         {
    4364        4226 :             IF( LT_32( masa_to_total_energy_ratio[b], MASA2TOTAL_THR_Q30 ) )
    4365             :             {
    4366        3768 :                 v_sub_s16_fx( ratio_ism_idx[b], ratio_ism_idx_ref, diff_idx, nchan_ism );
    4367        3768 :                 Copy( ratio_ism_idx[b], ratio_ism_idx_ref, nchan_ism );
    4368             : 
    4369             :                 /* transform difference index into positive */
    4370        3768 :                 transform_index_and_GR_encode_ivas_fx( diff_idx, sub( nchan_ism, 1 ), 0, hMetaData );
    4371             :             }
    4372             :         }
    4373             :     }
    4374             : 
    4375         666 :     return;
    4376             : }
    4377             : 
    4378             : 
    4379        1140 : static void independent_coding_ratio_ism_idx_fx(
    4380             :     Word16 ratio_ism_idx[MASA_FREQUENCY_BANDS][MAX_NUM_OBJECTS], /* i  : ISM ratios                */
    4381             :     const Word32 *masa_to_total_energy_ratio,                    /* i  : MASA to total ratios, Q30 */
    4382             :     const Word16 nchan_ism,                                      /* i  : number of objects         */
    4383             :     const Word16 numCodingBands,                                 /* i  : number of subbands        */
    4384             :     const Word16 bits_index,                                     /* i  : number of bits per index  */
    4385             :     BSTR_ENC_HANDLE hMetaData                                    /* i/o: metadata bitstream handle */
    4386             : )
    4387             : {
    4388             :     Word16 b, index;
    4389             : 
    4390        7844 :     FOR( b = 0; b < numCodingBands; b++ )
    4391             :     {
    4392        6704 :         IF( LT_32( masa_to_total_energy_ratio[b], MASA2TOTAL_THR_Q30 ) )
    4393             :         {
    4394        5999 :             index = index_slice_enum_fx( ratio_ism_idx[b], nchan_ism );
    4395        5999 :             push_next_indice( hMetaData, index, bits_index );
    4396             :         }
    4397             :     }
    4398             : 
    4399        1140 :     return;
    4400             : }
    4401             : 
    4402             : 
    4403       29124 : static void remove_sep_obj_fx(
    4404             :     Word16 *diff_idx,        /* i/o: array of difference of indexes                        */
    4405             :     const Word16 nchan_ism,  /* i  : number of objects                                     */
    4406             :     const Word16 idx_sep_obj /* i  : index of separated object, to be taken out of array   */
    4407             : )
    4408             : {
    4409             :     Word16 i;
    4410             : 
    4411       88197 :     FOR( i = idx_sep_obj; i < nchan_ism - 1; i++ )
    4412             :     {
    4413       59073 :         diff_idx[i] = diff_idx[i + 1];
    4414       59073 :         move16();
    4415             :     }
    4416             : 
    4417       29124 :     return;
    4418             : }
    4419             : 
    4420             : 
    4421       32736 : static void estimate_bits_subband_ism_ratio_fx(
    4422             :     const Word16 *ratio_ism_idx,
    4423             :     const Word16 *ratio_ism_idx_ref, /* ( i/o ) */
    4424             :     const Word16 nchan_ism,
    4425             :     const Word16 shift_one,
    4426             :     const Word16 idx_sep_obj,
    4427             :     Word16 *p_nbits0,
    4428             :     Word16 *p_nbits1 )
    4429             : {
    4430             :     Word16 diff_idx[MAX_NUM_OBJECTS];
    4431             :     Word16 nbits0, nbits1;
    4432             :     Word16 i;
    4433             : 
    4434       32736 :     nbits0 = 0;
    4435       32736 :     nbits1 = 0;
    4436       32736 :     move16();
    4437       32736 :     move16();
    4438             : 
    4439             :     /* take difference with respect to previous subframe */
    4440       32736 :     v_sub_s16_fx( ratio_ism_idx, ratio_ism_idx_ref, diff_idx, nchan_ism );
    4441             : 
    4442       32736 :     IF( shift_one )
    4443             :     {
    4444       19416 :         remove_sep_obj_fx( diff_idx, nchan_ism, idx_sep_obj );
    4445             :     }
    4446             : 
    4447             :     /* transform difference index into positive */
    4448       32736 :     transform_difference_index_ivas_fx( diff_idx, diff_idx, sub( sub( nchan_ism, 1 ), shift_one ) );
    4449             : 
    4450             :     /* GR encoding */
    4451       97918 :     FOR( i = 0; i < nchan_ism - 1 - shift_one; i++ )
    4452             :     {
    4453       65182 :         nbits0 = add( nbits0, ivas_qmetadata_encode_extended_gr_length_fx( diff_idx[i], 100, 0 ) );
    4454       65182 :         nbits1 = add( nbits1, ivas_qmetadata_encode_extended_gr_length_fx( diff_idx[i], 100, 1 ) );
    4455             :     }
    4456             : 
    4457       32736 :     *p_nbits0 = nbits0;
    4458       32736 :     *p_nbits1 = nbits1;
    4459       32736 :     move16();
    4460       32736 :     move16();
    4461             : 
    4462       32736 :     return;
    4463             : }
    4464             : 
    4465             : 
    4466        5636 : static Word16 encode_ratio_ism_subframe_fx(
    4467             :     Word16 ratio_ism_idx[MASA_FREQUENCY_BANDS][MAX_NUM_OBJECTS],
    4468             :     const Word16 nchan_ism,
    4469             :     const UWord8 numCodingBands,
    4470             :     const Word16 sf,
    4471             :     Word16 ratio_ism_idx_prev_sf[MASA_FREQUENCY_BANDS][MAX_NUM_OBJECTS],
    4472             :     BSTR_ENC_HANDLE hMetaData,
    4473             :     const Word32 *masa_to_total_energy_ratio, /* Q30 */
    4474             :     const Word16 shift_one,
    4475             :     const Word16 idx_separated_obj )
    4476             : {
    4477             :     Word16 b, b_signif;
    4478             :     Word16 diff_idx[MAX_NUM_OBJECTS];
    4479             :     Word16 nbits, nbits0, nbits1, GR_order, GR_order_sb;
    4480             :     Word16 differential_subframe;
    4481             :     Word16 ratio_ism_idx_ref[MAX_NUM_OBJECTS];
    4482             :     Word16 bits_index;
    4483             :     Word16 nbits00, nbits11;
    4484             :     Word16 idx_sep_obj_local;
    4485             : 
    4486        5636 :     idx_sep_obj_local = idx_separated_obj;
    4487        5636 :     move16();
    4488        5636 :     IF( GT_16( idx_separated_obj, -1 ) )
    4489             :     {
    4490        5636 :         if ( EQ_16( idx_separated_obj, sub( nchan_ism, 1 ) ) )
    4491             :         {
    4492         803 :             idx_sep_obj_local = 0;
    4493         803 :             move16();
    4494             :         }
    4495             :     }
    4496        5636 :     nbits = 0;
    4497        5636 :     nbits0 = 0;
    4498        5636 :     nbits1 = 0;
    4499        5636 :     move16();
    4500        5636 :     move16();
    4501        5636 :     move16();
    4502             : 
    4503        5636 :     differential_subframe = 1; /* the differences are taken with respect to previous subframe */
    4504        5636 :     move16();
    4505             : 
    4506             :     /* first subframe */
    4507        5636 :     bits_index = 0;
    4508        5636 :     move16();
    4509        5636 :     IF( sf == 0 )
    4510             :     {
    4511        1862 :         bits_index = bits_index_ism_ratio_fx( nchan_ism );
    4512             : 
    4513        1862 :         nbits = 0;
    4514        1862 :         move16();
    4515       13722 :         FOR( b = 0; b < numCodingBands; b++ )
    4516             :         {
    4517       11860 :             IF( LT_32( masa_to_total_energy_ratio[b], MASA2TOTAL_THR_Q30 ) )
    4518             :             {
    4519       10433 :                 nbits = add( nbits, bits_index );
    4520             :             }
    4521             :         }
    4522             : 
    4523        1862 :         nbits0 = try_differential_fx( numCodingBands, masa_to_total_energy_ratio, ratio_ism_idx, nchan_ism, bits_index, &b_signif );
    4524             : 
    4525        1862 :         test();
    4526        1862 :         IF( LE_16( nbits, nbits0 ) && nbits > 0 )
    4527             :         {
    4528             :             /* independent encoding */
    4529        1140 :             push_next_indice( hMetaData, 1, 1 );
    4530        1140 :             independent_coding_ratio_ism_idx_fx( ratio_ism_idx, masa_to_total_energy_ratio, nchan_ism, numCodingBands, bits_index, hMetaData );
    4531        1140 :             nbits = add( nbits, 1 );
    4532             :         }
    4533             :         ELSE
    4534             :         {
    4535         722 :             IF( nbits > 0 )
    4536             :             {
    4537         666 :                 differential_coding_first_subframe_ivas_fx( hMetaData, masa_to_total_energy_ratio, b_signif, ratio_ism_idx, nchan_ism, numCodingBands, bits_index );
    4538             : 
    4539         666 :                 nbits = add( nbits0, 1 );
    4540             :             }
    4541             :         }
    4542             :     }
    4543             :     ELSE
    4544             :     {
    4545             :         /* not first subframe */
    4546        3774 :         test();
    4547        3774 :         IF( EQ_16( shift_one, 1 ) && EQ_16( nchan_ism, 2 ) )
    4548             :         {
    4549          45 :             nbits = 0;
    4550          45 :             move16();
    4551             :         }
    4552             :         ELSE
    4553             :         {
    4554        3729 :             nbits0 = 0;
    4555        3729 :             nbits1 = 0;
    4556        3729 :             move16();
    4557        3729 :             move16();
    4558             : 
    4559       22266 :             FOR( b = 0; b < numCodingBands; b++ )
    4560             :             {
    4561       18537 :                 IF( LT_32( masa_to_total_energy_ratio[b], MASA2TOTAL_THR_Q30 ) )
    4562             :                 {
    4563       16371 :                     estimate_bits_subband_ism_ratio_fx( ratio_ism_idx[b], ratio_ism_idx_prev_sf[b], nchan_ism, shift_one, idx_sep_obj_local, &nbits00, &nbits11 );
    4564       16371 :                     nbits0 = add( nbits0, nbits00 );
    4565       16371 :                     nbits1 = add( nbits1, nbits11 );
    4566             :                 }
    4567             :             }
    4568        3729 :             IF( LT_16( nbits0, nbits1 ) )
    4569             :             {
    4570        2691 :                 GR_order = 0;
    4571        2691 :                 nbits = nbits0;
    4572        2691 :                 move16();
    4573        2691 :                 move16();
    4574             :             }
    4575             :             ELSE
    4576             :             {
    4577        1038 :                 GR_order = 1;
    4578        1038 :                 nbits = nbits1;
    4579        1038 :                 move16();
    4580        1038 :                 move16();
    4581             :             }
    4582             : 
    4583        3729 :             IF( GT_16( numCodingBands, 1 ) )
    4584             :             {
    4585             :                 /* try the difference from subband to subband; first subband is compared to previous subframe first subband*/
    4586             :                 /* take difference with respect to previous subframe only for first subband */
    4587        3702 :                 nbits0 = 0;
    4588        3702 :                 nbits1 = 0;
    4589        3702 :                 b_signif = 0;
    4590        3702 :                 move16();
    4591        3702 :                 move16();
    4592        3702 :                 move16();
    4593        3963 :                 WHILE( ( b_signif < numCodingBands ) && ( masa_to_total_energy_ratio[b_signif] >= MASA2TOTAL_THR_Q30 ) )
    4594             :                 {
    4595         261 :                     test();
    4596         261 :                     b_signif = add( b_signif, 1 );
    4597             :                 }
    4598             : 
    4599        3702 :                 IF( LT_16( b_signif, numCodingBands ) )
    4600             :                 {
    4601        3690 :                     estimate_bits_subband_ism_ratio_fx( ratio_ism_idx[b_signif], ratio_ism_idx_prev_sf[b_signif], nchan_ism, shift_one, idx_sep_obj_local, &nbits0, &nbits1 );
    4602             : 
    4603        3690 :                     Copy( ratio_ism_idx[b_signif], ratio_ism_idx_ref, nchan_ism );
    4604             : 
    4605       18249 :                     FOR( b = b_signif + 1; b < numCodingBands; b++ )
    4606             :                     {
    4607       14559 :                         IF( LT_32( masa_to_total_energy_ratio[b], MASA2TOTAL_THR_Q30 ) )
    4608             :                         {
    4609       12675 :                             estimate_bits_subband_ism_ratio_fx( ratio_ism_idx[b], ratio_ism_idx_ref, nchan_ism, shift_one, idx_sep_obj_local, &nbits00, &nbits11 );
    4610       12675 :                             nbits0 = add( nbits0, nbits00 );
    4611       12675 :                             nbits1 = add( nbits1, nbits11 );
    4612       12675 :                             Copy( ratio_ism_idx[b], ratio_ism_idx_ref, nchan_ism );
    4613             :                         }
    4614             :                     }
    4615             : 
    4616        3690 :                     IF( LT_16( nbits0, nbits1 ) )
    4617             :                     {
    4618         529 :                         GR_order_sb = 0;
    4619         529 :                         move16();
    4620             :                     }
    4621             :                     ELSE
    4622             :                     {
    4623        3161 :                         GR_order_sb = 1;
    4624        3161 :                         nbits0 = nbits1;
    4625        3161 :                         move16();
    4626        3161 :                         move16();
    4627             :                     }
    4628             : 
    4629        3690 :                     IF( LT_16( nbits0, nbits ) )
    4630             :                     {
    4631         343 :                         differential_subframe = 0;
    4632         343 :                         nbits = nbits0;
    4633         343 :                         GR_order = GR_order_sb;
    4634         343 :                         move16();
    4635         343 :                         move16();
    4636         343 :                         move16();
    4637             :                     }
    4638             : 
    4639        3690 :                     IF( nbits > 0 )
    4640             :                     {
    4641             :                         /* write prediction type */
    4642        3690 :                         push_next_indice( hMetaData, differential_subframe, 1 );
    4643             :                         /* write GR order */
    4644        3690 :                         push_next_indice( hMetaData, GR_order, 1 );
    4645        3690 :                         nbits = add( nbits, 1 ); /* for the prediction type */
    4646        3690 :                         nbits = add( nbits, 1 ); /* for GR_order */
    4647             : 
    4648             :                         /* write data */
    4649        3690 :                         IF( differential_subframe )
    4650             :                         {
    4651       20082 :                             FOR( b = 0; b < numCodingBands; b++ )
    4652             :                             {
    4653       16735 :                                 IF( LT_32( masa_to_total_energy_ratio[b], MASA2TOTAL_THR_Q30 ) )
    4654             :                                 {
    4655             :                                     /* take difference with respect to previous subframe */
    4656       14850 :                                     v_sub_s16_fx( ratio_ism_idx[b], ratio_ism_idx_prev_sf[b], diff_idx, nchan_ism );
    4657             : 
    4658       14850 :                                     IF( shift_one )
    4659             :                                     {
    4660        9289 :                                         remove_sep_obj_fx( diff_idx, nchan_ism, idx_sep_obj_local );
    4661             :                                     }
    4662             : 
    4663       14850 :                                     transform_index_and_GR_encode_ivas_fx( diff_idx, sub( sub( nchan_ism, 1 ), shift_one ), GR_order, hMetaData );
    4664             :                                 }
    4665             :                             }
    4666             :                         }
    4667             :                         ELSE
    4668             :                         {
    4669         343 :                             v_sub_s16_fx( ratio_ism_idx[b_signif], ratio_ism_idx_prev_sf[b_signif], diff_idx, nchan_ism );
    4670             : 
    4671         343 :                             IF( shift_one )
    4672             :                             {
    4673          87 :                                 remove_sep_obj_fx( diff_idx, nchan_ism, idx_sep_obj_local );
    4674             :                             }
    4675             : 
    4676         343 :                             transform_index_and_GR_encode_ivas_fx( diff_idx, sub( sub( nchan_ism, 1 ), shift_one ), GR_order, hMetaData );
    4677             : 
    4678         343 :                             Copy( ratio_ism_idx[b_signif], ratio_ism_idx_ref, sub( nchan_ism, shift_one ) );
    4679             : 
    4680        1709 :                             FOR( b = b_signif + 1; b < numCodingBands; b++ )
    4681             :                             {
    4682             :                                 /* take difference with respect to previous subband */
    4683        1366 :                                 IF( LT_32( masa_to_total_energy_ratio[b], MASA2TOTAL_THR_Q30 ) )
    4684             :                                 {
    4685        1172 :                                     v_sub_s16_fx( ratio_ism_idx[b], ratio_ism_idx_ref, diff_idx, nchan_ism );
    4686             : 
    4687        1172 :                                     IF( shift_one )
    4688             :                                     {
    4689         332 :                                         remove_sep_obj_fx( diff_idx, nchan_ism, idx_sep_obj_local );
    4690             :                                     }
    4691             : 
    4692        1172 :                                     transform_index_and_GR_encode_ivas_fx( diff_idx, sub( sub( nchan_ism, 1 ), shift_one ), GR_order, hMetaData );
    4693             : 
    4694        1172 :                                     Copy( ratio_ism_idx[b], ratio_ism_idx_ref, sub( nchan_ism, shift_one ) );
    4695             :                                 }
    4696             :                             }
    4697             :                         }
    4698             :                     }
    4699             :                 }
    4700             :             }
    4701             :             ELSE
    4702             :             {
    4703             :                 /* only differential wrt previous subframe is possible  */
    4704             :                 /* write the differential to subframe case and no bit to signal the difference type */
    4705             : 
    4706          27 :                 IF( nbits > 0 )
    4707             :                 {
    4708             :                     /* write GR order */
    4709           6 :                     push_next_indice( hMetaData, GR_order, 1 );
    4710           6 :                     nbits = add( nbits, 1 ); /* for GR_order */
    4711             :                     /* write data */
    4712             :                     /* only one subband */
    4713           6 :                     IF( LT_32( masa_to_total_energy_ratio[0], MASA2TOTAL_THR_Q30 ) )
    4714             :                     {
    4715             :                         /* take difference with respect to previous subframe */
    4716           6 :                         v_sub_s16_fx( ratio_ism_idx[0], ratio_ism_idx_prev_sf[0], diff_idx, nchan_ism );
    4717             : 
    4718           6 :                         IF( shift_one )
    4719             :                         {
    4720           0 :                             remove_sep_obj_fx( diff_idx, nchan_ism, idx_sep_obj_local );
    4721             :                         }
    4722             : 
    4723           6 :                         transform_index_and_GR_encode_ivas_fx( diff_idx, sub( sub( nchan_ism, 1 ), shift_one ), GR_order, hMetaData );
    4724             :                     }
    4725             :                 }
    4726             :             }
    4727             :         }
    4728             :     }
    4729             : 
    4730        5636 :     return nbits;
    4731             : }
    4732             : 
    4733             : 
    4734        1862 : static void ivas_encode_masaism_metadata_fx(
    4735             :     MASA_ENCODER_HANDLE hMasa,
    4736             :     IVAS_QMETADATA_HANDLE hQMetaData, /* i/o: q_metadata handle             */
    4737             :     BSTR_ENC_HANDLE hMetaData,        /* i/o: metadata bitstream handle     */
    4738             :     ISM_METADATA_HANDLE hIsmMeta[],   /* i/o: ISM metadata handles          */
    4739             :     const Word16 nchan_ism,           /* i  : number of ISM channels        */
    4740             :     const Word16 low_bitrate_mode,    /* i  : is low bitrate more? 1/0      */
    4741             :     const Word16 omasa_nbands,
    4742             :     const Word16 omasa_nblocks,
    4743             :     const Word16 idx_separated_object,
    4744             :     const Word16 ism_imp )
    4745             : {
    4746             :     Word16 sf, band;
    4747             :     UWord8 numCodingBands;
    4748             :     UWord8 numSf;
    4749             :     Word16 brange[2];
    4750             :     Word64 eneBand;
    4751             :     Word32 eneBand32;
    4752             :     Word16 eneBand_exp, shift;
    4753             :     Word16 bin;
    4754             :     Word16 obj;
    4755             :     Word16 bits_ism[MAX_NUM_OBJECTS];
    4756             :     UWord16 idx_sph;
    4757             :     Word32 theta_q, phi_q;
    4758             :     UWord16 index_theta, index_phi;
    4759             :     Word16 ratio_ism_fx[MASA_FREQUENCY_BANDS][MAX_NUM_OBJECTS];
    4760             :     Word16 ratio_ism_idx[MASA_FREQUENCY_BANDS][MAX_NUM_OBJECTS], ratio_ism_idx_prev_sf[MASA_FREQUENCY_BANDS][MAX_NUM_OBJECTS];
    4761             :     Word32 energy_ism, energy_ism_ind[MAX_NUM_OBJECTS];
    4762             :     Word16 tmp, rotate, energy_ism_e, energy_ism_ind_e[MAX_NUM_OBJECTS];
    4763             :     Word16 n_ism_tmp, i;
    4764        1862 :     OMASA_ENCODER_DATA_HANDLE hOmasaData = hMasa->data.hOmasaData;
    4765        1862 :     OMASA_ENCODER_ENERGY_HANDLE hOmasaEnergy = hOmasaData->hOmasaEnergy;
    4766             :     Word16 nbands_work;
    4767             :     Word32 L_tmp;
    4768             :     Word16 L_tmp_e;
    4769             : 
    4770             :     /* use the values from hQMetaData */
    4771        1862 :     numCodingBands = (UWord8) hQMetaData->q_direction->cfg.nbands;
    4772        1862 :     numSf = (Word8) hQMetaData->q_direction->cfg.nblocks;
    4773        1862 :     nbands_work = s_min( numCodingBands, omasa_nbands );
    4774        1862 :     move16();
    4775        1862 :     move16();
    4776        1862 :     IF( EQ_16( numCodingBands, 1 ) )
    4777             :     {
    4778         120 :         FOR( sf = 0; sf < numSf; sf++ )
    4779             :         {
    4780          96 :             L_tmp = 0;
    4781          96 :             L_tmp_e = 0;
    4782          96 :             move32();
    4783          96 :             move16();
    4784         576 :             FOR( i = 0; i < omasa_nbands; i++ )
    4785             :             {
    4786         480 :                 L_tmp = BASOP_Util_Add_Mant32Exp( L_tmp, L_tmp_e, hOmasaEnergy->energy_ism_fx[sf][i], hOmasaEnergy->energy_ism_fx_e[sf][i], &L_tmp_e );
    4787             :             }
    4788             : 
    4789             :             /* if ( sum_f( hOmasaEnergy->energy_ism[sf], omasa_nbands ) == 0.0f ) */
    4790          96 :             IF( L_tmp == 0 )
    4791             :             {
    4792           0 :                 hOmasaData->masa_to_total_energy_ratio_fx[sf][0] = ONE_IN_Q30; // 1.0f in Q30
    4793           0 :                 move32();
    4794             :             }
    4795             :             ELSE
    4796             :             {
    4797          96 :                 brange[0] = hMasa->data.band_mapping[0];
    4798          96 :                 brange[1] = hMasa->data.band_mapping[omasa_nbands];
    4799          96 :                 eneBand = 0;
    4800          96 :                 move16();
    4801          96 :                 move16();
    4802          96 :                 move64();
    4803        2400 :                 FOR( bin = brange[0]; bin < brange[1]; bin++ )
    4804             :                 {
    4805        2304 :                     eneBand = W_mac_32_32( eneBand, hMasa->data.energy_fx[sf][bin], 1 ); // hMasa->data.q_energy + 1
    4806             :                 }
    4807          96 :                 shift = W_norm( eneBand );
    4808          96 :                 eneBand32 = W_extract_h( W_shl( eneBand, shift ) );
    4809          96 :                 eneBand_exp = sub( 63, add( add( hMasa->data.q_energy, 1 ), shift ) );
    4810             : 
    4811          96 :                 energy_ism = 0;
    4812          96 :                 energy_ism_e = 0;
    4813          96 :                 move32();
    4814          96 :                 move16();
    4815         288 :                 FOR( obj = 0; obj < nchan_ism; obj++ )
    4816             :                 {
    4817         192 :                     energy_ism_ind[obj] = 0;
    4818         192 :                     energy_ism_ind_e[obj] = 0;
    4819         192 :                     move32();
    4820         192 :                     move16();
    4821             :                 }
    4822             : 
    4823         576 :                 FOR( band = 0; band < omasa_nbands; band++ )
    4824             :                 {
    4825         480 :                     energy_ism = BASOP_Util_Add_Mant32Exp( energy_ism, energy_ism_e, hOmasaEnergy->energy_ism_fx[sf][band], hOmasaEnergy->energy_ism_fx_e[sf][band], &energy_ism_e );
    4826             : 
    4827        1440 :                     FOR( obj = 0; obj < nchan_ism; obj++ )
    4828             :                     {
    4829             : 
    4830         960 :                         hOmasaData->masa_to_total_energy_ratio_fx[sf][0] = ONE_IN_Q30; // 1.0f in Q30
    4831         960 :                         move32();
    4832             :                     }
    4833             :                 }
    4834             : 
    4835         288 :                 FOR( obj = 0; obj < nchan_ism; obj++ )
    4836             :                 {
    4837         192 :                     hOmasaEnergy->energy_ratio_ism_fx[sf][0][obj] = BASOP_Util_Divide3232_Scale_newton( energy_ism_ind[obj], energy_ism, &L_tmp_e );
    4838         192 :                     move32();
    4839         192 :                     L_tmp_e = add( L_tmp_e, sub( energy_ism_ind_e[obj], energy_ism_e ) );
    4840             :                     /* Scaling to Q30 */
    4841         192 :                     hOmasaEnergy->energy_ratio_ism_fx[sf][0][obj] = L_shl( hOmasaEnergy->energy_ratio_ism_fx[sf][0][obj], sub( L_tmp_e, 1 ) ); // Q30
    4842         192 :                     move32();
    4843             :                 }
    4844          96 :                 L_tmp = BASOP_Util_Add_Mant32Exp( eneBand32, eneBand_exp, energy_ism, energy_ism_e, &L_tmp_e );
    4845          96 :                 IF( L_tmp != 0 )
    4846             :                 {
    4847          96 :                     hOmasaData->masa_to_total_energy_ratio_fx[sf][0] = BASOP_Util_Divide3232_Scale_newton( eneBand32, L_tmp, &tmp );
    4848          96 :                     move32();
    4849          96 :                     tmp = add( tmp, sub( eneBand_exp, L_tmp_e ) );
    4850             :                     /* Scaling to Q30 */
    4851          96 :                     hOmasaData->masa_to_total_energy_ratio_fx[sf][0] = L_shl( hOmasaData->masa_to_total_energy_ratio_fx[sf][0], sub( tmp, 1 ) ); // Q30
    4852          96 :                     move32();
    4853             :                 }
    4854             :                 ELSE
    4855             :                 {
    4856           0 :                     hOmasaData->masa_to_total_energy_ratio_fx[sf][0] = ONE_IN_Q30;
    4857           0 :                     move32();
    4858             :                 }
    4859             :             }
    4860             :         }
    4861             :     }
    4862        1838 :     ELSE IF( EQ_16( numSf, 1 ) )
    4863             :     {
    4864        6270 :         FOR( band = 0; band < nbands_work; band++ )
    4865             :         {
    4866        5666 :             energy_ism = 0; /* ISM energy for current subband */ // energy_ism_e
    4867        5666 :             energy_ism_e = 0;                                    /* ISM energy for current subband */
    4868        5666 :             move32();
    4869        5666 :             move16();
    4870       24246 :             FOR( obj = 0; obj < nchan_ism; obj++ )
    4871             :             {
    4872       18580 :                 energy_ism_ind[obj] = 0;
    4873       18580 :                 energy_ism_ind_e[obj] = 0;
    4874       18580 :                 move32();
    4875       18580 :                 move16();
    4876             :             }
    4877       14722 :             FOR( sf = 0; sf < omasa_nblocks; sf++ )
    4878             :             {
    4879        9056 :                 energy_ism = BASOP_Util_Add_Mant32Exp( energy_ism, energy_ism_e, hOmasaEnergy->energy_ism_fx[sf][band], hOmasaEnergy->energy_ism_fx_e[sf][band], &energy_ism_e );
    4880             : 
    4881       34416 :                 FOR( obj = 0; obj < nchan_ism; obj++ )
    4882             :                 {
    4883       25360 :                     L_tmp = Mpy_32_32( hOmasaEnergy->energy_ism_fx[sf][band], hOmasaEnergy->energy_ratio_ism_fx[sf][band][obj] ); // Q = (31 - hOmasaEnergy->energy_ism_fx_e[sf][band]) + Q30 - 31
    4884       25360 :                     L_tmp_e = add( 1, hOmasaEnergy->energy_ism_fx_e[sf][band] );
    4885       25360 :                     energy_ism_ind[obj] = BASOP_Util_Add_Mant32Exp( energy_ism_ind[obj], energy_ism_ind_e[obj], L_tmp, L_tmp_e, &energy_ism_ind_e[obj] );
    4886       25360 :                     move32();
    4887             :                 }
    4888             :             }
    4889             : 
    4890        5666 :             IF( energy_ism == 0 )
    4891             :             {
    4892           0 :                 hOmasaData->masa_to_total_energy_ratio_fx[0][band] = ONE_IN_Q30; // 1.0f in Q30
    4893           0 :                 move32();
    4894             :             }
    4895             :             ELSE
    4896             :             {
    4897       24246 :                 FOR( obj = 0; obj < nchan_ism; obj++ )
    4898             :                 {
    4899       18580 :                     hOmasaEnergy->energy_ratio_ism_fx[0][band][obj] = BASOP_Util_Divide3232_Scale_newton( energy_ism_ind[obj], energy_ism, &L_tmp_e );
    4900       18580 :                     move32();
    4901       18580 :                     L_tmp_e = add( L_tmp_e, sub( energy_ism_ind_e[obj], energy_ism_e ) );
    4902             :                     /* Scaling to Q30 */
    4903       18580 :                     hOmasaEnergy->energy_ratio_ism_fx[0][band][obj] = L_shl( hOmasaEnergy->energy_ratio_ism_fx[0][band][obj], sub( L_tmp_e, 1 ) ); // Q30
    4904       18580 :                     move32();
    4905             :                 }
    4906        5666 :                 brange[0] = hMasa->data.band_mapping[band];
    4907        5666 :                 brange[1] = hMasa->data.band_mapping[band + 1];
    4908        5666 :                 move16();
    4909        5666 :                 move16();
    4910             : 
    4911        5666 :                 eneBand = 0;
    4912        5666 :                 move64();
    4913       14722 :                 FOR( sf = 0; sf < omasa_nblocks; sf++ )
    4914             :                 {
    4915       39748 :                     FOR( bin = brange[0]; bin < brange[1]; bin++ )
    4916             :                     {
    4917       30692 :                         eneBand = W_mac_32_32( eneBand, hMasa->data.energy_fx[sf][bin], 1 ); // hMasa->data.q_energy + 1
    4918             :                     }
    4919             :                 }
    4920        5666 :                 shift = W_norm( eneBand );
    4921        5666 :                 eneBand32 = W_extract_h( W_shl( eneBand, shift ) );
    4922        5666 :                 eneBand_exp = sub( 63, add( add( hMasa->data.q_energy, 1 ), shift ) );
    4923             : 
    4924        5666 :                 L_tmp = BASOP_Util_Add_Mant32Exp( eneBand32, eneBand_exp, energy_ism, energy_ism_e, &L_tmp_e );
    4925        5666 :                 IF( L_tmp != 0 )
    4926             :                 {
    4927        5666 :                     hOmasaData->masa_to_total_energy_ratio_fx[0][band] = BASOP_Util_Divide3232_Scale_newton( eneBand32, L_tmp, &tmp );
    4928        5666 :                     move32();
    4929        5666 :                     tmp = add( tmp, sub( eneBand_exp, L_tmp_e ) );
    4930             :                     /* Scaling to Q30 */
    4931        5666 :                     hOmasaData->masa_to_total_energy_ratio_fx[0][band] = L_shl( hOmasaData->masa_to_total_energy_ratio_fx[0][band], sub( tmp, 1 ) ); // Q30
    4932        5666 :                     move32();
    4933             :                 }
    4934             :                 ELSE
    4935             :                 {
    4936           0 :                     hOmasaData->masa_to_total_energy_ratio_fx[0][band] = ONE_IN_Q30;
    4937           0 :                     move32();
    4938             :                 }
    4939             :             }
    4940             :         }
    4941         604 :         FOR( band = nbands_work; band < numCodingBands; band++ )
    4942             :         {
    4943           0 :             hOmasaData->masa_to_total_energy_ratio_fx[0][band] = ONE_IN_Q30;
    4944           0 :             move32();
    4945             : 
    4946           0 :             FOR( obj = 0; obj < nchan_ism; obj++ )
    4947             :             {
    4948           0 :                 hOmasaEnergy->energy_ratio_ism_fx[0][band][obj] = hOmasaEnergy->energy_ratio_ism_fx[0][nbands_work - 1][obj];
    4949           0 :                 move32();
    4950             :             }
    4951             :         }
    4952             :     }
    4953             :     ELSE
    4954             :     {
    4955        6170 :         FOR( sf = 0; sf < numSf; sf++ )
    4956             :         {
    4957       29616 :             FOR( band = 0; band < nbands_work; band++ )
    4958             :             {
    4959       24680 :                 IF( hOmasaEnergy->energy_ism_fx[sf][band] == 0 )
    4960             :                 {
    4961           0 :                     hOmasaData->masa_to_total_energy_ratio_fx[sf][band] = ONE_IN_Q30;
    4962           0 :                     move32();
    4963             :                 }
    4964             :                 ELSE
    4965             :                 {
    4966       24680 :                     brange[0] = hMasa->data.band_mapping[band];
    4967       24680 :                     brange[1] = hMasa->data.band_mapping[band + 1];
    4968       24680 :                     move16();
    4969       24680 :                     move16();
    4970             : 
    4971       24680 :                     eneBand = 0;
    4972       24680 :                     move64();
    4973      141656 :                     FOR( bin = brange[0]; bin < brange[1]; bin++ )
    4974             :                     {
    4975      116976 :                         eneBand = W_mac_32_32( eneBand, hMasa->data.energy_fx[sf][bin], 1 ); // hMasa->data.q_energy + 1
    4976             :                     }
    4977       24680 :                     shift = W_norm( eneBand );
    4978       24680 :                     eneBand32 = W_extract_h( W_shl( eneBand, shift ) );
    4979       24680 :                     eneBand_exp = sub( 63, add( add( hMasa->data.q_energy, 1 ), shift ) );
    4980             : 
    4981       24680 :                     L_tmp = BASOP_Util_Add_Mant32Exp( eneBand32, eneBand_exp, hOmasaEnergy->energy_ism_fx[sf][band], hOmasaEnergy->energy_ism_fx_e[sf][band], &L_tmp_e );
    4982       24680 :                     IF( L_tmp != 0 )
    4983             :                     {
    4984       24680 :                         hOmasaData->masa_to_total_energy_ratio_fx[sf][band] = BASOP_Util_Divide3232_Scale_newton( eneBand32, L_tmp, &tmp );
    4985       24680 :                         move32();
    4986       24680 :                         tmp = add( tmp, sub( eneBand_exp, L_tmp_e ) );
    4987             :                         /* Scaling to Q30 */
    4988       24680 :                         hOmasaData->masa_to_total_energy_ratio_fx[sf][band] = L_shl( hOmasaData->masa_to_total_energy_ratio_fx[sf][band], sub( tmp, 1 ) ); // Q30
    4989       24680 :                         move32();
    4990             :                     }
    4991             :                     ELSE
    4992             :                     {
    4993           0 :                         hOmasaData->masa_to_total_energy_ratio_fx[sf][band] = ONE_IN_Q30;
    4994           0 :                         move32();
    4995             :                     }
    4996             :                 }
    4997             :             }
    4998        4936 :             FOR( band = nbands_work; band < numCodingBands; band++ )
    4999             :             {
    5000           0 :                 hOmasaData->masa_to_total_energy_ratio_fx[sf][band] = ONE_IN_Q30;
    5001           0 :                 move32();
    5002             : 
    5003           0 :                 FOR( obj = 0; obj < nchan_ism; obj++ )
    5004             :                 {
    5005           0 :                     hOmasaEnergy->energy_ratio_ism_fx[sf][band][obj] = hOmasaEnergy->energy_ratio_ism_fx[sf][nbands_work - 1][obj];
    5006           0 :                     move32();
    5007             :                 }
    5008             :             }
    5009             :         }
    5010             :     }
    5011             : 
    5012        1862 :     ivas_omasa_encode_masa_to_total_fx( hOmasaData->masa_to_total_energy_ratio_fx, hMetaData, low_bitrate_mode, numCodingBands, numSf );
    5013             : 
    5014             :     /* quantize ism_ratios */
    5015        1862 :     IF( GT_16( nchan_ism, 1 ) )
    5016             :     {
    5017        1862 :         rotate = 0;
    5018        1862 :         n_ism_tmp = 0;
    5019        1862 :         move16();
    5020        1862 :         move16();
    5021             : 
    5022        7498 :         FOR( sf = 0; sf < numSf; sf++ )
    5023             :         {
    5024       36078 :             FOR( band = 0; band < numCodingBands; band++ )
    5025             :             {
    5026      137614 :                 FOR( obj = 0; obj < nchan_ism; obj++ )
    5027             :                 {
    5028      107172 :                     assert( ( hOmasaEnergy->energy_ratio_ism_fx[sf][band][obj] >= 0 ) && ( hOmasaEnergy->energy_ratio_ism_fx[sf][band][obj] <= ONE_IN_Q30 ) );
    5029      107172 :                     ratio_ism_fx[band][obj] = extract_h( hOmasaEnergy->energy_ratio_ism_fx[sf][band][obj] ); // Q14
    5030      107172 :                     move16();
    5031             :                 }
    5032             : 
    5033             :                 /* Quantize ISM ratios */
    5034       30442 :                 quantize_ratio_ism_vector_ivas_fx( ratio_ism_fx[band], 1 /* Q14 */, ratio_ism_idx[band], nchan_ism, hOmasaData->masa_to_total_energy_ratio_fx[sf][band], idx_separated_object );
    5035             : 
    5036       30442 :                 test();
    5037       30442 :                 test();
    5038       30442 :                 IF( EQ_16( n_ism_tmp, numCodingBands ) && ratio_ism_idx[band][idx_separated_object] != 0 && LT_32( hOmasaData->masa_to_total_energy_ratio_fx[sf][band], MASA2TOTAL_THR_Q30 ) )
    5039             :                 {
    5040          92 :                     i = 0;
    5041          92 :                     move16();
    5042         697 :                     WHILE( ratio_ism_idx[band][idx_separated_object] > 0 )
    5043             :                     {
    5044         605 :                         IF( NE_16( i, idx_separated_object ) )
    5045             :                         {
    5046         410 :                             ratio_ism_idx[band][i] = add( ratio_ism_idx[band][i], 1 );
    5047         410 :                             ratio_ism_idx[band][idx_separated_object] = sub( ratio_ism_idx[band][idx_separated_object], 1 );
    5048         410 :                             move16();
    5049         410 :                             move16();
    5050             :                         }
    5051         605 :                         i = add( i, 1 );
    5052         605 :                         if ( EQ_16( i, nchan_ism ) )
    5053             :                         {
    5054         138 :                             i = 0;
    5055         138 :                             move16();
    5056             :                         }
    5057             :                     }
    5058             :                 }
    5059             : 
    5060             :                 /* reconstructed values */
    5061       30442 :                 reconstruct_ism_ratios_fx( ratio_ism_idx[band], nchan_ism, STEP_PARAM_ISM_POW_RATIO_NBITS_Q31, hOmasaEnergy->q_energy_ratio_ism_fx[sf][band] );
    5062             :             }
    5063             : 
    5064        5636 :             test();
    5065        5636 :             IF( GT_16( nchan_ism, 2 ) && EQ_16( idx_separated_object, sub( nchan_ism, 1 ) ) )
    5066             :             {
    5067             :                 /* rotate components */
    5068         766 :                 rotate = 1;
    5069         766 :                 move16();
    5070        4610 :                 FOR( band = 0; band < numCodingBands; band++ )
    5071             :                 {
    5072        3844 :                     IF( LT_32( hOmasaData->masa_to_total_energy_ratio_fx[sf][band], MASA2TOTAL_THR_Q30 ) )
    5073             :                     {
    5074        3352 :                         tmp = ratio_ism_idx[band][nchan_ism - 1];
    5075        3352 :                         ratio_ism_idx[band][nchan_ism - 1] = ratio_ism_idx[band][0];
    5076        3352 :                         ratio_ism_idx[band][0] = tmp;
    5077        3352 :                         move16();
    5078        3352 :                         move16();
    5079        3352 :                         move16();
    5080        3352 :                         test();
    5081        3352 :                         IF( sf == 0 && tmp == 0 )
    5082             :                         {
    5083         799 :                             n_ism_tmp = add( n_ism_tmp, 1 );
    5084             :                         }
    5085             : 
    5086        3352 :                         if ( EQ_16( n_ism_tmp, numCodingBands ) )
    5087             :                         {
    5088        1753 :                             assert( tmp == 0 );
    5089             :                         }
    5090             :                     }
    5091             :                 }
    5092             :             }
    5093             :             ELSE
    5094             :             {
    5095        4870 :                 IF( GT_16( idx_separated_object, -1 ) )
    5096             :                 {
    5097       31468 :                     FOR( band = 0; band < numCodingBands; band++ )
    5098             :                     {
    5099       26598 :                         IF( LT_32( hOmasaData->masa_to_total_energy_ratio_fx[sf][band], MASA2TOTAL_THR_Q30 ) )
    5100             :                         {
    5101       23497 :                             test();
    5102       23497 :                             IF( ratio_ism_idx[band][idx_separated_object] == 0 && sf == 0 )
    5103             :                             {
    5104        8636 :                                 n_ism_tmp = add( n_ism_tmp, 1 );
    5105             :                             }
    5106             :                         }
    5107             :                     }
    5108             :                 }
    5109             :             }
    5110             : 
    5111             :             /* encode data for current subframe */
    5112        5636 :             test();
    5113        5636 :             IF( sf > 0 && EQ_16( n_ism_tmp, numCodingBands ) )
    5114             :             {
    5115        2082 :                 encode_ratio_ism_subframe_fx( ratio_ism_idx, nchan_ism, numCodingBands, sf, ratio_ism_idx_prev_sf, hMetaData, hOmasaData->masa_to_total_energy_ratio_fx[sf], 1, idx_separated_object );
    5116             :             }
    5117             :             ELSE
    5118             :             {
    5119        3554 :                 encode_ratio_ism_subframe_fx( ratio_ism_idx, nchan_ism, numCodingBands, sf, ratio_ism_idx_prev_sf, hMetaData, hOmasaData->masa_to_total_energy_ratio_fx[sf], 0, idx_separated_object );
    5120             :             }
    5121             : 
    5122             :             /* calculate quantized ISM ratios */
    5123             :             /* save previous subframe indexes */
    5124       36078 :             FOR( band = 0; band < numCodingBands; band++ )
    5125             :             {
    5126       30442 :                 Copy( ratio_ism_idx[band], ratio_ism_idx_prev_sf[band], nchan_ism );
    5127             :             }
    5128             : 
    5129        5636 :             IF( rotate )
    5130             :             {
    5131        4610 :                 FOR( band = 0; band < numCodingBands; band++ )
    5132             :                 {
    5133        3844 :                     IF( LT_32( hOmasaData->masa_to_total_energy_ratio_fx[sf][band], MASA2TOTAL_THR_Q30 ) )
    5134             :                     {
    5135        3352 :                         tmp = ratio_ism_idx[band][nchan_ism - 1];
    5136        3352 :                         ratio_ism_idx[band][nchan_ism - 1] = ratio_ism_idx[band][0];
    5137        3352 :                         ratio_ism_idx[band][0] = tmp;
    5138        3352 :                         move16();
    5139        3352 :                         move16();
    5140        3352 :                         move16();
    5141             :                     }
    5142             :                 }
    5143             :             }
    5144             :         }
    5145             :     }
    5146             : 
    5147        1862 :     calculate_nbits_meta_fx( nchan_ism, hOmasaEnergy->q_energy_ratio_ism_fx, hOmasaData->masa_to_total_energy_ratio_fx, numSf, numCodingBands, bits_ism, idx_separated_object, ism_imp );
    5148             : 
    5149             :     /* quantize directions */
    5150        8142 :     FOR( obj = 0; obj < nchan_ism; obj++ )
    5151             :     {
    5152        6280 :         IF( LT_16( bits_ism[obj], 8 ) )
    5153             :         {
    5154             :             /* check is same as previous */
    5155        2009 :             test();
    5156        2009 :             IF( LT_32( L_abs( L_sub( hIsmMeta[obj]->elevation_fx, hIsmMeta[obj]->q_elevation_old_fx ) ), 41943 /* 0.01f in Q22 */ ) && LT_32( L_abs( L_sub( hIsmMeta[obj]->azimuth_fx, hIsmMeta[obj]->q_azimuth_old_fx ) ), 41943 /* 0.01f in Q22 */ ) )
    5157             :             {
    5158         201 :                 push_next_indice( hMetaData, 1, 1 );
    5159             :                 /* the old stays the same */
    5160             :             }
    5161             :             ELSE
    5162             :             {
    5163        1808 :                 push_next_indice( hMetaData, 0, 1 );
    5164        1808 :                 idx_sph = quantize_direction_fx( hIsmMeta[obj]->elevation_fx, hIsmMeta[obj]->azimuth_fx, bits_ism[obj], &theta_q, &phi_q, &index_theta, &index_phi, MC_LS_SETUP_INVALID );
    5165        1808 :                 push_next_indice( hMetaData, idx_sph, bits_ism[obj] );
    5166        1808 :                 hIsmMeta[obj]->q_elevation_old_fx = hIsmMeta[obj]->elevation_fx;
    5167        1808 :                 hIsmMeta[obj]->q_azimuth_old_fx = hIsmMeta[obj]->azimuth_fx;
    5168        1808 :                 move32();
    5169        1808 :                 move32();
    5170             :             }
    5171             :         }
    5172             :         ELSE
    5173             :         {
    5174        4271 :             idx_sph = quantize_direction_fx( hIsmMeta[obj]->elevation_fx, hIsmMeta[obj]->azimuth_fx, bits_ism[obj], &theta_q, &phi_q, &index_theta, &index_phi, MC_LS_SETUP_INVALID );
    5175        4271 :             push_next_indice( hMetaData, idx_sph, bits_ism[obj] );
    5176        4271 :             hIsmMeta[obj]->q_elevation_old_fx = hIsmMeta[obj]->elevation_fx;
    5177        4271 :             hIsmMeta[obj]->q_azimuth_old_fx = hIsmMeta[obj]->azimuth_fx;
    5178        4271 :             move32();
    5179        4271 :             move32();
    5180             :         }
    5181             :     }
    5182             : 
    5183        1862 :     return;
    5184             : }
    5185             : 
    5186             : 
    5187             : /*-------------------------------------------------------------------*
    5188             :  * ivas_merge_masa_transports()
    5189             :  *
    5190             :  * Merge MASA transport channels
    5191             :  *-------------------------------------------------------------------*/
    5192             : 
    5193        5858 : void ivas_merge_masa_transports_fx(
    5194             :     Word32 data_in_f1_fx[][L_FRAME48k], // Qx
    5195             :     Word32 *data_in_f2_fx[],            // Qx
    5196             :     Word32 *data_out_f_fx[],            // Qx
    5197             :     const Word16 input_frame,
    5198             :     const Word16 num_transport_channels )
    5199             : {
    5200             :     Word16 i, j;
    5201             : 
    5202       17574 :     FOR( i = 0; i < num_transport_channels; i++ )
    5203             :     {
    5204    10588356 :         FOR( j = 0; j < input_frame; j++ )
    5205             :         {
    5206    10576640 :             data_out_f_fx[i][j] = L_add( data_in_f1_fx[i][j], data_in_f2_fx[i][j] );
    5207    10576640 :             move32();
    5208             :         }
    5209             :     }
    5210             : 
    5211        5858 :     return;
    5212             : }

Generated by: LCOV version 1.14