LCOV - code coverage report
Current view: top level - lib_enc - ivas_masa_enc.c (source / functions) Hit Total Coverage
Test: Coverage on main @ 6c9ddc4024a9c0e1ecb8f643f114a84a0e26ec6b Lines: 1353 1414 95.7 %
Date: 2025-05-27 05:28:09 Functions: 34 34 100.0 %

          Line data    Source code
       1             : /******************************************************************************************************
       2             : 
       3             :    (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB,
       4             :    Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
       5             :    Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
       6             :    Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
       7             :    contributors to this repository. All Rights Reserved.
       8             : 
       9             :    This software is protected by copyright law and by international treaties.
      10             :    The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB,
      11             :    Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
      12             :    Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
      13             :    Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
      14             :    contributors to this repository retain full ownership rights in their respective contributions in
      15             :    the software. This notice grants no license of any kind, including but not limited to patent
      16             :    license, nor is any license granted by implication, estoppel or otherwise.
      17             : 
      18             :    Contributors are required to enter into the IVAS codec Public Collaboration agreement before making
      19             :    contributions.
      20             : 
      21             :    This software is provided "AS IS", without any express or implied warranties. The software is in the
      22             :    development stage. It is intended exclusively for experts who have experience with such software and
      23             :    solely for the purpose of inspection. All implied warranties of non-infringement, merchantability
      24             :    and fitness for a particular purpose are hereby disclaimed and excluded.
      25             : 
      26             :    Any dispute, controversy or claim arising under or in relation to providing this software shall be
      27             :    submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in
      28             :    accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and
      29             :    the United Nations Convention on Contracts on the International Sales of Goods.
      30             : 
      31             : *******************************************************************************************************/
      32             : 
      33             : #include <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        7567 : 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        7567 :     error = IVAS_ERR_OK;
     104             : 
     105        7567 :     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        7567 :     hEncoderConfig = st_ivas->hEncoderConfig;
     111             : 
     112        7567 :     generate_gridEq( &( hMasa->data.Sph_Grid16 ) );
     113             : 
     114        7567 :     if ( hEncoderConfig->ivas_format == MASA_FORMAT || hEncoderConfig->ivas_format == MASA_ISM_FORMAT )
     115             :     {
     116         739 :         hMasa->data.num_Cldfb_instances = st_ivas->nchan_transport;
     117             :     }
     118             :     else
     119             :     {
     120        6828 :         hMasa->data.num_Cldfb_instances = 0;
     121             :     }
     122             : 
     123        8900 :     for ( i = 0; i < hMasa->data.num_Cldfb_instances; i++ )
     124             :     {
     125        1333 :         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        7567 :     ism_total_brate = 0;
     132        7567 :     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         924 :         for ( i = 0; i < st_ivas->nSCE; i++ )
     135             :         {
     136         600 :             ism_total_brate += st_ivas->hSCE[i]->element_brate;
     137             :         }
     138             :     }
     139             : 
     140        7567 :     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        7567 :     mvs2s( DirAC_block_grouping, hMasa->config.block_grouping, MAX_PARAM_SPATIAL_SUBFRAMES + 1 );
     143        7567 :     mvs2s( MASA_band_grouping_24, hMasa->config.band_grouping, MASA_FREQUENCY_BANDS + 1 );
     144             : 
     145             : 
     146        7567 :     hMasa->data.onset_detector_1 = 0.0f;
     147        7567 :     hMasa->data.onset_detector_2 = 0.0f;
     148             : 
     149        7567 :     set_zero( hMasa->data.lfeToTotalEnergyRatio, MAX_PARAM_SPATIAL_SUBFRAMES );
     150        7567 :     hMasa->data.prevq_lfeToTotalEnergyRatio = 0.0f;
     151        7567 :     hMasa->data.prevq_lfeIndex = 0;
     152             : 
     153        7567 :     hMasa->data.sync_state.prev_sim_stop = 0;
     154        7567 :     hMasa->data.sync_state.prev_offset = 0;
     155        7567 :     hMasa->data.sync_state.frame_mode = MASA_FRAME_4SF;
     156             : 
     157        7567 :     set_zero( hMasa->data.dir_align_state.previous_azi_dir1, MASA_FREQUENCY_BANDS );
     158        7567 :     set_zero( hMasa->data.dir_align_state.previous_ele_dir1, MASA_FREQUENCY_BANDS );
     159        7567 :     set_zero( hMasa->data.dir_align_state.previous_azi_dir2, MASA_FREQUENCY_BANDS );
     160        7567 :     set_zero( hMasa->data.dir_align_state.previous_ele_dir2, MASA_FREQUENCY_BANDS );
     161             : 
     162        7567 :     if ( hEncoderConfig->ivas_format == MASA_ISM_FORMAT )
     163             :     {
     164             :         OMASA_ENCODER_DATA_HANDLE hOmasaData;
     165             : 
     166         429 :         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        2145 :         for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ )
     171             :         {
     172        1716 :             set_f( hOmasaData->masa_to_total_energy_ratio[i], 0, MASA_FREQUENCY_BANDS );
     173             :         }
     174         429 :         hOmasaData->lp_noise_CPE = -1;
     175         429 :         hOmasaData->omasa_stereo_sw_cnt = OMASA_STEREO_SW_CNT_MAX;
     176             : 
     177         429 :         if ( st_ivas->ism_mode != ISM_MASA_MODE_DISC )
     178             :         {
     179         208 :             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         221 :             hOmasaData->hOmasaEnergy = NULL;
     187             :         }
     188             : 
     189         429 :         hMasa->data.hOmasaData = hOmasaData;
     190             :     }
     191             :     else
     192             :     {
     193        7138 :         hMasa->data.hOmasaData = NULL;
     194             :     }
     195             : 
     196        7567 :     st_ivas->hMasa = hMasa;
     197             : 
     198        7567 :     return error;
     199             : }
     200             : 
     201             : 
     202             : /*-----------------------------------------------------------------------*
     203             :  * ivas_masa_enc_close()
     204             :  *
     205             :  * close MASA encoder
     206             :  *-----------------------------------------------------------------------*/
     207             : 
     208       13643 : void ivas_masa_enc_close(
     209             :     MASA_ENCODER_HANDLE *hMasa /* i/o: MASA metadata structure      */
     210             : )
     211             : {
     212             :     int16_t i;
     213             : 
     214       13643 :     if ( hMasa == NULL || *hMasa == NULL )
     215             :     {
     216        6076 :         return;
     217             :     }
     218             : 
     219        8900 :     for ( i = 0; i < ( *hMasa )->data.num_Cldfb_instances; i++ )
     220             :     {
     221        1333 :         deleteCldfb( &( ( *hMasa )->data.cldfbAnaEnc[i] ) );
     222             :     }
     223             : 
     224        7567 :     if ( ( *hMasa )->data.hOmasaData != NULL )
     225             :     {
     226         429 :         if ( ( *hMasa )->data.hOmasaData->hOmasaEnergy != NULL )
     227             :         {
     228         206 :             free( ( *hMasa )->data.hOmasaData->hOmasaEnergy );
     229         206 :             ( *hMasa )->data.hOmasaData->hOmasaEnergy = NULL;
     230             :         }
     231             : 
     232         429 :         free( ( *hMasa )->data.hOmasaData );
     233         429 :         ( *hMasa )->data.hOmasaData = NULL;
     234             :     }
     235             : 
     236        7567 :     free( ( *hMasa ) );
     237        7567 :     ( *hMasa ) = NULL;
     238             : 
     239        7567 :     return;
     240             : }
     241             : 
     242             : 
     243             : /*-----------------------------------------------------------------------*
     244             :  * ivas_masa_encode()
     245             :  *
     246             :  * main MASA encoder function
     247             :  *-----------------------------------------------------------------------*/
     248             : 
     249     1068601 : 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     1068601 :     masa_sid_descriptor = -1;
     276     1068601 :     h_orig_metadata = NULL;
     277     1068601 :     low_bitrate_mode = 0;
     278             : 
     279     1068601 :     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      885461 :         if ( Opt_DTX_ON && hQMetaData != NULL )
     283             :         {
     284       63803 :             if ( nchan_transport == 2 ) /* this is MASA format in CPE only */
     285             :             {
     286       40796 :                 masa_sid_descriptor = 0; /* for IVAS_CPE_DFT */
     287       40796 :                 if ( element_mode == IVAS_CPE_MDCT )
     288             :                 {
     289       18118 :                     masa_sid_descriptor = 1;
     290             :                 }
     291             :             }
     292             :         }
     293             : 
     294             :         /* Validate and compensate ratios as necessary */
     295      885461 :         compensate_energy_ratios( hMasa );
     296             : 
     297      885461 :         if ( Opt_DTX_ON )
     298             :         {
     299       63803 :             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      191409 :             for ( i = 0; i < MASA_MAXIMUM_DIRECTIONS; i++ )
     305             :             {
     306      638030 :                 for ( j = 0; j < MAX_PARAM_SPATIAL_SUBFRAMES; j++ )
     307             :                 {
     308      510424 :                     mvr2r( hMasa->masaMetadata.directional_meta[i].azimuth[j], h_orig_metadata[i].azimuth[j], MASA_FREQUENCY_BANDS );
     309      510424 :                     mvr2r( hMasa->masaMetadata.directional_meta[i].elevation[j], h_orig_metadata[i].elevation[j], MASA_FREQUENCY_BANDS );
     310      510424 :                     mvr2r( hMasa->masaMetadata.directional_meta[i].energy_ratio[j], h_orig_metadata[i].energy_ratio[j], MASA_FREQUENCY_BANDS );
     311      510424 :                     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      885461 :         if ( ( ivas_format == MASA_FORMAT || ivas_format == MASA_ISM_FORMAT ) && ivas_total_brate >= IVAS_384k )
     317             :         {
     318       82530 :             hMasa->config.mergeRatiosOverSubframes = 0;
     319             :         }
     320             : 
     321             :         /* Combine frequency bands and sub-frames */
     322      885461 :         combine_freqbands_and_subframes( hMasa );
     323             :     }
     324             : 
     325     1068601 :     if ( hMasa->config.numberOfDirections == 2 && hMasa->config.numTwoDirBands < hMasa->config.numCodingBands && ( ivas_format == MASA_FORMAT || ivas_format == MASA_ISM_FORMAT ) )
     326             :     {
     327      328752 :         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      268162 :             ivas_masa_combine_directions( hMasa );
     331             :         }
     332             : 
     333             :         /* If we joined all bands, then metadata is now one directional. */
     334      328752 :         if ( hMasa->config.numTwoDirBands == 0 )
     335             :         {
     336      175015 :             hMasa->config.numberOfDirections = 1;
     337      175015 :             hMasa->masaMetadata.descriptive_meta.numberOfDirections = 0;
     338      175015 :             hQMetaData->no_directions = 1;
     339             :         }
     340             :     }
     341             : 
     342             :     /* Reset qmetadata bit budget */
     343     1068601 :     hQMetaData->metadata_max_bits = hMasa->config.max_metadata_bits;
     344     1068601 :     if ( ivas_format == MASA_FORMAT || ivas_format == MASA_ISM_FORMAT )
     345             :     {
     346      885461 :         if ( ivas_format == MASA_ISM_FORMAT && ism_mode != ISM_MODE_NONE )
     347             :         {
     348             :             /* write the number of objects in ISM_MASA format*/
     349      228178 :             push_next_indice( hMetaData, nchan_ism - 1, NO_BITS_MASA_ISM_NO_OBJ );
     350      228178 :             hQMetaData->metadata_max_bits -= NO_BITS_MASA_ISM_NO_OBJ;
     351             : 
     352             :             /* write index of separated object if needed */
     353      228178 :             if ( ism_mode == ISM_MASA_MODE_PARAM_ONE_OBJ && nchan_ism > 1 )
     354             :             {
     355       63612 :                 push_next_indice( hMetaData, idx_separated_object, NO_BITS_MASA_ISM_NO_OBJ );
     356       63612 :                 hQMetaData->metadata_max_bits -= NO_BITS_MASA_ISM_NO_OBJ;
     357             :             }
     358             : 
     359             :             /* write ISM importance flag (one per object) */
     360      228178 :             if ( ism_mode == ISM_MASA_MODE_PARAM_ONE_OBJ )
     361             :             {
     362       63612 :                 push_next_indice( hMetaData, hIsmMetaData[0]->ism_imp, ISM_METADATA_FLAG_BITS );
     363       63612 :                 hQMetaData->metadata_max_bits -= ISM_METADATA_FLAG_BITS;
     364             :             }
     365      164566 :             else if ( ism_mode == ISM_MASA_MODE_MASA_ONE_OBJ )
     366             :             {
     367       64754 :                 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       64754 :                     push_next_indice( hMetaData, hIsmMetaData[0]->ism_imp, ISM_METADATA_FLAG_BITS );
     382       64754 :                     hQMetaData->metadata_max_bits -= ISM_METADATA_FLAG_BITS;
     383             : 
     384       64754 :                     if ( hIsmMetaData[0]->ism_imp == ISM_NO_META )
     385             :                     {
     386             :                         /* signal low-rate ISM_NO_META frame */
     387        2310 :                         push_next_indice( hMetaData, 0, ISM_METADATA_MD_FLAG_BITS );
     388        2310 :                         hQMetaData->metadata_max_bits -= ISM_METADATA_MD_FLAG_BITS;
     389             : 
     390             :                         /* signal presence of MD in low-rate ISM_NO_META frame */
     391        2310 :                         push_next_indice( hMetaData, hIsmMetaData[0]->ism_md_lowrate_flag, ISM_METADATA_INACTIVE_FLAG_BITS );
     392        2310 :                         hQMetaData->metadata_max_bits -= ISM_METADATA_INACTIVE_FLAG_BITS;
     393             :                     }
     394             :                 }
     395             :             }
     396       99812 :             else if ( ism_mode == ISM_MASA_MODE_DISC )
     397             :             {
     398      378322 :                 for ( i = 0; i < nchan_ism; i++ )
     399             :                 {
     400      278510 :                     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      278510 :                         push_next_indice( hMetaData, hIsmMetaData[i]->ism_imp, ISM_METADATA_FLAG_BITS );
     415      278510 :                         hQMetaData->metadata_max_bits -= ISM_METADATA_FLAG_BITS;
     416             : 
     417      278510 :                         if ( hIsmMetaData[i]->ism_imp == ISM_NO_META )
     418             :                         {
     419             :                             /* signal low-rate ISM_NO_META frame */
     420       11566 :                             push_next_indice( hMetaData, 0, ISM_METADATA_MD_FLAG_BITS );
     421       11566 :                             hQMetaData->metadata_max_bits -= ISM_METADATA_MD_FLAG_BITS;
     422             : 
     423             :                             /* signal presence of MD in low-rate ISM_NO_META frame */
     424       11566 :                             push_next_indice( hMetaData, hIsmMetaData[i]->ism_md_lowrate_flag, ISM_METADATA_INACTIVE_FLAG_BITS );
     425       11566 :                             hQMetaData->metadata_max_bits -= ISM_METADATA_INACTIVE_FLAG_BITS;
     426             :                         }
     427             :                     }
     428             :                 }
     429             : 
     430       99812 :                 if ( ivas_total_brate == IVAS_128k && nchan_ism >= 3 )
     431             :                 {
     432        3786 :                     push_next_indice( hMetaData, flag_omasa_ener_brate, 1 );
     433        3786 :                     hQMetaData->metadata_max_bits -= 1;
     434             :                 }
     435             :             }
     436             :         }
     437             :         else
     438             :         {
     439      657283 :             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       62372 :                 if ( nchan_ism == 1 || nchan_ism == 2 )
     443             :                 {
     444       21364 :                     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       41008 :                     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      594911 :                 push_next_indice( hMetaData, nchan_transport - 1, MASA_TRANSP_BITS );
     456             :             }
     457      657283 :             hQMetaData->metadata_max_bits -= MASA_TRANSP_BITS;
     458             :         }
     459             : 
     460      885461 :         if ( ivas_format == MASA_ISM_FORMAT && ism_mode == ISM_MODE_NONE )
     461             :         {
     462       62372 :             if ( nchan_ism >= 3 ) /* if 3 or 4 objects */
     463             :             {
     464       41008 :                 push_next_indice( hMetaData, 5 - nchan_ism, MASA_HEADER_BITS );
     465             :             }
     466             :             else
     467             :             {
     468       21364 :                 push_next_indice( hMetaData, 3, MASA_HEADER_BITS );
     469             :             }
     470       62372 :             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      823089 :             push_next_indice( hMetaData, 0, MASA_HEADER_BITS );
     477      823089 :             hQMetaData->metadata_max_bits -= MASA_HEADER_BITS;
     478             :         }
     479      885461 :         if ( !( ivas_format == MASA_ISM_FORMAT && ism_mode == ISM_MODE_NONE && nchan_ism > 2 ) )
     480             :         {
     481             :             /* write number of directions */
     482      844453 :             push_next_indice( hMetaData, hQMetaData->no_directions - 1, 1 );
     483      844453 :             hQMetaData->metadata_max_bits -= 1;
     484             :         }
     485             :         /* write subframe mode */
     486      885461 :         push_next_indice( hMetaData, hQMetaData->q_direction[0].cfg.nblocks == 1 ? 1 : 0, MASA_SUBFRAME_BITS );
     487      885461 :         hQMetaData->metadata_max_bits -= MASA_SUBFRAME_BITS;
     488             :     }
     489             : 
     490     1068601 :     if ( ivas_format == MC_FORMAT )
     491             :     {
     492             :         int16_t lfeBitsWritten;
     493      183140 :         lfeBitsWritten = encode_lfe_to_total_energy_ratio( hMasa, hMetaData, ivas_total_brate );
     494      183140 :         hQMetaData->metadata_max_bits -= lfeBitsWritten;
     495             :     }
     496             : 
     497             :     /* Move data from encoder to qmetadata */
     498     1068601 :     if ( ivas_format == MASA_FORMAT || ivas_format == MASA_ISM_FORMAT )
     499             :     {
     500      885461 :         move_metadata_to_qmetadata( hMasa, hQMetaData );
     501             :     }
     502             : 
     503     1068601 :     if ( hMasa->config.max_metadata_bits < MINIMUM_BIT_BUDGET_NORMAL_META && !hMasa->config.joinedSubframes )
     504             :     {
     505      330389 :         reduce_metadata_further( hMasa, hQMetaData, ivas_format );
     506             : 
     507      330389 :         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      330389 :         push_next_indice( hMetaData, hQMetaData->q_direction[0].cfg.nblocks == 1 ? 1 : 0, MASA_LOWBITRATE_MODE_BITS );
     511      330389 :         hQMetaData->metadata_max_bits -= MASA_LOWBITRATE_MODE_BITS;
     512             :     }
     513             : 
     514             :     /* Encode MASA+ISM metadata */
     515     1068601 :     if ( ivas_format == MASA_ISM_FORMAT && ism_mode == ISM_MASA_MODE_PARAM_ONE_OBJ )
     516             :     {
     517             :         /* encode MASA/ISM energy ratios */
     518       63612 :         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     1004989 :         if ( ivas_format == MASA_ISM_FORMAT )
     523             :         {
     524      226938 :             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     1068601 :     masa_total_brate = ivas_total_brate;
     530     1068601 :     if ( ivas_format == MASA_ISM_FORMAT && ism_mode == ISM_MASA_MODE_DISC )
     531             :     {
     532       99812 :         masa_total_brate = calculate_cpe_brate_MASA_ISM( ism_mode, ivas_total_brate, nchan_ism );
     533             :     }
     534             : 
     535     1068601 :     if ( masa_total_brate >= IVAS_384k )
     536             :     {
     537       66396 :         if ( masa_total_brate >= IVAS_512k )
     538             :         {
     539       25910 :             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       40486 :             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     1002205 :         if ( ( error = ivas_qmetadata_enc_encode( hMetaData, hQMetaData, 0 ) ) != IVAS_ERR_OK )
     555             :         {
     556           0 :             return error;
     557             :         }
     558             :     }
     559             : 
     560     1068601 :     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       63612 :         ivas_omasa_modify_masa_energy_ratios( hQMetaData, hMasa->data.hOmasaData->masa_to_total_energy_ratio );
     564             :     }
     565             : 
     566     1068601 :     *nb_bits_metadata = hMetaData->nb_bits_tot;
     567             : 
     568     1068601 :     if ( ivas_format == MASA_FORMAT && Opt_DTX_ON )
     569             :     {
     570             :         /* save old values */
     571       63803 :         uint8_t numCodingBands = hMasa->config.numCodingBands;
     572       63803 :         uint8_t numTwoDirBands = hMasa->config.numTwoDirBands;
     573       63803 :         int16_t nbands = hQMetaData->q_direction[0].cfg.nbands;
     574       63803 :         uint8_t numberOfDirections = hMasa->config.numberOfDirections;
     575       63803 :         uint8_t numberOfDirectionsMeta = hMasa->masaMetadata.descriptive_meta.numberOfDirections;
     576       63803 :         uint16_t numberOfDirectionsQMetaData = hQMetaData->no_directions;
     577             : 
     578       63803 :         if ( !( hMasa->config.numberOfDirections == 1 && hQMetaData->q_direction->cfg.nbands == 5 ) )
     579             :         {
     580       71535 :             for ( i = 0; i < MASA_MAXIMUM_DIRECTIONS; i++ )
     581             :             {
     582      238450 :                 for ( j = 0; j < MAX_PARAM_SPATIAL_SUBFRAMES; j++ )
     583             :                 {
     584      190760 :                     mvr2r( h_orig_metadata[i].azimuth[j], hMasa->masaMetadata.directional_meta[i].azimuth[j], MASA_FREQUENCY_BANDS );
     585      190760 :                     mvr2r( h_orig_metadata[i].elevation[j], hMasa->masaMetadata.directional_meta[i].elevation[j], MASA_FREQUENCY_BANDS );
     586      190760 :                     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       23845 :             hMasa->config.numCodingBands = 5;
     592       23845 :             hMasa->config.numTwoDirBands = 0;
     593       23845 :             combine_freqbands_and_subframes( hMasa );
     594       23845 :             hQMetaData->q_direction[0].cfg.nbands = 5;
     595             : 
     596       23845 :             if ( hMasa->config.numberOfDirections == 2 && hMasa->config.numTwoDirBands < hMasa->config.numCodingBands )
     597             :             {
     598             :                 /* Combine directions */
     599        4509 :                 ivas_masa_combine_directions( hMasa );
     600             : 
     601             :                 /* If we joined all bands, then metadata is now one directional. */
     602        4509 :                 if ( hMasa->config.numTwoDirBands == 0 )
     603             :                 {
     604        4509 :                     hMasa->config.numberOfDirections = 1;
     605        4509 :                     hMasa->masaMetadata.descriptive_meta.numberOfDirections = 0;
     606        4509 :                     hQMetaData->no_directions = 1;
     607             :                 }
     608             :             }
     609             : 
     610       23845 :             move_metadata_to_qmetadata( hMasa, hQMetaData );
     611             : 
     612      143070 :             for ( j = hQMetaData->q_direction[0].cfg.start_band; j < hQMetaData->q_direction[0].cfg.nbands; ++j )
     613             :             {
     614      119225 :                 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       63803 :         free( h_orig_metadata );
     619             : 
     620       63803 :         ivas_qmetadata_enc_sid_encode( hMetaData, hQMetaData, masa_sid_descriptor, 0, ivas_format );
     621             : 
     622             :         /* restore old values */
     623       63803 :         hMasa->config.numCodingBands = numCodingBands;
     624       63803 :         hMasa->config.numTwoDirBands = numTwoDirBands;
     625       63803 :         hQMetaData->q_direction[0].cfg.nbands = nbands;
     626       63803 :         hMasa->config.numberOfDirections = numberOfDirections;
     627       63803 :         hMasa->masaMetadata.descriptive_meta.numberOfDirections = numberOfDirectionsMeta;
     628       63803 :         hQMetaData->no_directions = numberOfDirectionsQMetaData;
     629             :     }
     630             : 
     631     1068601 :     return IVAS_ERR_OK;
     632             : }
     633             : 
     634             : 
     635             : /*-----------------------------------------------------------------------*
     636             :  * ivas_masa_estimate_energy()
     637             :  *
     638             :  *
     639             :  *-----------------------------------------------------------------------*/
     640             : 
     641      885461 : 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      885461 :     maxBin = (int16_t) ( (float) CLDFB_NO_CHANNELS_MAX * (float) input_frame / L_FRAME48k + 0.5f );
     655             : 
     656      885461 :     l_ts = input_frame / CLDFB_NO_COL_MAX;
     657             : 
     658     4427305 :     for ( block_m_idx = 0; block_m_idx < MAX_PARAM_SPATIAL_SUBFRAMES; block_m_idx++ )
     659             :     {
     660     3541844 :         mrange[0] = hMasa->config.block_grouping[block_m_idx];
     661     3541844 :         mrange[1] = hMasa->config.block_grouping[block_m_idx + 1];
     662             : 
     663     3541844 :         set_zero( hMasa->data.energy[block_m_idx], MASA_FREQUENCY_BANDS );
     664             : 
     665    17709220 :         for ( ts = mrange[0]; ts < mrange[1]; ts++ )
     666             :         {
     667    39143968 :             for ( i = 0; i < nchan_transport; i++ )
     668             :             {
     669    24976592 :                 cldfbAnalysis_ts( &( data_f[i][l_ts * ts] ), Input_RealBuffer[i], Input_ImagBuffer[i], l_ts, hMasa->data.cldfbAnaEnc[i] );
     670             :             }
     671             : 
     672   354184400 :             for ( band_m_idx = 0; band_m_idx < MASA_FREQUENCY_BANDS; band_m_idx++ )
     673             :             {
     674   340017024 :                 brange[0] = hMasa->config.band_grouping[band_m_idx];
     675   340017024 :                 brange[1] = hMasa->config.band_grouping[band_m_idx + 1];
     676             : 
     677   939455232 :                 for ( i = 0; i < nchan_transport; i++ )
     678             :                 {
     679   599438208 :                     if ( brange[0] > maxBin )
     680             :                     {
     681     2788320 :                         hMasa->data.energy[block_m_idx][band_m_idx] = 0;
     682     2788320 :                         continue;
     683             :                     }
     684   596649888 :                     else if ( brange[1] >= maxBin )
     685             :                     {
     686    27530112 :                         brange[1] = maxBin;
     687             :                     }
     688             : 
     689  2025586208 :                     for ( j = brange[0]; j < brange[1]; j++ )
     690             :                     {
     691  1428936320 :                         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      885461 :     return;
     699             : }
     700             : 
     701             : 
     702             : /*-----------------------------------------------------------------------*
     703             :  * ivas_masa_enc_config()
     704             :  *
     705             :  * Frame-by-frame configuration of MASA encoder
     706             :  *-----------------------------------------------------------------------*/
     707             : 
     708      892289 : 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      892289 :     error = IVAS_ERR_OK;
     727             : 
     728      892289 :     hMasa = st_ivas->hMasa;
     729      892289 :     hQMetaData = st_ivas->hQMetaData;
     730      892289 :     ivas_format = st_ivas->hEncoderConfig->ivas_format;
     731      892289 :     ivas_total_brate = st_ivas->hEncoderConfig->ivas_total_brate;
     732             : 
     733      892289 :     ism_total_brate = 0;
     734      892289 :     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      635054 :         for ( i = 0; i < st_ivas->nSCE; i++ )
     737             :         {
     738      406876 :             ism_total_brate += st_ivas->hSCE[i]->element_brate;
     739             :         }
     740             :     }
     741             : 
     742      892289 :     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      892289 :     hQMetaData->is_masa_ivas_format = 1;
     745             : 
     746      892289 :     if ( ivas_format == MASA_FORMAT || ivas_format == MASA_ISM_FORMAT )
     747             :     {
     748      885461 :         masa_metadata_direction_alignment( hMasa );
     749             : 
     750      885461 :         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      885461 :         if ( hMasa->data.sync_state.frame_mode == MASA_FRAME_1SF && hMasa->data.sync_state.prev_offset != 0 )
     753             :         {
     754             :             /* average over sub-frames */
     755      109833 :             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      885461 :         detect_metadata_composition( hMasa, &joinedSubframes, &coherencePresent, &isActualTwoDir );
     760      885461 :         hMasa->config.joinedSubframes = joinedSubframes;
     761      885461 :         hMasa->config.coherencePresent = coherencePresent;
     762      885461 :         hMasa->config.numberOfDirections = ( hMasa->masaMetadata.descriptive_meta.numberOfDirections + 1 ) == 2 && isActualTwoDir ? 2 : 1;
     763             :     }
     764        6828 :     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        6828 :         hMasa->config.joinedSubframes = 0;
     768        6828 :         hMasa->config.numberOfDirections = 1;
     769             :     }
     770             : 
     771      892289 :     if ( ivas_format == MASA_ISM_FORMAT )
     772             :     {
     773      290550 :         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      601739 :         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      892289 :     if ( hMasa->config.numberOfDirections == 2 )
     782             :     {
     783      337682 :         set_f( hMasa->data.importanceWeight, 1.0f, hMasa->config.numCodingBands );
     784             : 
     785      337682 :         if ( hMasa->config.numCodingBands == 5 )
     786             :         {
     787      212421 :             hMasa->data.importanceWeight[4] = 0.7f;
     788             :         }
     789      125261 :         else if ( hMasa->config.numCodingBands == 8 )
     790             :         {
     791       21549 :             hMasa->data.importanceWeight[7] = 0.7f;
     792             :         }
     793      103712 :         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      103712 :         else if ( hMasa->config.numCodingBands == 12 )
     799             :         {
     800       41387 :             hMasa->data.importanceWeight[10] = 0.7f;
     801       41387 :             hMasa->data.importanceWeight[11] = 0.1f;
     802             :         }
     803       62325 :         else if ( hMasa->config.numCodingBands == 18 )
     804             :         {
     805       41467 :             hMasa->data.importanceWeight[14] = 0.8f;
     806       41467 :             hMasa->data.importanceWeight[15] = 0.5f;
     807       41467 :             hMasa->data.importanceWeight[16] = 0.2f;
     808       41467 :             hMasa->data.importanceWeight[17] = 0.0f;
     809             :         }
     810       20858 :         else if ( hMasa->config.numCodingBands == 24 )
     811             :         {
     812       20858 :             hMasa->data.importanceWeight[20] = 0.8f;
     813       20858 :             hMasa->data.importanceWeight[21] = 0.5f;
     814       20858 :             hMasa->data.importanceWeight[22] = 0.2f;
     815       20858 :             hMasa->data.importanceWeight[23] = 0.0f;
     816             :         }
     817             : 
     818      337682 :         if ( hMasa->config.numTwoDirBands == hMasa->config.numCodingBands )
     819             :         {
     820        7416 :             set_c( (int8_t *) hMasa->data.twoDirBands, 1, hMasa->config.numCodingBands );
     821             :         }
     822             :     }
     823             :     else
     824             :     {
     825      554607 :         set_c( (int8_t *) hMasa->data.twoDirBands, 0, hMasa->config.numCodingBands );
     826             :     }
     827             : 
     828             :     /* Set qmeta to correct values */
     829      892289 :     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     1947245 :     for ( i = 0; i < hQMetaData->no_directions; i++ )
     835             :     {
     836     1054956 :         hQMetaData->q_direction[i].cfg.nbands = hMasa->config.numCodingBands;
     837     1054956 :         hQMetaData->q_direction[i].cfg.nblocks = hMasa->config.joinedSubframes == TRUE ? 1 : MAX_PARAM_SPATIAL_SUBFRAMES;
     838             : 
     839     1054956 :         if ( ivas_format == MC_FORMAT )
     840             :         {
     841        6828 :             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     1048128 :             hQMetaData->q_direction[i].cfg.mc_ls_setup = MC_LS_SETUP_INVALID;
     847             :         }
     848             :     }
     849             : 
     850      892289 :     hQMetaData->all_coherence_zero = !hMasa->config.coherencePresent;
     851             : 
     852      892289 :     ivas_set_qmetadata_maxbit_req( hQMetaData, ivas_format );
     853             : 
     854             :     /* Find maximum band usable */
     855      892289 :     maxBin = (int16_t) ( st_ivas->hEncoderConfig->input_Fs * INV_CLDFB_BANDWIDTH );
     856      892289 :     maxBand = 0;
     857    23025698 :     while ( maxBand <= MASA_FREQUENCY_BANDS && MASA_band_grouping_24[maxBand] <= maxBin )
     858             :     {
     859    22133409 :         maxBand++;
     860             :     }
     861      892289 :     maxBand--;
     862             : 
     863      892289 :     st_ivas->hQMetaData->q_direction->cfg.inactiveBands = 0;
     864      892289 :     masa_total_brate = ivas_total_brate;
     865      892289 :     if ( ivas_format == MASA_ISM_FORMAT && st_ivas->ism_mode == ISM_MASA_MODE_DISC )
     866             :     {
     867       99812 :         masa_total_brate = calculate_cpe_brate_MASA_ISM( st_ivas->ism_mode, ivas_total_brate, st_ivas->hEncoderConfig->nchan_ism );
     868             :     }
     869      892289 :     if ( masa_total_brate >= IVAS_384k && ( ivas_format == MASA_FORMAT || ivas_format == MASA_ISM_FORMAT ) )
     870             :     {
     871             :         int16_t continueLoop;
     872       66396 :         continueLoop = 1;
     873      232022 :         while ( maxBand > 5 && continueLoop )
     874             :         {
     875      584550 :             for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
     876             :             {
     877      481194 :                 if ( hMasa->data.energy[sf][maxBand - 1] > 100000 )
     878             :                 {
     879       62270 :                     continueLoop = 0;
     880       62270 :                     break;
     881             :                 }
     882             :             }
     883      165626 :             if ( continueLoop )
     884             :             {
     885      103356 :                 maxBand--;
     886             :             }
     887             :         }
     888             : 
     889       66396 :         if ( maxBand < MASA_MAXIMUM_CODING_SUBBANDS )
     890             :         {
     891       14670 :             st_ivas->hQMetaData->q_direction->cfg.inactiveBands = MASA_MAXIMUM_CODING_SUBBANDS - maxBand;
     892             :         }
     893             :         else
     894             :         {
     895       51726 :             st_ivas->hQMetaData->q_direction->cfg.inactiveBands = 0;
     896             :         }
     897             :     }
     898             : 
     899      892289 :     masa_sample_rate_band_correction( &( hMasa->config ), hMasa->data.band_mapping, hQMetaData, maxBand, masa_total_brate >= IVAS_384k, NULL );
     900             : 
     901      892289 :     if ( hMasa->config.numTwoDirBands >= hMasa->config.numCodingBands )
     902             :     {
     903        8930 :         hMasa->config.numTwoDirBands = hMasa->config.numCodingBands;
     904        8930 :         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      892289 :     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      267232 :         st_ivas->hCPE[0]->hStereoDft->hConfig->force_mono_transmission = ( ivas_total_brate - ism_total_brate < MASA_STEREO_MIN_BITRATE ) ? 1 : 0;
     911             :     }
     912             : 
     913      892289 :     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      228178 :         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       95998 :             st_ivas->hMasa->data.hOmasaData->lp_noise_CPE = st_ivas->hCPE[0]->hCoreCoder[0]->lp_noise;
     918             :         }
     919             :         else
     920             :         {
     921      132180 :             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      892289 :     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      121313 : 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      121313 :     float surrCohSignificanceCoef = 0.4f;
     946      121313 :     float threshold = 0.1f;
     947             : 
     948      318066 :     for ( sf = 0; sf < nSubFrames; sf++ )
     949             :     {
     950      228620 :         surrCohToTotalSum = 0.0f;
     951      228620 :         surrCohToTotalTimesDiffSum = 0.0f;
     952      228620 :         diffSum = 0.0f;
     953     5315892 :         for ( band = 0; band < nBands; band++ )
     954             :         {
     955     5087272 :             surrCohToTotal = diffuse_to_total_ratio[sf][band] * surroundingCoherence[sf][band];
     956     5087272 :             surrCohToTotalSum += surrCohToTotal;
     957     5087272 :             surrCohToTotalTimesDiffSum += diffuse_to_total_ratio[sf][band] * surrCohToTotal;
     958     5087272 :             diffSum += diffuse_to_total_ratio[sf][band];
     959             :         }
     960      228620 :         significanceMeasure1 = surrCohToTotalSum / (float) nBands;
     961      228620 :         significanceMeasure2 = surrCohSignificanceCoef * surrCohToTotalTimesDiffSum / ( diffSum + EPSILON );
     962      228620 :         significanceMeasure = max( significanceMeasure1, significanceMeasure2 );
     963             : 
     964      228620 :         if ( significanceMeasure > threshold )
     965             :         {
     966       31867 :             return 1; /* Surrounding coherence was significant in at least one subframe */
     967             :         }
     968             :     }
     969             : 
     970       89446 :     return 0; /* Surrounding coherence was not significant in any subframe */
     971             : }
     972             : 
     973             : 
     974             : /*-----------------------------------------------------------------------*
     975             :  * Local functions
     976             :  *-----------------------------------------------------------------------*/
     977             : 
     978      909306 : 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      909306 :     numCodingBands = hMasa->config.numCodingBands;
    1004      909306 :     numDirections = hMasa->config.numberOfDirections;
    1005      909306 :     numSf = hMasa->config.joinedSubframes == TRUE ? 1 : MAX_PARAM_SPATIAL_SUBFRAMES;
    1006      909306 :     hMeta = &( hMasa->masaMetadata );
    1007             : 
    1008      909306 :     mergeRatiosOverSubframes = hMasa->config.mergeRatiosOverSubframes;
    1009      909306 :     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      909306 :     if ( numSf == 1 )
    1015             :     {
    1016     1247380 :         for ( j = 1; j < MAX_PARAM_SPATIAL_SUBFRAMES; j++ )
    1017             :         {
    1018    23388375 :             for ( k = 0; k < MASA_FREQUENCY_BANDS; k++ )
    1019             :             {
    1020    22452840 :                 hMasa->data.energy[0][k] += hMasa->data.energy[j][k];
    1021             :             }
    1022             :         }
    1023             :     }
    1024             : 
    1025      909306 :     if ( numCodingBands <= MAX_REDUCED_NBANDS )
    1026             :     {
    1027             :         /* reduce metadata *frequency* resolution. time resolution is not touched */
    1028     1945171 :         for ( i = 0; i < numDirections; i++ )
    1029             :         {
    1030     4462985 :             for ( j = 0; j < numSf; j++ ) /* NB: for numSf==1, operates only on first sub-frame */
    1031             :             {
    1032    83218975 :                 for ( k = 0; k < MASA_FREQUENCY_BANDS; k++ )
    1033             :                 {
    1034    79890216 :                     aziRad = hMeta->directional_meta[i].azimuth[j][k] / 180.0f * EVS_PI;
    1035    79890216 :                     eleRad = hMeta->directional_meta[i].elevation[j][k] / 180.0f * EVS_PI;
    1036    79890216 :                     vecLen = hMeta->directional_meta[i].energy_ratio[j][k] * hMasa->data.energy[j][k];
    1037             : 
    1038    79890216 :                     x[i][j][k] = cosf( aziRad ) * cosf( eleRad ) * vecLen;
    1039    79890216 :                     y[i][j][k] = sinf( aziRad ) * cosf( eleRad ) * vecLen;
    1040    79890216 :                     z[i][j][k] = sinf( eleRad ) * vecLen;
    1041             :                 }
    1042             :             }
    1043             :         }
    1044             : 
    1045     1945171 :         for ( i = 0; i < numDirections; i++ )
    1046             :         {
    1047     4462985 :             for ( j = 0; j < numSf; j++ )
    1048             :             {
    1049    25738452 :                 for ( k = 0; k < numCodingBands; k++ )
    1050             :                 {
    1051    22409693 :                     brange[0] = hMasa->data.band_mapping[k];
    1052    22409693 :                     brange[1] = hMasa->data.band_mapping[k + 1];
    1053             : 
    1054    22409693 :                     xSum = 0.0f;
    1055    22409693 :                     ySum = 0.0f;
    1056    22409693 :                     zSum = 0.0f;
    1057    22409693 :                     energySum = 0.0f;
    1058    22409693 :                     spreadCohSum = 0.0f;
    1059             : 
    1060   100322942 :                     for ( m = brange[0]; m < brange[1]; m++ )
    1061             :                     {
    1062    77913249 :                         xSum += x[i][j][m];
    1063    77913249 :                         ySum += y[i][j][m];
    1064    77913249 :                         zSum += z[i][j][m];
    1065    77913249 :                         energySum += hMasa->data.energy[j][m];
    1066             :                     }
    1067             : 
    1068    22409693 :                     aziRad = atan2f( ySum, xSum );
    1069    22409693 :                     eleRad = atan2f( zSum, sqrtf( xSum * xSum + ySum * ySum ) );
    1070             : 
    1071    22409693 :                     hMeta->directional_meta[i].azimuth[j][k] = aziRad / EVS_PI * 180.0f;
    1072    22409693 :                     hMeta->directional_meta[i].elevation[j][k] = eleRad / EVS_PI * 180.0f;
    1073             : 
    1074    22409693 :                     vecLen = sqrtf( xSum * xSum + ySum * ySum + zSum * zSum );
    1075    22409693 :                     hMeta->directional_meta[i].energy_ratio[j][k] = vecLen / ( energySum + EPSILON );
    1076             : 
    1077    22409693 :                     if ( computeCoherence )
    1078             :                     {
    1079    51986273 :                         for ( m = brange[0]; m < brange[1]; m++ )
    1080             :                         {
    1081    38527898 :                             spreadCohSum += hMeta->directional_meta[i].spread_coherence[j][m] * hMasa->data.energy[j][m];
    1082             :                         }
    1083    13458375 :                         hMeta->directional_meta[i].spread_coherence[j][k] = spreadCohSum / ( energySum + EPSILON );
    1084             : 
    1085    13458375 :                         if ( i == 0 )
    1086             :                         {
    1087     9478546 :                             surrCohSum = 0.0f;
    1088    36497632 :                             for ( m = brange[0]; m < brange[1]; m++ )
    1089             :                             {
    1090    27019086 :                                 surrCohSum += hMeta->common_meta.surround_coherence[j][m] * hMasa->data.energy[j][m];
    1091             :                             }
    1092     9478546 :                             hMeta->common_meta.surround_coherence[j][k] = surrCohSum / ( energySum + EPSILON );
    1093             :                         }
    1094             :                     }
    1095             : 
    1096    22409693 :                     if ( i == 0 )
    1097             :                     {
    1098    16097360 :                         energy[j][k] = energySum;
    1099             :                     }
    1100             :                 }
    1101             :             }
    1102             :         }
    1103             :     }
    1104       98361 :     else if ( mergeRatiosOverSubframes ) /* keep frequency resolution */
    1105             :     {
    1106      111925 :         for ( j = 0; j < numSf; j++ )
    1107             :         {
    1108     2234500 :             for ( k = 0; k < numCodingBands; k++ )
    1109             :             {
    1110     2144960 :                 energy[j][k] = hMasa->data.energy[j][k];
    1111             :             }
    1112             :         }
    1113             :     }
    1114             : 
    1115      909306 :     if ( mergeRatiosOverSubframes )
    1116             :     {
    1117     4228528 :         for ( k = 0; k < numCodingBands; k++ )
    1118             :         {
    1119     3690099 :             energySum = 0.0f;
    1120    18450495 :             for ( j = 0; j < numSf; j++ )
    1121             :             {
    1122    14760396 :                 energySum += energy[j][k];
    1123             :             }
    1124             : 
    1125     3690099 :             if ( computeCoherence )
    1126             :             {
    1127     2281279 :                 surrCohSum = 0.0f;
    1128    11406395 :                 for ( j = 0; j < numSf; j++ )
    1129             :                 {
    1130     9125116 :                     surrCohSum += energy[j][k] * hMeta->common_meta.surround_coherence[j][k];
    1131             :                 }
    1132     2281279 :                 surrCohTemp = surrCohSum / ( energySum + EPSILON );
    1133             : 
    1134    11406395 :                 for ( j = 0; j < numSf; j++ )
    1135             :                 {
    1136     9125116 :                     hMeta->common_meta.surround_coherence[j][k] = surrCohTemp;
    1137             :                 }
    1138             :             }
    1139             : 
    1140     8592395 :             for ( i = 0; i < numDirections; i++ )
    1141             :             {
    1142     4902296 :                 energyRatioSum = 0.0f;
    1143    24511480 :                 for ( j = 0; j < numSf; j++ )
    1144             :                 {
    1145    19609184 :                     energyRatioSum += energy[j][k] * hMeta->directional_meta[i].energy_ratio[j][k];
    1146             :                 }
    1147     4902296 :                 energyRatioTemp = energyRatioSum / ( energySum + EPSILON );
    1148             : 
    1149    24511480 :                 for ( j = 0; j < numSf; j++ )
    1150             :                 {
    1151    19609184 :                     hMeta->directional_meta[i].energy_ratio[j][k] = energyRatioTemp;
    1152             :                 }
    1153             :             }
    1154             :         }
    1155             :     }
    1156             : 
    1157      909306 :     return;
    1158             : }
    1159             : 
    1160             : 
    1161             : /*-------------------------------------------------------------------*
    1162             :  * ivas_masa_combine_directions()
    1163             :  *
    1164             :  *
    1165             :  *-------------------------------------------------------------------*/
    1166             : 
    1167      333261 : 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      333261 :     numCodingBands = hMasa->config.numCodingBands;
    1199      333261 :     numDirections = hMasa->config.numberOfDirections;
    1200      333261 :     numSf = hMasa->config.joinedSubframes == TRUE ? 1 : MAX_PARAM_SPATIAL_SUBFRAMES;
    1201             : 
    1202      333261 :     hMeta = &( hMasa->masaMetadata );
    1203             : 
    1204      333261 :     computeCoherence = hMasa->config.useCoherence && hMasa->config.coherencePresent;
    1205             : 
    1206      999783 :     for ( i = 0; i < numDirections; i++ )
    1207             :     {
    1208     2588304 :         for ( j = 0; j < numSf; j++ )
    1209             :         {
    1210    22529194 :             for ( k = 0; k < numCodingBands; k++ )
    1211             :             {
    1212    20607412 :                 aziRad = hMeta->directional_meta[i].azimuth[j][k] / 180.0f * EVS_PI;
    1213    20607412 :                 eleRad = hMeta->directional_meta[i].elevation[j][k] / 180.0f * EVS_PI;
    1214    20607412 :                 vecLen = hMeta->directional_meta[i].energy_ratio[j][k];
    1215             : 
    1216    20607412 :                 x[i][j][k] = cosf( aziRad ) * cosf( eleRad ) * vecLen;
    1217    20607412 :                 y[i][j][k] = sinf( aziRad ) * cosf( eleRad ) * vecLen;
    1218    20607412 :                 z[i][j][k] = sinf( eleRad ) * vecLen;
    1219             :             }
    1220             :         }
    1221             :     }
    1222             : 
    1223             :     /* Compute sum vector */
    1224     1294152 :     for ( j = 0; j < numSf; j++ )
    1225             :     {
    1226    11264597 :         for ( k = 0; k < numCodingBands; k++ )
    1227             :         {
    1228    10303706 :             xSum[j][k] = x[0][j][k] + x[1][j][k];
    1229    10303706 :             ySum[j][k] = y[0][j][k] + y[1][j][k];
    1230    10303706 :             zSum[j][k] = z[0][j][k] + z[1][j][k];
    1231    10303706 :             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     4244204 :     for ( i = 0; i < numCodingBands; i++ )
    1237             :     {
    1238     3910943 :         importance[i] = 0.0f;
    1239    14214649 :         for ( j = 0; j < numSf; j++ )
    1240             :         {
    1241    10303706 :             tempImportance = hMeta->directional_meta[0].energy_ratio[j][i] + hMeta->directional_meta[1].energy_ratio[j][i] - sumVecLen[j][i];
    1242    10303706 :             importance[i] += tempImportance;
    1243             :         }
    1244     3910943 :         importance[i] /= (float) numSf;
    1245     3910943 :         importance[i] *= hMasa->data.importanceWeight[i];
    1246             :     }
    1247             : 
    1248             :     /* Determine bands where to use two directions */
    1249      333261 :     find_n_largest( importance, indicesOfLargest, numCodingBands, hMasa->config.numTwoDirBands );
    1250             : 
    1251     4244204 :     for ( i = 0; i < numCodingBands; i++ )
    1252             :     {
    1253     3910943 :         hMasa->data.twoDirBands[i] = 0;
    1254             :     }
    1255             : 
    1256      932449 :     for ( i = 0; i < hMasa->config.numTwoDirBands; i++ )
    1257             :     {
    1258      599188 :         hMasa->data.twoDirBands[indicesOfLargest[i]] = 1;
    1259             :     }
    1260             : 
    1261             :     /* Combine directions on the remaining bands */
    1262     4244204 :     for ( i = 0; i < numCodingBands; i++ )
    1263             :     {
    1264     3910943 :         if ( hMasa->data.twoDirBands[i] == 0 )
    1265             :         {
    1266    12041648 :             for ( j = 0; j < numSf; j++ )
    1267             :             {
    1268     8729893 :                 aziRad = atan2f( ySum[j][i], xSum[j][i] );
    1269     8729893 :                 eleRad = atan2f( zSum[j][i], sqrtf( xSum[j][i] * xSum[j][i] + ySum[j][i] * ySum[j][i] ) );
    1270             : 
    1271     8729893 :                 hMeta->directional_meta[0].azimuth[j][i] = aziRad / EVS_PI * 180.0f;
    1272     8729893 :                 hMeta->directional_meta[0].elevation[j][i] = eleRad / EVS_PI * 180.0f;
    1273             : 
    1274     8729893 :                 ratioSum = hMeta->directional_meta[0].energy_ratio[j][i] + hMeta->directional_meta[1].energy_ratio[j][i];
    1275     8729893 :                 if ( computeCoherence )
    1276             :                 {
    1277     3228753 :                     hMeta->directional_meta[0].spread_coherence[j][i] =
    1278     3228753 :                         ( 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     8729893 :                 ambience2dir = 1.0f - ratioSum;
    1282     8729893 :                 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     8729893 :                 hMeta->directional_meta[1].energy_ratio[j][i] = 0.0f;
    1284     8729893 :                 hMeta->common_meta.diffuse_to_total_ratio[j][i] = 1.0f - hMeta->directional_meta[0].energy_ratio[j][i];
    1285     8729893 :                 if ( computeCoherence )
    1286             :                 {
    1287     3228753 :                     ambience1dir = 1.0f - hMeta->directional_meta[0].energy_ratio[j][i];
    1288     3228753 :                     ambienceIncrease = max( ambience1dir - ambience2dir, 0.0f );
    1289             : 
    1290     3228753 :                     origSurrCohEne = ambience2dir * hMeta->common_meta.surround_coherence[j][i];
    1291     3228753 :                     newSurrCohEne = ambienceIncrease * hMeta->directional_meta[0].spread_coherence[j][i];
    1292     3228753 :                     hMeta->common_meta.surround_coherence[j][i] = min( 1.0f, ( origSurrCohEne + newSurrCohEne ) / ( ambience1dir + EPSILON ) );
    1293             :                 }
    1294             :             }
    1295             :         }
    1296             :     }
    1297             : 
    1298      333261 :     return;
    1299             : }
    1300             : 
    1301             : 
    1302      333261 : 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     4244204 :     for ( j = 0; j < numElements; j++ )
    1314             :     {
    1315     3910943 :         values[j] = input[j];
    1316             :     }
    1317             : 
    1318      932449 :     for ( i = 0; i < numLargest; i++ )
    1319             :     {
    1320      599188 :         largestValue = values[0];
    1321      599188 :         largestIndex = 0;
    1322     9298494 :         for ( j = 1; j < numElements; j++ )
    1323             :         {
    1324     8699306 :             if ( values[j] > largestValue )
    1325             :             {
    1326     1253528 :                 largestValue = values[j];
    1327     1253528 :                 largestIndex = j;
    1328             :             }
    1329             :         }
    1330      599188 :         largestIndices[i] = largestIndex;
    1331      599188 :         values[largestIndex] = -1.0f;
    1332             :     }
    1333             : 
    1334      333261 :     return;
    1335             : }
    1336             : 
    1337             : 
    1338      909306 : 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      909306 :     numCodingBands = hMasa->config.numCodingBands;
    1349      909306 :     numDirections = hMasa->config.numberOfDirections;
    1350      909306 :     numSf = hMasa->config.joinedSubframes == TRUE ? 1 : MAX_PARAM_SPATIAL_SUBFRAMES;
    1351      909306 :     hMeta = &( hMasa->masaMetadata );
    1352             : 
    1353     1981279 :     for ( dir = 0; dir < numDirections; dir++ )
    1354             :     {
    1355     4247837 :         for ( sf = 0; sf < numSf; sf++ )
    1356             :         {
    1357    31506487 :             for ( band = 0; band < numCodingBands; band++ )
    1358             :             {
    1359    28330623 :                 hQMeta->q_direction[dir].band_data[band].azimuth[sf] = hMeta->directional_meta[dir].azimuth[sf][band];
    1360    28330623 :                 hQMeta->q_direction[dir].band_data[band].elevation[sf] = hMeta->directional_meta[dir].elevation[sf][band];
    1361    28330623 :                 hQMeta->q_direction[dir].band_data[band].energy_ratio[sf] = hMeta->directional_meta[dir].energy_ratio[sf][band];
    1362    28330623 :                 hQMeta->q_direction[dir].band_data[band].spherical_index[sf] = hMeta->directional_meta[dir].spherical_index[sf][band];
    1363    28330623 :                 if ( hQMeta->q_direction[dir].coherence_band_data != NULL )
    1364             :                 {
    1365    22555028 :                     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     3610995 :     for ( sf = 0; sf < numSf; sf++ )
    1372             :     {
    1373    26067753 :         for ( band = 0; band < numCodingBands; band++ )
    1374             :         {
    1375    23366064 :             if ( hQMeta->surcoh_band_data != NULL )
    1376             :             {
    1377    17590469 :                 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      909306 :     if ( numDirections > 1 )
    1383             :     {
    1384     2108725 :         for ( band = 0; band < numCodingBands; band++ )
    1385             :         {
    1386     1946058 :             hQMeta->twoDirBands[band] = hMasa->data.twoDirBands[band];
    1387             :         }
    1388      162667 :         hQMeta->numTwoDirBands = hMasa->config.numTwoDirBands;
    1389             :     }
    1390             : 
    1391             :     /* Copy spread coherence for DCT-based coding */
    1392      909306 :     if ( numSf == 1 && hMasa->config.useCoherence )
    1393             :     {
    1394      408041 :         for ( dir = 0; dir < numDirections; dir++ )
    1395             :         {
    1396      933744 :             for ( sf = 1; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1397             :             {
    1398    11901216 :                 for ( band = 0; band < numCodingBands; band++ )
    1399             :                 {
    1400    11200908 :                     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      909306 :     return;
    1407             : }
    1408             : 
    1409             : 
    1410             : /* This function studies parametric MASA metadata to provide information for codec configuration */
    1411      885461 : 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      885461 :     uint8_t dirValid[2] = { FALSE, FALSE };
    1422      885461 :     uint8_t cohPresent = FALSE;
    1423      885461 :     uint8_t sfDiffer = FALSE;
    1424             :     uint8_t sfSimilar;
    1425             : 
    1426      885461 :     hMeta = &( hMasa->masaMetadata );
    1427      885461 :     numDir = hMeta->descriptive_meta.numberOfDirections + 1;
    1428             : 
    1429      885461 :     *isTwoDir = FALSE;
    1430             : 
    1431             :     /* First check for valid two directions */
    1432      885461 :     if ( numDir == 1 )
    1433             :     {
    1434      542575 :         dirValid[0] = TRUE;
    1435             :     }
    1436             :     else
    1437             :     {
    1438             :         /* Default assumption */
    1439      342886 :         *isTwoDir = TRUE;
    1440             : 
    1441             :         /* Check for direct-to-total ratio values */
    1442     1028658 :         for ( dir = 0; dir < numDir; dir++ )
    1443             :         {
    1444      685772 :             sf = 0;
    1445     1392766 :             while ( !dirValid[dir] && sf < MAX_PARAM_SPATIAL_SUBFRAMES )
    1446             :             {
    1447      706994 :                 band = 0;
    1448     2205268 :                 while ( !dirValid[dir] && band < MASA_FREQUENCY_BANDS )
    1449             :                 {
    1450     1498274 :                     if ( hMeta->directional_meta[dir].energy_ratio[sf][band] >= MASA_RATIO_THRESHOLD )
    1451             :                     {
    1452      679104 :                         dirValid[dir] = TRUE;
    1453             :                     }
    1454     1498274 :                     band++;
    1455             :                 }
    1456      706994 :                 sf++;
    1457             :             }
    1458             :         }
    1459             : 
    1460      342886 :         if ( dirValid[1] == FALSE )
    1461             :         {
    1462             :             /* This handles also case where both are false. Then we just use first dir metadata. */
    1463        5204 :             *isTwoDir = FALSE;
    1464             :         }
    1465      337682 :         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      342886 :         if ( *isTwoDir == FALSE )
    1483             :         {
    1484             :             /* Further checks will be done with just one direction */
    1485        5204 :             numDir = 1;
    1486             :         }
    1487             :     }
    1488             : 
    1489             :     /* Check if data over subframes is identical. Check is done by comparing to first subframe. */
    1490      885461 :     sfSimilar = TRUE;
    1491      885461 :     sf = 1;
    1492     2554911 :     while ( ( sfSimilar == TRUE ) && ( sf < MAX_PARAM_SPATIAL_SUBFRAMES ) )
    1493             :     {
    1494     1669450 :         sfSimilar = are_masa_subframes_similar( hMeta, 0, hMeta, sf );
    1495     1669450 :         sf++;
    1496             :     }
    1497      885461 :     sfDiffer = sfSimilar == TRUE ? FALSE : TRUE;
    1498             : 
    1499             :     /* Further checks can be done with just one subframe if they are identical */
    1500      885461 :     nSubFrames = sfDiffer == TRUE ? MAX_PARAM_SPATIAL_SUBFRAMES : 1;
    1501             : 
    1502             :     /* Check spread coherence */
    1503      885461 :     dir = 0;
    1504     1787019 :     while ( cohPresent == FALSE && dir < numDir )
    1505             :     {
    1506      901558 :         sf = 0;
    1507     1961756 :         while ( cohPresent == FALSE && sf < nSubFrames )
    1508             :         {
    1509     1060198 :             band = 0;
    1510    10980364 :             while ( cohPresent == FALSE && band < MASA_FREQUENCY_BANDS )
    1511             :             {
    1512             :                 /* Check coherences for presence of coherence */
    1513     9920166 :                 if ( hMeta->directional_meta[dir].spread_coherence[sf][band] >= MASA_COHERENCE_THRESHOLD )
    1514             :                 {
    1515      785180 :                     cohPresent = TRUE;
    1516             :                 }
    1517     9920166 :                 band++;
    1518             :             }
    1519     1060198 :             sf++;
    1520             :         }
    1521      901558 :         dir++;
    1522             :     }
    1523             : 
    1524             :     /* Check surround coherence separately if we do not have already knowledge of coherence */
    1525      885461 :     if ( cohPresent == FALSE )
    1526             :     {
    1527      100281 :         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      885461 :     *joinedSubframes = sfDiffer == TRUE ? FALSE : TRUE;
    1532      885461 :     *coherencePresent = cohPresent;
    1533             : 
    1534      885461 :     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      885461 : 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      885461 :     hMeta = &( hMasa->masaMetadata );
    1550      885461 :     numDirs = hMasa->config.numberOfDirections;
    1551             : 
    1552     4427305 :     for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1553             :     {
    1554    88546100 :         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    85004256 :             hMeta->common_meta.remainder_to_total_ratio[sf][band] = 0.0f;
    1559             : 
    1560    85004256 :             ratioSum = 0;
    1561   202425984 :             for ( dir = 0; dir < numDirs; dir++ )
    1562             :             {
    1563   117421728 :                 ratioSum += hMeta->directional_meta[dir].energy_ratio[sf][band];
    1564             :             }
    1565    85004256 :             ratioSum += hMeta->common_meta.diffuse_to_total_ratio[sf][band];
    1566             : 
    1567    85004256 :             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    85004256 :             else if ( ratioSum != 1.0f )
    1576             :             {
    1577     6809685 :                 for ( dir = 0; dir < numDirs; dir++ )
    1578             :                 {
    1579     4010718 :                     hMeta->directional_meta[dir].energy_ratio[sf][band] /= ratioSum;
    1580             :                 }
    1581     2798967 :                 hMeta->common_meta.diffuse_to_total_ratio[sf][band] /= ratioSum;
    1582             :             }
    1583             :         }
    1584             :     }
    1585             : 
    1586      885461 :     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      330389 : 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      330389 :     numCodingBands = hMasa->config.numCodingBands;
    1609      330389 :     computeCoherence = hMasa->config.useCoherence && hMasa->config.coherencePresent;
    1610             : 
    1611             :     /* Set default values */
    1612      330389 :     selectedBand = 0;
    1613      330389 :     mergeOverFreqBands = 0;
    1614             : 
    1615             :     /* Get energy for the input data in 4-subframe, 5-band format */
    1616      330389 :     totalEnergySum = 0.0f;
    1617      330389 :     if ( ivas_format == MASA_FORMAT || ivas_format == MASA_ISM_FORMAT ) /* Energy data is in 4-subframe, 24-band format */
    1618             :     {
    1619     1219555 :         for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1620             :         {
    1621             :             int16_t brange[2];
    1622             :             float eneSum;
    1623             :             int16_t m;
    1624             : 
    1625     5853864 :             for ( band = 0; band < numCodingBands; band++ )
    1626             :             {
    1627     4878220 :                 brange[0] = hMasa->data.band_mapping[band];
    1628     4878220 :                 brange[1] = hMasa->data.band_mapping[band + 1];
    1629             : 
    1630     4878220 :                 eneSum = 0.0f;
    1631    28053268 :                 for ( m = brange[0]; m < brange[1]; m++ )
    1632             :                 {
    1633    23175048 :                     eneSum += hMasa->data.energy[sf][m];
    1634             :                 }
    1635     4878220 :                 energy[sf][band] = eneSum;
    1636     4878220 :                 totalEnergySum += eneSum;
    1637             :             }
    1638             :         }
    1639             :     }
    1640             :     else /* Energy data is already in 4-subframe, 5-band format */
    1641             :     {
    1642      432390 :         for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1643             :         {
    1644     2075472 :             for ( band = 0; band < numCodingBands; band++ )
    1645             :             {
    1646     1729560 :                 energy[sf][band] = hMasa->data.energy[sf][band];
    1647     1729560 :                 totalEnergySum += energy[sf][band];
    1648             :             }
    1649             :         }
    1650             :     }
    1651             : 
    1652             :     /* Determine onsets */
    1653      330389 :     hMasa->data.onset_detector_1 = hMasa->data.onset_detector_1 * LOWBITRATE_ONSET_ALPHA;
    1654      330389 :     hMasa->data.onset_detector_1 = max( hMasa->data.onset_detector_1, totalEnergySum );
    1655             : 
    1656      330389 :     hMasa->data.onset_detector_2 = LOWBITRATE_ONSET_BETA * hMasa->data.onset_detector_2 + ( 1.0f - LOWBITRATE_ONSET_BETA ) * hMasa->data.onset_detector_1;
    1657      330389 :     hMasa->data.onset_detector_2 = LOWBITRATE_ONSET_GAIN * min( hMasa->data.onset_detector_1, hMasa->data.onset_detector_2 );
    1658             : 
    1659      330389 :     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      330389 :     if ( onset_filter < 0.99f )
    1663             :     {
    1664             :         /* Determine one frequency band to use to represent all frequency bands */
    1665      299325 :         for ( band = numCodingBands - 1; band >= 0; band-- )
    1666             :         {
    1667             :             float threshold;
    1668             :             float bandRatio;
    1669             : 
    1670      294214 :             threshold = totalEnergySum / ( MAX_PARAM_SPATIAL_SUBFRAMES * LOWBITRATE_NUM_BANDS ) * 0.5f; /* Average energy multiplied with energy ratio of 0.5f */
    1671      294214 :             bandRatio = hqmetadata->q_direction[0].band_data[band].energy_ratio[0];
    1672             : 
    1673      294214 :             bandEnergy = 0.0f;
    1674     1471070 :             for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1675             :             {
    1676     1176856 :                 bandEnergy += energy[sf][band];
    1677             :             }
    1678             : 
    1679      294214 :             if ( bandEnergy / MAX_PARAM_SPATIAL_SUBFRAMES * bandRatio > threshold )
    1680             :             {
    1681       69687 :                 selectedBand = band;
    1682       69687 :                 break;
    1683             :             }
    1684             :         }
    1685             : 
    1686             :         /* Determine if to merge over frequency instead of time */
    1687       74798 :         meanRatio = 0.0f;
    1688      373990 :         for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1689             :         {
    1690     1795152 :             for ( band = 0; band < numCodingBands; band++ )
    1691             :             {
    1692     1495960 :                 meanRatio += hqmetadata->q_direction[0].band_data[band].energy_ratio[sf] * energy[sf][band];
    1693             :             }
    1694             :         }
    1695       74798 :         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       74798 :         if ( hqmetadata->q_direction[0].band_data[selectedBand].energy_ratio[0] > meanRatio )
    1700             :         {
    1701       50688 :             mergeOverFreqBands = 1;
    1702             :         }
    1703             :         else
    1704             :         {
    1705       24110 :             mergeOverFreqBands = 0;
    1706             :         }
    1707             :     }
    1708             :     else
    1709             :     {
    1710      255591 :         mergeOverFreqBands = 0;
    1711             :     }
    1712             : 
    1713             :     /* Merge values over subframes or frequency bands, depending on which one is less important */
    1714      330389 :     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     1678206 :         for ( band = 0; band < numCodingBands; band++ )
    1723             :         {
    1724     1398505 :             xSum = 0.0f;
    1725     1398505 :             ySum = 0.0f;
    1726     1398505 :             zSum = 0.0f;
    1727     1398505 :             bandSumEnergy = 0.0f;
    1728             : 
    1729     6992525 :             for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1730             :             {
    1731     5594020 :                 aziRad = hqmetadata->q_direction[0].band_data[band].azimuth[sf] / 180.0f * EVS_PI;
    1732     5594020 :                 eleRad = hqmetadata->q_direction[0].band_data[band].elevation[sf] / 180.0f * EVS_PI;
    1733     5594020 :                 veclen = hqmetadata->q_direction[0].band_data[band].energy_ratio[sf] * energy[sf][band];
    1734             : 
    1735     5594020 :                 x = cosf( aziRad ) * cosf( eleRad ) * veclen;
    1736     5594020 :                 y = sinf( aziRad ) * cosf( eleRad ) * veclen;
    1737     5594020 :                 z = sinf( eleRad ) * veclen;
    1738             : 
    1739     5594020 :                 xSum += x;
    1740     5594020 :                 ySum += y;
    1741     5594020 :                 zSum += z;
    1742             : 
    1743     5594020 :                 bandSumEnergy += energy[sf][band];
    1744             :             }
    1745             : 
    1746     1398505 :             aziRad = atan2f( ySum, xSum );
    1747     1398505 :             eleRad = atan2f( zSum, sqrtf( xSum * xSum + ySum * ySum ) );
    1748             : 
    1749     1398505 :             hqmetadata->q_direction[0].band_data[band].azimuth[0] = aziRad / EVS_PI * 180.0f;
    1750     1398505 :             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     1398505 :             if ( computeCoherence && hqmetadata->q_direction[0].coherence_band_data != NULL )
    1755             :             {
    1756             :                 float spreadCoh;
    1757      276615 :                 float spreadCohSum = 0.0f;
    1758     1383075 :                 for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1759             :                 {
    1760     1106460 :                     spreadCoh = (float) hqmetadata->q_direction[0].coherence_band_data[band].spread_coherence[sf] / 255.0f;
    1761     1106460 :                     spreadCohSum += spreadCoh * energy[sf][band];
    1762             :                 }
    1763      276615 :                 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     1106460 :                 for ( sf = 1; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1767             :                 {
    1768      829845 :                     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      279701 :         hqmetadata->q_direction->cfg.nblocks = 1;
    1776      279701 :         hMasa->config.joinedSubframes = 1;
    1777             :     }
    1778             :     else /* Merge values over frequency bands */
    1779             :     {
    1780             :         /* Use the selected frequency band to represent all data */
    1781      253440 :         for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1782             :         {
    1783      202752 :             hqmetadata->q_direction[0].band_data[0].azimuth[sf] = hqmetadata->q_direction[0].band_data[selectedBand].azimuth[sf];
    1784      202752 :             hqmetadata->q_direction[0].band_data[0].elevation[sf] = hqmetadata->q_direction[0].band_data[selectedBand].elevation[sf];
    1785      202752 :             hqmetadata->q_direction[0].band_data[0].energy_ratio[sf] = hqmetadata->q_direction[0].band_data[selectedBand].energy_ratio[sf];
    1786      202752 :             if ( hqmetadata->q_direction[0].coherence_band_data != NULL )
    1787             :             {
    1788       63440 :                 hqmetadata->q_direction[0].coherence_band_data[0].spread_coherence[sf] = hqmetadata->q_direction[0].coherence_band_data[selectedBand].spread_coherence[sf];
    1789             :             }
    1790      202752 :             if ( hqmetadata->surcoh_band_data != NULL )
    1791             :             {
    1792       63440 :                 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      253440 :         for ( band = 1; band < numCodingBands; band++ )
    1798             :         {
    1799      202752 :             if ( hqmetadata->q_direction[0].coherence_band_data != NULL )
    1800             :             {
    1801      317200 :                 for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1802             :                 {
    1803      253760 :                     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      202752 :             if ( hqmetadata->q_direction[0].coherence_band_data != NULL )
    1807             :             {
    1808      317200 :                 for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1809             :                 {
    1810      253760 :                     hqmetadata->surcoh_band_data[band].surround_coherence[sf] = hqmetadata->surcoh_band_data[0].surround_coherence[sf];
    1811             :                 }
    1812             :             }
    1813             :         }
    1814             : 
    1815       50688 :         hqmetadata->q_direction[0].cfg.nbands = 1;
    1816             :     }
    1817             : 
    1818      330389 :     return;
    1819             : }
    1820             : 
    1821             : 
    1822      183140 : 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      183140 :     VQLevels = 0;
    1841      183140 :     lfeAdaptiveVQBits = 0;
    1842             : 
    1843             :     /* Determine maximum amount of LFE energy in any subframe */
    1844      183140 :     maxLFESubFrameEner = 0.0f;
    1845      915700 :     for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ )
    1846             :     {
    1847      732560 :         if ( hMasa->data.lfeToTotalEnergyRatio[i] > maxLFESubFrameEner )
    1848             :         {
    1849      386979 :             maxLFESubFrameEner = hMasa->data.lfeToTotalEnergyRatio[i];
    1850             :         }
    1851             :     }
    1852             : 
    1853             :     /* Set default values for the indices */
    1854      732560 :     for ( i = 0; i < 3; i++ )
    1855             :     {
    1856      549420 :         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      183140 :     if ( maxLFESubFrameEner > 0.005f )
    1862             :     {
    1863             :         /* Convert energy to log2 domain, and clamp it to reasonable values */
    1864      162084 :         log2LFEaverage = 0.0f;
    1865      810420 :         for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ )
    1866             :         {
    1867      648336 :             log2LFEratio[i] = log2f( max( 0.001f, hMasa->data.lfeToTotalEnergyRatio[i] ) );
    1868      648336 :             if ( log2LFEratio[i] > 1.0f ) /* Corresponds to linear value 2.0f */
    1869             :             {
    1870           0 :                 log2LFEratio[i] = 1.0f;
    1871             :             }
    1872      648336 :             else if ( log2LFEratio[i] < -9.0f )
    1873             :             {
    1874       24607 :                 log2LFEratio[i] = -9.0f;
    1875             :             }
    1876      648336 :             log2LFEaverage += 0.25f * log2LFEratio[i];
    1877             :         }
    1878             : 
    1879      162084 :         if ( ivas_total_brate == IVAS_13k2 )
    1880             :         {
    1881             :             /* Calculate adaptive 1-bit LFE quantizer index */
    1882       12741 :             linearLFEaverage = exp2f( log2LFEaverage ); /* Convert back to linear domain */
    1883       12741 :             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        4898 :                 lfeToTotalEnergyRatioIndices[0] = 1;
    1886        4898 :                 if ( hMasa->data.prevq_lfeIndex == 1 )
    1887             :                 {
    1888        2088 :                     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        2810 :                     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        7843 :                 hMasa->data.prevq_lfeToTotalEnergyRatio = MCMASA_LFE_ALPHA * hMasa->data.prevq_lfeToTotalEnergyRatio; /* exponential decay */
    1898             :             }
    1899             : 
    1900       12741 :             if ( hMasa->data.prevq_lfeToTotalEnergyRatio > 1.0f )
    1901             :             {
    1902           4 :                 hMasa->data.prevq_lfeToTotalEnergyRatio = 1.0f;
    1903             :             }
    1904       12741 :             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      149343 :             lfeToTotalEnergyRatioIndices[0] = 1;
    1910      149343 :             lfeToTotalEnergyRatioIndices[1] = usquant( log2LFEaverage, &xq, MCMASA_LFE_QLOW, MCMASA_LFE_DELTA, 8 );
    1911             : 
    1912      149343 :             if ( ivas_total_brate >= IVAS_24k4 ) /* Vector quantization is applied if bitrate >= 24.4 kbps */
    1913             :             {
    1914             :                 /* Remove scalar value from the vector*/
    1915      723935 :                 for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ )
    1916             :                 {
    1917      579148 :                     log2LFEratio[i] -= xq;
    1918             :                 }
    1919             : 
    1920             :                 /* Vector quantize residual with energy adaptive bit allocation */
    1921      144787 :                 switch ( lfeToTotalEnergyRatioIndices[1] )
    1922             :                 {
    1923       30508 :                     case 0:
    1924             :                     case 1:
    1925       30508 :                         VQLevels = 0;
    1926       30508 :                         lfeAdaptiveVQBits = 0;
    1927       30508 :                         break;
    1928       15210 :                     case 2:
    1929       15210 :                         VQLevels = 2;
    1930       15210 :                         lfeAdaptiveVQBits = 1;
    1931       15210 :                         break;
    1932       18989 :                     case 3:
    1933       18989 :                         VQLevels = 4;
    1934       18989 :                         lfeAdaptiveVQBits = 2;
    1935       18989 :                         break;
    1936       22265 :                     case 4:
    1937       22265 :                         VQLevels = 8;
    1938       22265 :                         lfeAdaptiveVQBits = 3;
    1939       22265 :                         break;
    1940       57815 :                     default:
    1941       57815 :                         VQLevels = 16;
    1942       57815 :                         lfeAdaptiveVQBits = 4;
    1943             :                 }
    1944             : 
    1945      144787 :                 if ( VQLevels > 0 )
    1946             :                 {
    1947      114279 :                     lfeToTotalEnergyRatioIndices[2] = vquant( log2LFEratio, 0, xqv, McMASA_LFEGain_vectors, 4, VQLevels );
    1948             :                 }
    1949             :             }
    1950             :         }
    1951             :     }
    1952             : 
    1953             :     /* Write first LFE bit */
    1954      183140 :     lfeBitsWritten = 0;
    1955      183140 :     push_next_indice( hMetaData, lfeToTotalEnergyRatioIndices[0], 1 );
    1956      183140 :     lfeBitsWritten += 1;
    1957             : 
    1958      183140 :     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      149343 :         push_next_indice( hMetaData, lfeToTotalEnergyRatioIndices[1], 3 );
    1962      149343 :         lfeBitsWritten += 3;
    1963             : 
    1964             :         /*  If bitrate >= 24.4kbit/s, use adaptive 1 + (3.. 7) bit quantizer */
    1965      149343 :         if ( ivas_total_brate >= IVAS_24k4 )
    1966             :         {
    1967             :             /* Vector quantize residual with energy adaptive bit allocation */
    1968      144787 :             if ( lfeAdaptiveVQBits > 0 )
    1969             :             {
    1970      114279 :                 push_next_indice( hMetaData, lfeToTotalEnergyRatioIndices[2], lfeAdaptiveVQBits );
    1971      114279 :                 lfeBitsWritten += lfeAdaptiveVQBits;
    1972             :             }
    1973             :         }
    1974             :     }
    1975             : 
    1976      183140 :     return lfeBitsWritten;
    1977             : }
    1978             : 
    1979             : 
    1980             : /*-------------------------------------------------------------------*
    1981             :  * ivas_masa_enc_reconfigure()
    1982             :  *
    1983             :  * Reconfigure IVAS MASA encoder
    1984             :  *-------------------------------------------------------------------*/
    1985             : 
    1986      594911 : 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      594911 :     ivas_total_brate = st_ivas->hEncoderConfig->ivas_total_brate;
    1996             : 
    1997      594911 :     ism_total_brate = 0;
    1998      594911 :     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      594911 :     if ( ivas_total_brate != st_ivas->hEncoderConfig->last_ivas_total_brate )
    2007             :     {
    2008       18291 :         for ( sce_id = 0; sce_id < st_ivas->nSCE; sce_id++ )
    2009             :         {
    2010        5587 :             copy_encoder_config( st_ivas, st_ivas->hSCE[sce_id]->hCoreCoder[0], 0 );
    2011        5587 :             st_ivas->hSCE[sce_id]->element_brate = ivas_total_brate / st_ivas->nchan_transport;
    2012        5587 :             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       19821 :         for ( cpe_id = 0; cpe_id < st_ivas->nCPE; cpe_id++ )
    2016             :         {
    2017        7117 :             st_ivas->hCPE[cpe_id]->element_brate = ( ivas_total_brate / st_ivas->nchan_transport ) * CPE_CHANNELS;
    2018             : 
    2019             :             /* prepare bitstream buffers */
    2020       21351 :             for ( n = 0; n < CPE_CHANNELS; n++ )
    2021             :             {
    2022       14234 :                 copy_encoder_config( st_ivas, st_ivas->hCPE[cpe_id]->hCoreCoder[n], 0 );
    2023       14234 :                 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        7117 :             if ( ivas_total_brate - ism_total_brate < MIN_BRATE_MDCT_STEREO )
    2027             :             {
    2028        2117 :                 st_ivas->hCPE[cpe_id]->element_mode = IVAS_CPE_DFT;
    2029             :             }
    2030             :             else
    2031             :             {
    2032        5000 :                 st_ivas->hCPE[cpe_id]->element_mode = IVAS_CPE_MDCT;
    2033             :             }
    2034             :         }
    2035             : 
    2036       12704 :         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      594911 :     return;
    2040             : }
    2041             : 
    2042             : 
    2043             : /*-------------------------------------------------------------------*
    2044             :  * average_masa_metadata()
    2045             :  *
    2046             :  * Average MASA metadata frame subframe contents: applies aggregation over time
    2047             :  *-------------------------------------------------------------------*/
    2048             : 
    2049      109833 : 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      109833 :     numDirections = hMeta->descriptive_meta.numberOfDirections + 1;
    2061             : 
    2062             :     /* azi/ele/nrg into vectors for each sub-frame and band */
    2063      256292 :     for ( i = 0; i < numDirections; i++ )
    2064             :     {
    2065     3661475 :         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     3515016 :             x_sum = 0.0f;
    2070     3515016 :             y_sum = 0.0f;
    2071     3515016 :             z_sum = 0.0f;
    2072     3515016 :             energy_sum = 0.0f;
    2073     3515016 :             spread_coh_sum = 0.0f;
    2074     3515016 :             surr_coh_sum = 0.0f;
    2075    17575080 :             for ( j = 0; j < MAX_PARAM_SPATIAL_SUBFRAMES; j++ )
    2076             :             {
    2077    14060064 :                 azi_rad = hMeta->directional_meta[i].azimuth[j][k] / 180.0f * EVS_PI;
    2078    14060064 :                 ele_rad = hMeta->directional_meta[i].elevation[j][k] / 180.0f * EVS_PI;
    2079    14060064 :                 vec_len = hMeta->directional_meta[i].energy_ratio[j][k] * energy[j][k];
    2080             : 
    2081             :                 /* energy-weighted sum over subframes */
    2082    14060064 :                 x_sum += cosf( azi_rad ) * cosf( ele_rad ) * vec_len;
    2083    14060064 :                 y_sum += sinf( azi_rad ) * cosf( ele_rad ) * vec_len;
    2084    14060064 :                 z_sum += sinf( ele_rad ) * vec_len;
    2085             : 
    2086    14060064 :                 energy_sum += energy[j][k];
    2087             : 
    2088    14060064 :                 spread_coh_sum += hMeta->directional_meta[i].spread_coherence[j][k] * energy[j][k];
    2089    14060064 :                 if ( i == 0 )
    2090             :                 {
    2091             :                     /* this is in common metadata and not in each direction */
    2092    10543968 :                     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     3515016 :             j = 0;
    2098     3515016 :             hMeta->directional_meta[i].azimuth[j][k] = atan2f( y_sum, x_sum ) / EVS_PI * 180.0f;
    2099     3515016 :             hMeta->directional_meta[i].elevation[j][k] = atan2f( z_sum, sqrtf( x_sum * x_sum + y_sum * y_sum ) ) / EVS_PI * 180.0f;
    2100     3515016 :             if ( useSphGrid == TRUE )
    2101             :             {
    2102      142656 :                 hMeta->directional_meta[i].spherical_index[j][k] = index_theta_phi_16( &( hMeta->directional_meta[i].elevation[j][k] ),
    2103      142656 :                                                                                        &( hMeta->directional_meta[i].azimuth[j][k] ), Sph_Grid16 );
    2104             :             }
    2105     3515016 :             vec_len = sqrtf( x_sum * x_sum + y_sum * y_sum + z_sum * z_sum );
    2106     3515016 :             hMeta->directional_meta[i].energy_ratio[j][k] = vec_len / ( energy_sum + EPSILON );
    2107             : 
    2108     3515016 :             hMeta->directional_meta[i].spread_coherence[j][k] = spread_coh_sum / ( energy_sum + EPSILON );
    2109     3515016 :             if ( i == 0 )
    2110             :             {
    2111     2635992 :                 hMeta->common_meta.surround_coherence[j][k] = surr_coh_sum / ( energy_sum + EPSILON );
    2112             :             }
    2113             : 
    2114             :             /* copy the same value to all subframes */
    2115    14060064 :             for ( j = 1; j < MAX_PARAM_SPATIAL_SUBFRAMES; j++ )
    2116             :             {
    2117    10545048 :                 hMeta->directional_meta[i].azimuth[j][k] = hMeta->directional_meta[i].azimuth[0][k];
    2118    10545048 :                 hMeta->directional_meta[i].elevation[j][k] = hMeta->directional_meta[i].elevation[0][k];
    2119    10545048 :                 hMeta->directional_meta[i].energy_ratio[j][k] = hMeta->directional_meta[i].energy_ratio[0][k];
    2120    10545048 :                 hMeta->directional_meta[i].spread_coherence[j][k] = hMeta->directional_meta[i].spread_coherence[0][k];
    2121    10545048 :                 if ( i == 0 )
    2122             :                 {
    2123     7907976 :                     hMeta->common_meta.surround_coherence[j][k] = hMeta->common_meta.surround_coherence[0][k];
    2124             :                 }
    2125             :             }
    2126             :         }
    2127             :     }
    2128             : 
    2129     2745825 :     for ( k = 0; k < MASA_FREQUENCY_BANDS; k++ )
    2130             :     {
    2131    13179960 :         for ( j = 0; j < MAX_PARAM_SPATIAL_SUBFRAMES; j++ )
    2132             :         {
    2133    10543968 :             if ( numDirections == 2 )
    2134             :             {
    2135     3516096 :                 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     7027872 :                 hMeta->common_meta.diffuse_to_total_ratio[j][k] = max( 0.0f, 1.0f - hMeta->directional_meta[0].energy_ratio[j][k] );
    2140             :             }
    2141    10543968 :             hMeta->common_meta.remainder_to_total_ratio[j][k] = 0.0f;
    2142             :         }
    2143             :     }
    2144             : 
    2145      109833 :     return;
    2146             : }
    2147             : 
    2148             : 
    2149             : /*-------------------------------------------------------------------*
    2150             :  * copy_masa_metadata_subframe()
    2151             :  *
    2152             :  * Copy MASA metadata frame subframe contents
    2153             :  *-------------------------------------------------------------------*/
    2154             : 
    2155     3541844 : 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    10625532 :     for ( dir = 0; dir < MASA_MAXIMUM_DIRECTIONS; dir++ )
    2167             :     {
    2168   177092200 :         for ( band = 0; band < MASA_FREQUENCY_BANDS; band++ )
    2169             :         {
    2170   170008512 :             hMetaTo->directional_meta[dir].spherical_index[sfTo][band] = hMetaFrom->directional_meta[dir].spherical_index[sfFrom][band];
    2171             :         }
    2172     7083688 :         mvr2r( hMetaFrom->directional_meta[dir].azimuth[sfFrom], hMetaTo->directional_meta[dir].azimuth[sfTo], MASA_FREQUENCY_BANDS );
    2173     7083688 :         mvr2r( hMetaFrom->directional_meta[dir].elevation[sfFrom], hMetaTo->directional_meta[dir].elevation[sfTo], MASA_FREQUENCY_BANDS );
    2174     7083688 :         mvr2r( hMetaFrom->directional_meta[dir].energy_ratio[sfFrom], hMetaTo->directional_meta[dir].energy_ratio[sfTo], MASA_FREQUENCY_BANDS );
    2175     7083688 :         mvr2r( hMetaFrom->directional_meta[dir].spread_coherence[sfFrom], hMetaTo->directional_meta[dir].spread_coherence[sfTo], MASA_FREQUENCY_BANDS );
    2176             :     }
    2177             : 
    2178             :     /* common metadata */
    2179     3541844 :     mvr2r( hMetaFrom->common_meta.diffuse_to_total_ratio[sfFrom], hMetaTo->common_meta.diffuse_to_total_ratio[sfTo], MASA_FREQUENCY_BANDS );
    2180     3541844 :     mvr2r( hMetaFrom->common_meta.surround_coherence[sfFrom], hMetaTo->common_meta.surround_coherence[sfTo], MASA_FREQUENCY_BANDS );
    2181     3541844 :     mvr2r( hMetaFrom->common_meta.remainder_to_total_ratio[sfFrom], hMetaTo->common_meta.remainder_to_total_ratio[sfTo], MASA_FREQUENCY_BANDS );
    2182             : 
    2183     3541844 :     return;
    2184             : }
    2185             : 
    2186             : 
    2187             : /*-------------------------------------------------------------------*
    2188             :  * copy_masa_metadata()
    2189             :  *
    2190             :  * Copy MASA metada frame contents
    2191             :  *-------------------------------------------------------------------*/
    2192             : 
    2193      885461 : 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     7969149 :     for ( byte_idx = 0; byte_idx < 8; byte_idx++ )
    2202             :     {
    2203     7083688 :         hMetaTo->descriptive_meta.formatDescriptor[byte_idx] = hMetaFrom->descriptive_meta.formatDescriptor[byte_idx];
    2204             :     }
    2205             : 
    2206      885461 :     hMetaTo->descriptive_meta.numberOfDirections = hMetaFrom->descriptive_meta.numberOfDirections;
    2207      885461 :     hMetaTo->descriptive_meta.numberOfChannels = hMetaFrom->descriptive_meta.numberOfChannels;
    2208      885461 :     hMetaTo->descriptive_meta.sourceFormat = hMetaFrom->descriptive_meta.sourceFormat;
    2209      885461 :     hMetaTo->descriptive_meta.transportDefinition = hMetaFrom->descriptive_meta.transportDefinition;
    2210      885461 :     hMetaTo->descriptive_meta.channelAngle = hMetaFrom->descriptive_meta.channelAngle;
    2211      885461 :     hMetaTo->descriptive_meta.channelDistance = hMetaFrom->descriptive_meta.channelDistance;
    2212      885461 :     hMetaTo->descriptive_meta.channelLayout = hMetaFrom->descriptive_meta.channelLayout;
    2213             : 
    2214             :     /* directional and common metadata */
    2215     4427305 :     for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    2216             :     {
    2217     3541844 :         copy_masa_metadata_subframe( hMetaFrom, sf, hMetaTo, sf );
    2218             :     }
    2219             : 
    2220      885461 :     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     5022323 : 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     5022323 :     num_dir = frame1->descriptive_meta.numberOfDirections;
    2244     5022323 :     dir = 0;
    2245     5022323 :     band_idx = 0;
    2246     5022323 :     sf_differ = FALSE;
    2247             : 
    2248     5022323 :     if ( num_dir != frame2->descriptive_meta.numberOfDirections )
    2249             :     {
    2250       42358 :         sf_differ = TRUE;
    2251             :     }
    2252             :     else
    2253             :     {
    2254             :         /* check per-direction metadata */
    2255     4979965 :         dir = 0;
    2256     4979965 :         band_idx = 0;
    2257             : 
    2258    11033236 :         while ( ( sf_differ == FALSE ) && ( dir <= num_dir ) )
    2259             :         {
    2260     6053271 :             band_idx = 0;
    2261    92285416 :             while ( ( sf_differ == FALSE ) && ( band_idx < MASA_FREQUENCY_BANDS ) )
    2262             :             {
    2263             :                 float azi_dif;
    2264    88758993 :                 azi_dif = fabsf( frame1->directional_meta[dir].azimuth[sf1_idx][band_idx] - frame2->directional_meta[dir].azimuth[sf2_idx][band_idx] );
    2265    88758993 :                 azi_dif = azi_dif > 180.0f ? 360.0f - azi_dif : azi_dif;
    2266             : 
    2267    88758993 :                 if ( azi_dif > MASA_ANGLE_TOLERANCE )
    2268             :                 {
    2269     2354199 :                     sf_differ = TRUE;
    2270     2354199 :                     break;
    2271             :                 }
    2272             : 
    2273    86404794 :                 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       93884 :                     sf_differ = TRUE;
    2276       93884 :                     break;
    2277             :                 }
    2278             : 
    2279    86310910 :                 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       53626 :                     sf_differ = TRUE;
    2282       53626 :                     break;
    2283             :                 }
    2284             : 
    2285    86257284 :                 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       25139 :                     sf_differ = TRUE;
    2288       25139 :                     break;
    2289             :                 }
    2290             : 
    2291    86232145 :                 band_idx++;
    2292             :             }
    2293     6053271 :             dir++;
    2294             :         }
    2295             : 
    2296             :         /* check the common metadata */
    2297     4979965 :         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     5022323 :     if ( sf_differ )
    2310             :     {
    2311     2569206 :         return FALSE;
    2312             :     }
    2313             :     else
    2314             :     {
    2315     2453117 :         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      885461 : 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      885461 :     current_meta = &( hMasa->masaMetadata );  /* metadata from current frame */
    2340      885461 :     sync_state = &( hMasa->data.sync_state ); /* synchronization structure */
    2341      885461 :     previous_meta = &( sync_state->previous_metadata );
    2342             : 
    2343             :     /* check current frame, how many are similar from the start and from the end */
    2344      885461 :     n_sim_start = 1;
    2345     1804335 :     for ( sf_idx = n_sim_start; sf_idx < MAX_PARAM_SPATIAL_SUBFRAMES; sf_idx++ )
    2346             :     {
    2347     1580851 :         if ( are_masa_subframes_similar( current_meta, 0, current_meta, sf_idx ) == TRUE )
    2348             :         {
    2349      918874 :             n_sim_start = sf_idx + 1;
    2350             :         }
    2351             :         else
    2352             :         {
    2353      661977 :             break;
    2354             :         }
    2355             :     }
    2356             : 
    2357             :     /* number of similar sub-frames starting from the end of the frame */
    2358      885461 :     if ( n_sim_start == MAX_PARAM_SPATIAL_SUBFRAMES ) /* shortcut */
    2359             :     {
    2360      223484 :         n_sim_stop = n_sim_start;
    2361             :     }
    2362             :     else
    2363             :     {
    2364      661977 :         n_sim_stop = 1;
    2365      923678 :         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      905489 :             if ( are_masa_subframes_similar( current_meta, MAX_PARAM_SPATIAL_SUBFRAMES - 1, current_meta, MAX_PARAM_SPATIAL_SUBFRAMES - sf_idx ) == TRUE )
    2369             :             {
    2370      261701 :                 n_sim_stop = sf_idx;
    2371             :             }
    2372             :             else
    2373             :             {
    2374      643788 :                 break;
    2375             :             }
    2376             :         }
    2377             :     }
    2378             : 
    2379      885461 :     frame_mode = MASA_FRAME_4SF; /* default mode: 4sf */
    2380      885461 :     if ( sync_state->prev_offset > MAX_PARAM_SPATIAL_SUBFRAMES - 2 )
    2381             :     {
    2382             :         /* earlier offset was large => reset the offset */
    2383       26445 :         found_offset = 0;
    2384             :     }
    2385             :     else
    2386             :     {
    2387             :         /* keep previous offset unless something else is found. alternatively, we could reset always */
    2388      859016 :         found_offset = sync_state->prev_offset;
    2389             :     }
    2390             : 
    2391      885461 :     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      223484 :         frame_mode = MASA_FRAME_1SF;
    2395      223484 :         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       60082 :             if ( sync_state->prev_sim_stop < 3 )
    2399             :             {
    2400             :                 /* can nicely align the framing with the earlier data and a small offset */
    2401        4653 :                 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       55429 :                 found_offset = sync_state->prev_offset;
    2407             :             }
    2408             :         }
    2409             :         else
    2410             :         {
    2411             :             /* earlier window was different => reset the offset */
    2412      163402 :             found_offset = 0;
    2413             :         }
    2414             :     }
    2415      661977 :     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       18189 :         frame_mode = MASA_FRAME_1SF;
    2420       18189 :         found_offset = 3;
    2421             :     }
    2422      643788 :     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      123886 :         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       62912 :             frame_mode = MASA_FRAME_1SF;
    2429             : 
    2430       62912 :             if ( sync_state->prev_offset == 0 )
    2431             :             {
    2432        4593 :                 found_offset = min( 2, sync_state->prev_sim_stop );
    2433             :             }
    2434             :             else
    2435             :             {
    2436       58319 :                 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      885461 :     copy_masa_metadata( current_meta, previous_meta );
    2444             : 
    2445      885461 :     sync_state->prev_sim_stop = n_sim_stop;
    2446      885461 :     sync_state->prev_offset = found_offset;
    2447      885461 :     sync_state->frame_mode = frame_mode;
    2448             : 
    2449      885461 :     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      885461 : 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      885461 :     hAlignState = &( hMasa->data.dir_align_state );
    2469      885461 :     hMeta = &( hMasa->masaMetadata );
    2470             : 
    2471      885461 :     n_dirs = hMeta->descriptive_meta.numberOfDirections + 1; /* 1-based */
    2472    22136525 :     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    21251064 :         prev_ele_dir1_sin = sinf( hAlignState->previous_ele_dir1[band] );
    2482    21251064 :         prev_ele_dir2_sin = sinf( hAlignState->previous_ele_dir2[band] );
    2483             : 
    2484    21251064 :         prev_ele_dir1_cos = cosf( hAlignState->previous_ele_dir1[band] );
    2485    21251064 :         prev_ele_dir2_cos = cosf( hAlignState->previous_ele_dir2[band] );
    2486             : 
    2487   106255320 :         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    85004256 :             azi_rad1 = hMeta->directional_meta[0].azimuth[sf][band] * PI_OVER_180;
    2495    85004256 :             ele_rad1 = hMeta->directional_meta[0].elevation[sf][band] * PI_OVER_180;
    2496             : 
    2497    85004256 :             if ( n_dirs > 1 )
    2498             :             {
    2499    32917056 :                 azi_rad2 = hMeta->directional_meta[1].azimuth[sf][band] * PI_OVER_180;
    2500    32917056 :                 ele_rad2 = hMeta->directional_meta[1].elevation[sf][band] * PI_OVER_180;
    2501             : 
    2502             :                 /* quick checks to detect constant data and earlier flip */
    2503    32917056 :                 if ( fabsf( azi_rad1 - hAlignState->previous_azi_dir1[band] ) < EPSILON &&
    2504     8541627 :                      fabsf( azi_rad2 - hAlignState->previous_azi_dir2[band] ) < EPSILON &&
    2505     8520533 :                      fabsf( ele_rad1 - hAlignState->previous_ele_dir1[band] ) < EPSILON &&
    2506     8519273 :                      fabsf( ele_rad2 - hAlignState->previous_ele_dir2[band] ) < EPSILON )
    2507             :                 {
    2508     8519273 :                     diff_swap = 1.0f;
    2509     8519273 :                     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     8519273 :                     sin_ele1 = prev_ele_dir1_sin;
    2512     8519273 :                     sin_ele2 = prev_ele_dir2_sin;
    2513     8519273 :                     cos_ele1 = prev_ele_dir1_cos;
    2514     8519273 :                     cos_ele2 = prev_ele_dir2_cos;
    2515             :                 }
    2516    24397783 :                 else if ( fabsf( azi_rad1 - hAlignState->previous_azi_dir2[band] ) < EPSILON &&
    2517     7542204 :                           fabsf( azi_rad2 - hAlignState->previous_azi_dir1[band] ) < EPSILON &&
    2518     7525498 :                           fabsf( ele_rad1 - hAlignState->previous_ele_dir2[band] ) < EPSILON &&
    2519     7525330 :                           fabsf( ele_rad2 - hAlignState->previous_ele_dir1[band] ) < EPSILON )
    2520             :                 {
    2521     7525330 :                     diff_swap = 0.0f;
    2522     7525330 :                     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     7525330 :                     sin_ele1 = prev_ele_dir2_sin;
    2525     7525330 :                     sin_ele2 = prev_ele_dir1_sin;
    2526     7525330 :                     cos_ele1 = prev_ele_dir2_cos;
    2527     7525330 :                     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    16872453 :                     sin_ele1 = sinf( ele_rad1 );
    2534    16872453 :                     sin_ele2 = sinf( ele_rad2 );
    2535             : 
    2536    16872453 :                     cos_ele1 = cosf( ele_rad1 );
    2537    16872453 :                     cos_ele2 = cosf( ele_rad2 );
    2538             : 
    2539    16872453 :                     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    16872453 :                                    acosf( cos_ele2 * prev_ele_dir2_cos * cosf( azi_rad2 - hAlignState->previous_azi_dir2[band] ) + sin_ele2 * prev_ele_dir2_sin );
    2541             : 
    2542    16872453 :                     diff_swap = acosf( cos_ele1 * prev_ele_dir2_cos * cosf( azi_rad1 - hAlignState->previous_azi_dir2[band] ) + sin_ele1 * prev_ele_dir2_sin ) +
    2543    16872453 :                                 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    52087200 :                 sin_ele1 = sinf( ele_rad1 );
    2550    52087200 :                 cos_ele1 = cosf( ele_rad1 );
    2551             : 
    2552    52087200 :                 azi_rad2 = 0.0f;
    2553    52087200 :                 ele_rad2 = 0.0f;
    2554             : 
    2555    52087200 :                 sin_ele2 = 0.0f; /* sin(0) */
    2556    52087200 :                 cos_ele2 = 1.0f; /* cos(0) */
    2557             : 
    2558    52087200 :                 diff_swap = 1.0f;
    2559    52087200 :                 diff_no_swap = 0.0f;
    2560             :             }
    2561             : 
    2562    85004256 :             if ( n_dirs > 1 && diff_no_swap > diff_swap )
    2563    14786234 :             {
    2564             :                 /* swap the metadata of the two directions in this TF-tile */
    2565             :                 float tmp_val;
    2566             :                 uint16_t tmp_int_val;
    2567    14786234 :                 tmp_val = hMeta->directional_meta[0].azimuth[sf][band];
    2568    14786234 :                 hMeta->directional_meta[0].azimuth[sf][band] = hMeta->directional_meta[1].azimuth[sf][band];
    2569    14786234 :                 hMeta->directional_meta[1].azimuth[sf][band] = tmp_val;
    2570             : 
    2571    14786234 :                 tmp_val = hMeta->directional_meta[0].elevation[sf][band];
    2572    14786234 :                 hMeta->directional_meta[0].elevation[sf][band] = hMeta->directional_meta[1].elevation[sf][band];
    2573    14786234 :                 hMeta->directional_meta[1].elevation[sf][band] = tmp_val;
    2574    14786234 :                 tmp_int_val = hMeta->directional_meta[0].spherical_index[sf][band];
    2575    14786234 :                 hMeta->directional_meta[0].spherical_index[sf][band] = hMeta->directional_meta[1].spherical_index[sf][band];
    2576    14786234 :                 hMeta->directional_meta[1].spherical_index[sf][band] = tmp_int_val;
    2577    14786234 :                 tmp_val = hMeta->directional_meta[0].energy_ratio[sf][band];
    2578    14786234 :                 hMeta->directional_meta[0].energy_ratio[sf][band] = hMeta->directional_meta[1].energy_ratio[sf][band];
    2579    14786234 :                 hMeta->directional_meta[1].energy_ratio[sf][band] = tmp_val;
    2580             : 
    2581    14786234 :                 tmp_val = hMeta->directional_meta[0].spread_coherence[sf][band];
    2582    14786234 :                 hMeta->directional_meta[0].spread_coherence[sf][band] = hMeta->directional_meta[1].spread_coherence[sf][band];
    2583    14786234 :                 hMeta->directional_meta[1].spread_coherence[sf][band] = tmp_val;
    2584             : 
    2585    14786234 :                 hAlignState->previous_azi_dir1[band] = azi_rad2;
    2586    14786234 :                 hAlignState->previous_ele_dir1[band] = ele_rad2;
    2587             : 
    2588    14786234 :                 hAlignState->previous_azi_dir2[band] = azi_rad1;
    2589    14786234 :                 hAlignState->previous_ele_dir2[band] = ele_rad1;
    2590             : 
    2591    14786234 :                 prev_ele_dir1_cos = cos_ele2;
    2592    14786234 :                 prev_ele_dir1_sin = sin_ele2;
    2593             : 
    2594    14786234 :                 prev_ele_dir2_cos = cos_ele1;
    2595    14786234 :                 prev_ele_dir2_sin = sin_ele1;
    2596             :             }
    2597             :             else
    2598             :             {
    2599    70218022 :                 hAlignState->previous_azi_dir1[band] = azi_rad1;
    2600    70218022 :                 hAlignState->previous_ele_dir1[band] = ele_rad1;
    2601             : 
    2602    70218022 :                 hAlignState->previous_azi_dir2[band] = azi_rad2;
    2603    70218022 :                 hAlignState->previous_ele_dir2[band] = ele_rad2;
    2604             : 
    2605    70218022 :                 prev_ele_dir1_cos = cos_ele1;
    2606    70218022 :                 prev_ele_dir1_sin = sin_ele1;
    2607             : 
    2608    70218022 :                 prev_ele_dir2_cos = cos_ele2;
    2609    70218022 :                 prev_ele_dir2_sin = sin_ele2;
    2610             :             }
    2611             :         } /* sf */
    2612             :     }     /* band */
    2613             : 
    2614      885461 :     return;
    2615             : }
    2616             : 
    2617             : 
    2618             : /*-------------------------------------------------------------------*
    2619             :  * ivas_merge_masa_metadata()
    2620             :  *
    2621             :  *
    2622             :  *-------------------------------------------------------------------*/
    2623             : 
    2624      127126 : 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      127126 :     OMASA_ENCODER_ENERGY_HANDLE hOmasaEnergy = hMasa->data.hOmasaData->hOmasaEnergy;
    2640             : 
    2641      127126 :     numCodingBands = hMasa->config.numCodingBands;
    2642      127126 :     numDirections = hMasa->config.numberOfDirections;
    2643      127126 :     numSf = hMasa->config.joinedSubframes == TRUE ? 1 : MAX_PARAM_SPATIAL_SUBFRAMES;
    2644      127126 :     hMeta = &( hMasa->masaMetadata );
    2645             : 
    2646      635630 :     for ( sf = 0; sf < numSf; sf++ )
    2647             :     {
    2648    12555800 :         for ( band = 0; band < numCodingBands; band++ )
    2649             :         {
    2650             :             int16_t merge_dest;
    2651             :             float dir_sum;
    2652             :             uint8_t band_n_dirs;
    2653    12047296 :             if ( numDirections == 1 || ( numDirections == 2 && hMasa->data.twoDirBands[band] == 0 ) )
    2654             :             {
    2655    12047296 :                 band_n_dirs = 1;
    2656             :             }
    2657             :             else
    2658             :             {
    2659           0 :                 band_n_dirs = 2;
    2660             :             }
    2661             : 
    2662             :             /* Compute energies */
    2663    12047296 :             eneBand = hMasa->data.energy[sf][band];
    2664    12047296 :             energyMerged[sf][band] = eneBand + hOmasaEnergy->energy_ism[sf][band];
    2665             : 
    2666             :             /* Compute weights */
    2667    12047296 :             energyTimesRatioMASA[0] = eneBand * hMeta->directional_meta[0].energy_ratio[sf][band];
    2668    12047296 :             if ( band_n_dirs == 2 )
    2669             :             {
    2670           0 :                 energyTimesRatioMASA[1] = eneBand * hMeta->directional_meta[1].energy_ratio[sf][band];
    2671             :             }
    2672             :             else
    2673             :             {
    2674    12047296 :                 energyTimesRatioMASA[1] = 0.0f;
    2675             :             }
    2676             : 
    2677             :             /* target is original MASA diffuseness */
    2678    12047296 :             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    12047296 :             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    12047296 :             merge_dest = -1;
    2685    12047296 :             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     5817578 :                 merge_dest = 0;
    2690             :             }
    2691     6229718 :             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    12047296 :             if ( merge_dest >= 0 ) /* replace one MASA with ISM */
    2698             :             {
    2699     5817578 :                 hMeta->directional_meta[merge_dest].azimuth[sf][band] = hOMasaMeta->directional_meta[0].azimuth[sf][band];
    2700     5817578 :                 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     5817578 :                 dir_sum = 1.0f - total_diff_nrg / ( EPSILON + eneBand + hOmasaEnergy->energy_ism[sf][band] );                                        /* new dir ratio */
    2704     5817578 :                 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     5817578 :                 hMeta->common_meta.diffuse_to_total_ratio[sf][band] = 1.0f - hMeta->directional_meta[merge_dest].energy_ratio[sf][band];
    2706             : 
    2707     5817578 :                 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     5817578 :                 direct_quota = 1.0f - hMeta->common_meta.diffuse_to_total_ratio[sf][band];
    2716     5817578 :                 if ( band_n_dirs == 1 )
    2717             :                 {
    2718     5817578 :                     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      635630 :     for ( sf = 0; sf < numSf; sf++ )
    2732             :     {
    2733    12555800 :         for ( band = 0; band < numCodingBands; band++ )
    2734             :         {
    2735    12047296 :             hMasa->data.energy[sf][band] = energyMerged[sf][band];
    2736             :         }
    2737             :     }
    2738             : 
    2739      127126 :     return;
    2740             : }
    2741             : 
    2742             : 
    2743      936845 : 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      936845 :     max_sum_idx = ( 1 << PARAM_ISM_POW_RATIO_NBITS ) - 1;
    2757             : 
    2758      936845 :     if ( idx_sep_object > -1 )
    2759             :     {
    2760      936845 :         if ( ratio_ism[idx_sep_object] < 1.0f / (float) ( max_sum_idx ) )
    2761             :         {
    2762             :             /* take it out from quantize function  */
    2763      587713 :             mvr2r( ratio_ism, ratio_ism_loc, idx_sep_object );
    2764      587713 :             mvr2r( &ratio_ism[idx_sep_object + 1], &ratio_ism_loc[idx_sep_object], nchan_ism - idx_sep_object - 1 );
    2765      587713 :             no_ism_loc = nchan_ism - 1;
    2766             :         }
    2767             :         else
    2768             :         {
    2769      349132 :             no_ism_loc = nchan_ism;
    2770      349132 :             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      936845 :     if ( nchan_ism > 1 )
    2780             :     {
    2781      936845 :         if ( masa_to_total_energy_ratio >= MASA2TOTAL_THR )
    2782             :         {
    2783      417228 :             distribute_evenly_ism( idx, max_sum_idx, nchan_ism );
    2784             :         }
    2785             :         else
    2786             :         {
    2787      519617 :             if ( no_ism_loc > 1 )
    2788             :             {
    2789             : 
    2790      504228 :                 dist = 0.0f;
    2791      504228 :                 div = 1.0f / (float) ( max_sum_idx );
    2792             : 
    2793      504228 :                 part_idx_sum = 0;
    2794             : 
    2795     1872972 :                 for ( i = 0; i < no_ism_loc; i++ )
    2796             :                 {
    2797     1368744 :                     idx[i] = (int16_t) ( ( ratio_ism_loc[i] ) * ( max_sum_idx ) );
    2798     1368744 :                     part_idx_sum += idx[i];
    2799             : 
    2800     1368744 :                     tmp = ( ratio_ism_loc[i] - ( idx[i] * div ) );
    2801     1368744 :                     dist += ( tmp * tmp );
    2802             :                 }
    2803             : 
    2804      504228 :                 best_dist = dist;
    2805      504228 :                 best_i2 = -1;
    2806      777105 :                 while ( part_idx_sum < max_sum_idx )
    2807             :                 {
    2808      272877 :                     best_i = -1;
    2809             :                     /* check which index to increase by 1 for a possible improvement */
    2810             : 
    2811     1041552 :                     for ( i = 0; i < no_ism_loc; i++ )
    2812             :                     {
    2813      768675 :                         idx[i]++;
    2814      768675 :                         dist2 = 0.0f;
    2815             : 
    2816     3012894 :                         for ( j = 0; j < no_ism_loc; j++ )
    2817             :                         {
    2818     2244219 :                             tmp = ( ratio_ism_loc[i] - ( idx[i] * div ) );
    2819     2244219 :                             dist2 += ( tmp * tmp );
    2820             :                         }
    2821             : 
    2822      768675 :                         if ( dist2 < best_dist )
    2823             :                         {
    2824      232378 :                             best_i2 = best_i;
    2825      232378 :                             best_i = i;
    2826      232378 :                             best_dist = dist2;
    2827             :                         }
    2828      768675 :                         idx[i]--;
    2829             :                     }
    2830      272877 :                     if ( best_i > -1 )
    2831             :                     {
    2832      225770 :                         idx[best_i]++;
    2833      225770 :                         part_idx_sum++;
    2834             :                     }
    2835             :                     else
    2836             :                     {
    2837       47107 :                         if ( best_i2 > -1 )
    2838             :                         {
    2839        5639 :                             idx[best_i2]++;
    2840        5639 :                             part_idx_sum++;
    2841             :                         }
    2842             :                         else
    2843             :                         {
    2844       41468 :                             idx[no_ism_loc - 1] += max_sum_idx - part_idx_sum;
    2845       41468 :                             part_idx_sum = max_sum_idx;
    2846             :                         }
    2847             :                     }
    2848             :                 }
    2849      504228 :                 assert( sum_s( idx, no_ism_loc ) == max_sum_idx );
    2850             :             }
    2851             :             else
    2852             :             {
    2853       15389 :                 idx[0] = max_sum_idx;
    2854             :             }
    2855             : 
    2856      519617 :             if ( no_ism_loc < nchan_ism )
    2857             :             {
    2858             :                 /*  insert back the ratio of the separated object  */
    2859     1044082 :                 for ( i = nchan_ism - 1; i > idx_sep_object; i-- )
    2860             :                 {
    2861      580865 :                     idx[i] = idx[i - 1];
    2862             :                 }
    2863      463217 :                 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      936845 :     return;
    2873             : }
    2874             : 
    2875             : 
    2876       71593 : 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       71593 :     if ( nchan_ism == 2 )
    2885             :     {
    2886        5577 :         index = ratio_ism_idx[0];
    2887             :     }
    2888             :     else
    2889             :     {
    2890       66016 :         x = ratio_ism_idx[nchan_ism - 2];
    2891       66016 :         base = 10;
    2892      177811 :         for ( i = nchan_ism - 3; i >= 0; i-- )
    2893             :         {
    2894      111795 :             x += ratio_ism_idx[i] * base;
    2895      111795 :             base *= 10;
    2896             :         }
    2897             : 
    2898       66016 :         index = 0;
    2899       66016 :         i = 0;
    2900     5616232 :         while ( i <= x )
    2901             :         {
    2902     5550216 :             if ( valid_ratio_index( i, 7, nchan_ism - 1 ) )
    2903             :             {
    2904     1692308 :                 index++;
    2905             :             }
    2906     5550216 :             i++;
    2907             :         }
    2908       66016 :         index--;
    2909             :     }
    2910             : 
    2911       71593 :     return index;
    2912             : }
    2913             : 
    2914             : 
    2915     1194260 : 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     3736289 :     for ( i = 0; i < len; i++ )
    2922             :     {
    2923     2542029 :         if ( diff_idx[i] <= 0 )
    2924             :         {
    2925     2347698 :             idx[i] = -2 * diff_idx[i];
    2926             :         }
    2927             :         else
    2928             :         {
    2929      194331 :             idx[i] = 2 * diff_idx[i] - 1;
    2930             :         }
    2931             :     }
    2932             : 
    2933     1194260 :     return;
    2934             : }
    2935             : 
    2936             : 
    2937      447718 : 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      447718 :     transform_difference_index( diff_idx, idx, len );
    2949             : 
    2950             :     /* GR encoding */
    2951     1413846 :     for ( i = 0; i < len; i++ )
    2952             :     {
    2953      966128 :         ivas_qmetadata_encode_extended_gr( hMetaData, idx[i], 100, GR_order );
    2954             :     }
    2955             : 
    2956      447718 :     return;
    2957             : }
    2958             : 
    2959             : 
    2960       63612 : 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       63612 :     b_signif = 0;
    2975      249367 :     while ( ( b_signif < numCodingBands ) && ( masa_to_total_energy_ratio[b_signif] >= MASA2TOTAL_THR ) )
    2976             :     {
    2977      185755 :         b_signif++;
    2978             :     }
    2979             : 
    2980       63612 :     nbits0 = 0;
    2981             : 
    2982       63612 :     if ( b_signif < numCodingBands )
    2983             :     {
    2984       38817 :         nbits0 = bits_index;
    2985       38817 :         mvs2s( ratio_ism_idx[b_signif], ratio_ism_idx_ref, nchan_ism );
    2986             : 
    2987      283627 :         for ( b = b_signif + 1; b < numCodingBands; b++ )
    2988             :         {
    2989      244810 :             if ( masa_to_total_energy_ratio[b] < MASA2TOTAL_THR )
    2990             :             {
    2991      214408 :                 v_sub_s( ratio_ism_idx[b], ratio_ism_idx_ref, diff_idx, nchan_ism );
    2992      214408 :                 mvs2s( ratio_ism_idx[b], ratio_ism_idx_ref, nchan_ism );
    2993             : 
    2994             :                 /* transform difference index into positive */
    2995      214408 :                 transform_difference_index( diff_idx, diff_idx, nchan_ism - 1 );
    2996             : 
    2997             :                 /* GR encoding */
    2998      749219 :                 for ( i = 0; i < nchan_ism - 1; i++ )
    2999             :                 {
    3000      534811 :                     nbits0 += ivas_qmetadata_encode_extended_gr_length( diff_idx[i], 100, 0 );
    3001             :                 }
    3002             :             }
    3003             :         }
    3004             :     }
    3005       63612 :     *p_b_signif = b_signif;
    3006             : 
    3007       63612 :     return nbits0;
    3008             : }
    3009             : 
    3010             : 
    3011       31109 : 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       31109 :     push_next_indice( hMetaData, 0, 1 );
    3026             : 
    3027       31109 :     if ( b_signif < numCodingBands )
    3028             :     {
    3029       31109 :         index = index_slice_enum( ratio_ism_idx[b_signif], nchan_ism );
    3030       31109 :         push_next_indice( hMetaData, index, bits_index );
    3031             : 
    3032       31109 :         mvs2s( ratio_ism_idx[b_signif], ratio_ism_idx_ref, nchan_ism );
    3033             : 
    3034      238320 :         for ( b = b_signif + 1; b < numCodingBands; b++ )
    3035             :         {
    3036      207211 :             if ( masa_to_total_energy_ratio[b] < MASA2TOTAL_THR )
    3037             :             {
    3038      181632 :                 v_sub_s( ratio_ism_idx[b], ratio_ism_idx_ref, diff_idx, nchan_ism );
    3039      181632 :                 mvs2s( ratio_ism_idx[b], ratio_ism_idx_ref, nchan_ism );
    3040             : 
    3041             :                 /* transform difference index into positive */
    3042      181632 :                 transform_index_and_GR_encode( diff_idx, nchan_ism - 1, 0, hMetaData );
    3043             :             }
    3044             :         }
    3045             :     }
    3046             : 
    3047       31109 :     return;
    3048             : }
    3049             : 
    3050             : 
    3051        7708 : 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       55098 :     for ( b = 0; b < numCodingBands; b++ )
    3063             :     {
    3064       47390 :         if ( masa_to_total_energy_ratio[b] < MASA2TOTAL_THR )
    3065             :         {
    3066       40484 :             index = index_slice_enum( ratio_ism_idx[b], nchan_ism );
    3067       40484 :             push_next_indice( hMetaData, index, bits_index );
    3068             :         }
    3069             :     }
    3070             : 
    3071        7708 :     return;
    3072             : }
    3073             : 
    3074             : 
    3075      533733 : 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     1746342 :     for ( i = idx_sep_obj; i < nchan_ism - 1; i++ )
    3084             :     {
    3085     1212609 :         diff_idx[i] = diff_idx[i + 1];
    3086             :     }
    3087             : 
    3088      533733 :     return;
    3089             : }
    3090             : 
    3091             : 
    3092      532134 : 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      532134 :     nbits0 = 0;
    3106      532134 :     nbits1 = 0;
    3107             : 
    3108             :     /* take difference with respect to previous subframe */
    3109      532134 :     v_sub_s( ratio_ism_idx, ratio_ism_idx_ref, diff_idx, nchan_ism );
    3110             : 
    3111      532134 :     if ( shift_one )
    3112             :     {
    3113      355822 :         remove_sep_obj( diff_idx, nchan_ism, idx_sep_obj );
    3114             :     }
    3115             : 
    3116             :     /* transform difference index into positive */
    3117      532134 :     transform_difference_index( diff_idx, diff_idx, nchan_ism - 1 - shift_one );
    3118             : 
    3119             :     /* GR encoding */
    3120     1573224 :     for ( i = 0; i < nchan_ism - 1 - shift_one; i++ )
    3121             :     {
    3122     1041090 :         nbits0 += ivas_qmetadata_encode_extended_gr_length( diff_idx[i], 100, 0 );
    3123     1041090 :         nbits1 += ivas_qmetadata_encode_extended_gr_length( diff_idx[i], 100, 1 );
    3124             :     }
    3125             : 
    3126      532134 :     *p_nbits0 = nbits0;
    3127      532134 :     *p_nbits1 = nbits1;
    3128             : 
    3129      532134 :     return;
    3130             : }
    3131             : 
    3132             : 
    3133      157947 : 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      157947 :     idx_sep_obj_local = idx_separated_obj;
    3157      157947 :     if ( idx_separated_obj > -1 )
    3158             :     {
    3159      157947 :         if ( idx_separated_obj == nchan_ism - 1 )
    3160             :         {
    3161       63919 :             idx_sep_obj_local = 0;
    3162             :         }
    3163             :     }
    3164      157947 :     nbits = 0;
    3165      157947 :     nbits0 = 0;
    3166      157947 :     nbits1 = 0;
    3167             : 
    3168             : #ifdef DEBUGGING
    3169             :     bits_pos0 = hMetaData->nb_bits_tot;
    3170             : #endif
    3171      157947 :     differential_subframe = 1; /* the differences are taken with respect to previous subframe */
    3172             : 
    3173             :     /* first subframe */
    3174      157947 :     bits_index = 0;
    3175      157947 :     if ( sf == 0 )
    3176             :     {
    3177       63612 :         bits_index = bits_index_ism_ratio( nchan_ism );
    3178             : 
    3179       63612 :         nbits = 0;
    3180      532994 :         for ( b = 0; b < numCodingBands; b++ )
    3181             :         {
    3182      469382 :             if ( masa_to_total_energy_ratio[b] < MASA2TOTAL_THR )
    3183             :             {
    3184      253225 :                 nbits += bits_index;
    3185             :             }
    3186             :         }
    3187             : 
    3188       63612 :         nbits0 = try_differential( numCodingBands, masa_to_total_energy_ratio, ratio_ism_idx, nchan_ism, bits_index, &b_signif );
    3189             : 
    3190       63612 :         if ( nbits <= nbits0 && nbits > 0 )
    3191             :         {
    3192             :             /* independent encoding */
    3193        7708 :             push_next_indice( hMetaData, 1, 1 );
    3194        7708 :             independent_coding_ratio_ism_idx( ratio_ism_idx, masa_to_total_energy_ratio, nchan_ism, numCodingBands, bits_index, hMetaData );
    3195        7708 :             nbits = nbits + 1;
    3196             :         }
    3197             :         else
    3198             :         {
    3199       55904 :             if ( nbits > 0 )
    3200             :             {
    3201       31109 :                 differential_coding_first_subframe( hMetaData, masa_to_total_energy_ratio, b_signif, ratio_ism_idx, nchan_ism, numCodingBands, bits_index );
    3202       31109 :                 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       94335 :         if ( shift_one == 1 && nchan_ism == 2 )
    3214             :         {
    3215         309 :             nbits = 0;
    3216             :         }
    3217             :         else
    3218             :         {
    3219       94026 :             nbits0 = 0;
    3220       94026 :             nbits1 = 0;
    3221             : 
    3222      561180 :             for ( b = 0; b < numCodingBands; b++ )
    3223             :             {
    3224      467154 :                 if ( masa_to_total_energy_ratio[b] < MASA2TOTAL_THR )
    3225             :                 {
    3226      266086 :                     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      266086 :                     nbits0 += nbits00;
    3228      266086 :                     nbits1 += nbits11;
    3229             :                 }
    3230             :             }
    3231       94026 :             if ( nbits0 < nbits1 )
    3232             :             {
    3233       52360 :                 GR_order = 0;
    3234       52360 :                 nbits = nbits0;
    3235             :             }
    3236             :             else
    3237             :             {
    3238       41666 :                 GR_order = 1;
    3239       41666 :                 nbits = nbits1;
    3240             :             }
    3241             : 
    3242       94026 :             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       93282 :                 nbits0 = 0;
    3247       93282 :                 nbits1 = 0;
    3248       93282 :                 b_signif = 0;
    3249      268257 :                 while ( ( b_signif < numCodingBands ) && ( masa_to_total_energy_ratio[b_signif] >= MASA2TOTAL_THR ) )
    3250             :                 {
    3251      174975 :                     b_signif++;
    3252             :                 }
    3253             : 
    3254       93282 :                 if ( b_signif < numCodingBands )
    3255             :                 {
    3256       60480 :                     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       60480 :                     mvs2s( ratio_ism_idx[b_signif], ratio_ism_idx_ref, nchan_ism );
    3259             : 
    3260      291435 :                     for ( b = b_signif + 1; b < numCodingBands; b++ )
    3261             :                     {
    3262      230955 :                         if ( masa_to_total_energy_ratio[b] < MASA2TOTAL_THR )
    3263             :                         {
    3264      205568 :                             estimate_bits_subband_ism_ratio( ratio_ism_idx[b], ratio_ism_idx_ref, nchan_ism, shift_one, idx_sep_obj_local, &nbits00, &nbits11 );
    3265      205568 :                             nbits0 += nbits00;
    3266      205568 :                             nbits1 += nbits11;
    3267      205568 :                             mvs2s( ratio_ism_idx[b], ratio_ism_idx_ref, nchan_ism );
    3268             :                         }
    3269             :                     }
    3270             : 
    3271       60480 :                     if ( nbits0 < nbits1 )
    3272             :                     {
    3273       42728 :                         GR_order_sb = 0;
    3274             :                     }
    3275             :                     else
    3276             :                     {
    3277       17752 :                         GR_order_sb = 1;
    3278       17752 :                         nbits0 = nbits1;
    3279             :                     }
    3280             : 
    3281       60480 :                     if ( nbits0 < nbits )
    3282             :                     {
    3283        7226 :                         differential_subframe = 0;
    3284        7226 :                         nbits = nbits0;
    3285        7226 :                         GR_order = GR_order_sb;
    3286             :                     }
    3287             : 
    3288       60480 :                     if ( nbits > 0 )
    3289             :                     {
    3290             :                         /* write prediction type */
    3291       60480 :                         push_next_indice( hMetaData, differential_subframe, 1 );
    3292             :                         /* write GR order */
    3293       60480 :                         push_next_indice( hMetaData, GR_order, 1 );
    3294       60480 :                         nbits++; /* for the prediction type */
    3295       60480 :                         nbits++; /* for GR_order */
    3296             : 
    3297             :                         /* write data */
    3298       60480 :                         if ( differential_subframe )
    3299             :                         {
    3300      319524 :                             for ( b = 0; b < numCodingBands; b++ )
    3301             :                             {
    3302      266270 :                                 if ( masa_to_total_energy_ratio[b] < MASA2TOTAL_THR )
    3303             :                                 {
    3304             :                                     /* take difference with respect to previous subframe */
    3305      236362 :                                     v_sub_s( ratio_ism_idx[b], ratio_ism_idx_prev_sf[b], diff_idx, nchan_ism );
    3306             : 
    3307      236362 :                                     if ( shift_one )
    3308             :                                     {
    3309      170520 :                                         remove_sep_obj( diff_idx, nchan_ism, idx_sep_obj_local );
    3310             :                                     }
    3311             : 
    3312      236362 :                                     transform_index_and_GR_encode( diff_idx, nchan_ism - 1 - shift_one, GR_order, hMetaData );
    3313             :                                 }
    3314             :                             }
    3315             :                         }
    3316             :                         else
    3317             :                         {
    3318        7226 :                             v_sub_s( ratio_ism_idx[b_signif], ratio_ism_idx_prev_sf[b_signif], diff_idx, nchan_ism );
    3319             : 
    3320        7226 :                             if ( shift_one )
    3321             :                             {
    3322        1549 :                                 remove_sep_obj( diff_idx, nchan_ism, idx_sep_obj_local );
    3323             :                             }
    3324             : 
    3325        7226 :                             transform_index_and_GR_encode( diff_idx, nchan_ism - 1 - shift_one, GR_order, hMetaData );
    3326             : 
    3327        7226 :                             mvs2s( ratio_ism_idx[b_signif], ratio_ism_idx_ref, nchan_ism - shift_one );
    3328             : 
    3329       35329 :                             for ( b = b_signif + 1; b < numCodingBands; b++ )
    3330             :                             {
    3331             :                                 /* take difference with respect to previous subband */
    3332       28103 :                                 if ( masa_to_total_energy_ratio[b] < MASA2TOTAL_THR )
    3333             :                                 {
    3334       22460 :                                     v_sub_s( ratio_ism_idx[b], ratio_ism_idx_ref, diff_idx, nchan_ism );
    3335             : 
    3336       22460 :                                     if ( shift_one )
    3337             :                                     {
    3338        5842 :                                         remove_sep_obj( diff_idx, nchan_ism, idx_sep_obj_local );
    3339             :                                     }
    3340             : 
    3341       22460 :                                     transform_index_and_GR_encode( diff_idx, nchan_ism - 1 - shift_one, GR_order, hMetaData );
    3342             : 
    3343       22460 :                                     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         744 :                 if ( nbits > 0 )
    3356             :                 {
    3357             :                     /* write GR order */
    3358          38 :                     push_next_indice( hMetaData, GR_order, 1 );
    3359          38 :                     nbits++; /* for GR_order */
    3360             :                     /* write data */
    3361             :                     /* only one subband */
    3362          38 :                     if ( masa_to_total_energy_ratio[0] < MASA2TOTAL_THR )
    3363             :                     {
    3364             :                         /* take difference with respect to previous subframe */
    3365          38 :                         v_sub_s( ratio_ism_idx[0], ratio_ism_idx_prev_sf[0], diff_idx, nchan_ism );
    3366             : 
    3367          38 :                         if ( shift_one )
    3368             :                         {
    3369           0 :                             remove_sep_obj( diff_idx, nchan_ism, idx_sep_obj_local );
    3370             :                         }
    3371             : 
    3372          38 :                         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      157947 :     return nbits;
    3384             : }
    3385             : 
    3386             : 
    3387       63612 : 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       63612 :     OMASA_ENCODER_DATA_HANDLE hOmasaData = hMasa->data.hOmasaData;
    3418       63612 :     OMASA_ENCODER_ENERGY_HANDLE hOmasaEnergy = hOmasaData->hOmasaEnergy;
    3419             :     int16_t nbands_work;
    3420             : 
    3421             :     /* use the values from hQMetaData */
    3422       63612 :     numCodingBands = (uint8_t) hQMetaData->q_direction->cfg.nbands;
    3423       63612 :     numSf = (int8_t) hQMetaData->q_direction->cfg.nblocks;
    3424       63612 :     nbands_work = min( numCodingBands, omasa_nbands );
    3425       63612 :     if ( numCodingBands == 1 )
    3426             :     {
    3427        1755 :         for ( sf = 0; sf < numSf; sf++ )
    3428             :         {
    3429        1404 :             if ( sum_f( hOmasaEnergy->energy_ism[sf], omasa_nbands ) == 0.0f )
    3430             :             {
    3431         784 :                 hOmasaData->masa_to_total_energy_ratio[sf][0] = 1.0f;
    3432             :             }
    3433             :             else
    3434             :             {
    3435         620 :                 brange[0] = hMasa->data.band_mapping[0];
    3436         620 :                 brange[1] = hMasa->data.band_mapping[omasa_nbands];
    3437         620 :                 eneBand = 0.0f;
    3438       15320 :                 for ( bin = brange[0]; bin < brange[1]; bin++ )
    3439             :                 {
    3440       14700 :                     eneBand += hMasa->data.energy[sf][bin];
    3441             :                 }
    3442             : 
    3443         620 :                 energy_ism = 0.0f;
    3444        1860 :                 for ( obj = 0; obj < nchan_ism; obj++ )
    3445             :                 {
    3446        1240 :                     energy_ism_ind[obj] = 0.0f;
    3447             :                 }
    3448             : 
    3449        3720 :                 for ( band = 0; band < omasa_nbands; band++ )
    3450             :                 {
    3451        3100 :                     energy_ism += hOmasaEnergy->energy_ism[sf][band];
    3452        9300 :                     for ( obj = 0; obj < nchan_ism; obj++ )
    3453             :                     {
    3454        6200 :                         energy_ism_ind[obj] += hOmasaEnergy->energy_ism[sf][band] * hOmasaEnergy->energy_ratio_ism[sf][band][obj];
    3455             :                     }
    3456             :                 }
    3457             : 
    3458        1860 :                 for ( obj = 0; obj < nchan_ism; obj++ )
    3459             :                 {
    3460        1240 :                     hOmasaEnergy->energy_ratio_ism[sf][0][obj] = energy_ism_ind[obj] / energy_ism;
    3461             :                 }
    3462         620 :                 hOmasaData->masa_to_total_energy_ratio[sf][0] = eneBand / ( eneBand + energy_ism + EPSILON );
    3463             :             }
    3464             :         }
    3465             :     }
    3466       63261 :     else if ( numSf == 1 )
    3467             :     {
    3468      345728 :         for ( band = 0; band < nbands_work; band++ )
    3469             :         {
    3470      313561 :             energy_ism = 0.0f; /* ISM energy for current subband */
    3471     1352511 :             for ( obj = 0; obj < nchan_ism; obj++ )
    3472             :             {
    3473     1038950 :                 energy_ism_ind[obj] = 0.0f;
    3474             :             }
    3475      715367 :             for ( sf = 0; sf < omasa_nblocks; sf++ )
    3476             :             {
    3477      401806 :                 energy_ism += hOmasaEnergy->energy_ism[sf][band];
    3478     1617246 :                 for ( obj = 0; obj < nchan_ism; obj++ )
    3479             :                 {
    3480     1215440 :                     energy_ism_ind[obj] += hOmasaEnergy->energy_ism[sf][band] * hOmasaEnergy->energy_ratio_ism[sf][band][obj];
    3481             :                 }
    3482             :             }
    3483             : 
    3484      313561 :             if ( energy_ism == 0.0f )
    3485             :             {
    3486       99919 :                 hOmasaData->masa_to_total_energy_ratio[0][band] = 1.0f;
    3487             :             }
    3488             :             else
    3489             :             {
    3490      940290 :                 for ( obj = 0; obj < nchan_ism; obj++ )
    3491             :                 {
    3492      726648 :                     hOmasaEnergy->energy_ratio_ism[0][band][obj] = energy_ism_ind[obj] / energy_ism;
    3493             :                 }
    3494      213642 :                 brange[0] = hMasa->data.band_mapping[band];
    3495      213642 :                 brange[1] = hMasa->data.band_mapping[band + 1];
    3496             : 
    3497      213642 :                 eneBand = 0.0f;
    3498      472779 :                 for ( sf = 0; sf < omasa_nblocks; sf++ )
    3499             :                 {
    3500      969696 :                     for ( bin = brange[0]; bin < brange[1]; bin++ )
    3501             :                     {
    3502      710559 :                         eneBand += hMasa->data.energy[sf][bin];
    3503             :                     }
    3504             :                 }
    3505      213642 :                 hOmasaData->masa_to_total_energy_ratio[0][band] = eneBand / ( eneBand + energy_ism + EPSILON );
    3506             :             }
    3507             :         }
    3508       32167 :         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      155470 :         for ( sf = 0; sf < numSf; sf++ )
    3521             :         {
    3522      746256 :             for ( band = 0; band < nbands_work; band++ )
    3523             :             {
    3524      621880 :                 if ( hOmasaEnergy->energy_ism[sf][band] == 0.0f )
    3525             :                 {
    3526      180035 :                     hOmasaData->masa_to_total_energy_ratio[sf][band] = 1.0f;
    3527             :                 }
    3528             :                 else
    3529             :                 {
    3530      441845 :                     brange[0] = hMasa->data.band_mapping[band];
    3531      441845 :                     brange[1] = hMasa->data.band_mapping[band + 1];
    3532             : 
    3533      441845 :                     eneBand = 0.0f;
    3534     2531769 :                     for ( bin = brange[0]; bin < brange[1]; bin++ )
    3535             :                     {
    3536     2089924 :                         eneBand += hMasa->data.energy[sf][bin];
    3537             :                     }
    3538      441845 :                     hOmasaData->masa_to_total_energy_ratio[sf][band] = eneBand / ( eneBand + hOmasaEnergy->energy_ism[sf][band] + EPSILON );
    3539             :                 }
    3540             :             }
    3541      124376 :             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       63612 :     ivas_omasa_encode_masa_to_total( hOmasaData->masa_to_total_energy_ratio, hMetaData, low_bitrate_mode, numCodingBands, numSf );
    3553             : 
    3554             :     /* quantize ism_ratios */
    3555       63612 :     if ( nchan_ism > 1 )
    3556             :     {
    3557       63612 :         inv_step = ( ( 1 << PARAM_ISM_POW_RATIO_NBITS ) - 1 );
    3558       63612 :         step = 1.0f / inv_step;
    3559             : 
    3560       63612 :         rotate = 0;
    3561       63612 :         n_ism_tmp = 0;
    3562             : 
    3563      221559 :         for ( sf = 0; sf < numSf; sf++ )
    3564             :         {
    3565     1094792 :             for ( band = 0; band < numCodingBands; band++ )
    3566             :             {
    3567     4204103 :                 for ( obj = 0; obj < nchan_ism; obj++ )
    3568             :                 {
    3569     3267258 :                     assert( ( hOmasaEnergy->energy_ratio_ism[sf][band][obj] >= 0 ) && ( hOmasaEnergy->energy_ratio_ism[sf][band][obj] <= 1 ) );
    3570     3267258 :                     ratio_ism[band][obj] = hOmasaEnergy->energy_ratio_ism[sf][band][obj];
    3571             :                 }
    3572             : 
    3573             :                 /* Quantize ISM ratios */
    3574      936845 :                 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      936845 :                 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         789 :                     i = 0;
    3578        5909 :                     while ( ratio_ism_idx[band][idx_separated_object] > 0 )
    3579             :                     {
    3580        5120 :                         if ( i != idx_separated_object )
    3581             :                         {
    3582        3449 :                             ratio_ism_idx[band][i]++;
    3583        3449 :                             ratio_ism_idx[band][idx_separated_object]--;
    3584             :                         }
    3585        5120 :                         i++;
    3586        5120 :                         if ( i == nchan_ism )
    3587             :                         {
    3588        1155 :                             i = 0;
    3589             :                         }
    3590             :                     }
    3591             :                 }
    3592             : 
    3593             :                 /* reconstructed values */
    3594      936845 :                 reconstruct_ism_ratios( ratio_ism_idx[band], nchan_ism, step, hOmasaEnergy->q_energy_ratio_ism[sf][band] );
    3595             :             }
    3596             : 
    3597      157947 :             if ( ( nchan_ism > 2 ) && ( idx_separated_object == nchan_ism - 1 ) )
    3598             :             {
    3599             :                 /* rotate components */
    3600       58431 :                 rotate = 1;
    3601      413019 :                 for ( band = 0; band < numCodingBands; band++ )
    3602             :                 {
    3603      354588 :                     if ( hOmasaData->masa_to_total_energy_ratio[sf][band] < MASA2TOTAL_THR )
    3604             :                     {
    3605      178446 :                         tmp = ratio_ism_idx[band][nchan_ism - 1];
    3606      178446 :                         ratio_ism_idx[band][nchan_ism - 1] = ratio_ism_idx[band][0];
    3607      178446 :                         ratio_ism_idx[band][0] = tmp;
    3608      178446 :                         if ( sf == 0 && tmp == 0 )
    3609             :                         {
    3610       64952 :                             n_ism_tmp += 1;
    3611             :                         }
    3612             : 
    3613      178446 :                         if ( n_ism_tmp == numCodingBands )
    3614             :                         {
    3615       67341 :                             assert( tmp == 0 );
    3616             :                         }
    3617             :                     }
    3618             :                 }
    3619             :             }
    3620             :             else
    3621             :             {
    3622       99516 :                 if ( idx_separated_object > -1 )
    3623             :                 {
    3624      681773 :                     for ( band = 0; band < numCodingBands; band++ )
    3625             :                     {
    3626      582257 :                         if ( hOmasaData->masa_to_total_energy_ratio[sf][band] < MASA2TOTAL_THR )
    3627             :                         {
    3628      341171 :                             if ( ratio_ism_idx[band][idx_separated_object] == 0 && sf == 0 )
    3629             :                             {
    3630      151767 :                                 n_ism_tmp++;
    3631             :                             }
    3632             :                         }
    3633             :                     }
    3634             :                 }
    3635             :             }
    3636             : 
    3637             :             /* encode data for current subframe */
    3638      157947 :             if ( sf > 0 && n_ism_tmp == numCodingBands )
    3639             :             {
    3640       36669 :                 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      121278 :                 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     1094792 :             for ( band = 0; band < numCodingBands; band++ )
    3650             :             {
    3651      936845 :                 mvs2s( ratio_ism_idx[band], ratio_ism_idx_prev_sf[band], nchan_ism );
    3652             :             }
    3653             : 
    3654      157947 :             if ( rotate )
    3655             :             {
    3656      413019 :                 for ( band = 0; band < numCodingBands; band++ )
    3657             :                 {
    3658      354588 :                     if ( hOmasaData->masa_to_total_energy_ratio[sf][band] < MASA2TOTAL_THR )
    3659             :                     {
    3660      178446 :                         tmp = ratio_ism_idx[band][nchan_ism - 1];
    3661      178446 :                         ratio_ism_idx[band][nchan_ism - 1] = ratio_ism_idx[band][0];
    3662      178446 :                         ratio_ism_idx[band][0] = tmp;
    3663             :                     }
    3664             :                 }
    3665             :             }
    3666             :         }
    3667             :     }
    3668             : 
    3669       63612 :     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      274242 :     for ( obj = 0; obj < nchan_ism; obj++ )
    3673             :     {
    3674      210630 :         if ( bits_ism[obj] < 8 )
    3675             :         {
    3676             :             /* check is same as previous */
    3677      107434 :             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       10561 :                 push_next_indice( hMetaData, 1, 1 );
    3680             :                 /* the old stays the same */
    3681             :             }
    3682             :             else
    3683             :             {
    3684       96873 :                 push_next_indice( hMetaData, 0, 1 );
    3685       96873 :                 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       96873 :                 push_next_indice( hMetaData, idx_sph, bits_ism[obj] );
    3687       96873 :                 hIsmMeta[obj]->q_elevation_old = hIsmMeta[obj]->elevation;
    3688       96873 :                 hIsmMeta[obj]->q_azimuth_old = hIsmMeta[obj]->azimuth;
    3689             :             }
    3690             :         }
    3691             :         else
    3692             :         {
    3693      103196 :             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      103196 :             push_next_indice( hMetaData, idx_sph, bits_ism[obj] );
    3695      103196 :             hIsmMeta[obj]->q_elevation_old = hIsmMeta[obj]->elevation;
    3696      103196 :             hIsmMeta[obj]->q_azimuth_old = hIsmMeta[obj]->azimuth;
    3697             :         }
    3698             :     }
    3699             : 
    3700       63612 :     return;
    3701             : }
    3702             : 
    3703             : 
    3704             : /*-------------------------------------------------------------------*
    3705             :  * ivas_merge_masa_transports()
    3706             :  *
    3707             :  * Merge MASA transport channels
    3708             :  *-------------------------------------------------------------------*/
    3709             : 
    3710      190738 : 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      572214 :     for ( i = 0; i < num_transport_channels; i++ )
    3720             :     {
    3721   340468516 :         for ( j = 0; j < input_frame; j++ )
    3722             :         {
    3723   340087040 :             data_out_f[i][j] = data_in_f1[i][j] + data_in_f2[i][j];
    3724             :         }
    3725             :     }
    3726             : 
    3727      190738 :     return;
    3728             : }

Generated by: LCOV version 1.14