LCOV - code coverage report
Current view: top level - lib_enc - ivas_masa_enc.c (source / functions) Hit Total Coverage
Test: Coverage on main -- short test vectors @ 6c9ddc4024a9c0e1ecb8f643f114a84a0e26ec6b Lines: 1271 1414 89.9 %
Date: 2025-05-23 08:37:30 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_prot.h"
      38             : #include "ivas_rom_com.h"
      39             : #include "ivas_stat_enc.h"
      40             : #include "wmc_auto.h"
      41             : #include "prot.h"
      42             : 
      43             : 
      44             : /*-----------------------------------------------------------------------*
      45             :  * Local function prototypes
      46             :  *-----------------------------------------------------------------------*/
      47             : 
      48             : static void combine_freqbands_and_subframes( MASA_ENCODER_HANDLE hMasa );
      49             : 
      50             : static void find_n_largest( const float *input, int16_t *largestIndices, const int16_t numElements, const int16_t numLargest );
      51             : 
      52             : static void move_metadata_to_qmetadata( const MASA_ENCODER_HANDLE hMasa, IVAS_QMETADATA_HANDLE hQMeta );
      53             : 
      54             : static void detect_metadata_composition( const MASA_ENCODER_HANDLE hMasa, uint8_t *joinedSubframes, uint8_t *coherencePresent, uint8_t *isTwoDir );
      55             : 
      56             : static void compensate_energy_ratios( MASA_ENCODER_HANDLE hMasa );
      57             : 
      58             : static int16_t encode_lfe_to_total_energy_ratio( MASA_ENCODER_HANDLE hMasa, BSTR_ENC_HANDLE hMetaData, const int32_t ivas_total_brate );
      59             : 
      60             : static void ivas_encode_masaism_metadata( MASA_ENCODER_HANDLE hMasa, IVAS_QMETADATA_HANDLE hQMetaData, BSTR_ENC_HANDLE hMetaData, ISM_METADATA_HANDLE hIsmMeta[], const int16_t nchan_ism, const int16_t low_bitrate_mode, const int16_t omasa_nbands, const int16_t omasa_nblocks, const int16_t idx_separated_object, const int16_t ism_imp );
      61             : 
      62             : static void reduce_metadata_further( MASA_ENCODER_HANDLE hMasa, IVAS_QMETADATA_HANDLE hqmetadata, const IVAS_FORMAT ivas_format );
      63             : 
      64             : static void average_masa_metadata( MASA_METADATA_FRAME *masaMetadata, float energy[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS], const SPHERICAL_GRID_DATA *sphGrid, const uint8_t useSphGrid );
      65             : 
      66             : static void copy_masa_metadata_subframe( const MASA_METADATA_HANDLE hMetaFrom, const uint8_t sfFrom, MASA_METADATA_HANDLE hMetaTo, const uint8_t sfTo );
      67             : 
      68             : static void copy_masa_metadata( const MASA_METADATA_HANDLE hMetaFrom, MASA_METADATA_HANDLE hMetaTo );
      69             : 
      70             : static uint8_t are_masa_subframes_similar( const MASA_METADATA_HANDLE frame1, const uint8_t sf1_idx, const MASA_METADATA_HANDLE frame2, const uint8_t sf2_idx );
      71             : 
      72             : static void detect_framing_async( MASA_ENCODER_HANDLE hMasa );
      73             : 
      74             : static void masa_metadata_direction_alignment( MASA_ENCODER_HANDLE hMasa );
      75             : 
      76             : 
      77             : /*-----------------------------------------------------------------------*
      78             :  * Local constants
      79             :  *-----------------------------------------------------------------------*/
      80             : 
      81             : #define LOWBITRATE_ONSET_ALPHA 0.2f /* Onset values are for processing in frames */
      82             : #define LOWBITRATE_ONSET_BETA  0.92f
      83             : #define LOWBITRATE_ONSET_GAIN  1.4f
      84             : #define LOWBITRATE_NUM_BANDS   5
      85             : 
      86             : 
      87             : /*-----------------------------------------------------------------------*
      88             :  * ivas_masa_enc_open()
      89             :  *
      90             :  * open and initialize MASA encoder
      91             :  *-----------------------------------------------------------------------*/
      92             : 
      93         416 : ivas_error ivas_masa_enc_open(
      94             :     Encoder_Struct *st_ivas /* i/o: IVAS encoder handle          */
      95             : )
      96             : {
      97             :     int16_t i;
      98             :     MASA_ENCODER_HANDLE hMasa;
      99             :     ENCODER_CONFIG_HANDLE hEncoderConfig;
     100             :     ivas_error error;
     101             :     int32_t ism_total_brate;
     102             : 
     103         416 :     error = IVAS_ERR_OK;
     104             : 
     105         416 :     if ( ( hMasa = (MASA_ENCODER_HANDLE) malloc( sizeof( MASA_ENCODER ) ) ) == NULL )
     106             :     {
     107           0 :         return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for MASA encoder\n" ) );
     108             :     }
     109             : 
     110         416 :     hEncoderConfig = st_ivas->hEncoderConfig;
     111             : 
     112         416 :     generate_gridEq( &( hMasa->data.Sph_Grid16 ) );
     113             : 
     114         416 :     if ( hEncoderConfig->ivas_format == MASA_FORMAT || hEncoderConfig->ivas_format == MASA_ISM_FORMAT )
     115             :     {
     116         119 :         hMasa->data.num_Cldfb_instances = st_ivas->nchan_transport;
     117             :     }
     118             :     else
     119             :     {
     120         297 :         hMasa->data.num_Cldfb_instances = 0;
     121             :     }
     122             : 
     123         623 :     for ( i = 0; i < hMasa->data.num_Cldfb_instances; i++ )
     124             :     {
     125         207 :         if ( ( error = openCldfb( &( hMasa->data.cldfbAnaEnc[i] ), CLDFB_ANALYSIS, hEncoderConfig->input_Fs, CLDFB_PROTOTYPE_5_00MS ) ) != IVAS_ERR_OK )
     126             :         {
     127           0 :             return error;
     128             :         }
     129             :     }
     130             : 
     131         416 :     ism_total_brate = 0;
     132         416 :     if ( hEncoderConfig->ivas_format == MASA_ISM_FORMAT && st_ivas->nSCE > 0 && ( st_ivas->ism_mode == ISM_MASA_MODE_DISC || st_ivas->ism_mode == ISM_MASA_MODE_PARAM_ONE_OBJ || st_ivas->ism_mode == ISM_MASA_MODE_MASA_ONE_OBJ ) )
     133             :     {
     134         104 :         for ( i = 0; i < st_ivas->nSCE; i++ )
     135             :         {
     136          67 :             ism_total_brate += st_ivas->hSCE[i]->element_brate;
     137             :         }
     138             :     }
     139             : 
     140         416 :     ivas_masa_set_elements( 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 );
     141             : 
     142         416 :     mvs2s( DirAC_block_grouping, hMasa->config.block_grouping, MAX_PARAM_SPATIAL_SUBFRAMES + 1 );
     143         416 :     mvs2s( MASA_band_grouping_24, hMasa->config.band_grouping, MASA_FREQUENCY_BANDS + 1 );
     144             : 
     145             : 
     146         416 :     hMasa->data.onset_detector_1 = 0.0f;
     147         416 :     hMasa->data.onset_detector_2 = 0.0f;
     148             : 
     149         416 :     set_zero( hMasa->data.lfeToTotalEnergyRatio, MAX_PARAM_SPATIAL_SUBFRAMES );
     150         416 :     hMasa->data.prevq_lfeToTotalEnergyRatio = 0.0f;
     151         416 :     hMasa->data.prevq_lfeIndex = 0;
     152             : 
     153         416 :     hMasa->data.sync_state.prev_sim_stop = 0;
     154         416 :     hMasa->data.sync_state.prev_offset = 0;
     155         416 :     hMasa->data.sync_state.frame_mode = MASA_FRAME_4SF;
     156             : 
     157         416 :     set_zero( hMasa->data.dir_align_state.previous_azi_dir1, MASA_FREQUENCY_BANDS );
     158         416 :     set_zero( hMasa->data.dir_align_state.previous_ele_dir1, MASA_FREQUENCY_BANDS );
     159         416 :     set_zero( hMasa->data.dir_align_state.previous_azi_dir2, MASA_FREQUENCY_BANDS );
     160         416 :     set_zero( hMasa->data.dir_align_state.previous_ele_dir2, MASA_FREQUENCY_BANDS );
     161             : 
     162         416 :     if ( hEncoderConfig->ivas_format == MASA_ISM_FORMAT )
     163             :     {
     164             :         OMASA_ENCODER_DATA_HANDLE hOmasaData;
     165             : 
     166          44 :         if ( ( hOmasaData = (OMASA_ENCODER_DATA_HANDLE) malloc( sizeof( OMASA_ENCODER_DATA_STATE ) ) ) == NULL )
     167             :         {
     168           0 :             return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for OMASA data encoder\n" ) );
     169             :         }
     170         220 :         for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ )
     171             :         {
     172         176 :             set_f( hOmasaData->masa_to_total_energy_ratio[i], 0, MASA_FREQUENCY_BANDS );
     173             :         }
     174          44 :         hOmasaData->lp_noise_CPE = -1;
     175          44 :         hOmasaData->omasa_stereo_sw_cnt = OMASA_STEREO_SW_CNT_MAX;
     176             : 
     177          44 :         if ( st_ivas->ism_mode != ISM_MASA_MODE_DISC )
     178             :         {
     179          27 :             if ( ( hOmasaData->hOmasaEnergy = (OMASA_ENCODER_ENERGY_HANDLE) malloc( sizeof( OMASA_ENCODER_ENERGY_STATE ) ) ) == NULL )
     180             :             {
     181           0 :                 return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for OMASA energy handle\n" ) );
     182             :             }
     183             :         }
     184             :         else
     185             :         {
     186          17 :             hOmasaData->hOmasaEnergy = NULL;
     187             :         }
     188             : 
     189          44 :         hMasa->data.hOmasaData = hOmasaData;
     190             :     }
     191             :     else
     192             :     {
     193         372 :         hMasa->data.hOmasaData = NULL;
     194             :     }
     195             : 
     196         416 :     st_ivas->hMasa = hMasa;
     197             : 
     198         416 :     return error;
     199             : }
     200             : 
     201             : 
     202             : /*-----------------------------------------------------------------------*
     203             :  * ivas_masa_enc_close()
     204             :  *
     205             :  * close MASA encoder
     206             :  *-----------------------------------------------------------------------*/
     207             : 
     208        1086 : void ivas_masa_enc_close(
     209             :     MASA_ENCODER_HANDLE *hMasa /* i/o: MASA metadata structure      */
     210             : )
     211             : {
     212             :     int16_t i;
     213             : 
     214        1086 :     if ( hMasa == NULL || *hMasa == NULL )
     215             :     {
     216         670 :         return;
     217             :     }
     218             : 
     219         623 :     for ( i = 0; i < ( *hMasa )->data.num_Cldfb_instances; i++ )
     220             :     {
     221         207 :         deleteCldfb( &( ( *hMasa )->data.cldfbAnaEnc[i] ) );
     222             :     }
     223             : 
     224         416 :     if ( ( *hMasa )->data.hOmasaData != NULL )
     225             :     {
     226          44 :         if ( ( *hMasa )->data.hOmasaData->hOmasaEnergy != NULL )
     227             :         {
     228          25 :             free( ( *hMasa )->data.hOmasaData->hOmasaEnergy );
     229          25 :             ( *hMasa )->data.hOmasaData->hOmasaEnergy = NULL;
     230             :         }
     231             : 
     232          44 :         free( ( *hMasa )->data.hOmasaData );
     233          44 :         ( *hMasa )->data.hOmasaData = NULL;
     234             :     }
     235             : 
     236         416 :     free( ( *hMasa ) );
     237         416 :     ( *hMasa ) = NULL;
     238             : 
     239         416 :     return;
     240             : }
     241             : 
     242             : 
     243             : /*-----------------------------------------------------------------------*
     244             :  * ivas_masa_encode()
     245             :  *
     246             :  * main MASA encoder function
     247             :  *-----------------------------------------------------------------------*/
     248             : 
     249       51306 : ivas_error ivas_masa_encode(
     250             :     MASA_ENCODER_HANDLE hMasa,                         /* i/o: MASA encoder structure                  */
     251             :     IVAS_QMETADATA_HANDLE hQMetaData,                  /* i/o: q_metadata handle                       */
     252             :     BSTR_ENC_HANDLE hMetaData,                         /* i/o: Metadata bitstream handle               */
     253             :     int16_t *nb_bits_metadata,                         /* o  : number of metadata bits written         */
     254             :     const int16_t nchan_transport,                     /* i  : number of MASA input/transport channels */
     255             :     const IVAS_FORMAT ivas_format,                     /* i  : IVAS format                             */
     256             :     const int32_t ivas_total_brate,                    /* i  : IVAS total bitrate                      */
     257             :     const int16_t Opt_DTX_ON,                          /* i  : DTX on flag                             */
     258             :     const int16_t element_mode,                        /* i  : element mode                            */
     259             :     const ISM_MODE ism_mode,                           /* i  : ISM format mode                         */
     260             :     const int16_t nchan_ism,                           /* i  : number of ISM channels                  */
     261             :     ISM_METADATA_HANDLE hIsmMetaData[MAX_NUM_OBJECTS], /* i  : ISM metadata handle                     */
     262             :     const int16_t idx_separated_object,                /* i  : index of the separated object           */
     263             :     OMASA_ENC_HANDLE hOMasa,                           /* i  : OMASA encoder handle                    */
     264             :     const int16_t ism_imp,                             /* i  : importance of separated object          */
     265             :     const int16_t flag_omasa_ener_brate                /* i  : less bitrate for objects in OMASA flag  */
     266             : )
     267             : {
     268             :     MASA_DIRECTIONAL_SPATIAL_META *h_orig_metadata;
     269             :     int16_t i, j;
     270             :     int16_t masa_sid_descriptor;
     271             :     int16_t low_bitrate_mode;
     272             :     int32_t masa_total_brate;
     273             :     ivas_error error;
     274             : 
     275       51306 :     masa_sid_descriptor = -1;
     276       51306 :     h_orig_metadata = NULL;
     277       51306 :     low_bitrate_mode = 0;
     278             : 
     279       51306 :     if ( ivas_format == MASA_FORMAT || ivas_format == MASA_ISM_FORMAT )
     280             :     {
     281             :         /* Create the MASA SID descriptor for the metadata and CPE mode, in order to have the SID frame self-contained. */
     282       39626 :         if ( Opt_DTX_ON && hQMetaData != NULL )
     283             :         {
     284        7028 :             if ( nchan_transport == 2 ) /* this is MASA format in CPE only */
     285             :             {
     286        4016 :                 masa_sid_descriptor = 0; /* for IVAS_CPE_DFT */
     287        4016 :                 if ( element_mode == IVAS_CPE_MDCT )
     288             :                 {
     289        1648 :                     masa_sid_descriptor = 1;
     290             :                 }
     291             :             }
     292             :         }
     293             : 
     294             :         /* Validate and compensate ratios as necessary */
     295       39626 :         compensate_energy_ratios( hMasa );
     296             : 
     297       39626 :         if ( Opt_DTX_ON )
     298             :         {
     299        7028 :             if ( ( h_orig_metadata = (MASA_DIRECTIONAL_SPATIAL_META *) malloc( MASA_MAXIMUM_DIRECTIONS * sizeof( MASA_DIRECTIONAL_SPATIAL_META ) ) ) == NULL )
     300             :             {
     301           0 :                 return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for MASA encoder\n" ) );
     302             :             }
     303             : 
     304       21084 :             for ( i = 0; i < MASA_MAXIMUM_DIRECTIONS; i++ )
     305             :             {
     306       70280 :                 for ( j = 0; j < MAX_PARAM_SPATIAL_SUBFRAMES; j++ )
     307             :                 {
     308       56224 :                     mvr2r( hMasa->masaMetadata.directional_meta[i].azimuth[j], h_orig_metadata[i].azimuth[j], MASA_FREQUENCY_BANDS );
     309       56224 :                     mvr2r( hMasa->masaMetadata.directional_meta[i].elevation[j], h_orig_metadata[i].elevation[j], MASA_FREQUENCY_BANDS );
     310       56224 :                     mvr2r( hMasa->masaMetadata.directional_meta[i].energy_ratio[j], h_orig_metadata[i].energy_ratio[j], MASA_FREQUENCY_BANDS );
     311       56224 :                     mvs2s( (int16_t *) ( hMasa->masaMetadata.directional_meta[i].spherical_index[j] ), (int16_t *) ( h_orig_metadata[i].spherical_index[j] ), MASA_FREQUENCY_BANDS );
     312             :                 }
     313             :             }
     314             :         }
     315             : 
     316       39626 :         if ( ( ivas_format == MASA_FORMAT || ivas_format == MASA_ISM_FORMAT ) && ivas_total_brate >= IVAS_384k )
     317             :         {
     318        2636 :             hMasa->config.mergeRatiosOverSubframes = 0;
     319             :         }
     320             : 
     321             :         /* Combine frequency bands and sub-frames */
     322       39626 :         combine_freqbands_and_subframes( hMasa );
     323             :     }
     324             : 
     325       51306 :     if ( hMasa->config.numberOfDirections == 2 && hMasa->config.numTwoDirBands < hMasa->config.numCodingBands && ( ivas_format == MASA_FORMAT || ivas_format == MASA_ISM_FORMAT ) )
     326             :     {
     327        9520 :         if ( ( ivas_format == MASA_ISM_FORMAT && ism_mode != ISM_MODE_NONE && ism_mode != ISM_MASA_MODE_MASA_ONE_OBJ ) || ( ivas_format != MASA_ISM_FORMAT ) )
     328             :         {
     329             :             /* Combine directions */
     330        7322 :             ivas_masa_combine_directions( hMasa );
     331             :         }
     332             : 
     333             :         /* If we joined all bands, then metadata is now one directional. */
     334        9520 :         if ( hMasa->config.numTwoDirBands == 0 )
     335             :         {
     336        4064 :             hMasa->config.numberOfDirections = 1;
     337        4064 :             hMasa->masaMetadata.descriptive_meta.numberOfDirections = 0;
     338        4064 :             hQMetaData->no_directions = 1;
     339             :         }
     340             :     }
     341             : 
     342             :     /* Reset qmetadata bit budget */
     343       51306 :     hQMetaData->metadata_max_bits = hMasa->config.max_metadata_bits;
     344       51306 :     if ( ivas_format == MASA_FORMAT || ivas_format == MASA_ISM_FORMAT )
     345             :     {
     346       39626 :         if ( ivas_format == MASA_ISM_FORMAT && ism_mode != ISM_MODE_NONE )
     347             :         {
     348             :             /* write the number of objects in ISM_MASA format*/
     349        7058 :             push_next_indice( hMetaData, nchan_ism - 1, NO_BITS_MASA_ISM_NO_OBJ );
     350        7058 :             hQMetaData->metadata_max_bits -= NO_BITS_MASA_ISM_NO_OBJ;
     351             : 
     352             :             /* write index of separated object if needed */
     353        7058 :             if ( ism_mode == ISM_MASA_MODE_PARAM_ONE_OBJ && nchan_ism > 1 )
     354             :             {
     355        1862 :                 push_next_indice( hMetaData, idx_separated_object, NO_BITS_MASA_ISM_NO_OBJ );
     356        1862 :                 hQMetaData->metadata_max_bits -= NO_BITS_MASA_ISM_NO_OBJ;
     357             :             }
     358             : 
     359             :             /* write ISM importance flag (one per object) */
     360        7058 :             if ( ism_mode == ISM_MASA_MODE_PARAM_ONE_OBJ )
     361             :             {
     362        1862 :                 push_next_indice( hMetaData, hIsmMetaData[0]->ism_imp, ISM_METADATA_FLAG_BITS );
     363        1862 :                 hQMetaData->metadata_max_bits -= ISM_METADATA_FLAG_BITS;
     364             :             }
     365        5196 :             else if ( ism_mode == ISM_MASA_MODE_MASA_ONE_OBJ )
     366             :             {
     367        2054 :                 if ( hIsmMetaData[0]->ism_md_null_flag )
     368             :                 {
     369             :                     /* signal NULL metadata frame */
     370           0 :                     push_next_indice( hMetaData, 1, ISM_METADATA_MD_FLAG_BITS );
     371           0 :                     hQMetaData->metadata_max_bits -= ISM_METADATA_MD_FLAG_BITS;
     372             : 
     373             :                     /* write the ISM class to ISM_NO_META and again the true ISM class */
     374           0 :                     push_next_indice( hMetaData, ISM_NO_META, ISM_METADATA_FLAG_BITS );
     375           0 :                     hQMetaData->metadata_max_bits -= ISM_METADATA_FLAG_BITS;
     376           0 :                     push_next_indice( hMetaData, hIsmMetaData[0]->ism_imp, ISM_METADATA_FLAG_BITS );
     377           0 :                     hQMetaData->metadata_max_bits -= ISM_METADATA_FLAG_BITS;
     378             :                 }
     379             :                 else
     380             :                 {
     381        2054 :                     push_next_indice( hMetaData, hIsmMetaData[0]->ism_imp, ISM_METADATA_FLAG_BITS );
     382        2054 :                     hQMetaData->metadata_max_bits -= ISM_METADATA_FLAG_BITS;
     383             : 
     384        2054 :                     if ( hIsmMetaData[0]->ism_imp == ISM_NO_META )
     385             :                     {
     386             :                         /* signal low-rate ISM_NO_META frame */
     387           0 :                         push_next_indice( hMetaData, 0, ISM_METADATA_MD_FLAG_BITS );
     388           0 :                         hQMetaData->metadata_max_bits -= ISM_METADATA_MD_FLAG_BITS;
     389             : 
     390             :                         /* signal presence of MD in low-rate ISM_NO_META frame */
     391           0 :                         push_next_indice( hMetaData, hIsmMetaData[0]->ism_md_lowrate_flag, ISM_METADATA_INACTIVE_FLAG_BITS );
     392           0 :                         hQMetaData->metadata_max_bits -= ISM_METADATA_INACTIVE_FLAG_BITS;
     393             :                     }
     394             :                 }
     395             :             }
     396        3142 :             else if ( ism_mode == ISM_MASA_MODE_DISC )
     397             :             {
     398       11602 :                 for ( i = 0; i < nchan_ism; i++ )
     399             :                 {
     400        8460 :                     if ( hIsmMetaData[i]->ism_md_null_flag )
     401             :                     {
     402             :                         /* signal NULL metadata frame */
     403           0 :                         push_next_indice( hMetaData, 1, ISM_METADATA_MD_FLAG_BITS );
     404           0 :                         hQMetaData->metadata_max_bits -= ISM_METADATA_MD_FLAG_BITS;
     405             : 
     406             :                         /* write the ISM class to ISM_NO_META and again the true ISM class */
     407           0 :                         push_next_indice( hMetaData, ISM_NO_META, ISM_METADATA_FLAG_BITS );
     408           0 :                         hQMetaData->metadata_max_bits -= ISM_METADATA_FLAG_BITS;
     409           0 :                         push_next_indice( hMetaData, hIsmMetaData[i]->ism_imp, ISM_METADATA_FLAG_BITS );
     410           0 :                         hQMetaData->metadata_max_bits -= ISM_METADATA_FLAG_BITS;
     411             :                     }
     412             :                     else
     413             :                     {
     414        8460 :                         push_next_indice( hMetaData, hIsmMetaData[i]->ism_imp, ISM_METADATA_FLAG_BITS );
     415        8460 :                         hQMetaData->metadata_max_bits -= ISM_METADATA_FLAG_BITS;
     416             : 
     417        8460 :                         if ( hIsmMetaData[i]->ism_imp == ISM_NO_META )
     418             :                         {
     419             :                             /* signal low-rate ISM_NO_META frame */
     420           0 :                             push_next_indice( hMetaData, 0, ISM_METADATA_MD_FLAG_BITS );
     421           0 :                             hQMetaData->metadata_max_bits -= ISM_METADATA_MD_FLAG_BITS;
     422             : 
     423             :                             /* signal presence of MD in low-rate ISM_NO_META frame */
     424           0 :                             push_next_indice( hMetaData, hIsmMetaData[i]->ism_md_lowrate_flag, ISM_METADATA_INACTIVE_FLAG_BITS );
     425           0 :                             hQMetaData->metadata_max_bits -= ISM_METADATA_INACTIVE_FLAG_BITS;
     426             :                         }
     427             :                     }
     428             :                 }
     429             : 
     430        3142 :                 if ( ivas_total_brate == IVAS_128k && nchan_ism >= 3 )
     431             :                 {
     432         126 :                     push_next_indice( hMetaData, flag_omasa_ener_brate, 1 );
     433         126 :                     hQMetaData->metadata_max_bits -= 1;
     434             :                 }
     435             :             }
     436             :         }
     437             :         else
     438             :         {
     439       32568 :             if ( ivas_format == MASA_ISM_FORMAT && ism_mode == ISM_MODE_NONE )
     440             :             {
     441             :                 /* use the MASA number of transport channels bit to signal if there are 1 or 2 objects */
     442        1942 :                 if ( nchan_ism == 1 || nchan_ism == 2 )
     443             :                 {
     444         474 :                     push_next_indice( hMetaData, nchan_ism - 1, MASA_TRANSP_BITS );
     445             :                 }
     446             :                 else
     447             :                 {
     448             :                     /* for 3 or 4 objects write already the number of MASA directions */
     449        1468 :                     push_next_indice( hMetaData, hQMetaData->no_directions - 1, MASA_TRANSP_BITS );
     450             :                 }
     451             :             }
     452             :             else
     453             :             {
     454             :                 /* write the number of MASA transport channels */
     455       30626 :                 push_next_indice( hMetaData, nchan_transport - 1, MASA_TRANSP_BITS );
     456             :             }
     457       32568 :             hQMetaData->metadata_max_bits -= MASA_TRANSP_BITS;
     458             :         }
     459             : 
     460       39626 :         if ( ivas_format == MASA_ISM_FORMAT && ism_mode == ISM_MODE_NONE )
     461             :         {
     462        1942 :             if ( nchan_ism >= 3 ) /* if 3 or 4 objects */
     463             :             {
     464        1468 :                 push_next_indice( hMetaData, 5 - nchan_ism, MASA_HEADER_BITS );
     465             :             }
     466             :             else
     467             :             {
     468         474 :                 push_next_indice( hMetaData, 3, MASA_HEADER_BITS );
     469             :             }
     470        1942 :             hQMetaData->metadata_max_bits -= MASA_HEADER_BITS;
     471             :         }
     472             :         else
     473             :         {
     474             :             /* the MASA_ISM_FORMAT is not signalled here */
     475             :             /* write reserved bits */
     476       37684 :             push_next_indice( hMetaData, 0, MASA_HEADER_BITS );
     477       37684 :             hQMetaData->metadata_max_bits -= MASA_HEADER_BITS;
     478             :         }
     479       39626 :         if ( !( ivas_format == MASA_ISM_FORMAT && ism_mode == ISM_MODE_NONE && nchan_ism > 2 ) )
     480             :         {
     481             :             /* write number of directions */
     482       38158 :             push_next_indice( hMetaData, hQMetaData->no_directions - 1, 1 );
     483       38158 :             hQMetaData->metadata_max_bits -= 1;
     484             :         }
     485             :         /* write subframe mode */
     486       39626 :         push_next_indice( hMetaData, hQMetaData->q_direction[0].cfg.nblocks == 1 ? 1 : 0, MASA_SUBFRAME_BITS );
     487       39626 :         hQMetaData->metadata_max_bits -= MASA_SUBFRAME_BITS;
     488             :     }
     489             : 
     490       51306 :     if ( ivas_format == MC_FORMAT )
     491             :     {
     492             :         int16_t lfeBitsWritten;
     493       11680 :         lfeBitsWritten = encode_lfe_to_total_energy_ratio( hMasa, hMetaData, ivas_total_brate );
     494       11680 :         hQMetaData->metadata_max_bits -= lfeBitsWritten;
     495             :     }
     496             : 
     497             :     /* Move data from encoder to qmetadata */
     498       51306 :     if ( ivas_format == MASA_FORMAT || ivas_format == MASA_ISM_FORMAT )
     499             :     {
     500       39626 :         move_metadata_to_qmetadata( hMasa, hQMetaData );
     501             :     }
     502             : 
     503       51306 :     if ( hMasa->config.max_metadata_bits < MINIMUM_BIT_BUDGET_NORMAL_META && !hMasa->config.joinedSubframes )
     504             :     {
     505       25011 :         reduce_metadata_further( hMasa, hQMetaData, ivas_format );
     506             : 
     507       25011 :         low_bitrate_mode = ( ivas_total_brate <= 32000 );
     508             : 
     509             :         /* Write low bitrate mode. 1 signals that we have merged through time, 0 signals merge through frequency. */
     510       25011 :         push_next_indice( hMetaData, hQMetaData->q_direction[0].cfg.nblocks == 1 ? 1 : 0, MASA_LOWBITRATE_MODE_BITS );
     511       25011 :         hQMetaData->metadata_max_bits -= MASA_LOWBITRATE_MODE_BITS;
     512             :     }
     513             : 
     514             :     /* Encode MASA+ISM metadata */
     515       51306 :     if ( ivas_format == MASA_ISM_FORMAT && ism_mode == ISM_MASA_MODE_PARAM_ONE_OBJ )
     516             :     {
     517             :         /* encode MASA/ISM energy ratios */
     518        1862 :         ivas_encode_masaism_metadata( hMasa, hQMetaData, hMetaData, hIsmMetaData, nchan_ism, low_bitrate_mode, hOMasa->nCodingBands, hOMasa->nSubframes, idx_separated_object, ism_imp );
     519             :     }
     520             :     else
     521             :     {
     522       49444 :         if ( ivas_format == MASA_ISM_FORMAT )
     523             :         {
     524        7138 :             hMasa->data.hOmasaData->masa_to_total_energy_ratio[0][0] = -1; /* signals NOT to adjust the energy ratios */
     525             :         }
     526             :     }
     527             : 
     528             :     /* Encode metadata */
     529       51306 :     masa_total_brate = ivas_total_brate;
     530       51306 :     if ( ivas_format == MASA_ISM_FORMAT && ism_mode == ISM_MASA_MODE_DISC )
     531             :     {
     532        3142 :         masa_total_brate = calculate_cpe_brate_MASA_ISM( ism_mode, ivas_total_brate, nchan_ism );
     533             :     }
     534             : 
     535       51306 :     if ( masa_total_brate >= IVAS_384k )
     536             :     {
     537        2276 :         if ( masa_total_brate >= IVAS_512k )
     538             :         {
     539         800 :             if ( ( error = ivas_qmetadata_enc_encode_hr_384_512( hMetaData, hQMetaData, 16, 4 ) ) != IVAS_ERR_OK )
     540             :             {
     541           0 :                 return error;
     542             :             }
     543             :         }
     544             :         else
     545             :         {
     546        1476 :             if ( ( error = ivas_qmetadata_enc_encode_hr_384_512( hMetaData, hQMetaData, 11, 3 ) ) != IVAS_ERR_OK )
     547             :             {
     548           0 :                 return error;
     549             :             }
     550             :         }
     551             :     }
     552             :     else
     553             :     {
     554       49030 :         if ( ( error = ivas_qmetadata_enc_encode( hMetaData, hQMetaData, 0 ) ) != IVAS_ERR_OK )
     555             :         {
     556           0 :             return error;
     557             :         }
     558             :     }
     559             : 
     560       51306 :     if ( ivas_format == MASA_ISM_FORMAT && ism_mode == ISM_MASA_MODE_PARAM_ONE_OBJ )
     561             :     {
     562             :         /* Modify spatial metadata based on the MASA-to-total energy ratios */
     563        1862 :         ivas_omasa_modify_masa_energy_ratios( hQMetaData, hMasa->data.hOmasaData->masa_to_total_energy_ratio );
     564             :     }
     565             : 
     566       51306 :     *nb_bits_metadata = hMetaData->nb_bits_tot;
     567             : 
     568       51306 :     if ( ivas_format == MASA_FORMAT && Opt_DTX_ON )
     569             :     {
     570             :         /* save old values */
     571        7028 :         uint8_t numCodingBands = hMasa->config.numCodingBands;
     572        7028 :         uint8_t numTwoDirBands = hMasa->config.numTwoDirBands;
     573        7028 :         int16_t nbands = hQMetaData->q_direction[0].cfg.nbands;
     574        7028 :         uint8_t numberOfDirections = hMasa->config.numberOfDirections;
     575        7028 :         uint8_t numberOfDirectionsMeta = hMasa->masaMetadata.descriptive_meta.numberOfDirections;
     576        7028 :         uint16_t numberOfDirectionsQMetaData = hQMetaData->no_directions;
     577             : 
     578        7028 :         if ( !( hMasa->config.numberOfDirections == 1 && hQMetaData->q_direction->cfg.nbands == 5 ) )
     579             :         {
     580        5937 :             for ( i = 0; i < MASA_MAXIMUM_DIRECTIONS; i++ )
     581             :             {
     582       19790 :                 for ( j = 0; j < MAX_PARAM_SPATIAL_SUBFRAMES; j++ )
     583             :                 {
     584       15832 :                     mvr2r( h_orig_metadata[i].azimuth[j], hMasa->masaMetadata.directional_meta[i].azimuth[j], MASA_FREQUENCY_BANDS );
     585       15832 :                     mvr2r( h_orig_metadata[i].elevation[j], hMasa->masaMetadata.directional_meta[i].elevation[j], MASA_FREQUENCY_BANDS );
     586       15832 :                     mvr2r( h_orig_metadata[i].energy_ratio[j], hMasa->masaMetadata.directional_meta[i].energy_ratio[j], MASA_FREQUENCY_BANDS );
     587             :                 }
     588             :             }
     589             : 
     590             :             /* Force to have 5 bands and 1 direction */
     591        1979 :             hMasa->config.numCodingBands = 5;
     592        1979 :             hMasa->config.numTwoDirBands = 0;
     593        1979 :             combine_freqbands_and_subframes( hMasa );
     594        1979 :             hQMetaData->q_direction[0].cfg.nbands = 5;
     595             : 
     596        1979 :             if ( hMasa->config.numberOfDirections == 2 && hMasa->config.numTwoDirBands < hMasa->config.numCodingBands )
     597             :             {
     598             :                 /* Combine directions */
     599           0 :                 ivas_masa_combine_directions( hMasa );
     600             : 
     601             :                 /* If we joined all bands, then metadata is now one directional. */
     602           0 :                 if ( hMasa->config.numTwoDirBands == 0 )
     603             :                 {
     604           0 :                     hMasa->config.numberOfDirections = 1;
     605           0 :                     hMasa->masaMetadata.descriptive_meta.numberOfDirections = 0;
     606           0 :                     hQMetaData->no_directions = 1;
     607             :                 }
     608             :             }
     609             : 
     610        1979 :             move_metadata_to_qmetadata( hMasa, hQMetaData );
     611             : 
     612       11874 :             for ( j = hQMetaData->q_direction[0].cfg.start_band; j < hQMetaData->q_direction[0].cfg.nbands; ++j )
     613             :             {
     614        9895 :                 hQMetaData->q_direction[0].band_data[j].energy_ratio_index[0] = masa_sq( 1.0f - hQMetaData->q_direction[0].band_data[j].energy_ratio[0], diffuseness_thresholds, DIRAC_DIFFUSE_LEVELS );
     615             :             }
     616             :         }
     617             : 
     618        7028 :         free( h_orig_metadata );
     619             : 
     620        7028 :         ivas_qmetadata_enc_sid_encode( hMetaData, hQMetaData, masa_sid_descriptor, 0, ivas_format );
     621             : 
     622             :         /* restore old values */
     623        7028 :         hMasa->config.numCodingBands = numCodingBands;
     624        7028 :         hMasa->config.numTwoDirBands = numTwoDirBands;
     625        7028 :         hQMetaData->q_direction[0].cfg.nbands = nbands;
     626        7028 :         hMasa->config.numberOfDirections = numberOfDirections;
     627        7028 :         hMasa->masaMetadata.descriptive_meta.numberOfDirections = numberOfDirectionsMeta;
     628        7028 :         hQMetaData->no_directions = numberOfDirectionsQMetaData;
     629             :     }
     630             : 
     631       51306 :     return IVAS_ERR_OK;
     632             : }
     633             : 
     634             : 
     635             : /*-----------------------------------------------------------------------*
     636             :  * ivas_masa_estimate_energy()
     637             :  *
     638             :  *
     639             :  *-----------------------------------------------------------------------*/
     640             : 
     641       39626 : void ivas_masa_estimate_energy(
     642             :     MASA_ENCODER_HANDLE hMasa,    /* i/o: MASA encoder structure                    */
     643             :     float *data_f[],              /* i  : Input audio channels                      */
     644             :     const int16_t input_frame,    /* i  : frame length                              */
     645             :     const int16_t nchan_transport /* i  : number of MASA input/transport channels   */
     646             : )
     647             : {
     648             :     float Input_RealBuffer[MASA_MAX_TRANSPORT_CHANNELS][CLDFB_NO_CHANNELS_MAX];
     649             :     float Input_ImagBuffer[MASA_MAX_TRANSPORT_CHANNELS][CLDFB_NO_CHANNELS_MAX];
     650             :     int16_t block_m_idx, band_m_idx;
     651             :     int16_t mrange[2], brange[2];
     652             :     int16_t i, j, ts, l_ts, maxBin;
     653             : 
     654       39626 :     maxBin = (int16_t) ( (float) CLDFB_NO_CHANNELS_MAX * (float) input_frame / L_FRAME48k + 0.5f );
     655             : 
     656       39626 :     l_ts = input_frame / CLDFB_NO_COL_MAX;
     657             : 
     658      198130 :     for ( block_m_idx = 0; block_m_idx < MAX_PARAM_SPATIAL_SUBFRAMES; block_m_idx++ )
     659             :     {
     660      158504 :         mrange[0] = hMasa->config.block_grouping[block_m_idx];
     661      158504 :         mrange[1] = hMasa->config.block_grouping[block_m_idx + 1];
     662             : 
     663      158504 :         set_zero( hMasa->data.energy[block_m_idx], MASA_FREQUENCY_BANDS );
     664             : 
     665      792520 :         for ( ts = mrange[0]; ts < mrange[1]; ts++ )
     666             :         {
     667     1676608 :             for ( i = 0; i < nchan_transport; i++ )
     668             :             {
     669     1042592 :                 cldfbAnalysis_ts( &( data_f[i][l_ts * ts] ), Input_RealBuffer[i], Input_ImagBuffer[i], l_ts, hMasa->data.cldfbAnaEnc[i] );
     670             :             }
     671             : 
     672    15850400 :             for ( band_m_idx = 0; band_m_idx < MASA_FREQUENCY_BANDS; band_m_idx++ )
     673             :             {
     674    15216384 :                 brange[0] = hMasa->config.band_grouping[band_m_idx];
     675    15216384 :                 brange[1] = hMasa->config.band_grouping[band_m_idx + 1];
     676             : 
     677    40238592 :                 for ( i = 0; i < nchan_transport; i++ )
     678             :                 {
     679    25022208 :                     if ( brange[0] > maxBin )
     680             :                     {
     681       72000 :                         hMasa->data.energy[block_m_idx][band_m_idx] = 0;
     682       72000 :                         continue;
     683             :                     }
     684    24950208 :                     else if ( brange[1] >= maxBin )
     685             :                     {
     686     1116992 :                         brange[1] = maxBin;
     687             :                     }
     688             : 
     689    85537728 :                     for ( j = brange[0]; j < brange[1]; j++ )
     690             :                     {
     691    60587520 :                         hMasa->data.energy[block_m_idx][band_m_idx] += Input_RealBuffer[i][j] * Input_RealBuffer[i][j] + Input_ImagBuffer[i][j] * Input_ImagBuffer[i][j];
     692             :                     }
     693             :                 }
     694             :             }
     695             :         }
     696             :     }
     697             : 
     698       39626 :     return;
     699             : }
     700             : 
     701             : 
     702             : /*-----------------------------------------------------------------------*
     703             :  * ivas_masa_enc_config()
     704             :  *
     705             :  * Frame-by-frame configuration of MASA encoder
     706             :  *-----------------------------------------------------------------------*/
     707             : 
     708       39923 : ivas_error ivas_masa_enc_config(
     709             :     Encoder_Struct *st_ivas /* i/o: IVAS encoder structure */
     710             : )
     711             : {
     712             :     int16_t i;
     713             :     MASA_ENCODER_HANDLE hMasa;
     714             :     IVAS_QMETADATA_HANDLE hQMetaData;
     715             :     IVAS_FORMAT ivas_format;
     716             :     uint8_t joinedSubframes;
     717             :     uint8_t coherencePresent;
     718             :     uint8_t isActualTwoDir; /* Flag to tell that when there are two directions present in metadata, they both contain meaningful information. */
     719             :     int32_t ivas_total_brate;
     720             :     uint8_t maxBand;
     721             :     int16_t maxBin, sf;
     722             :     ivas_error error;
     723             :     int32_t ism_total_brate;
     724             :     int32_t masa_total_brate;
     725             : 
     726       39923 :     error = IVAS_ERR_OK;
     727             : 
     728       39923 :     hMasa = st_ivas->hMasa;
     729       39923 :     hQMetaData = st_ivas->hQMetaData;
     730       39923 :     ivas_format = st_ivas->hEncoderConfig->ivas_format;
     731       39923 :     ivas_total_brate = st_ivas->hEncoderConfig->ivas_total_brate;
     732             : 
     733       39923 :     ism_total_brate = 0;
     734       39923 :     if ( ivas_format == MASA_ISM_FORMAT && st_ivas->nSCE > 0 && ( st_ivas->ism_mode == ISM_MASA_MODE_DISC || st_ivas->ism_mode == ISM_MASA_MODE_PARAM_ONE_OBJ || st_ivas->ism_mode == ISM_MASA_MODE_MASA_ONE_OBJ ) )
     735             :     {
     736       19434 :         for ( i = 0; i < st_ivas->nSCE; i++ )
     737             :         {
     738       12376 :             ism_total_brate += st_ivas->hSCE[i]->element_brate;
     739             :         }
     740             :     }
     741             : 
     742       39923 :     ivas_masa_set_elements( 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 );
     743             : 
     744       39923 :     hQMetaData->is_masa_ivas_format = 1;
     745             : 
     746       39923 :     if ( ivas_format == MASA_FORMAT || ivas_format == MASA_ISM_FORMAT )
     747             :     {
     748       39626 :         masa_metadata_direction_alignment( hMasa );
     749             : 
     750       39626 :         detect_framing_async( hMasa ); /* detect the offset, set 1sf/4sf mode based on this. potentially also shift the metadata using a history buffer */
     751             : 
     752       39626 :         if ( hMasa->data.sync_state.frame_mode == MASA_FRAME_1SF && hMasa->data.sync_state.prev_offset != 0 )
     753             :         {
     754             :             /* average over sub-frames */
     755           0 :             average_masa_metadata( &( hMasa->masaMetadata ), hMasa->data.energy, &( hMasa->data.Sph_Grid16 ), ivas_total_brate == IVAS_512k ? TRUE : FALSE );
     756             :         }
     757             : 
     758             :         /* Inspect metadata for parameter changes that affect coding. */
     759       39626 :         detect_metadata_composition( hMasa, &joinedSubframes, &coherencePresent, &isActualTwoDir );
     760       39626 :         hMasa->config.joinedSubframes = joinedSubframes;
     761       39626 :         hMasa->config.coherencePresent = coherencePresent;
     762       39626 :         hMasa->config.numberOfDirections = ( hMasa->masaMetadata.descriptive_meta.numberOfDirections + 1 ) == 2 && isActualTwoDir ? 2 : 1;
     763             :     }
     764         297 :     else if ( ivas_format == MC_FORMAT && st_ivas->mc_mode == MC_MODE_MCMASA )
     765             :     {
     766             :         /* For McMASA, these are set only once as this function is called only once. */
     767         297 :         hMasa->config.joinedSubframes = 0;
     768         297 :         hMasa->config.numberOfDirections = 1;
     769             :     }
     770             : 
     771       39923 :     if ( ivas_format == MASA_ISM_FORMAT )
     772             :     {
     773        9000 :         ivas_masa_set_coding_config( &( hMasa->config ), hMasa->data.band_mapping, st_ivas->hCPE[0]->element_brate, st_ivas->nchan_transport, MC_MODE_NONE );
     774             :     }
     775             :     else
     776             :     {
     777       30923 :         ivas_masa_set_coding_config( &( hMasa->config ), hMasa->data.band_mapping, ivas_total_brate, st_ivas->nchan_transport, ( ivas_format == MC_FORMAT && st_ivas->mc_mode == MC_MODE_MCMASA ) );
     778             :     }
     779             : 
     780             :     /* Setup importance weights for two-direction band selection. */
     781       39923 :     if ( hMasa->config.numberOfDirections == 2 )
     782             :     {
     783        9900 :         set_f( hMasa->data.importanceWeight, 1.0f, hMasa->config.numCodingBands );
     784             : 
     785        9900 :         if ( hMasa->config.numCodingBands == 5 )
     786             :         {
     787        6670 :             hMasa->data.importanceWeight[4] = 0.7f;
     788             :         }
     789        3230 :         else if ( hMasa->config.numCodingBands == 8 )
     790             :         {
     791         354 :             hMasa->data.importanceWeight[7] = 0.7f;
     792             :         }
     793        2876 :         else if ( hMasa->config.numCodingBands == 10 )
     794             :         {
     795           0 :             hMasa->data.importanceWeight[8] = 0.7f;
     796           0 :             hMasa->data.importanceWeight[9] = 0.1f;
     797             :         }
     798        2876 :         else if ( hMasa->config.numCodingBands == 12 )
     799             :         {
     800         794 :             hMasa->data.importanceWeight[10] = 0.7f;
     801         794 :             hMasa->data.importanceWeight[11] = 0.1f;
     802             :         }
     803        2082 :         else if ( hMasa->config.numCodingBands == 18 )
     804             :         {
     805         798 :             hMasa->data.importanceWeight[14] = 0.8f;
     806         798 :             hMasa->data.importanceWeight[15] = 0.5f;
     807         798 :             hMasa->data.importanceWeight[16] = 0.2f;
     808         798 :             hMasa->data.importanceWeight[17] = 0.0f;
     809             :         }
     810        1284 :         else if ( hMasa->config.numCodingBands == 24 )
     811             :         {
     812        1284 :             hMasa->data.importanceWeight[20] = 0.8f;
     813        1284 :             hMasa->data.importanceWeight[21] = 0.5f;
     814        1284 :             hMasa->data.importanceWeight[22] = 0.2f;
     815        1284 :             hMasa->data.importanceWeight[23] = 0.0f;
     816             :         }
     817             : 
     818        9900 :         if ( hMasa->config.numTwoDirBands == hMasa->config.numCodingBands )
     819             :         {
     820         380 :             set_c( (int8_t *) hMasa->data.twoDirBands, 1, hMasa->config.numCodingBands );
     821             :         }
     822             :     }
     823             :     else
     824             :     {
     825       30023 :         set_c( (int8_t *) hMasa->data.twoDirBands, 0, hMasa->config.numCodingBands );
     826             :     }
     827             : 
     828             :     /* Set qmeta to correct values */
     829       39923 :     if ( ( error = ivas_qmetadata_allocate_memory( hQMetaData, hMasa->config.numCodingBands, hMasa->config.numberOfDirections == 2 && hMasa->config.numTwoDirBands != 0 ? 2 : 1, hMasa->config.useCoherence ) ) != IVAS_ERR_OK )
     830             :     {
     831           0 :         return error;
     832             :     }
     833             : 
     834       85682 :     for ( i = 0; i < hQMetaData->no_directions; i++ )
     835             :     {
     836       45759 :         hQMetaData->q_direction[i].cfg.nbands = hMasa->config.numCodingBands;
     837       45759 :         hQMetaData->q_direction[i].cfg.nblocks = hMasa->config.joinedSubframes == TRUE ? 1 : MAX_PARAM_SPATIAL_SUBFRAMES;
     838             : 
     839       45759 :         if ( ivas_format == MC_FORMAT )
     840             :         {
     841         297 :             hQMetaData->q_direction[i].cfg.mc_ls_setup = st_ivas->hEncoderConfig->mc_input_setup;
     842             :         }
     843             :         else
     844             :         {
     845             :             /* Just to be sure that this default value is maintained */
     846       45462 :             hQMetaData->q_direction[i].cfg.mc_ls_setup = MC_LS_SETUP_INVALID;
     847             :         }
     848             :     }
     849             : 
     850       39923 :     hQMetaData->all_coherence_zero = !hMasa->config.coherencePresent;
     851             : 
     852       39923 :     ivas_set_qmetadata_maxbit_req( hQMetaData, ivas_format );
     853             : 
     854             :     /* Find maximum band usable */
     855       39923 :     maxBin = (int16_t) ( st_ivas->hEncoderConfig->input_Fs * INV_CLDFB_BANDWIDTH );
     856       39923 :     maxBand = 0;
     857     1033308 :     while ( maxBand <= MASA_FREQUENCY_BANDS && MASA_band_grouping_24[maxBand] <= maxBin )
     858             :     {
     859      993385 :         maxBand++;
     860             :     }
     861       39923 :     maxBand--;
     862             : 
     863       39923 :     st_ivas->hQMetaData->q_direction->cfg.inactiveBands = 0;
     864       39923 :     masa_total_brate = ivas_total_brate;
     865       39923 :     if ( ivas_format == MASA_ISM_FORMAT && st_ivas->ism_mode == ISM_MASA_MODE_DISC )
     866             :     {
     867        3142 :         masa_total_brate = calculate_cpe_brate_MASA_ISM( st_ivas->ism_mode, ivas_total_brate, st_ivas->hEncoderConfig->nchan_ism );
     868             :     }
     869       39923 :     if ( masa_total_brate >= IVAS_384k && ( ivas_format == MASA_FORMAT || ivas_format == MASA_ISM_FORMAT ) )
     870             :     {
     871             :         int16_t continueLoop;
     872        2276 :         continueLoop = 1;
     873        4552 :         while ( maxBand > 5 && continueLoop )
     874             :         {
     875        2276 :             for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
     876             :             {
     877        2276 :                 if ( hMasa->data.energy[sf][maxBand - 1] > 100000 )
     878             :                 {
     879        2276 :                     continueLoop = 0;
     880        2276 :                     break;
     881             :                 }
     882             :             }
     883        2276 :             if ( continueLoop )
     884             :             {
     885           0 :                 maxBand--;
     886             :             }
     887             :         }
     888             : 
     889        2276 :         if ( maxBand < MASA_MAXIMUM_CODING_SUBBANDS )
     890             :         {
     891         300 :             st_ivas->hQMetaData->q_direction->cfg.inactiveBands = MASA_MAXIMUM_CODING_SUBBANDS - maxBand;
     892             :         }
     893             :         else
     894             :         {
     895        1976 :             st_ivas->hQMetaData->q_direction->cfg.inactiveBands = 0;
     896             :         }
     897             :     }
     898             : 
     899       39923 :     masa_sample_rate_band_correction( &( hMasa->config ), hMasa->data.band_mapping, hQMetaData, maxBand, masa_total_brate >= IVAS_384k, NULL );
     900             : 
     901       39923 :     if ( hMasa->config.numTwoDirBands >= hMasa->config.numCodingBands )
     902             :     {
     903         380 :         hMasa->config.numTwoDirBands = hMasa->config.numCodingBands;
     904         380 :         set_c( (int8_t *) hMasa->data.twoDirBands, 1, hMasa->config.numCodingBands );
     905             :     }
     906             : 
     907             :     /* Transmit stereo signals using a mono downmix at lowest bitrates */
     908       39923 :     if ( ( ivas_format == MASA_FORMAT || ivas_format == MASA_ISM_FORMAT ) && st_ivas->nCPE == 1 && st_ivas->hCPE[0]->hStereoDft != NULL && st_ivas->hCPE[0]->hStereoDft->hConfig != NULL )
     909             :     {
     910       11938 :         st_ivas->hCPE[0]->hStereoDft->hConfig->force_mono_transmission = ( ivas_total_brate - ism_total_brate < MASA_STEREO_MIN_BITRATE ) ? 1 : 0;
     911             :     }
     912             : 
     913       39923 :     if ( ivas_format == MASA_ISM_FORMAT && ( st_ivas->ism_mode == ISM_MASA_MODE_MASA_ONE_OBJ || st_ivas->ism_mode == ISM_MASA_MODE_PARAM_ONE_OBJ || st_ivas->ism_mode == ISM_MASA_MODE_DISC ) )
     914             :     {
     915        7058 :         if ( st_ivas->hCPE[0]->element_mode == IVAS_CPE_DFT || st_ivas->hMasa->data.hOmasaData->omasa_stereo_sw_cnt < OMASA_STEREO_SW_CNT_MAX )
     916             :         {
     917        3051 :             st_ivas->hMasa->data.hOmasaData->lp_noise_CPE = st_ivas->hCPE[0]->hCoreCoder[0]->lp_noise;
     918             :         }
     919             :         else
     920             :         {
     921        4007 :             st_ivas->hMasa->data.hOmasaData->lp_noise_CPE = ( st_ivas->hCPE[0]->hCoreCoder[0]->lp_noise + st_ivas->hCPE[0]->hCoreCoder[1]->lp_noise ) / CPE_CHANNELS;
     922             :         }
     923             :     }
     924             : 
     925       39923 :     return error;
     926             : }
     927             : 
     928             : 
     929             : /*-----------------------------------------------------------------------*
     930             :  * ivas_masa_surrcoh_signicant()
     931             :  *
     932             :  * Determine if surrounding coherence is significant in this frame and should be encoded
     933             :  *-----------------------------------------------------------------------*/
     934             : 
     935        2589 : uint8_t ivas_masa_surrcoh_signicant(
     936             :     float surroundingCoherence[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS],   /* i  : Surround coherence                      */
     937             :     float diffuse_to_total_ratio[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS], /* i  : Diffuse to total ratio                  */
     938             :     const int16_t nSubFrames,                                                        /* i  : Number of sub frames                    */
     939             :     const int16_t nBands                                                             /* i  : Number of frequency bands               */
     940             : )
     941             : {
     942             :     float significanceMeasure1, significanceMeasure2, significanceMeasure;
     943             :     float surrCohToTotal, surrCohToTotalSum, surrCohToTotalTimesDiffSum, diffSum;
     944             :     int16_t sf, band;
     945        2589 :     float surrCohSignificanceCoef = 0.4f;
     946        2589 :     float threshold = 0.1f;
     947             : 
     948        5802 :     for ( sf = 0; sf < nSubFrames; sf++ )
     949             :     {
     950        3630 :         surrCohToTotalSum = 0.0f;
     951        3630 :         surrCohToTotalTimesDiffSum = 0.0f;
     952        3630 :         diffSum = 0.0f;
     953       75702 :         for ( band = 0; band < nBands; band++ )
     954             :         {
     955       72072 :             surrCohToTotal = diffuse_to_total_ratio[sf][band] * surroundingCoherence[sf][band];
     956       72072 :             surrCohToTotalSum += surrCohToTotal;
     957       72072 :             surrCohToTotalTimesDiffSum += diffuse_to_total_ratio[sf][band] * surrCohToTotal;
     958       72072 :             diffSum += diffuse_to_total_ratio[sf][band];
     959             :         }
     960        3630 :         significanceMeasure1 = surrCohToTotalSum / (float) nBands;
     961        3630 :         significanceMeasure2 = surrCohSignificanceCoef * surrCohToTotalTimesDiffSum / ( diffSum + EPSILON );
     962        3630 :         significanceMeasure = max( significanceMeasure1, significanceMeasure2 );
     963             : 
     964        3630 :         if ( significanceMeasure > threshold )
     965             :         {
     966         417 :             return 1; /* Surrounding coherence was significant in at least one subframe */
     967             :         }
     968             :     }
     969             : 
     970        2172 :     return 0; /* Surrounding coherence was not significant in any subframe */
     971             : }
     972             : 
     973             : 
     974             : /*-----------------------------------------------------------------------*
     975             :  * Local functions
     976             :  *-----------------------------------------------------------------------*/
     977             : 
     978       41605 : static void combine_freqbands_and_subframes(
     979             :     MASA_ENCODER_HANDLE hMasa )
     980             : {
     981             :     int16_t i, j, k, m;
     982             :     float aziRad, eleRad;
     983             :     float x[MASA_MAXIMUM_DIRECTIONS][MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
     984             :     float y[MASA_MAXIMUM_DIRECTIONS][MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
     985             :     float z[MASA_MAXIMUM_DIRECTIONS][MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
     986             :     float vecLen;
     987             :     float xSum, ySum, zSum;
     988             :     float energySum;
     989             :     float spreadCohSum;
     990             :     float surrCohSum;
     991             :     float energyRatioSum;
     992             :     float surrCohTemp;
     993             :     float energyRatioTemp;
     994             :     float energy[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
     995             :     int16_t brange[2];
     996             :     uint8_t numCodingBands;
     997             :     uint8_t numSf;
     998             :     uint8_t numDirections;
     999             :     MASA_METADATA_HANDLE hMeta;
    1000             :     uint8_t mergeRatiosOverSubframes;
    1001             :     uint8_t computeCoherence;
    1002             : 
    1003       41605 :     numCodingBands = hMasa->config.numCodingBands;
    1004       41605 :     numDirections = hMasa->config.numberOfDirections;
    1005       41605 :     numSf = hMasa->config.joinedSubframes == TRUE ? 1 : MAX_PARAM_SPATIAL_SUBFRAMES;
    1006       41605 :     hMeta = &( hMasa->masaMetadata );
    1007             : 
    1008       41605 :     mergeRatiosOverSubframes = hMasa->config.mergeRatiosOverSubframes;
    1009       41605 :     computeCoherence = hMasa->config.useCoherence && hMasa->config.coherencePresent;
    1010             : 
    1011             :     /* If metadata subframes are joined then we need all energy to be in the first subframe for combining.
    1012             :      * This optimizes following computations a bit.
    1013             :      * Note: If energy is used elsewhere, then this can cause problems and local energy should be used. */
    1014       41605 :     if ( numSf == 1 )
    1015             :     {
    1016       22200 :         for ( j = 1; j < MAX_PARAM_SPATIAL_SUBFRAMES; j++ )
    1017             :         {
    1018      416250 :             for ( k = 0; k < MASA_FREQUENCY_BANDS; k++ )
    1019             :             {
    1020      399600 :                 hMasa->data.energy[0][k] += hMasa->data.energy[j][k];
    1021             :             }
    1022             :         }
    1023             :     }
    1024             : 
    1025       41605 :     if ( numCodingBands <= MAX_REDUCED_NBANDS )
    1026             :     {
    1027             :         /* reduce metadata *frequency* resolution. time resolution is not touched */
    1028       84542 :         for ( i = 0; i < numDirections; i++ )
    1029             :         {
    1030      212303 :             for ( j = 0; j < numSf; j++ ) /* NB: for numSf==1, operates only on first sub-frame */
    1031             :             {
    1032     4143100 :                 for ( k = 0; k < MASA_FREQUENCY_BANDS; k++ )
    1033             :                 {
    1034     3977376 :                     aziRad = hMeta->directional_meta[i].azimuth[j][k] / 180.0f * EVS_PI;
    1035     3977376 :                     eleRad = hMeta->directional_meta[i].elevation[j][k] / 180.0f * EVS_PI;
    1036     3977376 :                     vecLen = hMeta->directional_meta[i].energy_ratio[j][k] * hMasa->data.energy[j][k];
    1037             : 
    1038     3977376 :                     x[i][j][k] = cosf( aziRad ) * cosf( eleRad ) * vecLen;
    1039     3977376 :                     y[i][j][k] = sinf( aziRad ) * cosf( eleRad ) * vecLen;
    1040     3977376 :                     z[i][j][k] = sinf( eleRad ) * vecLen;
    1041             :                 }
    1042             :             }
    1043             :         }
    1044             : 
    1045       84542 :         for ( i = 0; i < numDirections; i++ )
    1046             :         {
    1047      212303 :             for ( j = 0; j < numSf; j++ )
    1048             :             {
    1049     1155432 :                 for ( k = 0; k < numCodingBands; k++ )
    1050             :                 {
    1051      989708 :                     brange[0] = hMasa->data.band_mapping[k];
    1052      989708 :                     brange[1] = hMasa->data.band_mapping[k + 1];
    1053             : 
    1054      989708 :                     xSum = 0.0f;
    1055      989708 :                     ySum = 0.0f;
    1056      989708 :                     zSum = 0.0f;
    1057      989708 :                     energySum = 0.0f;
    1058      989708 :                     spreadCohSum = 0.0f;
    1059             : 
    1060     4860002 :                     for ( m = brange[0]; m < brange[1]; m++ )
    1061             :                     {
    1062     3870294 :                         xSum += x[i][j][m];
    1063     3870294 :                         ySum += y[i][j][m];
    1064     3870294 :                         zSum += z[i][j][m];
    1065     3870294 :                         energySum += hMasa->data.energy[j][m];
    1066             :                     }
    1067             : 
    1068      989708 :                     aziRad = atan2f( ySum, xSum );
    1069      989708 :                     eleRad = atan2f( zSum, sqrtf( xSum * xSum + ySum * ySum ) );
    1070             : 
    1071      989708 :                     hMeta->directional_meta[i].azimuth[j][k] = aziRad / EVS_PI * 180.0f;
    1072      989708 :                     hMeta->directional_meta[i].elevation[j][k] = eleRad / EVS_PI * 180.0f;
    1073             : 
    1074      989708 :                     vecLen = sqrtf( xSum * xSum + ySum * ySum + zSum * zSum );
    1075      989708 :                     hMeta->directional_meta[i].energy_ratio[j][k] = vecLen / ( energySum + EPSILON );
    1076             : 
    1077      989708 :                     if ( computeCoherence )
    1078             :                     {
    1079     2379466 :                         for ( m = brange[0]; m < brange[1]; m++ )
    1080             :                         {
    1081     1827408 :                             spreadCohSum += hMeta->directional_meta[i].spread_coherence[j][m] * hMasa->data.energy[j][m];
    1082             :                         }
    1083      552058 :                         hMeta->directional_meta[i].spread_coherence[j][k] = spreadCohSum / ( energySum + EPSILON );
    1084             : 
    1085      552058 :                         if ( i == 0 )
    1086             :                         {
    1087      427914 :                             surrCohSum = 0.0f;
    1088     1833186 :                             for ( m = brange[0]; m < brange[1]; m++ )
    1089             :                             {
    1090     1405272 :                                 surrCohSum += hMeta->common_meta.surround_coherence[j][m] * hMasa->data.energy[j][m];
    1091             :                             }
    1092      427914 :                             hMeta->common_meta.surround_coherence[j][k] = surrCohSum / ( energySum + EPSILON );
    1093             :                         }
    1094             :                     }
    1095             : 
    1096      989708 :                     if ( i == 0 )
    1097             :                     {
    1098      805350 :                         energy[j][k] = energySum;
    1099             :                     }
    1100             :                 }
    1101             :             }
    1102             :         }
    1103             :     }
    1104        3642 :     else if ( mergeRatiosOverSubframes ) /* keep frequency resolution */
    1105             :     {
    1106        5700 :         for ( j = 0; j < numSf; j++ )
    1107             :         {
    1108      114000 :             for ( k = 0; k < numCodingBands; k++ )
    1109             :             {
    1110      109440 :                 energy[j][k] = hMasa->data.energy[j][k];
    1111             :             }
    1112             :         }
    1113             :     }
    1114             : 
    1115       41605 :     if ( mergeRatiosOverSubframes )
    1116             :     {
    1117      244114 :         for ( k = 0; k < numCodingBands; k++ )
    1118             :         {
    1119      210663 :             energySum = 0.0f;
    1120     1053315 :             for ( j = 0; j < numSf; j++ )
    1121             :             {
    1122      842652 :                 energySum += energy[j][k];
    1123             :             }
    1124             : 
    1125      210663 :             if ( computeCoherence )
    1126             :             {
    1127      122333 :                 surrCohSum = 0.0f;
    1128      611665 :                 for ( j = 0; j < numSf; j++ )
    1129             :                 {
    1130      489332 :                     surrCohSum += energy[j][k] * hMeta->common_meta.surround_coherence[j][k];
    1131             :                 }
    1132      122333 :                 surrCohTemp = surrCohSum / ( energySum + EPSILON );
    1133             : 
    1134      611665 :                 for ( j = 0; j < numSf; j++ )
    1135             :                 {
    1136      489332 :                     hMeta->common_meta.surround_coherence[j][k] = surrCohTemp;
    1137             :                 }
    1138             :             }
    1139             : 
    1140      459874 :             for ( i = 0; i < numDirections; i++ )
    1141             :             {
    1142      249211 :                 energyRatioSum = 0.0f;
    1143     1246055 :                 for ( j = 0; j < numSf; j++ )
    1144             :                 {
    1145      996844 :                     energyRatioSum += energy[j][k] * hMeta->directional_meta[i].energy_ratio[j][k];
    1146             :                 }
    1147      249211 :                 energyRatioTemp = energyRatioSum / ( energySum + EPSILON );
    1148             : 
    1149     1246055 :                 for ( j = 0; j < numSf; j++ )
    1150             :                 {
    1151      996844 :                     hMeta->directional_meta[i].energy_ratio[j][k] = energyRatioTemp;
    1152             :                 }
    1153             :             }
    1154             :         }
    1155             :     }
    1156             : 
    1157       41605 :     return;
    1158             : }
    1159             : 
    1160             : 
    1161             : /*-------------------------------------------------------------------*
    1162             :  * ivas_masa_combine_directions()
    1163             :  *
    1164             :  *
    1165             :  *-------------------------------------------------------------------*/
    1166             : 
    1167        9520 : void ivas_masa_combine_directions(
    1168             :     MASA_ENCODER_HANDLE hMasa )
    1169             : {
    1170             :     int16_t i, j, k;
    1171             :     uint8_t numCodingBands;
    1172             :     uint8_t numSf;
    1173             :     uint8_t numDirections;
    1174             :     uint8_t computeCoherence;
    1175             :     MASA_METADATA_HANDLE hMeta;
    1176             : 
    1177             :     float aziRad;
    1178             :     float eleRad;
    1179             :     float x[MASA_MAXIMUM_DIRECTIONS][MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
    1180             :     float y[MASA_MAXIMUM_DIRECTIONS][MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
    1181             :     float z[MASA_MAXIMUM_DIRECTIONS][MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
    1182             :     float vecLen;
    1183             :     float xSum[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
    1184             :     float ySum[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
    1185             :     float zSum[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
    1186             :     float sumVecLen[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
    1187             :     float tempImportance;
    1188             :     float importance[MASA_FREQUENCY_BANDS];
    1189             :     int16_t indicesOfLargest[MASA_FREQUENCY_BANDS];
    1190             : 
    1191             :     float ambience1dir;
    1192             :     float ambience2dir;
    1193             :     float ambienceIncrease;
    1194             :     float ratioSum;
    1195             :     float origSurrCohEne;
    1196             :     float newSurrCohEne;
    1197             : 
    1198        9520 :     numCodingBands = hMasa->config.numCodingBands;
    1199        9520 :     numDirections = hMasa->config.numberOfDirections;
    1200        9520 :     numSf = hMasa->config.joinedSubframes == TRUE ? 1 : MAX_PARAM_SPATIAL_SUBFRAMES;
    1201             : 
    1202        9520 :     hMeta = &( hMasa->masaMetadata );
    1203             : 
    1204        9520 :     computeCoherence = hMasa->config.useCoherence && hMasa->config.coherencePresent;
    1205             : 
    1206       28560 :     for ( i = 0; i < numDirections; i++ )
    1207             :     {
    1208       84400 :         for ( j = 0; j < numSf; j++ )
    1209             :         {
    1210      865744 :             for ( k = 0; k < numCodingBands; k++ )
    1211             :             {
    1212      800384 :                 aziRad = hMeta->directional_meta[i].azimuth[j][k] / 180.0f * EVS_PI;
    1213      800384 :                 eleRad = hMeta->directional_meta[i].elevation[j][k] / 180.0f * EVS_PI;
    1214      800384 :                 vecLen = hMeta->directional_meta[i].energy_ratio[j][k];
    1215             : 
    1216      800384 :                 x[i][j][k] = cosf( aziRad ) * cosf( eleRad ) * vecLen;
    1217      800384 :                 y[i][j][k] = sinf( aziRad ) * cosf( eleRad ) * vecLen;
    1218      800384 :                 z[i][j][k] = sinf( eleRad ) * vecLen;
    1219             :             }
    1220             :         }
    1221             :     }
    1222             : 
    1223             :     /* Compute sum vector */
    1224       42200 :     for ( j = 0; j < numSf; j++ )
    1225             :     {
    1226      432872 :         for ( k = 0; k < numCodingBands; k++ )
    1227             :         {
    1228      400192 :             xSum[j][k] = x[0][j][k] + x[1][j][k];
    1229      400192 :             ySum[j][k] = y[0][j][k] + y[1][j][k];
    1230      400192 :             zSum[j][k] = z[0][j][k] + z[1][j][k];
    1231      400192 :             sumVecLen[j][k] = sqrtf( xSum[j][k] * xSum[j][k] + ySum[j][k] * ySum[j][k] + zSum[j][k] * zSum[j][k] );
    1232             :         }
    1233             :     }
    1234             : 
    1235             :     /* Estimate the importance of having two directions instead of one */
    1236      132644 :     for ( i = 0; i < numCodingBands; i++ )
    1237             :     {
    1238      123124 :         importance[i] = 0.0f;
    1239      523316 :         for ( j = 0; j < numSf; j++ )
    1240             :         {
    1241      400192 :             tempImportance = hMeta->directional_meta[0].energy_ratio[j][i] + hMeta->directional_meta[1].energy_ratio[j][i] - sumVecLen[j][i];
    1242      400192 :             importance[i] += tempImportance;
    1243             :         }
    1244      123124 :         importance[i] /= (float) numSf;
    1245      123124 :         importance[i] *= hMasa->data.importanceWeight[i];
    1246             :     }
    1247             : 
    1248             :     /* Determine bands where to use two directions */
    1249        9520 :     find_n_largest( importance, indicesOfLargest, numCodingBands, hMasa->config.numTwoDirBands );
    1250             : 
    1251      132644 :     for ( i = 0; i < numCodingBands; i++ )
    1252             :     {
    1253      123124 :         hMasa->data.twoDirBands[i] = 0;
    1254             :     }
    1255             : 
    1256       31054 :     for ( i = 0; i < hMasa->config.numTwoDirBands; i++ )
    1257             :     {
    1258       21534 :         hMasa->data.twoDirBands[indicesOfLargest[i]] = 1;
    1259             :     }
    1260             : 
    1261             :     /* Combine directions on the remaining bands */
    1262      132644 :     for ( i = 0; i < numCodingBands; i++ )
    1263             :     {
    1264      123124 :         if ( hMasa->data.twoDirBands[i] == 0 )
    1265             :         {
    1266      430178 :             for ( j = 0; j < numSf; j++ )
    1267             :             {
    1268      328588 :                 aziRad = atan2f( ySum[j][i], xSum[j][i] );
    1269      328588 :                 eleRad = atan2f( zSum[j][i], sqrtf( xSum[j][i] * xSum[j][i] + ySum[j][i] * ySum[j][i] ) );
    1270             : 
    1271      328588 :                 hMeta->directional_meta[0].azimuth[j][i] = aziRad / EVS_PI * 180.0f;
    1272      328588 :                 hMeta->directional_meta[0].elevation[j][i] = eleRad / EVS_PI * 180.0f;
    1273             : 
    1274      328588 :                 ratioSum = hMeta->directional_meta[0].energy_ratio[j][i] + hMeta->directional_meta[1].energy_ratio[j][i];
    1275      328588 :                 if ( computeCoherence )
    1276             :                 {
    1277      127198 :                     hMeta->directional_meta[0].spread_coherence[j][i] =
    1278      127198 :                         ( hMeta->directional_meta[0].spread_coherence[j][i] * hMeta->directional_meta[0].energy_ratio[j][i] + hMeta->directional_meta[1].spread_coherence[j][i] * hMeta->directional_meta[1].energy_ratio[j][i] ) / ( ratioSum + EPSILON );
    1279             :                 }
    1280             : 
    1281      328588 :                 ambience2dir = 1.0f - ratioSum;
    1282      328588 :                 hMeta->directional_meta[0].energy_ratio[j][i] = sumVecLen[j][i] / ( hMeta->directional_meta[0].energy_ratio[j][i] + hMeta->directional_meta[1].energy_ratio[j][i] + ambience2dir / 2.0f );
    1283      328588 :                 hMeta->directional_meta[1].energy_ratio[j][i] = 0.0f;
    1284      328588 :                 hMeta->common_meta.diffuse_to_total_ratio[j][i] = 1.0f - hMeta->directional_meta[0].energy_ratio[j][i];
    1285      328588 :                 if ( computeCoherence )
    1286             :                 {
    1287      127198 :                     ambience1dir = 1.0f - hMeta->directional_meta[0].energy_ratio[j][i];
    1288      127198 :                     ambienceIncrease = max( ambience1dir - ambience2dir, 0.0f );
    1289             : 
    1290      127198 :                     origSurrCohEne = ambience2dir * hMeta->common_meta.surround_coherence[j][i];
    1291      127198 :                     newSurrCohEne = ambienceIncrease * hMeta->directional_meta[0].spread_coherence[j][i];
    1292      127198 :                     hMeta->common_meta.surround_coherence[j][i] = min( 1.0f, ( origSurrCohEne + newSurrCohEne ) / ( ambience1dir + EPSILON ) );
    1293             :                 }
    1294             :             }
    1295             :         }
    1296             :     }
    1297             : 
    1298        9520 :     return;
    1299             : }
    1300             : 
    1301             : 
    1302        9520 : static void find_n_largest(
    1303             :     const float *input,
    1304             :     int16_t *largestIndices,
    1305             :     const int16_t numElements,
    1306             :     const int16_t numLargest )
    1307             : {
    1308             :     int16_t i, j;
    1309             :     float largestValue;
    1310             :     int16_t largestIndex;
    1311             :     float values[MASA_FREQUENCY_BANDS];
    1312             : 
    1313      132644 :     for ( j = 0; j < numElements; j++ )
    1314             :     {
    1315      123124 :         values[j] = input[j];
    1316             :     }
    1317             : 
    1318       31054 :     for ( i = 0; i < numLargest; i++ )
    1319             :     {
    1320       21534 :         largestValue = values[0];
    1321       21534 :         largestIndex = 0;
    1322      342038 :         for ( j = 1; j < numElements; j++ )
    1323             :         {
    1324      320504 :             if ( values[j] > largestValue )
    1325             :             {
    1326       41072 :                 largestValue = values[j];
    1327       41072 :                 largestIndex = j;
    1328             :             }
    1329             :         }
    1330       21534 :         largestIndices[i] = largestIndex;
    1331       21534 :         values[largestIndex] = -1.0f;
    1332             :     }
    1333             : 
    1334        9520 :     return;
    1335             : }
    1336             : 
    1337             : 
    1338       41605 : static void move_metadata_to_qmetadata(
    1339             :     const MASA_ENCODER_HANDLE hMasa,
    1340             :     IVAS_QMETADATA_HANDLE hQMeta )
    1341             : {
    1342             :     int16_t dir, sf, band;
    1343             :     uint8_t numCodingBands;
    1344             :     uint8_t numDirections;
    1345             :     uint8_t numSf;
    1346             :     MASA_METADATA_HANDLE hMeta;
    1347             : 
    1348       41605 :     numCodingBands = hMasa->config.numCodingBands;
    1349       41605 :     numDirections = hMasa->config.numberOfDirections;
    1350       41605 :     numSf = hMasa->config.joinedSubframes == TRUE ? 1 : MAX_PARAM_SPATIAL_SUBFRAMES;
    1351       41605 :     hMeta = &( hMasa->masaMetadata );
    1352             : 
    1353       89046 :     for ( dir = 0; dir < numDirections; dir++ )
    1354             :     {
    1355      217567 :         for ( sf = 0; sf < numSf; sf++ )
    1356             :         {
    1357     1526120 :             for ( band = 0; band < numCodingBands; band++ )
    1358             :             {
    1359     1355994 :                 hQMeta->q_direction[dir].band_data[band].azimuth[sf] = hMeta->directional_meta[dir].azimuth[sf][band];
    1360     1355994 :                 hQMeta->q_direction[dir].band_data[band].elevation[sf] = hMeta->directional_meta[dir].elevation[sf][band];
    1361     1355994 :                 hQMeta->q_direction[dir].band_data[band].energy_ratio[sf] = hMeta->directional_meta[dir].energy_ratio[sf][band];
    1362     1355994 :                 hQMeta->q_direction[dir].band_data[band].spherical_index[sf] = hMeta->directional_meta[dir].spherical_index[sf][band];
    1363     1355994 :                 if ( hQMeta->q_direction[dir].coherence_band_data != NULL )
    1364             :                 {
    1365      990540 :                     hQMeta->q_direction[dir].coherence_band_data[band].spread_coherence[sf] = (uint8_t) roundf( hMeta->directional_meta[dir].spread_coherence[sf][band] * UINT8_MAX );
    1366             :                 }
    1367             :             }
    1368             :         }
    1369             :     }
    1370             : 
    1371      191375 :     for ( sf = 0; sf < numSf; sf++ )
    1372             :     {
    1373     1280362 :         for ( band = 0; band < numCodingBands; band++ )
    1374             :         {
    1375     1130592 :             if ( hQMeta->surcoh_band_data != NULL )
    1376             :             {
    1377      765138 :                 hQMeta->surcoh_band_data[band].surround_coherence[sf] = (uint8_t) roundf( hMeta->common_meta.surround_coherence[sf][band] * UINT8_MAX );
    1378             :             }
    1379             :         }
    1380             :     }
    1381             : 
    1382       41605 :     if ( numDirections > 1 )
    1383             :     {
    1384       75232 :         for ( band = 0; band < numCodingBands; band++ )
    1385             :         {
    1386       69396 :             hQMeta->twoDirBands[band] = hMasa->data.twoDirBands[band];
    1387             :         }
    1388        5836 :         hQMeta->numTwoDirBands = hMasa->config.numTwoDirBands;
    1389             :     }
    1390             : 
    1391             :     /* Copy spread coherence for DCT-based coding */
    1392       41605 :     if ( numSf == 1 && hMasa->config.useCoherence )
    1393             :     {
    1394        6620 :         for ( dir = 0; dir < numDirections; dir++ )
    1395             :         {
    1396       15232 :             for ( sf = 1; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1397             :             {
    1398      200268 :                 for ( band = 0; band < numCodingBands; band++ )
    1399             :                 {
    1400      188844 :                     hQMeta->q_direction[dir].coherence_band_data[band].spread_coherence[sf] = hQMeta->q_direction[dir].coherence_band_data[band].spread_coherence[0];
    1401             :                 }
    1402             :             }
    1403             :         }
    1404             :     }
    1405             : 
    1406       41605 :     return;
    1407             : }
    1408             : 
    1409             : 
    1410             : /* This function studies parametric MASA metadata to provide information for codec configuration */
    1411       39626 : static void detect_metadata_composition(
    1412             :     const MASA_ENCODER_HANDLE hMasa, /* i  : MASA encoder data              */
    1413             :     uint8_t *joinedSubframes,        /* o  : Result of subframe composition */
    1414             :     uint8_t *coherencePresent,       /* o  : Result of coherence presence   */
    1415             :     uint8_t *isTwoDir                /* o  : Result of two direction check  */
    1416             : )
    1417             : {
    1418             :     MASA_METADATA_FRAME *hMeta;
    1419             :     int8_t sf, band, dir, numDir;
    1420             :     int16_t nSubFrames;
    1421       39626 :     uint8_t dirValid[2] = { FALSE, FALSE };
    1422       39626 :     uint8_t cohPresent = FALSE;
    1423       39626 :     uint8_t sfDiffer = FALSE;
    1424             :     uint8_t sfSimilar;
    1425             : 
    1426       39626 :     hMeta = &( hMasa->masaMetadata );
    1427       39626 :     numDir = hMeta->descriptive_meta.numberOfDirections + 1;
    1428             : 
    1429       39626 :     *isTwoDir = FALSE;
    1430             : 
    1431             :     /* First check for valid two directions */
    1432       39626 :     if ( numDir == 1 )
    1433             :     {
    1434       29726 :         dirValid[0] = TRUE;
    1435             :     }
    1436             :     else
    1437             :     {
    1438             :         /* Default assumption */
    1439        9900 :         *isTwoDir = TRUE;
    1440             : 
    1441             :         /* Check for direct-to-total ratio values */
    1442       29700 :         for ( dir = 0; dir < numDir; dir++ )
    1443             :         {
    1444       19800 :             sf = 0;
    1445       39600 :             while ( !dirValid[dir] && sf < MAX_PARAM_SPATIAL_SUBFRAMES )
    1446             :             {
    1447       19800 :                 band = 0;
    1448       39600 :                 while ( !dirValid[dir] && band < MASA_FREQUENCY_BANDS )
    1449             :                 {
    1450       19800 :                     if ( hMeta->directional_meta[dir].energy_ratio[sf][band] >= MASA_RATIO_THRESHOLD )
    1451             :                     {
    1452       19800 :                         dirValid[dir] = TRUE;
    1453             :                     }
    1454       19800 :                     band++;
    1455             :                 }
    1456       19800 :                 sf++;
    1457             :             }
    1458             :         }
    1459             : 
    1460        9900 :         if ( dirValid[1] == FALSE )
    1461             :         {
    1462             :             /* This handles also case where both are false. Then we just use first dir metadata. */
    1463           0 :             *isTwoDir = FALSE;
    1464             :         }
    1465        9900 :         else if ( dirValid[0] == FALSE && dirValid[1] == TRUE )
    1466             :         {
    1467           0 :             *isTwoDir = FALSE;
    1468             :             /* Copy data to first direction */
    1469           0 :             for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1470             :             {
    1471           0 :                 for ( band = 0; band < MASA_FREQUENCY_BANDS; band++ )
    1472             :                 {
    1473           0 :                     hMeta->directional_meta[0].spherical_index[sf][band] = hMeta->directional_meta[1].spherical_index[sf][band];
    1474           0 :                     hMeta->directional_meta[0].azimuth[sf][band] = hMeta->directional_meta[1].azimuth[sf][band];
    1475           0 :                     hMeta->directional_meta[0].elevation[sf][band] = hMeta->directional_meta[1].elevation[sf][band];
    1476           0 :                     hMeta->directional_meta[0].energy_ratio[sf][band] = hMeta->directional_meta[1].energy_ratio[sf][band];
    1477           0 :                     hMeta->directional_meta[0].spread_coherence[sf][band] = hMeta->directional_meta[1].spread_coherence[sf][band];
    1478             :                 }
    1479             :             }
    1480             :         }
    1481             : 
    1482        9900 :         if ( *isTwoDir == FALSE )
    1483             :         {
    1484             :             /* Further checks will be done with just one direction */
    1485           0 :             numDir = 1;
    1486             :         }
    1487             :     }
    1488             : 
    1489             :     /* Check if data over subframes is identical. Check is done by comparing to first subframe. */
    1490       39626 :     sfSimilar = TRUE;
    1491       39626 :     sf = 1;
    1492       90352 :     while ( ( sfSimilar == TRUE ) && ( sf < MAX_PARAM_SPATIAL_SUBFRAMES ) )
    1493             :     {
    1494       50726 :         sfSimilar = are_masa_subframes_similar( hMeta, 0, hMeta, sf );
    1495       50726 :         sf++;
    1496             :     }
    1497       39626 :     sfDiffer = sfSimilar == TRUE ? FALSE : TRUE;
    1498             : 
    1499             :     /* Further checks can be done with just one subframe if they are identical */
    1500       39626 :     nSubFrames = sfDiffer == TRUE ? MAX_PARAM_SPATIAL_SUBFRAMES : 1;
    1501             : 
    1502             :     /* Check spread coherence */
    1503       39626 :     dir = 0;
    1504       79252 :     while ( cohPresent == FALSE && dir < numDir )
    1505             :     {
    1506       39626 :         sf = 0;
    1507       82138 :         while ( cohPresent == FALSE && sf < nSubFrames )
    1508             :         {
    1509       42512 :             band = 0;
    1510      277843 :             while ( cohPresent == FALSE && band < MASA_FREQUENCY_BANDS )
    1511             :             {
    1512             :                 /* Check coherences for presence of coherence */
    1513      235331 :                 if ( hMeta->directional_meta[dir].spread_coherence[sf][band] >= MASA_COHERENCE_THRESHOLD )
    1514             :                 {
    1515       37829 :                     cohPresent = TRUE;
    1516             :                 }
    1517      235331 :                 band++;
    1518             :             }
    1519       42512 :             sf++;
    1520             :         }
    1521       39626 :         dir++;
    1522             :     }
    1523             : 
    1524             :     /* Check surround coherence separately if we do not have already knowledge of coherence */
    1525       39626 :     if ( cohPresent == FALSE )
    1526             :     {
    1527        1797 :         cohPresent = ivas_masa_surrcoh_signicant( hMeta->common_meta.surround_coherence, hMeta->common_meta.diffuse_to_total_ratio, nSubFrames, MASA_FREQUENCY_BANDS );
    1528             :     }
    1529             : 
    1530             :     /* Set output flags */
    1531       39626 :     *joinedSubframes = sfDiffer == TRUE ? FALSE : TRUE;
    1532       39626 :     *coherencePresent = cohPresent;
    1533             : 
    1534       39626 :     return;
    1535             : }
    1536             : 
    1537             : 
    1538             : /* Check and compensate energy ratios. This function verifies that energy ratios follow the principle of summing to one.
    1539             :  * In addition, it implements simple remainder-to-total handling where remainder energy is proportionally added to other
    1540             :  * ratios. */
    1541       39626 : static void compensate_energy_ratios(
    1542             :     MASA_ENCODER_HANDLE hMasa )
    1543             : {
    1544             :     int16_t sf, band, dir;
    1545             :     float ratioSum;
    1546             :     MASA_METADATA_HANDLE hMeta;
    1547             :     uint8_t numDirs;
    1548             : 
    1549       39626 :     hMeta = &( hMasa->masaMetadata );
    1550       39626 :     numDirs = hMasa->config.numberOfDirections;
    1551             : 
    1552      198130 :     for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1553             :     {
    1554     3962600 :         for ( band = 0; band < MASA_FREQUENCY_BANDS; band++ )
    1555             :         {
    1556             :             /* Remainder is always set to zero and energy removal is compensated in following steps
    1557             :              * to other ratios. */
    1558     3804096 :             hMeta->common_meta.remainder_to_total_ratio[sf][band] = 0.0f;
    1559             : 
    1560     3804096 :             ratioSum = 0;
    1561     8558592 :             for ( dir = 0; dir < numDirs; dir++ )
    1562             :             {
    1563     4754496 :                 ratioSum += hMeta->directional_meta[dir].energy_ratio[sf][band];
    1564             :             }
    1565     3804096 :             ratioSum += hMeta->common_meta.diffuse_to_total_ratio[sf][band];
    1566             : 
    1567     3804096 :             if ( ratioSum == 0.0f )
    1568             :             {
    1569           0 :                 for ( dir = 0; dir < numDirs; dir++ )
    1570             :                 {
    1571           0 :                     hMeta->directional_meta[dir].energy_ratio[sf][band] = 0.0f;
    1572             :                 }
    1573           0 :                 hMeta->common_meta.diffuse_to_total_ratio[sf][band] = 1.0f;
    1574             :             }
    1575     3804096 :             else if ( ratioSum != 1.0f )
    1576             :             {
    1577      152049 :                 for ( dir = 0; dir < numDirs; dir++ )
    1578             :                 {
    1579      101366 :                     hMeta->directional_meta[dir].energy_ratio[sf][band] /= ratioSum;
    1580             :                 }
    1581       50683 :                 hMeta->common_meta.diffuse_to_total_ratio[sf][band] /= ratioSum;
    1582             :             }
    1583             :         }
    1584             :     }
    1585             : 
    1586       39626 :     return;
    1587             : }
    1588             : 
    1589             : 
    1590             : /* 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 */
    1591       25011 : static void reduce_metadata_further(
    1592             :     MASA_ENCODER_HANDLE hMasa,
    1593             :     IVAS_QMETADATA_HANDLE hqmetadata,
    1594             :     const IVAS_FORMAT ivas_format )
    1595             : {
    1596             :     int16_t sf;
    1597             :     int16_t band;
    1598             :     int16_t selectedBand;
    1599             :     float energy[MAX_PARAM_SPATIAL_SUBFRAMES][LOWBITRATE_NUM_BANDS];
    1600             :     float totalEnergySum;
    1601             :     uint8_t numCodingBands;
    1602             :     uint8_t computeCoherence;
    1603             :     float onset_filter;
    1604             :     float bandEnergy;
    1605             :     uint8_t mergeOverFreqBands;
    1606             :     float meanRatio;
    1607             : 
    1608       25011 :     numCodingBands = hMasa->config.numCodingBands;
    1609       25011 :     computeCoherence = hMasa->config.useCoherence && hMasa->config.coherencePresent;
    1610             : 
    1611             :     /* Set default values */
    1612       25011 :     selectedBand = 0;
    1613       25011 :     mergeOverFreqBands = 0;
    1614             : 
    1615             :     /* Get energy for the input data in 4-subframe, 5-band format */
    1616       25011 :     totalEnergySum = 0.0f;
    1617       25011 :     if ( ivas_format == MASA_FORMAT || ivas_format == MASA_ISM_FORMAT ) /* Energy data is in 4-subframe, 24-band format */
    1618             :     {
    1619       84280 :         for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1620             :         {
    1621             :             int16_t brange[2];
    1622             :             float eneSum;
    1623             :             int16_t m;
    1624             : 
    1625      404544 :             for ( band = 0; band < numCodingBands; band++ )
    1626             :             {
    1627      337120 :                 brange[0] = hMasa->data.band_mapping[band];
    1628      337120 :                 brange[1] = hMasa->data.band_mapping[band + 1];
    1629             : 
    1630      337120 :                 eneSum = 0.0f;
    1631     1949840 :                 for ( m = brange[0]; m < brange[1]; m++ )
    1632             :                 {
    1633     1612720 :                     eneSum += hMasa->data.energy[sf][m];
    1634             :                 }
    1635      337120 :                 energy[sf][band] = eneSum;
    1636      337120 :                 totalEnergySum += eneSum;
    1637             :             }
    1638             :         }
    1639             :     }
    1640             :     else /* Energy data is already in 4-subframe, 5-band format */
    1641             :     {
    1642       40775 :         for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1643             :         {
    1644      195720 :             for ( band = 0; band < numCodingBands; band++ )
    1645             :             {
    1646      163100 :                 energy[sf][band] = hMasa->data.energy[sf][band];
    1647      163100 :                 totalEnergySum += energy[sf][band];
    1648             :             }
    1649             :         }
    1650             :     }
    1651             : 
    1652             :     /* Determine onsets */
    1653       25011 :     hMasa->data.onset_detector_1 = hMasa->data.onset_detector_1 * LOWBITRATE_ONSET_ALPHA;
    1654       25011 :     hMasa->data.onset_detector_1 = max( hMasa->data.onset_detector_1, totalEnergySum );
    1655             : 
    1656       25011 :     hMasa->data.onset_detector_2 = LOWBITRATE_ONSET_BETA * hMasa->data.onset_detector_2 + ( 1.0f - LOWBITRATE_ONSET_BETA ) * hMasa->data.onset_detector_1;
    1657       25011 :     hMasa->data.onset_detector_2 = LOWBITRATE_ONSET_GAIN * min( hMasa->data.onset_detector_1, hMasa->data.onset_detector_2 );
    1658             : 
    1659       25011 :     onset_filter = min( max( hMasa->data.onset_detector_2 / ( hMasa->data.onset_detector_1 + EPSILON ), 0.0f ), 1.0f );
    1660             : 
    1661             :     /* If we have onset, continue checking if we should reduce in frequency instead of time. */
    1662       25011 :     if ( onset_filter < 0.99f )
    1663             :     {
    1664             :         /* Determine one frequency band to use to represent all frequency bands */
    1665       23532 :         for ( band = numCodingBands - 1; band >= 0; band-- )
    1666             :         {
    1667             :             float threshold;
    1668             :             float bandRatio;
    1669             : 
    1670       23453 :             threshold = totalEnergySum / ( MAX_PARAM_SPATIAL_SUBFRAMES * LOWBITRATE_NUM_BANDS ) * 0.5f; /* Average energy multiplied with energy ratio of 0.5f */
    1671       23453 :             bandRatio = hqmetadata->q_direction[0].band_data[band].energy_ratio[0];
    1672             : 
    1673       23453 :             bandEnergy = 0.0f;
    1674      117265 :             for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1675             :             {
    1676       93812 :                 bandEnergy += energy[sf][band];
    1677             :             }
    1678             : 
    1679       23453 :             if ( bandEnergy / MAX_PARAM_SPATIAL_SUBFRAMES * bandRatio > threshold )
    1680             :             {
    1681        5600 :                 selectedBand = band;
    1682        5600 :                 break;
    1683             :             }
    1684             :         }
    1685             : 
    1686             :         /* Determine if to merge over frequency instead of time */
    1687        5679 :         meanRatio = 0.0f;
    1688       28395 :         for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1689             :         {
    1690      136296 :             for ( band = 0; band < numCodingBands; band++ )
    1691             :             {
    1692      113580 :                 meanRatio += hqmetadata->q_direction[0].band_data[band].energy_ratio[sf] * energy[sf][band];
    1693             :             }
    1694             :         }
    1695        5679 :         meanRatio /= ( totalEnergySum + EPSILON );
    1696             : 
    1697             :         /* 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.
    1698             :          * Otherwise, merge over subframes. */
    1699        5679 :         if ( hqmetadata->q_direction[0].band_data[selectedBand].energy_ratio[0] > meanRatio )
    1700             :         {
    1701        4016 :             mergeOverFreqBands = 1;
    1702             :         }
    1703             :         else
    1704             :         {
    1705        1663 :             mergeOverFreqBands = 0;
    1706             :         }
    1707             :     }
    1708             :     else
    1709             :     {
    1710       19332 :         mergeOverFreqBands = 0;
    1711             :     }
    1712             : 
    1713             :     /* Merge values over subframes or frequency bands, depending on which one is less important */
    1714       25011 :     if ( !mergeOverFreqBands ) /* Merge values over subframes */
    1715             :     {
    1716             :         float xSum, ySum, zSum;
    1717             :         float bandSumEnergy;
    1718             :         float aziRad, eleRad;
    1719             :         float x, y, z;
    1720             :         float veclen;
    1721             : 
    1722      125970 :         for ( band = 0; band < numCodingBands; band++ )
    1723             :         {
    1724      104975 :             xSum = 0.0f;
    1725      104975 :             ySum = 0.0f;
    1726      104975 :             zSum = 0.0f;
    1727      104975 :             bandSumEnergy = 0.0f;
    1728             : 
    1729      524875 :             for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1730             :             {
    1731      419900 :                 aziRad = hqmetadata->q_direction[0].band_data[band].azimuth[sf] / 180.0f * EVS_PI;
    1732      419900 :                 eleRad = hqmetadata->q_direction[0].band_data[band].elevation[sf] / 180.0f * EVS_PI;
    1733      419900 :                 veclen = hqmetadata->q_direction[0].band_data[band].energy_ratio[sf] * energy[sf][band];
    1734             : 
    1735      419900 :                 x = cosf( aziRad ) * cosf( eleRad ) * veclen;
    1736      419900 :                 y = sinf( aziRad ) * cosf( eleRad ) * veclen;
    1737      419900 :                 z = sinf( eleRad ) * veclen;
    1738             : 
    1739      419900 :                 xSum += x;
    1740      419900 :                 ySum += y;
    1741      419900 :                 zSum += z;
    1742             : 
    1743      419900 :                 bandSumEnergy += energy[sf][band];
    1744             :             }
    1745             : 
    1746      104975 :             aziRad = atan2f( ySum, xSum );
    1747      104975 :             eleRad = atan2f( zSum, sqrtf( xSum * xSum + ySum * ySum ) );
    1748             : 
    1749      104975 :             hqmetadata->q_direction[0].band_data[band].azimuth[0] = aziRad / EVS_PI * 180.0f;
    1750      104975 :             hqmetadata->q_direction[0].band_data[band].elevation[0] = eleRad / EVS_PI * 180.0f;
    1751             : 
    1752             :             /* Energy ratio is already merged through time */
    1753             : 
    1754      104975 :             if ( computeCoherence && hqmetadata->q_direction[0].coherence_band_data != NULL )
    1755             :             {
    1756             :                 float spreadCoh;
    1757       27180 :                 float spreadCohSum = 0.0f;
    1758      135900 :                 for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1759             :                 {
    1760      108720 :                     spreadCoh = (float) hqmetadata->q_direction[0].coherence_band_data[band].spread_coherence[sf] / 255.0f;
    1761      108720 :                     spreadCohSum += spreadCoh * energy[sf][band];
    1762             :                 }
    1763       27180 :                 hqmetadata->q_direction[0].coherence_band_data[band].spread_coherence[0] = (uint8_t) roundf( spreadCohSum / ( bandSumEnergy + EPSILON ) * 255.0f );
    1764             : 
    1765             :                 /* Copy spread coherence to the rest of subframes for the coherence coding algorithm. */
    1766      108720 :                 for ( sf = 1; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1767             :                 {
    1768       81540 :                     hqmetadata->q_direction[0].coherence_band_data[band].spread_coherence[sf] = hqmetadata->q_direction[0].coherence_band_data[band].spread_coherence[0];
    1769             :                 }
    1770             : 
    1771             :                 /* Surround coherence is already merged through time */
    1772             :             }
    1773             :         }
    1774             : 
    1775       20995 :         hqmetadata->q_direction->cfg.nblocks = 1;
    1776       20995 :         hMasa->config.joinedSubframes = 1;
    1777             :     }
    1778             :     else /* Merge values over frequency bands */
    1779             :     {
    1780             :         /* Use the selected frequency band to represent all data */
    1781       20080 :         for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1782             :         {
    1783       16064 :             hqmetadata->q_direction[0].band_data[0].azimuth[sf] = hqmetadata->q_direction[0].band_data[selectedBand].azimuth[sf];
    1784       16064 :             hqmetadata->q_direction[0].band_data[0].elevation[sf] = hqmetadata->q_direction[0].band_data[selectedBand].elevation[sf];
    1785       16064 :             hqmetadata->q_direction[0].band_data[0].energy_ratio[sf] = hqmetadata->q_direction[0].band_data[selectedBand].energy_ratio[sf];
    1786       16064 :             if ( hqmetadata->q_direction[0].coherence_band_data != NULL )
    1787             :             {
    1788        5408 :                 hqmetadata->q_direction[0].coherence_band_data[0].spread_coherence[sf] = hqmetadata->q_direction[0].coherence_band_data[selectedBand].spread_coherence[sf];
    1789             :             }
    1790       16064 :             if ( hqmetadata->surcoh_band_data != NULL )
    1791             :             {
    1792        5408 :                 hqmetadata->surcoh_band_data[0].surround_coherence[sf] = hqmetadata->surcoh_band_data[selectedBand].surround_coherence[sf];
    1793             :             }
    1794             :         }
    1795             : 
    1796             :         /* Copy coherence to rest of bands for the coherence coding algorithm. */
    1797       20080 :         for ( band = 1; band < numCodingBands; band++ )
    1798             :         {
    1799       16064 :             if ( hqmetadata->q_direction[0].coherence_band_data != NULL )
    1800             :             {
    1801       27040 :                 for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1802             :                 {
    1803       21632 :                     hqmetadata->q_direction[0].coherence_band_data[band].spread_coherence[sf] = hqmetadata->q_direction[0].coherence_band_data[0].spread_coherence[sf];
    1804             :                 }
    1805             :             }
    1806       16064 :             if ( hqmetadata->q_direction[0].coherence_band_data != NULL )
    1807             :             {
    1808       27040 :                 for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1809             :                 {
    1810       21632 :                     hqmetadata->surcoh_band_data[band].surround_coherence[sf] = hqmetadata->surcoh_band_data[0].surround_coherence[sf];
    1811             :                 }
    1812             :             }
    1813             :         }
    1814             : 
    1815        4016 :         hqmetadata->q_direction[0].cfg.nbands = 1;
    1816             :     }
    1817             : 
    1818       25011 :     return;
    1819             : }
    1820             : 
    1821             : 
    1822       11680 : static int16_t encode_lfe_to_total_energy_ratio(
    1823             :     MASA_ENCODER_HANDLE hMasa,     /* i/o: MASA encoder structure       */
    1824             :     BSTR_ENC_HANDLE hMetaData,     /* i/o: Metadata bitstream handle    */
    1825             :     const int32_t ivas_total_brate /* i  : IVAS total bitrate           */
    1826             : )
    1827             : {
    1828             :     int16_t i;
    1829             :     float xq;
    1830             :     int16_t VQLevels;
    1831             :     float maxLFESubFrameEner;
    1832             :     float log2LFEaverage;
    1833             :     float log2LFEratio[4];
    1834             :     float xqv[4];
    1835             :     float linearLFEaverage;
    1836             :     int16_t lfeToTotalEnergyRatioIndices[3];
    1837             :     int16_t lfeAdaptiveVQBits;
    1838             :     int16_t lfeBitsWritten;
    1839             : 
    1840       11680 :     VQLevels = 0;
    1841       11680 :     lfeAdaptiveVQBits = 0;
    1842             : 
    1843             :     /* Determine maximum amount of LFE energy in any subframe */
    1844       11680 :     maxLFESubFrameEner = 0.0f;
    1845       58400 :     for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ )
    1846             :     {
    1847       46720 :         if ( hMasa->data.lfeToTotalEnergyRatio[i] > maxLFESubFrameEner )
    1848             :         {
    1849       24556 :             maxLFESubFrameEner = hMasa->data.lfeToTotalEnergyRatio[i];
    1850             :         }
    1851             :     }
    1852             : 
    1853             :     /* Set default values for the indices */
    1854       46720 :     for ( i = 0; i < 3; i++ )
    1855             :     {
    1856       35040 :         lfeToTotalEnergyRatioIndices[i] = 0;
    1857             :     }
    1858             : 
    1859             :     /* Check if there is enough energy in any subframe. If not, send only 1 bit (0) and abort. */
    1860             :     /* If there is enough LFE energy at least in one subframe, quantize it. */
    1861       11680 :     if ( maxLFESubFrameEner > 0.005f )
    1862             :     {
    1863             :         /* Convert energy to log2 domain, and clamp it to reasonable values */
    1864        2096 :         log2LFEaverage = 0.0f;
    1865       10480 :         for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ )
    1866             :         {
    1867        8384 :             log2LFEratio[i] = log2f( max( 0.001f, hMasa->data.lfeToTotalEnergyRatio[i] ) );
    1868        8384 :             if ( log2LFEratio[i] > 1.0f ) /* Corresponds to linear value 2.0f */
    1869             :             {
    1870           0 :                 log2LFEratio[i] = 1.0f;
    1871             :             }
    1872        8384 :             else if ( log2LFEratio[i] < -9.0f )
    1873             :             {
    1874         324 :                 log2LFEratio[i] = -9.0f;
    1875             :             }
    1876        8384 :             log2LFEaverage += 0.25f * log2LFEratio[i];
    1877             :         }
    1878             : 
    1879        2096 :         if ( ivas_total_brate == IVAS_13k2 )
    1880             :         {
    1881             :             /* Calculate adaptive 1-bit LFE quantizer index */
    1882         194 :             linearLFEaverage = exp2f( log2LFEaverage ); /* Convert back to linear domain */
    1883         194 :             if ( ( linearLFEaverage > MCMASA_LFE_1BIT_THRES ) && ( linearLFEaverage > ( 0.5f * ( MCMASA_LFE_BETA + hMasa->data.prevq_lfeToTotalEnergyRatio ) + 0.5f * ( MCMASA_LFE_ALPHA * hMasa->data.prevq_lfeToTotalEnergyRatio ) ) ) )
    1884             :             {
    1885         134 :                 lfeToTotalEnergyRatioIndices[0] = 1;
    1886         134 :                 if ( hMasa->data.prevq_lfeIndex == 1 )
    1887             :                 {
    1888          91 :                     hMasa->data.prevq_lfeToTotalEnergyRatio = hMasa->data.prevq_lfeToTotalEnergyRatio + MCMASA_LFE_THETA * MCMASA_LFE_BETA; /* larger "bump-up" to LFE-to-total energy ratio */
    1889             :                 }
    1890             :                 else
    1891             :                 {
    1892          43 :                     hMasa->data.prevq_lfeToTotalEnergyRatio = hMasa->data.prevq_lfeToTotalEnergyRatio + MCMASA_LFE_BETA; /* default "bump-up" to LFE-to-total energy ratio */
    1893             :                 }
    1894             :             }
    1895             :             else
    1896             :             {
    1897          60 :                 hMasa->data.prevq_lfeToTotalEnergyRatio = MCMASA_LFE_ALPHA * hMasa->data.prevq_lfeToTotalEnergyRatio; /* exponential decay */
    1898             :             }
    1899             : 
    1900         194 :             if ( hMasa->data.prevq_lfeToTotalEnergyRatio > 1.0f )
    1901             :             {
    1902           0 :                 hMasa->data.prevq_lfeToTotalEnergyRatio = 1.0f;
    1903             :             }
    1904         194 :             hMasa->data.prevq_lfeIndex = lfeToTotalEnergyRatioIndices[0]; /* Update to previous frame's index memories */
    1905             :         }
    1906             :         else /* Bitrate >= 16.4 kbps */
    1907             :         {
    1908             :             /* Do 1st stage scalar quantization */
    1909        1902 :             lfeToTotalEnergyRatioIndices[0] = 1;
    1910        1902 :             lfeToTotalEnergyRatioIndices[1] = usquant( log2LFEaverage, &xq, MCMASA_LFE_QLOW, MCMASA_LFE_DELTA, 8 );
    1911             : 
    1912        1902 :             if ( ivas_total_brate >= IVAS_24k4 ) /* Vector quantization is applied if bitrate >= 24.4 kbps */
    1913             :             {
    1914             :                 /* Remove scalar value from the vector*/
    1915        8885 :                 for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ )
    1916             :                 {
    1917        7108 :                     log2LFEratio[i] -= xq;
    1918             :                 }
    1919             : 
    1920             :                 /* Vector quantize residual with energy adaptive bit allocation */
    1921        1777 :                 switch ( lfeToTotalEnergyRatioIndices[1] )
    1922             :                 {
    1923         323 :                     case 0:
    1924             :                     case 1:
    1925         323 :                         VQLevels = 0;
    1926         323 :                         lfeAdaptiveVQBits = 0;
    1927         323 :                         break;
    1928         138 :                     case 2:
    1929         138 :                         VQLevels = 2;
    1930         138 :                         lfeAdaptiveVQBits = 1;
    1931         138 :                         break;
    1932          97 :                     case 3:
    1933          97 :                         VQLevels = 4;
    1934          97 :                         lfeAdaptiveVQBits = 2;
    1935          97 :                         break;
    1936         258 :                     case 4:
    1937         258 :                         VQLevels = 8;
    1938         258 :                         lfeAdaptiveVQBits = 3;
    1939         258 :                         break;
    1940         961 :                     default:
    1941         961 :                         VQLevels = 16;
    1942         961 :                         lfeAdaptiveVQBits = 4;
    1943             :                 }
    1944             : 
    1945        1777 :                 if ( VQLevels > 0 )
    1946             :                 {
    1947        1454 :                     lfeToTotalEnergyRatioIndices[2] = vquant( log2LFEratio, 0, xqv, McMASA_LFEGain_vectors, 4, VQLevels );
    1948             :                 }
    1949             :             }
    1950             :         }
    1951             :     }
    1952             : 
    1953             :     /* Write first LFE bit */
    1954       11680 :     lfeBitsWritten = 0;
    1955       11680 :     push_next_indice( hMetaData, lfeToTotalEnergyRatioIndices[0], 1 );
    1956       11680 :     lfeBitsWritten += 1;
    1957             : 
    1958       11680 :     if ( lfeToTotalEnergyRatioIndices[0] == 1 && ivas_total_brate >= IVAS_16k4 )
    1959             :     {
    1960             :         /* If bitrate >= 16.4kbit/s, send 1-bit on/off + 3-bit scalar */
    1961        1902 :         push_next_indice( hMetaData, lfeToTotalEnergyRatioIndices[1], 3 );
    1962        1902 :         lfeBitsWritten += 3;
    1963             : 
    1964             :         /*  If bitrate >= 24.4kbit/s, use adaptive 1 + (3.. 7) bit quantizer */
    1965        1902 :         if ( ivas_total_brate >= IVAS_24k4 )
    1966             :         {
    1967             :             /* Vector quantize residual with energy adaptive bit allocation */
    1968        1777 :             if ( lfeAdaptiveVQBits > 0 )
    1969             :             {
    1970        1454 :                 push_next_indice( hMetaData, lfeToTotalEnergyRatioIndices[2], lfeAdaptiveVQBits );
    1971        1454 :                 lfeBitsWritten += lfeAdaptiveVQBits;
    1972             :             }
    1973             :         }
    1974             :     }
    1975             : 
    1976       11680 :     return lfeBitsWritten;
    1977             : }
    1978             : 
    1979             : 
    1980             : /*-------------------------------------------------------------------*
    1981             :  * ivas_masa_enc_reconfigure()
    1982             :  *
    1983             :  * Reconfigure IVAS MASA encoder
    1984             :  *-------------------------------------------------------------------*/
    1985             : 
    1986       30626 : void ivas_masa_enc_reconfigure(
    1987             :     Encoder_Struct *st_ivas /* i/o: IVAS encoder structure */
    1988             : )
    1989             : {
    1990             :     int16_t n, tmp;
    1991             :     int16_t sce_id, cpe_id;
    1992             :     int32_t ivas_total_brate;
    1993             :     int32_t ism_total_brate;
    1994             : 
    1995       30626 :     ivas_total_brate = st_ivas->hEncoderConfig->ivas_total_brate;
    1996             : 
    1997       30626 :     ism_total_brate = 0;
    1998       30626 :     if ( st_ivas->hEncoderConfig->ivas_format == MASA_ISM_FORMAT && st_ivas->nSCE > 0 && ( st_ivas->ism_mode == ISM_MASA_MODE_DISC || st_ivas->ism_mode == ISM_MASA_MODE_PARAM_ONE_OBJ || st_ivas->ism_mode == ISM_MASA_MODE_MASA_ONE_OBJ ) )
    1999             :     {
    2000           0 :         for ( sce_id = 0; sce_id < st_ivas->nSCE; sce_id++ )
    2001             :         {
    2002           0 :             ism_total_brate += st_ivas->hSCE[sce_id]->element_brate;
    2003             :         }
    2004             :     }
    2005             : 
    2006       30626 :     if ( ivas_total_brate != st_ivas->hEncoderConfig->last_ivas_total_brate )
    2007             :     {
    2008        1934 :         for ( sce_id = 0; sce_id < st_ivas->nSCE; sce_id++ )
    2009             :         {
    2010         665 :             copy_encoder_config( st_ivas, st_ivas->hSCE[sce_id]->hCoreCoder[0], 0 );
    2011         665 :             st_ivas->hSCE[sce_id]->element_brate = ivas_total_brate / st_ivas->nchan_transport;
    2012         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() */
    2013             :         }
    2014             : 
    2015        1873 :         for ( cpe_id = 0; cpe_id < st_ivas->nCPE; cpe_id++ )
    2016             :         {
    2017         604 :             st_ivas->hCPE[cpe_id]->element_brate = ( ivas_total_brate / st_ivas->nchan_transport ) * CPE_CHANNELS;
    2018             : 
    2019             :             /* prepare bitstream buffers */
    2020        1812 :             for ( n = 0; n < CPE_CHANNELS; n++ )
    2021             :             {
    2022        1208 :                 copy_encoder_config( st_ivas, st_ivas->hCPE[cpe_id]->hCoreCoder[n], 0 );
    2023        1208 :                 st_ivas->hCPE[cpe_id]->hCoreCoder[n]->total_brate = st_ivas->hCPE[cpe_id]->element_brate / ( st_ivas->nCPE > 1 ? 1 : CPE_CHANNELS ); /* dummy initialization for getting right pointers initialization of input buffers in init_coder_ace_plus() */
    2024             :             }
    2025             : 
    2026         604 :             if ( ivas_total_brate - ism_total_brate < MIN_BRATE_MDCT_STEREO )
    2027             :             {
    2028         218 :                 st_ivas->hCPE[cpe_id]->element_mode = IVAS_CPE_DFT;
    2029             :             }
    2030             :             else
    2031             :             {
    2032         386 :                 st_ivas->hCPE[cpe_id]->element_mode = IVAS_CPE_MDCT;
    2033             :             }
    2034             :         }
    2035             : 
    2036        1269 :         ivas_masa_set_elements( 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 );
    2037             :     }
    2038             : 
    2039       30626 :     return;
    2040             : }
    2041             : 
    2042             : 
    2043             : /*-------------------------------------------------------------------*
    2044             :  * average_masa_metadata()
    2045             :  *
    2046             :  * Average MASA metadata frame subframe contents: applies aggregation over time
    2047             :  *-------------------------------------------------------------------*/
    2048             : 
    2049           0 : static void average_masa_metadata(
    2050             :     MASA_METADATA_FRAME *hMeta,
    2051             :     float energy[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS],
    2052             :     const SPHERICAL_GRID_DATA *Sph_Grid16,
    2053             :     const uint8_t useSphGrid )
    2054             : {
    2055             :     int16_t i, j, k;
    2056             :     float azi_rad, ele_rad;
    2057             :     uint8_t numDirections;
    2058             : 
    2059             :     /* use the nominal values without data-adaptivity */
    2060           0 :     numDirections = hMeta->descriptive_meta.numberOfDirections + 1;
    2061             : 
    2062             :     /* azi/ele/nrg into vectors for each sub-frame and band */
    2063           0 :     for ( i = 0; i < numDirections; i++ )
    2064             :     {
    2065           0 :         for ( k = 0; k < MASA_FREQUENCY_BANDS; k++ )
    2066             :         {
    2067             :             float x_sum, y_sum, z_sum, energy_sum, vec_len, spread_coh_sum, surr_coh_sum;
    2068             : 
    2069           0 :             x_sum = 0.0f;
    2070           0 :             y_sum = 0.0f;
    2071           0 :             z_sum = 0.0f;
    2072           0 :             energy_sum = 0.0f;
    2073           0 :             spread_coh_sum = 0.0f;
    2074           0 :             surr_coh_sum = 0.0f;
    2075           0 :             for ( j = 0; j < MAX_PARAM_SPATIAL_SUBFRAMES; j++ )
    2076             :             {
    2077           0 :                 azi_rad = hMeta->directional_meta[i].azimuth[j][k] / 180.0f * EVS_PI;
    2078           0 :                 ele_rad = hMeta->directional_meta[i].elevation[j][k] / 180.0f * EVS_PI;
    2079           0 :                 vec_len = hMeta->directional_meta[i].energy_ratio[j][k] * energy[j][k];
    2080             : 
    2081             :                 /* energy-weighted sum over subframes */
    2082           0 :                 x_sum += cosf( azi_rad ) * cosf( ele_rad ) * vec_len;
    2083           0 :                 y_sum += sinf( azi_rad ) * cosf( ele_rad ) * vec_len;
    2084           0 :                 z_sum += sinf( ele_rad ) * vec_len;
    2085             : 
    2086           0 :                 energy_sum += energy[j][k];
    2087             : 
    2088           0 :                 spread_coh_sum += hMeta->directional_meta[i].spread_coherence[j][k] * energy[j][k];
    2089           0 :                 if ( i == 0 )
    2090             :                 {
    2091             :                     /* this is in common metadata and not in each direction */
    2092           0 :                     surr_coh_sum += hMeta->common_meta.surround_coherence[j][k] * energy[j][k];
    2093             :                 }
    2094             :             }
    2095             : 
    2096             :             /* the data from the combined sub-frames is written into the first sub-frame band */
    2097           0 :             j = 0;
    2098           0 :             hMeta->directional_meta[i].azimuth[j][k] = atan2f( y_sum, x_sum ) / EVS_PI * 180.0f;
    2099           0 :             hMeta->directional_meta[i].elevation[j][k] = atan2f( z_sum, sqrtf( x_sum * x_sum + y_sum * y_sum ) ) / EVS_PI * 180.0f;
    2100           0 :             if ( useSphGrid == TRUE )
    2101             :             {
    2102           0 :                 hMeta->directional_meta[i].spherical_index[j][k] = index_theta_phi_16( &( hMeta->directional_meta[i].elevation[j][k] ),
    2103           0 :                                                                                        &( hMeta->directional_meta[i].azimuth[j][k] ), Sph_Grid16 );
    2104             :             }
    2105           0 :             vec_len = sqrtf( x_sum * x_sum + y_sum * y_sum + z_sum * z_sum );
    2106           0 :             hMeta->directional_meta[i].energy_ratio[j][k] = vec_len / ( energy_sum + EPSILON );
    2107             : 
    2108           0 :             hMeta->directional_meta[i].spread_coherence[j][k] = spread_coh_sum / ( energy_sum + EPSILON );
    2109           0 :             if ( i == 0 )
    2110             :             {
    2111           0 :                 hMeta->common_meta.surround_coherence[j][k] = surr_coh_sum / ( energy_sum + EPSILON );
    2112             :             }
    2113             : 
    2114             :             /* copy the same value to all subframes */
    2115           0 :             for ( j = 1; j < MAX_PARAM_SPATIAL_SUBFRAMES; j++ )
    2116             :             {
    2117           0 :                 hMeta->directional_meta[i].azimuth[j][k] = hMeta->directional_meta[i].azimuth[0][k];
    2118           0 :                 hMeta->directional_meta[i].elevation[j][k] = hMeta->directional_meta[i].elevation[0][k];
    2119           0 :                 hMeta->directional_meta[i].energy_ratio[j][k] = hMeta->directional_meta[i].energy_ratio[0][k];
    2120           0 :                 hMeta->directional_meta[i].spread_coherence[j][k] = hMeta->directional_meta[i].spread_coherence[0][k];
    2121           0 :                 if ( i == 0 )
    2122             :                 {
    2123           0 :                     hMeta->common_meta.surround_coherence[j][k] = hMeta->common_meta.surround_coherence[0][k];
    2124             :                 }
    2125             :             }
    2126             :         }
    2127             :     }
    2128             : 
    2129           0 :     for ( k = 0; k < MASA_FREQUENCY_BANDS; k++ )
    2130             :     {
    2131           0 :         for ( j = 0; j < MAX_PARAM_SPATIAL_SUBFRAMES; j++ )
    2132             :         {
    2133           0 :             if ( numDirections == 2 )
    2134             :             {
    2135           0 :                 hMeta->common_meta.diffuse_to_total_ratio[j][k] = max( 0.0f, 1.0f - hMeta->directional_meta[1].energy_ratio[j][k] - hMeta->directional_meta[0].energy_ratio[j][k] );
    2136             :             }
    2137             :             else
    2138             :             {
    2139           0 :                 hMeta->common_meta.diffuse_to_total_ratio[j][k] = max( 0.0f, 1.0f - hMeta->directional_meta[0].energy_ratio[j][k] );
    2140             :             }
    2141           0 :             hMeta->common_meta.remainder_to_total_ratio[j][k] = 0.0f;
    2142             :         }
    2143             :     }
    2144             : 
    2145           0 :     return;
    2146             : }
    2147             : 
    2148             : 
    2149             : /*-------------------------------------------------------------------*
    2150             :  * copy_masa_metadata_subframe()
    2151             :  *
    2152             :  * Copy MASA metadata frame subframe contents
    2153             :  *-------------------------------------------------------------------*/
    2154             : 
    2155      158504 : static void copy_masa_metadata_subframe(
    2156             :     const MASA_METADATA_HANDLE hMetaFrom, /* i  : MASA frame metdata to be copied      */
    2157             :     const uint8_t sfFrom,                 /* i  : subframe index of the copy source    */
    2158             :     MASA_METADATA_HANDLE hMetaTo,         /* o  : MASA frame metadata copy destination */
    2159             :     const uint8_t sfTo                    /* i  : subframe index of the copy target    */
    2160             : )
    2161             : {
    2162             :     uint8_t dir;
    2163             :     uint8_t band;
    2164             : 
    2165             :     /* directional metadata */
    2166      475512 :     for ( dir = 0; dir < MASA_MAXIMUM_DIRECTIONS; dir++ )
    2167             :     {
    2168     7925200 :         for ( band = 0; band < MASA_FREQUENCY_BANDS; band++ )
    2169             :         {
    2170     7608192 :             hMetaTo->directional_meta[dir].spherical_index[sfTo][band] = hMetaFrom->directional_meta[dir].spherical_index[sfFrom][band];
    2171             :         }
    2172      317008 :         mvr2r( hMetaFrom->directional_meta[dir].azimuth[sfFrom], hMetaTo->directional_meta[dir].azimuth[sfTo], MASA_FREQUENCY_BANDS );
    2173      317008 :         mvr2r( hMetaFrom->directional_meta[dir].elevation[sfFrom], hMetaTo->directional_meta[dir].elevation[sfTo], MASA_FREQUENCY_BANDS );
    2174      317008 :         mvr2r( hMetaFrom->directional_meta[dir].energy_ratio[sfFrom], hMetaTo->directional_meta[dir].energy_ratio[sfTo], MASA_FREQUENCY_BANDS );
    2175      317008 :         mvr2r( hMetaFrom->directional_meta[dir].spread_coherence[sfFrom], hMetaTo->directional_meta[dir].spread_coherence[sfTo], MASA_FREQUENCY_BANDS );
    2176             :     }
    2177             : 
    2178             :     /* common metadata */
    2179      158504 :     mvr2r( hMetaFrom->common_meta.diffuse_to_total_ratio[sfFrom], hMetaTo->common_meta.diffuse_to_total_ratio[sfTo], MASA_FREQUENCY_BANDS );
    2180      158504 :     mvr2r( hMetaFrom->common_meta.surround_coherence[sfFrom], hMetaTo->common_meta.surround_coherence[sfTo], MASA_FREQUENCY_BANDS );
    2181      158504 :     mvr2r( hMetaFrom->common_meta.remainder_to_total_ratio[sfFrom], hMetaTo->common_meta.remainder_to_total_ratio[sfTo], MASA_FREQUENCY_BANDS );
    2182             : 
    2183      158504 :     return;
    2184             : }
    2185             : 
    2186             : 
    2187             : /*-------------------------------------------------------------------*
    2188             :  * copy_masa_metadata()
    2189             :  *
    2190             :  * Copy MASA metada frame contents
    2191             :  *-------------------------------------------------------------------*/
    2192             : 
    2193       39626 : static void copy_masa_metadata(
    2194             :     const MASA_METADATA_HANDLE hMetaFrom, /* i  : MASA frame metadata to be copied     */
    2195             :     MASA_METADATA_HANDLE hMetaTo          /* o  : MASA frame metadata copy destination */
    2196             : )
    2197             : {
    2198             :     uint8_t sf, byte_idx;
    2199             : 
    2200             :     /* descriptive metadata */
    2201      356634 :     for ( byte_idx = 0; byte_idx < 8; byte_idx++ )
    2202             :     {
    2203      317008 :         hMetaTo->descriptive_meta.formatDescriptor[byte_idx] = hMetaFrom->descriptive_meta.formatDescriptor[byte_idx];
    2204             :     }
    2205             : 
    2206       39626 :     hMetaTo->descriptive_meta.numberOfDirections = hMetaFrom->descriptive_meta.numberOfDirections;
    2207       39626 :     hMetaTo->descriptive_meta.numberOfChannels = hMetaFrom->descriptive_meta.numberOfChannels;
    2208       39626 :     hMetaTo->descriptive_meta.sourceFormat = hMetaFrom->descriptive_meta.sourceFormat;
    2209       39626 :     hMetaTo->descriptive_meta.transportDefinition = hMetaFrom->descriptive_meta.transportDefinition;
    2210       39626 :     hMetaTo->descriptive_meta.channelAngle = hMetaFrom->descriptive_meta.channelAngle;
    2211       39626 :     hMetaTo->descriptive_meta.channelDistance = hMetaFrom->descriptive_meta.channelDistance;
    2212       39626 :     hMetaTo->descriptive_meta.channelLayout = hMetaFrom->descriptive_meta.channelLayout;
    2213             : 
    2214             :     /* directional and common metadata */
    2215      198130 :     for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    2216             :     {
    2217      158504 :         copy_masa_metadata_subframe( hMetaFrom, sf, hMetaTo, sf );
    2218             :     }
    2219             : 
    2220       39626 :     return;
    2221             : }
    2222             : 
    2223             : 
    2224             : /*-------------------------------------------------------------------*
    2225             :  * are_masa_subframes_similar()
    2226             :  *
    2227             :  * Compare the similarity of MASA metadata in two sub-frames
    2228             :  *-------------------------------------------------------------------*/
    2229             : 
    2230             : /* r: similarity decision */
    2231      175035 : static uint8_t are_masa_subframes_similar(
    2232             :     const MASA_METADATA_HANDLE frame1, /* i  : MASA metadata frame 1                      */
    2233             :     const uint8_t sf1_idx,             /* i  : index of the subframe of frame1 to inspect */
    2234             :     const MASA_METADATA_HANDLE frame2, /* i  : MASA metadata frame 2                      */
    2235             :     const uint8_t sf2_idx              /* i  : index of the subframe of frame2 to inspect */
    2236             : )
    2237             : {
    2238             :     uint8_t num_dir;
    2239             :     uint8_t dir;
    2240             :     uint8_t band_idx;
    2241             :     uint8_t sf_differ;
    2242             : 
    2243      175035 :     num_dir = frame1->descriptive_meta.numberOfDirections;
    2244      175035 :     dir = 0;
    2245      175035 :     band_idx = 0;
    2246      175035 :     sf_differ = FALSE;
    2247             : 
    2248      175035 :     if ( num_dir != frame2->descriptive_meta.numberOfDirections )
    2249             :     {
    2250           0 :         sf_differ = TRUE;
    2251             :     }
    2252             :     else
    2253             :     {
    2254             :         /* check per-direction metadata */
    2255      175035 :         dir = 0;
    2256      175035 :         band_idx = 0;
    2257             : 
    2258      360870 :         while ( ( sf_differ == FALSE ) && ( dir <= num_dir ) )
    2259             :         {
    2260      185835 :             band_idx = 0;
    2261     1244235 :             while ( ( sf_differ == FALSE ) && ( band_idx < MASA_FREQUENCY_BANDS ) )
    2262             :             {
    2263             :                 float azi_dif;
    2264     1200135 :                 azi_dif = fabsf( frame1->directional_meta[dir].azimuth[sf1_idx][band_idx] - frame2->directional_meta[dir].azimuth[sf2_idx][band_idx] );
    2265     1200135 :                 azi_dif = azi_dif > 180.0f ? 360.0f - azi_dif : azi_dif;
    2266             : 
    2267     1200135 :                 if ( azi_dif > MASA_ANGLE_TOLERANCE )
    2268             :                 {
    2269      139220 :                     sf_differ = TRUE;
    2270      139220 :                     break;
    2271             :                 }
    2272             : 
    2273     1060915 :                 if ( fabsf( frame1->directional_meta[dir].elevation[sf1_idx][band_idx] - frame2->directional_meta[dir].elevation[sf2_idx][band_idx] ) > MASA_ANGLE_TOLERANCE )
    2274             :                 {
    2275        2496 :                     sf_differ = TRUE;
    2276        2496 :                     break;
    2277             :                 }
    2278             : 
    2279     1058419 :                 if ( fabsf( frame1->directional_meta[dir].energy_ratio[sf1_idx][band_idx] - frame2->directional_meta[dir].energy_ratio[sf2_idx][band_idx] ) > MASA_RATIO_TOLERANCE )
    2280             :                 {
    2281          19 :                     sf_differ = TRUE;
    2282          19 :                     break;
    2283             :                 }
    2284             : 
    2285     1058400 :                 if ( fabsf( frame1->directional_meta[dir].spread_coherence[sf1_idx][band_idx] - frame2->directional_meta[dir].spread_coherence[sf2_idx][band_idx] ) > MASA_COHERENCE_TOLERANCE )
    2286             :                 {
    2287           0 :                     sf_differ = TRUE;
    2288           0 :                     break;
    2289             :                 }
    2290             : 
    2291     1058400 :                 band_idx++;
    2292             :             }
    2293      185835 :             dir++;
    2294             :         }
    2295             : 
    2296             :         /* check the common metadata */
    2297      175035 :         while ( ( sf_differ == FALSE ) && ( band_idx < MASA_FREQUENCY_BANDS ) )
    2298             :         {
    2299           0 :             if ( fabsf( frame1->common_meta.surround_coherence[sf1_idx][band_idx] - frame2->common_meta.surround_coherence[sf2_idx][band_idx] ) > MASA_COHERENCE_TOLERANCE )
    2300             :             {
    2301           0 :                 sf_differ = TRUE;
    2302           0 :                 break;
    2303             :             }
    2304             : 
    2305           0 :             band_idx++;
    2306             :         }
    2307             :     }
    2308             : 
    2309      175035 :     if ( sf_differ )
    2310             :     {
    2311      141735 :         return FALSE;
    2312             :     }
    2313             :     else
    2314             :     {
    2315       33300 :         return TRUE;
    2316             :     }
    2317             : }
    2318             : 
    2319             : 
    2320             : /*-------------------------------------------------------------------*
    2321             :  * detect_framing_async()
    2322             :  *
    2323             :  * Compare the similarity of MASA metadata in two sub-frames
    2324             :  * Analysis result is stored in hMasa->data.sync_state, and
    2325             :  * potentially hMasa->masaMetadata is modified
    2326             :  *-------------------------------------------------------------------*/
    2327             : 
    2328       39626 : static void detect_framing_async(
    2329             :     MASA_ENCODER_HANDLE hMasa /* i/o: MASA encoder structure */
    2330             : )
    2331             : {
    2332             :     MASA_METADATA_HANDLE current_meta;
    2333             :     MASA_METADATA_HANDLE previous_meta;
    2334             :     MASA_SYNC_HANDLE sync_state;
    2335             :     MASA_FRAME_MODE frame_mode;
    2336             :     uint8_t n_sim_start, n_sim_stop, sf_idx;
    2337             :     uint8_t found_offset;
    2338             : 
    2339       39626 :     current_meta = &( hMasa->masaMetadata );  /* metadata from current frame */
    2340       39626 :     sync_state = &( hMasa->data.sync_state ); /* synchronization structure */
    2341       39626 :     previous_meta = &( sync_state->previous_metadata );
    2342             : 
    2343             :     /* check current frame, how many are similar from the start and from the end */
    2344       39626 :     n_sim_start = 1;
    2345       56276 :     for ( sf_idx = n_sim_start; sf_idx < MAX_PARAM_SPATIAL_SUBFRAMES; sf_idx++ )
    2346             :     {
    2347       50726 :         if ( are_masa_subframes_similar( current_meta, 0, current_meta, sf_idx ) == TRUE )
    2348             :         {
    2349       16650 :             n_sim_start = sf_idx + 1;
    2350             :         }
    2351             :         else
    2352             :         {
    2353       34076 :             break;
    2354             :         }
    2355             :     }
    2356             : 
    2357             :     /* number of similar sub-frames starting from the end of the frame */
    2358       39626 :     if ( n_sim_start == MAX_PARAM_SPATIAL_SUBFRAMES ) /* shortcut */
    2359             :     {
    2360        5550 :         n_sim_stop = n_sim_start;
    2361             :     }
    2362             :     else
    2363             :     {
    2364       34076 :         n_sim_stop = 1;
    2365       34076 :         for ( sf_idx = 2; sf_idx < MAX_PARAM_SPATIAL_SUBFRAMES; sf_idx++ )
    2366             :         {
    2367             :             /* we need to check only the two middle sub-frames, as all being the same would have taken the shortcut above */
    2368       34076 :             if ( are_masa_subframes_similar( current_meta, MAX_PARAM_SPATIAL_SUBFRAMES - 1, current_meta, MAX_PARAM_SPATIAL_SUBFRAMES - sf_idx ) == TRUE )
    2369             :             {
    2370           0 :                 n_sim_stop = sf_idx;
    2371             :             }
    2372             :             else
    2373             :             {
    2374       34076 :                 break;
    2375             :             }
    2376             :         }
    2377             :     }
    2378             : 
    2379       39626 :     frame_mode = MASA_FRAME_4SF; /* default mode: 4sf */
    2380       39626 :     if ( sync_state->prev_offset > MAX_PARAM_SPATIAL_SUBFRAMES - 2 )
    2381             :     {
    2382             :         /* earlier offset was large => reset the offset */
    2383           0 :         found_offset = 0;
    2384             :     }
    2385             :     else
    2386             :     {
    2387             :         /* keep previous offset unless something else is found. alternatively, we could reset always */
    2388       39626 :         found_offset = sync_state->prev_offset;
    2389             :     }
    2390             : 
    2391       39626 :     if ( ( n_sim_start == MAX_PARAM_SPATIAL_SUBFRAMES ) && ( n_sim_stop == MAX_PARAM_SPATIAL_SUBFRAMES ) )
    2392             :     {
    2393             :         /* full frame consists of similar sub-frames */
    2394        5550 :         frame_mode = MASA_FRAME_1SF;
    2395        5550 :         if ( ( sync_state->prev_sim_stop != 0 ) && ( are_masa_subframes_similar( current_meta, 0, previous_meta, MAX_PARAM_SPATIAL_SUBFRAMES - 1 ) == TRUE ) )
    2396             :         {
    2397             :             /* > 4 sub-frames of similar data */
    2398           0 :             if ( sync_state->prev_sim_stop < 3 )
    2399             :             {
    2400             :                 /* can nicely align the framing with the earlier data and a small offset */
    2401           0 :                 found_offset = sync_state->prev_sim_stop;
    2402             :             }
    2403             :             else
    2404             :             {
    2405             :                 /* too many similar sub-frames to determine the offset accurately => keep earlier value */
    2406           0 :                 found_offset = sync_state->prev_offset;
    2407             :             }
    2408             :         }
    2409             :         else
    2410             :         {
    2411             :             /* earlier window was different => reset the offset */
    2412        5550 :             found_offset = 0;
    2413             :         }
    2414             :     }
    2415       34076 :     else if ( n_sim_stop == 3 )
    2416             :     {
    2417             :         /* first sub-frame different that the rest 3
    2418             :                        => make a risky guess that the future sf would be the same too and we're in an offset case */
    2419           0 :         frame_mode = MASA_FRAME_1SF;
    2420           0 :         found_offset = 3;
    2421             :     }
    2422       34076 :     else if ( ( sync_state->prev_sim_stop > 0 ) && ( are_masa_subframes_similar( current_meta, 0, previous_meta, MAX_PARAM_SPATIAL_SUBFRAMES - 1 ) == TRUE ) )
    2423             :     {
    2424             :         /* seeing data similar to past */
    2425           0 :         if ( ( n_sim_start > 1 ) && ( n_sim_start + sync_state->prev_sim_stop >= MAX_PARAM_SPATIAL_SUBFRAMES ) )
    2426             :         {
    2427             :             /* with the past, would have at least one long frame similar subframes */
    2428           0 :             frame_mode = MASA_FRAME_1SF;
    2429             : 
    2430           0 :             if ( sync_state->prev_offset == 0 )
    2431             :             {
    2432           0 :                 found_offset = min( 2, sync_state->prev_sim_stop );
    2433             :             }
    2434             :             else
    2435             :             {
    2436           0 :                 found_offset = sync_state->prev_offset;
    2437             :             }
    2438             :         }
    2439             :     }
    2440             : 
    2441             :     /* keep the original contents of the frame, but then perform interpolation later */
    2442             :     /* just copy current frame to storage */
    2443       39626 :     copy_masa_metadata( current_meta, previous_meta );
    2444             : 
    2445       39626 :     sync_state->prev_sim_stop = n_sim_stop;
    2446       39626 :     sync_state->prev_offset = found_offset;
    2447       39626 :     sync_state->frame_mode = frame_mode;
    2448             : 
    2449       39626 :     return;
    2450             : }
    2451             : 
    2452             : 
    2453             : /*-------------------------------------------------------------------*
    2454             :  * masa_metadata_direction_alignment()
    2455             :  *
    2456             :  * In 2dir MASA metadata, determine the ordering of the directional
    2457             :  * fields such that the azi/ele change across time is minimized.
    2458             :  *-------------------------------------------------------------------*/
    2459             : 
    2460       39626 : static void masa_metadata_direction_alignment(
    2461             :     MASA_ENCODER_HANDLE hMasa /* i/o: MASA encoder handle */
    2462             : )
    2463             : {
    2464             :     uint8_t band, n_dirs;
    2465             :     MASA_DIR_ALIGN_HANDLE hAlignState;
    2466             :     MASA_METADATA_HANDLE hMeta;
    2467             : 
    2468       39626 :     hAlignState = &( hMasa->data.dir_align_state );
    2469       39626 :     hMeta = &( hMasa->masaMetadata );
    2470             : 
    2471       39626 :     n_dirs = hMeta->descriptive_meta.numberOfDirections + 1; /* 1-based */
    2472      990650 :     for ( band = 0; band < MASA_FREQUENCY_BANDS; band++ )
    2473             :     {
    2474             :         uint8_t sf;
    2475             :         float diff_swap, diff_no_swap;
    2476             : 
    2477             :         /* trade 2*(cos+sin) against storing the values between frames */
    2478             :         float prev_ele_dir1_sin, prev_ele_dir2_sin;
    2479             :         float prev_ele_dir1_cos, prev_ele_dir2_cos;
    2480             : 
    2481      951024 :         prev_ele_dir1_sin = sinf( hAlignState->previous_ele_dir1[band] );
    2482      951024 :         prev_ele_dir2_sin = sinf( hAlignState->previous_ele_dir2[band] );
    2483             : 
    2484      951024 :         prev_ele_dir1_cos = cosf( hAlignState->previous_ele_dir1[band] );
    2485      951024 :         prev_ele_dir2_cos = cosf( hAlignState->previous_ele_dir2[band] );
    2486             : 
    2487     4755120 :         for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    2488             :         {
    2489             :             float azi_rad1, ele_rad1;
    2490             :             float azi_rad2, ele_rad2;
    2491             :             float cos_ele1, cos_ele2;
    2492             :             float sin_ele1, sin_ele2;
    2493             : 
    2494     3804096 :             azi_rad1 = hMeta->directional_meta[0].azimuth[sf][band] * PI_OVER_180;
    2495     3804096 :             ele_rad1 = hMeta->directional_meta[0].elevation[sf][band] * PI_OVER_180;
    2496             : 
    2497     3804096 :             if ( n_dirs > 1 )
    2498             :             {
    2499      950400 :                 azi_rad2 = hMeta->directional_meta[1].azimuth[sf][band] * PI_OVER_180;
    2500      950400 :                 ele_rad2 = hMeta->directional_meta[1].elevation[sf][band] * PI_OVER_180;
    2501             : 
    2502             :                 /* quick checks to detect constant data and earlier flip */
    2503      950400 :                 if ( fabsf( azi_rad1 - hAlignState->previous_azi_dir1[band] ) < EPSILON &&
    2504       95058 :                      fabsf( azi_rad2 - hAlignState->previous_azi_dir2[band] ) < EPSILON &&
    2505       91800 :                      fabsf( ele_rad1 - hAlignState->previous_ele_dir1[band] ) < EPSILON &&
    2506       91800 :                      fabsf( ele_rad2 - hAlignState->previous_ele_dir2[band] ) < EPSILON )
    2507             :                 {
    2508       91800 :                     diff_swap = 1.0f;
    2509       91800 :                     diff_no_swap = 0.0f;
    2510             :                     /* cached values that will be used for the short-cuts and over-written by the real computations, if done */
    2511       91800 :                     sin_ele1 = prev_ele_dir1_sin;
    2512       91800 :                     sin_ele2 = prev_ele_dir2_sin;
    2513       91800 :                     cos_ele1 = prev_ele_dir1_cos;
    2514       91800 :                     cos_ele2 = prev_ele_dir2_cos;
    2515             :                 }
    2516      858600 :                 else if ( fabsf( azi_rad1 - hAlignState->previous_azi_dir2[band] ) < EPSILON &&
    2517       38346 :                           fabsf( azi_rad2 - hAlignState->previous_azi_dir1[band] ) < EPSILON &&
    2518       37800 :                           fabsf( ele_rad1 - hAlignState->previous_ele_dir2[band] ) < EPSILON &&
    2519       37800 :                           fabsf( ele_rad2 - hAlignState->previous_ele_dir1[band] ) < EPSILON )
    2520             :                 {
    2521       37800 :                     diff_swap = 0.0f;
    2522       37800 :                     diff_no_swap = 1.0f;
    2523             :                     /* cached values that will be used for the short-cuts and over-written by the real computations, if done */
    2524       37800 :                     sin_ele1 = prev_ele_dir2_sin;
    2525       37800 :                     sin_ele2 = prev_ele_dir1_sin;
    2526       37800 :                     cos_ele1 = prev_ele_dir2_cos;
    2527       37800 :                     cos_ele2 = prev_ele_dir1_cos;
    2528             :                 }
    2529             :                 else
    2530             :                 {
    2531             :                     /* angular distance of the two vectors */
    2532             :                     /* pre-compute values for re-use */
    2533      820800 :                     sin_ele1 = sinf( ele_rad1 );
    2534      820800 :                     sin_ele2 = sinf( ele_rad2 );
    2535             : 
    2536      820800 :                     cos_ele1 = cosf( ele_rad1 );
    2537      820800 :                     cos_ele2 = cosf( ele_rad2 );
    2538             : 
    2539      820800 :                     diff_no_swap = acosf( cos_ele1 * prev_ele_dir1_cos * cosf( azi_rad1 - hAlignState->previous_azi_dir1[band] ) + sin_ele1 * prev_ele_dir1_sin ) +
    2540      820800 :                                    acosf( cos_ele2 * prev_ele_dir2_cos * cosf( azi_rad2 - hAlignState->previous_azi_dir2[band] ) + sin_ele2 * prev_ele_dir2_sin );
    2541             : 
    2542      820800 :                     diff_swap = acosf( cos_ele1 * prev_ele_dir2_cos * cosf( azi_rad1 - hAlignState->previous_azi_dir2[band] ) + sin_ele1 * prev_ele_dir2_sin ) +
    2543      820800 :                                 acosf( cos_ele2 * prev_ele_dir1_cos * cosf( azi_rad2 - hAlignState->previous_azi_dir1[band] ) + sin_ele2 * prev_ele_dir1_sin );
    2544             :                 }
    2545             :             }
    2546             :             else
    2547             :             {
    2548             :                 /* 1dir */
    2549     2853696 :                 sin_ele1 = sinf( ele_rad1 );
    2550     2853696 :                 cos_ele1 = cosf( ele_rad1 );
    2551             : 
    2552     2853696 :                 azi_rad2 = 0.0f;
    2553     2853696 :                 ele_rad2 = 0.0f;
    2554             : 
    2555     2853696 :                 sin_ele2 = 0.0f; /* sin(0) */
    2556     2853696 :                 cos_ele2 = 1.0f; /* cos(0) */
    2557             : 
    2558     2853696 :                 diff_swap = 1.0f;
    2559     2853696 :                 diff_no_swap = 0.0f;
    2560             :             }
    2561             : 
    2562     3804096 :             if ( n_dirs > 1 && diff_no_swap > diff_swap )
    2563      121788 :             {
    2564             :                 /* swap the metadata of the two directions in this TF-tile */
    2565             :                 float tmp_val;
    2566             :                 uint16_t tmp_int_val;
    2567      121788 :                 tmp_val = hMeta->directional_meta[0].azimuth[sf][band];
    2568      121788 :                 hMeta->directional_meta[0].azimuth[sf][band] = hMeta->directional_meta[1].azimuth[sf][band];
    2569      121788 :                 hMeta->directional_meta[1].azimuth[sf][band] = tmp_val;
    2570             : 
    2571      121788 :                 tmp_val = hMeta->directional_meta[0].elevation[sf][band];
    2572      121788 :                 hMeta->directional_meta[0].elevation[sf][band] = hMeta->directional_meta[1].elevation[sf][band];
    2573      121788 :                 hMeta->directional_meta[1].elevation[sf][band] = tmp_val;
    2574      121788 :                 tmp_int_val = hMeta->directional_meta[0].spherical_index[sf][band];
    2575      121788 :                 hMeta->directional_meta[0].spherical_index[sf][band] = hMeta->directional_meta[1].spherical_index[sf][band];
    2576      121788 :                 hMeta->directional_meta[1].spherical_index[sf][band] = tmp_int_val;
    2577      121788 :                 tmp_val = hMeta->directional_meta[0].energy_ratio[sf][band];
    2578      121788 :                 hMeta->directional_meta[0].energy_ratio[sf][band] = hMeta->directional_meta[1].energy_ratio[sf][band];
    2579      121788 :                 hMeta->directional_meta[1].energy_ratio[sf][band] = tmp_val;
    2580             : 
    2581      121788 :                 tmp_val = hMeta->directional_meta[0].spread_coherence[sf][band];
    2582      121788 :                 hMeta->directional_meta[0].spread_coherence[sf][band] = hMeta->directional_meta[1].spread_coherence[sf][band];
    2583      121788 :                 hMeta->directional_meta[1].spread_coherence[sf][band] = tmp_val;
    2584             : 
    2585      121788 :                 hAlignState->previous_azi_dir1[band] = azi_rad2;
    2586      121788 :                 hAlignState->previous_ele_dir1[band] = ele_rad2;
    2587             : 
    2588      121788 :                 hAlignState->previous_azi_dir2[band] = azi_rad1;
    2589      121788 :                 hAlignState->previous_ele_dir2[band] = ele_rad1;
    2590             : 
    2591      121788 :                 prev_ele_dir1_cos = cos_ele2;
    2592      121788 :                 prev_ele_dir1_sin = sin_ele2;
    2593             : 
    2594      121788 :                 prev_ele_dir2_cos = cos_ele1;
    2595      121788 :                 prev_ele_dir2_sin = sin_ele1;
    2596             :             }
    2597             :             else
    2598             :             {
    2599     3682308 :                 hAlignState->previous_azi_dir1[band] = azi_rad1;
    2600     3682308 :                 hAlignState->previous_ele_dir1[band] = ele_rad1;
    2601             : 
    2602     3682308 :                 hAlignState->previous_azi_dir2[band] = azi_rad2;
    2603     3682308 :                 hAlignState->previous_ele_dir2[band] = ele_rad2;
    2604             : 
    2605     3682308 :                 prev_ele_dir1_cos = cos_ele1;
    2606     3682308 :                 prev_ele_dir1_sin = sin_ele1;
    2607             : 
    2608     3682308 :                 prev_ele_dir2_cos = cos_ele2;
    2609     3682308 :                 prev_ele_dir2_sin = sin_ele2;
    2610             :             }
    2611             :         } /* sf */
    2612             :     }     /* band */
    2613             : 
    2614       39626 :     return;
    2615             : }
    2616             : 
    2617             : 
    2618             : /*-------------------------------------------------------------------*
    2619             :  * ivas_merge_masa_metadata()
    2620             :  *
    2621             :  *
    2622             :  *-------------------------------------------------------------------*/
    2623             : 
    2624        3996 : void ivas_merge_masa_metadata(
    2625             :     MASA_ENCODER_HANDLE hMasa,           /* i/o: MASA enc handle. source for MASA metadata and combined metadata will be here */
    2626             :     OMASA_SPATIAL_META_HANDLE hOMasaMeta /* i  : ISM-object metadata to be merged with the MASA metadata                      */
    2627             : )
    2628             : {
    2629             :     int16_t sf, band;
    2630             :     uint8_t numCodingBands;
    2631             :     uint8_t numDirections;
    2632             :     uint8_t numSf;
    2633             :     MASA_METADATA_HANDLE hMeta;
    2634             :     float energyTimesRatioISM;
    2635             :     float energyTimesRatioMASA[2];
    2636             :     float total_diff_nrg;
    2637             :     float eneBand;
    2638             :     float energyMerged[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
    2639        3996 :     OMASA_ENCODER_ENERGY_HANDLE hOmasaEnergy = hMasa->data.hOmasaData->hOmasaEnergy;
    2640             : 
    2641        3996 :     numCodingBands = hMasa->config.numCodingBands;
    2642        3996 :     numDirections = hMasa->config.numberOfDirections;
    2643        3996 :     numSf = hMasa->config.joinedSubframes == TRUE ? 1 : MAX_PARAM_SPATIAL_SUBFRAMES;
    2644        3996 :     hMeta = &( hMasa->masaMetadata );
    2645             : 
    2646       19980 :     for ( sf = 0; sf < numSf; sf++ )
    2647             :     {
    2648      396000 :         for ( band = 0; band < numCodingBands; band++ )
    2649             :         {
    2650             :             int16_t merge_dest;
    2651             :             float dir_sum;
    2652             :             uint8_t band_n_dirs;
    2653      380016 :             if ( numDirections == 1 || ( numDirections == 2 && hMasa->data.twoDirBands[band] == 0 ) )
    2654             :             {
    2655      380016 :                 band_n_dirs = 1;
    2656             :             }
    2657             :             else
    2658             :             {
    2659           0 :                 band_n_dirs = 2;
    2660             :             }
    2661             : 
    2662             :             /* Compute energies */
    2663      380016 :             eneBand = hMasa->data.energy[sf][band];
    2664      380016 :             energyMerged[sf][band] = eneBand + hOmasaEnergy->energy_ism[sf][band];
    2665             : 
    2666             :             /* Compute weights */
    2667      380016 :             energyTimesRatioMASA[0] = eneBand * hMeta->directional_meta[0].energy_ratio[sf][band];
    2668      380016 :             if ( band_n_dirs == 2 )
    2669             :             {
    2670           0 :                 energyTimesRatioMASA[1] = eneBand * hMeta->directional_meta[1].energy_ratio[sf][band];
    2671             :             }
    2672             :             else
    2673             :             {
    2674      380016 :                 energyTimesRatioMASA[1] = 0.0f;
    2675             :             }
    2676             : 
    2677             :             /* target is original MASA diffuseness */
    2678      380016 :             total_diff_nrg = eneBand * hMeta->common_meta.diffuse_to_total_ratio[sf][band];
    2679             : 
    2680             :             /* criterion is mean of ISM ratio and new ratio */
    2681      380016 :             energyTimesRatioISM = ( hOMasaMeta->directional_meta[0].energy_ratio[sf][band] + ( 1.0f - total_diff_nrg / ( EPSILON + eneBand + hOmasaEnergy->energy_ism[sf][band] ) ) ) / 2.0f * hMasa->data.hOmasaData->hOmasaEnergy->energy_ism[sf][band];
    2682             : 
    2683             :             /* Determine combined metadata based on the weights */
    2684      380016 :             merge_dest = -1;
    2685      380016 :             if ( ( band_n_dirs == 1 && energyTimesRatioMASA[0] < energyTimesRatioISM ) ||
    2686           0 :                  ( band_n_dirs == 2 && energyTimesRatioMASA[0] < energyTimesRatioMASA[1] && energyTimesRatioMASA[0] < energyTimesRatioISM ) )
    2687             :             {
    2688             :                 /* 1dir and ISM the most energetic, or 2dir and ISM the more energetic than MASA1 */
    2689      155924 :                 merge_dest = 0;
    2690             :             }
    2691      224092 :             else if ( band_n_dirs == 2 && energyTimesRatioMASA[1] <= energyTimesRatioMASA[0] && energyTimesRatioMASA[1] < energyTimesRatioISM )
    2692             :             {
    2693             :                 /* 2dir and ISM the most energetic and MASA2 the least energetic */
    2694           0 :                 merge_dest = 1;
    2695             :             }
    2696             : 
    2697      380016 :             if ( merge_dest >= 0 ) /* replace one MASA with ISM */
    2698             :             {
    2699      155924 :                 hMeta->directional_meta[merge_dest].azimuth[sf][band] = hOMasaMeta->directional_meta[0].azimuth[sf][band];
    2700      155924 :                 hMeta->directional_meta[merge_dest].elevation[sf][band] = hOMasaMeta->directional_meta[0].elevation[sf][band];
    2701             : 
    2702             :                 /* limit with the earlier direct-energy ratio */
    2703      155924 :                 dir_sum = 1.0f - total_diff_nrg / ( EPSILON + eneBand + hOmasaEnergy->energy_ism[sf][band] );                                        /* new dir ratio */
    2704      155924 :                 hMeta->directional_meta[merge_dest].energy_ratio[sf][band] = min( dir_sum, hOMasaMeta->directional_meta[0].energy_ratio[sf][band] ); /* clip with original ISM dir */
    2705      155924 :                 hMeta->common_meta.diffuse_to_total_ratio[sf][band] = 1.0f - hMeta->directional_meta[merge_dest].energy_ratio[sf][band];
    2706             : 
    2707      155924 :                 if ( hMasa->config.useCoherence )
    2708             :                 {
    2709           0 :                     hMeta->directional_meta[merge_dest].spread_coherence[sf][band] = hOMasaMeta->directional_meta[0].spread_coherence[sf][band];
    2710           0 :                     hMeta->common_meta.surround_coherence[sf][band] = hOMasaMeta->common_meta.surround_coherence[sf][band];
    2711             :                 }
    2712             : 
    2713             :                 /* recompute direct energy ratios to match the diffuse ratio */
    2714             :                 float direct_quota, direct_scaler;
    2715      155924 :                 direct_quota = 1.0f - hMeta->common_meta.diffuse_to_total_ratio[sf][band];
    2716      155924 :                 if ( band_n_dirs == 1 )
    2717             :                 {
    2718      155924 :                     hMeta->directional_meta[0].energy_ratio[sf][band] = direct_quota;
    2719             :                 }
    2720             :                 else
    2721             :                 {
    2722           0 :                     dir_sum = hMeta->directional_meta[0].energy_ratio[sf][band] + hMeta->directional_meta[1].energy_ratio[sf][band];
    2723           0 :                     direct_scaler = direct_quota / ( EPSILON + dir_sum );
    2724           0 :                     hMeta->directional_meta[0].energy_ratio[sf][band] *= direct_scaler;
    2725           0 :                     hMeta->directional_meta[1].energy_ratio[sf][band] *= direct_scaler;
    2726             :                 }
    2727             :             }
    2728             :         }
    2729             :     }
    2730             : 
    2731       19980 :     for ( sf = 0; sf < numSf; sf++ )
    2732             :     {
    2733      396000 :         for ( band = 0; band < numCodingBands; band++ )
    2734             :         {
    2735      380016 :             hMasa->data.energy[sf][band] = energyMerged[sf][band];
    2736             :         }
    2737             :     }
    2738             : 
    2739        3996 :     return;
    2740             : }
    2741             : 
    2742             : 
    2743       30442 : static void quantize_ratio_ism_vector(
    2744             :     const float *ratio_ism,
    2745             :     int16_t *idx,
    2746             :     const int16_t nchan_ism,
    2747             :     const float masa_to_total_energy_ratio,
    2748             :     const int16_t idx_sep_object )
    2749             : {
    2750             :     int16_t i, j, best_i, best_i2;
    2751             :     float dist, div, tmp, dist2, best_dist;
    2752             :     int16_t part_idx_sum, max_sum_idx;
    2753             :     float ratio_ism_loc[MAX_NUM_OBJECTS];
    2754             :     int16_t no_ism_loc;
    2755             : 
    2756       30442 :     max_sum_idx = ( 1 << PARAM_ISM_POW_RATIO_NBITS ) - 1;
    2757             : 
    2758       30442 :     if ( idx_sep_object > -1 )
    2759             :     {
    2760       30442 :         if ( ratio_ism[idx_sep_object] < 1.0f / (float) ( max_sum_idx ) )
    2761             :         {
    2762             :             /* take it out from quantize function  */
    2763       28834 :             mvr2r( ratio_ism, ratio_ism_loc, idx_sep_object );
    2764       28834 :             mvr2r( &ratio_ism[idx_sep_object + 1], &ratio_ism_loc[idx_sep_object], nchan_ism - idx_sep_object - 1 );
    2765       28834 :             no_ism_loc = nchan_ism - 1;
    2766             :         }
    2767             :         else
    2768             :         {
    2769        1608 :             no_ism_loc = nchan_ism;
    2770        1608 :             mvr2r( ratio_ism, ratio_ism_loc, nchan_ism );
    2771             :         }
    2772             :     }
    2773             :     else
    2774             :     {
    2775           0 :         no_ism_loc = nchan_ism;
    2776           0 :         mvr2r( ratio_ism, ratio_ism_loc, nchan_ism );
    2777             :     }
    2778             : 
    2779       30442 :     if ( nchan_ism > 1 )
    2780             :     {
    2781       30442 :         if ( masa_to_total_energy_ratio >= MASA2TOTAL_THR )
    2782             :         {
    2783        3599 :             distribute_evenly_ism( idx, max_sum_idx, nchan_ism );
    2784             :         }
    2785             :         else
    2786             :         {
    2787       26843 :             if ( no_ism_loc > 1 )
    2788             :             {
    2789             : 
    2790       26132 :                 dist = 0.0f;
    2791       26132 :                 div = 1.0f / (float) ( max_sum_idx );
    2792             : 
    2793       26132 :                 part_idx_sum = 0;
    2794             : 
    2795       95141 :                 for ( i = 0; i < no_ism_loc; i++ )
    2796             :                 {
    2797       69009 :                     idx[i] = (int16_t) ( ( ratio_ism_loc[i] ) * ( max_sum_idx ) );
    2798       69009 :                     part_idx_sum += idx[i];
    2799             : 
    2800       69009 :                     tmp = ( ratio_ism_loc[i] - ( idx[i] * div ) );
    2801       69009 :                     dist += ( tmp * tmp );
    2802             :                 }
    2803             : 
    2804       26132 :                 best_dist = dist;
    2805       26132 :                 best_i2 = -1;
    2806       54113 :                 while ( part_idx_sum < max_sum_idx )
    2807             :                 {
    2808       27981 :                     best_i = -1;
    2809             :                     /* check which index to increase by 1 for a possible improvement */
    2810             : 
    2811      102659 :                     for ( i = 0; i < no_ism_loc; i++ )
    2812             :                     {
    2813       74678 :                         idx[i]++;
    2814       74678 :                         dist2 = 0.0f;
    2815             : 
    2816      282058 :                         for ( j = 0; j < no_ism_loc; j++ )
    2817             :                         {
    2818      207380 :                             tmp = ( ratio_ism_loc[i] - ( idx[i] * div ) );
    2819      207380 :                             dist2 += ( tmp * tmp );
    2820             :                         }
    2821             : 
    2822       74678 :                         if ( dist2 < best_dist )
    2823             :                         {
    2824       22961 :                             best_i2 = best_i;
    2825       22961 :                             best_i = i;
    2826       22961 :                             best_dist = dist2;
    2827             :                         }
    2828       74678 :                         idx[i]--;
    2829             :                     }
    2830       27981 :                     if ( best_i > -1 )
    2831             :                     {
    2832       21753 :                         idx[best_i]++;
    2833       21753 :                         part_idx_sum++;
    2834             :                     }
    2835             :                     else
    2836             :                     {
    2837        6228 :                         if ( best_i2 > -1 )
    2838             :                         {
    2839        1047 :                             idx[best_i2]++;
    2840        1047 :                             part_idx_sum++;
    2841             :                         }
    2842             :                         else
    2843             :                         {
    2844        5181 :                             idx[no_ism_loc - 1] += max_sum_idx - part_idx_sum;
    2845        5181 :                             part_idx_sum = max_sum_idx;
    2846             :                         }
    2847             :                     }
    2848             :                 }
    2849       26132 :                 assert( sum_s( idx, no_ism_loc ) == max_sum_idx );
    2850             :             }
    2851             :             else
    2852             :             {
    2853         711 :                 idx[0] = max_sum_idx;
    2854             :             }
    2855             : 
    2856       26843 :             if ( no_ism_loc < nchan_ism )
    2857             :             {
    2858             :                 /*  insert back the ratio of the separated object  */
    2859       70942 :                 for ( i = nchan_ism - 1; i > idx_sep_object; i-- )
    2860             :                 {
    2861       45635 :                     idx[i] = idx[i - 1];
    2862             :                 }
    2863       25307 :                 idx[idx_sep_object] = 0;
    2864             :             }
    2865             :         }
    2866             :     }
    2867             :     else
    2868             :     {
    2869           0 :         idx[0] = (int16_t) ( ( ratio_ism[0] ) * ( ( 1 << PARAM_ISM_POW_RATIO_NBITS ) - 1 ) + 0.5f );
    2870             :     }
    2871             : 
    2872       30442 :     return;
    2873             : }
    2874             : 
    2875             : 
    2876        6667 : static int16_t index_slice_enum(
    2877             :     const int16_t *ratio_ism_idx,
    2878             :     const int16_t nchan_ism )
    2879             : {
    2880             :     int16_t i;
    2881             :     int16_t x, index;
    2882             :     int16_t base;
    2883             : 
    2884        6667 :     if ( nchan_ism == 2 )
    2885             :     {
    2886         308 :         index = ratio_ism_idx[0];
    2887             :     }
    2888             :     else
    2889             :     {
    2890        6359 :         x = ratio_ism_idx[nchan_ism - 2];
    2891        6359 :         base = 10;
    2892       17254 :         for ( i = nchan_ism - 3; i >= 0; i-- )
    2893             :         {
    2894       10895 :             x += ratio_ism_idx[i] * base;
    2895       10895 :             base *= 10;
    2896             :         }
    2897             : 
    2898        6359 :         index = 0;
    2899        6359 :         i = 0;
    2900      929374 :         while ( i <= x )
    2901             :         {
    2902      923015 :             if ( valid_ratio_index( i, 7, nchan_ism - 1 ) )
    2903             :             {
    2904      253005 :                 index++;
    2905             :             }
    2906      923015 :             i++;
    2907             :         }
    2908        6359 :         index--;
    2909             :     }
    2910             : 
    2911        6667 :     return index;
    2912             : }
    2913             : 
    2914             : 
    2915       61500 : static void transform_difference_index(
    2916             :     const int16_t *diff_idx,
    2917             :     int16_t *idx,
    2918             :     const int16_t len )
    2919             : {
    2920             :     int16_t i;
    2921      189120 :     for ( i = 0; i < len; i++ )
    2922             :     {
    2923      127620 :         if ( diff_idx[i] <= 0 )
    2924             :         {
    2925       99653 :             idx[i] = -2 * diff_idx[i];
    2926             :         }
    2927             :         else
    2928             :         {
    2929       27967 :             idx[i] = 2 * diff_idx[i] - 1;
    2930             :         }
    2931             :     }
    2932             : 
    2933       61500 :     return;
    2934             : }
    2935             : 
    2936             : 
    2937       20140 : static void transform_index_and_GR_encode(
    2938             :     int16_t *diff_idx,        /* i  : differenc eindex to encode    */
    2939             :     const int16_t len,        /* i  : input length                  */
    2940             :     const int16_t GR_order,   /* i  : GR order                      */
    2941             :     BSTR_ENC_HANDLE hMetaData /* i/o: metadata bitstream handle     */
    2942             : )
    2943             : {
    2944             :     int16_t i;
    2945             :     int16_t idx[IVAS_MAX_NUM_OBJECTS];
    2946             : 
    2947             :     /* transform difference index into positive */
    2948       20140 :     transform_difference_index( diff_idx, idx, len );
    2949             : 
    2950             :     /* GR encoding */
    2951       61048 :     for ( i = 0; i < len; i++ )
    2952             :     {
    2953       40908 :         ivas_qmetadata_encode_extended_gr( hMetaData, idx[i], 100, GR_order );
    2954             :     }
    2955             : 
    2956       20140 :     return;
    2957             : }
    2958             : 
    2959             : 
    2960        1862 : static int16_t try_differential(
    2961             :     const int16_t numCodingBands,
    2962             :     const float *masa_to_total_energy_ratio,
    2963             :     int16_t ratio_ism_idx[MASA_FREQUENCY_BANDS][MAX_NUM_OBJECTS],
    2964             :     const int16_t nchan_ism,
    2965             :     const int16_t bits_index,
    2966             :     int16_t *p_b_signif )
    2967             : {
    2968             :     int16_t b, i;
    2969             :     int16_t nbits0;
    2970             :     int16_t b_signif;
    2971             :     int16_t ratio_ism_idx_ref[MAX_NUM_OBJECTS];
    2972             :     int16_t diff_idx[MAX_NUM_OBJECTS];
    2973             : 
    2974        1862 :     b_signif = 0;
    2975        2162 :     while ( ( b_signif < numCodingBands ) && ( masa_to_total_energy_ratio[b_signif] >= MASA2TOTAL_THR ) )
    2976             :     {
    2977         300 :         b_signif++;
    2978             :     }
    2979             : 
    2980        1862 :     nbits0 = 0;
    2981             : 
    2982        1862 :     if ( b_signif < numCodingBands )
    2983             :     {
    2984        1806 :         nbits0 = bits_index;
    2985        1806 :         mvs2s( ratio_ism_idx[b_signif], ratio_ism_idx_ref, nchan_ism );
    2986             : 
    2987       11560 :         for ( b = b_signif + 1; b < numCodingBands; b++ )
    2988             :         {
    2989        9754 :             if ( masa_to_total_energy_ratio[b] < MASA2TOTAL_THR )
    2990             :             {
    2991        8627 :                 v_sub_s( ratio_ism_idx[b], ratio_ism_idx_ref, diff_idx, nchan_ism );
    2992        8627 :                 mvs2s( ratio_ism_idx[b], ratio_ism_idx_ref, nchan_ism );
    2993             : 
    2994             :                 /* transform difference index into positive */
    2995        8627 :                 transform_difference_index( diff_idx, diff_idx, nchan_ism - 1 );
    2996             : 
    2997             :                 /* GR encoding */
    2998       30124 :                 for ( i = 0; i < nchan_ism - 1; i++ )
    2999             :                 {
    3000       21497 :                     nbits0 += ivas_qmetadata_encode_extended_gr_length( diff_idx[i], 100, 0 );
    3001             :                 }
    3002             :             }
    3003             :         }
    3004             :     }
    3005        1862 :     *p_b_signif = b_signif;
    3006             : 
    3007        1862 :     return nbits0;
    3008             : }
    3009             : 
    3010             : 
    3011         666 : static void differential_coding_first_subframe(
    3012             :     BSTR_ENC_HANDLE hMetaData,
    3013             :     const float *masa_to_total_energy_ratio,
    3014             :     const int16_t b_signif,
    3015             :     int16_t ratio_ism_idx[MASA_FREQUENCY_BANDS][MAX_NUM_OBJECTS],
    3016             :     const int16_t nchan_ism,
    3017             :     const int16_t numCodingBands,
    3018             :     const int16_t bits_index )
    3019             : {
    3020             :     int16_t index, b;
    3021             :     int16_t ratio_ism_idx_ref[MAX_NUM_OBJECTS];
    3022             :     int16_t diff_idx[MAX_NUM_OBJECTS];
    3023             : 
    3024             :     /* differential encoding*/
    3025         666 :     push_next_indice( hMetaData, 0, 1 );
    3026             : 
    3027         666 :     if ( b_signif < numCodingBands )
    3028             :     {
    3029         666 :         index = index_slice_enum( ratio_ism_idx[b_signif], nchan_ism );
    3030         666 :         push_next_indice( hMetaData, index, bits_index );
    3031             : 
    3032         666 :         mvs2s( ratio_ism_idx[b_signif], ratio_ism_idx_ref, nchan_ism );
    3033             : 
    3034        4892 :         for ( b = b_signif + 1; b < numCodingBands; b++ )
    3035             :         {
    3036        4226 :             if ( masa_to_total_energy_ratio[b] < MASA2TOTAL_THR )
    3037             :             {
    3038        3766 :                 v_sub_s( ratio_ism_idx[b], ratio_ism_idx_ref, diff_idx, nchan_ism );
    3039        3766 :                 mvs2s( ratio_ism_idx[b], ratio_ism_idx_ref, nchan_ism );
    3040             : 
    3041             :                 /* transform difference index into positive */
    3042        3766 :                 transform_index_and_GR_encode( diff_idx, nchan_ism - 1, 0, hMetaData );
    3043             :             }
    3044             :         }
    3045             :     }
    3046             : 
    3047         666 :     return;
    3048             : }
    3049             : 
    3050             : 
    3051        1140 : static void independent_coding_ratio_ism_idx(
    3052             :     int16_t ratio_ism_idx[MASA_FREQUENCY_BANDS][MAX_NUM_OBJECTS], /* i  : ISM ratios                */
    3053             :     const float *masa_to_total_energy_ratio,                      /* i  : MASA to total ratios      */
    3054             :     const int16_t nchan_ism,                                      /* i  : number of objects         */
    3055             :     const int16_t numCodingBands,                                 /* i  : number of subbands        */
    3056             :     const int16_t bits_index,                                     /* i  : number of bits per index  */
    3057             :     BSTR_ENC_HANDLE hMetaData                                     /* i/o: metadata bitstream handle */
    3058             : )
    3059             : {
    3060             :     int16_t b, index;
    3061             : 
    3062        7844 :     for ( b = 0; b < numCodingBands; b++ )
    3063             :     {
    3064        6704 :         if ( masa_to_total_energy_ratio[b] < MASA2TOTAL_THR )
    3065             :         {
    3066        6001 :             index = index_slice_enum( ratio_ism_idx[b], nchan_ism );
    3067        6001 :             push_next_indice( hMetaData, index, bits_index );
    3068             :         }
    3069             :     }
    3070             : 
    3071        1140 :     return;
    3072             : }
    3073             : 
    3074             : 
    3075       29034 : static void remove_sep_obj(
    3076             :     int16_t *diff_idx,        /* i/o: array of difference of indexes                        */
    3077             :     const int16_t nchan_ism,  /* i  : number of objects                                     */
    3078             :     const int16_t idx_sep_obj /* i  : index of separated object, to be taken out of array   */
    3079             : )
    3080             : {
    3081             :     int16_t i;
    3082             : 
    3083       88017 :     for ( i = idx_sep_obj; i < nchan_ism - 1; i++ )
    3084             :     {
    3085       58983 :         diff_idx[i] = diff_idx[i + 1];
    3086             :     }
    3087             : 
    3088       29034 :     return;
    3089             : }
    3090             : 
    3091             : 
    3092       32733 : static void estimate_bits_subband_ism_ratio(
    3093             :     const int16_t *ratio_ism_idx,
    3094             :     const int16_t *ratio_ism_idx_ref, /* ( i/o ) */
    3095             :     const int16_t nchan_ism,
    3096             :     const int16_t shift_one,
    3097             :     const int16_t idx_sep_obj,
    3098             :     int16_t *p_nbits0,
    3099             :     int16_t *p_nbits1 )
    3100             : {
    3101             :     int16_t diff_idx[MAX_NUM_OBJECTS];
    3102             :     int16_t nbits0, nbits1;
    3103             :     int16_t i;
    3104             : 
    3105       32733 :     nbits0 = 0;
    3106       32733 :     nbits1 = 0;
    3107             : 
    3108             :     /* take difference with respect to previous subframe */
    3109       32733 :     v_sub_s( ratio_ism_idx, ratio_ism_idx_ref, diff_idx, nchan_ism );
    3110             : 
    3111       32733 :     if ( shift_one )
    3112             :     {
    3113       19356 :         remove_sep_obj( diff_idx, nchan_ism, idx_sep_obj );
    3114             :     }
    3115             : 
    3116             :     /* transform difference index into positive */
    3117       32733 :     transform_difference_index( diff_idx, diff_idx, nchan_ism - 1 - shift_one );
    3118             : 
    3119             :     /* GR encoding */
    3120       97948 :     for ( i = 0; i < nchan_ism - 1 - shift_one; i++ )
    3121             :     {
    3122       65215 :         nbits0 += ivas_qmetadata_encode_extended_gr_length( diff_idx[i], 100, 0 );
    3123       65215 :         nbits1 += ivas_qmetadata_encode_extended_gr_length( diff_idx[i], 100, 1 );
    3124             :     }
    3125             : 
    3126       32733 :     *p_nbits0 = nbits0;
    3127       32733 :     *p_nbits1 = nbits1;
    3128             : 
    3129       32733 :     return;
    3130             : }
    3131             : 
    3132             : 
    3133        5636 : static int16_t encode_ratio_ism_subframe(
    3134             :     int16_t ratio_ism_idx[MASA_FREQUENCY_BANDS][MAX_NUM_OBJECTS],
    3135             :     const int16_t nchan_ism,
    3136             :     const uint8_t numCodingBands,
    3137             :     const int16_t sf,
    3138             :     int16_t ratio_ism_idx_prev_sf[MASA_FREQUENCY_BANDS][MAX_NUM_OBJECTS],
    3139             :     BSTR_ENC_HANDLE hMetaData,
    3140             :     const float *masa_to_total_energy_ratio,
    3141             :     const int16_t shift_one,
    3142             :     const int16_t idx_separated_obj )
    3143             : {
    3144             :     int16_t b, b_signif;
    3145             :     int16_t diff_idx[MAX_NUM_OBJECTS];
    3146             :     int16_t nbits, nbits0, nbits1, GR_order, GR_order_sb;
    3147             :     int16_t differential_subframe;
    3148             :     int16_t ratio_ism_idx_ref[MAX_NUM_OBJECTS];
    3149             :     int16_t bits_index;
    3150             :     int16_t nbits00, nbits11;
    3151             :     int16_t idx_sep_obj_local;
    3152             : #ifdef DEBUGGING
    3153             :     int16_t bits_pos0;
    3154             : #endif
    3155             : 
    3156        5636 :     idx_sep_obj_local = idx_separated_obj;
    3157        5636 :     if ( idx_separated_obj > -1 )
    3158             :     {
    3159        5636 :         if ( idx_separated_obj == nchan_ism - 1 )
    3160             :         {
    3161         803 :             idx_sep_obj_local = 0;
    3162             :         }
    3163             :     }
    3164        5636 :     nbits = 0;
    3165        5636 :     nbits0 = 0;
    3166        5636 :     nbits1 = 0;
    3167             : 
    3168             : #ifdef DEBUGGING
    3169             :     bits_pos0 = hMetaData->nb_bits_tot;
    3170             : #endif
    3171        5636 :     differential_subframe = 1; /* the differences are taken with respect to previous subframe */
    3172             : 
    3173             :     /* first subframe */
    3174        5636 :     bits_index = 0;
    3175        5636 :     if ( sf == 0 )
    3176             :     {
    3177        1862 :         bits_index = bits_index_ism_ratio( nchan_ism );
    3178             : 
    3179        1862 :         nbits = 0;
    3180       13722 :         for ( b = 0; b < numCodingBands; b++ )
    3181             :         {
    3182       11860 :             if ( masa_to_total_energy_ratio[b] < MASA2TOTAL_THR )
    3183             :             {
    3184       10433 :                 nbits += bits_index;
    3185             :             }
    3186             :         }
    3187             : 
    3188        1862 :         nbits0 = try_differential( numCodingBands, masa_to_total_energy_ratio, ratio_ism_idx, nchan_ism, bits_index, &b_signif );
    3189             : 
    3190        1862 :         if ( nbits <= nbits0 && nbits > 0 )
    3191             :         {
    3192             :             /* independent encoding */
    3193        1140 :             push_next_indice( hMetaData, 1, 1 );
    3194        1140 :             independent_coding_ratio_ism_idx( ratio_ism_idx, masa_to_total_energy_ratio, nchan_ism, numCodingBands, bits_index, hMetaData );
    3195        1140 :             nbits = nbits + 1;
    3196             :         }
    3197             :         else
    3198             :         {
    3199         722 :             if ( nbits > 0 )
    3200             :             {
    3201         666 :                 differential_coding_first_subframe( hMetaData, masa_to_total_energy_ratio, b_signif, ratio_ism_idx, nchan_ism, numCodingBands, bits_index );
    3202         666 :                 nbits = nbits0 + 1;
    3203             :             }
    3204             :         }
    3205             : 
    3206             : #ifdef DEBUGGING
    3207             :         assert( nbits == ( hMetaData->nb_bits_tot - bits_pos0 ) );
    3208             : #endif
    3209             :     }
    3210             :     else
    3211             :     {
    3212             :         /* not first subframe */
    3213        3774 :         if ( shift_one == 1 && nchan_ism == 2 )
    3214             :         {
    3215          36 :             nbits = 0;
    3216             :         }
    3217             :         else
    3218             :         {
    3219        3738 :             nbits0 = 0;
    3220        3738 :             nbits1 = 0;
    3221             : 
    3222       22284 :             for ( b = 0; b < numCodingBands; b++ )
    3223             :             {
    3224       18546 :                 if ( masa_to_total_energy_ratio[b] < MASA2TOTAL_THR )
    3225             :                 {
    3226       16374 :                     estimate_bits_subband_ism_ratio( ratio_ism_idx[b], ratio_ism_idx_prev_sf[b], nchan_ism, shift_one, idx_sep_obj_local, &nbits00, &nbits11 );
    3227       16374 :                     nbits0 += nbits00;
    3228       16374 :                     nbits1 += nbits11;
    3229             :                 }
    3230             :             }
    3231        3738 :             if ( nbits0 < nbits1 )
    3232             :             {
    3233        2705 :                 GR_order = 0;
    3234        2705 :                 nbits = nbits0;
    3235             :             }
    3236             :             else
    3237             :             {
    3238        1033 :                 GR_order = 1;
    3239        1033 :                 nbits = nbits1;
    3240             :             }
    3241             : 
    3242        3738 :             if ( numCodingBands > 1 )
    3243             :             {
    3244             :                 /* try the difference from subband to subband; first subband is compared to previous subframe first subband*/
    3245             :                 /* take difference with respect to previous subframe only for first subband */
    3246        3702 :                 nbits0 = 0;
    3247        3702 :                 nbits1 = 0;
    3248        3702 :                 b_signif = 0;
    3249        3963 :                 while ( ( b_signif < numCodingBands ) && ( masa_to_total_energy_ratio[b_signif] >= MASA2TOTAL_THR ) )
    3250             :                 {
    3251         261 :                     b_signif++;
    3252             :                 }
    3253             : 
    3254        3702 :                 if ( b_signif < numCodingBands )
    3255             :                 {
    3256        3690 :                     estimate_bits_subband_ism_ratio( ratio_ism_idx[b_signif], ratio_ism_idx_prev_sf[b_signif], nchan_ism, shift_one, idx_sep_obj_local, &nbits0, &nbits1 );
    3257             : 
    3258        3690 :                     mvs2s( ratio_ism_idx[b_signif], ratio_ism_idx_ref, nchan_ism );
    3259             : 
    3260       18249 :                     for ( b = b_signif + 1; b < numCodingBands; b++ )
    3261             :                     {
    3262       14559 :                         if ( masa_to_total_energy_ratio[b] < MASA2TOTAL_THR )
    3263             :                         {
    3264       12669 :                             estimate_bits_subband_ism_ratio( ratio_ism_idx[b], ratio_ism_idx_ref, nchan_ism, shift_one, idx_sep_obj_local, &nbits00, &nbits11 );
    3265       12669 :                             nbits0 += nbits00;
    3266       12669 :                             nbits1 += nbits11;
    3267       12669 :                             mvs2s( ratio_ism_idx[b], ratio_ism_idx_ref, nchan_ism );
    3268             :                         }
    3269             :                     }
    3270             : 
    3271        3690 :                     if ( nbits0 < nbits1 )
    3272             :                     {
    3273         535 :                         GR_order_sb = 0;
    3274             :                     }
    3275             :                     else
    3276             :                     {
    3277        3155 :                         GR_order_sb = 1;
    3278        3155 :                         nbits0 = nbits1;
    3279             :                     }
    3280             : 
    3281        3690 :                     if ( nbits0 < nbits )
    3282             :                     {
    3283         349 :                         differential_subframe = 0;
    3284         349 :                         nbits = nbits0;
    3285         349 :                         GR_order = GR_order_sb;
    3286             :                     }
    3287             : 
    3288        3690 :                     if ( nbits > 0 )
    3289             :                     {
    3290             :                         /* write prediction type */
    3291        3690 :                         push_next_indice( hMetaData, differential_subframe, 1 );
    3292             :                         /* write GR order */
    3293        3690 :                         push_next_indice( hMetaData, GR_order, 1 );
    3294        3690 :                         nbits++; /* for the prediction type */
    3295        3690 :                         nbits++; /* for GR_order */
    3296             : 
    3297             :                         /* write data */
    3298        3690 :                         if ( differential_subframe )
    3299             :                         {
    3300       20046 :                             for ( b = 0; b < numCodingBands; b++ )
    3301             :                             {
    3302       16705 :                                 if ( masa_to_total_energy_ratio[b] < MASA2TOTAL_THR )
    3303             :                                 {
    3304             :                                     /* take difference with respect to previous subframe */
    3305       14824 :                                     v_sub_s( ratio_ism_idx[b], ratio_ism_idx_prev_sf[b], diff_idx, nchan_ism );
    3306             : 
    3307       14824 :                                     if ( shift_one )
    3308             :                                     {
    3309        9259 :                                         remove_sep_obj( diff_idx, nchan_ism, idx_sep_obj_local );
    3310             :                                     }
    3311             : 
    3312       14824 :                                     transform_index_and_GR_encode( diff_idx, nchan_ism - 1 - shift_one, GR_order, hMetaData );
    3313             :                                 }
    3314             :                             }
    3315             :                         }
    3316             :                         else
    3317             :                         {
    3318         349 :                             v_sub_s( ratio_ism_idx[b_signif], ratio_ism_idx_prev_sf[b_signif], diff_idx, nchan_ism );
    3319             : 
    3320         349 :                             if ( shift_one )
    3321             :                             {
    3322          87 :                                 remove_sep_obj( diff_idx, nchan_ism, idx_sep_obj_local );
    3323             :                             }
    3324             : 
    3325         349 :                             transform_index_and_GR_encode( diff_idx, nchan_ism - 1 - shift_one, GR_order, hMetaData );
    3326             : 
    3327         349 :                             mvs2s( ratio_ism_idx[b_signif], ratio_ism_idx_ref, nchan_ism - shift_one );
    3328             : 
    3329        1739 :                             for ( b = b_signif + 1; b < numCodingBands; b++ )
    3330             :                             {
    3331             :                                 /* take difference with respect to previous subband */
    3332        1390 :                                 if ( masa_to_total_energy_ratio[b] < MASA2TOTAL_THR )
    3333             :                                 {
    3334        1186 :                                     v_sub_s( ratio_ism_idx[b], ratio_ism_idx_ref, diff_idx, nchan_ism );
    3335             : 
    3336        1186 :                                     if ( shift_one )
    3337             :                                     {
    3338         332 :                                         remove_sep_obj( diff_idx, nchan_ism, idx_sep_obj_local );
    3339             :                                     }
    3340             : 
    3341        1186 :                                     transform_index_and_GR_encode( diff_idx, nchan_ism - 1 - shift_one, GR_order, hMetaData );
    3342             : 
    3343        1186 :                                     mvs2s( ratio_ism_idx[b], ratio_ism_idx_ref, nchan_ism - shift_one );
    3344             :                                 }
    3345             :                             }
    3346             :                         }
    3347             :                     }
    3348             :                 }
    3349             :             }
    3350             :             else
    3351             :             {
    3352             :                 /* only differential wrt previous subframe is possible  */
    3353             :                 /* write the differential to subframe case and no bit to signal the difference type */
    3354             : 
    3355          36 :                 if ( nbits > 0 )
    3356             :                 {
    3357             :                     /* write GR order */
    3358          15 :                     push_next_indice( hMetaData, GR_order, 1 );
    3359          15 :                     nbits++; /* for GR_order */
    3360             :                     /* write data */
    3361             :                     /* only one subband */
    3362          15 :                     if ( masa_to_total_energy_ratio[0] < MASA2TOTAL_THR )
    3363             :                     {
    3364             :                         /* take difference with respect to previous subframe */
    3365          15 :                         v_sub_s( ratio_ism_idx[0], ratio_ism_idx_prev_sf[0], diff_idx, nchan_ism );
    3366             : 
    3367          15 :                         if ( shift_one )
    3368             :                         {
    3369           0 :                             remove_sep_obj( diff_idx, nchan_ism, idx_sep_obj_local );
    3370             :                         }
    3371             : 
    3372          15 :                         transform_index_and_GR_encode( diff_idx, nchan_ism - 1 - shift_one, GR_order, hMetaData );
    3373             :                     }
    3374             :                 }
    3375             :             }
    3376             : 
    3377             : #ifdef DEBUGGING
    3378             :             assert( nbits == ( hMetaData->nb_bits_tot - bits_pos0 ) );
    3379             : #endif
    3380             :         }
    3381             :     }
    3382             : 
    3383        5636 :     return nbits;
    3384             : }
    3385             : 
    3386             : 
    3387        1862 : static void ivas_encode_masaism_metadata(
    3388             :     MASA_ENCODER_HANDLE hMasa,
    3389             :     IVAS_QMETADATA_HANDLE hQMetaData, /* i/o: q_metadata handle             */
    3390             :     BSTR_ENC_HANDLE hMetaData,        /* i/o: metadata bitstream handle     */
    3391             :     ISM_METADATA_HANDLE hIsmMeta[],   /* i/o: ISM metadata handles          */
    3392             :     const int16_t nchan_ism,          /* i  : number of ISM channels        */
    3393             :     const int16_t low_bitrate_mode,   /* i  : is low bitrate more? 1/0      */
    3394             :     const int16_t omasa_nbands,
    3395             :     const int16_t omasa_nblocks,
    3396             :     const int16_t idx_separated_object,
    3397             :     const int16_t ism_imp )
    3398             : {
    3399             :     int16_t sf, band;
    3400             :     uint8_t numCodingBands;
    3401             :     uint8_t numSf;
    3402             :     int16_t brange[2];
    3403             :     float eneBand;
    3404             :     int16_t bin;
    3405             :     int16_t obj;
    3406             :     int16_t bits_ism[MAX_NUM_OBJECTS];
    3407             :     uint16_t idx_sph;
    3408             :     float theta_q, phi_q;
    3409             :     uint16_t index_theta, index_phi;
    3410             :     float ratio_ism[MASA_FREQUENCY_BANDS][MAX_NUM_OBJECTS];
    3411             :     int16_t ratio_ism_idx[MASA_FREQUENCY_BANDS][MAX_NUM_OBJECTS], ratio_ism_idx_prev_sf[MASA_FREQUENCY_BANDS][MAX_NUM_OBJECTS];
    3412             :     float step;
    3413             :     int16_t inv_step;
    3414             :     float energy_ism, energy_ism_ind[MAX_NUM_OBJECTS];
    3415             :     int16_t tmp, rotate;
    3416             :     int16_t n_ism_tmp, i;
    3417        1862 :     OMASA_ENCODER_DATA_HANDLE hOmasaData = hMasa->data.hOmasaData;
    3418        1862 :     OMASA_ENCODER_ENERGY_HANDLE hOmasaEnergy = hOmasaData->hOmasaEnergy;
    3419             :     int16_t nbands_work;
    3420             : 
    3421             :     /* use the values from hQMetaData */
    3422        1862 :     numCodingBands = (uint8_t) hQMetaData->q_direction->cfg.nbands;
    3423        1862 :     numSf = (int8_t) hQMetaData->q_direction->cfg.nblocks;
    3424        1862 :     nbands_work = min( numCodingBands, omasa_nbands );
    3425        1862 :     if ( numCodingBands == 1 )
    3426             :     {
    3427         120 :         for ( sf = 0; sf < numSf; sf++ )
    3428             :         {
    3429          96 :             if ( sum_f( hOmasaEnergy->energy_ism[sf], omasa_nbands ) == 0.0f )
    3430             :             {
    3431           0 :                 hOmasaData->masa_to_total_energy_ratio[sf][0] = 1.0f;
    3432             :             }
    3433             :             else
    3434             :             {
    3435          96 :                 brange[0] = hMasa->data.band_mapping[0];
    3436          96 :                 brange[1] = hMasa->data.band_mapping[omasa_nbands];
    3437          96 :                 eneBand = 0.0f;
    3438        2400 :                 for ( bin = brange[0]; bin < brange[1]; bin++ )
    3439             :                 {
    3440        2304 :                     eneBand += hMasa->data.energy[sf][bin];
    3441             :                 }
    3442             : 
    3443          96 :                 energy_ism = 0.0f;
    3444         288 :                 for ( obj = 0; obj < nchan_ism; obj++ )
    3445             :                 {
    3446         192 :                     energy_ism_ind[obj] = 0.0f;
    3447             :                 }
    3448             : 
    3449         576 :                 for ( band = 0; band < omasa_nbands; band++ )
    3450             :                 {
    3451         480 :                     energy_ism += hOmasaEnergy->energy_ism[sf][band];
    3452        1440 :                     for ( obj = 0; obj < nchan_ism; obj++ )
    3453             :                     {
    3454         960 :                         energy_ism_ind[obj] += hOmasaEnergy->energy_ism[sf][band] * hOmasaEnergy->energy_ratio_ism[sf][band][obj];
    3455             :                     }
    3456             :                 }
    3457             : 
    3458         288 :                 for ( obj = 0; obj < nchan_ism; obj++ )
    3459             :                 {
    3460         192 :                     hOmasaEnergy->energy_ratio_ism[sf][0][obj] = energy_ism_ind[obj] / energy_ism;
    3461             :                 }
    3462          96 :                 hOmasaData->masa_to_total_energy_ratio[sf][0] = eneBand / ( eneBand + energy_ism + EPSILON );
    3463             :             }
    3464             :         }
    3465             :     }
    3466        1838 :     else if ( numSf == 1 )
    3467             :     {
    3468        6270 :         for ( band = 0; band < nbands_work; band++ )
    3469             :         {
    3470        5666 :             energy_ism = 0.0f; /* ISM energy for current subband */
    3471       24246 :             for ( obj = 0; obj < nchan_ism; obj++ )
    3472             :             {
    3473       18580 :                 energy_ism_ind[obj] = 0.0f;
    3474             :             }
    3475       14722 :             for ( sf = 0; sf < omasa_nblocks; sf++ )
    3476             :             {
    3477        9056 :                 energy_ism += hOmasaEnergy->energy_ism[sf][band];
    3478       34416 :                 for ( obj = 0; obj < nchan_ism; obj++ )
    3479             :                 {
    3480       25360 :                     energy_ism_ind[obj] += hOmasaEnergy->energy_ism[sf][band] * hOmasaEnergy->energy_ratio_ism[sf][band][obj];
    3481             :                 }
    3482             :             }
    3483             : 
    3484        5666 :             if ( energy_ism == 0.0f )
    3485             :             {
    3486           0 :                 hOmasaData->masa_to_total_energy_ratio[0][band] = 1.0f;
    3487             :             }
    3488             :             else
    3489             :             {
    3490       24246 :                 for ( obj = 0; obj < nchan_ism; obj++ )
    3491             :                 {
    3492       18580 :                     hOmasaEnergy->energy_ratio_ism[0][band][obj] = energy_ism_ind[obj] / energy_ism;
    3493             :                 }
    3494        5666 :                 brange[0] = hMasa->data.band_mapping[band];
    3495        5666 :                 brange[1] = hMasa->data.band_mapping[band + 1];
    3496             : 
    3497        5666 :                 eneBand = 0.0f;
    3498       14722 :                 for ( sf = 0; sf < omasa_nblocks; sf++ )
    3499             :                 {
    3500       39748 :                     for ( bin = brange[0]; bin < brange[1]; bin++ )
    3501             :                     {
    3502       30692 :                         eneBand += hMasa->data.energy[sf][bin];
    3503             :                     }
    3504             :                 }
    3505        5666 :                 hOmasaData->masa_to_total_energy_ratio[0][band] = eneBand / ( eneBand + energy_ism + EPSILON );
    3506             :             }
    3507             :         }
    3508         604 :         for ( band = nbands_work; band < numCodingBands; band++ )
    3509             :         {
    3510           0 :             hOmasaData->masa_to_total_energy_ratio[0][band] = 1.0f;
    3511             : 
    3512           0 :             for ( obj = 0; obj < nchan_ism; obj++ )
    3513             :             {
    3514           0 :                 hOmasaEnergy->energy_ratio_ism[0][band][obj] = hOmasaEnergy->energy_ratio_ism[0][nbands_work - 1][obj];
    3515             :             }
    3516             :         }
    3517             :     }
    3518             :     else
    3519             :     {
    3520        6170 :         for ( sf = 0; sf < numSf; sf++ )
    3521             :         {
    3522       29616 :             for ( band = 0; band < nbands_work; band++ )
    3523             :             {
    3524       24680 :                 if ( hOmasaEnergy->energy_ism[sf][band] == 0.0f )
    3525             :                 {
    3526           0 :                     hOmasaData->masa_to_total_energy_ratio[sf][band] = 1.0f;
    3527             :                 }
    3528             :                 else
    3529             :                 {
    3530       24680 :                     brange[0] = hMasa->data.band_mapping[band];
    3531       24680 :                     brange[1] = hMasa->data.band_mapping[band + 1];
    3532             : 
    3533       24680 :                     eneBand = 0.0f;
    3534      141656 :                     for ( bin = brange[0]; bin < brange[1]; bin++ )
    3535             :                     {
    3536      116976 :                         eneBand += hMasa->data.energy[sf][bin];
    3537             :                     }
    3538       24680 :                     hOmasaData->masa_to_total_energy_ratio[sf][band] = eneBand / ( eneBand + hOmasaEnergy->energy_ism[sf][band] + EPSILON );
    3539             :                 }
    3540             :             }
    3541        4936 :             for ( band = nbands_work; band < numCodingBands; band++ )
    3542             :             {
    3543           0 :                 hOmasaData->masa_to_total_energy_ratio[sf][band] = 1.0f;
    3544             : 
    3545           0 :                 for ( obj = 0; obj < nchan_ism; obj++ )
    3546             :                 {
    3547           0 :                     hOmasaEnergy->energy_ratio_ism[sf][band][obj] = hOmasaEnergy->energy_ratio_ism[sf][nbands_work - 1][obj];
    3548             :                 }
    3549             :             }
    3550             :         }
    3551             :     }
    3552        1862 :     ivas_omasa_encode_masa_to_total( hOmasaData->masa_to_total_energy_ratio, hMetaData, low_bitrate_mode, numCodingBands, numSf );
    3553             : 
    3554             :     /* quantize ism_ratios */
    3555        1862 :     if ( nchan_ism > 1 )
    3556             :     {
    3557        1862 :         inv_step = ( ( 1 << PARAM_ISM_POW_RATIO_NBITS ) - 1 );
    3558        1862 :         step = 1.0f / inv_step;
    3559             : 
    3560        1862 :         rotate = 0;
    3561        1862 :         n_ism_tmp = 0;
    3562             : 
    3563        7498 :         for ( sf = 0; sf < numSf; sf++ )
    3564             :         {
    3565       36078 :             for ( band = 0; band < numCodingBands; band++ )
    3566             :             {
    3567      137614 :                 for ( obj = 0; obj < nchan_ism; obj++ )
    3568             :                 {
    3569      107172 :                     assert( ( hOmasaEnergy->energy_ratio_ism[sf][band][obj] >= 0 ) && ( hOmasaEnergy->energy_ratio_ism[sf][band][obj] <= 1 ) );
    3570      107172 :                     ratio_ism[band][obj] = hOmasaEnergy->energy_ratio_ism[sf][band][obj];
    3571             :                 }
    3572             : 
    3573             :                 /* Quantize ISM ratios */
    3574       30442 :                 quantize_ratio_ism_vector( ratio_ism[band], ratio_ism_idx[band], nchan_ism, hOmasaData->masa_to_total_energy_ratio[sf][band], idx_separated_object );
    3575       30442 :                 if ( n_ism_tmp == numCodingBands && ratio_ism_idx[band][idx_separated_object] != 0 && hOmasaData->masa_to_total_energy_ratio[sf][band] < MASA2TOTAL_THR )
    3576             :                 {
    3577          92 :                     i = 0;
    3578         697 :                     while ( ratio_ism_idx[band][idx_separated_object] > 0 )
    3579             :                     {
    3580         605 :                         if ( i != idx_separated_object )
    3581             :                         {
    3582         410 :                             ratio_ism_idx[band][i]++;
    3583         410 :                             ratio_ism_idx[band][idx_separated_object]--;
    3584             :                         }
    3585         605 :                         i++;
    3586         605 :                         if ( i == nchan_ism )
    3587             :                         {
    3588         138 :                             i = 0;
    3589             :                         }
    3590             :                     }
    3591             :                 }
    3592             : 
    3593             :                 /* reconstructed values */
    3594       30442 :                 reconstruct_ism_ratios( ratio_ism_idx[band], nchan_ism, step, hOmasaEnergy->q_energy_ratio_ism[sf][band] );
    3595             :             }
    3596             : 
    3597        5636 :             if ( ( nchan_ism > 2 ) && ( idx_separated_object == nchan_ism - 1 ) )
    3598             :             {
    3599             :                 /* rotate components */
    3600         766 :                 rotate = 1;
    3601        4610 :                 for ( band = 0; band < numCodingBands; band++ )
    3602             :                 {
    3603        3844 :                     if ( hOmasaData->masa_to_total_energy_ratio[sf][band] < MASA2TOTAL_THR )
    3604             :                     {
    3605        3352 :                         tmp = ratio_ism_idx[band][nchan_ism - 1];
    3606        3352 :                         ratio_ism_idx[band][nchan_ism - 1] = ratio_ism_idx[band][0];
    3607        3352 :                         ratio_ism_idx[band][0] = tmp;
    3608        3352 :                         if ( sf == 0 && tmp == 0 )
    3609             :                         {
    3610         799 :                             n_ism_tmp += 1;
    3611             :                         }
    3612             : 
    3613        3352 :                         if ( n_ism_tmp == numCodingBands )
    3614             :                         {
    3615        1753 :                             assert( tmp == 0 );
    3616             :                         }
    3617             :                     }
    3618             :                 }
    3619             :             }
    3620             :             else
    3621             :             {
    3622        4870 :                 if ( idx_separated_object > -1 )
    3623             :                 {
    3624       31468 :                     for ( band = 0; band < numCodingBands; band++ )
    3625             :                     {
    3626       26598 :                         if ( hOmasaData->masa_to_total_energy_ratio[sf][band] < MASA2TOTAL_THR )
    3627             :                         {
    3628       23491 :                             if ( ratio_ism_idx[band][idx_separated_object] == 0 && sf == 0 )
    3629             :                             {
    3630        8633 :                                 n_ism_tmp++;
    3631             :                             }
    3632             :                         }
    3633             :                     }
    3634             :                 }
    3635             :             }
    3636             : 
    3637             :             /* encode data for current subframe */
    3638        5636 :             if ( sf > 0 && n_ism_tmp == numCodingBands )
    3639             :             {
    3640        2067 :                 encode_ratio_ism_subframe( ratio_ism_idx, nchan_ism, numCodingBands, sf, ratio_ism_idx_prev_sf, hMetaData, hOmasaData->masa_to_total_energy_ratio[sf], 1, idx_separated_object );
    3641             :             }
    3642             :             else
    3643             :             {
    3644        3569 :                 encode_ratio_ism_subframe( ratio_ism_idx, nchan_ism, numCodingBands, sf, ratio_ism_idx_prev_sf, hMetaData, hOmasaData->masa_to_total_energy_ratio[sf], 0, idx_separated_object );
    3645             :             }
    3646             : 
    3647             :             /* calculate quantized ISM ratios */
    3648             :             /* save previous subframe indexes */
    3649       36078 :             for ( band = 0; band < numCodingBands; band++ )
    3650             :             {
    3651       30442 :                 mvs2s( ratio_ism_idx[band], ratio_ism_idx_prev_sf[band], nchan_ism );
    3652             :             }
    3653             : 
    3654        5636 :             if ( rotate )
    3655             :             {
    3656        4610 :                 for ( band = 0; band < numCodingBands; band++ )
    3657             :                 {
    3658        3844 :                     if ( hOmasaData->masa_to_total_energy_ratio[sf][band] < MASA2TOTAL_THR )
    3659             :                     {
    3660        3352 :                         tmp = ratio_ism_idx[band][nchan_ism - 1];
    3661        3352 :                         ratio_ism_idx[band][nchan_ism - 1] = ratio_ism_idx[band][0];
    3662        3352 :                         ratio_ism_idx[band][0] = tmp;
    3663             :                     }
    3664             :                 }
    3665             :             }
    3666             :         }
    3667             :     }
    3668             : 
    3669        1862 :     calculate_nbits_meta( nchan_ism, hOmasaEnergy->q_energy_ratio_ism, hOmasaData->masa_to_total_energy_ratio, numSf, numCodingBands, bits_ism, idx_separated_object, ism_imp );
    3670             : 
    3671             :     /* quantize directions */
    3672        8142 :     for ( obj = 0; obj < nchan_ism; obj++ )
    3673             :     {
    3674        6280 :         if ( bits_ism[obj] < 8 )
    3675             :         {
    3676             :             /* check is same as previous */
    3677        2006 :             if ( ( fabs( hIsmMeta[obj]->elevation - hIsmMeta[obj]->q_elevation_old ) < 0.01f ) && ( fabs( hIsmMeta[obj]->azimuth - hIsmMeta[obj]->q_azimuth_old ) < 0.01f ) )
    3678             :             {
    3679         200 :                 push_next_indice( hMetaData, 1, 1 );
    3680             :                 /* the old stays the same */
    3681             :             }
    3682             :             else
    3683             :             {
    3684        1806 :                 push_next_indice( hMetaData, 0, 1 );
    3685        1806 :                 idx_sph = quantize_direction( hIsmMeta[obj]->elevation, hIsmMeta[obj]->azimuth, bits_ism[obj], &theta_q, &phi_q, &index_theta, &index_phi, MC_LS_SETUP_INVALID );
    3686        1806 :                 push_next_indice( hMetaData, idx_sph, bits_ism[obj] );
    3687        1806 :                 hIsmMeta[obj]->q_elevation_old = hIsmMeta[obj]->elevation;
    3688        1806 :                 hIsmMeta[obj]->q_azimuth_old = hIsmMeta[obj]->azimuth;
    3689             :             }
    3690             :         }
    3691             :         else
    3692             :         {
    3693        4274 :             idx_sph = quantize_direction( hIsmMeta[obj]->elevation, hIsmMeta[obj]->azimuth, bits_ism[obj], &theta_q, &phi_q, &index_theta, &index_phi, MC_LS_SETUP_INVALID );
    3694        4274 :             push_next_indice( hMetaData, idx_sph, bits_ism[obj] );
    3695        4274 :             hIsmMeta[obj]->q_elevation_old = hIsmMeta[obj]->elevation;
    3696        4274 :             hIsmMeta[obj]->q_azimuth_old = hIsmMeta[obj]->azimuth;
    3697             :         }
    3698             :     }
    3699             : 
    3700        1862 :     return;
    3701             : }
    3702             : 
    3703             : 
    3704             : /*-------------------------------------------------------------------*
    3705             :  * ivas_merge_masa_transports()
    3706             :  *
    3707             :  * Merge MASA transport channels
    3708             :  *-------------------------------------------------------------------*/
    3709             : 
    3710        5858 : void ivas_merge_masa_transports(
    3711             :     float data_in_f1[][L_FRAME48k],
    3712             :     float *data_in_f2[],
    3713             :     float *data_out_f[],
    3714             :     const int16_t input_frame,
    3715             :     const int16_t num_transport_channels )
    3716             : {
    3717             :     int16_t i, j;
    3718             : 
    3719       17574 :     for ( i = 0; i < num_transport_channels; i++ )
    3720             :     {
    3721    10588356 :         for ( j = 0; j < input_frame; j++ )
    3722             :         {
    3723    10576640 :             data_out_f[i][j] = data_in_f1[i][j] + data_in_f2[i][j];
    3724             :         }
    3725             :     }
    3726             : 
    3727        5858 :     return;
    3728             : }

Generated by: LCOV version 1.14