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

Generated by: LCOV version 1.14