LCOV - code coverage report
Current view: top level - lib_enc - ivas_masa_enc.c (source / functions) Hit Total Coverage
Test: Coverage on main -- merged total coverage @ efe53129c9ed87a5067dd0a8fb9dca41db9c4add Lines: 1362 1415 96.3 %
Date: 2026-02-12 08:06:51 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        8752 : 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        8752 :     error = IVAS_ERR_OK;
     104             : 
     105        8752 :     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        8752 :     hEncoderConfig = st_ivas->hEncoderConfig;
     111             : 
     112        8752 :     generate_gridEq( &( hMasa->data.Sph_Grid16 ) );
     113             : 
     114        8752 :     if ( hEncoderConfig->ivas_format == MASA_FORMAT || hEncoderConfig->ivas_format == MASA_ISM_FORMAT )
     115             :     {
     116        1642 :         hMasa->data.num_Cldfb_instances = st_ivas->nchan_transport;
     117             :     }
     118             :     else
     119             :     {
     120        7110 :         hMasa->data.num_Cldfb_instances = 0;
     121             :     }
     122             : 
     123       11741 :     for ( i = 0; i < hMasa->data.num_Cldfb_instances; i++ )
     124             :     {
     125        2989 :         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        8752 :     ism_total_brate = 0;
     132        8752 :     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        2060 :         for ( i = 0; i < st_ivas->nSCE; i++ )
     135             :         {
     136        1291 :             ism_total_brate += st_ivas->hSCE[i]->element_brate;
     137             :         }
     138             :     }
     139             : 
     140        8752 :     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        8752 :     mvs2s( DirAC_block_grouping, hMasa->config.block_grouping, MAX_PARAM_SPATIAL_SUBFRAMES + 1 );
     143        8752 :     mvs2s( MASA_band_grouping_24, hMasa->config.band_grouping, MASA_FREQUENCY_BANDS + 1 );
     144             : 
     145             : 
     146        8752 :     hMasa->data.onset_detector_1 = 0.0f;
     147        8752 :     hMasa->data.onset_detector_2 = 0.0f;
     148             : 
     149        8752 :     set_zero( hMasa->data.lfeToTotalEnergyRatio, MAX_PARAM_SPATIAL_SUBFRAMES );
     150        8752 :     hMasa->data.prevq_lfeToTotalEnergyRatio = 0.0f;
     151        8752 :     hMasa->data.prevq_lfeIndex = 0;
     152             : 
     153        8752 :     hMasa->data.sync_state.prev_sim_stop = 0;
     154        8752 :     hMasa->data.sync_state.prev_offset = 0;
     155        8752 :     hMasa->data.sync_state.frame_mode = MASA_FRAME_4SF;
     156             : 
     157        8752 :     set_zero( hMasa->data.dir_align_state.previous_azi_dir1, MASA_FREQUENCY_BANDS );
     158        8752 :     set_zero( hMasa->data.dir_align_state.previous_ele_dir1, MASA_FREQUENCY_BANDS );
     159        8752 :     set_zero( hMasa->data.dir_align_state.previous_azi_dir2, MASA_FREQUENCY_BANDS );
     160        8752 :     set_zero( hMasa->data.dir_align_state.previous_ele_dir2, MASA_FREQUENCY_BANDS );
     161             : 
     162        8752 :     if ( hEncoderConfig->ivas_format == MASA_ISM_FORMAT )
     163             :     {
     164             :         OMASA_ENCODER_DATA_HANDLE hOmasaData;
     165             : 
     166        1016 :         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        5080 :         for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ )
     171             :         {
     172        4064 :             set_f( hOmasaData->masa_to_total_energy_ratio[i], 0, MASA_FREQUENCY_BANDS );
     173             :         }
     174        1016 :         hOmasaData->lp_noise_CPE = -1;
     175        1016 :         hOmasaData->omasa_stereo_sw_cnt = OMASA_STEREO_SW_CNT_MAX;
     176             : 
     177        1016 :         if ( st_ivas->ism_mode != ISM_MASA_MODE_DISC )
     178             :         {
     179         501 :             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         515 :             hOmasaData->hOmasaEnergy = NULL;
     187             :         }
     188             : 
     189        1016 :         hMasa->data.hOmasaData = hOmasaData;
     190             :     }
     191             :     else
     192             :     {
     193        7736 :         hMasa->data.hOmasaData = NULL;
     194             :     }
     195             : 
     196        8752 :     st_ivas->hMasa = hMasa;
     197             : 
     198        8752 :     return error;
     199             : }
     200             : 
     201             : 
     202             : /*-----------------------------------------------------------------------*
     203             :  * ivas_masa_enc_close()
     204             :  *
     205             :  * close MASA encoder
     206             :  *-----------------------------------------------------------------------*/
     207             : 
     208       16681 : void ivas_masa_enc_close(
     209             :     MASA_ENCODER_HANDLE *hMasa /* i/o: MASA metadata structure      */
     210             : )
     211             : {
     212             :     int16_t i;
     213             : 
     214       16681 :     if ( hMasa == NULL || *hMasa == NULL )
     215             :     {
     216        7929 :         return;
     217             :     }
     218             : 
     219       11741 :     for ( i = 0; i < ( *hMasa )->data.num_Cldfb_instances; i++ )
     220             :     {
     221        2989 :         deleteCldfb( &( ( *hMasa )->data.cldfbAnaEnc[i] ) );
     222             :     }
     223             : 
     224        8752 :     if ( ( *hMasa )->data.hOmasaData != NULL )
     225             :     {
     226        1016 :         if ( ( *hMasa )->data.hOmasaData->hOmasaEnergy != NULL )
     227             :         {
     228         512 :             free( ( *hMasa )->data.hOmasaData->hOmasaEnergy );
     229         512 :             ( *hMasa )->data.hOmasaData->hOmasaEnergy = NULL;
     230             :         }
     231             : 
     232        1016 :         free( ( *hMasa )->data.hOmasaData );
     233        1016 :         ( *hMasa )->data.hOmasaData = NULL;
     234             :     }
     235             : 
     236        8752 :     free( ( *hMasa ) );
     237        8752 :     ( *hMasa ) = NULL;
     238             : 
     239        8752 :     return;
     240             : }
     241             : 
     242             : 
     243             : /*-----------------------------------------------------------------------*
     244             :  * ivas_masa_encode()
     245             :  *
     246             :  * main MASA encoder function
     247             :  *-----------------------------------------------------------------------*/
     248             : 
     249     1302497 : 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     1302497 :     masa_sid_descriptor = -1;
     276     1302497 :     h_orig_metadata = NULL;
     277     1302497 :     low_bitrate_mode = 0;
     278             : 
     279     1302497 :     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     1111657 :         if ( Opt_DTX_ON && hQMetaData != NULL )
     283             :         {
     284       70127 :             if ( nchan_transport == 2 ) /* this is MASA format in CPE only */
     285             :             {
     286       45112 :                 masa_sid_descriptor = 0; /* for IVAS_CPE_DFT */
     287       45112 :                 if ( element_mode == IVAS_CPE_MDCT )
     288             :                 {
     289       19946 :                     masa_sid_descriptor = 1;
     290             :                 }
     291             :             }
     292             :         }
     293             : 
     294             :         /* Validate and compensate ratios as necessary */
     295     1111657 :         compensate_energy_ratios( hMasa );
     296             : 
     297     1111657 :         if ( Opt_DTX_ON )
     298             :         {
     299       70127 :             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      210381 :             for ( i = 0; i < MASA_MAXIMUM_DIRECTIONS; i++ )
     305             :             {
     306      701270 :                 for ( j = 0; j < MAX_PARAM_SPATIAL_SUBFRAMES; j++ )
     307             :                 {
     308      561016 :                     mvr2r( hMasa->masaMetadata.directional_meta[i].azimuth[j], h_orig_metadata[i].azimuth[j], MASA_FREQUENCY_BANDS );
     309      561016 :                     mvr2r( hMasa->masaMetadata.directional_meta[i].elevation[j], h_orig_metadata[i].elevation[j], MASA_FREQUENCY_BANDS );
     310      561016 :                     mvr2r( hMasa->masaMetadata.directional_meta[i].energy_ratio[j], h_orig_metadata[i].energy_ratio[j], MASA_FREQUENCY_BANDS );
     311      561016 :                     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     1111657 :         if ( ( ivas_format == MASA_FORMAT || ivas_format == MASA_ISM_FORMAT ) && ivas_total_brate >= IVAS_384k )
     317             :         {
     318      108834 :             hMasa->config.mergeRatiosOverSubframes = 0;
     319             :         }
     320             : 
     321             :         /* Combine frequency bands and sub-frames */
     322     1111657 :         combine_freqbands_and_subframes( hMasa );
     323             :     }
     324             : 
     325     1302497 :     if ( hMasa->config.numberOfDirections == 2 && hMasa->config.numTwoDirBands < hMasa->config.numCodingBands && ( ivas_format == MASA_FORMAT || ivas_format == MASA_ISM_FORMAT ) )
     326             :     {
     327      422730 :         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      332942 :             ivas_masa_combine_directions( hMasa );
     331             :         }
     332             : 
     333             :         /* If we joined all bands, then metadata is now one directional. */
     334      422730 :         if ( hMasa->config.numTwoDirBands == 0 )
     335             :         {
     336      225318 :             hMasa->config.numberOfDirections = 1;
     337      225318 :             hMasa->masaMetadata.descriptive_meta.numberOfDirections = 0;
     338      225318 :             hQMetaData->no_directions = 1;
     339             :         }
     340             :     }
     341             : 
     342             :     /* Reset qmetadata bit budget */
     343     1302497 :     hQMetaData->metadata_max_bits = hMasa->config.max_metadata_bits;
     344     1302497 :     if ( ivas_format == MASA_FORMAT || ivas_format == MASA_ISM_FORMAT )
     345             :     {
     346     1111657 :         if ( ivas_format == MASA_ISM_FORMAT && ism_mode != ISM_MODE_NONE )
     347             :         {
     348             :             /* write the number of objects in ISM_MASA format*/
     349      320920 :             push_next_indice( hMetaData, nchan_ism - 1, NO_BITS_MASA_ISM_NO_OBJ );
     350      320920 :             hQMetaData->metadata_max_bits -= NO_BITS_MASA_ISM_NO_OBJ;
     351             : 
     352             :             /* write index of separated object if needed */
     353      320920 :             if ( ism_mode == ISM_MASA_MODE_PARAM_ONE_OBJ && nchan_ism > 1 )
     354             :             {
     355       82794 :                 push_next_indice( hMetaData, idx_separated_object, NO_BITS_MASA_ISM_NO_OBJ );
     356       82794 :                 hQMetaData->metadata_max_bits -= NO_BITS_MASA_ISM_NO_OBJ;
     357             :             }
     358             : 
     359             :             /* write ISM importance flag (one per object) */
     360      320920 :             if ( ism_mode == ISM_MASA_MODE_PARAM_ONE_OBJ )
     361             :             {
     362       82794 :                 push_next_indice( hMetaData, hIsmMetaData[0]->ism_imp, ISM_METADATA_FLAG_BITS );
     363       82794 :                 hQMetaData->metadata_max_bits -= ISM_METADATA_FLAG_BITS;
     364             :             }
     365      238126 :             else if ( ism_mode == ISM_MASA_MODE_MASA_ONE_OBJ )
     366             :             {
     367       87818 :                 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       87818 :                     push_next_indice( hMetaData, hIsmMetaData[0]->ism_imp, ISM_METADATA_FLAG_BITS );
     382       87818 :                     hQMetaData->metadata_max_bits -= ISM_METADATA_FLAG_BITS;
     383             : 
     384       87818 :                     if ( hIsmMetaData[0]->ism_imp == ISM_NO_META )
     385             :                     {
     386             :                         /* signal low-rate ISM_NO_META frame */
     387        2830 :                         push_next_indice( hMetaData, 0, ISM_METADATA_MD_FLAG_BITS );
     388        2830 :                         hQMetaData->metadata_max_bits -= ISM_METADATA_MD_FLAG_BITS;
     389             : 
     390             :                         /* signal presence of MD in low-rate ISM_NO_META frame */
     391        2830 :                         push_next_indice( hMetaData, hIsmMetaData[0]->ism_md_lowrate_flag, ISM_METADATA_INACTIVE_FLAG_BITS );
     392        2830 :                         hQMetaData->metadata_max_bits -= ISM_METADATA_INACTIVE_FLAG_BITS;
     393             :                     }
     394             :                 }
     395             :             }
     396      150308 :             else if ( ism_mode == ISM_MASA_MODE_DISC )
     397             :             {
     398      544040 :                 for ( i = 0; i < nchan_ism; i++ )
     399             :                 {
     400      393732 :                     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      393732 :                         push_next_indice( hMetaData, hIsmMetaData[i]->ism_imp, ISM_METADATA_FLAG_BITS );
     415      393732 :                         hQMetaData->metadata_max_bits -= ISM_METADATA_FLAG_BITS;
     416             : 
     417      393732 :                         if ( hIsmMetaData[i]->ism_imp == ISM_NO_META )
     418             :                         {
     419             :                             /* signal low-rate ISM_NO_META frame */
     420       11733 :                             push_next_indice( hMetaData, 0, ISM_METADATA_MD_FLAG_BITS );
     421       11733 :                             hQMetaData->metadata_max_bits -= ISM_METADATA_MD_FLAG_BITS;
     422             : 
     423             :                             /* signal presence of MD in low-rate ISM_NO_META frame */
     424       11733 :                             push_next_indice( hMetaData, hIsmMetaData[i]->ism_md_lowrate_flag, ISM_METADATA_INACTIVE_FLAG_BITS );
     425       11733 :                             hQMetaData->metadata_max_bits -= ISM_METADATA_INACTIVE_FLAG_BITS;
     426             :                         }
     427             :                     }
     428             :                 }
     429             : 
     430      150308 :                 if ( ivas_total_brate == IVAS_128k && nchan_ism >= 3 )
     431             :                 {
     432        4446 :                     push_next_indice( hMetaData, flag_omasa_ener_brate, 1 );
     433        4446 :                     hQMetaData->metadata_max_bits -= 1;
     434             :                 }
     435             :             }
     436             :         }
     437             :         else
     438             :         {
     439      790737 :             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       90320 :                 if ( nchan_ism == 1 || nchan_ism == 2 )
     443             :                 {
     444       32666 :                     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       57654 :                     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      700417 :                 push_next_indice( hMetaData, nchan_transport - 1, MASA_TRANSP_BITS );
     456             :             }
     457      790737 :             hQMetaData->metadata_max_bits -= MASA_TRANSP_BITS;
     458             :         }
     459             : 
     460     1111657 :         if ( ivas_format == MASA_ISM_FORMAT && ism_mode == ISM_MODE_NONE )
     461             :         {
     462       90320 :             if ( nchan_ism >= 3 ) /* if 3 or 4 objects */
     463             :             {
     464       57654 :                 push_next_indice( hMetaData, 5 - nchan_ism, MASA_HEADER_BITS );
     465             :             }
     466             :             else
     467             :             {
     468       32666 :                 push_next_indice( hMetaData, 3, MASA_HEADER_BITS );
     469             :             }
     470       90320 :             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     1021337 :             push_next_indice( hMetaData, 0, MASA_HEADER_BITS );
     477     1021337 :             hQMetaData->metadata_max_bits -= MASA_HEADER_BITS;
     478             :         }
     479     1111657 :         if ( !( ivas_format == MASA_ISM_FORMAT && ism_mode == ISM_MODE_NONE && nchan_ism > 2 ) )
     480             :         {
     481             :             /* write number of directions */
     482     1054003 :             push_next_indice( hMetaData, hQMetaData->no_directions - 1, 1 );
     483     1054003 :             hQMetaData->metadata_max_bits -= 1;
     484             :         }
     485             :         /* write subframe mode */
     486     1111657 :         push_next_indice( hMetaData, hQMetaData->q_direction[0].cfg.nblocks == 1 ? 1 : 0, MASA_SUBFRAME_BITS );
     487     1111657 :         hQMetaData->metadata_max_bits -= MASA_SUBFRAME_BITS;
     488             :     }
     489             : 
     490     1302497 :     if ( ivas_format == MC_FORMAT )
     491             :     {
     492             :         int16_t lfeBitsWritten;
     493      190840 :         lfeBitsWritten = encode_lfe_to_total_energy_ratio( hMasa, hMetaData, ivas_total_brate );
     494      190840 :         hQMetaData->metadata_max_bits -= lfeBitsWritten;
     495             :     }
     496             : 
     497             :     /* Move data from encoder to qmetadata */
     498     1302497 :     if ( ivas_format == MASA_FORMAT || ivas_format == MASA_ISM_FORMAT )
     499             :     {
     500     1111657 :         move_metadata_to_qmetadata( hMasa, hQMetaData );
     501             :     }
     502             : 
     503     1302497 :     if ( hMasa->config.max_metadata_bits < MINIMUM_BIT_BUDGET_NORMAL_META && !hMasa->config.joinedSubframes )
     504             :     {
     505      409021 :         reduce_metadata_further( hMasa, hQMetaData, ivas_format );
     506             : 
     507      409021 :         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      409021 :         push_next_indice( hMetaData, hQMetaData->q_direction[0].cfg.nblocks == 1 ? 1 : 0, MASA_LOWBITRATE_MODE_BITS );
     511      409021 :         hQMetaData->metadata_max_bits -= MASA_LOWBITRATE_MODE_BITS;
     512             :     }
     513             : 
     514             :     /* Encode MASA+ISM metadata */
     515     1302497 :     if ( ivas_format == MASA_ISM_FORMAT && ism_mode == ISM_MASA_MODE_PARAM_ONE_OBJ )
     516             :     {
     517             :         /* encode MASA/ISM energy ratios */
     518       82794 :         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     1219703 :         if ( ivas_format == MASA_ISM_FORMAT )
     523             :         {
     524      328446 :             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     1302497 :     masa_total_brate = ivas_total_brate;
     530     1302497 :     if ( ivas_format == MASA_ISM_FORMAT && ism_mode == ISM_MASA_MODE_DISC )
     531             :     {
     532      150308 :         masa_total_brate = calculate_cpe_brate_MASA_ISM( ism_mode, ivas_total_brate, nchan_ism );
     533             :     }
     534             : 
     535     1302497 :     if ( masa_total_brate >= IVAS_384k )
     536             :     {
     537       74940 :         if ( masa_total_brate >= IVAS_512k )
     538             :         {
     539       28990 :             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       45950 :             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     1227557 :         if ( ( error = ivas_qmetadata_enc_encode( hMetaData, hQMetaData, 0 ) ) != IVAS_ERR_OK )
     555             :         {
     556           0 :             return error;
     557             :         }
     558             :     }
     559             : 
     560     1302497 :     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       82794 :         ivas_omasa_modify_masa_energy_ratios( hQMetaData, hMasa->data.hOmasaData->masa_to_total_energy_ratio );
     564             :     }
     565             : 
     566     1302497 :     *nb_bits_metadata = hMetaData->nb_bits_tot;
     567             : 
     568     1302497 :     if ( ivas_format == MASA_FORMAT && Opt_DTX_ON )
     569             :     {
     570             :         /* save old values */
     571       70127 :         uint8_t numCodingBands = hMasa->config.numCodingBands;
     572       70127 :         uint8_t numTwoDirBands = hMasa->config.numTwoDirBands;
     573       70127 :         int16_t nbands = hQMetaData->q_direction[0].cfg.nbands;
     574       70127 :         uint8_t numberOfDirections = hMasa->config.numberOfDirections;
     575       70127 :         uint8_t numberOfDirectionsMeta = hMasa->masaMetadata.descriptive_meta.numberOfDirections;
     576       70127 :         uint16_t numberOfDirectionsQMetaData = hQMetaData->no_directions;
     577             : 
     578       70127 :         if ( !( hMasa->config.numberOfDirections == 1 && hQMetaData->q_direction->cfg.nbands == 5 ) )
     579             :         {
     580       77655 :             for ( i = 0; i < MASA_MAXIMUM_DIRECTIONS; i++ )
     581             :             {
     582      258850 :                 for ( j = 0; j < MAX_PARAM_SPATIAL_SUBFRAMES; j++ )
     583             :                 {
     584      207080 :                     mvr2r( h_orig_metadata[i].azimuth[j], hMasa->masaMetadata.directional_meta[i].azimuth[j], MASA_FREQUENCY_BANDS );
     585      207080 :                     mvr2r( h_orig_metadata[i].elevation[j], hMasa->masaMetadata.directional_meta[i].elevation[j], MASA_FREQUENCY_BANDS );
     586      207080 :                     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       25885 :             hMasa->config.numCodingBands = 5;
     592       25885 :             hMasa->config.numTwoDirBands = 0;
     593       25885 :             combine_freqbands_and_subframes( hMasa );
     594       25885 :             hQMetaData->q_direction[0].cfg.nbands = 5;
     595             : 
     596       25885 :             if ( hMasa->config.numberOfDirections == 2 && hMasa->config.numTwoDirBands < hMasa->config.numCodingBands )
     597             :             {
     598             :                 /* Combine directions */
     599        4669 :                 ivas_masa_combine_directions( hMasa );
     600             : 
     601             :                 /* If we joined all bands, then metadata is now one directional. */
     602        4669 :                 if ( hMasa->config.numTwoDirBands == 0 )
     603             :                 {
     604        4669 :                     hMasa->config.numberOfDirections = 1;
     605        4669 :                     hMasa->masaMetadata.descriptive_meta.numberOfDirections = 0;
     606        4669 :                     hQMetaData->no_directions = 1;
     607             :                 }
     608             :             }
     609             : 
     610       25885 :             move_metadata_to_qmetadata( hMasa, hQMetaData );
     611             : 
     612      155310 :             for ( j = hQMetaData->q_direction[0].cfg.start_band; j < hQMetaData->q_direction[0].cfg.nbands; ++j )
     613             :             {
     614      129425 :                 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       70127 :         free( h_orig_metadata );
     619             : 
     620       70127 :         ivas_qmetadata_enc_sid_encode( hMetaData, hQMetaData, masa_sid_descriptor, 0, ivas_format );
     621             : 
     622             :         /* restore old values */
     623       70127 :         hMasa->config.numCodingBands = numCodingBands;
     624       70127 :         hMasa->config.numTwoDirBands = numTwoDirBands;
     625       70127 :         hQMetaData->q_direction[0].cfg.nbands = nbands;
     626       70127 :         hMasa->config.numberOfDirections = numberOfDirections;
     627       70127 :         hMasa->masaMetadata.descriptive_meta.numberOfDirections = numberOfDirectionsMeta;
     628       70127 :         hQMetaData->no_directions = numberOfDirectionsQMetaData;
     629             :     }
     630             : 
     631     1302497 :     return IVAS_ERR_OK;
     632             : }
     633             : 
     634             : 
     635             : /*-----------------------------------------------------------------------*
     636             :  * ivas_masa_estimate_energy()
     637             :  *
     638             :  *
     639             :  *-----------------------------------------------------------------------*/
     640             : 
     641     1111657 : 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     1111657 :     maxBin = (int16_t) ( (float) CLDFB_NO_CHANNELS_MAX * (float) input_frame / L_FRAME48k + 0.5f );
     655             : 
     656     1111657 :     l_ts = input_frame / CLDFB_NO_COL_MAX;
     657             : 
     658     5558285 :     for ( block_m_idx = 0; block_m_idx < MAX_PARAM_SPATIAL_SUBFRAMES; block_m_idx++ )
     659             :     {
     660     4446628 :         mrange[0] = hMasa->config.block_grouping[block_m_idx];
     661     4446628 :         mrange[1] = hMasa->config.block_grouping[block_m_idx + 1];
     662             : 
     663     4446628 :         set_zero( hMasa->data.energy[block_m_idx], MASA_FREQUENCY_BANDS );
     664             : 
     665    22233140 :         for ( ts = mrange[0]; ts < mrange[1]; ts++ )
     666             :         {
     667    49305216 :             for ( i = 0; i < nchan_transport; i++ )
     668             :             {
     669    31518704 :                 cldfbAnalysis_ts( &( data_f[i][l_ts * ts] ), Input_RealBuffer[i], Input_ImagBuffer[i], l_ts, hMasa->data.cldfbAnaEnc[i] );
     670             :             }
     671             : 
     672   444662800 :             for ( band_m_idx = 0; band_m_idx < MASA_FREQUENCY_BANDS; band_m_idx++ )
     673             :             {
     674   426876288 :                 brange[0] = hMasa->config.band_grouping[band_m_idx];
     675   426876288 :                 brange[1] = hMasa->config.band_grouping[band_m_idx + 1];
     676             : 
     677  1183325184 :                 for ( i = 0; i < nchan_transport; i++ )
     678             :                 {
     679   756448896 :                     if ( brange[0] > maxBin )
     680             :                     {
     681     2860320 :                         hMasa->data.energy[block_m_idx][band_m_idx] = 0;
     682     2860320 :                         continue;
     683             :                     }
     684   753588576 :                     else if ( brange[1] >= maxBin )
     685             :                     {
     686    34137024 :                         brange[1] = maxBin;
     687             :                     }
     688             : 
     689  2573275616 :                     for ( j = brange[0]; j < brange[1]; j++ )
     690             :                     {
     691  1819687040 :                         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     1111657 :     return;
     699             : }
     700             : 
     701             : 
     702             : /*-----------------------------------------------------------------------*
     703             :  * ivas_masa_enc_config()
     704             :  *
     705             :  * Frame-by-frame configuration of MASA encoder
     706             :  *-----------------------------------------------------------------------*/
     707             : 
     708     1118767 : 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     1118767 :     error = IVAS_ERR_OK;
     727             : 
     728     1118767 :     hMasa = st_ivas->hMasa;
     729     1118767 :     hQMetaData = st_ivas->hQMetaData;
     730     1118767 :     ivas_format = st_ivas->hEncoderConfig->ivas_format;
     731     1118767 :     ivas_total_brate = st_ivas->hEncoderConfig->ivas_total_brate;
     732             : 
     733     1118767 :     ism_total_brate = 0;
     734     1118767 :     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      885264 :         for ( i = 0; i < st_ivas->nSCE; i++ )
     737             :         {
     738      564344 :             ism_total_brate += st_ivas->hSCE[i]->element_brate;
     739             :         }
     740             :     }
     741             : 
     742     1118767 :     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     1118767 :     hQMetaData->is_masa_ivas_format = 1;
     745             : 
     746     1118767 :     if ( ivas_format == MASA_FORMAT || ivas_format == MASA_ISM_FORMAT )
     747             :     {
     748     1111657 :         masa_metadata_direction_alignment( hMasa );
     749             : 
     750     1111657 :         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     1111657 :         if ( hMasa->data.sync_state.frame_mode == MASA_FRAME_1SF && hMasa->data.sync_state.prev_offset != 0 )
     753             :         {
     754             :             /* average over sub-frames */
     755      142467 :             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     1111657 :         detect_metadata_composition( hMasa, &joinedSubframes, &coherencePresent, &isActualTwoDir );
     760     1111657 :         hMasa->config.joinedSubframes = joinedSubframes;
     761     1111657 :         hMasa->config.coherencePresent = coherencePresent;
     762     1111657 :         hMasa->config.numberOfDirections = ( hMasa->masaMetadata.descriptive_meta.numberOfDirections + 1 ) == 2 && isActualTwoDir ? 2 : 1;
     763             :     }
     764        7110 :     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        7110 :         hMasa->config.joinedSubframes = 0;
     768        7110 :         hMasa->config.numberOfDirections = 1;
     769             :     }
     770             : 
     771     1118767 :     if ( ivas_format == MASA_ISM_FORMAT )
     772             :     {
     773      411240 :         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      707527 :         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     1118767 :     if ( hMasa->config.numberOfDirections == 2 )
     782             :     {
     783      432192 :         set_f( hMasa->data.importanceWeight, 1.0f, hMasa->config.numCodingBands );
     784             : 
     785      432192 :         if ( hMasa->config.numCodingBands == 5 )
     786             :         {
     787      280403 :             hMasa->data.importanceWeight[4] = 0.7f;
     788             :         }
     789      151789 :         else if ( hMasa->config.numCodingBands == 8 )
     790             :         {
     791       25850 :             hMasa->data.importanceWeight[7] = 0.7f;
     792             :         }
     793      125939 :         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      125939 :         else if ( hMasa->config.numCodingBands == 12 )
     799             :         {
     800       55807 :             hMasa->data.importanceWeight[10] = 0.7f;
     801       55807 :             hMasa->data.importanceWeight[11] = 0.1f;
     802             :         }
     803       70132 :         else if ( hMasa->config.numCodingBands == 18 )
     804             :         {
     805       47282 :             hMasa->data.importanceWeight[14] = 0.8f;
     806       47282 :             hMasa->data.importanceWeight[15] = 0.5f;
     807       47282 :             hMasa->data.importanceWeight[16] = 0.2f;
     808       47282 :             hMasa->data.importanceWeight[17] = 0.0f;
     809             :         }
     810       22850 :         else if ( hMasa->config.numCodingBands == 24 )
     811             :         {
     812       22850 :             hMasa->data.importanceWeight[20] = 0.8f;
     813       22850 :             hMasa->data.importanceWeight[21] = 0.5f;
     814       22850 :             hMasa->data.importanceWeight[22] = 0.2f;
     815       22850 :             hMasa->data.importanceWeight[23] = 0.0f;
     816             :         }
     817             : 
     818      432192 :         if ( hMasa->config.numTwoDirBands == hMasa->config.numCodingBands )
     819             :         {
     820        7944 :             set_c( (int8_t *) hMasa->data.twoDirBands, 1, hMasa->config.numCodingBands );
     821             :         }
     822             :     }
     823             :     else
     824             :     {
     825      686575 :         set_c( (int8_t *) hMasa->data.twoDirBands, 0, hMasa->config.numCodingBands );
     826             :     }
     827             : 
     828             :     /* Set qmeta to correct values */
     829     1118767 :     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     2444408 :     for ( i = 0; i < hQMetaData->no_directions; i++ )
     835             :     {
     836     1325641 :         hQMetaData->q_direction[i].cfg.nbands = hMasa->config.numCodingBands;
     837     1325641 :         hQMetaData->q_direction[i].cfg.nblocks = hMasa->config.joinedSubframes == TRUE ? 1 : MAX_PARAM_SPATIAL_SUBFRAMES;
     838             : 
     839     1325641 :         if ( ivas_format == MC_FORMAT )
     840             :         {
     841        7110 :             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     1318531 :             hQMetaData->q_direction[i].cfg.mc_ls_setup = MC_LS_SETUP_INVALID;
     847             :         }
     848             :     }
     849             : 
     850     1118767 :     hQMetaData->all_coherence_zero = !hMasa->config.coherencePresent;
     851             : 
     852     1118767 :     ivas_set_qmetadata_maxbit_req( hQMetaData, ivas_format );
     853             : 
     854             :     /* Find maximum band usable */
     855     1118767 :     maxBin = (int16_t) ( st_ivas->hEncoderConfig->input_Fs * INV_CLDFB_BANDWIDTH );
     856     1118767 :     maxBand = 0;
     857    28909736 :     while ( maxBand <= MASA_FREQUENCY_BANDS && MASA_band_grouping_24[maxBand] <= maxBin )
     858             :     {
     859    27790969 :         maxBand++;
     860             :     }
     861     1118767 :     maxBand--;
     862             : 
     863     1118767 :     st_ivas->hQMetaData->q_direction->cfg.inactiveBands = 0;
     864     1118767 :     masa_total_brate = ivas_total_brate;
     865     1118767 :     if ( ivas_format == MASA_ISM_FORMAT && st_ivas->ism_mode == ISM_MASA_MODE_DISC )
     866             :     {
     867      150308 :         masa_total_brate = calculate_cpe_brate_MASA_ISM( st_ivas->ism_mode, ivas_total_brate, st_ivas->hEncoderConfig->nchan_ism );
     868             :     }
     869     1118767 :     if ( masa_total_brate >= IVAS_384k && ( ivas_format == MASA_FORMAT || ivas_format == MASA_ISM_FORMAT ) )
     870             :     {
     871             :         int16_t continueLoop;
     872       74940 :         continueLoop = 1;
     873      251696 :         while ( maxBand > 5 && continueLoop )
     874             :         {
     875      606656 :             for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
     876             :             {
     877      500606 :                 if ( hMasa->data.energy[sf][maxBand - 1] > 100000 )
     878             :                 {
     879       70706 :                     continueLoop = 0;
     880       70706 :                     break;
     881             :                 }
     882             :             }
     883      176756 :             if ( continueLoop )
     884             :             {
     885      106050 :                 maxBand--;
     886             :             }
     887             :         }
     888             : 
     889       74940 :         if ( maxBand < MASA_MAXIMUM_CODING_SUBBANDS )
     890             :         {
     891       15616 :             st_ivas->hQMetaData->q_direction->cfg.inactiveBands = MASA_MAXIMUM_CODING_SUBBANDS - maxBand;
     892             :         }
     893             :         else
     894             :         {
     895       59324 :             st_ivas->hQMetaData->q_direction->cfg.inactiveBands = 0;
     896             :         }
     897             :     }
     898             : 
     899     1118767 :     masa_sample_rate_band_correction( &( hMasa->config ), hMasa->data.band_mapping, hQMetaData, maxBand, masa_total_brate >= IVAS_384k, NULL );
     900             : 
     901     1118767 :     if ( hMasa->config.numTwoDirBands >= hMasa->config.numCodingBands )
     902             :     {
     903        9462 :         hMasa->config.numTwoDirBands = hMasa->config.numCodingBands;
     904        9462 :         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     1118767 :     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      352536 :         st_ivas->hCPE[0]->hStereoDft->hConfig->force_mono_transmission = ( ivas_total_brate - ism_total_brate < MASA_STEREO_MIN_BITRATE ) ? 1 : 0;
     911             :     }
     912             : 
     913     1118767 :     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      320920 :         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      133660 :             st_ivas->hMasa->data.hOmasaData->lp_noise_CPE = st_ivas->hCPE[0]->hCoreCoder[0]->lp_noise;
     918             :         }
     919             :         else
     920             :         {
     921      187260 :             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     1118767 :     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      158916 : 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      158916 :     float surrCohSignificanceCoef = 0.4f;
     946      158916 :     float threshold = 0.1f;
     947             : 
     948      391157 :     for ( sf = 0; sf < nSubFrames; sf++ )
     949             :     {
     950      273396 :         surrCohToTotalSum = 0.0f;
     951      273396 :         surrCohToTotalTimesDiffSum = 0.0f;
     952      273396 :         diffSum = 0.0f;
     953     6418230 :         for ( band = 0; band < nBands; band++ )
     954             :         {
     955     6144834 :             surrCohToTotal = diffuse_to_total_ratio[sf][band] * surroundingCoherence[sf][band];
     956     6144834 :             surrCohToTotalSum += surrCohToTotal;
     957     6144834 :             surrCohToTotalTimesDiffSum += diffuse_to_total_ratio[sf][band] * surrCohToTotal;
     958     6144834 :             diffSum += diffuse_to_total_ratio[sf][band];
     959             :         }
     960      273396 :         significanceMeasure1 = surrCohToTotalSum / (float) nBands;
     961      273396 :         significanceMeasure2 = surrCohSignificanceCoef * surrCohToTotalTimesDiffSum / ( diffSum + EPSILON );
     962      273396 :         significanceMeasure = max( significanceMeasure1, significanceMeasure2 );
     963             : 
     964      273396 :         if ( significanceMeasure > threshold )
     965             :         {
     966       41155 :             return 1; /* Surrounding coherence was significant in at least one subframe */
     967             :         }
     968             :     }
     969             : 
     970      117761 :     return 0; /* Surrounding coherence was not significant in any subframe */
     971             : }
     972             : 
     973             : 
     974             : /*-----------------------------------------------------------------------*
     975             :  * Local functions
     976             :  *-----------------------------------------------------------------------*/
     977             : 
     978     1137542 : 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     1137542 :     numCodingBands = hMasa->config.numCodingBands;
    1004     1137542 :     numDirections = hMasa->config.numberOfDirections;
    1005     1137542 :     numSf = hMasa->config.joinedSubframes == TRUE ? 1 : MAX_PARAM_SPATIAL_SUBFRAMES;
    1006     1137542 :     hMeta = &( hMasa->masaMetadata );
    1007             : 
    1008     1137542 :     mergeRatiosOverSubframes = hMasa->config.mergeRatiosOverSubframes;
    1009     1137542 :     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     1137542 :     if ( numSf == 1 )
    1015             :     {
    1016     1542288 :         for ( j = 1; j < MAX_PARAM_SPATIAL_SUBFRAMES; j++ )
    1017             :         {
    1018    28917900 :             for ( k = 0; k < MASA_FREQUENCY_BANDS; k++ )
    1019             :             {
    1020    27761184 :                 hMasa->data.energy[0][k] += hMasa->data.energy[j][k];
    1021             :             }
    1022             :         }
    1023             :     }
    1024             : 
    1025     1137542 :     if ( numCodingBands <= MAX_REDUCED_NBANDS )
    1026             :     {
    1027             :         /* reduce metadata *frequency* resolution. time resolution is not touched */
    1028     2450255 :         for ( i = 0; i < numDirections; i++ )
    1029             :         {
    1030     5696451 :             for ( j = 0; j < numSf; j++ ) /* NB: for numSf==1, operates only on first sub-frame */
    1031             :             {
    1032   106583550 :                 for ( k = 0; k < MASA_FREQUENCY_BANDS; k++ )
    1033             :                 {
    1034   102320208 :                     aziRad = hMeta->directional_meta[i].azimuth[j][k] / 180.0f * EVS_PI;
    1035   102320208 :                     eleRad = hMeta->directional_meta[i].elevation[j][k] / 180.0f * EVS_PI;
    1036   102320208 :                     vecLen = hMeta->directional_meta[i].energy_ratio[j][k] * hMasa->data.energy[j][k];
    1037             : 
    1038   102320208 :                     x[i][j][k] = cosf( aziRad ) * cosf( eleRad ) * vecLen;
    1039   102320208 :                     y[i][j][k] = sinf( aziRad ) * cosf( eleRad ) * vecLen;
    1040   102320208 :                     z[i][j][k] = sinf( eleRad ) * vecLen;
    1041             :                 }
    1042             :             }
    1043             :         }
    1044             : 
    1045     2450255 :         for ( i = 0; i < numDirections; i++ )
    1046             :         {
    1047     5696451 :             for ( j = 0; j < numSf; j++ )
    1048             :             {
    1049    32695617 :                 for ( k = 0; k < numCodingBands; k++ )
    1050             :                 {
    1051    28432275 :                     brange[0] = hMasa->data.band_mapping[k];
    1052    28432275 :                     brange[1] = hMasa->data.band_mapping[k + 1];
    1053             : 
    1054    28432275 :                     xSum = 0.0f;
    1055    28432275 :                     ySum = 0.0f;
    1056    28432275 :                     zSum = 0.0f;
    1057    28432275 :                     energySum = 0.0f;
    1058    28432275 :                     spreadCohSum = 0.0f;
    1059             : 
    1060   128648548 :                     for ( m = brange[0]; m < brange[1]; m++ )
    1061             :                     {
    1062   100216273 :                         xSum += x[i][j][m];
    1063   100216273 :                         ySum += y[i][j][m];
    1064   100216273 :                         zSum += z[i][j][m];
    1065   100216273 :                         energySum += hMasa->data.energy[j][m];
    1066             :                     }
    1067             : 
    1068    28432275 :                     aziRad = atan2f( ySum, xSum );
    1069    28432275 :                     eleRad = atan2f( zSum, sqrtf( xSum * xSum + ySum * ySum ) );
    1070             : 
    1071    28432275 :                     hMeta->directional_meta[i].azimuth[j][k] = aziRad / EVS_PI * 180.0f;
    1072    28432275 :                     hMeta->directional_meta[i].elevation[j][k] = eleRad / EVS_PI * 180.0f;
    1073             : 
    1074    28432275 :                     vecLen = sqrtf( xSum * xSum + ySum * ySum + zSum * zSum );
    1075    28432275 :                     hMeta->directional_meta[i].energy_ratio[j][k] = vecLen / ( energySum + EPSILON );
    1076             : 
    1077    28432275 :                     if ( computeCoherence )
    1078             :                     {
    1079    65693318 :                         for ( m = brange[0]; m < brange[1]; m++ )
    1080             :                         {
    1081    48873580 :                             spreadCohSum += hMeta->directional_meta[i].spread_coherence[j][m] * hMasa->data.energy[j][m];
    1082             :                         }
    1083    16819738 :                         hMeta->directional_meta[i].spread_coherence[j][k] = spreadCohSum / ( energySum + EPSILON );
    1084             : 
    1085    16819738 :                         if ( i == 0 )
    1086             :                         {
    1087    11653209 :                             surrCohSum = 0.0f;
    1088    45371013 :                             for ( m = brange[0]; m < brange[1]; m++ )
    1089             :                             {
    1090    33717804 :                                 surrCohSum += hMeta->common_meta.surround_coherence[j][m] * hMasa->data.energy[j][m];
    1091             :                             }
    1092    11653209 :                             hMeta->common_meta.surround_coherence[j][k] = surrCohSum / ( energySum + EPSILON );
    1093             :                         }
    1094             :                     }
    1095             : 
    1096    28432275 :                     if ( i == 0 )
    1097             :                     {
    1098    20156817 :                         energy[j][k] = energySum;
    1099             :                     }
    1100             :                 }
    1101             :             }
    1102             :         }
    1103             :     }
    1104      120396 :     else if ( mergeRatiosOverSubframes ) /* keep frequency resolution */
    1105             :     {
    1106      123390 :         for ( j = 0; j < numSf; j++ )
    1107             :         {
    1108     2463800 :             for ( k = 0; k < numCodingBands; k++ )
    1109             :             {
    1110     2365088 :                 energy[j][k] = hMasa->data.energy[j][k];
    1111             :             }
    1112             :         }
    1113             :     }
    1114             : 
    1115     1137542 :     if ( mergeRatiosOverSubframes )
    1116             :     {
    1117     5155228 :         for ( k = 0; k < numCodingBands; k++ )
    1118             :         {
    1119     4482321 :             energySum = 0.0f;
    1120    22411605 :             for ( j = 0; j < numSf; j++ )
    1121             :             {
    1122    17929284 :                 energySum += energy[j][k];
    1123             :             }
    1124             : 
    1125     4482321 :             if ( computeCoherence )
    1126             :             {
    1127     2696265 :                 surrCohSum = 0.0f;
    1128    13481325 :                 for ( j = 0; j < numSf; j++ )
    1129             :                 {
    1130    10785060 :                     surrCohSum += energy[j][k] * hMeta->common_meta.surround_coherence[j][k];
    1131             :                 }
    1132     2696265 :                 surrCohTemp = surrCohSum / ( energySum + EPSILON );
    1133             : 
    1134    13481325 :                 for ( j = 0; j < numSf; j++ )
    1135             :                 {
    1136    10785060 :                     hMeta->common_meta.surround_coherence[j][k] = surrCohTemp;
    1137             :                 }
    1138             :             }
    1139             : 
    1140    10515352 :             for ( i = 0; i < numDirections; i++ )
    1141             :             {
    1142     6033031 :                 energyRatioSum = 0.0f;
    1143    30165155 :                 for ( j = 0; j < numSf; j++ )
    1144             :                 {
    1145    24132124 :                     energyRatioSum += energy[j][k] * hMeta->directional_meta[i].energy_ratio[j][k];
    1146             :                 }
    1147     6033031 :                 energyRatioTemp = energyRatioSum / ( energySum + EPSILON );
    1148             : 
    1149    30165155 :                 for ( j = 0; j < numSf; j++ )
    1150             :                 {
    1151    24132124 :                     hMeta->directional_meta[i].energy_ratio[j][k] = energyRatioTemp;
    1152             :                 }
    1153             :             }
    1154             :         }
    1155             :     }
    1156             : 
    1157     1137542 :     return;
    1158             : }
    1159             : 
    1160             : 
    1161             : /*-------------------------------------------------------------------*
    1162             :  * ivas_masa_combine_directions()
    1163             :  *
    1164             :  *
    1165             :  *-------------------------------------------------------------------*/
    1166             : 
    1167      427399 : 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      427399 :     numCodingBands = hMasa->config.numCodingBands;
    1199      427399 :     numDirections = hMasa->config.numberOfDirections;
    1200      427399 :     numSf = hMasa->config.joinedSubframes == TRUE ? 1 : MAX_PARAM_SPATIAL_SUBFRAMES;
    1201             : 
    1202      427399 :     hMeta = &( hMasa->masaMetadata );
    1203             : 
    1204      427399 :     computeCoherence = hMasa->config.useCoherence && hMasa->config.coherencePresent;
    1205             : 
    1206     1282197 :     for ( i = 0; i < numDirections; i++ )
    1207             :     {
    1208     3393184 :         for ( j = 0; j < numSf; j++ )
    1209             :         {
    1210    30863046 :             for ( k = 0; k < numCodingBands; k++ )
    1211             :             {
    1212    28324660 :                 aziRad = hMeta->directional_meta[i].azimuth[j][k] / 180.0f * EVS_PI;
    1213    28324660 :                 eleRad = hMeta->directional_meta[i].elevation[j][k] / 180.0f * EVS_PI;
    1214    28324660 :                 vecLen = hMeta->directional_meta[i].energy_ratio[j][k];
    1215             : 
    1216    28324660 :                 x[i][j][k] = cosf( aziRad ) * cosf( eleRad ) * vecLen;
    1217    28324660 :                 y[i][j][k] = sinf( aziRad ) * cosf( eleRad ) * vecLen;
    1218    28324660 :                 z[i][j][k] = sinf( eleRad ) * vecLen;
    1219             :             }
    1220             :         }
    1221             :     }
    1222             : 
    1223             :     /* Compute sum vector */
    1224     1696592 :     for ( j = 0; j < numSf; j++ )
    1225             :     {
    1226    15431523 :         for ( k = 0; k < numCodingBands; k++ )
    1227             :         {
    1228    14162330 :             xSum[j][k] = x[0][j][k] + x[1][j][k];
    1229    14162330 :             ySum[j][k] = y[0][j][k] + y[1][j][k];
    1230    14162330 :             zSum[j][k] = z[0][j][k] + z[1][j][k];
    1231    14162330 :             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      427399 :     if ( hMasa->config.numTwoDirBands > 0 )
    1236             :     {
    1237             :         /* Estimate the importance of having two directions instead of one */
    1238     2378017 :         for ( i = 0; i < numCodingBands; i++ )
    1239             :         {
    1240     2180605 :             importance[i] = 0.0f;
    1241     7824329 :             for ( j = 0; j < numSf; j++ )
    1242             :             {
    1243     5643724 :                 tempImportance = hMeta->directional_meta[0].energy_ratio[j][i] + hMeta->directional_meta[1].energy_ratio[j][i] - sumVecLen[j][i];
    1244     5643724 :                 importance[i] += tempImportance;
    1245             :             }
    1246     2180605 :             importance[i] /= (float) numSf;
    1247     2180605 :             importance[i] *= hMasa->data.importanceWeight[i];
    1248             :         }
    1249             : 
    1250             :         /* Determine bands where to use two directions */
    1251      197412 :         find_n_largest( importance, indicesOfLargest, numCodingBands, hMasa->config.numTwoDirBands );
    1252             :     }
    1253             : 
    1254     5574486 :     for ( i = 0; i < numCodingBands; i++ )
    1255             :     {
    1256     5147087 :         hMasa->data.twoDirBands[i] = 0;
    1257             :     }
    1258             : 
    1259     1184096 :     for ( i = 0; i < hMasa->config.numTwoDirBands; i++ )
    1260             :     {
    1261      756697 :         hMasa->data.twoDirBands[indicesOfLargest[i]] = 1;
    1262             :     }
    1263             : 
    1264             :     /* Combine directions on the remaining bands */
    1265     5574486 :     for ( i = 0; i < numCodingBands; i++ )
    1266             :     {
    1267     5147087 :         if ( hMasa->data.twoDirBands[i] == 0 )
    1268             :         {
    1269    16487507 :             for ( j = 0; j < numSf; j++ )
    1270             :             {
    1271    12097117 :                 aziRad = atan2f( ySum[j][i], xSum[j][i] );
    1272    12097117 :                 eleRad = atan2f( zSum[j][i], sqrtf( xSum[j][i] * xSum[j][i] + ySum[j][i] * ySum[j][i] ) );
    1273             : 
    1274    12097117 :                 hMeta->directional_meta[0].azimuth[j][i] = aziRad / EVS_PI * 180.0f;
    1275    12097117 :                 hMeta->directional_meta[0].elevation[j][i] = eleRad / EVS_PI * 180.0f;
    1276             : 
    1277    12097117 :                 ratioSum = hMeta->directional_meta[0].energy_ratio[j][i] + hMeta->directional_meta[1].energy_ratio[j][i];
    1278    12097117 :                 if ( computeCoherence )
    1279             :                 {
    1280     4002758 :                     hMeta->directional_meta[0].spread_coherence[j][i] =
    1281     4002758 :                         ( 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    12097117 :                 ambience2dir = 1.0f - ratioSum;
    1285    12097117 :                 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    12097117 :                 hMeta->directional_meta[1].energy_ratio[j][i] = 0.0f;
    1287    12097117 :                 hMeta->common_meta.diffuse_to_total_ratio[j][i] = 1.0f - hMeta->directional_meta[0].energy_ratio[j][i];
    1288    12097117 :                 if ( computeCoherence )
    1289             :                 {
    1290     4002758 :                     ambience1dir = 1.0f - hMeta->directional_meta[0].energy_ratio[j][i];
    1291     4002758 :                     ambienceIncrease = max( ambience1dir - ambience2dir, 0.0f );
    1292             : 
    1293     4002758 :                     origSurrCohEne = ambience2dir * hMeta->common_meta.surround_coherence[j][i];
    1294     4002758 :                     newSurrCohEne = ambienceIncrease * hMeta->directional_meta[0].spread_coherence[j][i];
    1295     4002758 :                     hMeta->common_meta.surround_coherence[j][i] = min( 1.0f, ( origSurrCohEne + newSurrCohEne ) / ( ambience1dir + EPSILON ) );
    1296             :                 }
    1297             :             }
    1298             :         }
    1299             :     }
    1300             : 
    1301      427399 :     return;
    1302             : }
    1303             : 
    1304             : 
    1305      197412 : 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     2378017 :     for ( j = 0; j < numElements; j++ )
    1317             :     {
    1318     2180605 :         values[j] = input[j];
    1319             :     }
    1320             : 
    1321      954109 :     for ( i = 0; i < numLargest; i++ )
    1322             :     {
    1323      756697 :         largestValue = values[0];
    1324      756697 :         largestIndex = 0;
    1325    11277099 :         for ( j = 1; j < numElements; j++ )
    1326             :         {
    1327    10520402 :             if ( values[j] > largestValue )
    1328             :             {
    1329     1545972 :                 largestValue = values[j];
    1330     1545972 :                 largestIndex = j;
    1331             :             }
    1332             :         }
    1333      756697 :         largestIndices[i] = largestIndex;
    1334      756697 :         values[largestIndex] = -1.0f;
    1335             :     }
    1336             : 
    1337      197412 :     return;
    1338             : }
    1339             : 
    1340             : 
    1341     1137542 : 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     1137542 :     numCodingBands = hMasa->config.numCodingBands;
    1352     1137542 :     numDirections = hMasa->config.numberOfDirections;
    1353     1137542 :     numSf = hMasa->config.joinedSubframes == TRUE ? 1 : MAX_PARAM_SPATIAL_SUBFRAMES;
    1354     1137542 :     hMeta = &( hMasa->masaMetadata );
    1355             : 
    1356     2481958 :     for ( dir = 0; dir < numDirections; dir++ )
    1357             :     {
    1358     5359243 :         for ( sf = 0; sf < numSf; sf++ )
    1359             :         {
    1360    39124985 :             for ( band = 0; band < numCodingBands; band++ )
    1361             :             {
    1362    35110158 :                 hQMeta->q_direction[dir].band_data[band].azimuth[sf] = hMeta->directional_meta[dir].azimuth[sf][band];
    1363    35110158 :                 hQMeta->q_direction[dir].band_data[band].elevation[sf] = hMeta->directional_meta[dir].elevation[sf][band];
    1364    35110158 :                 hQMeta->q_direction[dir].band_data[band].energy_ratio[sf] = hMeta->directional_meta[dir].energy_ratio[sf][band];
    1365    35110158 :                 hQMeta->q_direction[dir].band_data[band].spherical_index[sf] = hMeta->directional_meta[dir].spherical_index[sf][band];
    1366    35110158 :                 if ( hQMeta->q_direction[dir].coherence_band_data != NULL )
    1367             :                 {
    1368    27650494 :                     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     4530994 :     for ( sf = 0; sf < numSf; sf++ )
    1375             :     {
    1376    32308987 :         for ( band = 0; band < numCodingBands; band++ )
    1377             :         {
    1378    28915535 :             if ( hQMeta->surcoh_band_data != NULL )
    1379             :             {
    1380    21455871 :                 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     1137542 :     if ( numDirections > 1 )
    1386             :     {
    1387     2578237 :         for ( band = 0; band < numCodingBands; band++ )
    1388             :         {
    1389     2371363 :             hQMeta->twoDirBands[band] = hMasa->data.twoDirBands[band];
    1390             :         }
    1391      206874 :         hQMeta->numTwoDirBands = hMasa->config.numTwoDirBands;
    1392             :     }
    1393             : 
    1394             :     /* Copy spread coherence for DCT-based coding */
    1395     1137542 :     if ( numSf == 1 && hMasa->config.useCoherence )
    1396             :     {
    1397      498477 :         for ( dir = 0; dir < numDirections; dir++ )
    1398             :         {
    1399     1134368 :             for ( sf = 1; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1400             :             {
    1401    14557314 :                 for ( band = 0; band < numCodingBands; band++ )
    1402             :                 {
    1403    13706538 :                     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     1137542 :     return;
    1410             : }
    1411             : 
    1412             : 
    1413             : /* This function studies parametric MASA metadata to provide information for codec configuration */
    1414     1111657 : 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     1111657 :     uint8_t dirValid[2] = { FALSE, FALSE };
    1425     1111657 :     uint8_t cohPresent = FALSE;
    1426     1111657 :     uint8_t sfDiffer = FALSE;
    1427             :     uint8_t sfSimilar;
    1428             : 
    1429     1111657 :     hMeta = &( hMasa->masaMetadata );
    1430     1111657 :     numDir = hMeta->descriptive_meta.numberOfDirections + 1;
    1431             : 
    1432     1111657 :     *isTwoDir = FALSE;
    1433             : 
    1434             :     /* First check for valid two directions */
    1435     1111657 :     if ( numDir == 1 )
    1436             :     {
    1437      665685 :         dirValid[0] = TRUE;
    1438             :     }
    1439             :     else
    1440             :     {
    1441             :         /* Default assumption */
    1442      445972 :         *isTwoDir = TRUE;
    1443             : 
    1444             :         /* Check for direct-to-total ratio values */
    1445     1337916 :         for ( dir = 0; dir < numDir; dir++ )
    1446             :         {
    1447      891944 :             sf = 0;
    1448     1832218 :             while ( !dirValid[dir] && sf < MAX_PARAM_SPATIAL_SUBFRAMES )
    1449             :             {
    1450      940274 :                 band = 0;
    1451     3503842 :                 while ( !dirValid[dir] && band < MASA_FREQUENCY_BANDS )
    1452             :                 {
    1453     2563568 :                     if ( hMeta->directional_meta[dir].energy_ratio[sf][band] >= MASA_RATIO_THRESHOLD )
    1454             :                     {
    1455      876240 :                         dirValid[dir] = TRUE;
    1456             :                     }
    1457     2563568 :                     band++;
    1458             :                 }
    1459      940274 :                 sf++;
    1460             :             }
    1461             :         }
    1462             : 
    1463      445972 :         if ( dirValid[1] == FALSE )
    1464             :         {
    1465             :             /* This handles also case where both are false. Then we just use first dir metadata. */
    1466        5664 :             *isTwoDir = FALSE;
    1467             :         }
    1468      440308 :         else if ( dirValid[0] == FALSE && dirValid[1] == TRUE )
    1469             :         {
    1470        8116 :             *isTwoDir = FALSE;
    1471             :             /* Copy data to first direction */
    1472       40580 :             for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1473             :             {
    1474      811600 :                 for ( band = 0; band < MASA_FREQUENCY_BANDS; band++ )
    1475             :                 {
    1476      779136 :                     hMeta->directional_meta[0].spherical_index[sf][band] = hMeta->directional_meta[1].spherical_index[sf][band];
    1477      779136 :                     hMeta->directional_meta[0].azimuth[sf][band] = hMeta->directional_meta[1].azimuth[sf][band];
    1478      779136 :                     hMeta->directional_meta[0].elevation[sf][band] = hMeta->directional_meta[1].elevation[sf][band];
    1479      779136 :                     hMeta->directional_meta[0].energy_ratio[sf][band] = hMeta->directional_meta[1].energy_ratio[sf][band];
    1480      779136 :                     hMeta->directional_meta[0].spread_coherence[sf][band] = hMeta->directional_meta[1].spread_coherence[sf][band];
    1481             :                 }
    1482             :             }
    1483             :         }
    1484             : 
    1485      445972 :         if ( *isTwoDir == FALSE )
    1486             :         {
    1487             :             /* Further checks will be done with just one direction */
    1488       13780 :             numDir = 1;
    1489             :         }
    1490             :     }
    1491             : 
    1492             :     /* Check if data over subframes is identical. Check is done by comparing to first subframe. */
    1493     1111657 :     sfSimilar = TRUE;
    1494     1111657 :     sf = 1;
    1495     3185967 :     while ( ( sfSimilar == TRUE ) && ( sf < MAX_PARAM_SPATIAL_SUBFRAMES ) )
    1496             :     {
    1497     2074310 :         sfSimilar = are_masa_subframes_similar( hMeta, 0, hMeta, sf );
    1498     2074310 :         sf++;
    1499             :     }
    1500     1111657 :     sfDiffer = sfSimilar == TRUE ? FALSE : TRUE;
    1501             : 
    1502             :     /* Further checks can be done with just one subframe if they are identical */
    1503     1111657 :     nSubFrames = sfDiffer == TRUE ? MAX_PARAM_SPATIAL_SUBFRAMES : 1;
    1504             : 
    1505             :     /* Check spread coherence */
    1506     1111657 :     dir = 0;
    1507     2239809 :     while ( cohPresent == FALSE && dir < numDir )
    1508             :     {
    1509     1128152 :         sf = 0;
    1510     2430679 :         while ( cohPresent == FALSE && sf < nSubFrames )
    1511             :         {
    1512     1302527 :             band = 0;
    1513    13135144 :             while ( cohPresent == FALSE && band < MASA_FREQUENCY_BANDS )
    1514             :             {
    1515             :                 /* Check coherences for presence of coherence */
    1516    11832617 :                 if ( hMeta->directional_meta[dir].spread_coherence[sf][band] >= MASA_COHERENCE_THRESHOLD )
    1517             :                 {
    1518      974671 :                     cohPresent = TRUE;
    1519             :                 }
    1520    11832617 :                 band++;
    1521             :             }
    1522     1302527 :             sf++;
    1523             :         }
    1524     1128152 :         dir++;
    1525             :     }
    1526             : 
    1527             :     /* Check surround coherence separately if we do not have already knowledge of coherence */
    1528     1111657 :     if ( cohPresent == FALSE )
    1529             :     {
    1530      136986 :         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     1111657 :     *joinedSubframes = sfDiffer == TRUE ? FALSE : TRUE;
    1535     1111657 :     *coherencePresent = cohPresent;
    1536             : 
    1537     1111657 :     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     1111657 : 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     1111657 :     hMeta = &( hMasa->masaMetadata );
    1553     1111657 :     numDirs = hMasa->config.numberOfDirections;
    1554             : 
    1555     5558285 :     for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1556             :     {
    1557   111165700 :         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   106719072 :             hMeta->common_meta.remainder_to_total_ratio[sf][band] = 0.0f;
    1562             : 
    1563   106719072 :             ratioSum = 0;
    1564   254928576 :             for ( dir = 0; dir < numDirs; dir++ )
    1565             :             {
    1566   148209504 :                 ratioSum += hMeta->directional_meta[dir].energy_ratio[sf][band];
    1567             :             }
    1568   106719072 :             ratioSum += hMeta->common_meta.diffuse_to_total_ratio[sf][band];
    1569             : 
    1570   106719072 :             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   106719072 :             else if ( ratioSum != 1.0f )
    1579             :             {
    1580     7971054 :                 for ( dir = 0; dir < numDirs; dir++ )
    1581             :                 {
    1582     4784964 :                     hMeta->directional_meta[dir].energy_ratio[sf][band] /= ratioSum;
    1583             :                 }
    1584     3186090 :                 hMeta->common_meta.diffuse_to_total_ratio[sf][band] /= ratioSum;
    1585             :             }
    1586             :         }
    1587             :     }
    1588             : 
    1589     1111657 :     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      409021 : 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      409021 :     numCodingBands = hMasa->config.numCodingBands;
    1612      409021 :     computeCoherence = hMasa->config.useCoherence && hMasa->config.coherencePresent;
    1613             : 
    1614             :     /* Set default values */
    1615      409021 :     selectedBand = 0;
    1616      409021 :     mergeOverFreqBands = 0;
    1617             : 
    1618             :     /* Get energy for the input data in 4-subframe, 5-band format */
    1619      409021 :     totalEnergySum = 0.0f;
    1620      409021 :     if ( ivas_format == MASA_FORMAT || ivas_format == MASA_ISM_FORMAT ) /* Energy data is in 4-subframe, 24-band format */
    1621             :     {
    1622     1588540 :         for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1623             :         {
    1624             :             int16_t brange[2];
    1625             :             float eneSum;
    1626             :             int16_t m;
    1627             : 
    1628     7624992 :             for ( band = 0; band < numCodingBands; band++ )
    1629             :             {
    1630     6354160 :                 brange[0] = hMasa->data.band_mapping[band];
    1631     6354160 :                 brange[1] = hMasa->data.band_mapping[band + 1];
    1632             : 
    1633     6354160 :                 eneSum = 0.0f;
    1634    36608592 :                 for ( m = brange[0]; m < brange[1]; m++ )
    1635             :                 {
    1636    30254432 :                     eneSum += hMasa->data.energy[sf][m];
    1637             :                 }
    1638     6354160 :                 energy[sf][band] = eneSum;
    1639     6354160 :                 totalEnergySum += eneSum;
    1640             :             }
    1641             :         }
    1642             :     }
    1643             :     else /* Energy data is already in 4-subframe, 5-band format */
    1644             :     {
    1645      456565 :         for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1646             :         {
    1647     2191512 :             for ( band = 0; band < numCodingBands; band++ )
    1648             :             {
    1649     1826260 :                 energy[sf][band] = hMasa->data.energy[sf][band];
    1650     1826260 :                 totalEnergySum += energy[sf][band];
    1651             :             }
    1652             :         }
    1653             :     }
    1654             : 
    1655             :     /* Determine onsets */
    1656      409021 :     hMasa->data.onset_detector_1 = hMasa->data.onset_detector_1 * LOWBITRATE_ONSET_ALPHA;
    1657      409021 :     hMasa->data.onset_detector_1 = max( hMasa->data.onset_detector_1, totalEnergySum );
    1658             : 
    1659      409021 :     hMasa->data.onset_detector_2 = LOWBITRATE_ONSET_BETA * hMasa->data.onset_detector_2 + ( 1.0f - LOWBITRATE_ONSET_BETA ) * hMasa->data.onset_detector_1;
    1660      409021 :     hMasa->data.onset_detector_2 = LOWBITRATE_ONSET_GAIN * min( hMasa->data.onset_detector_1, hMasa->data.onset_detector_2 );
    1661             : 
    1662      409021 :     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      409021 :     if ( onset_filter < 0.99f )
    1666             :     {
    1667             :         /* Determine one frequency band to use to represent all frequency bands */
    1668      375810 :         for ( band = numCodingBands - 1; band >= 0; band-- )
    1669             :         {
    1670             :             float threshold;
    1671             :             float bandRatio;
    1672             : 
    1673      369663 :             threshold = totalEnergySum / ( MAX_PARAM_SPATIAL_SUBFRAMES * LOWBITRATE_NUM_BANDS ) * 0.5f; /* Average energy multiplied with energy ratio of 0.5f */
    1674      369663 :             bandRatio = hqmetadata->q_direction[0].band_data[band].energy_ratio[0];
    1675             : 
    1676      369663 :             bandEnergy = 0.0f;
    1677     1848315 :             for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1678             :             {
    1679     1478652 :                 bandEnergy += energy[sf][band];
    1680             :             }
    1681             : 
    1682      369663 :             if ( bandEnergy / MAX_PARAM_SPATIAL_SUBFRAMES * bandRatio > threshold )
    1683             :             {
    1684       90901 :                 selectedBand = band;
    1685       90901 :                 break;
    1686             :             }
    1687             :         }
    1688             : 
    1689             :         /* Determine if to merge over frequency instead of time */
    1690       97048 :         meanRatio = 0.0f;
    1691      485240 :         for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1692             :         {
    1693     2329152 :             for ( band = 0; band < numCodingBands; band++ )
    1694             :             {
    1695     1940960 :                 meanRatio += hqmetadata->q_direction[0].band_data[band].energy_ratio[sf] * energy[sf][band];
    1696             :             }
    1697             :         }
    1698       97048 :         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       97048 :         if ( hqmetadata->q_direction[0].band_data[selectedBand].energy_ratio[0] > meanRatio )
    1703             :         {
    1704       63720 :             mergeOverFreqBands = 1;
    1705             :         }
    1706             :         else
    1707             :         {
    1708       33328 :             mergeOverFreqBands = 0;
    1709             :         }
    1710             :     }
    1711             :     else
    1712             :     {
    1713      311973 :         mergeOverFreqBands = 0;
    1714             :     }
    1715             : 
    1716             :     /* Merge values over subframes or frequency bands, depending on which one is less important */
    1717      409021 :     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     2071806 :         for ( band = 0; band < numCodingBands; band++ )
    1726             :         {
    1727     1726505 :             xSum = 0.0f;
    1728     1726505 :             ySum = 0.0f;
    1729     1726505 :             zSum = 0.0f;
    1730     1726505 :             bandSumEnergy = 0.0f;
    1731             : 
    1732     8632525 :             for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1733             :             {
    1734     6906020 :                 aziRad = hqmetadata->q_direction[0].band_data[band].azimuth[sf] / 180.0f * EVS_PI;
    1735     6906020 :                 eleRad = hqmetadata->q_direction[0].band_data[band].elevation[sf] / 180.0f * EVS_PI;
    1736     6906020 :                 veclen = hqmetadata->q_direction[0].band_data[band].energy_ratio[sf] * energy[sf][band];
    1737             : 
    1738     6906020 :                 x = cosf( aziRad ) * cosf( eleRad ) * veclen;
    1739     6906020 :                 y = sinf( aziRad ) * cosf( eleRad ) * veclen;
    1740     6906020 :                 z = sinf( eleRad ) * veclen;
    1741             : 
    1742     6906020 :                 xSum += x;
    1743     6906020 :                 ySum += y;
    1744     6906020 :                 zSum += z;
    1745             : 
    1746     6906020 :                 bandSumEnergy += energy[sf][band];
    1747             :             }
    1748             : 
    1749     1726505 :             aziRad = atan2f( ySum, xSum );
    1750     1726505 :             eleRad = atan2f( zSum, sqrtf( xSum * xSum + ySum * ySum ) );
    1751             : 
    1752     1726505 :             hqmetadata->q_direction[0].band_data[band].azimuth[0] = aziRad / EVS_PI * 180.0f;
    1753     1726505 :             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     1726505 :             if ( computeCoherence && hqmetadata->q_direction[0].coherence_band_data != NULL )
    1758             :             {
    1759             :                 float spreadCoh;
    1760      288995 :                 float spreadCohSum = 0.0f;
    1761     1444975 :                 for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1762             :                 {
    1763     1155980 :                     spreadCoh = (float) hqmetadata->q_direction[0].coherence_band_data[band].spread_coherence[sf] / 255.0f;
    1764     1155980 :                     spreadCohSum += spreadCoh * energy[sf][band];
    1765             :                 }
    1766      288995 :                 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     1155980 :                 for ( sf = 1; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1770             :                 {
    1771      866985 :                     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      345301 :         hqmetadata->q_direction->cfg.nblocks = 1;
    1779      345301 :         hMasa->config.joinedSubframes = 1;
    1780             :     }
    1781             :     else /* Merge values over frequency bands */
    1782             :     {
    1783             :         /* Use the selected frequency band to represent all data */
    1784      318600 :         for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1785             :         {
    1786      254880 :             hqmetadata->q_direction[0].band_data[0].azimuth[sf] = hqmetadata->q_direction[0].band_data[selectedBand].azimuth[sf];
    1787      254880 :             hqmetadata->q_direction[0].band_data[0].elevation[sf] = hqmetadata->q_direction[0].band_data[selectedBand].elevation[sf];
    1788      254880 :             hqmetadata->q_direction[0].band_data[0].energy_ratio[sf] = hqmetadata->q_direction[0].band_data[selectedBand].energy_ratio[sf];
    1789      254880 :             if ( hqmetadata->q_direction[0].coherence_band_data != NULL )
    1790             :             {
    1791       66480 :                 hqmetadata->q_direction[0].coherence_band_data[0].spread_coherence[sf] = hqmetadata->q_direction[0].coherence_band_data[selectedBand].spread_coherence[sf];
    1792             :             }
    1793      254880 :             if ( hqmetadata->surcoh_band_data != NULL )
    1794             :             {
    1795       66480 :                 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      318600 :         for ( band = 1; band < numCodingBands; band++ )
    1801             :         {
    1802      254880 :             if ( hqmetadata->q_direction[0].coherence_band_data != NULL )
    1803             :             {
    1804      332400 :                 for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1805             :                 {
    1806      265920 :                     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      254880 :             if ( hqmetadata->q_direction[0].coherence_band_data != NULL )
    1810             :             {
    1811      332400 :                 for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    1812             :                 {
    1813      265920 :                     hqmetadata->surcoh_band_data[band].surround_coherence[sf] = hqmetadata->surcoh_band_data[0].surround_coherence[sf];
    1814             :                 }
    1815             :             }
    1816             :         }
    1817             : 
    1818       63720 :         hqmetadata->q_direction[0].cfg.nbands = 1;
    1819             :     }
    1820             : 
    1821      409021 :     return;
    1822             : }
    1823             : 
    1824             : 
    1825      190840 : 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      190840 :     VQLevels = 0;
    1844      190840 :     lfeAdaptiveVQBits = 0;
    1845             : 
    1846             :     /* Determine maximum amount of LFE energy in any subframe */
    1847      190840 :     maxLFESubFrameEner = 0.0f;
    1848      954200 :     for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ )
    1849             :     {
    1850      763360 :         if ( hMasa->data.lfeToTotalEnergyRatio[i] > maxLFESubFrameEner )
    1851             :         {
    1852      402890 :             maxLFESubFrameEner = hMasa->data.lfeToTotalEnergyRatio[i];
    1853             :         }
    1854             :     }
    1855             : 
    1856             :     /* Set default values for the indices */
    1857      763360 :     for ( i = 0; i < 3; i++ )
    1858             :     {
    1859      572520 :         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      190840 :     if ( maxLFESubFrameEner > 0.005f )
    1865             :     {
    1866             :         /* Convert energy to log2 domain, and clamp it to reasonable values */
    1867      164345 :         log2LFEaverage = 0.0f;
    1868      821725 :         for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ )
    1869             :         {
    1870      657380 :             log2LFEratio[i] = log2f( max( 0.001f, hMasa->data.lfeToTotalEnergyRatio[i] ) );
    1871      657380 :             if ( log2LFEratio[i] > 1.0f ) /* Corresponds to linear value 2.0f */
    1872             :             {
    1873           0 :                 log2LFEratio[i] = 1.0f;
    1874             :             }
    1875      657380 :             else if ( log2LFEratio[i] < -9.0f )
    1876             :             {
    1877       25003 :                 log2LFEratio[i] = -9.0f;
    1878             :             }
    1879      657380 :             log2LFEaverage += 0.25f * log2LFEratio[i];
    1880             :         }
    1881             : 
    1882      164345 :         if ( ivas_total_brate == IVAS_13k2 )
    1883             :         {
    1884             :             /* Calculate adaptive 1-bit LFE quantizer index */
    1885       13039 :             linearLFEaverage = exp2f( log2LFEaverage ); /* Convert back to linear domain */
    1886       13039 :             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        5072 :                 lfeToTotalEnergyRatioIndices[0] = 1;
    1889        5072 :                 if ( hMasa->data.prevq_lfeIndex == 1 )
    1890             :                 {
    1891        2197 :                     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        2875 :                     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        7967 :                 hMasa->data.prevq_lfeToTotalEnergyRatio = MCMASA_LFE_ALPHA * hMasa->data.prevq_lfeToTotalEnergyRatio; /* exponential decay */
    1901             :             }
    1902             : 
    1903       13039 :             if ( hMasa->data.prevq_lfeToTotalEnergyRatio > 1.0f )
    1904             :             {
    1905           4 :                 hMasa->data.prevq_lfeToTotalEnergyRatio = 1.0f;
    1906             :             }
    1907       13039 :             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      151306 :             lfeToTotalEnergyRatioIndices[0] = 1;
    1913      151306 :             lfeToTotalEnergyRatioIndices[1] = usquant( log2LFEaverage, &xq, MCMASA_LFE_QLOW, MCMASA_LFE_DELTA, 8 );
    1914             : 
    1915      151306 :             if ( ivas_total_brate >= IVAS_24k4 ) /* Vector quantization is applied if bitrate >= 24.4 kbps */
    1916             :             {
    1917             :                 /* Remove scalar value from the vector*/
    1918      732645 :                 for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ )
    1919             :                 {
    1920      586116 :                     log2LFEratio[i] -= xq;
    1921             :                 }
    1922             : 
    1923             :                 /* Vector quantize residual with energy adaptive bit allocation */
    1924      146529 :                 switch ( lfeToTotalEnergyRatioIndices[1] )
    1925             :                 {
    1926       30837 :                     case 0:
    1927             :                     case 1:
    1928       30837 :                         VQLevels = 0;
    1929       30837 :                         lfeAdaptiveVQBits = 0;
    1930       30837 :                         break;
    1931       15327 :                     case 2:
    1932       15327 :                         VQLevels = 2;
    1933       15327 :                         lfeAdaptiveVQBits = 1;
    1934       15327 :                         break;
    1935       19092 :                     case 3:
    1936       19092 :                         VQLevels = 4;
    1937       19092 :                         lfeAdaptiveVQBits = 2;
    1938       19092 :                         break;
    1939       22580 :                     case 4:
    1940       22580 :                         VQLevels = 8;
    1941       22580 :                         lfeAdaptiveVQBits = 3;
    1942       22580 :                         break;
    1943       58693 :                     default:
    1944       58693 :                         VQLevels = 16;
    1945       58693 :                         lfeAdaptiveVQBits = 4;
    1946             :                 }
    1947             : 
    1948      146529 :                 if ( VQLevels > 0 )
    1949             :                 {
    1950      115692 :                     lfeToTotalEnergyRatioIndices[2] = vquant( log2LFEratio, 0, xqv, McMASA_LFEGain_vectors, 4, VQLevels );
    1951             :                 }
    1952             :             }
    1953             :         }
    1954             :     }
    1955             : 
    1956             :     /* Write first LFE bit */
    1957      190840 :     lfeBitsWritten = 0;
    1958      190840 :     push_next_indice( hMetaData, lfeToTotalEnergyRatioIndices[0], 1 );
    1959      190840 :     lfeBitsWritten += 1;
    1960             : 
    1961      190840 :     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      151306 :         push_next_indice( hMetaData, lfeToTotalEnergyRatioIndices[1], 3 );
    1965      151306 :         lfeBitsWritten += 3;
    1966             : 
    1967             :         /*  If bitrate >= 24.4kbit/s, use adaptive 1 + (3.. 7) bit quantizer */
    1968      151306 :         if ( ivas_total_brate >= IVAS_24k4 )
    1969             :         {
    1970             :             /* Vector quantize residual with energy adaptive bit allocation */
    1971      146529 :             if ( lfeAdaptiveVQBits > 0 )
    1972             :             {
    1973      115692 :                 push_next_indice( hMetaData, lfeToTotalEnergyRatioIndices[2], lfeAdaptiveVQBits );
    1974      115692 :                 lfeBitsWritten += lfeAdaptiveVQBits;
    1975             :             }
    1976             :         }
    1977             :     }
    1978             : 
    1979      190840 :     return lfeBitsWritten;
    1980             : }
    1981             : 
    1982             : 
    1983             : /*-------------------------------------------------------------------*
    1984             :  * ivas_masa_enc_reconfigure()
    1985             :  *
    1986             :  * Reconfigure IVAS MASA encoder
    1987             :  *-------------------------------------------------------------------*/
    1988             : 
    1989      700417 : 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      700417 :     ivas_total_brate = st_ivas->hEncoderConfig->ivas_total_brate;
    1999             : 
    2000      700417 :     ism_total_brate = 0;
    2001      700417 :     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      700417 :     if ( ivas_total_brate != st_ivas->hEncoderConfig->last_ivas_total_brate )
    2010             :     {
    2011       18981 :         for ( sce_id = 0; sce_id < st_ivas->nSCE; sce_id++ )
    2012             :         {
    2013        5674 :             copy_encoder_config( st_ivas, st_ivas->hSCE[sce_id]->hCoreCoder[0], 0 );
    2014        5674 :             st_ivas->hSCE[sce_id]->element_brate = ivas_total_brate / st_ivas->nchan_transport;
    2015        5674 :             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       20940 :         for ( cpe_id = 0; cpe_id < st_ivas->nCPE; cpe_id++ )
    2019             :         {
    2020        7633 :             st_ivas->hCPE[cpe_id]->element_brate = ( ivas_total_brate / st_ivas->nchan_transport ) * CPE_CHANNELS;
    2021             : 
    2022             :             /* prepare bitstream buffers */
    2023       22899 :             for ( n = 0; n < CPE_CHANNELS; n++ )
    2024             :             {
    2025       15266 :                 copy_encoder_config( st_ivas, st_ivas->hCPE[cpe_id]->hCoreCoder[n], 0 );
    2026       15266 :                 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        7633 :             if ( ivas_total_brate - ism_total_brate < MIN_BRATE_MDCT_STEREO )
    2030             :             {
    2031        2305 :                 st_ivas->hCPE[cpe_id]->element_mode = IVAS_CPE_DFT;
    2032             :             }
    2033             :             else
    2034             :             {
    2035        5328 :                 st_ivas->hCPE[cpe_id]->element_mode = IVAS_CPE_MDCT;
    2036             :             }
    2037             :         }
    2038             : 
    2039       13307 :         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      700417 :     return;
    2043             : }
    2044             : 
    2045             : 
    2046             : /*-------------------------------------------------------------------*
    2047             :  * average_masa_metadata()
    2048             :  *
    2049             :  * Average MASA metadata frame subframe contents: applies aggregation over time
    2050             :  *-------------------------------------------------------------------*/
    2051             : 
    2052      142467 : 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      142467 :     numDirections = hMeta->descriptive_meta.numberOfDirections + 1;
    2064             : 
    2065             :     /* azi/ele/nrg into vectors for each sub-frame and band */
    2066      332194 :     for ( i = 0; i < numDirections; i++ )
    2067             :     {
    2068     4743175 :         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     4553448 :             x_sum = 0.0f;
    2073     4553448 :             y_sum = 0.0f;
    2074     4553448 :             z_sum = 0.0f;
    2075     4553448 :             energy_sum = 0.0f;
    2076     4553448 :             spread_coh_sum = 0.0f;
    2077     4553448 :             surr_coh_sum = 0.0f;
    2078    22767240 :             for ( j = 0; j < MAX_PARAM_SPATIAL_SUBFRAMES; j++ )
    2079             :             {
    2080    18213792 :                 azi_rad = hMeta->directional_meta[i].azimuth[j][k] / 180.0f * EVS_PI;
    2081    18213792 :                 ele_rad = hMeta->directional_meta[i].elevation[j][k] / 180.0f * EVS_PI;
    2082    18213792 :                 vec_len = hMeta->directional_meta[i].energy_ratio[j][k] * energy[j][k];
    2083             : 
    2084             :                 /* energy-weighted sum over subframes */
    2085    18213792 :                 x_sum += cosf( azi_rad ) * cosf( ele_rad ) * vec_len;
    2086    18213792 :                 y_sum += sinf( azi_rad ) * cosf( ele_rad ) * vec_len;
    2087    18213792 :                 z_sum += sinf( ele_rad ) * vec_len;
    2088             : 
    2089    18213792 :                 energy_sum += energy[j][k];
    2090             : 
    2091    18213792 :                 spread_coh_sum += hMeta->directional_meta[i].spread_coherence[j][k] * energy[j][k];
    2092    18213792 :                 if ( i == 0 )
    2093             :                 {
    2094             :                     /* this is in common metadata and not in each direction */
    2095    13676832 :                     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     4553448 :             j = 0;
    2101     4553448 :             hMeta->directional_meta[i].azimuth[j][k] = atan2f( y_sum, x_sum ) / EVS_PI * 180.0f;
    2102     4553448 :             hMeta->directional_meta[i].elevation[j][k] = atan2f( z_sum, sqrtf( x_sum * x_sum + y_sum * y_sum ) ) / EVS_PI * 180.0f;
    2103     4553448 :             if ( useSphGrid == TRUE )
    2104             :             {
    2105      166152 :                 hMeta->directional_meta[i].spherical_index[j][k] = index_theta_phi_16( &( hMeta->directional_meta[i].elevation[j][k] ),
    2106      166152 :                                                                                        &( hMeta->directional_meta[i].azimuth[j][k] ), Sph_Grid16 );
    2107             :             }
    2108     4553448 :             vec_len = sqrtf( x_sum * x_sum + y_sum * y_sum + z_sum * z_sum );
    2109     4553448 :             hMeta->directional_meta[i].energy_ratio[j][k] = vec_len / ( energy_sum + EPSILON );
    2110             : 
    2111     4553448 :             hMeta->directional_meta[i].spread_coherence[j][k] = spread_coh_sum / ( energy_sum + EPSILON );
    2112     4553448 :             if ( i == 0 )
    2113             :             {
    2114     3419208 :                 hMeta->common_meta.surround_coherence[j][k] = surr_coh_sum / ( energy_sum + EPSILON );
    2115             :             }
    2116             : 
    2117             :             /* copy the same value to all subframes */
    2118    18213792 :             for ( j = 1; j < MAX_PARAM_SPATIAL_SUBFRAMES; j++ )
    2119             :             {
    2120    13660344 :                 hMeta->directional_meta[i].azimuth[j][k] = hMeta->directional_meta[i].azimuth[0][k];
    2121    13660344 :                 hMeta->directional_meta[i].elevation[j][k] = hMeta->directional_meta[i].elevation[0][k];
    2122    13660344 :                 hMeta->directional_meta[i].energy_ratio[j][k] = hMeta->directional_meta[i].energy_ratio[0][k];
    2123    13660344 :                 hMeta->directional_meta[i].spread_coherence[j][k] = hMeta->directional_meta[i].spread_coherence[0][k];
    2124    13660344 :                 if ( i == 0 )
    2125             :                 {
    2126    10257624 :                     hMeta->common_meta.surround_coherence[j][k] = hMeta->common_meta.surround_coherence[0][k];
    2127             :                 }
    2128             :             }
    2129             :         }
    2130             :     }
    2131             : 
    2132     3561675 :     for ( k = 0; k < MASA_FREQUENCY_BANDS; k++ )
    2133             :     {
    2134    17096040 :         for ( j = 0; j < MAX_PARAM_SPATIAL_SUBFRAMES; j++ )
    2135             :         {
    2136    13676832 :             if ( numDirections == 2 )
    2137             :             {
    2138     4536960 :                 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     9139872 :                 hMeta->common_meta.diffuse_to_total_ratio[j][k] = max( 0.0f, 1.0f - hMeta->directional_meta[0].energy_ratio[j][k] );
    2143             :             }
    2144    13676832 :             hMeta->common_meta.remainder_to_total_ratio[j][k] = 0.0f;
    2145             :         }
    2146             :     }
    2147             : 
    2148      142467 :     return;
    2149             : }
    2150             : 
    2151             : 
    2152             : /*-------------------------------------------------------------------*
    2153             :  * copy_masa_metadata_subframe()
    2154             :  *
    2155             :  * Copy MASA metadata frame subframe contents
    2156             :  *-------------------------------------------------------------------*/
    2157             : 
    2158     4446628 : 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    13339884 :     for ( dir = 0; dir < MASA_MAXIMUM_DIRECTIONS; dir++ )
    2170             :     {
    2171   222331400 :         for ( band = 0; band < MASA_FREQUENCY_BANDS; band++ )
    2172             :         {
    2173   213438144 :             hMetaTo->directional_meta[dir].spherical_index[sfTo][band] = hMetaFrom->directional_meta[dir].spherical_index[sfFrom][band];
    2174             :         }
    2175     8893256 :         mvr2r( hMetaFrom->directional_meta[dir].azimuth[sfFrom], hMetaTo->directional_meta[dir].azimuth[sfTo], MASA_FREQUENCY_BANDS );
    2176     8893256 :         mvr2r( hMetaFrom->directional_meta[dir].elevation[sfFrom], hMetaTo->directional_meta[dir].elevation[sfTo], MASA_FREQUENCY_BANDS );
    2177     8893256 :         mvr2r( hMetaFrom->directional_meta[dir].energy_ratio[sfFrom], hMetaTo->directional_meta[dir].energy_ratio[sfTo], MASA_FREQUENCY_BANDS );
    2178     8893256 :         mvr2r( hMetaFrom->directional_meta[dir].spread_coherence[sfFrom], hMetaTo->directional_meta[dir].spread_coherence[sfTo], MASA_FREQUENCY_BANDS );
    2179             :     }
    2180             : 
    2181             :     /* common metadata */
    2182     4446628 :     mvr2r( hMetaFrom->common_meta.diffuse_to_total_ratio[sfFrom], hMetaTo->common_meta.diffuse_to_total_ratio[sfTo], MASA_FREQUENCY_BANDS );
    2183     4446628 :     mvr2r( hMetaFrom->common_meta.surround_coherence[sfFrom], hMetaTo->common_meta.surround_coherence[sfTo], MASA_FREQUENCY_BANDS );
    2184     4446628 :     mvr2r( hMetaFrom->common_meta.remainder_to_total_ratio[sfFrom], hMetaTo->common_meta.remainder_to_total_ratio[sfTo], MASA_FREQUENCY_BANDS );
    2185             : 
    2186     4446628 :     return;
    2187             : }
    2188             : 
    2189             : 
    2190             : /*-------------------------------------------------------------------*
    2191             :  * copy_masa_metadata()
    2192             :  *
    2193             :  * Copy MASA metada frame contents
    2194             :  *-------------------------------------------------------------------*/
    2195             : 
    2196     1111657 : 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    10004913 :     for ( byte_idx = 0; byte_idx < 8; byte_idx++ )
    2205             :     {
    2206     8893256 :         hMetaTo->descriptive_meta.formatDescriptor[byte_idx] = hMetaFrom->descriptive_meta.formatDescriptor[byte_idx];
    2207             :     }
    2208             : 
    2209     1111657 :     hMetaTo->descriptive_meta.numberOfDirections = hMetaFrom->descriptive_meta.numberOfDirections;
    2210     1111657 :     hMetaTo->descriptive_meta.numberOfChannels = hMetaFrom->descriptive_meta.numberOfChannels;
    2211     1111657 :     hMetaTo->descriptive_meta.sourceFormat = hMetaFrom->descriptive_meta.sourceFormat;
    2212     1111657 :     hMetaTo->descriptive_meta.transportDefinition = hMetaFrom->descriptive_meta.transportDefinition;
    2213     1111657 :     hMetaTo->descriptive_meta.channelAngle = hMetaFrom->descriptive_meta.channelAngle;
    2214     1111657 :     hMetaTo->descriptive_meta.channelDistance = hMetaFrom->descriptive_meta.channelDistance;
    2215     1111657 :     hMetaTo->descriptive_meta.channelLayout = hMetaFrom->descriptive_meta.channelLayout;
    2216             : 
    2217             :     /* directional and common metadata */
    2218     5558285 :     for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    2219             :     {
    2220     4446628 :         copy_masa_metadata_subframe( hMetaFrom, sf, hMetaTo, sf );
    2221             :     }
    2222             : 
    2223     1111657 :     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     6260718 : 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     6260718 :     num_dir = frame1->descriptive_meta.numberOfDirections;
    2247     6260718 :     dir = 0;
    2248     6260718 :     band_idx = 0;
    2249     6260718 :     sf_differ = FALSE;
    2250             : 
    2251     6260718 :     if ( num_dir != frame2->descriptive_meta.numberOfDirections )
    2252             :     {
    2253       51054 :         sf_differ = TRUE;
    2254             :     }
    2255             :     else
    2256             :     {
    2257             :         /* check per-direction metadata */
    2258     6209664 :         dir = 0;
    2259     6209664 :         band_idx = 0;
    2260             : 
    2261    13725787 :         while ( ( sf_differ == FALSE ) && ( dir <= num_dir ) )
    2262             :         {
    2263     7516123 :             band_idx = 0;
    2264   112779235 :             while ( ( sf_differ == FALSE ) && ( band_idx < MASA_FREQUENCY_BANDS ) )
    2265             :             {
    2266             :                 float azi_dif;
    2267   108463203 :                 azi_dif = fabsf( frame1->directional_meta[dir].azimuth[sf1_idx][band_idx] - frame2->directional_meta[dir].azimuth[sf2_idx][band_idx] );
    2268   108463203 :                 azi_dif = azi_dif > 180.0f ? 360.0f - azi_dif : azi_dif;
    2269             : 
    2270   108463203 :                 if ( azi_dif > MASA_ANGLE_TOLERANCE )
    2271             :                 {
    2272     3005232 :                     sf_differ = TRUE;
    2273     3005232 :                     break;
    2274             :                 }
    2275             : 
    2276   105457971 :                 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      111494 :                     sf_differ = TRUE;
    2279      111494 :                     break;
    2280             :                 }
    2281             : 
    2282   105346477 :                 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       55575 :                     sf_differ = TRUE;
    2285       55575 :                     break;
    2286             :                 }
    2287             : 
    2288   105290902 :                 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       27790 :                     sf_differ = TRUE;
    2291       27790 :                     break;
    2292             :                 }
    2293             : 
    2294   105263112 :                 band_idx++;
    2295             :             }
    2296     7516123 :             dir++;
    2297             :         }
    2298             : 
    2299             :         /* check the common metadata */
    2300     6209664 :         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     6260718 :     if ( sf_differ )
    2313             :     {
    2314     3251145 :         return FALSE;
    2315             :     }
    2316             :     else
    2317             :     {
    2318     3009573 :         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     1111657 : 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     1111657 :     current_meta = &( hMasa->masaMetadata );  /* metadata from current frame */
    2343     1111657 :     sync_state = &( hMasa->data.sync_state ); /* synchronization structure */
    2344     1111657 :     previous_meta = &( sync_state->previous_metadata );
    2345             : 
    2346             :     /* check current frame, how many are similar from the start and from the end */
    2347     1111657 :     n_sim_start = 1;
    2348     2221924 :     for ( sf_idx = n_sim_start; sf_idx < MAX_PARAM_SPATIAL_SUBFRAMES; sf_idx++ )
    2349             :     {
    2350     1954457 :         if ( are_masa_subframes_similar( current_meta, 0, current_meta, sf_idx ) == TRUE )
    2351             :         {
    2352     1110267 :             n_sim_start = sf_idx + 1;
    2353             :         }
    2354             :         else
    2355             :         {
    2356      844190 :             break;
    2357             :         }
    2358             :     }
    2359             : 
    2360             :     /* number of similar sub-frames starting from the end of the frame */
    2361     1111657 :     if ( n_sim_start == MAX_PARAM_SPATIAL_SUBFRAMES ) /* shortcut */
    2362             :     {
    2363      267467 :         n_sim_stop = n_sim_start;
    2364             :     }
    2365             :     else
    2366             :     {
    2367      844190 :         n_sim_stop = 1;
    2368     1167858 :         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     1144897 :             if ( are_masa_subframes_similar( current_meta, MAX_PARAM_SPATIAL_SUBFRAMES - 1, current_meta, MAX_PARAM_SPATIAL_SUBFRAMES - sf_idx ) == TRUE )
    2372             :             {
    2373      323668 :                 n_sim_stop = sf_idx;
    2374             :             }
    2375             :             else
    2376             :             {
    2377      821229 :                 break;
    2378             :             }
    2379             :         }
    2380             :     }
    2381             : 
    2382     1111657 :     frame_mode = MASA_FRAME_4SF; /* default mode: 4sf */
    2383     1111657 :     if ( sync_state->prev_offset > MAX_PARAM_SPATIAL_SUBFRAMES - 2 )
    2384             :     {
    2385             :         /* earlier offset was large => reset the offset */
    2386       31804 :         found_offset = 0;
    2387             :     }
    2388             :     else
    2389             :     {
    2390             :         /* keep previous offset unless something else is found. alternatively, we could reset always */
    2391     1079853 :         found_offset = sync_state->prev_offset;
    2392             :     }
    2393             : 
    2394     1111657 :     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      267467 :         frame_mode = MASA_FRAME_1SF;
    2398      267467 :         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       69377 :             if ( sync_state->prev_sim_stop < 3 )
    2402             :             {
    2403             :                 /* can nicely align the framing with the earlier data and a small offset */
    2404        5671 :                 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       63706 :                 found_offset = sync_state->prev_offset;
    2410             :             }
    2411             :         }
    2412             :         else
    2413             :         {
    2414             :             /* earlier window was different => reset the offset */
    2415      198090 :             found_offset = 0;
    2416             :         }
    2417             :     }
    2418      844190 :     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       22961 :         frame_mode = MASA_FRAME_1SF;
    2423       22961 :         found_offset = 3;
    2424             :     }
    2425      821229 :     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      165296 :         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       87884 :             frame_mode = MASA_FRAME_1SF;
    2432             : 
    2433       87884 :             if ( sync_state->prev_offset == 0 )
    2434             :             {
    2435        5466 :                 found_offset = min( 2, sync_state->prev_sim_stop );
    2436             :             }
    2437             :             else
    2438             :             {
    2439       82418 :                 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     1111657 :     copy_masa_metadata( current_meta, previous_meta );
    2447             : 
    2448     1111657 :     sync_state->prev_sim_stop = n_sim_stop;
    2449     1111657 :     sync_state->prev_offset = found_offset;
    2450     1111657 :     sync_state->frame_mode = frame_mode;
    2451             : 
    2452     1111657 :     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     1111657 : 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     1111657 :     hAlignState = &( hMasa->data.dir_align_state );
    2472     1111657 :     hMeta = &( hMasa->masaMetadata );
    2473             : 
    2474     1111657 :     n_dirs = hMeta->descriptive_meta.numberOfDirections + 1; /* 1-based */
    2475    27791425 :     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    26679768 :         prev_ele_dir1_sin = sinf( hAlignState->previous_ele_dir1[band] );
    2485    26679768 :         prev_ele_dir2_sin = sinf( hAlignState->previous_ele_dir2[band] );
    2486             : 
    2487    26679768 :         prev_ele_dir1_cos = cosf( hAlignState->previous_ele_dir1[band] );
    2488    26679768 :         prev_ele_dir2_cos = cosf( hAlignState->previous_ele_dir2[band] );
    2489             : 
    2490   133398840 :         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   106719072 :             azi_rad1 = hMeta->directional_meta[0].azimuth[sf][band] * PI_OVER_180;
    2498   106719072 :             ele_rad1 = hMeta->directional_meta[0].elevation[sf][band] * PI_OVER_180;
    2499             : 
    2500   106719072 :             if ( n_dirs > 1 )
    2501             :             {
    2502    42813312 :                 azi_rad2 = hMeta->directional_meta[1].azimuth[sf][band] * PI_OVER_180;
    2503    42813312 :                 ele_rad2 = hMeta->directional_meta[1].elevation[sf][band] * PI_OVER_180;
    2504             : 
    2505             :                 /* quick checks to detect constant data and earlier flip */
    2506    42813312 :                 if ( fabsf( azi_rad1 - hAlignState->previous_azi_dir1[band] ) < EPSILON &&
    2507    11181739 :                      fabsf( azi_rad2 - hAlignState->previous_azi_dir2[band] ) < EPSILON &&
    2508    10551575 :                      fabsf( ele_rad1 - hAlignState->previous_ele_dir1[band] ) < EPSILON &&
    2509    10550315 :                      fabsf( ele_rad2 - hAlignState->previous_ele_dir2[band] ) < EPSILON )
    2510             :                 {
    2511    10550309 :                     diff_swap = 1.0f;
    2512    10550309 :                     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    10550309 :                     sin_ele1 = prev_ele_dir1_sin;
    2515    10550309 :                     sin_ele2 = prev_ele_dir2_sin;
    2516    10550309 :                     cos_ele1 = prev_ele_dir1_cos;
    2517    10550309 :                     cos_ele2 = prev_ele_dir2_cos;
    2518             :                 }
    2519    32263003 :                 else if ( fabsf( azi_rad1 - hAlignState->previous_azi_dir2[band] ) < EPSILON &&
    2520     8582747 :                           fabsf( azi_rad2 - hAlignState->previous_azi_dir1[band] ) < EPSILON &&
    2521     8551810 :                           fabsf( ele_rad1 - hAlignState->previous_ele_dir2[band] ) < EPSILON &&
    2522     8551587 :                           fabsf( ele_rad2 - hAlignState->previous_ele_dir1[band] ) < EPSILON )
    2523             :                 {
    2524     8551554 :                     diff_swap = 0.0f;
    2525     8551554 :                     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     8551554 :                     sin_ele1 = prev_ele_dir2_sin;
    2528     8551554 :                     sin_ele2 = prev_ele_dir1_sin;
    2529     8551554 :                     cos_ele1 = prev_ele_dir2_cos;
    2530     8551554 :                     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    23711449 :                     sin_ele1 = sinf( ele_rad1 );
    2537    23711449 :                     sin_ele2 = sinf( ele_rad2 );
    2538             : 
    2539    23711449 :                     cos_ele1 = cosf( ele_rad1 );
    2540    23711449 :                     cos_ele2 = cosf( ele_rad2 );
    2541             : 
    2542    23711449 :                     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    23711449 :                                    acosf( cos_ele2 * prev_ele_dir2_cos * cosf( azi_rad2 - hAlignState->previous_azi_dir2[band] ) + sin_ele2 * prev_ele_dir2_sin );
    2544             : 
    2545    23711449 :                     diff_swap = acosf( cos_ele1 * prev_ele_dir2_cos * cosf( azi_rad1 - hAlignState->previous_azi_dir2[band] ) + sin_ele1 * prev_ele_dir2_sin ) +
    2546    23711449 :                                 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    63905760 :                 sin_ele1 = sinf( ele_rad1 );
    2553    63905760 :                 cos_ele1 = cosf( ele_rad1 );
    2554             : 
    2555    63905760 :                 azi_rad2 = 0.0f;
    2556    63905760 :                 ele_rad2 = 0.0f;
    2557             : 
    2558    63905760 :                 sin_ele2 = 0.0f; /* sin(0) */
    2559    63905760 :                 cos_ele2 = 1.0f; /* cos(0) */
    2560             : 
    2561    63905760 :                 diff_swap = 1.0f;
    2562    63905760 :                 diff_no_swap = 0.0f;
    2563             :             }
    2564             : 
    2565   106719072 :             if ( n_dirs > 1 && diff_no_swap > diff_swap )
    2566    17077310 :             {
    2567             :                 /* swap the metadata of the two directions in this TF-tile */
    2568             :                 float tmp_val;
    2569             :                 uint16_t tmp_int_val;
    2570    17077310 :                 tmp_val = hMeta->directional_meta[0].azimuth[sf][band];
    2571    17077310 :                 hMeta->directional_meta[0].azimuth[sf][band] = hMeta->directional_meta[1].azimuth[sf][band];
    2572    17077310 :                 hMeta->directional_meta[1].azimuth[sf][band] = tmp_val;
    2573             : 
    2574    17077310 :                 tmp_val = hMeta->directional_meta[0].elevation[sf][band];
    2575    17077310 :                 hMeta->directional_meta[0].elevation[sf][band] = hMeta->directional_meta[1].elevation[sf][band];
    2576    17077310 :                 hMeta->directional_meta[1].elevation[sf][band] = tmp_val;
    2577    17077310 :                 tmp_int_val = hMeta->directional_meta[0].spherical_index[sf][band];
    2578    17077310 :                 hMeta->directional_meta[0].spherical_index[sf][band] = hMeta->directional_meta[1].spherical_index[sf][band];
    2579    17077310 :                 hMeta->directional_meta[1].spherical_index[sf][band] = tmp_int_val;
    2580    17077310 :                 tmp_val = hMeta->directional_meta[0].energy_ratio[sf][band];
    2581    17077310 :                 hMeta->directional_meta[0].energy_ratio[sf][band] = hMeta->directional_meta[1].energy_ratio[sf][band];
    2582    17077310 :                 hMeta->directional_meta[1].energy_ratio[sf][band] = tmp_val;
    2583             : 
    2584    17077310 :                 tmp_val = hMeta->directional_meta[0].spread_coherence[sf][band];
    2585    17077310 :                 hMeta->directional_meta[0].spread_coherence[sf][band] = hMeta->directional_meta[1].spread_coherence[sf][band];
    2586    17077310 :                 hMeta->directional_meta[1].spread_coherence[sf][band] = tmp_val;
    2587             : 
    2588    17077310 :                 hAlignState->previous_azi_dir1[band] = azi_rad2;
    2589    17077310 :                 hAlignState->previous_ele_dir1[band] = ele_rad2;
    2590             : 
    2591    17077310 :                 hAlignState->previous_azi_dir2[band] = azi_rad1;
    2592    17077310 :                 hAlignState->previous_ele_dir2[band] = ele_rad1;
    2593             : 
    2594    17077310 :                 prev_ele_dir1_cos = cos_ele2;
    2595    17077310 :                 prev_ele_dir1_sin = sin_ele2;
    2596             : 
    2597    17077310 :                 prev_ele_dir2_cos = cos_ele1;
    2598    17077310 :                 prev_ele_dir2_sin = sin_ele1;
    2599             :             }
    2600             :             else
    2601             :             {
    2602    89641762 :                 hAlignState->previous_azi_dir1[band] = azi_rad1;
    2603    89641762 :                 hAlignState->previous_ele_dir1[band] = ele_rad1;
    2604             : 
    2605    89641762 :                 hAlignState->previous_azi_dir2[band] = azi_rad2;
    2606    89641762 :                 hAlignState->previous_ele_dir2[band] = ele_rad2;
    2607             : 
    2608    89641762 :                 prev_ele_dir1_cos = cos_ele1;
    2609    89641762 :                 prev_ele_dir1_sin = sin_ele1;
    2610             : 
    2611    89641762 :                 prev_ele_dir2_cos = cos_ele2;
    2612    89641762 :                 prev_ele_dir2_sin = sin_ele2;
    2613             :             }
    2614             :         } /* sf */
    2615             :     }     /* band */
    2616             : 
    2617     1111657 :     return;
    2618             : }
    2619             : 
    2620             : 
    2621             : /*-------------------------------------------------------------------*
    2622             :  * ivas_merge_masa_metadata()
    2623             :  *
    2624             :  *
    2625             :  *-------------------------------------------------------------------*/
    2626             : 
    2627      178138 : 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      178138 :     OMASA_ENCODER_ENERGY_HANDLE hOmasaEnergy = hMasa->data.hOmasaData->hOmasaEnergy;
    2643             : 
    2644      178138 :     numCodingBands = hMasa->config.numCodingBands;
    2645      178138 :     numDirections = hMasa->config.numberOfDirections;
    2646      178138 :     numSf = hMasa->config.joinedSubframes == TRUE ? 1 : MAX_PARAM_SPATIAL_SUBFRAMES;
    2647      178138 :     hMeta = &( hMasa->masaMetadata );
    2648             : 
    2649      890690 :     for ( sf = 0; sf < numSf; sf++ )
    2650             :     {
    2651    17654000 :         for ( band = 0; band < numCodingBands; band++ )
    2652             :         {
    2653             :             int16_t merge_dest;
    2654             :             float dir_sum;
    2655             :             uint8_t band_n_dirs;
    2656    16941448 :             if ( numDirections == 1 || ( numDirections == 2 && hMasa->data.twoDirBands[band] == 0 ) )
    2657             :             {
    2658    16941448 :                 band_n_dirs = 1;
    2659             :             }
    2660             :             else
    2661             :             {
    2662           0 :                 band_n_dirs = 2;
    2663             :             }
    2664             : 
    2665             :             /* Compute energies */
    2666    16941448 :             eneBand = hMasa->data.energy[sf][band];
    2667    16941448 :             energyMerged[sf][band] = eneBand + hOmasaEnergy->energy_ism[sf][band];
    2668             : 
    2669             :             /* Compute weights */
    2670    16941448 :             energyTimesRatioMASA[0] = eneBand * hMeta->directional_meta[0].energy_ratio[sf][band];
    2671    16941448 :             if ( band_n_dirs == 2 )
    2672             :             {
    2673           0 :                 energyTimesRatioMASA[1] = eneBand * hMeta->directional_meta[1].energy_ratio[sf][band];
    2674             :             }
    2675             :             else
    2676             :             {
    2677    16941448 :                 energyTimesRatioMASA[1] = 0.0f;
    2678             :             }
    2679             : 
    2680             :             /* target is original MASA diffuseness */
    2681    16941448 :             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    16941448 :             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    16941448 :             merge_dest = -1;
    2688    16941448 :             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     8021015 :                 merge_dest = 0;
    2693             :             }
    2694     8920433 :             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    16941448 :             if ( merge_dest >= 0 ) /* replace one MASA with ISM */
    2701             :             {
    2702     8021015 :                 hMeta->directional_meta[merge_dest].azimuth[sf][band] = hOMasaMeta->directional_meta[0].azimuth[sf][band];
    2703     8021015 :                 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     8021015 :                 dir_sum = 1.0f - total_diff_nrg / ( EPSILON + eneBand + hOmasaEnergy->energy_ism[sf][band] );                                        /* new dir ratio */
    2707     8021015 :                 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     8021015 :                 hMeta->common_meta.diffuse_to_total_ratio[sf][band] = 1.0f - hMeta->directional_meta[merge_dest].energy_ratio[sf][band];
    2709             : 
    2710     8021015 :                 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     8021015 :                 direct_quota = 1.0f - hMeta->common_meta.diffuse_to_total_ratio[sf][band];
    2719     8021015 :                 if ( band_n_dirs == 1 )
    2720             :                 {
    2721     8021015 :                     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      890690 :     for ( sf = 0; sf < numSf; sf++ )
    2735             :     {
    2736    17654000 :         for ( band = 0; band < numCodingBands; band++ )
    2737             :         {
    2738    16941448 :             hMasa->data.energy[sf][band] = energyMerged[sf][band];
    2739             :         }
    2740             :     }
    2741             : 
    2742      178138 :     return;
    2743             : }
    2744             : 
    2745             : 
    2746     1239089 : 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     1239089 :     max_sum_idx = ( 1 << PARAM_ISM_POW_RATIO_NBITS ) - 1;
    2760             : 
    2761     1239089 :     if ( idx_sep_object > -1 )
    2762             :     {
    2763     1239089 :         if ( ratio_ism[idx_sep_object] < 1.0f / (float) ( max_sum_idx ) )
    2764             :         {
    2765             :             /* take it out from quantize function  */
    2766      854589 :             mvr2r( ratio_ism, ratio_ism_loc, idx_sep_object );
    2767      854589 :             mvr2r( &ratio_ism[idx_sep_object + 1], &ratio_ism_loc[idx_sep_object], nchan_ism - idx_sep_object - 1 );
    2768      854589 :             no_ism_loc = nchan_ism - 1;
    2769             :         }
    2770             :         else
    2771             :         {
    2772      384500 :             no_ism_loc = nchan_ism;
    2773      384500 :             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     1239089 :     if ( nchan_ism > 1 )
    2783             :     {
    2784     1239089 :         if ( masa_to_total_energy_ratio >= MASA2TOTAL_THR )
    2785             :         {
    2786      512223 :             distribute_evenly_ism( idx, max_sum_idx, nchan_ism );
    2787             :         }
    2788             :         else
    2789             :         {
    2790      726866 :             if ( no_ism_loc > 1 )
    2791             :             {
    2792             : 
    2793      705910 :                 dist = 0.0f;
    2794      705910 :                 div = 1.0f / (float) ( max_sum_idx );
    2795             : 
    2796      705910 :                 part_idx_sum = 0;
    2797             : 
    2798     2668612 :                 for ( i = 0; i < no_ism_loc; i++ )
    2799             :                 {
    2800     1962702 :                     idx[i] = (int16_t) ( ( ratio_ism_loc[i] ) * ( max_sum_idx ) );
    2801     1962702 :                     part_idx_sum += idx[i];
    2802             : 
    2803     1962702 :                     tmp = ( ratio_ism_loc[i] - ( idx[i] * div ) );
    2804     1962702 :                     dist += ( tmp * tmp );
    2805             :                 }
    2806             : 
    2807      705910 :                 best_dist = dist;
    2808      705910 :                 best_i2 = -1;
    2809     1154315 :                 while ( part_idx_sum < max_sum_idx )
    2810             :                 {
    2811      448405 :                     best_i = -1;
    2812             :                     /* check which index to increase by 1 for a possible improvement */
    2813             : 
    2814     1735647 :                     for ( i = 0; i < no_ism_loc; i++ )
    2815             :                     {
    2816     1287242 :                         idx[i]++;
    2817     1287242 :                         dist2 = 0.0f;
    2818             : 
    2819     5086702 :                         for ( j = 0; j < no_ism_loc; j++ )
    2820             :                         {
    2821     3799460 :                             tmp = ( ratio_ism_loc[i] - ( idx[i] * div ) );
    2822     3799460 :                             dist2 += ( tmp * tmp );
    2823             :                         }
    2824             : 
    2825     1287242 :                         if ( dist2 < best_dist )
    2826             :                         {
    2827      378523 :                             best_i2 = best_i;
    2828      378523 :                             best_i = i;
    2829      378523 :                             best_dist = dist2;
    2830             :                         }
    2831     1287242 :                         idx[i]--;
    2832             :                     }
    2833      448405 :                     if ( best_i > -1 )
    2834             :                     {
    2835      366228 :                         idx[best_i]++;
    2836      366228 :                         part_idx_sum++;
    2837             :                     }
    2838             :                     else
    2839             :                     {
    2840       82177 :                         if ( best_i2 > -1 )
    2841             :                         {
    2842       10464 :                             idx[best_i2]++;
    2843       10464 :                             part_idx_sum++;
    2844             :                         }
    2845             :                         else
    2846             :                         {
    2847       71713 :                             idx[no_ism_loc - 1] += max_sum_idx - part_idx_sum;
    2848       71713 :                             part_idx_sum = max_sum_idx;
    2849             :                         }
    2850             :                     }
    2851             :                 }
    2852      705910 :                 assert( sum_s( idx, no_ism_loc ) == max_sum_idx );
    2853             :             }
    2854             :             else
    2855             :             {
    2856       20956 :                 idx[0] = max_sum_idx;
    2857             :             }
    2858             : 
    2859      726866 :             if ( no_ism_loc < nchan_ism )
    2860             :             {
    2861             :                 /*  insert back the ratio of the separated object  */
    2862     1553910 :                 for ( i = nchan_ism - 1; i > idx_sep_object; i-- )
    2863             :                 {
    2864      897982 :                     idx[i] = idx[i - 1];
    2865             :                 }
    2866      655928 :                 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     1239089 :     return;
    2876             : }
    2877             : 
    2878             : 
    2879      106906 : 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      106906 :     if ( nchan_ism == 2 )
    2888             :     {
    2889        7703 :         index = ratio_ism_idx[0];
    2890             :     }
    2891             :     else
    2892             :     {
    2893       99203 :         x = ratio_ism_idx[nchan_ism - 2];
    2894       99203 :         base = 10;
    2895      274449 :         for ( i = nchan_ism - 3; i >= 0; i-- )
    2896             :         {
    2897      175246 :             x += ratio_ism_idx[i] * base;
    2898      175246 :             base *= 10;
    2899             :         }
    2900             : 
    2901       99203 :         index = 0;
    2902       99203 :         i = 0;
    2903    11544110 :         while ( i <= x )
    2904             :         {
    2905    11444907 :             if ( valid_ratio_index( i, 7, nchan_ism - 1 ) )
    2906             :             {
    2907     3213638 :                 index++;
    2908             :             }
    2909    11444907 :             i++;
    2910             :         }
    2911       99203 :         index--;
    2912             :     }
    2913             : 
    2914      106906 :     return index;
    2915             : }
    2916             : 
    2917             : 
    2918     1686755 : 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     5391742 :     for ( i = 0; i < len; i++ )
    2925             :     {
    2926     3704987 :         if ( diff_idx[i] <= 0 )
    2927             :         {
    2928     3358264 :             idx[i] = -2 * diff_idx[i];
    2929             :         }
    2930             :         else
    2931             :         {
    2932      346723 :             idx[i] = 2 * diff_idx[i] - 1;
    2933             :         }
    2934             :     }
    2935             : 
    2936     1686755 :     return;
    2937             : }
    2938             : 
    2939             : 
    2940      619530 : 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      619530 :     transform_difference_index( diff_idx, idx, len );
    2952             : 
    2953             :     /* GR encoding */
    2954     1991054 :     for ( i = 0; i < len; i++ )
    2955             :     {
    2956     1371524 :         ivas_qmetadata_encode_extended_gr( hMetaData, idx[i], 100, GR_order );
    2957             :     }
    2958             : 
    2959      619530 :     return;
    2960             : }
    2961             : 
    2962             : 
    2963       82794 : 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       82794 :     b_signif = 0;
    2978      305556 :     while ( ( b_signif < numCodingBands ) && ( masa_to_total_energy_ratio[b_signif] >= MASA2TOTAL_THR ) )
    2979             :     {
    2980      222762 :         b_signif++;
    2981             :     }
    2982             : 
    2983       82794 :     nbits0 = 0;
    2984             : 
    2985       82794 :     if ( b_signif < numCodingBands )
    2986             :     {
    2987       53170 :         nbits0 = bits_index;
    2988       53170 :         mvs2s( ratio_ism_idx[b_signif], ratio_ism_idx_ref, nchan_ism );
    2989             : 
    2990      372836 :         for ( b = b_signif + 1; b < numCodingBands; b++ )
    2991             :         {
    2992      319666 :             if ( masa_to_total_energy_ratio[b] < MASA2TOTAL_THR )
    2993             :             {
    2994      279276 :                 v_sub_s( ratio_ism_idx[b], ratio_ism_idx_ref, diff_idx, nchan_ism );
    2995      279276 :                 mvs2s( ratio_ism_idx[b], ratio_ism_idx_ref, nchan_ism );
    2996             : 
    2997             :                 /* transform difference index into positive */
    2998      279276 :                 transform_difference_index( diff_idx, diff_idx, nchan_ism - 1 );
    2999             : 
    3000             :                 /* GR encoding */
    3001      988330 :                 for ( i = 0; i < nchan_ism - 1; i++ )
    3002             :                 {
    3003      709054 :                     nbits0 += ivas_qmetadata_encode_extended_gr_length( diff_idx[i], 100, 0 );
    3004             :                 }
    3005             :             }
    3006             :         }
    3007             :     }
    3008       82794 :     *p_b_signif = b_signif;
    3009             : 
    3010       82794 :     return nbits0;
    3011             : }
    3012             : 
    3013             : 
    3014       39486 : 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       39486 :     push_next_indice( hMetaData, 0, 1 );
    3029             : 
    3030       39486 :     if ( b_signif < numCodingBands )
    3031             :     {
    3032       39486 :         index = index_slice_enum( ratio_ism_idx[b_signif], nchan_ism );
    3033       39486 :         push_next_indice( hMetaData, index, bits_index );
    3034             : 
    3035       39486 :         mvs2s( ratio_ism_idx[b_signif], ratio_ism_idx_ref, nchan_ism );
    3036             : 
    3037      296466 :         for ( b = b_signif + 1; b < numCodingBands; b++ )
    3038             :         {
    3039      256980 :             if ( masa_to_total_energy_ratio[b] < MASA2TOTAL_THR )
    3040             :             {
    3041      225540 :                 v_sub_s( ratio_ism_idx[b], ratio_ism_idx_ref, diff_idx, nchan_ism );
    3042      225540 :                 mvs2s( ratio_ism_idx[b], ratio_ism_idx_ref, nchan_ism );
    3043             : 
    3044             :                 /* transform difference index into positive */
    3045      225540 :                 transform_index_and_GR_encode( diff_idx, nchan_ism - 1, 0, hMetaData );
    3046             :             }
    3047             :         }
    3048             :     }
    3049             : 
    3050       39486 :     return;
    3051             : }
    3052             : 
    3053             : 
    3054       13684 : 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       92504 :     for ( b = 0; b < numCodingBands; b++ )
    3066             :     {
    3067       78820 :         if ( masa_to_total_energy_ratio[b] < MASA2TOTAL_THR )
    3068             :         {
    3069       67420 :             index = index_slice_enum( ratio_ism_idx[b], nchan_ism );
    3070       67420 :             push_next_indice( hMetaData, index, bits_index );
    3071             :         }
    3072             :     }
    3073             : 
    3074       13684 :     return;
    3075             : }
    3076             : 
    3077             : 
    3078      775842 : 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     2431089 :     for ( i = idx_sep_obj; i < nchan_ism - 1; i++ )
    3087             :     {
    3088     1655247 :         diff_idx[i] = diff_idx[i + 1];
    3089             :     }
    3090             : 
    3091      775842 :     return;
    3092             : }
    3093             : 
    3094             : 
    3095      787949 : 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      787949 :     nbits0 = 0;
    3109      787949 :     nbits1 = 0;
    3110             : 
    3111             :     /* take difference with respect to previous subframe */
    3112      787949 :     v_sub_s( ratio_ism_idx, ratio_ism_idx_ref, diff_idx, nchan_ism );
    3113             : 
    3114      787949 :     if ( shift_one )
    3115             :     {
    3116      517228 :         remove_sep_obj( diff_idx, nchan_ism, idx_sep_obj );
    3117             :     }
    3118             : 
    3119             :     /* transform difference index into positive */
    3120      787949 :     transform_difference_index( diff_idx, diff_idx, nchan_ism - 1 - shift_one );
    3121             : 
    3122             :     /* GR encoding */
    3123     2412358 :     for ( i = 0; i < nchan_ism - 1 - shift_one; i++ )
    3124             :     {
    3125     1624409 :         nbits0 += ivas_qmetadata_encode_extended_gr_length( diff_idx[i], 100, 0 );
    3126     1624409 :         nbits1 += ivas_qmetadata_encode_extended_gr_length( diff_idx[i], 100, 1 );
    3127             :     }
    3128             : 
    3129      787949 :     *p_nbits0 = nbits0;
    3130      787949 :     *p_nbits1 = nbits1;
    3131             : 
    3132      787949 :     return;
    3133             : }
    3134             : 
    3135             : 
    3136      212589 : 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      212589 :     idx_sep_obj_local = idx_separated_obj;
    3160      212589 :     if ( idx_separated_obj > -1 )
    3161             :     {
    3162      212589 :         if ( idx_separated_obj == nchan_ism - 1 )
    3163             :         {
    3164       73603 :             idx_sep_obj_local = 0;
    3165             :         }
    3166             :     }
    3167      212589 :     nbits = 0;
    3168      212589 :     nbits0 = 0;
    3169      212589 :     nbits1 = 0;
    3170             : 
    3171             : #ifdef DEBUGGING
    3172             :     bits_pos0 = hMetaData->nb_bits_tot;
    3173             : #endif
    3174      212589 :     differential_subframe = 1; /* the differences are taken with respect to previous subframe */
    3175             : 
    3176             :     /* first subframe */
    3177      212589 :     bits_index = 0;
    3178      212589 :     if ( sf == 0 )
    3179             :     {
    3180       82794 :         bits_index = bits_index_ism_ratio( nchan_ism );
    3181             : 
    3182       82794 :         nbits = 0;
    3183      678392 :         for ( b = 0; b < numCodingBands; b++ )
    3184             :         {
    3185      595598 :             if ( masa_to_total_energy_ratio[b] < MASA2TOTAL_THR )
    3186             :             {
    3187      332446 :                 nbits += bits_index;
    3188             :             }
    3189             :         }
    3190             : 
    3191       82794 :         nbits0 = try_differential( numCodingBands, masa_to_total_energy_ratio, ratio_ism_idx, nchan_ism, bits_index, &b_signif );
    3192             : 
    3193       82794 :         if ( nbits <= nbits0 && nbits > 0 )
    3194             :         {
    3195             :             /* independent encoding */
    3196       13684 :             push_next_indice( hMetaData, 1, 1 );
    3197       13684 :             independent_coding_ratio_ism_idx( ratio_ism_idx, masa_to_total_energy_ratio, nchan_ism, numCodingBands, bits_index, hMetaData );
    3198       13684 :             nbits = nbits + 1;
    3199             :         }
    3200             :         else
    3201             :         {
    3202       69110 :             if ( nbits > 0 )
    3203             :             {
    3204       39486 :                 differential_coding_first_subframe( hMetaData, masa_to_total_energy_ratio, b_signif, ratio_ism_idx, nchan_ism, numCodingBands, bits_index );
    3205       39486 :                 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      129795 :         if ( shift_one == 1 && nchan_ism == 2 )
    3217             :         {
    3218         435 :             nbits = 0;
    3219             :         }
    3220             :         else
    3221             :         {
    3222      129360 :             nbits0 = 0;
    3223      129360 :             nbits1 = 0;
    3224             : 
    3225      772416 :             for ( b = 0; b < numCodingBands; b++ )
    3226             :             {
    3227      643056 :                 if ( masa_to_total_energy_ratio[b] < MASA2TOTAL_THR )
    3228             :                 {
    3229      393990 :                     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      393990 :                     nbits0 += nbits00;
    3231      393990 :                     nbits1 += nbits11;
    3232             :                 }
    3233             :             }
    3234      129360 :             if ( nbits0 < nbits1 )
    3235             :             {
    3236       77053 :                 GR_order = 0;
    3237       77053 :                 nbits = nbits0;
    3238             :             }
    3239             :             else
    3240             :             {
    3241       52307 :                 GR_order = 1;
    3242       52307 :                 nbits = nbits1;
    3243             :             }
    3244             : 
    3245      129360 :             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      128424 :                 nbits0 = 0;
    3250      128424 :                 nbits1 = 0;
    3251      128424 :                 b_signif = 0;
    3252      333844 :                 while ( ( b_signif < numCodingBands ) && ( masa_to_total_energy_ratio[b_signif] >= MASA2TOTAL_THR ) )
    3253             :                 {
    3254      205420 :                     b_signif++;
    3255             :                 }
    3256             : 
    3257      128424 :                 if ( b_signif < numCodingBands )
    3258             :                 {
    3259       90269 :                     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       90269 :                     mvs2s( ratio_ism_idx[b_signif], ratio_ism_idx_ref, nchan_ism );
    3262             : 
    3263      436700 :                     for ( b = b_signif + 1; b < numCodingBands; b++ )
    3264             :                     {
    3265      346431 :                         if ( masa_to_total_energy_ratio[b] < MASA2TOTAL_THR )
    3266             :                         {
    3267      303690 :                             estimate_bits_subband_ism_ratio( ratio_ism_idx[b], ratio_ism_idx_ref, nchan_ism, shift_one, idx_sep_obj_local, &nbits00, &nbits11 );
    3268      303690 :                             nbits0 += nbits00;
    3269      303690 :                             nbits1 += nbits11;
    3270      303690 :                             mvs2s( ratio_ism_idx[b], ratio_ism_idx_ref, nchan_ism );
    3271             :                         }
    3272             :                     }
    3273             : 
    3274       90269 :                     if ( nbits0 < nbits1 )
    3275             :                     {
    3276       57601 :                         GR_order_sb = 0;
    3277             :                     }
    3278             :                     else
    3279             :                     {
    3280       32668 :                         GR_order_sb = 1;
    3281       32668 :                         nbits0 = nbits1;
    3282             :                     }
    3283             : 
    3284       90269 :                     if ( nbits0 < nbits )
    3285             :                     {
    3286       10985 :                         differential_subframe = 0;
    3287       10985 :                         nbits = nbits0;
    3288       10985 :                         GR_order = GR_order_sb;
    3289             :                     }
    3290             : 
    3291       90269 :                     if ( nbits > 0 )
    3292             :                     {
    3293             :                         /* write prediction type */
    3294       90269 :                         push_next_indice( hMetaData, differential_subframe, 1 );
    3295             :                         /* write GR order */
    3296       90269 :                         push_next_indice( hMetaData, GR_order, 1 );
    3297       90269 :                         nbits++; /* for the prediction type */
    3298       90269 :                         nbits++; /* for GR_order */
    3299             : 
    3300             :                         /* write data */
    3301       90269 :                         if ( differential_subframe )
    3302             :                         {
    3303      475704 :                             for ( b = 0; b < numCodingBands; b++ )
    3304             :                             {
    3305      396420 :                                 if ( masa_to_total_energy_ratio[b] < MASA2TOTAL_THR )
    3306             :                                 {
    3307             :                                     /* take difference with respect to previous subframe */
    3308      348536 :                                     v_sub_s( ratio_ism_idx[b], ratio_ism_idx_prev_sf[b], diff_idx, nchan_ism );
    3309             : 
    3310      348536 :                                     if ( shift_one )
    3311             :                                     {
    3312      245682 :                                         remove_sep_obj( diff_idx, nchan_ism, idx_sep_obj_local );
    3313             :                                     }
    3314             : 
    3315      348536 :                                     transform_index_and_GR_encode( diff_idx, nchan_ism - 1 - shift_one, GR_order, hMetaData );
    3316             :                                 }
    3317             :                             }
    3318             :                         }
    3319             :                         else
    3320             :                         {
    3321       10985 :                             v_sub_s( ratio_ism_idx[b_signif], ratio_ism_idx_prev_sf[b_signif], diff_idx, nchan_ism );
    3322             : 
    3323       10985 :                             if ( shift_one )
    3324             :                             {
    3325        2675 :                                 remove_sep_obj( diff_idx, nchan_ism, idx_sep_obj_local );
    3326             :                             }
    3327             : 
    3328       10985 :                             transform_index_and_GR_encode( diff_idx, nchan_ism - 1 - shift_one, GR_order, hMetaData );
    3329             : 
    3330       10985 :                             mvs2s( ratio_ism_idx[b_signif], ratio_ism_idx_ref, nchan_ism - shift_one );
    3331             : 
    3332       53427 :                             for ( b = b_signif + 1; b < numCodingBands; b++ )
    3333             :                             {
    3334             :                                 /* take difference with respect to previous subband */
    3335       42442 :                                 if ( masa_to_total_energy_ratio[b] < MASA2TOTAL_THR )
    3336             :                                 {
    3337       34438 :                                     v_sub_s( ratio_ism_idx[b], ratio_ism_idx_ref, diff_idx, nchan_ism );
    3338             : 
    3339       34438 :                                     if ( shift_one )
    3340             :                                     {
    3341       10257 :                                         remove_sep_obj( diff_idx, nchan_ism, idx_sep_obj_local );
    3342             :                                     }
    3343             : 
    3344       34438 :                                     transform_index_and_GR_encode( diff_idx, nchan_ism - 1 - shift_one, GR_order, hMetaData );
    3345             : 
    3346       34438 :                                     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         936 :                 if ( nbits > 0 )
    3359             :                 {
    3360             :                     /* write GR order */
    3361          31 :                     push_next_indice( hMetaData, GR_order, 1 );
    3362          31 :                     nbits++; /* for GR_order */
    3363             :                     /* write data */
    3364             :                     /* only one subband */
    3365          31 :                     if ( masa_to_total_energy_ratio[0] < MASA2TOTAL_THR )
    3366             :                     {
    3367             :                         /* take difference with respect to previous subframe */
    3368          31 :                         v_sub_s( ratio_ism_idx[0], ratio_ism_idx_prev_sf[0], diff_idx, nchan_ism );
    3369             : 
    3370          31 :                         if ( shift_one )
    3371             :                         {
    3372           0 :                             remove_sep_obj( diff_idx, nchan_ism, idx_sep_obj_local );
    3373             :                         }
    3374             : 
    3375          31 :                         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      212589 :     return nbits;
    3387             : }
    3388             : 
    3389             : 
    3390       82794 : 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       82794 :     OMASA_ENCODER_DATA_HANDLE hOmasaData = hMasa->data.hOmasaData;
    3421       82794 :     OMASA_ENCODER_ENERGY_HANDLE hOmasaEnergy = hOmasaData->hOmasaEnergy;
    3422             :     int16_t nbands_work;
    3423             : 
    3424             :     /* use the values from hQMetaData */
    3425       82794 :     numCodingBands = (uint8_t) hQMetaData->q_direction->cfg.nbands;
    3426       82794 :     numSf = (int8_t) hQMetaData->q_direction->cfg.nblocks;
    3427       82794 :     nbands_work = min( numCodingBands, omasa_nbands );
    3428       82794 :     if ( numCodingBands == 1 )
    3429             :     {
    3430        2285 :         for ( sf = 0; sf < numSf; sf++ )
    3431             :         {
    3432        1828 :             if ( sum_f( hOmasaEnergy->energy_ism[sf], omasa_nbands ) == 0.0f )
    3433             :             {
    3434         856 :                 hOmasaData->masa_to_total_energy_ratio[sf][0] = 1.0f;
    3435             :             }
    3436             :             else
    3437             :             {
    3438         972 :                 brange[0] = hMasa->data.band_mapping[0];
    3439         972 :                 brange[1] = hMasa->data.band_mapping[omasa_nbands];
    3440         972 :                 eneBand = 0.0f;
    3441       24120 :                 for ( bin = brange[0]; bin < brange[1]; bin++ )
    3442             :                 {
    3443       23148 :                     eneBand += hMasa->data.energy[sf][bin];
    3444             :                 }
    3445             : 
    3446         972 :                 energy_ism = 0.0f;
    3447        2916 :                 for ( obj = 0; obj < nchan_ism; obj++ )
    3448             :                 {
    3449        1944 :                     energy_ism_ind[obj] = 0.0f;
    3450             :                 }
    3451             : 
    3452        5832 :                 for ( band = 0; band < omasa_nbands; band++ )
    3453             :                 {
    3454        4860 :                     energy_ism += hOmasaEnergy->energy_ism[sf][band];
    3455       14580 :                     for ( obj = 0; obj < nchan_ism; obj++ )
    3456             :                     {
    3457        9720 :                         energy_ism_ind[obj] += hOmasaEnergy->energy_ism[sf][band] * hOmasaEnergy->energy_ratio_ism[sf][band][obj];
    3458             :                     }
    3459             :                 }
    3460             : 
    3461        2916 :                 for ( obj = 0; obj < nchan_ism; obj++ )
    3462             :                 {
    3463        1944 :                     hOmasaEnergy->energy_ratio_ism[sf][0][obj] = energy_ism_ind[obj] / energy_ism;
    3464             :                 }
    3465         972 :                 hOmasaData->masa_to_total_energy_ratio[sf][0] = eneBand / ( eneBand + energy_ism + EPSILON );
    3466             :             }
    3467             :         }
    3468             :     }
    3469       82337 :     else if ( numSf == 1 )
    3470             :     {
    3471      420630 :         for ( band = 0; band < nbands_work; band++ )
    3472             :         {
    3473      381101 :             energy_ism = 0.0f; /* ISM energy for current subband */
    3474     1648911 :             for ( obj = 0; obj < nchan_ism; obj++ )
    3475             :             {
    3476     1267810 :                 energy_ism_ind[obj] = 0.0f;
    3477             :             }
    3478      874867 :             for ( sf = 0; sf < omasa_nblocks; sf++ )
    3479             :             {
    3480      493766 :                 energy_ism += hOmasaEnergy->energy_ism[sf][band];
    3481     1986906 :                 for ( obj = 0; obj < nchan_ism; obj++ )
    3482             :                 {
    3483     1493140 :                     energy_ism_ind[obj] += hOmasaEnergy->energy_ism[sf][band] * hOmasaEnergy->energy_ratio_ism[sf][band][obj];
    3484             :                 }
    3485             :             }
    3486             : 
    3487      381101 :             if ( energy_ism == 0.0f )
    3488             :             {
    3489      106595 :                 hOmasaData->masa_to_total_energy_ratio[0][band] = 1.0f;
    3490             :             }
    3491             :             else
    3492             :             {
    3493     1208850 :                 for ( obj = 0; obj < nchan_ism; obj++ )
    3494             :                 {
    3495      934344 :                     hOmasaEnergy->energy_ratio_ism[0][band][obj] = energy_ism_ind[obj] / energy_ism;
    3496             :                 }
    3497      274506 :                 brange[0] = hMasa->data.band_mapping[band];
    3498      274506 :                 brange[1] = hMasa->data.band_mapping[band + 1];
    3499             : 
    3500      274506 :                 eneBand = 0.0f;
    3501      614787 :                 for ( sf = 0; sf < omasa_nblocks; sf++ )
    3502             :                 {
    3503     1305490 :                     for ( bin = brange[0]; bin < brange[1]; bin++ )
    3504             :                     {
    3505      965209 :                         eneBand += hMasa->data.energy[sf][bin];
    3506             :                     }
    3507             :                 }
    3508      274506 :                 hOmasaData->masa_to_total_energy_ratio[0][band] = eneBand / ( eneBand + energy_ism + EPSILON );
    3509             :             }
    3510             :         }
    3511       39529 :         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      214040 :         for ( sf = 0; sf < numSf; sf++ )
    3524             :         {
    3525     1027392 :             for ( band = 0; band < nbands_work; band++ )
    3526             :             {
    3527      856160 :                 if ( hOmasaEnergy->energy_ism[sf][band] == 0.0f )
    3528             :                 {
    3529      191300 :                     hOmasaData->masa_to_total_energy_ratio[sf][band] = 1.0f;
    3530             :                 }
    3531             :                 else
    3532             :                 {
    3533      664860 :                     brange[0] = hMasa->data.band_mapping[band];
    3534      664860 :                     brange[1] = hMasa->data.band_mapping[band + 1];
    3535             : 
    3536      664860 :                     eneBand = 0.0f;
    3537     3823912 :                     for ( bin = brange[0]; bin < brange[1]; bin++ )
    3538             :                     {
    3539     3159052 :                         eneBand += hMasa->data.energy[sf][bin];
    3540             :                     }
    3541      664860 :                     hOmasaData->masa_to_total_energy_ratio[sf][band] = eneBand / ( eneBand + hOmasaEnergy->energy_ism[sf][band] + EPSILON );
    3542             :                 }
    3543             :             }
    3544      171232 :             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       82794 :     ivas_omasa_encode_masa_to_total( hOmasaData->masa_to_total_energy_ratio, hMetaData, low_bitrate_mode, numCodingBands, numSf );
    3556             : 
    3557             :     /* quantize ism_ratios */
    3558       82794 :     if ( nchan_ism > 1 )
    3559             :     {
    3560       82794 :         inv_step = ( ( 1 << PARAM_ISM_POW_RATIO_NBITS ) - 1 );
    3561       82794 :         step = 1.0f / inv_step;
    3562             : 
    3563       82794 :         rotate = 0;
    3564       82794 :         n_ism_tmp = 0;
    3565             : 
    3566      295383 :         for ( sf = 0; sf < numSf; sf++ )
    3567             :         {
    3568     1451678 :             for ( band = 0; band < numCodingBands; band++ )
    3569             :             {
    3570     5649395 :                 for ( obj = 0; obj < nchan_ism; obj++ )
    3571             :                 {
    3572     4410306 :                     assert( ( hOmasaEnergy->energy_ratio_ism[sf][band][obj] >= 0 ) && ( hOmasaEnergy->energy_ratio_ism[sf][band][obj] <= 1 ) );
    3573     4410306 :                     ratio_ism[band][obj] = hOmasaEnergy->energy_ratio_ism[sf][band][obj];
    3574             :                 }
    3575             : 
    3576             :                 /* Quantize ISM ratios */
    3577     1239089 :                 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     1239089 :                 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         978 :                     i = 0;
    3581        6921 :                     while ( ratio_ism_idx[band][idx_separated_object] > 0 )
    3582             :                     {
    3583        5943 :                         if ( i != idx_separated_object )
    3584             :                         {
    3585        4030 :                             ratio_ism_idx[band][i]++;
    3586        4030 :                             ratio_ism_idx[band][idx_separated_object]--;
    3587             :                         }
    3588        5943 :                         i++;
    3589        5943 :                         if ( i == nchan_ism )
    3590             :                         {
    3591        1269 :                             i = 0;
    3592             :                         }
    3593             :                     }
    3594             :                 }
    3595             : 
    3596             :                 /* reconstructed values */
    3597     1239089 :                 reconstruct_ism_ratios( ratio_ism_idx[band], nchan_ism, step, hOmasaEnergy->q_energy_ratio_ism[sf][band] );
    3598             :             }
    3599             : 
    3600      212589 :             if ( ( nchan_ism > 2 ) && ( idx_separated_object == nchan_ism - 1 ) )
    3601             :             {
    3602             :                 /* rotate components */
    3603       66204 :                 rotate = 1;
    3604      468148 :                 for ( band = 0; band < numCodingBands; band++ )
    3605             :                 {
    3606      401944 :                     if ( hOmasaData->masa_to_total_energy_ratio[sf][band] < MASA2TOTAL_THR )
    3607             :                     {
    3608      203741 :                         tmp = ratio_ism_idx[band][nchan_ism - 1];
    3609      203741 :                         ratio_ism_idx[band][nchan_ism - 1] = ratio_ism_idx[band][0];
    3610      203741 :                         ratio_ism_idx[band][0] = tmp;
    3611      203741 :                         if ( sf == 0 && tmp == 0 )
    3612             :                         {
    3613       74042 :                             n_ism_tmp += 1;
    3614             :                         }
    3615             : 
    3616      203741 :                         if ( n_ism_tmp == numCodingBands )
    3617             :                         {
    3618       75846 :                             assert( tmp == 0 );
    3619             :                         }
    3620             :                     }
    3621             :                 }
    3622             :             }
    3623             :             else
    3624             :             {
    3625      146385 :                 if ( idx_separated_object > -1 )
    3626             :                 {
    3627      983530 :                     for ( band = 0; band < numCodingBands; band++ )
    3628             :                     {
    3629      837145 :                         if ( hOmasaData->masa_to_total_energy_ratio[sf][band] < MASA2TOTAL_THR )
    3630             :                         {
    3631      523125 :                             if ( ratio_ism_idx[band][idx_separated_object] == 0 && sf == 0 )
    3632             :                             {
    3633      212974 :                                 n_ism_tmp++;
    3634             :                             }
    3635             :                         }
    3636             :                     }
    3637             :                 }
    3638             :             }
    3639             : 
    3640             :             /* encode data for current subframe */
    3641      212589 :             if ( sf > 0 && n_ism_tmp == numCodingBands )
    3642             :             {
    3643       53565 :                 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      159024 :                 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     1451678 :             for ( band = 0; band < numCodingBands; band++ )
    3653             :             {
    3654     1239089 :                 mvs2s( ratio_ism_idx[band], ratio_ism_idx_prev_sf[band], nchan_ism );
    3655             :             }
    3656             : 
    3657      212589 :             if ( rotate )
    3658             :             {
    3659      468148 :                 for ( band = 0; band < numCodingBands; band++ )
    3660             :                 {
    3661      401944 :                     if ( hOmasaData->masa_to_total_energy_ratio[sf][band] < MASA2TOTAL_THR )
    3662             :                     {
    3663      203741 :                         tmp = ratio_ism_idx[band][nchan_ism - 1];
    3664      203741 :                         ratio_ism_idx[band][nchan_ism - 1] = ratio_ism_idx[band][0];
    3665      203741 :                         ratio_ism_idx[band][0] = tmp;
    3666             :                     }
    3667             :                 }
    3668             :             }
    3669             :         }
    3670             :     }
    3671             : 
    3672       82794 :     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      361842 :     for ( obj = 0; obj < nchan_ism; obj++ )
    3676             :     {
    3677      279048 :         if ( bits_ism[obj] < 8 )
    3678             :         {
    3679             :             /* check is same as previous */
    3680      141123 :             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       13568 :                 push_next_indice( hMetaData, 1, 1 );
    3683             :                 /* the old stays the same */
    3684             :             }
    3685             :             else
    3686             :             {
    3687      127555 :                 push_next_indice( hMetaData, 0, 1 );
    3688      127555 :                 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      127555 :                 push_next_indice( hMetaData, idx_sph, bits_ism[obj] );
    3690      127555 :                 hIsmMeta[obj]->q_elevation_old = hIsmMeta[obj]->elevation;
    3691      127555 :                 hIsmMeta[obj]->q_azimuth_old = hIsmMeta[obj]->azimuth;
    3692             :             }
    3693             :         }
    3694             :         else
    3695             :         {
    3696      137925 :             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      137925 :             push_next_indice( hMetaData, idx_sph, bits_ism[obj] );
    3698      137925 :             hIsmMeta[obj]->q_elevation_old = hIsmMeta[obj]->elevation;
    3699      137925 :             hIsmMeta[obj]->q_azimuth_old = hIsmMeta[obj]->azimuth;
    3700             :         }
    3701             :     }
    3702             : 
    3703       82794 :     return;
    3704             : }
    3705             : 
    3706             : 
    3707             : /*-------------------------------------------------------------------*
    3708             :  * ivas_merge_masa_transports()
    3709             :  *
    3710             :  * Merge MASA transport channels
    3711             :  *-------------------------------------------------------------------*/
    3712             : 
    3713      260932 : 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      782796 :     for ( i = 0; i < num_transport_channels; i++ )
    3723             :     {
    3724   474854024 :         for ( j = 0; j < input_frame; j++ )
    3725             :         {
    3726   474332160 :             data_out_f[i][j] = data_in_f1[i][j] + data_in_f2[i][j];
    3727             :         }
    3728             :     }
    3729             : 
    3730      260932 :     return;
    3731             : }

Generated by: LCOV version 1.14