LCOV - code coverage report
Current view: top level - lib_enc - ivas_masa_enc.c (source / functions) Hit Total Coverage
Test: Coverage on main -- long test vectors @ efe53129c9ed87a5067dd0a8fb9dca41db9c4add Lines: 1354 1415 95.7 %
Date: 2026-02-12 08:06:16 Functions: 34 34 100.0 %

          Line data    Source code
       1             : /******************************************************************************************************
       2             : 
       3             :    (C) 2022-2026 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        6551 : 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        6551 :     error = IVAS_ERR_OK;
     104             : 
     105        6551 :     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        6551 :     hEncoderConfig = st_ivas->hEncoderConfig;
     111             : 
     112        6551 :     generate_gridEq( &( hMasa->data.Sph_Grid16 ) );
     113             : 
     114        6551 :     if ( hEncoderConfig->ivas_format == MASA_FORMAT || hEncoderConfig->ivas_format == MASA_ISM_FORMAT )
     115             :     {
     116         119 :         hMasa->data.num_Cldfb_instances = st_ivas->nchan_transport;
     117             :     }
     118             :     else
     119             :     {
     120        6432 :         hMasa->data.num_Cldfb_instances = 0;
     121             :     }
     122             : 
     123        6756 :     for ( i = 0; i < hMasa->data.num_Cldfb_instances; i++ )
     124             :     {
     125         205 :         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        6551 :     ism_total_brate = 0;
     132        6551 :     if ( hEncoderConfig->ivas_format == MASA_ISM_FORMAT && st_ivas->nSCE > 0 && ( st_ivas->ism_mode == ISM_MASA_MODE_DISC || st_ivas->ism_mode == ISM_MASA_MODE_PARAM_ONE_OBJ || st_ivas->ism_mode == ISM_MASA_MODE_MASA_ONE_OBJ ) )
     133             :     {
     134         104 :         for ( i = 0; i < st_ivas->nSCE; i++ )
     135             :         {
     136          67 :             ism_total_brate += st_ivas->hSCE[i]->element_brate;
     137             :         }
     138             :     }
     139             : 
     140        6551 :     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        6551 :     mvs2s( DirAC_block_grouping, hMasa->config.block_grouping, MAX_PARAM_SPATIAL_SUBFRAMES + 1 );
     143        6551 :     mvs2s( MASA_band_grouping_24, hMasa->config.band_grouping, MASA_FREQUENCY_BANDS + 1 );
     144             : 
     145             : 
     146        6551 :     hMasa->data.onset_detector_1 = 0.0f;
     147        6551 :     hMasa->data.onset_detector_2 = 0.0f;
     148             : 
     149        6551 :     set_zero( hMasa->data.lfeToTotalEnergyRatio, MAX_PARAM_SPATIAL_SUBFRAMES );
     150        6551 :     hMasa->data.prevq_lfeToTotalEnergyRatio = 0.0f;
     151        6551 :     hMasa->data.prevq_lfeIndex = 0;
     152             : 
     153        6551 :     hMasa->data.sync_state.prev_sim_stop = 0;
     154        6551 :     hMasa->data.sync_state.prev_offset = 0;
     155        6551 :     hMasa->data.sync_state.frame_mode = MASA_FRAME_4SF;
     156             : 
     157        6551 :     set_zero( hMasa->data.dir_align_state.previous_azi_dir1, MASA_FREQUENCY_BANDS );
     158        6551 :     set_zero( hMasa->data.dir_align_state.previous_ele_dir1, MASA_FREQUENCY_BANDS );
     159        6551 :     set_zero( hMasa->data.dir_align_state.previous_azi_dir2, MASA_FREQUENCY_BANDS );
     160        6551 :     set_zero( hMasa->data.dir_align_state.previous_ele_dir2, MASA_FREQUENCY_BANDS );
     161             : 
     162        6551 :     if ( hEncoderConfig->ivas_format == MASA_ISM_FORMAT )
     163             :     {
     164             :         OMASA_ENCODER_DATA_HANDLE hOmasaData;
     165             : 
     166          44 :         if ( ( hOmasaData = (OMASA_ENCODER_DATA_HANDLE) malloc( sizeof( OMASA_ENCODER_DATA_STATE ) ) ) == NULL )
     167             :         {
     168           0 :             return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for OMASA data encoder\n" ) );
     169             :         }
     170         220 :         for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ )
     171             :         {
     172         176 :             set_f( hOmasaData->masa_to_total_energy_ratio[i], 0, MASA_FREQUENCY_BANDS );
     173             :         }
     174          44 :         hOmasaData->lp_noise_CPE = -1;
     175          44 :         hOmasaData->omasa_stereo_sw_cnt = OMASA_STEREO_SW_CNT_MAX;
     176             : 
     177          44 :         if ( st_ivas->ism_mode != ISM_MASA_MODE_DISC )
     178             :         {
     179          27 :             if ( ( hOmasaData->hOmasaEnergy = (OMASA_ENCODER_ENERGY_HANDLE) malloc( sizeof( OMASA_ENCODER_ENERGY_STATE ) ) ) == NULL )
     180             :             {
     181           0 :                 return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for OMASA energy handle\n" ) );
     182             :             }
     183             :         }
     184             :         else
     185             :         {
     186          17 :             hOmasaData->hOmasaEnergy = NULL;
     187             :         }
     188             : 
     189          44 :         hMasa->data.hOmasaData = hOmasaData;
     190             :     }
     191             :     else
     192             :     {
     193        6507 :         hMasa->data.hOmasaData = NULL;
     194             :     }
     195             : 
     196        6551 :     st_ivas->hMasa = hMasa;
     197             : 
     198        6551 :     return error;
     199             : }
     200             : 
     201             : 
     202             : /*-----------------------------------------------------------------------*
     203             :  * ivas_masa_enc_close()
     204             :  *
     205             :  * close MASA encoder
     206             :  *-----------------------------------------------------------------------*/
     207             : 
     208        9583 : void ivas_masa_enc_close(
     209             :     MASA_ENCODER_HANDLE *hMasa /* i/o: MASA metadata structure      */
     210             : )
     211             : {
     212             :     int16_t i;
     213             : 
     214        9583 :     if ( hMasa == NULL || *hMasa == NULL )
     215             :     {
     216        3032 :         return;
     217             :     }
     218             : 
     219        6756 :     for ( i = 0; i < ( *hMasa )->data.num_Cldfb_instances; i++ )
     220             :     {
     221         205 :         deleteCldfb( &( ( *hMasa )->data.cldfbAnaEnc[i] ) );
     222             :     }
     223             : 
     224        6551 :     if ( ( *hMasa )->data.hOmasaData != NULL )
     225             :     {
     226          44 :         if ( ( *hMasa )->data.hOmasaData->hOmasaEnergy != NULL )
     227             :         {
     228          27 :             free( ( *hMasa )->data.hOmasaData->hOmasaEnergy );
     229          27 :             ( *hMasa )->data.hOmasaData->hOmasaEnergy = NULL;
     230             :         }
     231             : 
     232          44 :         free( ( *hMasa )->data.hOmasaData );
     233          44 :         ( *hMasa )->data.hOmasaData = NULL;
     234             :     }
     235             : 
     236        6551 :     free( ( *hMasa ) );
     237        6551 :     ( *hMasa ) = NULL;
     238             : 
     239        6551 :     return;
     240             : }
     241             : 
     242             : 
     243             : /*-----------------------------------------------------------------------*
     244             :  * ivas_masa_encode()
     245             :  *
     246             :  * main MASA encoder function
     247             :  *-----------------------------------------------------------------------*/
     248             : 
     249      984945 : 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      984945 :     masa_sid_descriptor = -1;
     276      984945 :     h_orig_metadata = NULL;
     277      984945 :     low_bitrate_mode = 0;
     278             : 
     279      984945 :     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      818385 :         if ( Opt_DTX_ON && hQMetaData != NULL )
     283             :         {
     284       51975 :             if ( nchan_transport == 2 ) /* this is MASA format in CPE only */
     285             :             {
     286       34680 :                 masa_sid_descriptor = 0; /* for IVAS_CPE_DFT */
     287       34680 :                 if ( element_mode == IVAS_CPE_MDCT )
     288             :                 {
     289       14820 :                     masa_sid_descriptor = 1;
     290             :                 }
     291             :             }
     292             :         }
     293             : 
     294             :         /* Validate and compensate ratios as necessary */
     295      818385 :         compensate_energy_ratios( hMasa );
     296             : 
     297      818385 :         if ( Opt_DTX_ON )
     298             :         {
     299       51975 :             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      155925 :             for ( i = 0; i < MASA_MAXIMUM_DIRECTIONS; i++ )
     305             :             {
     306      519750 :                 for ( j = 0; j < MAX_PARAM_SPATIAL_SUBFRAMES; j++ )
     307             :                 {
     308      415800 :                     mvr2r( hMasa->masaMetadata.directional_meta[i].azimuth[j], h_orig_metadata[i].azimuth[j], MASA_FREQUENCY_BANDS );
     309      415800 :                     mvr2r( hMasa->masaMetadata.directional_meta[i].elevation[j], h_orig_metadata[i].elevation[j], MASA_FREQUENCY_BANDS );
     310      415800 :                     mvr2r( hMasa->masaMetadata.directional_meta[i].energy_ratio[j], h_orig_metadata[i].energy_ratio[j], MASA_FREQUENCY_BANDS );
     311      415800 :                     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      818385 :         if ( ( ivas_format == MASA_FORMAT || ivas_format == MASA_ISM_FORMAT ) && ivas_total_brate >= IVAS_384k )
     317             :         {
     318       75244 :             hMasa->config.mergeRatiosOverSubframes = 0;
     319             :         }
     320             : 
     321             :         /* Combine frequency bands and sub-frames */
     322      818385 :         combine_freqbands_and_subframes( hMasa );
     323             :     }
     324             : 
     325      984945 :     if ( hMasa->config.numberOfDirections == 2 && hMasa->config.numTwoDirBands < hMasa->config.numCodingBands && ( ivas_format == MASA_FORMAT || ivas_format == MASA_ISM_FORMAT ) )
     326             :     {
     327      316832 :         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      258440 :             ivas_masa_combine_directions( hMasa );
     331             :         }
     332             : 
     333             :         /* If we joined all bands, then metadata is now one directional. */
     334      316832 :         if ( hMasa->config.numTwoDirBands == 0 )
     335             :         {
     336      169751 :             hMasa->config.numberOfDirections = 1;
     337      169751 :             hMasa->masaMetadata.descriptive_meta.numberOfDirections = 0;
     338      169751 :             hQMetaData->no_directions = 1;
     339             :         }
     340             :     }
     341             : 
     342             :     /* Reset qmetadata bit budget */
     343      984945 :     hQMetaData->metadata_max_bits = hMasa->config.max_metadata_bits;
     344      984945 :     if ( ivas_format == MASA_FORMAT || ivas_format == MASA_ISM_FORMAT )
     345             :     {
     346      818385 :         if ( ivas_format == MASA_ISM_FORMAT && ism_mode != ISM_MODE_NONE )
     347             :         {
     348             :             /* write the number of objects in ISM_MASA format*/
     349      207500 :             push_next_indice( hMetaData, nchan_ism - 1, NO_BITS_MASA_ISM_NO_OBJ );
     350      207500 :             hQMetaData->metadata_max_bits -= NO_BITS_MASA_ISM_NO_OBJ;
     351             : 
     352             :             /* write index of separated object if needed */
     353      207500 :             if ( ism_mode == ISM_MASA_MODE_PARAM_ONE_OBJ && nchan_ism > 1 )
     354             :             {
     355       59500 :                 push_next_indice( hMetaData, idx_separated_object, NO_BITS_MASA_ISM_NO_OBJ );
     356       59500 :                 hQMetaData->metadata_max_bits -= NO_BITS_MASA_ISM_NO_OBJ;
     357             :             }
     358             : 
     359             :             /* write ISM importance flag (one per object) */
     360      207500 :             if ( ism_mode == ISM_MASA_MODE_PARAM_ONE_OBJ )
     361             :             {
     362       59500 :                 push_next_indice( hMetaData, hIsmMetaData[0]->ism_imp, ISM_METADATA_FLAG_BITS );
     363       59500 :                 hQMetaData->metadata_max_bits -= ISM_METADATA_FLAG_BITS;
     364             :             }
     365      148000 :             else if ( ism_mode == ISM_MASA_MODE_MASA_ONE_OBJ )
     366             :             {
     367       61500 :                 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       61500 :                     push_next_indice( hMetaData, hIsmMetaData[0]->ism_imp, ISM_METADATA_FLAG_BITS );
     382       61500 :                     hQMetaData->metadata_max_bits -= ISM_METADATA_FLAG_BITS;
     383             : 
     384       61500 :                     if ( hIsmMetaData[0]->ism_imp == ISM_NO_META )
     385             :                     {
     386             :                         /* signal low-rate ISM_NO_META frame */
     387        2314 :                         push_next_indice( hMetaData, 0, ISM_METADATA_MD_FLAG_BITS );
     388        2314 :                         hQMetaData->metadata_max_bits -= ISM_METADATA_MD_FLAG_BITS;
     389             : 
     390             :                         /* signal presence of MD in low-rate ISM_NO_META frame */
     391        2314 :                         push_next_indice( hMetaData, hIsmMetaData[0]->ism_md_lowrate_flag, ISM_METADATA_INACTIVE_FLAG_BITS );
     392        2314 :                         hQMetaData->metadata_max_bits -= ISM_METADATA_INACTIVE_FLAG_BITS;
     393             :                     }
     394             :                 }
     395             :             }
     396       86500 :             else if ( ism_mode == ISM_MASA_MODE_DISC )
     397             :             {
     398      334500 :                 for ( i = 0; i < nchan_ism; i++ )
     399             :                 {
     400      248000 :                     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      248000 :                         push_next_indice( hMetaData, hIsmMetaData[i]->ism_imp, ISM_METADATA_FLAG_BITS );
     415      248000 :                         hQMetaData->metadata_max_bits -= ISM_METADATA_FLAG_BITS;
     416             : 
     417      248000 :                         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       86500 :                 if ( ivas_total_brate == IVAS_128k && nchan_ism >= 3 )
     431             :                 {
     432        3060 :                     push_next_indice( hMetaData, flag_omasa_ener_brate, 1 );
     433        3060 :                     hQMetaData->metadata_max_bits -= 1;
     434             :                 }
     435             :             }
     436             :         }
     437             :         else
     438             :         {
     439      610885 :             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       56500 :                 if ( nchan_ism == 1 || nchan_ism == 2 )
     443             :                 {
     444       19000 :                     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       37500 :                     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      554385 :                 push_next_indice( hMetaData, nchan_transport - 1, MASA_TRANSP_BITS );
     456             :             }
     457      610885 :             hQMetaData->metadata_max_bits -= MASA_TRANSP_BITS;
     458             :         }
     459             : 
     460      818385 :         if ( ivas_format == MASA_ISM_FORMAT && ism_mode == ISM_MODE_NONE )
     461             :         {
     462       56500 :             if ( nchan_ism >= 3 ) /* if 3 or 4 objects */
     463             :             {
     464       37500 :                 push_next_indice( hMetaData, 5 - nchan_ism, MASA_HEADER_BITS );
     465             :             }
     466             :             else
     467             :             {
     468       19000 :                 push_next_indice( hMetaData, 3, MASA_HEADER_BITS );
     469             :             }
     470       56500 :             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      761885 :             push_next_indice( hMetaData, 0, MASA_HEADER_BITS );
     477      761885 :             hQMetaData->metadata_max_bits -= MASA_HEADER_BITS;
     478             :         }
     479      818385 :         if ( !( ivas_format == MASA_ISM_FORMAT && ism_mode == ISM_MODE_NONE && nchan_ism > 2 ) )
     480             :         {
     481             :             /* write number of directions */
     482      780885 :             push_next_indice( hMetaData, hQMetaData->no_directions - 1, 1 );
     483      780885 :             hQMetaData->metadata_max_bits -= 1;
     484             :         }
     485             :         /* write subframe mode */
     486      818385 :         push_next_indice( hMetaData, hQMetaData->q_direction[0].cfg.nblocks == 1 ? 1 : 0, MASA_SUBFRAME_BITS );
     487      818385 :         hQMetaData->metadata_max_bits -= MASA_SUBFRAME_BITS;
     488             :     }
     489             : 
     490      984945 :     if ( ivas_format == MC_FORMAT )
     491             :     {
     492             :         int16_t lfeBitsWritten;
     493      166560 :         lfeBitsWritten = encode_lfe_to_total_energy_ratio( hMasa, hMetaData, ivas_total_brate );
     494      166560 :         hQMetaData->metadata_max_bits -= lfeBitsWritten;
     495             :     }
     496             : 
     497             :     /* Move data from encoder to qmetadata */
     498      984945 :     if ( ivas_format == MASA_FORMAT || ivas_format == MASA_ISM_FORMAT )
     499             :     {
     500      818385 :         move_metadata_to_qmetadata( hMasa, hQMetaData );
     501             :     }
     502             : 
     503      984945 :     if ( hMasa->config.max_metadata_bits < MINIMUM_BIT_BUDGET_NORMAL_META && !hMasa->config.joinedSubframes )
     504             :     {
     505      292228 :         reduce_metadata_further( hMasa, hQMetaData, ivas_format );
     506             : 
     507      292228 :         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      292228 :         push_next_indice( hMetaData, hQMetaData->q_direction[0].cfg.nblocks == 1 ? 1 : 0, MASA_LOWBITRATE_MODE_BITS );
     511      292228 :         hQMetaData->metadata_max_bits -= MASA_LOWBITRATE_MODE_BITS;
     512             :     }
     513             : 
     514             :     /* Encode MASA+ISM metadata */
     515      984945 :     if ( ivas_format == MASA_ISM_FORMAT && ism_mode == ISM_MASA_MODE_PARAM_ONE_OBJ )
     516             :     {
     517             :         /* encode MASA/ISM energy ratios */
     518       59500 :         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      925445 :         if ( ivas_format == MASA_ISM_FORMAT )
     523             :         {
     524      204500 :             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      984945 :     masa_total_brate = ivas_total_brate;
     530      984945 :     if ( ivas_format == MASA_ISM_FORMAT && ism_mode == ISM_MASA_MODE_DISC )
     531             :     {
     532       86500 :         masa_total_brate = calculate_cpe_brate_MASA_ISM( ism_mode, ivas_total_brate, nchan_ism );
     533             :     }
     534             : 
     535      984945 :     if ( masa_total_brate >= IVAS_384k )
     536             :     {
     537       62230 :         if ( masa_total_brate >= IVAS_512k )
     538             :         {
     539       24450 :             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       37780 :             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      922715 :         if ( ( error = ivas_qmetadata_enc_encode( hMetaData, hQMetaData, 0 ) ) != IVAS_ERR_OK )
     555             :         {
     556           0 :             return error;
     557             :         }
     558             :     }
     559             : 
     560      984945 :     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       59500 :         ivas_omasa_modify_masa_energy_ratios( hQMetaData, hMasa->data.hOmasaData->masa_to_total_energy_ratio );
     564             :     }
     565             : 
     566      984945 :     *nb_bits_metadata = hMetaData->nb_bits_tot;
     567             : 
     568      984945 :     if ( ivas_format == MASA_FORMAT && Opt_DTX_ON )
     569             :     {
     570             :         /* save old values */
     571       51975 :         uint8_t numCodingBands = hMasa->config.numCodingBands;
     572       51975 :         uint8_t numTwoDirBands = hMasa->config.numTwoDirBands;
     573       51975 :         int16_t nbands = hQMetaData->q_direction[0].cfg.nbands;
     574       51975 :         uint8_t numberOfDirections = hMasa->config.numberOfDirections;
     575       51975 :         uint8_t numberOfDirectionsMeta = hMasa->masaMetadata.descriptive_meta.numberOfDirections;
     576       51975 :         uint16_t numberOfDirectionsQMetaData = hQMetaData->no_directions;
     577             : 
     578       51975 :         if ( !( hMasa->config.numberOfDirections == 1 && hQMetaData->q_direction->cfg.nbands == 5 ) )
     579             :         {
     580       58941 :             for ( i = 0; i < MASA_MAXIMUM_DIRECTIONS; i++ )
     581             :             {
     582      196470 :                 for ( j = 0; j < MAX_PARAM_SPATIAL_SUBFRAMES; j++ )
     583             :                 {
     584      157176 :                     mvr2r( h_orig_metadata[i].azimuth[j], hMasa->masaMetadata.directional_meta[i].azimuth[j], MASA_FREQUENCY_BANDS );
     585      157176 :                     mvr2r( h_orig_metadata[i].elevation[j], hMasa->masaMetadata.directional_meta[i].elevation[j], MASA_FREQUENCY_BANDS );
     586      157176 :                     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       19647 :             hMasa->config.numCodingBands = 5;
     592       19647 :             hMasa->config.numTwoDirBands = 0;
     593       19647 :             combine_freqbands_and_subframes( hMasa );
     594       19647 :             hQMetaData->q_direction[0].cfg.nbands = 5;
     595             : 
     596       19647 :             if ( hMasa->config.numberOfDirections == 2 && hMasa->config.numTwoDirBands < hMasa->config.numCodingBands )
     597             :             {
     598             :                 /* Combine directions */
     599        3909 :                 ivas_masa_combine_directions( hMasa );
     600             : 
     601             :                 /* If we joined all bands, then metadata is now one directional. */
     602        3909 :                 if ( hMasa->config.numTwoDirBands == 0 )
     603             :                 {
     604        3909 :                     hMasa->config.numberOfDirections = 1;
     605        3909 :                     hMasa->masaMetadata.descriptive_meta.numberOfDirections = 0;
     606        3909 :                     hQMetaData->no_directions = 1;
     607             :                 }
     608             :             }
     609             : 
     610       19647 :             move_metadata_to_qmetadata( hMasa, hQMetaData );
     611             : 
     612      117882 :             for ( j = hQMetaData->q_direction[0].cfg.start_band; j < hQMetaData->q_direction[0].cfg.nbands; ++j )
     613             :             {
     614       98235 :                 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       51975 :         free( h_orig_metadata );
     619             : 
     620       51975 :         ivas_qmetadata_enc_sid_encode( hMetaData, hQMetaData, masa_sid_descriptor, 0, ivas_format );
     621             : 
     622             :         /* restore old values */
     623       51975 :         hMasa->config.numCodingBands = numCodingBands;
     624       51975 :         hMasa->config.numTwoDirBands = numTwoDirBands;
     625       51975 :         hQMetaData->q_direction[0].cfg.nbands = nbands;
     626       51975 :         hMasa->config.numberOfDirections = numberOfDirections;
     627       51975 :         hMasa->masaMetadata.descriptive_meta.numberOfDirections = numberOfDirectionsMeta;
     628       51975 :         hQMetaData->no_directions = numberOfDirectionsQMetaData;
     629             :     }
     630             : 
     631      984945 :     return IVAS_ERR_OK;
     632             : }
     633             : 
     634             : 
     635             : /*-----------------------------------------------------------------------*
     636             :  * ivas_masa_estimate_energy()
     637             :  *
     638             :  *
     639             :  *-----------------------------------------------------------------------*/
     640             : 
     641      818385 : 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      818385 :     maxBin = (int16_t) ( (float) CLDFB_NO_CHANNELS_MAX * (float) input_frame / L_FRAME48k + 0.5f );
     655             : 
     656      818385 :     l_ts = input_frame / CLDFB_NO_COL_MAX;
     657             : 
     658     4091925 :     for ( block_m_idx = 0; block_m_idx < MAX_PARAM_SPATIAL_SUBFRAMES; block_m_idx++ )
     659             :     {
     660     3273540 :         mrange[0] = hMasa->config.block_grouping[block_m_idx];
     661     3273540 :         mrange[1] = hMasa->config.block_grouping[block_m_idx + 1];
     662             : 
     663     3273540 :         set_zero( hMasa->data.energy[block_m_idx], MASA_FREQUENCY_BANDS );
     664             : 
     665    16367700 :         for ( ts = mrange[0]; ts < mrange[1]; ts++ )
     666             :         {
     667    36238560 :             for ( i = 0; i < nchan_transport; i++ )
     668             :             {
     669    23144400 :                 cldfbAnalysis_ts( &( data_f[i][l_ts * ts] ), Input_RealBuffer[i], Input_ImagBuffer[i], l_ts, hMasa->data.cldfbAnaEnc[i] );
     670             :             }
     671             : 
     672   327354000 :             for ( band_m_idx = 0; band_m_idx < MASA_FREQUENCY_BANDS; band_m_idx++ )
     673             :             {
     674   314259840 :                 brange[0] = hMasa->config.band_grouping[band_m_idx];
     675   314259840 :                 brange[1] = hMasa->config.band_grouping[band_m_idx + 1];
     676             : 
     677   869725440 :                 for ( i = 0; i < nchan_transport; i++ )
     678             :                 {
     679   555465600 :                     if ( brange[0] > maxBin )
     680             :                     {
     681     1984320 :                         hMasa->data.energy[block_m_idx][band_m_idx] = 0;
     682     1984320 :                         continue;
     683             :                     }
     684   553481280 :                     else if ( brange[1] >= maxBin )
     685             :                     {
     686    25135520 :                         brange[1] = maxBin;
     687             :                     }
     688             : 
     689  1889094080 :                     for ( j = brange[0]; j < brange[1]; j++ )
     690             :                     {
     691  1335612800 :                         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      818385 :     return;
     699             : }
     700             : 
     701             : 
     702             : /*-----------------------------------------------------------------------*
     703             :  * ivas_masa_enc_config()
     704             :  *
     705             :  * Frame-by-frame configuration of MASA encoder
     706             :  *-----------------------------------------------------------------------*/
     707             : 
     708      824817 : 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      824817 :     error = IVAS_ERR_OK;
     727             : 
     728      824817 :     hMasa = st_ivas->hMasa;
     729      824817 :     hQMetaData = st_ivas->hQMetaData;
     730      824817 :     ivas_format = st_ivas->hEncoderConfig->ivas_format;
     731      824817 :     ivas_total_brate = st_ivas->hEncoderConfig->ivas_total_brate;
     732             : 
     733      824817 :     ism_total_brate = 0;
     734      824817 :     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      576500 :         for ( i = 0; i < st_ivas->nSCE; i++ )
     737             :         {
     738      369000 :             ism_total_brate += st_ivas->hSCE[i]->element_brate;
     739             :         }
     740             :     }
     741             : 
     742      824817 :     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      824817 :     hQMetaData->is_masa_ivas_format = 1;
     745             : 
     746      824817 :     if ( ivas_format == MASA_FORMAT || ivas_format == MASA_ISM_FORMAT )
     747             :     {
     748      818385 :         masa_metadata_direction_alignment( hMasa );
     749             : 
     750      818385 :         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      818385 :         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      818385 :         detect_metadata_composition( hMasa, &joinedSubframes, &coherencePresent, &isActualTwoDir );
     760      818385 :         hMasa->config.joinedSubframes = joinedSubframes;
     761      818385 :         hMasa->config.coherencePresent = coherencePresent;
     762      818385 :         hMasa->config.numberOfDirections = ( hMasa->masaMetadata.descriptive_meta.numberOfDirections + 1 ) == 2 && isActualTwoDir ? 2 : 1;
     763             :     }
     764        6432 :     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        6432 :         hMasa->config.joinedSubframes = 0;
     768        6432 :         hMasa->config.numberOfDirections = 1;
     769             :     }
     770             : 
     771      824817 :     if ( ivas_format == MASA_ISM_FORMAT )
     772             :     {
     773      264000 :         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      560817 :         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      824817 :     if ( hMasa->config.numberOfDirections == 2 )
     782             :     {
     783      325382 :         set_f( hMasa->data.importanceWeight, 1.0f, hMasa->config.numCodingBands );
     784             : 
     785      325382 :         if ( hMasa->config.numCodingBands == 5 )
     786             :         {
     787      203951 :             hMasa->data.importanceWeight[4] = 0.7f;
     788             :         }
     789      121431 :         else if ( hMasa->config.numCodingBands == 8 )
     790             :         {
     791       21195 :             hMasa->data.importanceWeight[7] = 0.7f;
     792             :         }
     793      100236 :         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      100236 :         else if ( hMasa->config.numCodingBands == 12 )
     799             :         {
     800       40593 :             hMasa->data.importanceWeight[10] = 0.7f;
     801       40593 :             hMasa->data.importanceWeight[11] = 0.1f;
     802             :         }
     803       59643 :         else if ( hMasa->config.numCodingBands == 18 )
     804             :         {
     805       40069 :             hMasa->data.importanceWeight[14] = 0.8f;
     806       40069 :             hMasa->data.importanceWeight[15] = 0.5f;
     807       40069 :             hMasa->data.importanceWeight[16] = 0.2f;
     808       40069 :             hMasa->data.importanceWeight[17] = 0.0f;
     809             :         }
     810       19574 :         else if ( hMasa->config.numCodingBands == 24 )
     811             :         {
     812       19574 :             hMasa->data.importanceWeight[20] = 0.8f;
     813       19574 :             hMasa->data.importanceWeight[21] = 0.5f;
     814       19574 :             hMasa->data.importanceWeight[22] = 0.2f;
     815       19574 :             hMasa->data.importanceWeight[23] = 0.0f;
     816             :         }
     817             : 
     818      325382 :         if ( hMasa->config.numTwoDirBands == hMasa->config.numCodingBands )
     819             :         {
     820        7036 :             set_c( (int8_t *) hMasa->data.twoDirBands, 1, hMasa->config.numCodingBands );
     821             :         }
     822             :     }
     823             :     else
     824             :     {
     825      499435 :         set_c( (int8_t *) hMasa->data.twoDirBands, 0, hMasa->config.numCodingBands );
     826             :     }
     827             : 
     828             :     /* Set qmeta to correct values */
     829      824817 :     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     1805265 :     for ( i = 0; i < hQMetaData->no_directions; i++ )
     835             :     {
     836      980448 :         hQMetaData->q_direction[i].cfg.nbands = hMasa->config.numCodingBands;
     837      980448 :         hQMetaData->q_direction[i].cfg.nblocks = hMasa->config.joinedSubframes == TRUE ? 1 : MAX_PARAM_SPATIAL_SUBFRAMES;
     838             : 
     839      980448 :         if ( ivas_format == MC_FORMAT )
     840             :         {
     841        6432 :             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      974016 :             hQMetaData->q_direction[i].cfg.mc_ls_setup = MC_LS_SETUP_INVALID;
     847             :         }
     848             :     }
     849             : 
     850      824817 :     hQMetaData->all_coherence_zero = !hMasa->config.coherencePresent;
     851             : 
     852      824817 :     ivas_set_qmetadata_maxbit_req( hQMetaData, ivas_format );
     853             : 
     854             :     /* Find maximum band usable */
     855      824817 :     maxBin = (int16_t) ( st_ivas->hEncoderConfig->input_Fs * INV_CLDFB_BANDWIDTH );
     856      824817 :     maxBand = 0;
     857    21317801 :     while ( maxBand <= MASA_FREQUENCY_BANDS && MASA_band_grouping_24[maxBand] <= maxBin )
     858             :     {
     859    20492984 :         maxBand++;
     860             :     }
     861      824817 :     maxBand--;
     862             : 
     863      824817 :     st_ivas->hQMetaData->q_direction->cfg.inactiveBands = 0;
     864      824817 :     masa_total_brate = ivas_total_brate;
     865      824817 :     if ( ivas_format == MASA_ISM_FORMAT && st_ivas->ism_mode == ISM_MASA_MODE_DISC )
     866             :     {
     867       86500 :         masa_total_brate = calculate_cpe_brate_MASA_ISM( st_ivas->ism_mode, ivas_total_brate, st_ivas->hEncoderConfig->nchan_ism );
     868             :     }
     869      824817 :     if ( masa_total_brate >= IVAS_384k && ( ivas_format == MASA_FORMAT || ivas_format == MASA_ISM_FORMAT ) )
     870             :     {
     871             :         int16_t continueLoop;
     872       62230 :         continueLoop = 1;
     873      223690 :         while ( maxBand > 5 && continueLoop )
     874             :         {
     875      580359 :             for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
     876             :             {
     877      477003 :                 if ( hMasa->data.energy[sf][maxBand - 1] > 100000 )
     878             :                 {
     879       58104 :                     continueLoop = 0;
     880       58104 :                     break;
     881             :                 }
     882             :             }
     883      161460 :             if ( continueLoop )
     884             :             {
     885      103356 :                 maxBand--;
     886             :             }
     887             :         }
     888             : 
     889       62230 :         if ( maxBand < MASA_MAXIMUM_CODING_SUBBANDS )
     890             :         {
     891       13210 :             st_ivas->hQMetaData->q_direction->cfg.inactiveBands = MASA_MAXIMUM_CODING_SUBBANDS - maxBand;
     892             :         }
     893             :         else
     894             :         {
     895       49020 :             st_ivas->hQMetaData->q_direction->cfg.inactiveBands = 0;
     896             :         }
     897             :     }
     898             : 
     899      824817 :     masa_sample_rate_band_correction( &( hMasa->config ), hMasa->data.band_mapping, hQMetaData, maxBand, masa_total_brate >= IVAS_384k, NULL );
     900             : 
     901      824817 :     if ( hMasa->config.numTwoDirBands >= hMasa->config.numCodingBands )
     902             :     {
     903        8550 :         hMasa->config.numTwoDirBands = hMasa->config.numCodingBands;
     904        8550 :         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      824817 :     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      246734 :         st_ivas->hCPE[0]->hStereoDft->hConfig->force_mono_transmission = ( ivas_total_brate - ism_total_brate < MASA_STEREO_MIN_BITRATE ) ? 1 : 0;
     911             :     }
     912             : 
     913      824817 :     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      207500 :         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       89163 :             st_ivas->hMasa->data.hOmasaData->lp_noise_CPE = st_ivas->hCPE[0]->hCoreCoder[0]->lp_noise;
     918             :         }
     919             :         else
     920             :         {
     921      118337 :             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      824817 :     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      117078 : 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      117078 :     float surrCohSignificanceCoef = 0.4f;
     946      117078 :     float threshold = 0.1f;
     947             : 
     948      309771 :     for ( sf = 0; sf < nSubFrames; sf++ )
     949             :     {
     950      223299 :         surrCohToTotalSum = 0.0f;
     951      223299 :         surrCohToTotalTimesDiffSum = 0.0f;
     952      223299 :         diffSum = 0.0f;
     953     5228904 :         for ( band = 0; band < nBands; band++ )
     954             :         {
     955     5005605 :             surrCohToTotal = diffuse_to_total_ratio[sf][band] * surroundingCoherence[sf][band];
     956     5005605 :             surrCohToTotalSum += surrCohToTotal;
     957     5005605 :             surrCohToTotalTimesDiffSum += diffuse_to_total_ratio[sf][band] * surrCohToTotal;
     958     5005605 :             diffSum += diffuse_to_total_ratio[sf][band];
     959             :         }
     960      223299 :         significanceMeasure1 = surrCohToTotalSum / (float) nBands;
     961      223299 :         significanceMeasure2 = surrCohSignificanceCoef * surrCohToTotalTimesDiffSum / ( diffSum + EPSILON );
     962      223299 :         significanceMeasure = max( significanceMeasure1, significanceMeasure2 );
     963             : 
     964      223299 :         if ( significanceMeasure > threshold )
     965             :         {
     966       30606 :             return 1; /* Surrounding coherence was significant in at least one subframe */
     967             :         }
     968             :     }
     969             : 
     970       86472 :     return 0; /* Surrounding coherence was not significant in any subframe */
     971             : }
     972             : 
     973             : 
     974             : /*-----------------------------------------------------------------------*
     975             :  * Local functions
     976             :  *-----------------------------------------------------------------------*/
     977             : 
     978      838032 : 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      838032 :     numCodingBands = hMasa->config.numCodingBands;
    1004      838032 :     numDirections = hMasa->config.numberOfDirections;
    1005      838032 :     numSf = hMasa->config.joinedSubframes == TRUE ? 1 : MAX_PARAM_SPATIAL_SUBFRAMES;
    1006      838032 :     hMeta = &( hMasa->masaMetadata );
    1007             : 
    1008      838032 :     mergeRatiosOverSubframes = hMasa->config.mergeRatiosOverSubframes;
    1009      838032 :     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      838032 :     if ( numSf == 1 )
    1015             :     {
    1016     1220980 :         for ( j = 1; j < MAX_PARAM_SPATIAL_SUBFRAMES; j++ )
    1017             :         {
    1018    22893375 :             for ( k = 0; k < MASA_FREQUENCY_BANDS; k++ )
    1019             :             {
    1020    21977640 :                 hMasa->data.energy[0][k] += hMasa->data.energy[j][k];
    1021             :             }
    1022             :         }
    1023             :     }
    1024             : 
    1025      838032 :     if ( numCodingBands <= MAX_REDUCED_NBANDS )
    1026             :     {
    1027             :         /* reduce metadata *frequency* resolution. time resolution is not touched */
    1028     1807111 :         for ( i = 0; i < numDirections; i++ )
    1029             :         {
    1030     4115687 :             for ( j = 0; j < numSf; j++ ) /* NB: for numSf==1, operates only on first sub-frame */
    1031             :             {
    1032    76407475 :                 for ( k = 0; k < MASA_FREQUENCY_BANDS; k++ )
    1033             :                 {
    1034    73351176 :                     aziRad = hMeta->directional_meta[i].azimuth[j][k] / 180.0f * EVS_PI;
    1035    73351176 :                     eleRad = hMeta->directional_meta[i].elevation[j][k] / 180.0f * EVS_PI;
    1036    73351176 :                     vecLen = hMeta->directional_meta[i].energy_ratio[j][k] * hMasa->data.energy[j][k];
    1037             : 
    1038    73351176 :                     x[i][j][k] = cosf( aziRad ) * cosf( eleRad ) * vecLen;
    1039    73351176 :                     y[i][j][k] = sinf( aziRad ) * cosf( eleRad ) * vecLen;
    1040    73351176 :                     z[i][j][k] = sinf( eleRad ) * vecLen;
    1041             :                 }
    1042             :             }
    1043             :         }
    1044             : 
    1045     1807111 :         for ( i = 0; i < numDirections; i++ )
    1046             :         {
    1047     4115687 :             for ( j = 0; j < numSf; j++ )
    1048             :             {
    1049    23811524 :                 for ( k = 0; k < numCodingBands; k++ )
    1050             :                 {
    1051    20755225 :                     brange[0] = hMasa->data.band_mapping[k];
    1052    20755225 :                     brange[1] = hMasa->data.band_mapping[k + 1];
    1053             : 
    1054    20755225 :                     xSum = 0.0f;
    1055    20755225 :                     ySum = 0.0f;
    1056    20755225 :                     zSum = 0.0f;
    1057    20755225 :                     energySum = 0.0f;
    1058    20755225 :                     spreadCohSum = 0.0f;
    1059             : 
    1060    92513736 :                     for ( m = brange[0]; m < brange[1]; m++ )
    1061             :                     {
    1062    71758511 :                         xSum += x[i][j][m];
    1063    71758511 :                         ySum += y[i][j][m];
    1064    71758511 :                         zSum += z[i][j][m];
    1065    71758511 :                         energySum += hMasa->data.energy[j][m];
    1066             :                     }
    1067             : 
    1068    20755225 :                     aziRad = atan2f( ySum, xSum );
    1069    20755225 :                     eleRad = atan2f( zSum, sqrtf( xSum * xSum + ySum * ySum ) );
    1070             : 
    1071    20755225 :                     hMeta->directional_meta[i].azimuth[j][k] = aziRad / EVS_PI * 180.0f;
    1072    20755225 :                     hMeta->directional_meta[i].elevation[j][k] = eleRad / EVS_PI * 180.0f;
    1073             : 
    1074    20755225 :                     vecLen = sqrtf( xSum * xSum + ySum * ySum + zSum * zSum );
    1075    20755225 :                     hMeta->directional_meta[i].energy_ratio[j][k] = vecLen / ( energySum + EPSILON );
    1076             : 
    1077    20755225 :                     if ( computeCoherence )
    1078             :                     {
    1079    47892983 :                         for ( m = brange[0]; m < brange[1]; m++ )
    1080             :                         {
    1081    35426926 :                             spreadCohSum += hMeta->directional_meta[i].spread_coherence[j][m] * hMasa->data.energy[j][m];
    1082             :                         }
    1083    12466057 :                         hMeta->directional_meta[i].spread_coherence[j][k] = spreadCohSum / ( energySum + EPSILON );
    1084             : 
    1085    12466057 :                         if ( i == 0 )
    1086             :                         {
    1087     8659122 :                             surrCohSum = 0.0f;
    1088    33125522 :                             for ( m = brange[0]; m < brange[1]; m++ )
    1089             :                             {
    1090    24466400 :                                 surrCohSum += hMeta->common_meta.surround_coherence[j][m] * hMasa->data.energy[j][m];
    1091             :                             }
    1092     8659122 :                             hMeta->common_meta.surround_coherence[j][k] = surrCohSum / ( energySum + EPSILON );
    1093             :                         }
    1094             :                     }
    1095             : 
    1096    20755225 :                     if ( i == 0 )
    1097             :                     {
    1098    14691000 :                         energy[j][k] = energySum;
    1099             :                     }
    1100             :                 }
    1101             :             }
    1102             :         }
    1103             :     }
    1104       90309 :     else if ( mergeRatiosOverSubframes ) /* keep frequency resolution */
    1105             :     {
    1106      103225 :         for ( j = 0; j < numSf; j++ )
    1107             :         {
    1108     2064500 :             for ( k = 0; k < numCodingBands; k++ )
    1109             :             {
    1110     1981920 :                 energy[j][k] = hMasa->data.energy[j][k];
    1111             :             }
    1112             :         }
    1113             :     }
    1114             : 
    1115      838032 :     if ( mergeRatiosOverSubframes )
    1116             :     {
    1117     3816400 :         for ( k = 0; k < numCodingBands; k++ )
    1118             :         {
    1119     3334791 :             energySum = 0.0f;
    1120    16673955 :             for ( j = 0; j < numSf; j++ )
    1121             :             {
    1122    13339164 :                 energySum += energy[j][k];
    1123             :             }
    1124             : 
    1125     3334791 :             if ( computeCoherence )
    1126             :             {
    1127     2065926 :                 surrCohSum = 0.0f;
    1128    10329630 :                 for ( j = 0; j < numSf; j++ )
    1129             :                 {
    1130     8263704 :                     surrCohSum += energy[j][k] * hMeta->common_meta.surround_coherence[j][k];
    1131             :                 }
    1132     2065926 :                 surrCohTemp = surrCohSum / ( energySum + EPSILON );
    1133             : 
    1134    10329630 :                 for ( j = 0; j < numSf; j++ )
    1135             :                 {
    1136     8263704 :                     hMeta->common_meta.surround_coherence[j][k] = surrCohTemp;
    1137             :                 }
    1138             :             }
    1139             : 
    1140     7829581 :             for ( i = 0; i < numDirections; i++ )
    1141             :             {
    1142     4494790 :                 energyRatioSum = 0.0f;
    1143    22473950 :                 for ( j = 0; j < numSf; j++ )
    1144             :                 {
    1145    17979160 :                     energyRatioSum += energy[j][k] * hMeta->directional_meta[i].energy_ratio[j][k];
    1146             :                 }
    1147     4494790 :                 energyRatioTemp = energyRatioSum / ( energySum + EPSILON );
    1148             : 
    1149    22473950 :                 for ( j = 0; j < numSf; j++ )
    1150             :                 {
    1151    17979160 :                     hMeta->directional_meta[i].energy_ratio[j][k] = energyRatioTemp;
    1152             :                 }
    1153             :             }
    1154             :         }
    1155             :     }
    1156             : 
    1157      838032 :     return;
    1158             : }
    1159             : 
    1160             : 
    1161             : /*-------------------------------------------------------------------*
    1162             :  * ivas_masa_combine_directions()
    1163             :  *
    1164             :  *
    1165             :  *-------------------------------------------------------------------*/
    1166             : 
    1167      320741 : 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      320741 :     numCodingBands = hMasa->config.numCodingBands;
    1199      320741 :     numDirections = hMasa->config.numberOfDirections;
    1200      320741 :     numSf = hMasa->config.joinedSubframes == TRUE ? 1 : MAX_PARAM_SPATIAL_SUBFRAMES;
    1201             : 
    1202      320741 :     hMeta = &( hMasa->masaMetadata );
    1203             : 
    1204      320741 :     computeCoherence = hMasa->config.useCoherence && hMasa->config.coherencePresent;
    1205             : 
    1206      962223 :     for ( i = 0; i < numDirections; i++ )
    1207             :     {
    1208     2480204 :         for ( j = 0; j < numSf; j++ )
    1209             :         {
    1210    21518250 :             for ( k = 0; k < numCodingBands; k++ )
    1211             :             {
    1212    19679528 :                 aziRad = hMeta->directional_meta[i].azimuth[j][k] / 180.0f * EVS_PI;
    1213    19679528 :                 eleRad = hMeta->directional_meta[i].elevation[j][k] / 180.0f * EVS_PI;
    1214    19679528 :                 vecLen = hMeta->directional_meta[i].energy_ratio[j][k];
    1215             : 
    1216    19679528 :                 x[i][j][k] = cosf( aziRad ) * cosf( eleRad ) * vecLen;
    1217    19679528 :                 y[i][j][k] = sinf( aziRad ) * cosf( eleRad ) * vecLen;
    1218    19679528 :                 z[i][j][k] = sinf( eleRad ) * vecLen;
    1219             :             }
    1220             :         }
    1221             :     }
    1222             : 
    1223             :     /* Compute sum vector */
    1224     1240102 :     for ( j = 0; j < numSf; j++ )
    1225             :     {
    1226    10759125 :         for ( k = 0; k < numCodingBands; k++ )
    1227             :         {
    1228     9839764 :             xSum[j][k] = x[0][j][k] + x[1][j][k];
    1229     9839764 :             ySum[j][k] = y[0][j][k] + y[1][j][k];
    1230     9839764 :             zSum[j][k] = z[0][j][k] + z[1][j][k];
    1231     9839764 :             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      320741 :     if ( hMasa->config.numTwoDirBands > 0 )
    1236             :     {
    1237             :         /* Estimate the importance of having two directions instead of one */
    1238     1840997 :         for ( i = 0; i < numCodingBands; i++ )
    1239             :         {
    1240     1693916 :             importance[i] = 0.0f;
    1241     5901202 :             for ( j = 0; j < numSf; j++ )
    1242             :             {
    1243     4207286 :                 tempImportance = hMeta->directional_meta[0].energy_ratio[j][i] + hMeta->directional_meta[1].energy_ratio[j][i] - sumVecLen[j][i];
    1244     4207286 :                 importance[i] += tempImportance;
    1245             :             }
    1246     1693916 :             importance[i] /= (float) numSf;
    1247     1693916 :             importance[i] *= hMasa->data.importanceWeight[i];
    1248             :         }
    1249             : 
    1250             :         /* Determine bands where to use two directions */
    1251      147081 :         find_n_largest( importance, indicesOfLargest, numCodingBands, hMasa->config.numTwoDirBands );
    1252             :     }
    1253             : 
    1254     4085760 :     for ( i = 0; i < numCodingBands; i++ )
    1255             :     {
    1256     3765019 :         hMasa->data.twoDirBands[i] = 0;
    1257             :     }
    1258             : 
    1259      894195 :     for ( i = 0; i < hMasa->config.numTwoDirBands; i++ )
    1260             :     {
    1261      573454 :         hMasa->data.twoDirBands[indicesOfLargest[i]] = 1;
    1262             :     }
    1263             : 
    1264             :     /* Combine directions on the remaining bands */
    1265     4085760 :     for ( i = 0; i < numCodingBands; i++ )
    1266             :     {
    1267     3765019 :         if ( hMasa->data.twoDirBands[i] == 0 )
    1268             :         {
    1269    11542320 :             for ( j = 0; j < numSf; j++ )
    1270             :             {
    1271     8350755 :                 aziRad = atan2f( ySum[j][i], xSum[j][i] );
    1272     8350755 :                 eleRad = atan2f( zSum[j][i], sqrtf( xSum[j][i] * xSum[j][i] + ySum[j][i] * ySum[j][i] ) );
    1273             : 
    1274     8350755 :                 hMeta->directional_meta[0].azimuth[j][i] = aziRad / EVS_PI * 180.0f;
    1275     8350755 :                 hMeta->directional_meta[0].elevation[j][i] = eleRad / EVS_PI * 180.0f;
    1276             : 
    1277     8350755 :                 ratioSum = hMeta->directional_meta[0].energy_ratio[j][i] + hMeta->directional_meta[1].energy_ratio[j][i];
    1278     8350755 :                 if ( computeCoherence )
    1279             :                 {
    1280     3066005 :                     hMeta->directional_meta[0].spread_coherence[j][i] =
    1281     3066005 :                         ( 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 );
    1282             :                 }
    1283             : 
    1284     8350755 :                 ambience2dir = 1.0f - ratioSum;
    1285     8350755 :                 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 );
    1286     8350755 :                 hMeta->directional_meta[1].energy_ratio[j][i] = 0.0f;
    1287     8350755 :                 hMeta->common_meta.diffuse_to_total_ratio[j][i] = 1.0f - hMeta->directional_meta[0].energy_ratio[j][i];
    1288     8350755 :                 if ( computeCoherence )
    1289             :                 {
    1290     3066005 :                     ambience1dir = 1.0f - hMeta->directional_meta[0].energy_ratio[j][i];
    1291     3066005 :                     ambienceIncrease = max( ambience1dir - ambience2dir, 0.0f );
    1292             : 
    1293     3066005 :                     origSurrCohEne = ambience2dir * hMeta->common_meta.surround_coherence[j][i];
    1294     3066005 :                     newSurrCohEne = ambienceIncrease * hMeta->directional_meta[0].spread_coherence[j][i];
    1295     3066005 :                     hMeta->common_meta.surround_coherence[j][i] = min( 1.0f, ( origSurrCohEne + newSurrCohEne ) / ( ambience1dir + EPSILON ) );
    1296             :                 }
    1297             :             }
    1298             :         }
    1299             :     }
    1300             : 
    1301      320741 :     return;
    1302             : }
    1303             : 
    1304             : 
    1305      147081 : static void find_n_largest(
    1306             :     const float *input,
    1307             :     int16_t *largestIndices,
    1308             :     const int16_t numElements,
    1309             :     const int16_t numLargest )
    1310             : {
    1311             :     int16_t i, j;
    1312             :     float largestValue;
    1313             :     int16_t largestIndex;
    1314             :     float values[MASA_FREQUENCY_BANDS];
    1315             : 
    1316     1840997 :     for ( j = 0; j < numElements; j++ )
    1317             :     {
    1318     1693916 :         values[j] = input[j];
    1319             :     }
    1320             : 
    1321      720535 :     for ( i = 0; i < numLargest; i++ )
    1322             :     {
    1323      573454 :         largestValue = values[0];
    1324      573454 :         largestIndex = 0;
    1325     8896456 :         for ( j = 1; j < numElements; j++ )
    1326             :         {
    1327     8323002 :             if ( values[j] > largestValue )
    1328             :             {
    1329     1205266 :                 largestValue = values[j];
    1330     1205266 :                 largestIndex = j;
    1331             :             }
    1332             :         }
    1333      573454 :         largestIndices[i] = largestIndex;
    1334      573454 :         values[largestIndex] = -1.0f;
    1335             :     }
    1336             : 
    1337      147081 :     return;
    1338             : }
    1339             : 
    1340             : 
    1341      838032 : static void move_metadata_to_qmetadata(
    1342             :     const MASA_ENCODER_HANDLE hMasa,
    1343             :     IVAS_QMETADATA_HANDLE hQMeta )
    1344             : {
    1345             :     int16_t dir, sf, band;
    1346             :     uint8_t numCodingBands;
    1347             :     uint8_t numDirections;
    1348             :     uint8_t numSf;
    1349             :     MASA_METADATA_HANDLE hMeta;
    1350             : 
    1351      838032 :     numCodingBands = hMasa->config.numCodingBands;
    1352      838032 :     numDirections = hMasa->config.numberOfDirections;
    1353      838032 :     numSf = hMasa->config.joinedSubframes == TRUE ? 1 : MAX_PARAM_SPATIAL_SUBFRAMES;
    1354      838032 :     hMeta = &( hMasa->masaMetadata );
    1355             : 
    1356     1831695 :     for ( dir = 0; dir < numDirections; dir++ )
    1357             :     {
    1358     3879975 :         for ( sf = 0; sf < numSf; sf++ )
    1359             :         {
    1360    28825971 :             for ( band = 0; band < numCodingBands; band++ )
    1361             :             {
    1362    25939659 :                 hQMeta->q_direction[dir].band_data[band].azimuth[sf] = hMeta->directional_meta[dir].azimuth[sf][band];
    1363    25939659 :                 hQMeta->q_direction[dir].band_data[band].elevation[sf] = hMeta->directional_meta[dir].elevation[sf][band];
    1364    25939659 :                 hQMeta->q_direction[dir].band_data[band].energy_ratio[sf] = hMeta->directional_meta[dir].energy_ratio[sf][band];
    1365    25939659 :                 hQMeta->q_direction[dir].band_data[band].spherical_index[sf] = hMeta->directional_meta[dir].spherical_index[sf][band];
    1366    25939659 :                 if ( hQMeta->q_direction[dir].coherence_band_data != NULL )
    1367             :                 {
    1368    20738898 :                     hQMeta->q_direction[dir].coherence_band_data[band].spread_coherence[sf] = (uint8_t) roundf( hMeta->directional_meta[dir].spread_coherence[sf][band] * UINT8_MAX );
    1369             :                 }
    1370             :             }
    1371             :         }
    1372             :     }
    1373             : 
    1374     3274425 :     for ( sf = 0; sf < numSf; sf++ )
    1375             :     {
    1376    23675895 :         for ( band = 0; band < numCodingBands; band++ )
    1377             :         {
    1378    21239502 :             if ( hQMeta->surcoh_band_data != NULL )
    1379             :             {
    1380    16038741 :                 hQMeta->surcoh_band_data[band].surround_coherence[sf] = (uint8_t) roundf( hMeta->common_meta.surround_coherence[sf][band] * UINT8_MAX );
    1381             :             }
    1382             :         }
    1383             :     }
    1384             : 
    1385      838032 :     if ( numDirections > 1 )
    1386             :     {
    1387     2018493 :         for ( band = 0; band < numCodingBands; band++ )
    1388             :         {
    1389     1862862 :             hQMeta->twoDirBands[band] = hMasa->data.twoDirBands[band];
    1390             :         }
    1391      155631 :         hQMeta->numTwoDirBands = hMasa->config.numTwoDirBands;
    1392             :     }
    1393             : 
    1394             :     /* Copy spread coherence for DCT-based coding */
    1395      838032 :     if ( numSf == 1 && hMasa->config.useCoherence )
    1396             :     {
    1397      400221 :         for ( dir = 0; dir < numDirections; dir++ )
    1398             :         {
    1399      915512 :             for ( sf = 1; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1400             :             {
    1401    11664048 :                 for ( band = 0; band < numCodingBands; band++ )
    1402             :                 {
    1403    10977414 :                     hQMeta->q_direction[dir].coherence_band_data[band].spread_coherence[sf] = hQMeta->q_direction[dir].coherence_band_data[band].spread_coherence[0];
    1404             :                 }
    1405             :             }
    1406             :         }
    1407             :     }
    1408             : 
    1409      838032 :     return;
    1410             : }
    1411             : 
    1412             : 
    1413             : /* This function studies parametric MASA metadata to provide information for codec configuration */
    1414      818385 : static void detect_metadata_composition(
    1415             :     const MASA_ENCODER_HANDLE hMasa, /* i  : MASA encoder data              */
    1416             :     uint8_t *joinedSubframes,        /* o  : Result of subframe composition */
    1417             :     uint8_t *coherencePresent,       /* o  : Result of coherence presence   */
    1418             :     uint8_t *isTwoDir                /* o  : Result of two direction check  */
    1419             : )
    1420             : {
    1421             :     MASA_METADATA_FRAME *hMeta;
    1422             :     int8_t sf, band, dir, numDir;
    1423             :     int16_t nSubFrames;
    1424      818385 :     uint8_t dirValid[2] = { FALSE, FALSE };
    1425      818385 :     uint8_t cohPresent = FALSE;
    1426      818385 :     uint8_t sfDiffer = FALSE;
    1427             :     uint8_t sfSimilar;
    1428             : 
    1429      818385 :     hMeta = &( hMasa->masaMetadata );
    1430      818385 :     numDir = hMeta->descriptive_meta.numberOfDirections + 1;
    1431             : 
    1432      818385 :     *isTwoDir = FALSE;
    1433             : 
    1434             :     /* First check for valid two directions */
    1435      818385 :     if ( numDir == 1 )
    1436             :     {
    1437      487799 :         dirValid[0] = TRUE;
    1438             :     }
    1439             :     else
    1440             :     {
    1441             :         /* Default assumption */
    1442      330586 :         *isTwoDir = TRUE;
    1443             : 
    1444             :         /* Check for direct-to-total ratio values */
    1445      991758 :         for ( dir = 0; dir < numDir; dir++ )
    1446             :         {
    1447      661172 :             sf = 0;
    1448     1343566 :             while ( !dirValid[dir] && sf < MAX_PARAM_SPATIAL_SUBFRAMES )
    1449             :             {
    1450      682394 :                 band = 0;
    1451     2156068 :                 while ( !dirValid[dir] && band < MASA_FREQUENCY_BANDS )
    1452             :                 {
    1453     1473674 :                     if ( hMeta->directional_meta[dir].energy_ratio[sf][band] >= MASA_RATIO_THRESHOLD )
    1454             :                     {
    1455      654504 :                         dirValid[dir] = TRUE;
    1456             :                     }
    1457     1473674 :                     band++;
    1458             :                 }
    1459      682394 :                 sf++;
    1460             :             }
    1461             :         }
    1462             : 
    1463      330586 :         if ( dirValid[1] == FALSE )
    1464             :         {
    1465             :             /* This handles also case where both are false. Then we just use first dir metadata. */
    1466        5204 :             *isTwoDir = FALSE;
    1467             :         }
    1468      325382 :         else if ( dirValid[0] == FALSE && dirValid[1] == TRUE )
    1469             :         {
    1470           0 :             *isTwoDir = FALSE;
    1471             :             /* Copy data to first direction */
    1472           0 :             for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1473             :             {
    1474           0 :                 for ( band = 0; band < MASA_FREQUENCY_BANDS; band++ )
    1475             :                 {
    1476           0 :                     hMeta->directional_meta[0].spherical_index[sf][band] = hMeta->directional_meta[1].spherical_index[sf][band];
    1477           0 :                     hMeta->directional_meta[0].azimuth[sf][band] = hMeta->directional_meta[1].azimuth[sf][band];
    1478           0 :                     hMeta->directional_meta[0].elevation[sf][band] = hMeta->directional_meta[1].elevation[sf][band];
    1479           0 :                     hMeta->directional_meta[0].energy_ratio[sf][band] = hMeta->directional_meta[1].energy_ratio[sf][band];
    1480           0 :                     hMeta->directional_meta[0].spread_coherence[sf][band] = hMeta->directional_meta[1].spread_coherence[sf][band];
    1481             :                 }
    1482             :             }
    1483             :         }
    1484             : 
    1485      330586 :         if ( *isTwoDir == FALSE )
    1486             :         {
    1487             :             /* Further checks will be done with just one direction */
    1488        5204 :             numDir = 1;
    1489             :         }
    1490             :     }
    1491             : 
    1492             :     /* Check if data over subframes is identical. Check is done by comparing to first subframe. */
    1493      818385 :     sfSimilar = TRUE;
    1494      818385 :     sf = 1;
    1495     2407859 :     while ( ( sfSimilar == TRUE ) && ( sf < MAX_PARAM_SPATIAL_SUBFRAMES ) )
    1496             :     {
    1497     1589474 :         sfSimilar = are_masa_subframes_similar( hMeta, 0, hMeta, sf );
    1498     1589474 :         sf++;
    1499             :     }
    1500      818385 :     sfDiffer = sfSimilar == TRUE ? FALSE : TRUE;
    1501             : 
    1502             :     /* Further checks can be done with just one subframe if they are identical */
    1503      818385 :     nSubFrames = sfDiffer == TRUE ? MAX_PARAM_SPATIAL_SUBFRAMES : 1;
    1504             : 
    1505             :     /* Check spread coherence */
    1506      818385 :     dir = 0;
    1507     1652867 :     while ( cohPresent == FALSE && dir < numDir )
    1508             :     {
    1509      834482 :         sf = 0;
    1510     1824553 :         while ( cohPresent == FALSE && sf < nSubFrames )
    1511             :         {
    1512      990071 :             band = 0;
    1513    10554073 :             while ( cohPresent == FALSE && band < MASA_FREQUENCY_BANDS )
    1514             :             {
    1515             :                 /* Check coherences for presence of coherence */
    1516     9564002 :                 if ( hMeta->directional_meta[dir].spread_coherence[sf][band] >= MASA_COHERENCE_THRESHOLD )
    1517             :                 {
    1518      719916 :                     cohPresent = TRUE;
    1519             :                 }
    1520     9564002 :                 band++;
    1521             :             }
    1522      990071 :             sf++;
    1523             :         }
    1524      834482 :         dir++;
    1525             :     }
    1526             : 
    1527             :     /* Check surround coherence separately if we do not have already knowledge of coherence */
    1528      818385 :     if ( cohPresent == FALSE )
    1529             :     {
    1530       98469 :         cohPresent = ivas_masa_surrcoh_signicant( hMeta->common_meta.surround_coherence, hMeta->common_meta.diffuse_to_total_ratio, nSubFrames, MASA_FREQUENCY_BANDS );
    1531             :     }
    1532             : 
    1533             :     /* Set output flags */
    1534      818385 :     *joinedSubframes = sfDiffer == TRUE ? FALSE : TRUE;
    1535      818385 :     *coherencePresent = cohPresent;
    1536             : 
    1537      818385 :     return;
    1538             : }
    1539             : 
    1540             : 
    1541             : /* Check and compensate energy ratios. This function verifies that energy ratios follow the principle of summing to one.
    1542             :  * In addition, it implements simple remainder-to-total handling where remainder energy is proportionally added to other
    1543             :  * ratios. */
    1544      818385 : static void compensate_energy_ratios(
    1545             :     MASA_ENCODER_HANDLE hMasa )
    1546             : {
    1547             :     int16_t sf, band, dir;
    1548             :     float ratioSum;
    1549             :     MASA_METADATA_HANDLE hMeta;
    1550             :     uint8_t numDirs;
    1551             : 
    1552      818385 :     hMeta = &( hMasa->masaMetadata );
    1553      818385 :     numDirs = hMasa->config.numberOfDirections;
    1554             : 
    1555     4091925 :     for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1556             :     {
    1557    81838500 :         for ( band = 0; band < MASA_FREQUENCY_BANDS; band++ )
    1558             :         {
    1559             :             /* Remainder is always set to zero and energy removal is compensated in following steps
    1560             :              * to other ratios. */
    1561    78564960 :             hMeta->common_meta.remainder_to_total_ratio[sf][band] = 0.0f;
    1562             : 
    1563    78564960 :             ratioSum = 0;
    1564   188366592 :             for ( dir = 0; dir < numDirs; dir++ )
    1565             :             {
    1566   109801632 :                 ratioSum += hMeta->directional_meta[dir].energy_ratio[sf][band];
    1567             :             }
    1568    78564960 :             ratioSum += hMeta->common_meta.diffuse_to_total_ratio[sf][band];
    1569             : 
    1570    78564960 :             if ( ratioSum == 0.0f )
    1571             :             {
    1572           0 :                 for ( dir = 0; dir < numDirs; dir++ )
    1573             :                 {
    1574           0 :                     hMeta->directional_meta[dir].energy_ratio[sf][band] = 0.0f;
    1575             :                 }
    1576           0 :                 hMeta->common_meta.diffuse_to_total_ratio[sf][band] = 1.0f;
    1577             :             }
    1578    78564960 :             else if ( ratioSum != 1.0f )
    1579             :             {
    1580     6625488 :                 for ( dir = 0; dir < numDirs; dir++ )
    1581             :                 {
    1582     3887920 :                     hMeta->directional_meta[dir].energy_ratio[sf][band] /= ratioSum;
    1583             :                 }
    1584     2737568 :                 hMeta->common_meta.diffuse_to_total_ratio[sf][band] /= ratioSum;
    1585             :             }
    1586             :         }
    1587             :     }
    1588             : 
    1589      818385 :     return;
    1590             : }
    1591             : 
    1592             : 
    1593             : /* 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 */
    1594      292228 : static void reduce_metadata_further(
    1595             :     MASA_ENCODER_HANDLE hMasa,
    1596             :     IVAS_QMETADATA_HANDLE hqmetadata,
    1597             :     const IVAS_FORMAT ivas_format )
    1598             : {
    1599             :     int16_t sf;
    1600             :     int16_t band;
    1601             :     int16_t selectedBand;
    1602             :     float energy[MAX_PARAM_SPATIAL_SUBFRAMES][LOWBITRATE_NUM_BANDS];
    1603             :     float totalEnergySum;
    1604             :     uint8_t numCodingBands;
    1605             :     uint8_t computeCoherence;
    1606             :     float onset_filter;
    1607             :     float bandEnergy;
    1608             :     uint8_t mergeOverFreqBands;
    1609             :     float meanRatio;
    1610             : 
    1611      292228 :     numCodingBands = hMasa->config.numCodingBands;
    1612      292228 :     computeCoherence = hMasa->config.useCoherence && hMasa->config.coherencePresent;
    1613             : 
    1614             :     /* Set default values */
    1615      292228 :     selectedBand = 0;
    1616      292228 :     mergeOverFreqBands = 0;
    1617             : 
    1618             :     /* Get energy for the input data in 4-subframe, 5-band format */
    1619      292228 :     totalEnergySum = 0.0f;
    1620      292228 :     if ( ivas_format == MASA_FORMAT || ivas_format == MASA_ISM_FORMAT ) /* Energy data is in 4-subframe, 24-band format */
    1621             :     {
    1622     1084275 :         for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1623             :         {
    1624             :             int16_t brange[2];
    1625             :             float eneSum;
    1626             :             int16_t m;
    1627             : 
    1628     5204520 :             for ( band = 0; band < numCodingBands; band++ )
    1629             :             {
    1630     4337100 :                 brange[0] = hMasa->data.band_mapping[band];
    1631     4337100 :                 brange[1] = hMasa->data.band_mapping[band + 1];
    1632             : 
    1633     4337100 :                 eneSum = 0.0f;
    1634    24986228 :                 for ( m = brange[0]; m < brange[1]; m++ )
    1635             :                 {
    1636    20649128 :                     eneSum += hMasa->data.energy[sf][m];
    1637             :                 }
    1638     4337100 :                 energy[sf][band] = eneSum;
    1639     4337100 :                 totalEnergySum += eneSum;
    1640             :             }
    1641             :         }
    1642             :     }
    1643             :     else /* Energy data is already in 4-subframe, 5-band format */
    1644             :     {
    1645      376865 :         for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1646             :         {
    1647     1808952 :             for ( band = 0; band < numCodingBands; band++ )
    1648             :             {
    1649     1507460 :                 energy[sf][band] = hMasa->data.energy[sf][band];
    1650     1507460 :                 totalEnergySum += energy[sf][band];
    1651             :             }
    1652             :         }
    1653             :     }
    1654             : 
    1655             :     /* Determine onsets */
    1656      292228 :     hMasa->data.onset_detector_1 = hMasa->data.onset_detector_1 * LOWBITRATE_ONSET_ALPHA;
    1657      292228 :     hMasa->data.onset_detector_1 = max( hMasa->data.onset_detector_1, totalEnergySum );
    1658             : 
    1659      292228 :     hMasa->data.onset_detector_2 = LOWBITRATE_ONSET_BETA * hMasa->data.onset_detector_2 + ( 1.0f - LOWBITRATE_ONSET_BETA ) * hMasa->data.onset_detector_1;
    1660      292228 :     hMasa->data.onset_detector_2 = LOWBITRATE_ONSET_GAIN * min( hMasa->data.onset_detector_1, hMasa->data.onset_detector_2 );
    1661             : 
    1662      292228 :     onset_filter = min( max( hMasa->data.onset_detector_2 / ( hMasa->data.onset_detector_1 + EPSILON ), 0.0f ), 1.0f );
    1663             : 
    1664             :     /* If we have onset, continue checking if we should reduce in frequency instead of time. */
    1665      292228 :     if ( onset_filter < 0.99f )
    1666             :     {
    1667             :         /* Determine one frequency band to use to represent all frequency bands */
    1668      261389 :         for ( band = numCodingBands - 1; band >= 0; band-- )
    1669             :         {
    1670             :             float threshold;
    1671             :             float bandRatio;
    1672             : 
    1673      256381 :             threshold = totalEnergySum / ( MAX_PARAM_SPATIAL_SUBFRAMES * LOWBITRATE_NUM_BANDS ) * 0.5f; /* Average energy multiplied with energy ratio of 0.5f */
    1674      256381 :             bandRatio = hqmetadata->q_direction[0].band_data[band].energy_ratio[0];
    1675             : 
    1676      256381 :             bandEnergy = 0.0f;
    1677     1281905 :             for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1678             :             {
    1679     1025524 :                 bandEnergy += energy[sf][band];
    1680             :             }
    1681             : 
    1682      256381 :             if ( bandEnergy / MAX_PARAM_SPATIAL_SUBFRAMES * bandRatio > threshold )
    1683             :             {
    1684       60442 :                 selectedBand = band;
    1685       60442 :                 break;
    1686             :             }
    1687             :         }
    1688             : 
    1689             :         /* Determine if to merge over frequency instead of time */
    1690       65450 :         meanRatio = 0.0f;
    1691      327250 :         for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1692             :         {
    1693     1570800 :             for ( band = 0; band < numCodingBands; band++ )
    1694             :             {
    1695     1309000 :                 meanRatio += hqmetadata->q_direction[0].band_data[band].energy_ratio[sf] * energy[sf][band];
    1696             :             }
    1697             :         }
    1698       65450 :         meanRatio /= ( totalEnergySum + EPSILON );
    1699             : 
    1700             :         /* 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.
    1701             :          * Otherwise, merge over subframes. */
    1702       65450 :         if ( hqmetadata->q_direction[0].band_data[selectedBand].energy_ratio[0] > meanRatio )
    1703             :         {
    1704       44640 :             mergeOverFreqBands = 1;
    1705             :         }
    1706             :         else
    1707             :         {
    1708       20810 :             mergeOverFreqBands = 0;
    1709             :         }
    1710             :     }
    1711             :     else
    1712             :     {
    1713      226778 :         mergeOverFreqBands = 0;
    1714             :     }
    1715             : 
    1716             :     /* Merge values over subframes or frequency bands, depending on which one is less important */
    1717      292228 :     if ( !mergeOverFreqBands ) /* Merge values over subframes */
    1718             :     {
    1719             :         float xSum, ySum, zSum;
    1720             :         float bandSumEnergy;
    1721             :         float aziRad, eleRad;
    1722             :         float x, y, z;
    1723             :         float veclen;
    1724             : 
    1725     1485528 :         for ( band = 0; band < numCodingBands; band++ )
    1726             :         {
    1727     1237940 :             xSum = 0.0f;
    1728     1237940 :             ySum = 0.0f;
    1729     1237940 :             zSum = 0.0f;
    1730     1237940 :             bandSumEnergy = 0.0f;
    1731             : 
    1732     6189700 :             for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1733             :             {
    1734     4951760 :                 aziRad = hqmetadata->q_direction[0].band_data[band].azimuth[sf] / 180.0f * EVS_PI;
    1735     4951760 :                 eleRad = hqmetadata->q_direction[0].band_data[band].elevation[sf] / 180.0f * EVS_PI;
    1736     4951760 :                 veclen = hqmetadata->q_direction[0].band_data[band].energy_ratio[sf] * energy[sf][band];
    1737             : 
    1738     4951760 :                 x = cosf( aziRad ) * cosf( eleRad ) * veclen;
    1739     4951760 :                 y = sinf( aziRad ) * cosf( eleRad ) * veclen;
    1740     4951760 :                 z = sinf( eleRad ) * veclen;
    1741             : 
    1742     4951760 :                 xSum += x;
    1743     4951760 :                 ySum += y;
    1744     4951760 :                 zSum += z;
    1745             : 
    1746     4951760 :                 bandSumEnergy += energy[sf][band];
    1747             :             }
    1748             : 
    1749     1237940 :             aziRad = atan2f( ySum, xSum );
    1750     1237940 :             eleRad = atan2f( zSum, sqrtf( xSum * xSum + ySum * ySum ) );
    1751             : 
    1752     1237940 :             hqmetadata->q_direction[0].band_data[band].azimuth[0] = aziRad / EVS_PI * 180.0f;
    1753     1237940 :             hqmetadata->q_direction[0].band_data[band].elevation[0] = eleRad / EVS_PI * 180.0f;
    1754             : 
    1755             :             /* Energy ratio is already merged through time */
    1756             : 
    1757     1237940 :             if ( computeCoherence && hqmetadata->q_direction[0].coherence_band_data != NULL )
    1758             :             {
    1759             :                 float spreadCoh;
    1760      240165 :                 float spreadCohSum = 0.0f;
    1761     1200825 :                 for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1762             :                 {
    1763      960660 :                     spreadCoh = (float) hqmetadata->q_direction[0].coherence_band_data[band].spread_coherence[sf] / 255.0f;
    1764      960660 :                     spreadCohSum += spreadCoh * energy[sf][band];
    1765             :                 }
    1766      240165 :                 hqmetadata->q_direction[0].coherence_band_data[band].spread_coherence[0] = (uint8_t) roundf( spreadCohSum / ( bandSumEnergy + EPSILON ) * 255.0f );
    1767             : 
    1768             :                 /* Copy spread coherence to the rest of subframes for the coherence coding algorithm. */
    1769      960660 :                 for ( sf = 1; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1770             :                 {
    1771      720495 :                     hqmetadata->q_direction[0].coherence_band_data[band].spread_coherence[sf] = hqmetadata->q_direction[0].coherence_band_data[band].spread_coherence[0];
    1772             :                 }
    1773             : 
    1774             :                 /* Surround coherence is already merged through time */
    1775             :             }
    1776             :         }
    1777             : 
    1778      247588 :         hqmetadata->q_direction->cfg.nblocks = 1;
    1779      247588 :         hMasa->config.joinedSubframes = 1;
    1780             :     }
    1781             :     else /* Merge values over frequency bands */
    1782             :     {
    1783             :         /* Use the selected frequency band to represent all data */
    1784      223200 :         for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1785             :         {
    1786      178560 :             hqmetadata->q_direction[0].band_data[0].azimuth[sf] = hqmetadata->q_direction[0].band_data[selectedBand].azimuth[sf];
    1787      178560 :             hqmetadata->q_direction[0].band_data[0].elevation[sf] = hqmetadata->q_direction[0].band_data[selectedBand].elevation[sf];
    1788      178560 :             hqmetadata->q_direction[0].band_data[0].energy_ratio[sf] = hqmetadata->q_direction[0].band_data[selectedBand].energy_ratio[sf];
    1789      178560 :             if ( hqmetadata->q_direction[0].coherence_band_data != NULL )
    1790             :             {
    1791       56604 :                 hqmetadata->q_direction[0].coherence_band_data[0].spread_coherence[sf] = hqmetadata->q_direction[0].coherence_band_data[selectedBand].spread_coherence[sf];
    1792             :             }
    1793      178560 :             if ( hqmetadata->surcoh_band_data != NULL )
    1794             :             {
    1795       56604 :                 hqmetadata->surcoh_band_data[0].surround_coherence[sf] = hqmetadata->surcoh_band_data[selectedBand].surround_coherence[sf];
    1796             :             }
    1797             :         }
    1798             : 
    1799             :         /* Copy coherence to rest of bands for the coherence coding algorithm. */
    1800      223200 :         for ( band = 1; band < numCodingBands; band++ )
    1801             :         {
    1802      178560 :             if ( hqmetadata->q_direction[0].coherence_band_data != NULL )
    1803             :             {
    1804      283020 :                 for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1805             :                 {
    1806      226416 :                     hqmetadata->q_direction[0].coherence_band_data[band].spread_coherence[sf] = hqmetadata->q_direction[0].coherence_band_data[0].spread_coherence[sf];
    1807             :                 }
    1808             :             }
    1809      178560 :             if ( hqmetadata->q_direction[0].coherence_band_data != NULL )
    1810             :             {
    1811      283020 :                 for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1812             :                 {
    1813      226416 :                     hqmetadata->surcoh_band_data[band].surround_coherence[sf] = hqmetadata->surcoh_band_data[0].surround_coherence[sf];
    1814             :                 }
    1815             :             }
    1816             :         }
    1817             : 
    1818       44640 :         hqmetadata->q_direction[0].cfg.nbands = 1;
    1819             :     }
    1820             : 
    1821      292228 :     return;
    1822             : }
    1823             : 
    1824             : 
    1825      166560 : static int16_t encode_lfe_to_total_energy_ratio(
    1826             :     MASA_ENCODER_HANDLE hMasa,     /* i/o: MASA encoder structure       */
    1827             :     BSTR_ENC_HANDLE hMetaData,     /* i/o: Metadata bitstream handle    */
    1828             :     const int32_t ivas_total_brate /* i  : IVAS total bitrate           */
    1829             : )
    1830             : {
    1831             :     int16_t i;
    1832             :     float xq;
    1833             :     int16_t VQLevels;
    1834             :     float maxLFESubFrameEner;
    1835             :     float log2LFEaverage;
    1836             :     float log2LFEratio[4];
    1837             :     float xqv[4];
    1838             :     float linearLFEaverage;
    1839             :     int16_t lfeToTotalEnergyRatioIndices[3];
    1840             :     int16_t lfeAdaptiveVQBits;
    1841             :     int16_t lfeBitsWritten;
    1842             : 
    1843      166560 :     VQLevels = 0;
    1844      166560 :     lfeAdaptiveVQBits = 0;
    1845             : 
    1846             :     /* Determine maximum amount of LFE energy in any subframe */
    1847      166560 :     maxLFESubFrameEner = 0.0f;
    1848      832800 :     for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ )
    1849             :     {
    1850      666240 :         if ( hMasa->data.lfeToTotalEnergyRatio[i] > maxLFESubFrameEner )
    1851             :         {
    1852      352604 :             maxLFESubFrameEner = hMasa->data.lfeToTotalEnergyRatio[i];
    1853             :         }
    1854             :     }
    1855             : 
    1856             :     /* Set default values for the indices */
    1857      666240 :     for ( i = 0; i < 3; i++ )
    1858             :     {
    1859      499680 :         lfeToTotalEnergyRatioIndices[i] = 0;
    1860             :     }
    1861             : 
    1862             :     /* Check if there is enough energy in any subframe. If not, send only 1 bit (0) and abort. */
    1863             :     /* If there is enough LFE energy at least in one subframe, quantize it. */
    1864      166560 :     if ( maxLFESubFrameEner > 0.005f )
    1865             :     {
    1866             :         /* Convert energy to log2 domain, and clamp it to reasonable values */
    1867      157480 :         log2LFEaverage = 0.0f;
    1868      787400 :         for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ )
    1869             :         {
    1870      629920 :             log2LFEratio[i] = log2f( max( 0.001f, hMasa->data.lfeToTotalEnergyRatio[i] ) );
    1871      629920 :             if ( log2LFEratio[i] > 1.0f ) /* Corresponds to linear value 2.0f */
    1872             :             {
    1873           0 :                 log2LFEratio[i] = 1.0f;
    1874             :             }
    1875      629920 :             else if ( log2LFEratio[i] < -9.0f )
    1876             :             {
    1877       23924 :                 log2LFEratio[i] = -9.0f;
    1878             :             }
    1879      629920 :             log2LFEaverage += 0.25f * log2LFEratio[i];
    1880             :         }
    1881             : 
    1882      157480 :         if ( ivas_total_brate == IVAS_13k2 )
    1883             :         {
    1884             :             /* Calculate adaptive 1-bit LFE quantizer index */
    1885       12199 :             linearLFEaverage = exp2f( log2LFEaverage ); /* Convert back to linear domain */
    1886       12199 :             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 ) ) ) )
    1887             :             {
    1888        4607 :                 lfeToTotalEnergyRatioIndices[0] = 1;
    1889        4607 :                 if ( hMasa->data.prevq_lfeIndex == 1 )
    1890             :                 {
    1891        1900 :                     hMasa->data.prevq_lfeToTotalEnergyRatio = hMasa->data.prevq_lfeToTotalEnergyRatio + MCMASA_LFE_THETA * MCMASA_LFE_BETA; /* larger "bump-up" to LFE-to-total energy ratio */
    1892             :                 }
    1893             :                 else
    1894             :                 {
    1895        2707 :                     hMasa->data.prevq_lfeToTotalEnergyRatio = hMasa->data.prevq_lfeToTotalEnergyRatio + MCMASA_LFE_BETA; /* default "bump-up" to LFE-to-total energy ratio */
    1896             :                 }
    1897             :             }
    1898             :             else
    1899             :             {
    1900        7592 :                 hMasa->data.prevq_lfeToTotalEnergyRatio = MCMASA_LFE_ALPHA * hMasa->data.prevq_lfeToTotalEnergyRatio; /* exponential decay */
    1901             :             }
    1902             : 
    1903       12199 :             if ( hMasa->data.prevq_lfeToTotalEnergyRatio > 1.0f )
    1904             :             {
    1905           4 :                 hMasa->data.prevq_lfeToTotalEnergyRatio = 1.0f;
    1906             :             }
    1907       12199 :             hMasa->data.prevq_lfeIndex = lfeToTotalEnergyRatioIndices[0]; /* Update to previous frame's index memories */
    1908             :         }
    1909             :         else /* Bitrate >= 16.4 kbps */
    1910             :         {
    1911             :             /* Do 1st stage scalar quantization */
    1912      145281 :             lfeToTotalEnergyRatioIndices[0] = 1;
    1913      145281 :             lfeToTotalEnergyRatioIndices[1] = usquant( log2LFEaverage, &xq, MCMASA_LFE_QLOW, MCMASA_LFE_DELTA, 8 );
    1914             : 
    1915      145281 :             if ( ivas_total_brate >= IVAS_24k4 ) /* Vector quantization is applied if bitrate >= 24.4 kbps */
    1916             :             {
    1917             :                 /* Remove scalar value from the vector*/
    1918      706300 :                 for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ )
    1919             :                 {
    1920      565040 :                     log2LFEratio[i] -= xq;
    1921             :                 }
    1922             : 
    1923             :                 /* Vector quantize residual with energy adaptive bit allocation */
    1924      141260 :                 switch ( lfeToTotalEnergyRatioIndices[1] )
    1925             :                 {
    1926       29851 :                     case 0:
    1927             :                     case 1:
    1928       29851 :                         VQLevels = 0;
    1929       29851 :                         lfeAdaptiveVQBits = 0;
    1930       29851 :                         break;
    1931       14839 :                     case 2:
    1932       14839 :                         VQLevels = 2;
    1933       14839 :                         lfeAdaptiveVQBits = 1;
    1934       14839 :                         break;
    1935       18731 :                     case 3:
    1936       18731 :                         VQLevels = 4;
    1937       18731 :                         lfeAdaptiveVQBits = 2;
    1938       18731 :                         break;
    1939       21845 :                     case 4:
    1940       21845 :                         VQLevels = 8;
    1941       21845 :                         lfeAdaptiveVQBits = 3;
    1942       21845 :                         break;
    1943       55994 :                     default:
    1944       55994 :                         VQLevels = 16;
    1945       55994 :                         lfeAdaptiveVQBits = 4;
    1946             :                 }
    1947             : 
    1948      141260 :                 if ( VQLevels > 0 )
    1949             :                 {
    1950      111409 :                     lfeToTotalEnergyRatioIndices[2] = vquant( log2LFEratio, 0, xqv, McMASA_LFEGain_vectors, 4, VQLevels );
    1951             :                 }
    1952             :             }
    1953             :         }
    1954             :     }
    1955             : 
    1956             :     /* Write first LFE bit */
    1957      166560 :     lfeBitsWritten = 0;
    1958      166560 :     push_next_indice( hMetaData, lfeToTotalEnergyRatioIndices[0], 1 );
    1959      166560 :     lfeBitsWritten += 1;
    1960             : 
    1961      166560 :     if ( lfeToTotalEnergyRatioIndices[0] == 1 && ivas_total_brate >= IVAS_16k4 )
    1962             :     {
    1963             :         /* If bitrate >= 16.4kbit/s, send 1-bit on/off + 3-bit scalar */
    1964      145281 :         push_next_indice( hMetaData, lfeToTotalEnergyRatioIndices[1], 3 );
    1965      145281 :         lfeBitsWritten += 3;
    1966             : 
    1967             :         /*  If bitrate >= 24.4kbit/s, use adaptive 1 + (3.. 7) bit quantizer */
    1968      145281 :         if ( ivas_total_brate >= IVAS_24k4 )
    1969             :         {
    1970             :             /* Vector quantize residual with energy adaptive bit allocation */
    1971      141260 :             if ( lfeAdaptiveVQBits > 0 )
    1972             :             {
    1973      111409 :                 push_next_indice( hMetaData, lfeToTotalEnergyRatioIndices[2], lfeAdaptiveVQBits );
    1974      111409 :                 lfeBitsWritten += lfeAdaptiveVQBits;
    1975             :             }
    1976             :         }
    1977             :     }
    1978             : 
    1979      166560 :     return lfeBitsWritten;
    1980             : }
    1981             : 
    1982             : 
    1983             : /*-------------------------------------------------------------------*
    1984             :  * ivas_masa_enc_reconfigure()
    1985             :  *
    1986             :  * Reconfigure IVAS MASA encoder
    1987             :  *-------------------------------------------------------------------*/
    1988             : 
    1989      554385 : void ivas_masa_enc_reconfigure(
    1990             :     Encoder_Struct *st_ivas /* i/o: IVAS encoder structure */
    1991             : )
    1992             : {
    1993             :     int16_t n, tmp;
    1994             :     int16_t sce_id, cpe_id;
    1995             :     int32_t ivas_total_brate;
    1996             :     int32_t ism_total_brate;
    1997             : 
    1998      554385 :     ivas_total_brate = st_ivas->hEncoderConfig->ivas_total_brate;
    1999             : 
    2000      554385 :     ism_total_brate = 0;
    2001      554385 :     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 ) )
    2002             :     {
    2003           0 :         for ( sce_id = 0; sce_id < st_ivas->nSCE; sce_id++ )
    2004             :         {
    2005           0 :             ism_total_brate += st_ivas->hSCE[sce_id]->element_brate;
    2006             :         }
    2007             :     }
    2008             : 
    2009      554385 :     if ( ivas_total_brate != st_ivas->hEncoderConfig->last_ivas_total_brate )
    2010             :     {
    2011       16330 :         for ( sce_id = 0; sce_id < st_ivas->nSCE; sce_id++ )
    2012             :         {
    2013        4913 :             copy_encoder_config( st_ivas, st_ivas->hSCE[sce_id]->hCoreCoder[0], 0 );
    2014        4913 :             st_ivas->hSCE[sce_id]->element_brate = ivas_total_brate / st_ivas->nchan_transport;
    2015        4913 :             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() */
    2016             :         }
    2017             : 
    2018       17921 :         for ( cpe_id = 0; cpe_id < st_ivas->nCPE; cpe_id++ )
    2019             :         {
    2020        6504 :             st_ivas->hCPE[cpe_id]->element_brate = ( ivas_total_brate / st_ivas->nchan_transport ) * CPE_CHANNELS;
    2021             : 
    2022             :             /* prepare bitstream buffers */
    2023       19512 :             for ( n = 0; n < CPE_CHANNELS; n++ )
    2024             :             {
    2025       13008 :                 copy_encoder_config( st_ivas, st_ivas->hCPE[cpe_id]->hCoreCoder[n], 0 );
    2026       13008 :                 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() */
    2027             :             }
    2028             : 
    2029        6504 :             if ( ivas_total_brate - ism_total_brate < MIN_BRATE_MDCT_STEREO )
    2030             :             {
    2031        1896 :                 st_ivas->hCPE[cpe_id]->element_mode = IVAS_CPE_DFT;
    2032             :             }
    2033             :             else
    2034             :             {
    2035        4608 :                 st_ivas->hCPE[cpe_id]->element_mode = IVAS_CPE_MDCT;
    2036             :             }
    2037             :         }
    2038             : 
    2039       11417 :         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 );
    2040             :     }
    2041             : 
    2042      554385 :     return;
    2043             : }
    2044             : 
    2045             : 
    2046             : /*-------------------------------------------------------------------*
    2047             :  * average_masa_metadata()
    2048             :  *
    2049             :  * Average MASA metadata frame subframe contents: applies aggregation over time
    2050             :  *-------------------------------------------------------------------*/
    2051             : 
    2052      109833 : static void average_masa_metadata(
    2053             :     MASA_METADATA_FRAME *hMeta,
    2054             :     float energy[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS],
    2055             :     const SPHERICAL_GRID_DATA *Sph_Grid16,
    2056             :     const uint8_t useSphGrid )
    2057             : {
    2058             :     int16_t i, j, k;
    2059             :     float azi_rad, ele_rad;
    2060             :     uint8_t numDirections;
    2061             : 
    2062             :     /* use the nominal values without data-adaptivity */
    2063      109833 :     numDirections = hMeta->descriptive_meta.numberOfDirections + 1;
    2064             : 
    2065             :     /* azi/ele/nrg into vectors for each sub-frame and band */
    2066      256292 :     for ( i = 0; i < numDirections; i++ )
    2067             :     {
    2068     3661475 :         for ( k = 0; k < MASA_FREQUENCY_BANDS; k++ )
    2069             :         {
    2070             :             float x_sum, y_sum, z_sum, energy_sum, vec_len, spread_coh_sum, surr_coh_sum;
    2071             : 
    2072     3515016 :             x_sum = 0.0f;
    2073     3515016 :             y_sum = 0.0f;
    2074     3515016 :             z_sum = 0.0f;
    2075     3515016 :             energy_sum = 0.0f;
    2076     3515016 :             spread_coh_sum = 0.0f;
    2077     3515016 :             surr_coh_sum = 0.0f;
    2078    17575080 :             for ( j = 0; j < MAX_PARAM_SPATIAL_SUBFRAMES; j++ )
    2079             :             {
    2080    14060064 :                 azi_rad = hMeta->directional_meta[i].azimuth[j][k] / 180.0f * EVS_PI;
    2081    14060064 :                 ele_rad = hMeta->directional_meta[i].elevation[j][k] / 180.0f * EVS_PI;
    2082    14060064 :                 vec_len = hMeta->directional_meta[i].energy_ratio[j][k] * energy[j][k];
    2083             : 
    2084             :                 /* energy-weighted sum over subframes */
    2085    14060064 :                 x_sum += cosf( azi_rad ) * cosf( ele_rad ) * vec_len;
    2086    14060064 :                 y_sum += sinf( azi_rad ) * cosf( ele_rad ) * vec_len;
    2087    14060064 :                 z_sum += sinf( ele_rad ) * vec_len;
    2088             : 
    2089    14060064 :                 energy_sum += energy[j][k];
    2090             : 
    2091    14060064 :                 spread_coh_sum += hMeta->directional_meta[i].spread_coherence[j][k] * energy[j][k];
    2092    14060064 :                 if ( i == 0 )
    2093             :                 {
    2094             :                     /* this is in common metadata and not in each direction */
    2095    10543968 :                     surr_coh_sum += hMeta->common_meta.surround_coherence[j][k] * energy[j][k];
    2096             :                 }
    2097             :             }
    2098             : 
    2099             :             /* the data from the combined sub-frames is written into the first sub-frame band */
    2100     3515016 :             j = 0;
    2101     3515016 :             hMeta->directional_meta[i].azimuth[j][k] = atan2f( y_sum, x_sum ) / EVS_PI * 180.0f;
    2102     3515016 :             hMeta->directional_meta[i].elevation[j][k] = atan2f( z_sum, sqrtf( x_sum * x_sum + y_sum * y_sum ) ) / EVS_PI * 180.0f;
    2103     3515016 :             if ( useSphGrid == TRUE )
    2104             :             {
    2105      142656 :                 hMeta->directional_meta[i].spherical_index[j][k] = index_theta_phi_16( &( hMeta->directional_meta[i].elevation[j][k] ),
    2106      142656 :                                                                                        &( hMeta->directional_meta[i].azimuth[j][k] ), Sph_Grid16 );
    2107             :             }
    2108     3515016 :             vec_len = sqrtf( x_sum * x_sum + y_sum * y_sum + z_sum * z_sum );
    2109     3515016 :             hMeta->directional_meta[i].energy_ratio[j][k] = vec_len / ( energy_sum + EPSILON );
    2110             : 
    2111     3515016 :             hMeta->directional_meta[i].spread_coherence[j][k] = spread_coh_sum / ( energy_sum + EPSILON );
    2112     3515016 :             if ( i == 0 )
    2113             :             {
    2114     2635992 :                 hMeta->common_meta.surround_coherence[j][k] = surr_coh_sum / ( energy_sum + EPSILON );
    2115             :             }
    2116             : 
    2117             :             /* copy the same value to all subframes */
    2118    14060064 :             for ( j = 1; j < MAX_PARAM_SPATIAL_SUBFRAMES; j++ )
    2119             :             {
    2120    10545048 :                 hMeta->directional_meta[i].azimuth[j][k] = hMeta->directional_meta[i].azimuth[0][k];
    2121    10545048 :                 hMeta->directional_meta[i].elevation[j][k] = hMeta->directional_meta[i].elevation[0][k];
    2122    10545048 :                 hMeta->directional_meta[i].energy_ratio[j][k] = hMeta->directional_meta[i].energy_ratio[0][k];
    2123    10545048 :                 hMeta->directional_meta[i].spread_coherence[j][k] = hMeta->directional_meta[i].spread_coherence[0][k];
    2124    10545048 :                 if ( i == 0 )
    2125             :                 {
    2126     7907976 :                     hMeta->common_meta.surround_coherence[j][k] = hMeta->common_meta.surround_coherence[0][k];
    2127             :                 }
    2128             :             }
    2129             :         }
    2130             :     }
    2131             : 
    2132     2745825 :     for ( k = 0; k < MASA_FREQUENCY_BANDS; k++ )
    2133             :     {
    2134    13179960 :         for ( j = 0; j < MAX_PARAM_SPATIAL_SUBFRAMES; j++ )
    2135             :         {
    2136    10543968 :             if ( numDirections == 2 )
    2137             :             {
    2138     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] );
    2139             :             }
    2140             :             else
    2141             :             {
    2142     7027872 :                 hMeta->common_meta.diffuse_to_total_ratio[j][k] = max( 0.0f, 1.0f - hMeta->directional_meta[0].energy_ratio[j][k] );
    2143             :             }
    2144    10543968 :             hMeta->common_meta.remainder_to_total_ratio[j][k] = 0.0f;
    2145             :         }
    2146             :     }
    2147             : 
    2148      109833 :     return;
    2149             : }
    2150             : 
    2151             : 
    2152             : /*-------------------------------------------------------------------*
    2153             :  * copy_masa_metadata_subframe()
    2154             :  *
    2155             :  * Copy MASA metadata frame subframe contents
    2156             :  *-------------------------------------------------------------------*/
    2157             : 
    2158     3273540 : static void copy_masa_metadata_subframe(
    2159             :     const MASA_METADATA_HANDLE hMetaFrom, /* i  : MASA frame metdata to be copied      */
    2160             :     const uint8_t sfFrom,                 /* i  : subframe index of the copy source    */
    2161             :     MASA_METADATA_HANDLE hMetaTo,         /* o  : MASA frame metadata copy destination */
    2162             :     const uint8_t sfTo                    /* i  : subframe index of the copy target    */
    2163             : )
    2164             : {
    2165             :     uint8_t dir;
    2166             :     uint8_t band;
    2167             : 
    2168             :     /* directional metadata */
    2169     9820620 :     for ( dir = 0; dir < MASA_MAXIMUM_DIRECTIONS; dir++ )
    2170             :     {
    2171   163677000 :         for ( band = 0; band < MASA_FREQUENCY_BANDS; band++ )
    2172             :         {
    2173   157129920 :             hMetaTo->directional_meta[dir].spherical_index[sfTo][band] = hMetaFrom->directional_meta[dir].spherical_index[sfFrom][band];
    2174             :         }
    2175     6547080 :         mvr2r( hMetaFrom->directional_meta[dir].azimuth[sfFrom], hMetaTo->directional_meta[dir].azimuth[sfTo], MASA_FREQUENCY_BANDS );
    2176     6547080 :         mvr2r( hMetaFrom->directional_meta[dir].elevation[sfFrom], hMetaTo->directional_meta[dir].elevation[sfTo], MASA_FREQUENCY_BANDS );
    2177     6547080 :         mvr2r( hMetaFrom->directional_meta[dir].energy_ratio[sfFrom], hMetaTo->directional_meta[dir].energy_ratio[sfTo], MASA_FREQUENCY_BANDS );
    2178     6547080 :         mvr2r( hMetaFrom->directional_meta[dir].spread_coherence[sfFrom], hMetaTo->directional_meta[dir].spread_coherence[sfTo], MASA_FREQUENCY_BANDS );
    2179             :     }
    2180             : 
    2181             :     /* common metadata */
    2182     3273540 :     mvr2r( hMetaFrom->common_meta.diffuse_to_total_ratio[sfFrom], hMetaTo->common_meta.diffuse_to_total_ratio[sfTo], MASA_FREQUENCY_BANDS );
    2183     3273540 :     mvr2r( hMetaFrom->common_meta.surround_coherence[sfFrom], hMetaTo->common_meta.surround_coherence[sfTo], MASA_FREQUENCY_BANDS );
    2184     3273540 :     mvr2r( hMetaFrom->common_meta.remainder_to_total_ratio[sfFrom], hMetaTo->common_meta.remainder_to_total_ratio[sfTo], MASA_FREQUENCY_BANDS );
    2185             : 
    2186     3273540 :     return;
    2187             : }
    2188             : 
    2189             : 
    2190             : /*-------------------------------------------------------------------*
    2191             :  * copy_masa_metadata()
    2192             :  *
    2193             :  * Copy MASA metada frame contents
    2194             :  *-------------------------------------------------------------------*/
    2195             : 
    2196      818385 : static void copy_masa_metadata(
    2197             :     const MASA_METADATA_HANDLE hMetaFrom, /* i  : MASA frame metadata to be copied     */
    2198             :     MASA_METADATA_HANDLE hMetaTo          /* o  : MASA frame metadata copy destination */
    2199             : )
    2200             : {
    2201             :     uint8_t sf, byte_idx;
    2202             : 
    2203             :     /* descriptive metadata */
    2204     7365465 :     for ( byte_idx = 0; byte_idx < 8; byte_idx++ )
    2205             :     {
    2206     6547080 :         hMetaTo->descriptive_meta.formatDescriptor[byte_idx] = hMetaFrom->descriptive_meta.formatDescriptor[byte_idx];
    2207             :     }
    2208             : 
    2209      818385 :     hMetaTo->descriptive_meta.numberOfDirections = hMetaFrom->descriptive_meta.numberOfDirections;
    2210      818385 :     hMetaTo->descriptive_meta.numberOfChannels = hMetaFrom->descriptive_meta.numberOfChannels;
    2211      818385 :     hMetaTo->descriptive_meta.sourceFormat = hMetaFrom->descriptive_meta.sourceFormat;
    2212      818385 :     hMetaTo->descriptive_meta.transportDefinition = hMetaFrom->descriptive_meta.transportDefinition;
    2213      818385 :     hMetaTo->descriptive_meta.channelAngle = hMetaFrom->descriptive_meta.channelAngle;
    2214      818385 :     hMetaTo->descriptive_meta.channelDistance = hMetaFrom->descriptive_meta.channelDistance;
    2215      818385 :     hMetaTo->descriptive_meta.channelLayout = hMetaFrom->descriptive_meta.channelLayout;
    2216             : 
    2217             :     /* directional and common metadata */
    2218     4091925 :     for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    2219             :     {
    2220     3273540 :         copy_masa_metadata_subframe( hMetaFrom, sf, hMetaTo, sf );
    2221             :     }
    2222             : 
    2223      818385 :     return;
    2224             : }
    2225             : 
    2226             : 
    2227             : /*-------------------------------------------------------------------*
    2228             :  * are_masa_subframes_similar()
    2229             :  *
    2230             :  * Compare the similarity of MASA metadata in two sub-frames
    2231             :  *-------------------------------------------------------------------*/
    2232             : 
    2233             : /* r: similarity decision */
    2234     4735289 : static uint8_t are_masa_subframes_similar(
    2235             :     const MASA_METADATA_HANDLE frame1, /* i  : MASA metadata frame 1                      */
    2236             :     const uint8_t sf1_idx,             /* i  : index of the subframe of frame1 to inspect */
    2237             :     const MASA_METADATA_HANDLE frame2, /* i  : MASA metadata frame 2                      */
    2238             :     const uint8_t sf2_idx              /* i  : index of the subframe of frame2 to inspect */
    2239             : )
    2240             : {
    2241             :     uint8_t num_dir;
    2242             :     uint8_t dir;
    2243             :     uint8_t band_idx;
    2244             :     uint8_t sf_differ;
    2245             : 
    2246     4735289 :     num_dir = frame1->descriptive_meta.numberOfDirections;
    2247     4735289 :     dir = 0;
    2248     4735289 :     band_idx = 0;
    2249     4735289 :     sf_differ = FALSE;
    2250             : 
    2251     4735289 :     if ( num_dir != frame2->descriptive_meta.numberOfDirections )
    2252             :     {
    2253       42358 :         sf_differ = TRUE;
    2254             :     }
    2255             :     else
    2256             :     {
    2257             :         /* check per-direction metadata */
    2258     4692931 :         dir = 0;
    2259     4692931 :         band_idx = 0;
    2260             : 
    2261    10442968 :         while ( ( sf_differ == FALSE ) && ( dir <= num_dir ) )
    2262             :         {
    2263     5750037 :             band_idx = 0;
    2264    90664582 :             while ( ( sf_differ == FALSE ) && ( band_idx < MASA_FREQUENCY_BANDS ) )
    2265             :             {
    2266             :                 float azi_dif;
    2267    87193059 :                 azi_dif = fabsf( frame1->directional_meta[dir].azimuth[sf1_idx][band_idx] - frame2->directional_meta[dir].azimuth[sf2_idx][band_idx] );
    2268    87193059 :                 azi_dif = azi_dif > 180.0f ? 360.0f - azi_dif : azi_dif;
    2269             : 
    2270    87193059 :                 if ( azi_dif > MASA_ANGLE_TOLERANCE )
    2271             :                 {
    2272     2111065 :                     sf_differ = TRUE;
    2273     2111065 :                     break;
    2274             :                 }
    2275             : 
    2276    85081994 :                 if ( fabsf( frame1->directional_meta[dir].elevation[sf1_idx][band_idx] - frame2->directional_meta[dir].elevation[sf2_idx][band_idx] ) > MASA_ANGLE_TOLERANCE )
    2277             :                 {
    2278       88703 :                     sf_differ = TRUE;
    2279       88703 :                     break;
    2280             :                 }
    2281             : 
    2282    84993291 :                 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 )
    2283             :                 {
    2284       53607 :                     sf_differ = TRUE;
    2285       53607 :                     break;
    2286             :                 }
    2287             : 
    2288    84939684 :                 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 )
    2289             :                 {
    2290       25139 :                     sf_differ = TRUE;
    2291       25139 :                     break;
    2292             :                 }
    2293             : 
    2294    84914545 :                 band_idx++;
    2295             :             }
    2296     5750037 :             dir++;
    2297             :         }
    2298             : 
    2299             :         /* check the common metadata */
    2300     4692931 :         while ( ( sf_differ == FALSE ) && ( band_idx < MASA_FREQUENCY_BANDS ) )
    2301             :         {
    2302           0 :             if ( fabsf( frame1->common_meta.surround_coherence[sf1_idx][band_idx] - frame2->common_meta.surround_coherence[sf2_idx][band_idx] ) > MASA_COHERENCE_TOLERANCE )
    2303             :             {
    2304           0 :                 sf_differ = TRUE;
    2305           0 :                 break;
    2306             :             }
    2307             : 
    2308           0 :             band_idx++;
    2309             :         }
    2310             :     }
    2311             : 
    2312     4735289 :     if ( sf_differ )
    2313             :     {
    2314     2320872 :         return FALSE;
    2315             :     }
    2316             :     else
    2317             :     {
    2318     2414417 :         return TRUE;
    2319             :     }
    2320             : }
    2321             : 
    2322             : 
    2323             : /*-------------------------------------------------------------------*
    2324             :  * detect_framing_async()
    2325             :  *
    2326             :  * Compare the similarity of MASA metadata in two sub-frames
    2327             :  * Analysis result is stored in hMasa->data.sync_state, and
    2328             :  * potentially hMasa->masaMetadata is modified
    2329             :  *-------------------------------------------------------------------*/
    2330             : 
    2331      818385 : static void detect_framing_async(
    2332             :     MASA_ENCODER_HANDLE hMasa /* i/o: MASA encoder structure */
    2333             : )
    2334             : {
    2335             :     MASA_METADATA_HANDLE current_meta;
    2336             :     MASA_METADATA_HANDLE previous_meta;
    2337             :     MASA_SYNC_HANDLE sync_state;
    2338             :     MASA_FRAME_MODE frame_mode;
    2339             :     uint8_t n_sim_start, n_sim_stop, sf_idx;
    2340             :     uint8_t found_offset;
    2341             : 
    2342      818385 :     current_meta = &( hMasa->masaMetadata );  /* metadata from current frame */
    2343      818385 :     sync_state = &( hMasa->data.sync_state ); /* synchronization structure */
    2344      818385 :     previous_meta = &( sync_state->previous_metadata );
    2345             : 
    2346             :     /* check current frame, how many are similar from the start and from the end */
    2347      818385 :     n_sim_start = 1;
    2348     1717909 :     for ( sf_idx = n_sim_start; sf_idx < MAX_PARAM_SPATIAL_SUBFRAMES; sf_idx++ )
    2349             :     {
    2350     1500875 :         if ( are_masa_subframes_similar( current_meta, 0, current_meta, sf_idx ) == TRUE )
    2351             :         {
    2352      899524 :             n_sim_start = sf_idx + 1;
    2353             :         }
    2354             :         else
    2355             :         {
    2356      601351 :             break;
    2357             :         }
    2358             :     }
    2359             : 
    2360             :     /* number of similar sub-frames starting from the end of the frame */
    2361      818385 :     if ( n_sim_start == MAX_PARAM_SPATIAL_SUBFRAMES ) /* shortcut */
    2362             :     {
    2363      217034 :         n_sim_stop = n_sim_start;
    2364             :     }
    2365             :     else
    2366             :     {
    2367      601351 :         n_sim_stop = 1;
    2368      863052 :         for ( sf_idx = 2; sf_idx < MAX_PARAM_SPATIAL_SUBFRAMES; sf_idx++ )
    2369             :         {
    2370             :             /* we need to check only the two middle sub-frames, as all being the same would have taken the shortcut above */
    2371      844863 :             if ( are_masa_subframes_similar( current_meta, MAX_PARAM_SPATIAL_SUBFRAMES - 1, current_meta, MAX_PARAM_SPATIAL_SUBFRAMES - sf_idx ) == TRUE )
    2372             :             {
    2373      261701 :                 n_sim_stop = sf_idx;
    2374             :             }
    2375             :             else
    2376             :             {
    2377      583162 :                 break;
    2378             :             }
    2379             :         }
    2380             :     }
    2381             : 
    2382      818385 :     frame_mode = MASA_FRAME_4SF; /* default mode: 4sf */
    2383      818385 :     if ( sync_state->prev_offset > MAX_PARAM_SPATIAL_SUBFRAMES - 2 )
    2384             :     {
    2385             :         /* earlier offset was large => reset the offset */
    2386       26445 :         found_offset = 0;
    2387             :     }
    2388             :     else
    2389             :     {
    2390             :         /* keep previous offset unless something else is found. alternatively, we could reset always */
    2391      791940 :         found_offset = sync_state->prev_offset;
    2392             :     }
    2393             : 
    2394      818385 :     if ( ( n_sim_start == MAX_PARAM_SPATIAL_SUBFRAMES ) && ( n_sim_stop == MAX_PARAM_SPATIAL_SUBFRAMES ) )
    2395             :     {
    2396             :         /* full frame consists of similar sub-frames */
    2397      217034 :         frame_mode = MASA_FRAME_1SF;
    2398      217034 :         if ( ( sync_state->prev_sim_stop != 0 ) && ( are_masa_subframes_similar( current_meta, 0, previous_meta, MAX_PARAM_SPATIAL_SUBFRAMES - 1 ) == TRUE ) )
    2399             :         {
    2400             :             /* > 4 sub-frames of similar data */
    2401       60082 :             if ( sync_state->prev_sim_stop < 3 )
    2402             :             {
    2403             :                 /* can nicely align the framing with the earlier data and a small offset */
    2404        4653 :                 found_offset = sync_state->prev_sim_stop;
    2405             :             }
    2406             :             else
    2407             :             {
    2408             :                 /* too many similar sub-frames to determine the offset accurately => keep earlier value */
    2409       55429 :                 found_offset = sync_state->prev_offset;
    2410             :             }
    2411             :         }
    2412             :         else
    2413             :         {
    2414             :             /* earlier window was different => reset the offset */
    2415      156952 :             found_offset = 0;
    2416             :         }
    2417             :     }
    2418      601351 :     else if ( n_sim_stop == 3 )
    2419             :     {
    2420             :         /* first sub-frame different that the rest 3
    2421             :                        => make a risky guess that the future sf would be the same too and we're in an offset case */
    2422       18189 :         frame_mode = MASA_FRAME_1SF;
    2423       18189 :         found_offset = 3;
    2424             :     }
    2425      583162 :     else if ( ( sync_state->prev_sim_stop > 0 ) && ( are_masa_subframes_similar( current_meta, 0, previous_meta, MAX_PARAM_SPATIAL_SUBFRAMES - 1 ) == TRUE ) )
    2426             :     {
    2427             :         /* seeing data similar to past */
    2428      123886 :         if ( ( n_sim_start > 1 ) && ( n_sim_start + sync_state->prev_sim_stop >= MAX_PARAM_SPATIAL_SUBFRAMES ) )
    2429             :         {
    2430             :             /* with the past, would have at least one long frame similar subframes */
    2431       62912 :             frame_mode = MASA_FRAME_1SF;
    2432             : 
    2433       62912 :             if ( sync_state->prev_offset == 0 )
    2434             :             {
    2435        4593 :                 found_offset = min( 2, sync_state->prev_sim_stop );
    2436             :             }
    2437             :             else
    2438             :             {
    2439       58319 :                 found_offset = sync_state->prev_offset;
    2440             :             }
    2441             :         }
    2442             :     }
    2443             : 
    2444             :     /* keep the original contents of the frame, but then perform interpolation later */
    2445             :     /* just copy current frame to storage */
    2446      818385 :     copy_masa_metadata( current_meta, previous_meta );
    2447             : 
    2448      818385 :     sync_state->prev_sim_stop = n_sim_stop;
    2449      818385 :     sync_state->prev_offset = found_offset;
    2450      818385 :     sync_state->frame_mode = frame_mode;
    2451             : 
    2452      818385 :     return;
    2453             : }
    2454             : 
    2455             : 
    2456             : /*-------------------------------------------------------------------*
    2457             :  * masa_metadata_direction_alignment()
    2458             :  *
    2459             :  * In 2dir MASA metadata, determine the ordering of the directional
    2460             :  * fields such that the azi/ele change across time is minimized.
    2461             :  *-------------------------------------------------------------------*/
    2462             : 
    2463      818385 : static void masa_metadata_direction_alignment(
    2464             :     MASA_ENCODER_HANDLE hMasa /* i/o: MASA encoder handle */
    2465             : )
    2466             : {
    2467             :     uint8_t band, n_dirs;
    2468             :     MASA_DIR_ALIGN_HANDLE hAlignState;
    2469             :     MASA_METADATA_HANDLE hMeta;
    2470             : 
    2471      818385 :     hAlignState = &( hMasa->data.dir_align_state );
    2472      818385 :     hMeta = &( hMasa->masaMetadata );
    2473             : 
    2474      818385 :     n_dirs = hMeta->descriptive_meta.numberOfDirections + 1; /* 1-based */
    2475    20459625 :     for ( band = 0; band < MASA_FREQUENCY_BANDS; band++ )
    2476             :     {
    2477             :         uint8_t sf;
    2478             :         float diff_swap, diff_no_swap;
    2479             : 
    2480             :         /* trade 2*(cos+sin) against storing the values between frames */
    2481             :         float prev_ele_dir1_sin, prev_ele_dir2_sin;
    2482             :         float prev_ele_dir1_cos, prev_ele_dir2_cos;
    2483             : 
    2484    19641240 :         prev_ele_dir1_sin = sinf( hAlignState->previous_ele_dir1[band] );
    2485    19641240 :         prev_ele_dir2_sin = sinf( hAlignState->previous_ele_dir2[band] );
    2486             : 
    2487    19641240 :         prev_ele_dir1_cos = cosf( hAlignState->previous_ele_dir1[band] );
    2488    19641240 :         prev_ele_dir2_cos = cosf( hAlignState->previous_ele_dir2[band] );
    2489             : 
    2490    98206200 :         for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    2491             :         {
    2492             :             float azi_rad1, ele_rad1;
    2493             :             float azi_rad2, ele_rad2;
    2494             :             float cos_ele1, cos_ele2;
    2495             :             float sin_ele1, sin_ele2;
    2496             : 
    2497    78564960 :             azi_rad1 = hMeta->directional_meta[0].azimuth[sf][band] * PI_OVER_180;
    2498    78564960 :             ele_rad1 = hMeta->directional_meta[0].elevation[sf][band] * PI_OVER_180;
    2499             : 
    2500    78564960 :             if ( n_dirs > 1 )
    2501             :             {
    2502    31736256 :                 azi_rad2 = hMeta->directional_meta[1].azimuth[sf][band] * PI_OVER_180;
    2503    31736256 :                 ele_rad2 = hMeta->directional_meta[1].elevation[sf][band] * PI_OVER_180;
    2504             : 
    2505             :                 /* quick checks to detect constant data and earlier flip */
    2506    31736256 :                 if ( fabsf( azi_rad1 - hAlignState->previous_azi_dir1[band] ) < EPSILON &&
    2507     8399941 :                      fabsf( azi_rad2 - hAlignState->previous_azi_dir2[band] ) < EPSILON &&
    2508     8382833 :                      fabsf( ele_rad1 - hAlignState->previous_ele_dir1[band] ) < EPSILON &&
    2509     8381573 :                      fabsf( ele_rad2 - hAlignState->previous_ele_dir2[band] ) < EPSILON )
    2510             :                 {
    2511     8381573 :                     diff_swap = 1.0f;
    2512     8381573 :                     diff_no_swap = 0.0f;
    2513             :                     /* cached values that will be used for the short-cuts and over-written by the real computations, if done */
    2514     8381573 :                     sin_ele1 = prev_ele_dir1_sin;
    2515     8381573 :                     sin_ele2 = prev_ele_dir2_sin;
    2516     8381573 :                     cos_ele1 = prev_ele_dir1_cos;
    2517     8381573 :                     cos_ele2 = prev_ele_dir2_cos;
    2518             :                 }
    2519    23354683 :                 else if ( fabsf( azi_rad1 - hAlignState->previous_azi_dir2[band] ) < EPSILON &&
    2520     7484804 :                           fabsf( azi_rad2 - hAlignState->previous_azi_dir1[band] ) < EPSILON &&
    2521     7468798 :                           fabsf( ele_rad1 - hAlignState->previous_ele_dir2[band] ) < EPSILON &&
    2522     7468630 :                           fabsf( ele_rad2 - hAlignState->previous_ele_dir1[band] ) < EPSILON )
    2523             :                 {
    2524     7468630 :                     diff_swap = 0.0f;
    2525     7468630 :                     diff_no_swap = 1.0f;
    2526             :                     /* cached values that will be used for the short-cuts and over-written by the real computations, if done */
    2527     7468630 :                     sin_ele1 = prev_ele_dir2_sin;
    2528     7468630 :                     sin_ele2 = prev_ele_dir1_sin;
    2529     7468630 :                     cos_ele1 = prev_ele_dir2_cos;
    2530     7468630 :                     cos_ele2 = prev_ele_dir1_cos;
    2531             :                 }
    2532             :                 else
    2533             :                 {
    2534             :                     /* angular distance of the two vectors */
    2535             :                     /* pre-compute values for re-use */
    2536    15886053 :                     sin_ele1 = sinf( ele_rad1 );
    2537    15886053 :                     sin_ele2 = sinf( ele_rad2 );
    2538             : 
    2539    15886053 :                     cos_ele1 = cosf( ele_rad1 );
    2540    15886053 :                     cos_ele2 = cosf( ele_rad2 );
    2541             : 
    2542    15886053 :                     diff_no_swap = acosf( cos_ele1 * prev_ele_dir1_cos * cosf( azi_rad1 - hAlignState->previous_azi_dir1[band] ) + sin_ele1 * prev_ele_dir1_sin ) +
    2543    15886053 :                                    acosf( cos_ele2 * prev_ele_dir2_cos * cosf( azi_rad2 - hAlignState->previous_azi_dir2[band] ) + sin_ele2 * prev_ele_dir2_sin );
    2544             : 
    2545    15886053 :                     diff_swap = acosf( cos_ele1 * prev_ele_dir2_cos * cosf( azi_rad1 - hAlignState->previous_azi_dir2[band] ) + sin_ele1 * prev_ele_dir2_sin ) +
    2546    15886053 :                                 acosf( cos_ele2 * prev_ele_dir1_cos * cosf( azi_rad2 - hAlignState->previous_azi_dir1[band] ) + sin_ele2 * prev_ele_dir1_sin );
    2547             :                 }
    2548             :             }
    2549             :             else
    2550             :             {
    2551             :                 /* 1dir */
    2552    46828704 :                 sin_ele1 = sinf( ele_rad1 );
    2553    46828704 :                 cos_ele1 = cosf( ele_rad1 );
    2554             : 
    2555    46828704 :                 azi_rad2 = 0.0f;
    2556    46828704 :                 ele_rad2 = 0.0f;
    2557             : 
    2558    46828704 :                 sin_ele2 = 0.0f; /* sin(0) */
    2559    46828704 :                 cos_ele2 = 1.0f; /* cos(0) */
    2560             : 
    2561    46828704 :                 diff_swap = 1.0f;
    2562    46828704 :                 diff_no_swap = 0.0f;
    2563             :             }
    2564             : 
    2565    78564960 :             if ( n_dirs > 1 && diff_no_swap > diff_swap )
    2566    14626026 :             {
    2567             :                 /* swap the metadata of the two directions in this TF-tile */
    2568             :                 float tmp_val;
    2569             :                 uint16_t tmp_int_val;
    2570    14626026 :                 tmp_val = hMeta->directional_meta[0].azimuth[sf][band];
    2571    14626026 :                 hMeta->directional_meta[0].azimuth[sf][band] = hMeta->directional_meta[1].azimuth[sf][band];
    2572    14626026 :                 hMeta->directional_meta[1].azimuth[sf][band] = tmp_val;
    2573             : 
    2574    14626026 :                 tmp_val = hMeta->directional_meta[0].elevation[sf][band];
    2575    14626026 :                 hMeta->directional_meta[0].elevation[sf][band] = hMeta->directional_meta[1].elevation[sf][band];
    2576    14626026 :                 hMeta->directional_meta[1].elevation[sf][band] = tmp_val;
    2577    14626026 :                 tmp_int_val = hMeta->directional_meta[0].spherical_index[sf][band];
    2578    14626026 :                 hMeta->directional_meta[0].spherical_index[sf][band] = hMeta->directional_meta[1].spherical_index[sf][band];
    2579    14626026 :                 hMeta->directional_meta[1].spherical_index[sf][band] = tmp_int_val;
    2580    14626026 :                 tmp_val = hMeta->directional_meta[0].energy_ratio[sf][band];
    2581    14626026 :                 hMeta->directional_meta[0].energy_ratio[sf][band] = hMeta->directional_meta[1].energy_ratio[sf][band];
    2582    14626026 :                 hMeta->directional_meta[1].energy_ratio[sf][band] = tmp_val;
    2583             : 
    2584    14626026 :                 tmp_val = hMeta->directional_meta[0].spread_coherence[sf][band];
    2585    14626026 :                 hMeta->directional_meta[0].spread_coherence[sf][band] = hMeta->directional_meta[1].spread_coherence[sf][band];
    2586    14626026 :                 hMeta->directional_meta[1].spread_coherence[sf][band] = tmp_val;
    2587             : 
    2588    14626026 :                 hAlignState->previous_azi_dir1[band] = azi_rad2;
    2589    14626026 :                 hAlignState->previous_ele_dir1[band] = ele_rad2;
    2590             : 
    2591    14626026 :                 hAlignState->previous_azi_dir2[band] = azi_rad1;
    2592    14626026 :                 hAlignState->previous_ele_dir2[band] = ele_rad1;
    2593             : 
    2594    14626026 :                 prev_ele_dir1_cos = cos_ele2;
    2595    14626026 :                 prev_ele_dir1_sin = sin_ele2;
    2596             : 
    2597    14626026 :                 prev_ele_dir2_cos = cos_ele1;
    2598    14626026 :                 prev_ele_dir2_sin = sin_ele1;
    2599             :             }
    2600             :             else
    2601             :             {
    2602    63938934 :                 hAlignState->previous_azi_dir1[band] = azi_rad1;
    2603    63938934 :                 hAlignState->previous_ele_dir1[band] = ele_rad1;
    2604             : 
    2605    63938934 :                 hAlignState->previous_azi_dir2[band] = azi_rad2;
    2606    63938934 :                 hAlignState->previous_ele_dir2[band] = ele_rad2;
    2607             : 
    2608    63938934 :                 prev_ele_dir1_cos = cos_ele1;
    2609    63938934 :                 prev_ele_dir1_sin = sin_ele1;
    2610             : 
    2611    63938934 :                 prev_ele_dir2_cos = cos_ele2;
    2612    63938934 :                 prev_ele_dir2_sin = sin_ele2;
    2613             :             }
    2614             :         } /* sf */
    2615             :     }     /* band */
    2616             : 
    2617      818385 :     return;
    2618             : }
    2619             : 
    2620             : 
    2621             : /*-------------------------------------------------------------------*
    2622             :  * ivas_merge_masa_metadata()
    2623             :  *
    2624             :  *
    2625             :  *-------------------------------------------------------------------*/
    2626             : 
    2627      118000 : void ivas_merge_masa_metadata(
    2628             :     MASA_ENCODER_HANDLE hMasa,           /* i/o: MASA enc handle. source for MASA metadata and combined metadata will be here */
    2629             :     OMASA_SPATIAL_META_HANDLE hOMasaMeta /* i  : ISM-object metadata to be merged with the MASA metadata                      */
    2630             : )
    2631             : {
    2632             :     int16_t sf, band;
    2633             :     uint8_t numCodingBands;
    2634             :     uint8_t numDirections;
    2635             :     uint8_t numSf;
    2636             :     MASA_METADATA_HANDLE hMeta;
    2637             :     float energyTimesRatioISM;
    2638             :     float energyTimesRatioMASA[2];
    2639             :     float total_diff_nrg;
    2640             :     float eneBand;
    2641             :     float energyMerged[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
    2642      118000 :     OMASA_ENCODER_ENERGY_HANDLE hOmasaEnergy = hMasa->data.hOmasaData->hOmasaEnergy;
    2643             : 
    2644      118000 :     numCodingBands = hMasa->config.numCodingBands;
    2645      118000 :     numDirections = hMasa->config.numberOfDirections;
    2646      118000 :     numSf = hMasa->config.joinedSubframes == TRUE ? 1 : MAX_PARAM_SPATIAL_SUBFRAMES;
    2647      118000 :     hMeta = &( hMasa->masaMetadata );
    2648             : 
    2649      590000 :     for ( sf = 0; sf < numSf; sf++ )
    2650             :     {
    2651    11680000 :         for ( band = 0; band < numCodingBands; band++ )
    2652             :         {
    2653             :             int16_t merge_dest;
    2654             :             float dir_sum;
    2655             :             uint8_t band_n_dirs;
    2656    11208000 :             if ( numDirections == 1 || ( numDirections == 2 && hMasa->data.twoDirBands[band] == 0 ) )
    2657             :             {
    2658    11208000 :                 band_n_dirs = 1;
    2659             :             }
    2660             :             else
    2661             :             {
    2662           0 :                 band_n_dirs = 2;
    2663             :             }
    2664             : 
    2665             :             /* Compute energies */
    2666    11208000 :             eneBand = hMasa->data.energy[sf][band];
    2667    11208000 :             energyMerged[sf][band] = eneBand + hOmasaEnergy->energy_ism[sf][band];
    2668             : 
    2669             :             /* Compute weights */
    2670    11208000 :             energyTimesRatioMASA[0] = eneBand * hMeta->directional_meta[0].energy_ratio[sf][band];
    2671    11208000 :             if ( band_n_dirs == 2 )
    2672             :             {
    2673           0 :                 energyTimesRatioMASA[1] = eneBand * hMeta->directional_meta[1].energy_ratio[sf][band];
    2674             :             }
    2675             :             else
    2676             :             {
    2677    11208000 :                 energyTimesRatioMASA[1] = 0.0f;
    2678             :             }
    2679             : 
    2680             :             /* target is original MASA diffuseness */
    2681    11208000 :             total_diff_nrg = eneBand * hMeta->common_meta.diffuse_to_total_ratio[sf][band];
    2682             : 
    2683             :             /* criterion is mean of ISM ratio and new ratio */
    2684    11208000 :             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];
    2685             : 
    2686             :             /* Determine combined metadata based on the weights */
    2687    11208000 :             merge_dest = -1;
    2688    11208000 :             if ( ( band_n_dirs == 1 && energyTimesRatioMASA[0] < energyTimesRatioISM ) ||
    2689           0 :                  ( band_n_dirs == 2 && energyTimesRatioMASA[0] < energyTimesRatioMASA[1] && energyTimesRatioMASA[0] < energyTimesRatioISM ) )
    2690             :             {
    2691             :                 /* 1dir and ISM the most energetic, or 2dir and ISM the more energetic than MASA1 */
    2692     5389086 :                 merge_dest = 0;
    2693             :             }
    2694     5818914 :             else if ( band_n_dirs == 2 && energyTimesRatioMASA[1] <= energyTimesRatioMASA[0] && energyTimesRatioMASA[1] < energyTimesRatioISM )
    2695             :             {
    2696             :                 /* 2dir and ISM the most energetic and MASA2 the least energetic */
    2697           0 :                 merge_dest = 1;
    2698             :             }
    2699             : 
    2700    11208000 :             if ( merge_dest >= 0 ) /* replace one MASA with ISM */
    2701             :             {
    2702     5389086 :                 hMeta->directional_meta[merge_dest].azimuth[sf][band] = hOMasaMeta->directional_meta[0].azimuth[sf][band];
    2703     5389086 :                 hMeta->directional_meta[merge_dest].elevation[sf][band] = hOMasaMeta->directional_meta[0].elevation[sf][band];
    2704             : 
    2705             :                 /* limit with the earlier direct-energy ratio */
    2706     5389086 :                 dir_sum = 1.0f - total_diff_nrg / ( EPSILON + eneBand + hOmasaEnergy->energy_ism[sf][band] );                                        /* new dir ratio */
    2707     5389086 :                 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 */
    2708     5389086 :                 hMeta->common_meta.diffuse_to_total_ratio[sf][band] = 1.0f - hMeta->directional_meta[merge_dest].energy_ratio[sf][band];
    2709             : 
    2710     5389086 :                 if ( hMasa->config.useCoherence )
    2711             :                 {
    2712           0 :                     hMeta->directional_meta[merge_dest].spread_coherence[sf][band] = hOMasaMeta->directional_meta[0].spread_coherence[sf][band];
    2713           0 :                     hMeta->common_meta.surround_coherence[sf][band] = hOMasaMeta->common_meta.surround_coherence[sf][band];
    2714             :                 }
    2715             : 
    2716             :                 /* recompute direct energy ratios to match the diffuse ratio */
    2717             :                 float direct_quota, direct_scaler;
    2718     5389086 :                 direct_quota = 1.0f - hMeta->common_meta.diffuse_to_total_ratio[sf][band];
    2719     5389086 :                 if ( band_n_dirs == 1 )
    2720             :                 {
    2721     5389086 :                     hMeta->directional_meta[0].energy_ratio[sf][band] = direct_quota;
    2722             :                 }
    2723             :                 else
    2724             :                 {
    2725           0 :                     dir_sum = hMeta->directional_meta[0].energy_ratio[sf][band] + hMeta->directional_meta[1].energy_ratio[sf][band];
    2726           0 :                     direct_scaler = direct_quota / ( EPSILON + dir_sum );
    2727           0 :                     hMeta->directional_meta[0].energy_ratio[sf][band] *= direct_scaler;
    2728           0 :                     hMeta->directional_meta[1].energy_ratio[sf][band] *= direct_scaler;
    2729             :                 }
    2730             :             }
    2731             :         }
    2732             :     }
    2733             : 
    2734      590000 :     for ( sf = 0; sf < numSf; sf++ )
    2735             :     {
    2736    11680000 :         for ( band = 0; band < numCodingBands; band++ )
    2737             :         {
    2738    11208000 :             hMasa->data.energy[sf][band] = energyMerged[sf][band];
    2739             :         }
    2740             :     }
    2741             : 
    2742      118000 :     return;
    2743             : }
    2744             : 
    2745             : 
    2746      868200 : static void quantize_ratio_ism_vector(
    2747             :     const float *ratio_ism,
    2748             :     int16_t *idx,
    2749             :     const int16_t nchan_ism,
    2750             :     const float masa_to_total_energy_ratio,
    2751             :     const int16_t idx_sep_object )
    2752             : {
    2753             :     int16_t i, j, best_i, best_i2;
    2754             :     float dist, div, tmp, dist2, best_dist;
    2755             :     int16_t part_idx_sum, max_sum_idx;
    2756             :     float ratio_ism_loc[MAX_NUM_OBJECTS];
    2757             :     int16_t no_ism_loc;
    2758             : 
    2759      868200 :     max_sum_idx = ( 1 << PARAM_ISM_POW_RATIO_NBITS ) - 1;
    2760             : 
    2761      868200 :     if ( idx_sep_object > -1 )
    2762             :     {
    2763      868200 :         if ( ratio_ism[idx_sep_object] < 1.0f / (float) ( max_sum_idx ) )
    2764             :         {
    2765             :             /* take it out from quantize function  */
    2766      521372 :             mvr2r( ratio_ism, ratio_ism_loc, idx_sep_object );
    2767      521372 :             mvr2r( &ratio_ism[idx_sep_object + 1], &ratio_ism_loc[idx_sep_object], nchan_ism - idx_sep_object - 1 );
    2768      521372 :             no_ism_loc = nchan_ism - 1;
    2769             :         }
    2770             :         else
    2771             :         {
    2772      346828 :             no_ism_loc = nchan_ism;
    2773      346828 :             mvr2r( ratio_ism, ratio_ism_loc, nchan_ism );
    2774             :         }
    2775             :     }
    2776             :     else
    2777             :     {
    2778           0 :         no_ism_loc = nchan_ism;
    2779           0 :         mvr2r( ratio_ism, ratio_ism_loc, nchan_ism );
    2780             :     }
    2781             : 
    2782      868200 :     if ( nchan_ism > 1 )
    2783             :     {
    2784      868200 :         if ( masa_to_total_energy_ratio >= MASA2TOTAL_THR )
    2785             :         {
    2786      411552 :             distribute_evenly_ism( idx, max_sum_idx, nchan_ism );
    2787             :         }
    2788             :         else
    2789             :         {
    2790      456648 :             if ( no_ism_loc > 1 )
    2791             :             {
    2792             : 
    2793      443704 :                 dist = 0.0f;
    2794      443704 :                 div = 1.0f / (float) ( max_sum_idx );
    2795             : 
    2796      443704 :                 part_idx_sum = 0;
    2797             : 
    2798     1653781 :                 for ( i = 0; i < no_ism_loc; i++ )
    2799             :                 {
    2800     1210077 :                     idx[i] = (int16_t) ( ( ratio_ism_loc[i] ) * ( max_sum_idx ) );
    2801     1210077 :                     part_idx_sum += idx[i];
    2802             : 
    2803     1210077 :                     tmp = ( ratio_ism_loc[i] - ( idx[i] * div ) );
    2804     1210077 :                     dist += ( tmp * tmp );
    2805             :                 }
    2806             : 
    2807      443704 :                 best_dist = dist;
    2808      443704 :                 best_i2 = -1;
    2809      651544 :                 while ( part_idx_sum < max_sum_idx )
    2810             :                 {
    2811      207840 :                     best_i = -1;
    2812             :                     /* check which index to increase by 1 for a possible improvement */
    2813             : 
    2814      804109 :                     for ( i = 0; i < no_ism_loc; i++ )
    2815             :                     {
    2816      596269 :                         idx[i]++;
    2817      596269 :                         dist2 = 0.0f;
    2818             : 
    2819     2365874 :                         for ( j = 0; j < no_ism_loc; j++ )
    2820             :                         {
    2821     1769605 :                             tmp = ( ratio_ism_loc[i] - ( idx[i] * div ) );
    2822     1769605 :                             dist2 += ( tmp * tmp );
    2823             :                         }
    2824             : 
    2825      596269 :                         if ( dist2 < best_dist )
    2826             :                         {
    2827      179186 :                             best_i2 = best_i;
    2828      179186 :                             best_i = i;
    2829      179186 :                             best_dist = dist2;
    2830             :                         }
    2831      596269 :                         idx[i]--;
    2832             :                     }
    2833      207840 :                     if ( best_i > -1 )
    2834             :                     {
    2835      175572 :                         idx[best_i]++;
    2836      175572 :                         part_idx_sum++;
    2837             :                     }
    2838             :                     else
    2839             :                     {
    2840       32268 :                         if ( best_i2 > -1 )
    2841             :                         {
    2842        3099 :                             idx[best_i2]++;
    2843        3099 :                             part_idx_sum++;
    2844             :                         }
    2845             :                         else
    2846             :                         {
    2847       29169 :                             idx[no_ism_loc - 1] += max_sum_idx - part_idx_sum;
    2848       29169 :                             part_idx_sum = max_sum_idx;
    2849             :                         }
    2850             :                     }
    2851             :                 }
    2852      443704 :                 assert( sum_s( idx, no_ism_loc ) == max_sum_idx );
    2853             :             }
    2854             :             else
    2855             :             {
    2856       12944 :                 idx[0] = max_sum_idx;
    2857             :             }
    2858             : 
    2859      456648 :             if ( no_ism_loc < nchan_ism )
    2860             :             {
    2861             :                 /*  insert back the ratio of the separated object  */
    2862      854819 :                 for ( i = nchan_ism - 1; i > idx_sep_object; i-- )
    2863             :                 {
    2864      452359 :                     idx[i] = idx[i - 1];
    2865             :                 }
    2866      402460 :                 idx[idx_sep_object] = 0;
    2867             :             }
    2868             :         }
    2869             :     }
    2870             :     else
    2871             :     {
    2872           0 :         idx[0] = (int16_t) ( ( ratio_ism[0] ) * ( ( 1 << PARAM_ISM_POW_RATIO_NBITS ) - 1 ) + 0.5f );
    2873             :     }
    2874             : 
    2875      868200 :     return;
    2876             : }
    2877             : 
    2878             : 
    2879       57263 : static int16_t index_slice_enum(
    2880             :     const int16_t *ratio_ism_idx,
    2881             :     const int16_t nchan_ism )
    2882             : {
    2883             :     int16_t i;
    2884             :     int16_t x, index;
    2885             :     int16_t base;
    2886             : 
    2887       57263 :     if ( nchan_ism == 2 )
    2888             :     {
    2889        4840 :         index = ratio_ism_idx[0];
    2890             :     }
    2891             :     else
    2892             :     {
    2893       52423 :         x = ratio_ism_idx[nchan_ism - 2];
    2894       52423 :         base = 10;
    2895      141234 :         for ( i = nchan_ism - 3; i >= 0; i-- )
    2896             :         {
    2897       88811 :             x += ratio_ism_idx[i] * base;
    2898       88811 :             base *= 10;
    2899             :         }
    2900             : 
    2901       52423 :         index = 0;
    2902       52423 :         i = 0;
    2903     4349061 :         while ( i <= x )
    2904             :         {
    2905     4296638 :             if ( valid_ratio_index( i, 7, nchan_ism - 1 ) )
    2906             :             {
    2907     1284865 :                 index++;
    2908             :             }
    2909     4296638 :             i++;
    2910             :         }
    2911       52423 :         index--;
    2912             :     }
    2913             : 
    2914       57263 :     return index;
    2915             : }
    2916             : 
    2917             : 
    2918     1044834 : static void transform_difference_index(
    2919             :     const int16_t *diff_idx,
    2920             :     int16_t *idx,
    2921             :     const int16_t len )
    2922             : {
    2923             :     int16_t i;
    2924     3301153 :     for ( i = 0; i < len; i++ )
    2925             :     {
    2926     2256319 :         if ( diff_idx[i] <= 0 )
    2927             :         {
    2928     2130851 :             idx[i] = -2 * diff_idx[i];
    2929             :         }
    2930             :         else
    2931             :         {
    2932      125468 :             idx[i] = 2 * diff_idx[i] - 1;
    2933             :         }
    2934             :     }
    2935             : 
    2936     1044834 :     return;
    2937             : }
    2938             : 
    2939             : 
    2940      399229 : static void transform_index_and_GR_encode(
    2941             :     int16_t *diff_idx,        /* i  : differenc eindex to encode    */
    2942             :     const int16_t len,        /* i  : input length                  */
    2943             :     const int16_t GR_order,   /* i  : GR order                      */
    2944             :     BSTR_ENC_HANDLE hMetaData /* i/o: metadata bitstream handle     */
    2945             : )
    2946             : {
    2947             :     int16_t i;
    2948             :     int16_t idx[IVAS_MAX_NUM_OBJECTS];
    2949             : 
    2950             :     /* transform difference index into positive */
    2951      399229 :     transform_difference_index( diff_idx, idx, len );
    2952             : 
    2953             :     /* GR encoding */
    2954     1275267 :     for ( i = 0; i < len; i++ )
    2955             :     {
    2956      876038 :         ivas_qmetadata_encode_extended_gr( hMetaData, idx[i], 100, GR_order );
    2957             :     }
    2958             : 
    2959      399229 :     return;
    2960             : }
    2961             : 
    2962             : 
    2963       59500 : static int16_t try_differential(
    2964             :     const int16_t numCodingBands,
    2965             :     const float *masa_to_total_energy_ratio,
    2966             :     int16_t ratio_ism_idx[MASA_FREQUENCY_BANDS][MAX_NUM_OBJECTS],
    2967             :     const int16_t nchan_ism,
    2968             :     const int16_t bits_index,
    2969             :     int16_t *p_b_signif )
    2970             : {
    2971             :     int16_t b, i;
    2972             :     int16_t nbits0;
    2973             :     int16_t b_signif;
    2974             :     int16_t ratio_ism_idx_ref[MAX_NUM_OBJECTS];
    2975             :     int16_t diff_idx[MAX_NUM_OBJECTS];
    2976             : 
    2977       59500 :     b_signif = 0;
    2978      244776 :     while ( ( b_signif < numCodingBands ) && ( masa_to_total_energy_ratio[b_signif] >= MASA2TOTAL_THR ) )
    2979             :     {
    2980      185276 :         b_signif++;
    2981             :     }
    2982             : 
    2983       59500 :     nbits0 = 0;
    2984             : 
    2985       59500 :     if ( b_signif < numCodingBands )
    2986             :     {
    2987       34800 :         nbits0 = bits_index;
    2988       34800 :         mvs2s( ratio_ism_idx[b_signif], ratio_ism_idx_ref, nchan_ism );
    2989             : 
    2990      261184 :         for ( b = b_signif + 1; b < numCodingBands; b++ )
    2991             :         {
    2992      226384 :             if ( masa_to_total_energy_ratio[b] < MASA2TOTAL_THR )
    2993             :             {
    2994      197761 :                 v_sub_s( ratio_ism_idx[b], ratio_ism_idx_ref, diff_idx, nchan_ism );
    2995      197761 :                 mvs2s( ratio_ism_idx[b], ratio_ism_idx_ref, nchan_ism );
    2996             : 
    2997             :                 /* transform difference index into positive */
    2998      197761 :                 transform_difference_index( diff_idx, diff_idx, nchan_ism - 1 );
    2999             : 
    3000             :                 /* GR encoding */
    3001      692238 :                 for ( i = 0; i < nchan_ism - 1; i++ )
    3002             :                 {
    3003      494477 :                     nbits0 += ivas_qmetadata_encode_extended_gr_length( diff_idx[i], 100, 0 );
    3004             :                 }
    3005             :             }
    3006             :         }
    3007             :     }
    3008       59500 :     *p_b_signif = b_signif;
    3009             : 
    3010       59500 :     return nbits0;
    3011             : }
    3012             : 
    3013             : 
    3014       29705 : static void differential_coding_first_subframe(
    3015             :     BSTR_ENC_HANDLE hMetaData,
    3016             :     const float *masa_to_total_energy_ratio,
    3017             :     const int16_t b_signif,
    3018             :     int16_t ratio_ism_idx[MASA_FREQUENCY_BANDS][MAX_NUM_OBJECTS],
    3019             :     const int16_t nchan_ism,
    3020             :     const int16_t numCodingBands,
    3021             :     const int16_t bits_index )
    3022             : {
    3023             :     int16_t index, b;
    3024             :     int16_t ratio_ism_idx_ref[MAX_NUM_OBJECTS];
    3025             :     int16_t diff_idx[MAX_NUM_OBJECTS];
    3026             : 
    3027             :     /* differential encoding*/
    3028       29705 :     push_next_indice( hMetaData, 0, 1 );
    3029             : 
    3030       29705 :     if ( b_signif < numCodingBands )
    3031             :     {
    3032       29705 :         index = index_slice_enum( ratio_ism_idx[b_signif], nchan_ism );
    3033       29705 :         push_next_indice( hMetaData, index, bits_index );
    3034             : 
    3035       29705 :         mvs2s( ratio_ism_idx[b_signif], ratio_ism_idx_ref, nchan_ism );
    3036             : 
    3037      229746 :         for ( b = b_signif + 1; b < numCodingBands; b++ )
    3038             :         {
    3039      200041 :             if ( masa_to_total_energy_ratio[b] < MASA2TOTAL_THR )
    3040             :             {
    3041      175298 :                 v_sub_s( ratio_ism_idx[b], ratio_ism_idx_ref, diff_idx, nchan_ism );
    3042      175298 :                 mvs2s( ratio_ism_idx[b], ratio_ism_idx_ref, nchan_ism );
    3043             : 
    3044             :                 /* transform difference index into positive */
    3045      175298 :                 transform_index_and_GR_encode( diff_idx, nchan_ism - 1, 0, hMetaData );
    3046             :             }
    3047             :         }
    3048             :     }
    3049             : 
    3050       29705 :     return;
    3051             : }
    3052             : 
    3053             : 
    3054        5095 : static void independent_coding_ratio_ism_idx(
    3055             :     int16_t ratio_ism_idx[MASA_FREQUENCY_BANDS][MAX_NUM_OBJECTS], /* i  : ISM ratios                */
    3056             :     const float *masa_to_total_energy_ratio,                      /* i  : MASA to total ratios      */
    3057             :     const int16_t nchan_ism,                                      /* i  : number of objects         */
    3058             :     const int16_t numCodingBands,                                 /* i  : number of subbands        */
    3059             :     const int16_t bits_index,                                     /* i  : number of bits per index  */
    3060             :     BSTR_ENC_HANDLE hMetaData                                     /* i/o: metadata bitstream handle */
    3061             : )
    3062             : {
    3063             :     int16_t b, index;
    3064             : 
    3065       38572 :     for ( b = 0; b < numCodingBands; b++ )
    3066             :     {
    3067       33477 :         if ( masa_to_total_energy_ratio[b] < MASA2TOTAL_THR )
    3068             :         {
    3069       27558 :             index = index_slice_enum( ratio_ism_idx[b], nchan_ism );
    3070       27558 :             push_next_indice( hMetaData, index, bits_index );
    3071             :         }
    3072             :     }
    3073             : 
    3074        5095 :     return;
    3075             : }
    3076             : 
    3077             : 
    3078      439695 : static void remove_sep_obj(
    3079             :     int16_t *diff_idx,        /* i/o: array of difference of indexes                        */
    3080             :     const int16_t nchan_ism,  /* i  : number of objects                                     */
    3081             :     const int16_t idx_sep_obj /* i  : index of separated object, to be taken out of array   */
    3082             : )
    3083             : {
    3084             :     int16_t i;
    3085             : 
    3086     1429050 :     for ( i = idx_sep_obj; i < nchan_ism - 1; i++ )
    3087             :     {
    3088      989355 :         diff_idx[i] = diff_idx[i + 1];
    3089             :     }
    3090             : 
    3091      439695 :     return;
    3092             : }
    3093             : 
    3094             : 
    3095      447844 : static void estimate_bits_subband_ism_ratio(
    3096             :     const int16_t *ratio_ism_idx,
    3097             :     const int16_t *ratio_ism_idx_ref, /* ( i/o ) */
    3098             :     const int16_t nchan_ism,
    3099             :     const int16_t shift_one,
    3100             :     const int16_t idx_sep_obj,
    3101             :     int16_t *p_nbits0,
    3102             :     int16_t *p_nbits1 )
    3103             : {
    3104             :     int16_t diff_idx[MAX_NUM_OBJECTS];
    3105             :     int16_t nbits0, nbits1;
    3106             :     int16_t i;
    3107             : 
    3108      447844 :     nbits0 = 0;
    3109      447844 :     nbits1 = 0;
    3110             : 
    3111             :     /* take difference with respect to previous subframe */
    3112      447844 :     v_sub_s( ratio_ism_idx, ratio_ism_idx_ref, diff_idx, nchan_ism );
    3113             : 
    3114      447844 :     if ( shift_one )
    3115             :     {
    3116      293130 :         remove_sep_obj( diff_idx, nchan_ism, idx_sep_obj );
    3117             :     }
    3118             : 
    3119             :     /* transform difference index into positive */
    3120      447844 :     transform_difference_index( diff_idx, diff_idx, nchan_ism - 1 - shift_one );
    3121             : 
    3122             :     /* GR encoding */
    3123     1333648 :     for ( i = 0; i < nchan_ism - 1 - shift_one; i++ )
    3124             :     {
    3125      885804 :         nbits0 += ivas_qmetadata_encode_extended_gr_length( diff_idx[i], 100, 0 );
    3126      885804 :         nbits1 += ivas_qmetadata_encode_extended_gr_length( diff_idx[i], 100, 1 );
    3127             :     }
    3128             : 
    3129      447844 :     *p_nbits0 = nbits0;
    3130      447844 :     *p_nbits1 = nbits1;
    3131             : 
    3132      447844 :     return;
    3133             : }
    3134             : 
    3135             : 
    3136      144520 : static int16_t encode_ratio_ism_subframe(
    3137             :     int16_t ratio_ism_idx[MASA_FREQUENCY_BANDS][MAX_NUM_OBJECTS],
    3138             :     const int16_t nchan_ism,
    3139             :     const uint8_t numCodingBands,
    3140             :     const int16_t sf,
    3141             :     int16_t ratio_ism_idx_prev_sf[MASA_FREQUENCY_BANDS][MAX_NUM_OBJECTS],
    3142             :     BSTR_ENC_HANDLE hMetaData,
    3143             :     const float *masa_to_total_energy_ratio,
    3144             :     const int16_t shift_one,
    3145             :     const int16_t idx_separated_obj )
    3146             : {
    3147             :     int16_t b, b_signif;
    3148             :     int16_t diff_idx[MAX_NUM_OBJECTS];
    3149             :     int16_t nbits, nbits0, nbits1, GR_order, GR_order_sb;
    3150             :     int16_t differential_subframe;
    3151             :     int16_t ratio_ism_idx_ref[MAX_NUM_OBJECTS];
    3152             :     int16_t bits_index;
    3153             :     int16_t nbits00, nbits11;
    3154             :     int16_t idx_sep_obj_local;
    3155             : #ifdef DEBUGGING
    3156             :     int16_t bits_pos0;
    3157             : #endif
    3158             : 
    3159      144520 :     idx_sep_obj_local = idx_separated_obj;
    3160      144520 :     if ( idx_separated_obj > -1 )
    3161             :     {
    3162      144520 :         if ( idx_separated_obj == nchan_ism - 1 )
    3163             :         {
    3164       62729 :             idx_sep_obj_local = 0;
    3165             :         }
    3166             :     }
    3167      144520 :     nbits = 0;
    3168      144520 :     nbits0 = 0;
    3169      144520 :     nbits1 = 0;
    3170             : 
    3171             : #ifdef DEBUGGING
    3172             :     bits_pos0 = hMetaData->nb_bits_tot;
    3173             : #endif
    3174      144520 :     differential_subframe = 1; /* the differences are taken with respect to previous subframe */
    3175             : 
    3176             :     /* first subframe */
    3177      144520 :     bits_index = 0;
    3178      144520 :     if ( sf == 0 )
    3179             :     {
    3180       59500 :         bits_index = bits_index_ism_ratio( nchan_ism );
    3181             : 
    3182       59500 :         nbits = 0;
    3183      505960 :         for ( b = 0; b < numCodingBands; b++ )
    3184             :         {
    3185      446460 :             if ( masa_to_total_energy_ratio[b] < MASA2TOTAL_THR )
    3186             :             {
    3187      232561 :                 nbits += bits_index;
    3188             :             }
    3189             :         }
    3190             : 
    3191       59500 :         nbits0 = try_differential( numCodingBands, masa_to_total_energy_ratio, ratio_ism_idx, nchan_ism, bits_index, &b_signif );
    3192             : 
    3193       59500 :         if ( nbits <= nbits0 && nbits > 0 )
    3194             :         {
    3195             :             /* independent encoding */
    3196        5095 :             push_next_indice( hMetaData, 1, 1 );
    3197        5095 :             independent_coding_ratio_ism_idx( ratio_ism_idx, masa_to_total_energy_ratio, nchan_ism, numCodingBands, bits_index, hMetaData );
    3198        5095 :             nbits = nbits + 1;
    3199             :         }
    3200             :         else
    3201             :         {
    3202       54405 :             if ( nbits > 0 )
    3203             :             {
    3204       29705 :                 differential_coding_first_subframe( hMetaData, masa_to_total_energy_ratio, b_signif, ratio_ism_idx, nchan_ism, numCodingBands, bits_index );
    3205       29705 :                 nbits = nbits0 + 1;
    3206             :             }
    3207             :         }
    3208             : 
    3209             : #ifdef DEBUGGING
    3210             :         assert( nbits == ( hMetaData->nb_bits_tot - bits_pos0 ) );
    3211             : #endif
    3212             :     }
    3213             :     else
    3214             :     {
    3215             :         /* not first subframe */
    3216       85020 :         if ( shift_one == 1 && nchan_ism == 2 )
    3217             :         {
    3218         159 :             nbits = 0;
    3219             :         }
    3220             :         else
    3221             :         {
    3222       84861 :             nbits0 = 0;
    3223       84861 :             nbits1 = 0;
    3224             : 
    3225      506442 :             for ( b = 0; b < numCodingBands; b++ )
    3226             :             {
    3227      421581 :                 if ( masa_to_total_energy_ratio[b] < MASA2TOTAL_THR )
    3228             :                 {
    3229      223931 :                     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 );
    3230      223931 :                     nbits0 += nbits00;
    3231      223931 :                     nbits1 += nbits11;
    3232             :                 }
    3233             :             }
    3234       84861 :             if ( nbits0 < nbits1 )
    3235             :             {
    3236       45636 :                 GR_order = 0;
    3237       45636 :                 nbits = nbits0;
    3238             :             }
    3239             :             else
    3240             :             {
    3241       39225 :                 GR_order = 1;
    3242       39225 :                 nbits = nbits1;
    3243             :             }
    3244             : 
    3245       84861 :             if ( numCodingBands > 1 )
    3246             :             {
    3247             :                 /* try the difference from subband to subband; first subband is compared to previous subframe first subband*/
    3248             :                 /* take difference with respect to previous subframe only for first subband */
    3249       84180 :                 nbits0 = 0;
    3250       84180 :                 nbits1 = 0;
    3251       84180 :                 b_signif = 0;
    3252      258813 :                 while ( ( b_signif < numCodingBands ) && ( masa_to_total_energy_ratio[b_signif] >= MASA2TOTAL_THR ) )
    3253             :                 {
    3254      174633 :                     b_signif++;
    3255             :                 }
    3256             : 
    3257       84180 :                 if ( b_signif < numCodingBands )
    3258             :                 {
    3259       51396 :                     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 );
    3260             : 
    3261       51396 :                     mvs2s( ratio_ism_idx[b_signif], ratio_ism_idx_ref, nchan_ism );
    3262             : 
    3263      246267 :                     for ( b = b_signif + 1; b < numCodingBands; b++ )
    3264             :                     {
    3265      194871 :                         if ( masa_to_total_energy_ratio[b] < MASA2TOTAL_THR )
    3266             :                         {
    3267      172517 :                             estimate_bits_subband_ism_ratio( ratio_ism_idx[b], ratio_ism_idx_ref, nchan_ism, shift_one, idx_sep_obj_local, &nbits00, &nbits11 );
    3268      172517 :                             nbits0 += nbits00;
    3269      172517 :                             nbits1 += nbits11;
    3270      172517 :                             mvs2s( ratio_ism_idx[b], ratio_ism_idx_ref, nchan_ism );
    3271             :                         }
    3272             :                     }
    3273             : 
    3274       51396 :                     if ( nbits0 < nbits1 )
    3275             :                     {
    3276       41752 :                         GR_order_sb = 0;
    3277             :                     }
    3278             :                     else
    3279             :                     {
    3280        9644 :                         GR_order_sb = 1;
    3281        9644 :                         nbits0 = nbits1;
    3282             :                     }
    3283             : 
    3284       51396 :                     if ( nbits0 < nbits )
    3285             :                     {
    3286        6556 :                         differential_subframe = 0;
    3287        6556 :                         nbits = nbits0;
    3288        6556 :                         GR_order = GR_order_sb;
    3289             :                     }
    3290             : 
    3291       51396 :                     if ( nbits > 0 )
    3292             :                     {
    3293             :                         /* write prediction type */
    3294       51396 :                         push_next_indice( hMetaData, differential_subframe, 1 );
    3295             :                         /* write GR order */
    3296       51396 :                         push_next_indice( hMetaData, GR_order, 1 );
    3297       51396 :                         nbits++; /* for the prediction type */
    3298       51396 :                         nbits++; /* for GR_order */
    3299             : 
    3300             :                         /* write data */
    3301       51396 :                         if ( differential_subframe )
    3302             :                         {
    3303      269040 :                             for ( b = 0; b < numCodingBands; b++ )
    3304             :                             {
    3305      224200 :                                 if ( masa_to_total_energy_ratio[b] < MASA2TOTAL_THR )
    3306             :                                 {
    3307             :                                     /* take difference with respect to previous subframe */
    3308      197223 :                                     v_sub_s( ratio_ism_idx[b], ratio_ism_idx_prev_sf[b], diff_idx, nchan_ism );
    3309             : 
    3310      197223 :                                     if ( shift_one )
    3311             :                                     {
    3312      140404 :                                         remove_sep_obj( diff_idx, nchan_ism, idx_sep_obj_local );
    3313             :                                     }
    3314             : 
    3315      197223 :                                     transform_index_and_GR_encode( diff_idx, nchan_ism - 1 - shift_one, GR_order, hMetaData );
    3316             :                                 }
    3317             :                             }
    3318             :                         }
    3319             :                         else
    3320             :                         {
    3321        6556 :                             v_sub_s( ratio_ism_idx[b_signif], ratio_ism_idx_prev_sf[b_signif], diff_idx, nchan_ism );
    3322             : 
    3323        6556 :                             if ( shift_one )
    3324             :                             {
    3325        1291 :                                 remove_sep_obj( diff_idx, nchan_ism, idx_sep_obj_local );
    3326             :                             }
    3327             : 
    3328        6556 :                             transform_index_and_GR_encode( diff_idx, nchan_ism - 1 - shift_one, GR_order, hMetaData );
    3329             : 
    3330        6556 :                             mvs2s( ratio_ism_idx[b_signif], ratio_ism_idx_ref, nchan_ism - shift_one );
    3331             : 
    3332       31986 :                             for ( b = b_signif + 1; b < numCodingBands; b++ )
    3333             :                             {
    3334             :                                 /* take difference with respect to previous subband */
    3335       25430 :                                 if ( masa_to_total_energy_ratio[b] < MASA2TOTAL_THR )
    3336             :                                 {
    3337       20134 :                                     v_sub_s( ratio_ism_idx[b], ratio_ism_idx_ref, diff_idx, nchan_ism );
    3338             : 
    3339       20134 :                                     if ( shift_one )
    3340             :                                     {
    3341        4870 :                                         remove_sep_obj( diff_idx, nchan_ism, idx_sep_obj_local );
    3342             :                                     }
    3343             : 
    3344       20134 :                                     transform_index_and_GR_encode( diff_idx, nchan_ism - 1 - shift_one, GR_order, hMetaData );
    3345             : 
    3346       20134 :                                     mvs2s( ratio_ism_idx[b], ratio_ism_idx_ref, nchan_ism - shift_one );
    3347             :                                 }
    3348             :                             }
    3349             :                         }
    3350             :                     }
    3351             :                 }
    3352             :             }
    3353             :             else
    3354             :             {
    3355             :                 /* only differential wrt previous subframe is possible  */
    3356             :                 /* write the differential to subframe case and no bit to signal the difference type */
    3357             : 
    3358         681 :                 if ( nbits > 0 )
    3359             :                 {
    3360             :                     /* write GR order */
    3361          18 :                     push_next_indice( hMetaData, GR_order, 1 );
    3362          18 :                     nbits++; /* for GR_order */
    3363             :                     /* write data */
    3364             :                     /* only one subband */
    3365          18 :                     if ( masa_to_total_energy_ratio[0] < MASA2TOTAL_THR )
    3366             :                     {
    3367             :                         /* take difference with respect to previous subframe */
    3368          18 :                         v_sub_s( ratio_ism_idx[0], ratio_ism_idx_prev_sf[0], diff_idx, nchan_ism );
    3369             : 
    3370          18 :                         if ( shift_one )
    3371             :                         {
    3372           0 :                             remove_sep_obj( diff_idx, nchan_ism, idx_sep_obj_local );
    3373             :                         }
    3374             : 
    3375          18 :                         transform_index_and_GR_encode( diff_idx, nchan_ism - 1 - shift_one, GR_order, hMetaData );
    3376             :                     }
    3377             :                 }
    3378             :             }
    3379             : 
    3380             : #ifdef DEBUGGING
    3381             :             assert( nbits == ( hMetaData->nb_bits_tot - bits_pos0 ) );
    3382             : #endif
    3383             :         }
    3384             :     }
    3385             : 
    3386      144520 :     return nbits;
    3387             : }
    3388             : 
    3389             : 
    3390       59500 : static void ivas_encode_masaism_metadata(
    3391             :     MASA_ENCODER_HANDLE hMasa,
    3392             :     IVAS_QMETADATA_HANDLE hQMetaData, /* i/o: q_metadata handle             */
    3393             :     BSTR_ENC_HANDLE hMetaData,        /* i/o: metadata bitstream handle     */
    3394             :     ISM_METADATA_HANDLE hIsmMeta[],   /* i/o: ISM metadata handles          */
    3395             :     const int16_t nchan_ism,          /* i  : number of ISM channels        */
    3396             :     const int16_t low_bitrate_mode,   /* i  : is low bitrate more? 1/0      */
    3397             :     const int16_t omasa_nbands,
    3398             :     const int16_t omasa_nblocks,
    3399             :     const int16_t idx_separated_object,
    3400             :     const int16_t ism_imp )
    3401             : {
    3402             :     int16_t sf, band;
    3403             :     uint8_t numCodingBands;
    3404             :     uint8_t numSf;
    3405             :     int16_t brange[2];
    3406             :     float eneBand;
    3407             :     int16_t bin;
    3408             :     int16_t obj;
    3409             :     int16_t bits_ism[MAX_NUM_OBJECTS];
    3410             :     uint16_t idx_sph;
    3411             :     float theta_q, phi_q;
    3412             :     uint16_t index_theta, index_phi;
    3413             :     float ratio_ism[MASA_FREQUENCY_BANDS][MAX_NUM_OBJECTS];
    3414             :     int16_t ratio_ism_idx[MASA_FREQUENCY_BANDS][MAX_NUM_OBJECTS], ratio_ism_idx_prev_sf[MASA_FREQUENCY_BANDS][MAX_NUM_OBJECTS];
    3415             :     float step;
    3416             :     int16_t inv_step;
    3417             :     float energy_ism, energy_ism_ind[MAX_NUM_OBJECTS];
    3418             :     int16_t tmp, rotate;
    3419             :     int16_t n_ism_tmp, i;
    3420       59500 :     OMASA_ENCODER_DATA_HANDLE hOmasaData = hMasa->data.hOmasaData;
    3421       59500 :     OMASA_ENCODER_ENERGY_HANDLE hOmasaEnergy = hOmasaData->hOmasaEnergy;
    3422             :     int16_t nbands_work;
    3423             : 
    3424             :     /* use the values from hQMetaData */
    3425       59500 :     numCodingBands = (uint8_t) hQMetaData->q_direction->cfg.nbands;
    3426       59500 :     numSf = (int8_t) hQMetaData->q_direction->cfg.nblocks;
    3427       59500 :     nbands_work = min( numCodingBands, omasa_nbands );
    3428       59500 :     if ( numCodingBands == 1 )
    3429             :     {
    3430        1400 :         for ( sf = 0; sf < numSf; sf++ )
    3431             :         {
    3432        1120 :             if ( sum_f( hOmasaEnergy->energy_ism[sf], omasa_nbands ) == 0.0f )
    3433             :             {
    3434         784 :                 hOmasaData->masa_to_total_energy_ratio[sf][0] = 1.0f;
    3435             :             }
    3436             :             else
    3437             :             {
    3438         336 :                 brange[0] = hMasa->data.band_mapping[0];
    3439         336 :                 brange[1] = hMasa->data.band_mapping[omasa_nbands];
    3440         336 :                 eneBand = 0.0f;
    3441        8400 :                 for ( bin = brange[0]; bin < brange[1]; bin++ )
    3442             :                 {
    3443        8064 :                     eneBand += hMasa->data.energy[sf][bin];
    3444             :                 }
    3445             : 
    3446         336 :                 energy_ism = 0.0f;
    3447        1008 :                 for ( obj = 0; obj < nchan_ism; obj++ )
    3448             :                 {
    3449         672 :                     energy_ism_ind[obj] = 0.0f;
    3450             :                 }
    3451             : 
    3452        2016 :                 for ( band = 0; band < omasa_nbands; band++ )
    3453             :                 {
    3454        1680 :                     energy_ism += hOmasaEnergy->energy_ism[sf][band];
    3455        5040 :                     for ( obj = 0; obj < nchan_ism; obj++ )
    3456             :                     {
    3457        3360 :                         energy_ism_ind[obj] += hOmasaEnergy->energy_ism[sf][band] * hOmasaEnergy->energy_ratio_ism[sf][band][obj];
    3458             :                     }
    3459             :                 }
    3460             : 
    3461        1008 :                 for ( obj = 0; obj < nchan_ism; obj++ )
    3462             :                 {
    3463         672 :                     hOmasaEnergy->energy_ratio_ism[sf][0][obj] = energy_ism_ind[obj] / energy_ism;
    3464             :                 }
    3465         336 :                 hOmasaData->masa_to_total_energy_ratio[sf][0] = eneBand / ( eneBand + energy_ism + EPSILON );
    3466             :             }
    3467             :         }
    3468             :     }
    3469       59220 :     else if ( numSf == 1 )
    3470             :     {
    3471      337040 :         for ( band = 0; band < nbands_work; band++ )
    3472             :         {
    3473      305880 :             energy_ism = 0.0f; /* ISM energy for current subband */
    3474     1322220 :             for ( obj = 0; obj < nchan_ism; obj++ )
    3475             :             {
    3476     1016340 :                 energy_ism_ind[obj] = 0.0f;
    3477             :             }
    3478      690570 :             for ( sf = 0; sf < omasa_nblocks; sf++ )
    3479             :             {
    3480      384690 :                 energy_ism += hOmasaEnergy->energy_ism[sf][band];
    3481     1558650 :                 for ( obj = 0; obj < nchan_ism; obj++ )
    3482             :                 {
    3483     1173960 :                     energy_ism_ind[obj] += hOmasaEnergy->energy_ism[sf][band] * hOmasaEnergy->energy_ratio_ism[sf][band][obj];
    3484             :                 }
    3485             :             }
    3486             : 
    3487      305880 :             if ( energy_ism == 0.0f )
    3488             :             {
    3489       99919 :                 hOmasaData->masa_to_total_energy_ratio[0][band] = 1.0f;
    3490             :             }
    3491             :             else
    3492             :             {
    3493      909999 :                 for ( obj = 0; obj < nchan_ism; obj++ )
    3494             :                 {
    3495      704038 :                     hOmasaEnergy->energy_ratio_ism[0][band][obj] = energy_ism_ind[obj] / energy_ism;
    3496             :                 }
    3497      205961 :                 brange[0] = hMasa->data.band_mapping[band];
    3498      205961 :                 brange[1] = hMasa->data.band_mapping[band + 1];
    3499             : 
    3500      205961 :                 eneBand = 0.0f;
    3501      447982 :                 for ( sf = 0; sf < omasa_nblocks; sf++ )
    3502             :                 {
    3503      885020 :                     for ( bin = brange[0]; bin < brange[1]; bin++ )
    3504             :                     {
    3505      642999 :                         eneBand += hMasa->data.energy[sf][bin];
    3506             :                     }
    3507             :                 }
    3508      205961 :                 hOmasaData->masa_to_total_energy_ratio[0][band] = eneBand / ( eneBand + energy_ism + EPSILON );
    3509             :             }
    3510             :         }
    3511       31160 :         for ( band = nbands_work; band < numCodingBands; band++ )
    3512             :         {
    3513           0 :             hOmasaData->masa_to_total_energy_ratio[0][band] = 1.0f;
    3514             : 
    3515           0 :             for ( obj = 0; obj < nchan_ism; obj++ )
    3516             :             {
    3517           0 :                 hOmasaEnergy->energy_ratio_ism[0][band][obj] = hOmasaEnergy->energy_ratio_ism[0][nbands_work - 1][obj];
    3518             :             }
    3519             :         }
    3520             :     }
    3521             :     else
    3522             :     {
    3523      140300 :         for ( sf = 0; sf < numSf; sf++ )
    3524             :         {
    3525      673440 :             for ( band = 0; band < nbands_work; band++ )
    3526             :             {
    3527      561200 :                 if ( hOmasaEnergy->energy_ism[sf][band] == 0.0f )
    3528             :                 {
    3529      180035 :                     hOmasaData->masa_to_total_energy_ratio[sf][band] = 1.0f;
    3530             :                 }
    3531             :                 else
    3532             :                 {
    3533      381165 :                     brange[0] = hMasa->data.band_mapping[band];
    3534      381165 :                     brange[1] = hMasa->data.band_mapping[band + 1];
    3535             : 
    3536      381165 :                     eneBand = 0.0f;
    3537     2191313 :                     for ( bin = brange[0]; bin < brange[1]; bin++ )
    3538             :                     {
    3539     1810148 :                         eneBand += hMasa->data.energy[sf][bin];
    3540             :                     }
    3541      381165 :                     hOmasaData->masa_to_total_energy_ratio[sf][band] = eneBand / ( eneBand + hOmasaEnergy->energy_ism[sf][band] + EPSILON );
    3542             :                 }
    3543             :             }
    3544      112240 :             for ( band = nbands_work; band < numCodingBands; band++ )
    3545             :             {
    3546           0 :                 hOmasaData->masa_to_total_energy_ratio[sf][band] = 1.0f;
    3547             : 
    3548           0 :                 for ( obj = 0; obj < nchan_ism; obj++ )
    3549             :                 {
    3550           0 :                     hOmasaEnergy->energy_ratio_ism[sf][band][obj] = hOmasaEnergy->energy_ratio_ism[sf][nbands_work - 1][obj];
    3551             :                 }
    3552             :             }
    3553             :         }
    3554             :     }
    3555       59500 :     ivas_omasa_encode_masa_to_total( hOmasaData->masa_to_total_energy_ratio, hMetaData, low_bitrate_mode, numCodingBands, numSf );
    3556             : 
    3557             :     /* quantize ism_ratios */
    3558       59500 :     if ( nchan_ism > 1 )
    3559             :     {
    3560       59500 :         inv_step = ( ( 1 << PARAM_ISM_POW_RATIO_NBITS ) - 1 );
    3561       59500 :         step = 1.0f / inv_step;
    3562             : 
    3563       59500 :         rotate = 0;
    3564       59500 :         n_ism_tmp = 0;
    3565             : 
    3566      204020 :         for ( sf = 0; sf < numSf; sf++ )
    3567             :         {
    3568     1012720 :             for ( band = 0; band < numCodingBands; band++ )
    3569             :             {
    3570     3894880 :                 for ( obj = 0; obj < nchan_ism; obj++ )
    3571             :                 {
    3572     3026680 :                     assert( ( hOmasaEnergy->energy_ratio_ism[sf][band][obj] >= 0 ) && ( hOmasaEnergy->energy_ratio_ism[sf][band][obj] <= 1 ) );
    3573     3026680 :                     ratio_ism[band][obj] = hOmasaEnergy->energy_ratio_ism[sf][band][obj];
    3574             :                 }
    3575             : 
    3576             :                 /* Quantize ISM ratios */
    3577      868200 :                 quantize_ratio_ism_vector( ratio_ism[band], ratio_ism_idx[band], nchan_ism, hOmasaData->masa_to_total_energy_ratio[sf][band], idx_separated_object );
    3578      868200 :                 if ( n_ism_tmp == numCodingBands && ratio_ism_idx[band][idx_separated_object] != 0 && hOmasaData->masa_to_total_energy_ratio[sf][band] < MASA2TOTAL_THR )
    3579             :                 {
    3580         615 :                     i = 0;
    3581        4717 :                     while ( ratio_ism_idx[band][idx_separated_object] > 0 )
    3582             :                     {
    3583        4102 :                         if ( i != idx_separated_object )
    3584             :                         {
    3585        2762 :                             ratio_ism_idx[band][i]++;
    3586        2762 :                             ratio_ism_idx[band][idx_separated_object]--;
    3587             :                         }
    3588        4102 :                         i++;
    3589        4102 :                         if ( i == nchan_ism )
    3590             :                         {
    3591         931 :                             i = 0;
    3592             :                         }
    3593             :                     }
    3594             :                 }
    3595             : 
    3596             :                 /* reconstructed values */
    3597      868200 :                 reconstruct_ism_ratios( ratio_ism_idx[band], nchan_ism, step, hOmasaEnergy->q_energy_ratio_ism[sf][band] );
    3598             :             }
    3599             : 
    3600      144520 :             if ( ( nchan_ism > 2 ) && ( idx_separated_object == nchan_ism - 1 ) )
    3601             :             {
    3602             :                 /* rotate components */
    3603       57305 :                 rotate = 1;
    3604      406249 :                 for ( band = 0; band < numCodingBands; band++ )
    3605             :                 {
    3606      348944 :                     if ( hOmasaData->masa_to_total_energy_ratio[sf][band] < MASA2TOTAL_THR )
    3607             :                     {
    3608      173498 :                         tmp = ratio_ism_idx[band][nchan_ism - 1];
    3609      173498 :                         ratio_ism_idx[band][nchan_ism - 1] = ratio_ism_idx[band][0];
    3610      173498 :                         ratio_ism_idx[band][0] = tmp;
    3611      173498 :                         if ( sf == 0 && tmp == 0 )
    3612             :                         {
    3613       63804 :                             n_ism_tmp += 1;
    3614             :                         }
    3615             : 
    3616      173498 :                         if ( n_ism_tmp == numCodingBands )
    3617             :                         {
    3618       64808 :                             assert( tmp == 0 );
    3619             :                         }
    3620             :                     }
    3621             :                 }
    3622             :             }
    3623             :             else
    3624             :             {
    3625       87215 :                 if ( idx_separated_object > -1 )
    3626             :                 {
    3627      606471 :                     for ( band = 0; band < numCodingBands; band++ )
    3628             :                     {
    3629      519256 :                         if ( hOmasaData->masa_to_total_energy_ratio[sf][band] < MASA2TOTAL_THR )
    3630             :                         {
    3631      283150 :                             if ( ratio_ism_idx[band][idx_separated_object] == 0 && sf == 0 )
    3632             :                             {
    3633      133434 :                                 n_ism_tmp++;
    3634             :                             }
    3635             :                         }
    3636             :                     }
    3637             :                 }
    3638             :             }
    3639             : 
    3640             :             /* encode data for current subframe */
    3641      144520 :             if ( sf > 0 && n_ism_tmp == numCodingBands )
    3642             :             {
    3643       30054 :                 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 );
    3644             :             }
    3645             :             else
    3646             :             {
    3647      114466 :                 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 );
    3648             :             }
    3649             : 
    3650             :             /* calculate quantized ISM ratios */
    3651             :             /* save previous subframe indexes */
    3652     1012720 :             for ( band = 0; band < numCodingBands; band++ )
    3653             :             {
    3654      868200 :                 mvs2s( ratio_ism_idx[band], ratio_ism_idx_prev_sf[band], nchan_ism );
    3655             :             }
    3656             : 
    3657      144520 :             if ( rotate )
    3658             :             {
    3659      406249 :                 for ( band = 0; band < numCodingBands; band++ )
    3660             :                 {
    3661      348944 :                     if ( hOmasaData->masa_to_total_energy_ratio[sf][band] < MASA2TOTAL_THR )
    3662             :                     {
    3663      173498 :                         tmp = ratio_ism_idx[band][nchan_ism - 1];
    3664      173498 :                         ratio_ism_idx[band][nchan_ism - 1] = ratio_ism_idx[band][0];
    3665      173498 :                         ratio_ism_idx[band][0] = tmp;
    3666             :                     }
    3667             :                 }
    3668             :             }
    3669             :         }
    3670             :     }
    3671             : 
    3672       59500 :     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 );
    3673             : 
    3674             :     /* quantize directions */
    3675      256500 :     for ( obj = 0; obj < nchan_ism; obj++ )
    3676             :     {
    3677      197000 :         if ( bits_ism[obj] < 8 )
    3678             :         {
    3679             :             /* check is same as previous */
    3680      104008 :             if ( ( fabs( hIsmMeta[obj]->elevation - hIsmMeta[obj]->q_elevation_old ) < 0.01f ) && ( fabs( hIsmMeta[obj]->azimuth - hIsmMeta[obj]->q_azimuth_old ) < 0.01f ) )
    3681             :             {
    3682       10319 :                 push_next_indice( hMetaData, 1, 1 );
    3683             :                 /* the old stays the same */
    3684             :             }
    3685             :             else
    3686             :             {
    3687       93689 :                 push_next_indice( hMetaData, 0, 1 );
    3688       93689 :                 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 );
    3689       93689 :                 push_next_indice( hMetaData, idx_sph, bits_ism[obj] );
    3690       93689 :                 hIsmMeta[obj]->q_elevation_old = hIsmMeta[obj]->elevation;
    3691       93689 :                 hIsmMeta[obj]->q_azimuth_old = hIsmMeta[obj]->azimuth;
    3692             :             }
    3693             :         }
    3694             :         else
    3695             :         {
    3696       92992 :             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 );
    3697       92992 :             push_next_indice( hMetaData, idx_sph, bits_ism[obj] );
    3698       92992 :             hIsmMeta[obj]->q_elevation_old = hIsmMeta[obj]->elevation;
    3699       92992 :             hIsmMeta[obj]->q_azimuth_old = hIsmMeta[obj]->azimuth;
    3700             :         }
    3701             :     }
    3702             : 
    3703       59500 :     return;
    3704             : }
    3705             : 
    3706             : 
    3707             : /*-------------------------------------------------------------------*
    3708             :  * ivas_merge_masa_transports()
    3709             :  *
    3710             :  * Merge MASA transport channels
    3711             :  *-------------------------------------------------------------------*/
    3712             : 
    3713      177500 : void ivas_merge_masa_transports(
    3714             :     float data_in_f1[][L_FRAME48k],
    3715             :     float *data_in_f2[],
    3716             :     float *data_out_f[],
    3717             :     const int16_t input_frame,
    3718             :     const int16_t num_transport_channels )
    3719             : {
    3720             :     int16_t i, j;
    3721             : 
    3722      532500 :     for ( i = 0; i < num_transport_channels; i++ )
    3723             :     {
    3724   320035000 :         for ( j = 0; j < input_frame; j++ )
    3725             :         {
    3726   319680000 :             data_out_f[i][j] = data_in_f1[i][j] + data_in_f2[i][j];
    3727             :         }
    3728             :     }
    3729             : 
    3730      177500 :     return;
    3731             : }

Generated by: LCOV version 1.14