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

Generated by: LCOV version 1.14