From bb647bbfca76861e1c73e754a9cedfdd26bf0c3e Mon Sep 17 00:00:00 2001 From: Sandesh Venkatesh Date: Wed, 19 Jun 2024 11:47:48 +0530 Subject: [PATCH 1/2] Integrate lib_com functions in lib_enc modules [x] Integrated all the functions present in ivas_stereo_dft_com.c, ivas_stereo_mdct_bands_com.c, delay_comp.c and ivas_stereo_mdct_stereo_com.c [x] Integrated functions invdct4_transform, ivas_get_df_ratio_bits, ivas_qmetadata_azimuth_elevation_to_direction_vector, masa_sq, only_reduce_bits_direction in encoder [x] ivas_qmetadata_direction_vector_to_azimuth_elevation is integrated but disabled due to the high deviations observed after integrating the function. --- lib_com/delay_comp.c | 20 +- lib_com/ivas_qmetadata_com.c | 23 +- lib_com/ivas_stereo_dft_com.c | 140 +- lib_com/ivas_stereo_mdct_bands_com.c | 80 +- lib_com/ivas_stereo_mdct_stereo_com.c | 27 +- lib_dec/TonalComponentDetection.c | 2 +- lib_dec/ivas_stereo_dft_dec_fx.c | 4 +- lib_dec/lib_dec_fx.c | 5 +- lib_enc/ivas_corecoder_enc_reconfig.c | 4 + lib_enc/ivas_cpe_enc.c | 58 + lib_enc/ivas_dirac_enc.c | 464 +++ lib_enc/ivas_masa_enc.c | 379 ++- lib_enc/ivas_mcmasa_enc.c | 538 ++++ lib_enc/ivas_mct_core_enc.c | 15 + lib_enc/ivas_mct_enc.c | 12 + lib_enc/ivas_omasa_enc.c | 214 ++ lib_enc/ivas_qmetadata_enc.c | 4208 ++++++++++++++++++------- lib_enc/ivas_stereo_cng_enc.c | 7 + lib_enc/ivas_stereo_dft_enc.c | 18 + lib_enc/ivas_stereo_mdct_core_enc.c | 15 + lib_enc/ivas_stereo_mdct_stereo_enc.c | 12 +- lib_enc/ivas_stereo_switching_enc.c | 4 + lib_enc/lib_enc.c | 30 + lib_enc/lib_enc.h | 7 + 24 files changed, 5069 insertions(+), 1217 deletions(-) diff --git a/lib_com/delay_comp.c b/lib_com/delay_comp.c index 9174efd31..0c0beef9e 100644 --- a/lib_com/delay_comp.c +++ b/lib_com/delay_comp.c @@ -49,6 +49,7 @@ *--------------------------------------------------------------------------*/ /*! r: delay value in ns */ +#ifndef IVAS_FLOAT_FIXED int32_t get_delay( const int16_t enc_dec, /* i : encoder/decoder flag */ const int32_t io_fs, /* i : input/output sampling frequency */ @@ -111,13 +112,7 @@ int32_t get_delay( return delay; } - -/*-------------------------------------------------------------------------- - * get_delay_fx() - * - * Function returns various types of delays in the codec in ns. - *--------------------------------------------------------------------------*/ - +#else Word32 get_delay_fx( /* o : delay value in ms */ const Word16 what_delay, /* i : what delay? (ENC or DEC) */ const Word32 io_fs, /* i : input/output sampling frequency */ @@ -130,6 +125,7 @@ Word32 get_delay_fx( /* o : delay value in ms ) { Word32 delay = 0; + move32(); IF( EQ_16( what_delay, ENC ) ) { @@ -141,17 +137,19 @@ Word32 get_delay_fx( /* o : delay value in ms ELSE { delay = IVAS_ENC_DELAY_NS; + move32(); test(); IF( EQ_16( ivas_format, MASA_FORMAT ) || EQ_16( ivas_format, MASA_ISM_FORMAT ) ) { delay = 0; /* All delay is compensated in the decoder with MASA */ + move32(); } } test(); IF( EQ_16( ivas_format, SBA_FORMAT ) || EQ_16( ivas_format, SBA_ISM_FORMAT ) ) { /* compensate for DirAC/SPAR filterbank delay */ - delay += IVAS_FB_ENC_DELAY_NS; + delay = L_add( delay, IVAS_FB_ENC_DELAY_NS ); } } ELSE @@ -172,6 +170,7 @@ Word32 get_delay_fx( /* o : delay value in ms ELSE /* IVAS */ { delay = IVAS_DEC_DELAY_NS; + move32(); #ifdef SPLIT_REND_WITH_HEAD_ROT @@ -181,7 +180,7 @@ Word32 get_delay_fx( /* o : delay value in ms IF( hCldfb != NULL ) { /* compensate for filterbank delay */ - delay += IVAS_FB_DEC_DELAY_NS; + delay = L_add( delay, IVAS_FB_DEC_DELAY_NS ); } #ifdef SPLIT_REND_WITH_HEAD_ROT } @@ -189,10 +188,11 @@ Word32 get_delay_fx( /* o : delay value in ms test(); IF( EQ_16( ivas_format, MASA_FORMAT ) || EQ_16( ivas_format, MASA_ISM_FORMAT ) ) { - delay += IVAS_ENC_DELAY_NS; /* Compensate also the encoder delay in the decoder with MASA */ + delay = L_add( delay, IVAS_ENC_DELAY_NS ); /* Compensate also the encoder delay in the decoder with MASA */ } } } return delay; } +#endif diff --git a/lib_com/ivas_qmetadata_com.c b/lib_com/ivas_qmetadata_com.c index f816a740a..bc998fed5 100644 --- a/lib_com/ivas_qmetadata_com.c +++ b/lib_com/ivas_qmetadata_com.c @@ -466,6 +466,7 @@ void ivas_qmetadata_close( *------------------------------------------------------------------------*/ /*! r: codeword index */ +#ifndef IVAS_FLOAT_FIXED int16_t masa_sq( const float in, /* i : input value */ const float *threshold, /* i : partition */ @@ -484,8 +485,7 @@ int16_t masa_sq( return -1; } - -#ifdef IVAS_FLOAT_FIXED +#else Word16 masa_sq_fx( const Word32 in, /* i : input value */ const Word32 *threshold, /* i : partition */ @@ -728,7 +728,7 @@ ivas_error only_reduce_bits_direction_fx( return IVAS_ERR_OK; } -#endif +#else ivas_error only_reduce_bits_direction( int16_t *reduce_bits_out, IVAS_QDIRECTION *q_direction, /* i/o: quantized direction structure */ @@ -834,6 +834,7 @@ ivas_error only_reduce_bits_direction( return IVAS_ERR_OK; } +#endif /*--------------------------------------------------------------- @@ -940,6 +941,7 @@ void update_bits_next_block( * Inverse DCT transform for 4D vector *---------------------------------------------------------------*/ +#ifndef IVAS_FLOAT_FIXED void invdct4_transform( float *v, /* i : input vector */ uint8_t *invdct_v /* o : inverse transformed vector */ @@ -976,8 +978,7 @@ void invdct4_transform( return; } - -#ifdef IVAS_FLOAT_FIXED +#else void invdct4_transform_fx( Word32 *v_fx, /* i : input vector */ UWord8 *invdct_v, /* o : inverse transformed vector */ @@ -1052,7 +1053,7 @@ void masa_compensate_two_dir_energy_ratio_index_fx( return; } -#endif +#else void masa_compensate_two_dir_energy_ratio_index( const int16_t ratio_index_1, /* i : Input ratio for direction 1 */ const int16_t ratio_index_2, /* i : Input ratio for direction 2 */ @@ -1091,7 +1092,7 @@ void masa_compensate_two_dir_energy_ratio_index( return; } - +#endif /*--------------------------------------------------------------- * set_qmetadata_maxbit_req() @@ -1144,6 +1145,7 @@ void ivas_set_qmetadata_maxbit_req( * *------------------------------------------------------------------------*/ +#ifndef IVAS_FLOAT_FIXED void ivas_qmetadata_azimuth_elevation_to_direction_vector( const float az, /* i : azimuth */ const float el, /* i : elevation */ @@ -1160,8 +1162,7 @@ void ivas_qmetadata_azimuth_elevation_to_direction_vector( return; } - -#ifdef IVAS_FLOAT_FIXED +#else void ivas_qmetadata_azimuth_elevation_to_direction_vector_fx( const Word32 az, /* i : azimuth */ const Word32 el, /* i : elevation */ @@ -1171,8 +1172,8 @@ void ivas_qmetadata_azimuth_elevation_to_direction_vector_fx( Word16 radius_length; Word16 elevation_fx, azimuth_fx; - elevation_fx = extract_l( L_shr( Mpy_32_16_1( el, 91 ), 7 ) ); - azimuth_fx = extract_l( L_shr( Mpy_32_16_1( az, 91 ), 7 ) ); + elevation_fx = extract_l( L_shr( Mpy_32_32( el, 5965232 ), 7 ) ); + azimuth_fx = extract_l( L_shr( Mpy_32_32( az, 5965232 ), 7 ) ); dv[2] = L_shl( getSineWord16R2( elevation_fx ), Q15 ); /* Q30 */ move32(); diff --git a/lib_com/ivas_stereo_dft_com.c b/lib_com/ivas_stereo_dft_com.c index 02eb6dfb0..595d8f1db 100644 --- a/lib_com/ivas_stereo_dft_com.c +++ b/lib_com/ivas_stereo_dft_com.c @@ -43,13 +43,13 @@ #include "ivas_prot_fx.h" #endif -#ifdef IVAS_FLOAT_FIXED /*------------------------------------------------------------------------- * stereo_dft_config() * * DFT Stereo Configuration function *------------------------------------------------------------------------*/ +#ifdef IVAS_FLOAT_FIXED void stereo_dft_config_fx( STEREO_DFT_CONFIG_DATA_HANDLE hConfig, /* o : DFT stereo configuration */ const Word32 brate, /* i : IVAS/CPE/nominal total bitrate */ @@ -195,80 +195,7 @@ void stereo_dft_config_fx( return; } - -/*------------------------------------------------------------------------- - * stereo_dft_band_config() - * - * Stereo DFT bands condfiguration - *------------------------------------------------------------------------*/ - -Word16 stereo_dft_band_config_fx( - Word16 *band_limits, /* o : DFT band limits */ - const Word16 band_res, /* i : DFT band resolution */ - const Word16 NFFT, /* i : analysis/synthesis window length */ - const Word16 enc_dec /* i : flag to indicate enc vs dec */ -) -{ - Word16 nbands; - - /*sanity check*/ - assert( ( EQ_16( band_res, 1 ) || EQ_16( band_res, 0 ) || EQ_16( band_res, 2 ) ) && "stereo DFT: Parameter band resolution not supported!\n" ); - - band_limits[0] = 1; - move16(); - nbands = 0; - move16(); - WHILE( LT_16( band_limits[nbands++], shr( NFFT, 1 ) ) ) - { - IF( EQ_16( band_res, 0 ) ) - { - assert( 0 && "stereo DFT: band config failed!\n" ); - } - ELSE IF( EQ_16( band_res, 1 ) ) - { - IF( EQ_16( enc_dec, ENC ) ) - { - band_limits[nbands] = round_fx( L_mult0( shl( dft_band_limits_erb4[nbands], 2 ), 26214 /* 1.60000002 in Q14 */ ) ); - move16(); - } - ELSE - { - band_limits[nbands] = round_fx( L_mult0( shl( dft_band_limits_erb4[nbands], 1 ), 26214 /* 0.800000012 in Q14 */ ) ); - move16(); - } - - assert( ( LT_16( nbands, STEREO_DFT_ERB4_BANDS ) ) && "stereo DFT: band config failed!\n" ); - } - ELSE - { - IF( EQ_16( enc_dec, ENC ) ) - { - band_limits[nbands] = round_fx( L_mult0( shl( dft_band_limits_erb8[nbands], 2 ), 26214 /* 1.60000002 in Q14 */ ) ); - move16(); - } - ELSE - { - band_limits[nbands] = round_fx( L_mult0( shl( dft_band_limits_erb8[nbands], 1 ), 26214 /* 0.800000012 in Q14 */ ) ); - move16(); - } - - assert( ( LT_16( nbands, STEREO_DFT_ERB8_BANDS ) ) && "stereo DFT: band config failed!\n" ); - } - } - nbands = sub( nbands, 1 ); - band_limits[nbands] = shr( NFFT, 1 ); /*Nyquist Freq*/ - move16(); - - return ( nbands ); -} -#endif - -/*------------------------------------------------------------------------- - * stereo_dft_config() - * - * DFT Stereo Configuration function - *------------------------------------------------------------------------*/ - +#else void stereo_dft_config( STEREO_DFT_CONFIG_DATA_HANDLE hConfig, /* o : DFT stereo configuration */ const int32_t brate, /* i : IVAS/CPE/nominal total bitrate */ @@ -378,6 +305,7 @@ void stereo_dft_config( return; } +#endif /*------------------------------------------------------------------------- * stereo_dft_band_config() @@ -385,6 +313,67 @@ void stereo_dft_config( * Stereo DFT bands condfiguration *------------------------------------------------------------------------*/ +#ifdef IVAS_FLOAT_FIXED +Word16 stereo_dft_band_config_fx( + Word16 *band_limits, /* o : DFT band limits */ + const Word16 band_res, /* i : DFT band resolution */ + const Word16 NFFT, /* i : analysis/synthesis window length */ + const Word16 enc_dec /* i : flag to indicate enc vs dec */ +) +{ + Word16 nbands; + + /*sanity check*/ + assert( ( EQ_16( band_res, 1 ) || EQ_16( band_res, 0 ) || EQ_16( band_res, 2 ) ) && "stereo DFT: Parameter band resolution not supported!\n" ); + + band_limits[0] = 1; + move16(); + nbands = 0; + move16(); + WHILE( LT_16( band_limits[nbands++], shr( NFFT, 1 ) ) ) + { + IF( EQ_16( band_res, 0 ) ) + { + assert( 0 && "stereo DFT: band config failed!\n" ); + } + ELSE IF( EQ_16( band_res, 1 ) ) + { + IF( enc_dec == ENC ) + { + band_limits[nbands] = round_fx( L_mult0( shl( dft_band_limits_erb4[nbands], 2 ), 26214 /* 1.60000002 in Q14 */ ) ); + move16(); + } + ELSE + { + band_limits[nbands] = round_fx( L_mult0( shl( dft_band_limits_erb4[nbands], 1 ), 26214 /* 0.800000012 in Q14 */ ) ); + move16(); + } + + assert( ( LT_16( nbands, STEREO_DFT_ERB4_BANDS ) ) && "stereo DFT: band config failed!\n" ); + } + ELSE + { + IF( enc_dec == ENC ) + { + band_limits[nbands] = round_fx( L_mult0( shl( dft_band_limits_erb8[nbands], 2 ), 26214 /* 1.60000002 in Q14 */ ) ); + move16(); + } + ELSE + { + band_limits[nbands] = round_fx( L_mult0( shl( dft_band_limits_erb8[nbands], 1 ), 26214 /* 0.800000012 in Q14 */ ) ); + move16(); + } + + assert( ( LT_16( nbands, STEREO_DFT_ERB8_BANDS ) ) && "stereo DFT: band config failed!\n" ); + } + } + nbands = sub( nbands, 1 ); + band_limits[nbands] = shr( NFFT, 1 ); /*Nyquist Freq*/ + move16(); + + return ( nbands ); +} +#else int16_t stereo_dft_band_config( int16_t *band_limits, /* o : DFT band limits */ const int16_t band_res, /* i : DFT band resolution */ @@ -437,3 +426,4 @@ int16_t stereo_dft_band_config( return ( nbands ); } +#endif diff --git a/lib_com/ivas_stereo_mdct_bands_com.c b/lib_com/ivas_stereo_mdct_bands_com.c index af8110c06..3c06612c4 100644 --- a/lib_com/ivas_stereo_mdct_bands_com.c +++ b/lib_com/ivas_stereo_mdct_bands_com.c @@ -84,47 +84,54 @@ void stereo_mdct_init_bands_fx( IF( tmp_tcx_mode > 0 ) { tcx_mode = tmp_tcx_mode; - L_frameTCX = ( tcx_mode == TCX_20_CORE ) ? L_frame : ( L_frame / 2 ); + move16(); + L_frameTCX = EQ_16( tcx_mode, TCX_20_CORE ) ? L_frame : ( L_frame / 2 ); + move16(); } ELSE { /*transition frame*/ - L_frameTCX = L_frame + L_frame / 4; + L_frameTCX = add( L_frame, L_frame / 4 ); tcx_mode = TCX_20_CORE; + move16(); } /* select table */ - IF( L_frame == L_FRAME48k ) + IF( EQ_16( L_frame, L_FRAME48k ) ) { sfbParam.steBands = mdctStereoBands_32000_640; - cnt = ( tcx_mode == TCX_20_CORE ? sfbParam.steBands->bdnCnt_TCX20[0] : sfbParam.steBands->bndCnt_TCX10[0] ); + cnt = EQ_16( tcx_mode, TCX_20_CORE ) ? sfbParam.steBands->bdnCnt_TCX20[0] : sfbParam.steBands->bndCnt_TCX10[0]; + move16(); - sfbWidths = ( tcx_mode == TCX_20_CORE ? sfbParam.steBands->bandLengthsTCX20 : sfbParam.steBands->bandLengthsTCX10 ); + sfbWidths = EQ_16( tcx_mode, TCX_20_CORE ) ? sfbParam.steBands->bandLengthsTCX20 : sfbParam.steBands->bandLengthsTCX10; } ELSE { - IF( element_brate < IVAS_96k ) + IF( LT_32( element_brate, IVAS_96k ) ) { sfbParam.steBands = mdctStereoBands_32000_640; SWITCH( L_frame ) { case L_FRAME32k: - cnt = ( tcx_mode == TCX_20_CORE ? sfbParam.steBands->bdnCnt_TCX20[1] : sfbParam.steBands->bndCnt_TCX10[1] ); + cnt = EQ_16( tcx_mode, TCX_20_CORE ) ? sfbParam.steBands->bdnCnt_TCX20[1] : sfbParam.steBands->bndCnt_TCX10[1]; + move16(); BREAK; case L_FRAME25_6k: - cnt = ( tcx_mode == TCX_20_CORE ? sfbParam.steBands->bdnCnt_TCX20[2] : sfbParam.steBands->bndCnt_TCX10[2] ); + cnt = EQ_16( tcx_mode, TCX_20_CORE ) ? sfbParam.steBands->bdnCnt_TCX20[2] : sfbParam.steBands->bndCnt_TCX10[2]; + move16(); BREAK; case L_FRAME16k: - cnt = ( tcx_mode == TCX_20_CORE ? sfbParam.steBands->bdnCnt_TCX20[3] : sfbParam.steBands->bndCnt_TCX10[3] ); + cnt = EQ_16( tcx_mode, TCX_20_CORE ) ? sfbParam.steBands->bdnCnt_TCX20[3] : sfbParam.steBands->bndCnt_TCX10[3]; + move16(); BREAK; default: assert( !"Subband division not defined for this frame size" ); return; } - sfbWidths = ( tcx_mode == TCX_20_CORE ? sfbParam.steBands->bandLengthsTCX20 : sfbParam.steBands->bandLengthsTCX10 ); + sfbWidths = EQ_16( tcx_mode, TCX_20_CORE ) ? sfbParam.steBands->bandLengthsTCX20 : sfbParam.steBands->bandLengthsTCX10; } ELSE { @@ -145,33 +152,40 @@ void stereo_mdct_init_bands_fx( return; } - sfbWidths = ( tcx_mode == TCX_20_CORE ? sfbParam.lpcBndsParam->bandLengthsTCX20 : sfbParam.lpcBndsParam->bandLengthsTCX10 ); + sfbWidths = EQ_16( tcx_mode, TCX_20_CORE ) ? sfbParam.lpcBndsParam->bandLengthsTCX20 : sfbParam.lpcBndsParam->bandLengthsTCX10; cnt = 64; + move16(); } } /* calc sfb offsets */ specStartOffset = 0; + move16(); FOR( i = 0; i < cnt; i++ ) { - sfbOffset[i] = min( specStartOffset, L_frameTCX ); - specStartOffset += sfbWidths[i]; + sfbOffset[i] = s_min( specStartOffset, L_frameTCX ); + move16(); + specStartOffset = add( specStartOffset, sfbWidths[i] ); - IF( sfbOffset[i] >= L_frameTCX ) + IF( GE_16( sfbOffset[i], L_frameTCX ) ) { BREAK; } } *sfbCnt = i; - sfbOffset[*sfbCnt] = min( specStartOffset, L_frameTCX ); + move16(); + sfbOffset[*sfbCnt] = s_min( specStartOffset, L_frameTCX ); + move16(); IF( igf ) { Word16 sfbOldCnt = *sfbCnt; Word16 igfSfbStep = hIgfGrid->infoIsRefined ? 2 : 1; Word16 k; + move16(); + move16(); /* modify sfb bands according to igf grid */ assert( hIgfGrid != NULL ); @@ -179,44 +193,49 @@ void stereo_mdct_init_bands_fx( /* find sfb where IGF starts */ FOR( i = 0; i <= *sfbCnt; i++ ) { - IF( sfbOffset[i] >= hIgfGrid->startLine ) + IF( GE_16( sfbOffset[i], hIgfGrid->startLine ) ) { /* set band border to igf start line */ sfbOffset[i] = hIgfGrid->startLine; + move16(); *sfbCnt = i; + move16(); BREAK; } } /* change bands above the igf start line to match igf bands */ - for ( i = 1, k = igfSfbStep; i < hIgfGrid->swb_offset_len; i++, k += igfSfbStep ) + FOR( ( i = 1, k = igfSfbStep ); i < hIgfGrid->swb_offset_len; ( i++, k += igfSfbStep ) ) { - sfbOffset[*sfbCnt + i] = hIgfGrid->swb_offset[k]; + sfbOffset[add( *sfbCnt, i )] = hIgfGrid->swb_offset[k]; + move16(); } - *sfbCnt += ( hIgfGrid->swb_offset_len - 1 ); + *sfbCnt = add( *sfbCnt, sub( hIgfGrid->swb_offset_len, 1 ) ); + move16(); /* better save than sorry, overwrite anything that is left above */ FOR( i = *sfbCnt + 1; i < sfbOldCnt + 1; i++ ) { sfbOffset[i] = 0; + move16(); } } ELSE { - IF( sfbOffset[*sfbCnt] < L_frameTCX ) + IF( LT_16( sfbOffset[*sfbCnt], L_frameTCX ) ) { - Word16 nMissingBins = L_frameTCX - sfbOffset[*sfbCnt]; - IF( sfbWidths[i] / 2 < nMissingBins ) + Word16 nMissingBins = sub( L_frameTCX, sfbOffset[*sfbCnt] ); + if ( LT_16( sfbWidths[i] / 2, nMissingBins ) ) { ( *sfbCnt )++; } sfbOffset[*sfbCnt] = L_frameTCX; + move16(); } } return; } -#endif - +#else void stereo_mdct_init_bands( const int16_t L_frame, /* i : frame length */ const int16_t tmp_tcx_mode, /* i : tcx mode (TCX10, TCX 20), -1 if transition frame */ @@ -365,6 +384,7 @@ void stereo_mdct_init_bands( } return; } +#endif /*-------------------------------------------------------------------* * stereo_mdct_init_igf_start_band() @@ -389,20 +409,21 @@ void stereo_mdct_init_igf_start_band_fx( FOR( i = 0; i < stbParams->sfbCnt; i++ ) { - IF( igfStartLine == stbParams->sfbOffset[i] ) + IF( EQ_16( igfStartLine, stbParams->sfbOffset[i] ) ) { stbParams->sfbIgfStart = i; + move16(); BREAK; } } stbParams->nBandsStereoCore = stbParams->sfbIgfStart; + move16(); return; } -#endif - +#else void stereo_mdct_init_igf_start_band( STEREO_MDCT_BAND_PARAMETERS *stbParams, /* i/o: stereo frequency band parameters */ const float transFac, /* i : transform factor */ @@ -413,11 +434,7 @@ void stereo_mdct_init_igf_start_band( int16_t i, bitRateIndex, igfStartLine; const int16_t *swb_offset; -#ifdef IVAS_FLOAT_FIXED - bitRateIndex = IGF_MapBitRateToIndex( element_brate, bwidth, IVAS_CPE_MDCT, 0 ); -#else bitRateIndex = IGF_MapBitRateToIndex_flt( element_brate, bwidth, IVAS_CPE_MDCT, 0 ); -#endif swb_offset = &swb_offset_LB_new[bitRateIndex][1]; igfStartLine = IGF_ApplyTransFac_flt( swb_offset[0], transFac ); @@ -435,3 +452,4 @@ void stereo_mdct_init_igf_start_band( return; } +#endif diff --git a/lib_com/ivas_stereo_mdct_stereo_com.c b/lib_com/ivas_stereo_mdct_stereo_com.c index 275dcbdae..28e22b28c 100644 --- a/lib_com/ivas_stereo_mdct_stereo_com.c +++ b/lib_com/ivas_stereo_mdct_stereo_com.c @@ -42,14 +42,13 @@ #include "ivas_prot_fx.h" #endif -#ifdef IVAS_FLOAT_FIXED -#define POINT_2_Q15 6554 /*-------------------------------------------------------------------* * splitAvailableBits() * * split available bits between channels based on the split ratio *-------------------------------------------------------------------*/ +#ifdef IVAS_FLOAT_FIXED void splitAvailableBits_fx( const Word16 total_bits, /* i : total available bits for TCX coding */ const Word16 split_ratio, /* i : split ratio */ @@ -60,25 +59,22 @@ void splitAvailableBits_fx( { assert( split_ratio >= 1 && split_ratio < SMDCT_BITRATE_RATIO_RANGE ); - *bits_ch0 = split_ratio * total_bits / SMDCT_BITRATE_RATIO_RANGE; + /* *bits_ch0 = split_ratio * total_bits / SMDCT_BITRATE_RATIO_RANGE; */ + *bits_ch0 = extract_l( L_mult0( split_ratio, total_bits ) / SMDCT_BITRATE_RATIO_RANGE ); + move16(); /* for SBA mode bias the distribution towards the W channel */ - if ( split_ratio < 7 && isSBAStereoMode ) + test(); + IF( LT_16( split_ratio, 7 ) && isSBAStereoMode ) { - //*bits_ch0 += (int16_t) ( 0.2 * *bits_ch0 ); - *bits_ch0 += (Word16) ( Mpy_32_16_1( 6554, *bits_ch0 ) ); // 0.2 in Q15 + *bits_ch0 = add( *bits_ch0, extract_l( Mpy_32_16_1( 6554 /* 0.2 in Q15 */, *bits_ch0 ) ) ); + move16(); } - *bits_ch1 = total_bits - *bits_ch0; + *bits_ch1 = sub( total_bits, *bits_ch0 ); + move16(); return; } -#endif - -/*-------------------------------------------------------------------* - * splitAvailableBits() - * - * split available bits between channels based on the split ratio - *-------------------------------------------------------------------*/ - +#else void splitAvailableBits( const int16_t total_bits, /* i : total available bits for TCX coding */ const int16_t split_ratio, /* i : split ratio */ @@ -99,3 +95,4 @@ void splitAvailableBits( return; } +#endif diff --git a/lib_dec/TonalComponentDetection.c b/lib_dec/TonalComponentDetection.c index 12908a001..66333630f 100644 --- a/lib_dec/TonalComponentDetection.c +++ b/lib_dec/TonalComponentDetection.c @@ -886,4 +886,4 @@ static void findTonalComponents( return; } -#endif +#endif \ No newline at end of file diff --git a/lib_dec/ivas_stereo_dft_dec_fx.c b/lib_dec/ivas_stereo_dft_dec_fx.c index 09867f30c..8a7f883ec 100644 --- a/lib_dec/ivas_stereo_dft_dec_fx.c +++ b/lib_dec/ivas_stereo_dft_dec_fx.c @@ -333,8 +333,10 @@ static void stereo_dft_dec_open_fx( /*Bands: find the number of bands, Nyquist freq. is not taken into account*/ set_s( hStereoDft->band_res, hStereoDft->hConfig->band_res, STEREO_DFT_DEC_DFT_NB ); - hStereoDft->nbands = stereo_dft_band_config( hStereoDft->band_limits, hStereoDft->band_res[0], hStereoDft->NFFT, DEC ); + hStereoDft->nbands = stereo_dft_band_config_fx( hStereoDft->band_limits, hStereoDft->band_res[0], hStereoDft->NFFT, DEC ); + move16(); hStereoDft->hb_stefi_delay = NS2SA( output_Fs, STEREO_DFT_TD_STEFI_DELAY_NS ); + move16(); IF( GT_16( nchan_transport, 2 ) ) { diff --git a/lib_dec/lib_dec_fx.c b/lib_dec/lib_dec_fx.c index 11a38a393..7ca71ffb2 100644 --- a/lib_dec/lib_dec_fx.c +++ b/lib_dec/lib_dec_fx.c @@ -2422,9 +2422,12 @@ ivas_error IVAS_DEC_GetDelay( out_fs_fx = ( hDecoderConfig->output_Fs != 48000 ) ? ( ( hDecoderConfig->output_Fs != 32000 ) ? FS_16K_IN_NS_Q31 : FS_32K_IN_NS_Q31 ) : FS_48K_IN_NS_Q31; - nSamples[1] = NS2SA_fx2( hDecoderConfig->output_Fs, get_delay( DEC, hDecoderConfig->output_Fs, st_ivas->ivas_format, st_ivas->cldfbAnaDec[0] ) ); + nSamples[1] = NS2SA_fx2( hDecoderConfig->output_Fs, get_delay_fx( DEC, hDecoderConfig->output_Fs, st_ivas->ivas_format, st_ivas->cldfbAnaDec[0] ) ); + move16(); nSamples[2] = (Word16) W_round64_L( W_mult0_32_32( L_shl( st_ivas->binaural_latency_ns, 1 ), out_fs_fx ) ); + move16(); nSamples[0] = add( nSamples[1], nSamples[2] ); + move16(); IF( EQ_16( (Word16) st_ivas->ivas_format, MASA_FORMAT ) ) { diff --git a/lib_enc/ivas_corecoder_enc_reconfig.c b/lib_enc/ivas_corecoder_enc_reconfig.c index 21eedf230..da56ae4dc 100644 --- a/lib_enc/ivas_corecoder_enc_reconfig.c +++ b/lib_enc/ivas_corecoder_enc_reconfig.c @@ -481,7 +481,11 @@ ivas_error ivas_corecoder_enc_reconfig( st_ivas->hCPE[0]->hCoreCoder[n]->mct_chan_mode = MCT_CHAN_MODE_REGULAR; } +#ifndef IVAS_FLOAT_FIXED initMdctStereoEncData( st_ivas->hCPE[st_ivas->nCPE - 1]->hStereoMdct, hEncoderConfig->ivas_format, st_ivas->hCPE[st_ivas->nCPE - 1]->element_mode, st_ivas->hCPE[st_ivas->nCPE - 1]->element_brate, hEncoderConfig->max_bwidth, 0, NULL, 1 ); +#else + initMdctStereoEncData_fx( st_ivas->hCPE[st_ivas->nCPE - 1]->hStereoMdct, hEncoderConfig->ivas_format, st_ivas->hCPE[st_ivas->nCPE - 1]->element_mode, st_ivas->hCPE[st_ivas->nCPE - 1]->element_brate, hEncoderConfig->max_bwidth, 0, NULL, 1 ); +#endif st_ivas->hCPE[st_ivas->nCPE - 1]->hStereoMdct->isSBAStereoMode = ( ( hEncoderConfig->ivas_format == SBA_FORMAT || hEncoderConfig->ivas_format == SBA_ISM_FORMAT ) && ( st_ivas->nchan_transport == 2 ) ); } } diff --git a/lib_enc/ivas_cpe_enc.c b/lib_enc/ivas_cpe_enc.c index 5e9f49ba7..55f76e430 100644 --- a/lib_enc/ivas_cpe_enc.c +++ b/lib_enc/ivas_cpe_enc.c @@ -271,6 +271,7 @@ ivas_error ivas_cpe_enc( } +#ifndef IVAS_FLOAT_FIXED if ( hCPE->element_mode != IVAS_CPE_MDCT && ( hCPE->element_brate != hCPE->last_element_brate || hCPE->last_element_mode != hCPE->element_mode || sts[0]->ini_frame == 0 || ( ivas_total_brate != st_ivas->hEncoderConfig->last_ivas_total_brate ) || sts[0]->last_core_brate <= SID_2k40 ) ) /* If the last frame was SID or NO_DATA, we need to run stereo_dft_config here since VAD decision is not known yet */ { @@ -291,6 +292,36 @@ ivas_error ivas_cpe_enc( stereo_dft_config( hCPE->hStereoDft == NULL ? NULL : hCPE->hStereoDft->hConfig, hCPE->element_brate, &sts[0]->bits_frame_nominal, &sts[1]->bits_frame_nominal ); } } +#else + test(); + test(); + test(); + test(); + test(); + /* No Basop - sts[0]->ini_frame == 0 as comparison with 0 */ + IF( NE_16( hCPE->element_mode, IVAS_CPE_MDCT ) && ( NE_32( hCPE->element_brate, hCPE->last_element_brate ) || NE_16( hCPE->last_element_mode, hCPE->element_mode ) || sts[0]->ini_frame == 0 || + ( NE_32( ivas_total_brate, st_ivas->hEncoderConfig->last_ivas_total_brate ) ) || LE_32( sts[0]->last_core_brate, SID_2k40 ) ) ) /* If the last frame was SID or NO_DATA, we need to run stereo_dft_config here since VAD decision is not known yet */ + { + IF( st_ivas->hQMetaData != NULL ) + { + test(); + /* No Basop - st_ivas->ism_mode != ISM_MODE_NONE as comparison with 0 */ + IF( EQ_16( ivas_format, MASA_ISM_FORMAT ) && st_ivas->ism_mode != ISM_MODE_NONE ) + { + stereo_dft_config_fx( hCPE->hStereoDft == NULL ? NULL : hCPE->hStereoDft->hConfig, L_mult0( st_ivas->hQMetaData->bits_frame_nominal, 35 /* 0.70f * FRAMES_PER_SEC */ ), &sts[0]->bits_frame_nominal, &sts[1]->bits_frame_nominal ); + } + ELSE + { + stereo_dft_config_fx( hCPE->hStereoDft == NULL ? NULL : hCPE->hStereoDft->hConfig, L_mult0( st_ivas->hQMetaData->bits_frame_nominal, FRAMES_PER_SEC ), &sts[0]->bits_frame_nominal, &sts[1]->bits_frame_nominal ); + } + } + ELSE + { + /* note; "bits_frame_nominal" needed in TD stereo as well */ + stereo_dft_config_fx( hCPE->hStereoDft == NULL ? NULL : hCPE->hStereoDft->hConfig, hCPE->element_brate, &sts[0]->bits_frame_nominal, &sts[1]->bits_frame_nominal ); + } + } +#endif if ( hCPE->element_mode == IVAS_CPE_TD ) { @@ -301,7 +332,11 @@ ivas_error ivas_cpe_enc( } else { +#ifndef IVAS_FLOAT_FIXED stereo_dft_config( NULL, hCPE->element_brate, &sts[0]->bits_frame_nominal, &sts[1]->bits_frame_nominal ); +#else + stereo_dft_config_fx( NULL, hCPE->element_brate, &sts[0]->bits_frame_nominal, &sts[1]->bits_frame_nominal ); +#endif } } @@ -344,7 +379,11 @@ ivas_error ivas_cpe_enc( /* reconfiguration in case of bitrate switching */ if ( hCPE->element_brate != hCPE->last_element_brate && st_ivas->hMCT == NULL ) { +#ifndef IVAS_FLOAT_FIXED initMdctStereoEncData( hCPE->hStereoMdct, ivas_format, hCPE->element_mode, hCPE->element_brate, max_bwidth, 0, NULL, 0 ); +#else + initMdctStereoEncData_fx( hCPE->hStereoMdct, ivas_format, hCPE->element_mode, hCPE->element_brate, max_bwidth, 0, NULL, 0 ); +#endif hCPE->hStereoMdct->isSBAStereoMode = ( ( ivas_format == SBA_FORMAT || ivas_format == SBA_ISM_FORMAT ) && ( st_ivas->nchan_transport == 2 ) ); } } @@ -515,7 +554,11 @@ ivas_error ivas_cpe_enc( /* reconfiguration of MDCT stereo */ if ( sts[0]->bwidth != sts[0]->last_bwidth || ( ( hCPE->last_element_brate != hCPE->element_brate || hCPE->last_element_mode != hCPE->element_mode ) && sts[0]->bwidth != sts[0]->max_bwidth ) ) { +#ifndef IVAS_FLOAT_FIXED initMdctStereoEncData( hCPE->hStereoMdct, ivas_format, hCPE->element_mode, hCPE->element_brate, sts[0]->bwidth, 0, NULL, 0 ); +#else + initMdctStereoEncData_fx( hCPE->hStereoMdct, ivas_format, hCPE->element_mode, hCPE->element_brate, sts[0]->bwidth, 0, NULL, 0 ); +#endif hCPE->hStereoMdct->isSBAStereoMode = ( ( ivas_format == SBA_FORMAT || ivas_format == SBA_ISM_FORMAT ) && ( st_ivas->nchan_transport == 2 ) ); if ( hCPE->element_brate <= MAX_MDCT_ITD_BRATE && ivas_format == STEREO_FORMAT ) @@ -586,6 +629,7 @@ ivas_error ivas_cpe_enc( if ( sts[0]->core_brate == SID_2k40 || sts[0]->core_brate == FRAME_NO_DATA ) { /* Reconfigure DFT Stereo for inactive frames */ +#ifndef IVAS_FLOAT_FIXED if ( sts[0]->core_brate == SID_2k40 ) { stereo_dft_config( hCPE->hStereoDft->hConfig, IVAS_SID_5k2, &sts[0]->bits_frame_nominal, &sts[1]->bits_frame_nominal ); @@ -594,6 +638,16 @@ ivas_error ivas_cpe_enc( { stereo_dft_config( hCPE->hStereoDft->hConfig, FRAME_NO_DATA, &sts[0]->bits_frame_nominal, &sts[1]->bits_frame_nominal ); } +#else + IF( EQ_32( sts[0]->core_brate, SID_2k40 ) ) + { + stereo_dft_config_fx( hCPE->hStereoDft->hConfig, IVAS_SID_5k2, &sts[0]->bits_frame_nominal, &sts[1]->bits_frame_nominal ); + } + ELSE + { + stereo_dft_config_fx( hCPE->hStereoDft->hConfig, FRAME_NO_DATA, &sts[0]->bits_frame_nominal, &sts[1]->bits_frame_nominal ); + } +#endif stereo_dft_cng_side_gain( hCPE->hStereoDft, hCPE->hStereoCng, sts[0]->core_brate, sts[0]->last_core_brate, sts[0]->bwidth ); } @@ -955,7 +1009,11 @@ ivas_error create_cpe_enc( return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for MDCT Stereo \n" ) ); } +#ifndef IVAS_FLOAT_FIXED initMdctStereoEncData( hCPE->hStereoMdct, ivas_format, hCPE->element_mode, hCPE->element_brate, max_bwidth, 0, NULL, 1 ); +#else + initMdctStereoEncData_fx( hCPE->hStereoMdct, ivas_format, hCPE->element_mode, hCPE->element_brate, max_bwidth, 0, NULL, 1 ); +#endif hCPE->hStereoMdct->isSBAStereoMode = ( ( ivas_format == SBA_FORMAT || ivas_format == SBA_ISM_FORMAT ) && ( st_ivas->nchan_transport == 2 ) ); if ( hCPE->element_mode == IVAS_CPE_MDCT && element_brate <= MAX_MDCT_ITD_BRATE && ivas_format == STEREO_FORMAT ) diff --git a/lib_enc/ivas_dirac_enc.c b/lib_enc/ivas_dirac_enc.c index 23ddd3ddd..6f58a2501 100644 --- a/lib_enc/ivas_dirac_enc.c +++ b/lib_enc/ivas_dirac_enc.c @@ -36,7 +36,10 @@ #include #include "cnst.h" #include "prot.h" +#include "prot_fx1.h" +#include "prot_fx2.h" #include "ivas_prot.h" +#include "ivas_prot_fx.h" #include "ivas_cnst.h" #include "ivas_rom_com.h" #include "wmc_auto.h" @@ -278,6 +281,7 @@ void ivas_dirac_enc_close( * *------------------------------------------------------------------------*/ +#ifdef IVAS_FLOAT_FIXED ivas_error ivas_dirac_enc( DIRAC_ENC_HANDLE hDirAC, /* i/o: encoder DirAC handle */ IVAS_QMETADATA_HANDLE hQMetaData, /* i/o: q_metadata handle */ @@ -293,6 +297,9 @@ ivas_error ivas_dirac_enc( { int16_t orig_dirac_bands; float dir[3], avg_dir[3]; +#ifdef IVAS_FLOAT_FIXED + Word32 dir_fx[3] /*, avg_dir_fx[3]*/; +#endif float energySum, vecLen; int16_t i, j, b, i_ts; ivas_error error; @@ -342,7 +349,21 @@ ivas_error ivas_dirac_enc( /* combine all DirAC bands except the last one, handle last band separately, last band covers BW above WB */ for ( j = 0; j < orig_dirac_bands - 1; j++ ) { +#ifdef IVAS_FLOAT_FIXED + /*==========================================flt-2-fix======================================================*/ + hQMetaData->q_direction[0].band_data[j].azimuth_fx[i] = floatToFixed( hQMetaData->q_direction[0].band_data[j].azimuth[i], Q22 ); + hQMetaData->q_direction[0].band_data[j].elevation_fx[i] = floatToFixed( hQMetaData->q_direction[0].band_data[j].elevation[i], Q22 ); + /*==========================================flt-2-fix======================================================*/ + + ivas_qmetadata_azimuth_elevation_to_direction_vector_fx( hQMetaData->q_direction[0].band_data[j].azimuth_fx[i], hQMetaData->q_direction[0].band_data[j].elevation_fx[i], &dir_fx[0] ); + + /*==========================================fix-2-flt======================================================*/ + fixedToFloat_arrL( dir_fx, dir, Q30, 3 ); + /*==========================================fix-2-flt======================================================*/ + +#else ivas_qmetadata_azimuth_elevation_to_direction_vector( hQMetaData->q_direction[0].band_data[j].azimuth[i], hQMetaData->q_direction[0].band_data[j].elevation[i], &dir[0] ); +#endif vecLen = hQMetaData->q_direction[0].band_data[j].energy_ratio[i] * hDirAC->buffer_energy[i * orig_dirac_bands + j]; avg_dir[0] += dir[0] * vecLen; @@ -352,7 +373,22 @@ ivas_error ivas_dirac_enc( energySum += hDirAC->buffer_energy[i * orig_dirac_bands + j]; } +#ifdef IVAS_FLOAT_FIXED_ + /*==========================================flt-2-fix======================================================*/ + Word16 q_dir_e = 0; + f2me_buf( avg_dir, avg_dir_fx, &q_dir_e, 3 ); + Scale_sig32( avg_dir_fx, 3, -1 ); + /*==========================================flt-2-fix======================================================*/ + + ivas_qmetadata_direction_vector_to_azimuth_elevation_fx( &avg_dir_fx[0], Q30, &hQMetaData->q_direction[0].band_data[0].azimuth_fx[i], &hQMetaData->q_direction[0].band_data[0].elevation_fx[i] ); + + /*==========================================fix-2-flt======================================================*/ + hQMetaData->q_direction[0].band_data[0].azimuth[i] = fixedToFloat( hQMetaData->q_direction[0].band_data[0].azimuth_fx[i], Q22 ); + hQMetaData->q_direction[0].band_data[0].elevation[i] = fixedToFloat( hQMetaData->q_direction[0].band_data[0].elevation_fx[i], Q22 ); + /*==========================================fix-2-flt======================================================*/ +#else ivas_qmetadata_direction_vector_to_azimuth_elevation( &avg_dir[0], &hQMetaData->q_direction[0].band_data[0].azimuth[i], &hQMetaData->q_direction[0].band_data[0].elevation[i] ); +#endif hQMetaData->q_direction[0].band_data[0].energy_ratio[i] = sqrtf( dotp( avg_dir, avg_dir, 3 ) ) / ( energySum + EPSILON ); hQMetaData->q_direction[0].band_data[1].azimuth[i] = hQMetaData->q_direction[0].band_data[orig_dirac_bands - 1].azimuth[i]; @@ -403,6 +439,133 @@ ivas_error ivas_dirac_enc( return IVAS_ERR_OK; } +#else +ivas_error ivas_dirac_enc( + DIRAC_ENC_HANDLE hDirAC, /* i/o: encoder DirAC handle */ + IVAS_QMETADATA_HANDLE hQMetaData, /* i/o: q_metadata handle */ + BSTR_ENC_HANDLE hMetaData, /* i/o: Metadata bitstream handle */ + float *data_f[], /* i/o: SBA channels */ + float **ppIn_FR_real, /* o : real freq domain values */ + float **ppIn_FR_imag, /* o : imag freq domain values */ + const int16_t input_frame, /* i : input frame length */ + const int16_t dtx_vad, /* i : DTX vad flag */ + const IVAS_FORMAT ivas_format, /* i : ivas format */ + const int16_t hodirac_flag /* i : hodirac flag */ +) +{ + int16_t orig_dirac_bands; + float dir[3], avg_dir[3]; + float energySum, vecLen; + int16_t i, j, b, i_ts; + ivas_error error; + push_wmops( "ivas_dirac_enc" ); + + ivas_dirac_param_est_enc( hDirAC, hQMetaData->q_direction, hQMetaData->useLowerRes, data_f, ppIn_FR_real, ppIn_FR_imag, input_frame, ivas_format, hodirac_flag, hodirac_flag ? HOA2_CHANNELS : FOA_CHANNELS, &( hDirAC->mono_frame_count ), &( hQMetaData->dirac_mono_flag ) ); + + if ( hQMetaData->q_direction->cfg.nbands > 0 ) + { + orig_dirac_bands = hQMetaData->q_direction[0].cfg.nbands; + + if ( dtx_vad == 1 ) + { + /* WB 4TC mode bit : disable for now*/ + push_next_indice( hMetaData, 0, 1 ); + + /* Set Energy Ratio to 0.0 if the mono flag is set, before the metadata is encoded */ + if ( hQMetaData->dirac_mono_flag ) + { + for ( b = hQMetaData->q_direction->cfg.start_band; b < hQMetaData->q_direction->cfg.nbands; b++ ) + { + for ( i_ts = 0; i_ts < ( ( dtx_vad == 1 ) ? hQMetaData->q_direction[0].cfg.nblocks : 1 ); i_ts++ ) + { + hQMetaData->q_direction[0].band_data[b].energy_ratio[i_ts] = 0.0f; + hQMetaData->q_direction[0].band_data[b].azimuth[i_ts] = 0.0f; + hQMetaData->q_direction[0].band_data[b].elevation[i_ts] = 0.0f; + } + } + } + + if ( ( error = ivas_qmetadata_enc_encode( hMetaData, hQMetaData, hodirac_flag ) ) != IVAS_ERR_OK ) + { + return error; + } + } + else + { + hQMetaData->q_direction[0].cfg.nbands = DIRAC_DTX_BANDS; + + /* compute directions */ + for ( i = 0; i < hQMetaData->q_direction[0].cfg.nblocks; i++ ) + { + set_zero( dir, 3 ); + set_zero( avg_dir, 3 ); + energySum = 0.0f; + + /* combine all DirAC bands except the last one, handle last band separately, last band covers BW above WB */ + for ( j = 0; j < orig_dirac_bands - 1; j++ ) + { + ivas_qmetadata_azimuth_elevation_to_direction_vector( hQMetaData->q_direction[0].band_data[j].azimuth[i], hQMetaData->q_direction[0].band_data[j].elevation[i], &dir[0] ); + vecLen = hQMetaData->q_direction[0].band_data[j].energy_ratio[i] * hDirAC->buffer_energy[i * orig_dirac_bands + j]; + + avg_dir[0] += dir[0] * vecLen; + avg_dir[1] += dir[1] * vecLen; + avg_dir[2] += dir[2] * vecLen; + + energySum += hDirAC->buffer_energy[i * orig_dirac_bands + j]; + } + + ivas_qmetadata_direction_vector_to_azimuth_elevation( &avg_dir[0], &hQMetaData->q_direction[0].band_data[0].azimuth[i], &hQMetaData->q_direction[0].band_data[0].elevation[i] ); + hQMetaData->q_direction[0].band_data[0].energy_ratio[i] = sqrtf( dotp( avg_dir, avg_dir, 3 ) ) / ( energySum + EPSILON ); + + hQMetaData->q_direction[0].band_data[1].azimuth[i] = hQMetaData->q_direction[0].band_data[orig_dirac_bands - 1].azimuth[i]; + hQMetaData->q_direction[0].band_data[1].elevation[i] = hQMetaData->q_direction[0].band_data[orig_dirac_bands - 1].elevation[i]; + hQMetaData->q_direction[0].band_data[1].energy_ratio[i] = hQMetaData->q_direction[0].band_data[orig_dirac_bands - 1].energy_ratio[i]; + } + + /* 1 bit to indicate mode MD coding : temp solution*/ + push_next_indice( hMetaData, 1, 1 ); + + /* encode SID parameters */ + ivas_qmetadata_enc_sid_encode( hMetaData, hQMetaData, -1, SBA_FORMAT ); + } + + for ( b = hQMetaData->q_direction->cfg.start_band; b < hQMetaData->q_direction->cfg.nbands; b++ ) + { + for ( i_ts = 0; i_ts < ( ( dtx_vad == 1 ) ? hQMetaData->q_direction[0].cfg.nblocks : 1 ); i_ts++ ) + { + hQMetaData->q_direction->band_data[b].azimuth[i_ts] = hQMetaData->q_direction->band_data[b].q_azimuth[i_ts]; + hQMetaData->q_direction->band_data[b].elevation[i_ts] = hQMetaData->q_direction->band_data[b].q_elevation[i_ts]; + hQMetaData->q_direction[0].band_data[b].energy_ratio[0] = 1.0f - diffuseness_reconstructions[hQMetaData->q_direction[0].band_data[b].energy_ratio_index[0]]; + } + } + + if ( dtx_vad == 0 ) + { + for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) + { + hQMetaData->q_direction[0].band_data[orig_dirac_bands - 1].azimuth[i] = hQMetaData->q_direction[0].band_data[1].azimuth[0]; + hQMetaData->q_direction[0].band_data[orig_dirac_bands - 1].elevation[i] = hQMetaData->q_direction[0].band_data[1].elevation[0]; + hQMetaData->q_direction[0].band_data[orig_dirac_bands - 1].energy_ratio[i] = hQMetaData->q_direction[0].band_data[1].energy_ratio[0]; + } + + for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) + { + for ( j = orig_dirac_bands - 2; j >= 0; j-- ) + { + hQMetaData->q_direction[0].band_data[j].azimuth[i] = hQMetaData->q_direction[0].band_data[0].azimuth[0]; + hQMetaData->q_direction[0].band_data[j].elevation[i] = hQMetaData->q_direction[0].band_data[0].elevation[0]; + hQMetaData->q_direction[0].band_data[j].energy_ratio[i] = hQMetaData->q_direction[0].band_data[0].energy_ratio[0]; + } + } + + hQMetaData->q_direction->cfg.nbands = orig_dirac_bands; + } + } + pop_wmops(); + + return IVAS_ERR_OK; +} +#endif /*------------------------------------------------------------------------- @@ -593,6 +756,306 @@ void computeReferencePower_enc( * *------------------------------------------------------------------------*/ +#ifdef IVAS_FLOAT_FIXED +void ivas_dirac_param_est_enc( + DIRAC_ENC_HANDLE hDirAC, + IVAS_QDIRECTION *q_direction, + const uint8_t useLowerRes, + float *data_f[], + float **pp_fr_real, + float **pp_fr_imag, + const int16_t input_frame, + const IVAS_FORMAT ivas_format, + const int16_t hodirac_flag, + const int16_t nchan_fb_in, + int16_t *mono_frame_count, + int16_t *dirac_mono_flag ) +{ + int16_t i, d, ts, index, l_ts, num_freq_bands; + int16_t band_m_idx, block_m_idx; + float dir_v[DIRAC_NUM_DIMS]; +#ifdef IVAS_FLOAT_FIXED_ + Word32 dir_v_fx[DIRAC_NUM_DIMS]; +#endif + float *pcm_in[DIRAC_MAX_ANA_CHANS]; + float Cldfb_RealBuffer[DIRAC_MAX_ANA_CHANS][DIRAC_NO_FB_BANDS_MAX]; + float Cldfb_ImagBuffer[DIRAC_MAX_ANA_CHANS][DIRAC_NO_FB_BANDS_MAX]; + float *p_Cldfb_RealBuffer[DIRAC_MAX_ANA_CHANS]; + float *p_Cldfb_ImagBuffer[DIRAC_MAX_ANA_CHANS]; + float intensity_real[DIRAC_NUM_DIMS][DIRAC_MAX_NBANDS]; + float direction_vector[DIRAC_NUM_DIMS][DIRAC_MAX_NBANDS]; + float diffuseness_vector[DIRAC_MAX_NBANDS]; + float renormalization_factor[DIRAC_MAX_NBANDS]; + float renormalization_factor_diff[DIRAC_MAX_NBANDS]; + float norm_tmp; + int16_t mrange[2]; + int16_t num_blocks; + float reference_power[CLDFB_NO_COL_MAX][DIRAC_NO_FB_BANDS_MAX]; + float azi_secs[2 * DIRAC_MAX_ANA_CHANS * DIRAC_MAX_NBANDS]; + float ele_secs[2 * DIRAC_MAX_ANA_CHANS * DIRAC_MAX_NBANDS]; + float diff_secs[2 * DIRAC_MAX_ANA_CHANS * DIRAC_MAX_NBANDS]; + float ene_secs[2 * DIRAC_MAX_ANA_CHANS * DIRAC_MAX_NBANDS]; + + push_wmops( "dirac_enc_param_est" ); + num_freq_bands = hDirAC->hConfig->nbands; + + /* Initialization */ + l_ts = input_frame / MAX_PARAM_SPATIAL_SUBFRAMES; + if ( useLowerRes ) + { + q_direction->cfg.nblocks = 1; + num_blocks = 1; + } + else + { + q_direction->cfg.nblocks = MAX_PARAM_SPATIAL_SUBFRAMES; + num_blocks = MAX_PARAM_SPATIAL_SUBFRAMES; + } + + /* Need to initialize renormalization_factors, direction_m and diffuseness_m */ + for ( i = 0; i < hDirAC->hConfig->nbands; i++ ) + { + renormalization_factor_diff[i] = 0; + hDirAC->diffuseness_m[i] = 0; + } + + set_zero( azi_secs, 2 * DIRAC_MAX_ANA_CHANS * DIRAC_MAX_NBANDS ); + set_zero( ele_secs, 2 * DIRAC_MAX_ANA_CHANS * DIRAC_MAX_NBANDS ); + set_zero( diff_secs, 2 * DIRAC_MAX_ANA_CHANS * DIRAC_MAX_NBANDS ); + set_zero( ene_secs, 2 * DIRAC_MAX_ANA_CHANS * DIRAC_MAX_NBANDS ); + + /* Copy current frame to memory for delay compensation */ + for ( i = 0; i < nchan_fb_in; i++ ) + { + pcm_in[i] = data_f[i]; + p_Cldfb_RealBuffer[i] = &Cldfb_RealBuffer[i][0]; + p_Cldfb_ImagBuffer[i] = &Cldfb_ImagBuffer[i][0]; + } + + /* do processing over all CLDFB time slots */ + for ( block_m_idx = 0; block_m_idx < num_blocks; block_m_idx++ ) + { + mrange[0] = hDirAC->block_grouping[block_m_idx]; + mrange[1] = hDirAC->block_grouping[block_m_idx + 1]; + + for ( band_m_idx = 0; band_m_idx < hDirAC->hConfig->nbands; band_m_idx++ ) + { + renormalization_factor[band_m_idx] = EPSILON; + hDirAC->direction_vector_m[0][block_m_idx][band_m_idx] = 0; + hDirAC->direction_vector_m[1][block_m_idx][band_m_idx] = 0; + hDirAC->direction_vector_m[2][block_m_idx][band_m_idx] = 0; + } + + for ( ts = mrange[0]; ts < mrange[1]; ts++ ) + { + if ( hDirAC->hFbMixer ) + { + ivas_fb_mixer_get_windowed_fr( hDirAC->hFbMixer, pcm_in, p_Cldfb_RealBuffer, p_Cldfb_ImagBuffer, l_ts, l_ts, hDirAC->hFbMixer->fb_cfg->num_in_chans ); + + ivas_fb_mixer_update_prior_input( hDirAC->hFbMixer, pcm_in, l_ts, hDirAC->hFbMixer->fb_cfg->num_in_chans ); + + for ( i = 0; i < nchan_fb_in; i++ ) + { + pcm_in[i] += l_ts; + } + } + else + { + for ( i = 0; i < nchan_fb_in; i++ ) + { + mvr2r( &pp_fr_real[i][ts * l_ts], Cldfb_RealBuffer[i], l_ts ); + mvr2r( &pp_fr_imag[i][ts * l_ts], Cldfb_ImagBuffer[i], l_ts ); + } + } + + computeReferencePower_enc( + hDirAC->band_grouping, + Cldfb_RealBuffer, + Cldfb_ImagBuffer, + reference_power[ts], + hDirAC->hConfig->enc_param_start_band, + num_freq_bands, + ivas_format, + hodirac_flag ? 0 : 1, + FOA_CHANNELS, + mono_frame_count, + dirac_mono_flag ); + + computeIntensityVector_enc( + hDirAC, + Cldfb_RealBuffer, + Cldfb_ImagBuffer, + hDirAC->hConfig->enc_param_start_band, + num_freq_bands, + intensity_real ); + + if ( !hodirac_flag ) + { + computeDirectionVectors( + intensity_real[0], + intensity_real[1], + intensity_real[2], + hDirAC->hConfig->enc_param_start_band, + num_freq_bands, + direction_vector[0], + direction_vector[1], + direction_vector[2] ); + } + + /* fill buffers of length "averaging_length" time slots for intensity and energy */ + hDirAC->index_buffer_intensity = ( hDirAC->index_buffer_intensity % hDirAC->no_col_avg_diff ) + 1; /* averaging_length = 32 */ + index = hDirAC->index_buffer_intensity; + for ( i = 0; i < DIRAC_NUM_DIMS; i++ ) + { + /* only real part needed */ + mvr2r( intensity_real[i], &( hDirAC->buffer_intensity_real[i][index - 1][0] ), num_freq_bands ); + } + mvr2r( reference_power[ts], &( hDirAC->buffer_energy[( index - 1 ) * num_freq_bands] ), num_freq_bands ); + + computeDiffuseness_mdft( hDirAC->buffer_intensity_real, hDirAC->buffer_energy, num_freq_bands, hDirAC->no_col_avg_diff, diffuseness_vector ); + + if ( hodirac_flag ) + { + calculate_hodirac_sector_parameters( + hDirAC, + Cldfb_RealBuffer, + Cldfb_ImagBuffer, + 0.20f, + hDirAC->band_grouping, + hDirAC->hConfig->nbands, + hDirAC->hConfig->enc_param_start_band, + azi_secs, + ele_secs, + diff_secs, + ene_secs ); + } + + if ( hodirac_flag ) + { + for ( band_m_idx = 0; band_m_idx < hDirAC->hConfig->nbands; band_m_idx++ ) + { + hDirAC->diffuseness_m[band_m_idx] += reference_power[ts][band_m_idx] * diffuseness_vector[band_m_idx]; + renormalization_factor_diff[band_m_idx] += reference_power[ts][band_m_idx]; + } + } + else + { + for ( band_m_idx = 0; band_m_idx < hDirAC->hConfig->nbands; band_m_idx++ ) + { + norm_tmp = reference_power[ts][band_m_idx] * ( 1 - diffuseness_vector[band_m_idx] ); + + hDirAC->direction_vector_m[0][block_m_idx][band_m_idx] += norm_tmp * direction_vector[0][band_m_idx]; + hDirAC->direction_vector_m[1][block_m_idx][band_m_idx] += norm_tmp * direction_vector[1][band_m_idx]; + hDirAC->direction_vector_m[2][block_m_idx][band_m_idx] += norm_tmp * direction_vector[2][band_m_idx]; + renormalization_factor[band_m_idx] += norm_tmp; + + hDirAC->diffuseness_m[band_m_idx] += reference_power[ts][band_m_idx] * diffuseness_vector[band_m_idx]; + renormalization_factor_diff[band_m_idx] += reference_power[ts][band_m_idx]; + } + } + } + + if ( !hodirac_flag ) + { + for ( band_m_idx = 0; band_m_idx < hDirAC->hConfig->nbands; band_m_idx++ ) + { + renormalization_factor[band_m_idx] = EPSILON; + for ( d = 0; d < DIRAC_NUM_DIMS; d++ ) + { + renormalization_factor[band_m_idx] += ( hDirAC->direction_vector_m[d][block_m_idx][band_m_idx] * hDirAC->direction_vector_m[d][block_m_idx][band_m_idx] ); + } + renormalization_factor[band_m_idx] = sqrtf( renormalization_factor[band_m_idx] ); + + if ( renormalization_factor[band_m_idx] > EPSILON ) + { + hDirAC->direction_vector_m[0][block_m_idx][band_m_idx] /= renormalization_factor[band_m_idx]; + hDirAC->direction_vector_m[1][block_m_idx][band_m_idx] /= renormalization_factor[band_m_idx]; + hDirAC->direction_vector_m[2][block_m_idx][band_m_idx] /= renormalization_factor[band_m_idx]; + } + else + { + hDirAC->direction_vector_m[0][block_m_idx][band_m_idx] = 1; + hDirAC->direction_vector_m[1][block_m_idx][band_m_idx] = 0; + hDirAC->direction_vector_m[2][block_m_idx][band_m_idx] = 0; + } + + /* save the elevation and azimuth values to be used later by the ivas_dirac_QuantizeParameters function */ + for ( d = 0; d < DIRAC_NUM_DIMS; d++ ) + { + dir_v[d] = hDirAC->direction_vector_m[d][block_m_idx][band_m_idx]; + } + +#ifdef IVAS_FLOAT_FIXED_ + /*==========================================flt-2-fix======================================================*/ + Word16 q_dir_e = 0; + f2me_buf( dir_v, dir_v_fx, &q_dir_e, 3 ); + Scale_sig32( dir_v_fx, 3, -1 ); + /*==========================================flt-2-fix======================================================*/ + + ivas_qmetadata_direction_vector_to_azimuth_elevation_fx( + dir_v_fx, + Q31 - q_dir_e, + &q_direction->band_data[band_m_idx].azimuth_fx[block_m_idx], + &q_direction->band_data[band_m_idx].elevation_fx[block_m_idx] ); + + /*==========================================fix-2-flt======================================================*/ + q_direction->band_data[band_m_idx].azimuth[block_m_idx] = fixedToFloat( q_direction->band_data[band_m_idx].azimuth_fx[block_m_idx], Q22 ); + q_direction->band_data[band_m_idx].elevation[block_m_idx] = fixedToFloat( q_direction->band_data[band_m_idx].elevation_fx[block_m_idx], Q22 ); + /*==========================================fix-2-flt======================================================*/ +#else + ivas_qmetadata_direction_vector_to_azimuth_elevation( + dir_v, + &q_direction->band_data[band_m_idx].azimuth[block_m_idx], + &q_direction->band_data[band_m_idx].elevation[block_m_idx] ); +#endif + } + } + + /* Sectors */ + if ( hodirac_flag ) + { + for ( band_m_idx = 0; band_m_idx < hDirAC->hConfig->nbands; band_m_idx++ ) + { + q_direction->band_data[band_m_idx].azimuth[block_m_idx] = azi_secs[band_m_idx]; + q_direction->band_data[band_m_idx].elevation[block_m_idx] = ele_secs[band_m_idx]; + // q_direction->band_data[band_m_idx].energy_ratio[block_m_idx] = 1.f - diffuseness_vector[band_m_idx]; // set later + + q_direction[1].band_data[band_m_idx].azimuth[block_m_idx] = azi_secs[num_freq_bands + band_m_idx]; + q_direction[1].band_data[band_m_idx].elevation[block_m_idx] = ele_secs[num_freq_bands + band_m_idx]; + q_direction[1].band_data[band_m_idx].energy_ratio[block_m_idx] = ( 1.f - diff_secs[band_m_idx] ) / ( ( 1.f - diff_secs[band_m_idx] ) + ( 1.f - diff_secs[num_freq_bands + band_m_idx] ) + EPSILON ); + } + } + } + + /* Diffuseness */ + for ( band_m_idx = 0; band_m_idx < hDirAC->hConfig->nbands; band_m_idx++ ) + { + if ( renormalization_factor_diff[band_m_idx] > EPSILON ) + { + hDirAC->diffuseness_m[band_m_idx] /= renormalization_factor_diff[band_m_idx]; + } + else + { + hDirAC->diffuseness_m[band_m_idx] = 0.f; + } + + /* set coherence to zero and convert diffuseness to energy ratio*/ + + set_f( q_direction->band_data[band_m_idx].energy_ratio, 1.f - hDirAC->diffuseness_m[band_m_idx], q_direction->cfg.nblocks ); + + for ( block_m_idx = 0; block_m_idx < q_direction->cfg.nblocks; block_m_idx++ ) + { + if ( q_direction->coherence_band_data != NULL ) + { + q_direction->coherence_band_data[band_m_idx].spread_coherence[block_m_idx] = 0; + } + } + } + + pop_wmops(); + return; +} +#else void ivas_dirac_param_est_enc( DIRAC_ENC_HANDLE hDirAC, IVAS_QDIRECTION *q_direction, @@ -869,6 +1332,7 @@ void ivas_dirac_param_est_enc( pop_wmops(); return; } +#endif /*------------------------------------------------------------------------- diff --git a/lib_enc/ivas_masa_enc.c b/lib_enc/ivas_masa_enc.c index 6f10ae187..2445f2e0d 100644 --- a/lib_enc/ivas_masa_enc.c +++ b/lib_enc/ivas_masa_enc.c @@ -39,6 +39,8 @@ #include "ivas_stat_enc.h" #include "wmc_auto.h" #include "prot.h" +#include "prot_fx1.h" +#include "prot_fx2.h" #ifdef IVAS_FLOAT_FIXED #include "prot_fx1.h" #include "prot_fx2.h" @@ -241,6 +243,7 @@ void ivas_masa_enc_close( * main MASA encoder function *-----------------------------------------------------------------------*/ +#ifdef IVAS_FLOAT_FIXED ivas_error ivas_masa_encode( MASA_ENCODER_HANDLE hMasa, /* i/o: MASA encoder structure */ IVAS_QMETADATA_HANDLE hQMetaData, /* i/o: q_metadata handle */ @@ -584,6 +587,378 @@ ivas_error ivas_masa_encode( *nb_bits_metadata = hMetaData->nb_bits_tot; + if ( ivas_format == MASA_FORMAT && Opt_DTX_ON ) + { + /* save old values */ + uint8_t numCodingBands = hMasa->config.numCodingBands; + uint8_t numTwoDirBands = hMasa->config.numTwoDirBands; + int16_t nbands = hQMetaData->q_direction[0].cfg.nbands; + uint8_t numberOfDirections = hMasa->config.numberOfDirections; + uint8_t numberOfDirectionsMeta = hMasa->masaMetadata.descriptive_meta.numberOfDirections; + uint16_t numberOfDirectionsQMetaData = hQMetaData->no_directions; + + if ( !( hMasa->config.numberOfDirections == 1 && hQMetaData->q_direction->cfg.nbands == 5 ) ) + { + for ( i = 0; i < MASA_MAXIMUM_DIRECTIONS; i++ ) + { + for ( j = 0; j < MAX_PARAM_SPATIAL_SUBFRAMES; j++ ) + { + mvr2r( h_orig_metadata[i].azimuth[j], hMasa->masaMetadata.directional_meta[i].azimuth[j], MASA_FREQUENCY_BANDS ); + mvr2r( h_orig_metadata[i].elevation[j], hMasa->masaMetadata.directional_meta[i].elevation[j], MASA_FREQUENCY_BANDS ); + mvr2r( h_orig_metadata[i].energy_ratio[j], hMasa->masaMetadata.directional_meta[i].energy_ratio[j], MASA_FREQUENCY_BANDS ); + } + } + + /* Force to have 5 bands and 1 direction */ + hMasa->config.numCodingBands = 5; + hMasa->config.numTwoDirBands = 0; + combine_freqbands_and_subframes( hMasa ); + hQMetaData->q_direction[0].cfg.nbands = 5; + + if ( hMasa->config.numberOfDirections == 2 && hMasa->config.numTwoDirBands < hMasa->config.numCodingBands ) + { + /* Combine directions */ + ivas_masa_combine_directions( hMasa ); + + /* If we joined all bands, then metadata is now one directional. */ + if ( hMasa->config.numTwoDirBands == 0 ) + { + hMasa->config.numberOfDirections = 1; + hMasa->masaMetadata.descriptive_meta.numberOfDirections = 0; + hQMetaData->no_directions = 1; + } + } + + move_metadata_to_qmetadata( hMasa, hQMetaData ); + + for ( j = hQMetaData->q_direction[0].cfg.start_band; j < hQMetaData->q_direction[0].cfg.nbands; ++j ) + { +#ifdef IVAS_FLOAT_FIXED + /*=====================================flt-2-fix============================================*/ + hQMetaData->q_direction[0].band_data[j].energy_ratio_fx[0] = floatToFixed( hQMetaData->q_direction[0].band_data[j].energy_ratio[0], Q30 ); + /*=====================================flt-2-fix============================================*/ + + hQMetaData->q_direction[0].band_data[j].energy_ratio_index[0] = masa_sq_fx( L_sub( ONE_IN_Q30, hQMetaData->q_direction[0].band_data[j].energy_ratio_fx[0] ), diffuseness_thresholds_fx, DIRAC_DIFFUSE_LEVELS ); +#else + 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 ); +#endif + } + } + + free( h_orig_metadata ); + + ivas_qmetadata_enc_sid_encode( hMetaData, hQMetaData, masa_sid_descriptor, ivas_format ); + + /* restore old values */ + hMasa->config.numCodingBands = numCodingBands; + hMasa->config.numTwoDirBands = numTwoDirBands; + hQMetaData->q_direction[0].cfg.nbands = nbands; + hMasa->config.numberOfDirections = numberOfDirections; + hMasa->masaMetadata.descriptive_meta.numberOfDirections = numberOfDirectionsMeta; + hQMetaData->no_directions = numberOfDirectionsQMetaData; + } + + return IVAS_ERR_OK; +} +#else +ivas_error ivas_masa_encode( + MASA_ENCODER_HANDLE hMasa, /* i/o: MASA encoder structure */ + IVAS_QMETADATA_HANDLE hQMetaData, /* i/o: q_metadata handle */ + BSTR_ENC_HANDLE hMetaData, /* i/o: Metadata bitstream handle */ + int16_t *nb_bits_metadata, /* o : number of metadata bits written */ + const int16_t nchan_transport, /* i : number of MASA input/transport channels */ + const IVAS_FORMAT ivas_format, /* i : IVAS format */ + const int32_t ivas_total_brate, /* i : IVAS total bitrate */ + const int16_t Opt_DTX_ON, /* i : DTX on flag */ + const int16_t element_mode, /* i : element mode */ + const ISM_MODE ism_mode, /* i : ISM format mode */ + const int16_t nchan_ism, /* i : number of ISM channels */ + ISM_METADATA_HANDLE hIsmMetaData[MAX_NUM_OBJECTS], /* i : ISM metadata handle */ + const int16_t idx_separated_object, /* i : index of the separated object */ + OMASA_ENC_HANDLE hOMasa, /* i : OMASA encoder handle */ + const int16_t ism_imp, /* i : importance of separated object */ + const int16_t flag_omasa_ener_brate /* i : less bitrate for objects in OMASA flag */ +) +{ + MASA_DIRECTIONAL_SPATIAL_META *h_orig_metadata; + int16_t i, j; + int16_t masa_sid_descriptor; + int16_t low_bitrate_mode; + int32_t masa_total_brate; + ivas_error error; + + masa_sid_descriptor = -1; + h_orig_metadata = NULL; + low_bitrate_mode = 0; + + if ( ivas_format == MASA_FORMAT || ivas_format == MASA_ISM_FORMAT ) + { + /* Create the MASA SID descriptor for the metadata and CPE mode, in order to have the SID frame self-contained. */ + if ( Opt_DTX_ON && hQMetaData != NULL ) + { + if ( nchan_transport == 2 ) /* this is MASA format in CPE only */ + { + masa_sid_descriptor = 0; /* for IVAS_CPE_DFT */ + if ( element_mode == IVAS_CPE_MDCT ) + { + masa_sid_descriptor = 1; + } + } + } + + /* Validate and compensate ratios as necessary */ + compensate_energy_ratios( hMasa ); + + if ( Opt_DTX_ON ) + { + if ( ( h_orig_metadata = (MASA_DIRECTIONAL_SPATIAL_META *) malloc( MASA_MAXIMUM_DIRECTIONS * sizeof( MASA_DIRECTIONAL_SPATIAL_META ) ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for MASA encoder\n" ) ); + } + + for ( i = 0; i < MASA_MAXIMUM_DIRECTIONS; i++ ) + { + for ( j = 0; j < MAX_PARAM_SPATIAL_SUBFRAMES; j++ ) + { + mvr2r( hMasa->masaMetadata.directional_meta[i].azimuth[j], h_orig_metadata[i].azimuth[j], MASA_FREQUENCY_BANDS ); + mvr2r( hMasa->masaMetadata.directional_meta[i].elevation[j], h_orig_metadata[i].elevation[j], MASA_FREQUENCY_BANDS ); + mvr2r( hMasa->masaMetadata.directional_meta[i].energy_ratio[j], h_orig_metadata[i].energy_ratio[j], MASA_FREQUENCY_BANDS ); + mvs2s( (int16_t *) ( hMasa->masaMetadata.directional_meta[i].spherical_index[j] ), (int16_t *) ( h_orig_metadata[i].spherical_index[j] ), MASA_FREQUENCY_BANDS ); + } + } + } + + if ( ( ivas_format == MASA_FORMAT || ivas_format == MASA_ISM_FORMAT ) && ivas_total_brate >= IVAS_384k ) + { + hMasa->config.mergeRatiosOverSubframes = 0; + } + + /* Combine frequency bands and sub-frames */ + combine_freqbands_and_subframes( hMasa ); + } + + if ( hMasa->config.numberOfDirections == 2 && hMasa->config.numTwoDirBands < hMasa->config.numCodingBands && ( ivas_format == MASA_FORMAT || ivas_format == MASA_ISM_FORMAT ) ) + { + if ( ( ivas_format == MASA_ISM_FORMAT && ism_mode != ISM_MODE_NONE && ism_mode != ISM_MASA_MODE_MASA_ONE_OBJ ) || ( ivas_format != MASA_ISM_FORMAT ) ) + { + /* Combine directions */ + ivas_masa_combine_directions( hMasa ); + } + + /* If we joined all bands, then metadata is now one directional. */ + if ( hMasa->config.numTwoDirBands == 0 ) + { + hMasa->config.numberOfDirections = 1; + hMasa->masaMetadata.descriptive_meta.numberOfDirections = 0; + hQMetaData->no_directions = 1; + } + } + + /* Reset qmetadata bit budget */ + hQMetaData->metadata_max_bits = hMasa->config.max_metadata_bits; + if ( ivas_format == MASA_FORMAT || ivas_format == MASA_ISM_FORMAT ) + { + if ( ivas_format == MASA_ISM_FORMAT && ism_mode != ISM_MODE_NONE ) + { + /* write the number of objects in ISM_MASA format*/ + push_next_indice( hMetaData, nchan_ism - 1, NO_BITS_MASA_ISM_NO_OBJ ); + hQMetaData->metadata_max_bits -= NO_BITS_MASA_ISM_NO_OBJ; + + /* write index of separated object if needed */ + if ( ism_mode == ISM_MASA_MODE_PARAM_ONE_OBJ && nchan_ism > 1 ) + { + push_next_indice( hMetaData, idx_separated_object, NO_BITS_MASA_ISM_NO_OBJ ); + hQMetaData->metadata_max_bits -= NO_BITS_MASA_ISM_NO_OBJ; + } + + /* write ISM importance flag (one per object) */ + if ( ism_mode == ISM_MASA_MODE_PARAM_ONE_OBJ ) + { + push_next_indice( hMetaData, hIsmMetaData[0]->ism_imp, ISM_METADATA_FLAG_BITS ); + hQMetaData->metadata_max_bits -= ISM_METADATA_FLAG_BITS; + } + else if ( ism_mode == ISM_MASA_MODE_MASA_ONE_OBJ ) + { + if ( hIsmMetaData[0]->ism_md_null_flag ) + { + /* signal NULL metadata frame */ + push_next_indice( hMetaData, 1, ISM_METADATA_MD_FLAG_BITS ); + hQMetaData->metadata_max_bits -= ISM_METADATA_MD_FLAG_BITS; + + /* write the ISM class to ISM_NO_META and again the true ISM class */ + push_next_indice( hMetaData, ISM_NO_META, ISM_METADATA_FLAG_BITS ); + hQMetaData->metadata_max_bits -= ISM_METADATA_FLAG_BITS; + push_next_indice( hMetaData, hIsmMetaData[0]->ism_imp, ISM_METADATA_FLAG_BITS ); + hQMetaData->metadata_max_bits -= ISM_METADATA_FLAG_BITS; + } + else + { + push_next_indice( hMetaData, hIsmMetaData[0]->ism_imp, ISM_METADATA_FLAG_BITS ); + hQMetaData->metadata_max_bits -= ISM_METADATA_FLAG_BITS; + + if ( hIsmMetaData[0]->ism_imp == ISM_NO_META ) + { + /* signal low-rate ISM_NO_META frame */ + push_next_indice( hMetaData, 0, ISM_METADATA_MD_FLAG_BITS ); + hQMetaData->metadata_max_bits -= ISM_METADATA_MD_FLAG_BITS; + + /* signal presence of MD in low-rate ISM_NO_META frame */ + push_next_indice( hMetaData, hIsmMetaData[0]->ism_md_lowrate_flag, ISM_METADATA_INACTIVE_FLAG_BITS ); + hQMetaData->metadata_max_bits -= ISM_METADATA_INACTIVE_FLAG_BITS; + } + } + } + else if ( ism_mode == ISM_MASA_MODE_DISC ) + { + for ( i = 0; i < nchan_ism; i++ ) + { + if ( hIsmMetaData[i]->ism_md_null_flag ) + { + /* signal NULL metadata frame */ + push_next_indice( hMetaData, 1, ISM_METADATA_MD_FLAG_BITS ); + hQMetaData->metadata_max_bits -= ISM_METADATA_MD_FLAG_BITS; + + /* write the ISM class to ISM_NO_META and again the true ISM class */ + push_next_indice( hMetaData, ISM_NO_META, ISM_METADATA_FLAG_BITS ); + hQMetaData->metadata_max_bits -= ISM_METADATA_FLAG_BITS; + push_next_indice( hMetaData, hIsmMetaData[i]->ism_imp, ISM_METADATA_FLAG_BITS ); + hQMetaData->metadata_max_bits -= ISM_METADATA_FLAG_BITS; + } + else + { + push_next_indice( hMetaData, hIsmMetaData[i]->ism_imp, ISM_METADATA_FLAG_BITS ); + hQMetaData->metadata_max_bits -= ISM_METADATA_FLAG_BITS; + + if ( hIsmMetaData[i]->ism_imp == ISM_NO_META ) + { + /* signal low-rate ISM_NO_META frame */ + push_next_indice( hMetaData, 0, ISM_METADATA_MD_FLAG_BITS ); + hQMetaData->metadata_max_bits -= ISM_METADATA_MD_FLAG_BITS; + + /* signal presence of MD in low-rate ISM_NO_META frame */ + push_next_indice( hMetaData, hIsmMetaData[i]->ism_md_lowrate_flag, ISM_METADATA_INACTIVE_FLAG_BITS ); + hQMetaData->metadata_max_bits -= ISM_METADATA_INACTIVE_FLAG_BITS; + } + } + } + + if ( ivas_total_brate == IVAS_128k && nchan_ism >= 3 ) + { + push_next_indice( hMetaData, flag_omasa_ener_brate, 1 ); + hQMetaData->metadata_max_bits -= 1; + } + } + } + else + { + /* write the number of MASA transport channels */ + push_next_indice( hMetaData, nchan_transport - 1, MASA_TRANSP_BITS ); + hQMetaData->metadata_max_bits -= MASA_TRANSP_BITS; + } + + if ( ivas_format == MASA_ISM_FORMAT && ism_mode == ISM_MODE_NONE ) + { + /* signal MASA_ISM_FORMAT to decoder */ + push_next_indice( hMetaData, 1, 1 ); + /* write reserved bit */ + push_next_indice( hMetaData, 0, MASA_HEADER_BITS - 1 ); + hQMetaData->metadata_max_bits -= MASA_HEADER_BITS; + } + else + { + /* the MASA_ISM_FORMAT is not signalled here */ + /* write reserved bits */ + push_next_indice( hMetaData, 0, MASA_HEADER_BITS ); + hQMetaData->metadata_max_bits -= MASA_HEADER_BITS; + } + /* write number of directions */ + push_next_indice( hMetaData, hQMetaData->no_directions - 1, 1 ); + hQMetaData->metadata_max_bits -= 1; + + /* write subframe mode */ + push_next_indice( hMetaData, hQMetaData->q_direction[0].cfg.nblocks == 1 ? 1 : 0, MASA_SUBFRAME_BITS ); + hQMetaData->metadata_max_bits -= MASA_SUBFRAME_BITS; + } + + if ( ivas_format == MC_FORMAT ) + { + int16_t lfeBitsWritten; + lfeBitsWritten = encode_lfe_to_total_energy_ratio( hMasa, hMetaData, ivas_total_brate ); + hQMetaData->metadata_max_bits -= lfeBitsWritten; + } + + /* Move data from encoder to qmetadata */ + if ( ivas_format == MASA_FORMAT || ivas_format == MASA_ISM_FORMAT ) + { + move_metadata_to_qmetadata( hMasa, hQMetaData ); + } + + if ( hMasa->config.max_metadata_bits < MINIMUM_BIT_BUDGET_NORMAL_META && !hMasa->config.joinedSubframes ) + { + reduce_metadata_further( hMasa, hQMetaData, ivas_format ); + + low_bitrate_mode = ( ivas_total_brate <= 32000 ); + + /* Write low bitrate mode. 1 signals that we have merged through time, 0 signals merge through frequency. */ + push_next_indice( hMetaData, hQMetaData->q_direction[0].cfg.nblocks == 1 ? 1 : 0, MASA_LOWBITRATE_MODE_BITS ); + hQMetaData->metadata_max_bits -= MASA_LOWBITRATE_MODE_BITS; + } + + /* Encode MASA+ISM metadata */ + if ( ivas_format == MASA_ISM_FORMAT && ism_mode == ISM_MASA_MODE_PARAM_ONE_OBJ ) + { + /* encode MASA/ISM energy ratios */ + ivas_encode_masaism_metadata( hMasa, hQMetaData, hMetaData, hIsmMetaData, nchan_ism, low_bitrate_mode, hOMasa->nCodingBands, hOMasa->nSubframes, idx_separated_object, ism_imp ); + } + else + { + if ( ivas_format == MASA_ISM_FORMAT ) + { + hMasa->data.hOmasaData->masa_to_total_energy_ratio[0][0] = -1; /* signals NOT to adjust the energy ratios */ + } + } + + /* Encode metadata */ + masa_total_brate = ivas_total_brate; + + if ( ivas_format == MASA_ISM_FORMAT && ism_mode == ISM_MASA_MODE_DISC ) + { + masa_total_brate = calculate_cpe_brate_MASA_ISM( ism_mode, ivas_total_brate, nchan_ism ); + } + + if ( masa_total_brate >= IVAS_384k ) + { + if ( masa_total_brate >= IVAS_512k ) + { + if ( ( error = ivas_qmetadata_enc_encode_hr_384_512( hMetaData, hQMetaData, 16, 4 ) ) != IVAS_ERR_OK ) + { + return error; + } + } + else + { + if ( ( error = ivas_qmetadata_enc_encode_hr_384_512( hMetaData, hQMetaData, 11, 3 ) ) != IVAS_ERR_OK ) + { + return error; + } + } + } + else + { + if ( ( error = ivas_qmetadata_enc_encode( hMetaData, hQMetaData, 0 ) ) != IVAS_ERR_OK ) + { + return error; + } + } + + if ( ivas_format == MASA_ISM_FORMAT && ism_mode == ISM_MASA_MODE_PARAM_ONE_OBJ ) + { + /* Modify spatial metadata based on the MASA-to-total energy ratios */ + ivas_omasa_modify_masa_energy_ratios( hQMetaData, hMasa->data.hOmasaData->masa_to_total_energy_ratio ); + } + + *nb_bits_metadata = hMetaData->nb_bits_tot; + if ( ivas_format == MASA_FORMAT && Opt_DTX_ON ) { /* save old values */ @@ -649,6 +1024,7 @@ ivas_error ivas_masa_encode( return IVAS_ERR_OK; } +#endif /*-----------------------------------------------------------------------* @@ -3671,11 +4047,10 @@ static void ivas_encode_masaism_metadata( reconstruct_ism_ratios( ratio_ism_idx[band], nchan_ism, step, hMasa->data.hOmasaData->q_energy_ratio_ism[sf][band] ); #else Word16 step_fx = float_to_fix16( step, Q15 ); - floatToFixed_arr32( hMasa->data.hOmasaData->q_energy_ratio_ism[sf][band], hMasa->data.hOmasaData->q_energy_ratio_ism_fx[sf][band], Q30, MAX_NUM_OBJECTS ); reconstruct_ism_ratios_fx( ratio_ism_idx[band], nchan_ism, step_fx, hMasa->data.hOmasaData->q_energy_ratio_ism_fx[sf][band] ); - fixedToFloat_arrL( hMasa->data.hOmasaData->q_energy_ratio_ism_fx[sf][band], hMasa->data.hOmasaData->q_energy_ratio_ism[sf][band], Q30, MAX_NUM_OBJECTS ); + fixedToFloat_arrL( hMasa->data.hOmasaData->q_energy_ratio_ism_fx[sf][band], hMasa->data.hOmasaData->q_energy_ratio_ism[sf][band], Q30, nchan_ism ); #endif } diff --git a/lib_enc/ivas_mcmasa_enc.c b/lib_enc/ivas_mcmasa_enc.c index 56800005b..34f1c2249 100644 --- a/lib_enc/ivas_mcmasa_enc.c +++ b/lib_enc/ivas_mcmasa_enc.c @@ -36,8 +36,11 @@ #include #include "ivas_cnst.h" #include "ivas_prot.h" +#include "ivas_prot_fx.h" #include "options.h" #include "prot.h" +#include "prot_fx1.h" +#include "prot_fx2.h" #include "ivas_rom_com.h" #include "ivas_rom_enc.h" #include "wmc_auto.h" @@ -731,6 +734,7 @@ void ivas_mcmasa_enc( * Estimate metadata parameters for McMASA *--------------------------------------------------------------------------*/ +#ifdef IVAS_FLOAT_FIXED void ivas_mcmasa_param_est_enc( MCMASA_ENC_HANDLE hMcMasa, /* i : McMASA encoder structure */ MASA_ENCODER_HANDLE hMasa, /* i : MASA encoder structure */ @@ -748,6 +752,11 @@ void ivas_mcmasa_param_est_enc( int16_t ts, i, j, d; int16_t num_freq_bins, num_freq_bands, index; float dir_v[DIRAC_NUM_DIMS]; +#ifdef IVAS_FLOAT_FIXED_ + Word32 elevation_m_values_fx[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS]; + Word32 azimuth_m_values_fx[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS]; + Word32 dir_v_fx[DIRAC_NUM_DIMS]; +#endif int16_t l_ts; float *pcm_in[MCMASA_MAX_ANA_CHANS]; float Chnl_RealBuffer[MCMASA_MAX_ANA_CHANS][DIRAC_NO_FB_BANDS_MAX]; @@ -1038,7 +1047,22 @@ void ivas_mcmasa_param_est_enc( { dir_v[d] = hMcMasa->direction_vector_m[d][block_m_idx][band_m_idx]; } +#ifdef IVAS_FLOAT_FIXED_ + /*==========================================flt-2-fix======================================================*/ + Word16 q_dir_e = 0; + f2me_buf( dir_v, dir_v_fx, &q_dir_e, 3 ); + Scale_sig32( dir_v_fx, 3, -1 ); + /*==========================================flt-2-fix======================================================*/ + + ivas_qmetadata_direction_vector_to_azimuth_elevation_fx( dir_v_fx, Q30, &azimuth_m_values_fx[block_m_idx][band_m_idx], &elevation_m_values_fx[block_m_idx][band_m_idx] ); + + /*==========================================fix-2-flt======================================================*/ + azimuth_m_values[block_m_idx][band_m_idx] = fixedToFloat( azimuth_m_values_fx[block_m_idx][band_m_idx], Q22 ); + elevation_m_values[block_m_idx][band_m_idx] = fixedToFloat( elevation_m_values_fx[block_m_idx][band_m_idx], Q22 ); + /*==========================================fix-2-flt======================================================*/ +#else ivas_qmetadata_direction_vector_to_azimuth_elevation( dir_v, &azimuth_m_values[block_m_idx][band_m_idx], &elevation_m_values[block_m_idx][band_m_idx] ); +#endif } /* Coherence processing */ @@ -1243,6 +1267,520 @@ void ivas_mcmasa_param_est_enc( return; } +#else +void ivas_mcmasa_param_est_enc( + MCMASA_ENC_HANDLE hMcMasa, /* i : McMASA encoder structure */ + MASA_ENCODER_HANDLE hMasa, /* i : MASA encoder structure */ + float *data_f[], /* i : Audio frame in MC-format */ + float elevation_m_values[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS], /* o : Estimated elevation */ + float azimuth_m_values[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS], /* o : Estimated azimuth */ + float energyRatio[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS], /* o : Estimated direct-to-total ratio */ + float spreadCoherence[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS], /* o : Estimated spread coherence */ + float surroundingCoherence[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS], /* o : Estimated surround coherence */ + const int16_t input_frame, /* i : Input frame size */ + const int16_t nchan_inp /* i : Number of input channels */ +) +{ + float reference_power[MDFT_NO_COL_MAX][DIRAC_NO_FB_BANDS_MAX]; + int16_t ts, i, j, d; + int16_t num_freq_bins, num_freq_bands, index; + float dir_v[DIRAC_NUM_DIMS]; + int16_t l_ts; + float *pcm_in[MCMASA_MAX_ANA_CHANS]; + float Chnl_RealBuffer[MCMASA_MAX_ANA_CHANS][DIRAC_NO_FB_BANDS_MAX]; + float Chnl_ImagBuffer[MCMASA_MAX_ANA_CHANS][DIRAC_NO_FB_BANDS_MAX]; + float *p_Chnl_RealBuffer[MCMASA_MAX_ANA_CHANS]; + float *p_Chnl_ImagBuffer[MCMASA_MAX_ANA_CHANS]; + float Foa_RealBuffer[FOA_CHANNELS][DIRAC_NO_FB_BANDS_MAX]; + float Foa_ImagBuffer[FOA_CHANNELS][DIRAC_NO_FB_BANDS_MAX]; + float FoaEven_RealBuffer[FOA_CHANNELS][DIRAC_NO_FB_BANDS_MAX]; + float FoaEven_ImagBuffer[FOA_CHANNELS][DIRAC_NO_FB_BANDS_MAX]; + float intensity_real[DIRAC_NUM_DIMS][MASA_FREQUENCY_BANDS]; + float intensity_even_real[DIRAC_NUM_DIMS][MASA_FREQUENCY_BANDS]; + float direction_vector[DIRAC_NUM_DIMS][MASA_FREQUENCY_BANDS]; + float diffuseness_vector[MASA_FREQUENCY_BANDS]; + float vertical_diffuseness_vector[MASA_FREQUENCY_BANDS]; + float diffuseness_m[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS]; + float coherentEnergyRatio[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS]; + int16_t band_m_idx, block_m_idx; + float renormalization_factor_diff[MASA_FREQUENCY_BANDS]; + float norm_tmp; + int16_t mrange[2], brange[2]; + int16_t numSubFramesForRatio; + CovarianceMatrix COVls[MASA_FREQUENCY_BANDS]; + float absCOVls[MCMASA_MAX_ANA_CHANS][MCMASA_MAX_ANA_CHANS]; + float lsEnergy[MCMASA_MAX_ANA_CHANS]; + float lsEnergySum, maxEne; + int16_t loudestCh; + float surrCoh, tempCoh, tempCoh2; + int16_t i1, i2, i3; + float angleDist, minAngleDist; + float currentAzi; + float lsEnergyRelation; + float tempLsEnergyRelation; + float stereoness, cohwideness, spreadCoh; + float stereoRatio, cohPanRatio; + float stereoCoh, cohPanCoh, cohRatio; + float renormalization_factor_coh[MASA_FREQUENCY_BANDS]; + int16_t numAnalysisChannels; + + num_freq_bins = input_frame / MDFT_NO_COL_MAX; + num_freq_bands = hMcMasa->nbands; + l_ts = input_frame / MDFT_NO_COL_MAX; + + numAnalysisChannels = nchan_inp - 1; + if ( hMcMasa->separateChannelEnabled ) + { + numAnalysisChannels = nchan_inp - 2; + } + + if ( hMcMasa->combineRatios ) + { + /* Need to initialize renormalization_factors, and variables to be normalized */ + set_zero( renormalization_factor_diff, hMcMasa->nbands ); + set_zero( diffuseness_m[0], hMcMasa->nbands ); + set_zero( renormalization_factor_coh, hMcMasa->nbands ); + set_zero( surroundingCoherence[0], hMcMasa->nbands ); + set_zero( coherentEnergyRatio[0], hMcMasa->nbands ); + } + + /* Copy current frame to memory for delay compensation */ + for ( i = 0; i < numAnalysisChannels; i++ ) + { + pcm_in[i] = data_f[i]; + p_Chnl_RealBuffer[i] = &Chnl_RealBuffer[i][0]; + p_Chnl_ImagBuffer[i] = &Chnl_ImagBuffer[i][0]; + } + + /* do processing over all CLDFB time slots */ + for ( block_m_idx = 0; block_m_idx < MAX_PARAM_SPATIAL_SUBFRAMES; block_m_idx++ ) + { + mrange[0] = hMcMasa->block_grouping[block_m_idx]; + mrange[1] = hMcMasa->block_grouping[block_m_idx + 1]; + + for ( band_m_idx = 0; band_m_idx < hMcMasa->nbands; band_m_idx++ ) + { + hMcMasa->direction_vector_m[0][block_m_idx][band_m_idx] = 0; + hMcMasa->direction_vector_m[1][block_m_idx][band_m_idx] = 0; + hMcMasa->direction_vector_m[2][block_m_idx][band_m_idx] = 0; + } + + /* Reset variable */ + for ( i = 0; i < hMcMasa->nbands; i++ ) + { + for ( j = 0; j < numAnalysisChannels; j++ ) + { + set_zero( COVls[i].xr[j], numAnalysisChannels ); + set_zero( COVls[i].xi[j], numAnalysisChannels ); + } + } + + for ( ts = mrange[0]; ts < mrange[1]; ts++ ) + { + ivas_fb_mixer_get_windowed_fr( hMcMasa->hFbMixer, pcm_in, p_Chnl_RealBuffer, p_Chnl_ImagBuffer, l_ts, l_ts, hMcMasa->hFbMixer->fb_cfg->num_in_chans ); + + ivas_fb_mixer_update_prior_input( hMcMasa->hFbMixer, pcm_in, l_ts, hMcMasa->hFbMixer->fb_cfg->num_in_chans ); + + for ( i = 0; i < numAnalysisChannels; i++ ) + { + pcm_in[i] += l_ts; + } + + /* Compute covariance matrix */ + for ( i = 0; i < num_freq_bands; i++ ) + { + brange[0] = hMcMasa->band_grouping[i]; + brange[1] = hMcMasa->band_grouping[i + 1]; + for ( j = brange[0]; j < brange[1]; j++ ) + { + compute_cov_mtx( Chnl_RealBuffer, Chnl_ImagBuffer, j, numAnalysisChannels, &( COVls[i] ) ); + } + + /* Store energies for guiding metadata encoding */ + hMasa->data.energy[block_m_idx][i] = 0.0f; + for ( j = 0; j < numAnalysisChannels; j++ ) + { + hMasa->data.energy[block_m_idx][i] += COVls[i].xr[j][j]; + } + } + + if ( !hMcMasa->separateChannelEnabled ) + { + /* Compute low frequency energy */ + for ( i = 0; i < numAnalysisChannels; i++ ) + { + for ( j = 0; j < CLDFB_TO_MDFT_FAC; j++ ) + { + hMcMasa->totalLfEne[block_m_idx] += Chnl_RealBuffer[i][j] * Chnl_RealBuffer[i][j] + Chnl_ImagBuffer[i][j] * Chnl_ImagBuffer[i][j]; + } + } + } + + /* Compute standard FOA */ + /* W */ + v_add( Chnl_RealBuffer[0], Chnl_RealBuffer[1], Foa_RealBuffer[0], num_freq_bins ); + v_add( Chnl_ImagBuffer[0], Chnl_ImagBuffer[1], Foa_ImagBuffer[0], num_freq_bins ); + for ( i = 2; i < numAnalysisChannels; i++ ) + { + v_add( Chnl_RealBuffer[i], Foa_RealBuffer[0], Foa_RealBuffer[0], num_freq_bins ); + v_add( Chnl_ImagBuffer[i], Foa_ImagBuffer[0], Foa_ImagBuffer[0], num_freq_bins ); + } + + /* Y */ + v_multc( Chnl_RealBuffer[0], hMcMasa->chnlToFoaMtx[1][0], Foa_RealBuffer[1], num_freq_bins ); + v_multc( Chnl_ImagBuffer[0], hMcMasa->chnlToFoaMtx[1][0], Foa_ImagBuffer[1], num_freq_bins ); + for ( i = 1; i < numAnalysisChannels; i++ ) + { + v_multc_acc( Chnl_RealBuffer[i], hMcMasa->chnlToFoaMtx[1][i], Foa_RealBuffer[1], num_freq_bins ); + v_multc_acc( Chnl_ImagBuffer[i], hMcMasa->chnlToFoaMtx[1][i], Foa_ImagBuffer[1], num_freq_bins ); + } + + /* Z */ + if ( hMcMasa->isHorizontalSetup ) + { + /* Set zero for horizontal setups */ + set_zero( Foa_RealBuffer[2], num_freq_bins ); + set_zero( Foa_ImagBuffer[2], num_freq_bins ); + } + else + { + v_multc( Chnl_RealBuffer[0], hMcMasa->chnlToFoaMtx[2][0], Foa_RealBuffer[2], num_freq_bins ); + v_multc( Chnl_ImagBuffer[0], hMcMasa->chnlToFoaMtx[2][0], Foa_ImagBuffer[2], num_freq_bins ); + for ( i = 1; i < numAnalysisChannels; i++ ) + { + v_multc_acc( Chnl_RealBuffer[i], hMcMasa->chnlToFoaMtx[2][i], Foa_RealBuffer[2], num_freq_bins ); + v_multc_acc( Chnl_ImagBuffer[i], hMcMasa->chnlToFoaMtx[2][i], Foa_ImagBuffer[2], num_freq_bins ); + } + } + + /* X */ + v_multc( Chnl_RealBuffer[0], hMcMasa->chnlToFoaMtx[3][0], Foa_RealBuffer[3], num_freq_bins ); + v_multc( Chnl_ImagBuffer[0], hMcMasa->chnlToFoaMtx[3][0], Foa_ImagBuffer[3], num_freq_bins ); + for ( i = 1; i < numAnalysisChannels; i++ ) + { + v_multc_acc( Chnl_RealBuffer[i], hMcMasa->chnlToFoaMtx[3][i], Foa_RealBuffer[3], num_freq_bins ); + v_multc_acc( Chnl_ImagBuffer[i], hMcMasa->chnlToFoaMtx[3][i], Foa_ImagBuffer[3], num_freq_bins ); + } + + /* Compute even FOA */ + /* W */ + mvr2r( Foa_RealBuffer[0], FoaEven_RealBuffer[0], num_freq_bins ); + mvr2r( Foa_ImagBuffer[0], FoaEven_ImagBuffer[0], num_freq_bins ); + + /* Y */ + v_multc( Chnl_RealBuffer[0], hMcMasa->chnlToFoaEvenMtx[1][0], FoaEven_RealBuffer[1], num_freq_bins ); + v_multc( Chnl_ImagBuffer[0], hMcMasa->chnlToFoaEvenMtx[1][0], FoaEven_ImagBuffer[1], num_freq_bins ); + for ( i = 1; i < numAnalysisChannels; i++ ) + { + v_multc_acc( Chnl_RealBuffer[i], hMcMasa->chnlToFoaEvenMtx[1][i], FoaEven_RealBuffer[1], num_freq_bins ); + v_multc_acc( Chnl_ImagBuffer[i], hMcMasa->chnlToFoaEvenMtx[1][i], FoaEven_ImagBuffer[1], num_freq_bins ); + } + + /* Z (even setups are handled as horizontal) */ + set_zero( FoaEven_RealBuffer[2], num_freq_bins ); + set_zero( FoaEven_ImagBuffer[2], num_freq_bins ); + + /* X */ + v_multc( Chnl_RealBuffer[0], hMcMasa->chnlToFoaEvenMtx[3][0], FoaEven_RealBuffer[3], num_freq_bins ); + v_multc( Chnl_ImagBuffer[0], hMcMasa->chnlToFoaEvenMtx[3][0], FoaEven_ImagBuffer[3], num_freq_bins ); + for ( i = 1; i < numAnalysisChannels; i++ ) + { + v_multc_acc( Chnl_RealBuffer[i], hMcMasa->chnlToFoaEvenMtx[3][i], FoaEven_RealBuffer[3], num_freq_bins ); + v_multc_acc( Chnl_ImagBuffer[i], hMcMasa->chnlToFoaEvenMtx[3][i], FoaEven_ImagBuffer[3], num_freq_bins ); + } + + /* Direction estimation */ + computeIntensityVector_enc( + hMcMasa->band_grouping, + Foa_RealBuffer, + Foa_ImagBuffer, + 0, + num_freq_bands, + intensity_real ); + + computeDirectionVectors( + intensity_real[0], + intensity_real[1], + intensity_real[2], + 0, + num_freq_bands, + direction_vector[0], + direction_vector[1], + direction_vector[2] ); + + /* Power and intensity estimation for diffuseness */ + computeIntensityVector_enc( + hMcMasa->band_grouping, + FoaEven_RealBuffer, + FoaEven_ImagBuffer, + 0, + num_freq_bands, + intensity_even_real ); + + computeReferencePower_enc( hMcMasa->band_grouping, + FoaEven_RealBuffer, + FoaEven_ImagBuffer, + reference_power[ts], + 0, + num_freq_bands, + MC_FORMAT, + 0, + FOA_CHANNELS, + NULL, + NULL ); + + /* Fill buffers of length "averaging_length" time slots for intensity and energy */ + hMcMasa->index_buffer_intensity = ( hMcMasa->index_buffer_intensity % hMcMasa->no_col_avg_diff ) + 1; /* averaging_length = 32 */ + index = hMcMasa->index_buffer_intensity; + for ( i = 0; i < DIRAC_NUM_DIMS; i++ ) + { + /* only real part needed */ + mvr2r( intensity_even_real[i], &( hMcMasa->buffer_intensity_real[i][index - 1][0] ), num_freq_bands ); + } + mvr2r( reference_power[ts], &( hMcMasa->buffer_energy[( index - 1 ) * num_freq_bands] ), num_freq_bands ); + + computeDiffuseness_mdft( hMcMasa->buffer_intensity_real, hMcMasa->buffer_energy, num_freq_bands, hMcMasa->no_col_avg_diff, diffuseness_vector ); + + /* Compute vertical diffuseness, and tune original diffuseness if needed */ + if ( !hMcMasa->isHorizontalSetup ) + { + mvr2r( intensity_real[2], &( hMcMasa->buffer_intensity_real_vert[index - 1][0] ), num_freq_bands ); + computeVerticalDiffuseness( hMcMasa->buffer_intensity_real_vert, hMcMasa->buffer_energy, hMcMasa->no_col_avg_diff, num_freq_bands, vertical_diffuseness_vector ); + v_min( diffuseness_vector, vertical_diffuseness_vector, diffuseness_vector, num_freq_bands ); + } + + for ( band_m_idx = 0; band_m_idx < hMcMasa->nbands; band_m_idx++ ) + { + norm_tmp = reference_power[ts][band_m_idx] * ( 1 - diffuseness_vector[band_m_idx] ); + + hMcMasa->direction_vector_m[0][block_m_idx][band_m_idx] += norm_tmp * direction_vector[0][band_m_idx]; + hMcMasa->direction_vector_m[1][block_m_idx][band_m_idx] += norm_tmp * direction_vector[1][band_m_idx]; + hMcMasa->direction_vector_m[2][block_m_idx][band_m_idx] += norm_tmp * direction_vector[2][band_m_idx]; + + if ( hMcMasa->combineRatios ) + { + diffuseness_m[0][band_m_idx] += reference_power[ts][band_m_idx] * diffuseness_vector[band_m_idx]; + renormalization_factor_diff[band_m_idx] += reference_power[ts][band_m_idx]; + } + else + { + diffuseness_m[block_m_idx][band_m_idx] = diffuseness_vector[band_m_idx]; + } + } + } + + for ( band_m_idx = 0; band_m_idx < hMcMasa->nbands; band_m_idx++ ) + { + for ( d = 0; d < DIRAC_NUM_DIMS; d++ ) + { + dir_v[d] = hMcMasa->direction_vector_m[d][block_m_idx][band_m_idx]; + } + ivas_qmetadata_direction_vector_to_azimuth_elevation( dir_v, &azimuth_m_values[block_m_idx][band_m_idx], &elevation_m_values[block_m_idx][band_m_idx] ); + } + + /* Coherence processing */ + for ( band_m_idx = 0; band_m_idx < hMcMasa->nbands; band_m_idx++ ) + { + /* Compute absolute values */ + for ( i = 0; i < numAnalysisChannels; i++ ) + { + for ( j = i; j < numAnalysisChannels; j++ ) + { + absCOVls[i][j] = sqrtf( ( COVls[band_m_idx].xr[i][j] * COVls[band_m_idx].xr[i][j] + COVls[band_m_idx].xi[i][j] * COVls[band_m_idx].xi[i][j] ) ); + } + lsEnergy[i] = absCOVls[i][i]; + } + + /* Find loudest channel */ + maxEne = lsEnergy[0]; + loudestCh = 0; + for ( i = 1; i < numAnalysisChannels; i++ ) + { + if ( lsEnergy[i] > maxEne ) + { + maxEne = lsEnergy[i]; + loudestCh = i; + } + } + + /* Compute surrounding coherence */ + surrCoh = 1.0f; + for ( i = 0; i < numAnalysisChannels; i++ ) + { + if ( i != loudestCh ) + { + if ( i < loudestCh ) + { + i1 = i; + i2 = loudestCh; + } + else + { + i1 = loudestCh; + i2 = i; + } + tempCoh = absCOVls[i1][i2] / ( sqrtf( ( lsEnergy[i1] * lsEnergy[i2] + EPSILON ) ) ); + surrCoh = ( surrCoh < tempCoh ) ? surrCoh : tempCoh; + } + } + surrCoh = surrCoh * surrCoh; + surrCoh = ( surrCoh < 1.0f ) ? surrCoh : 1.0f; + surrCoh = ( surrCoh > 0.0f ) ? surrCoh : 0.0f; + + /* Compute spread coherence */ + if ( elevation_m_values[block_m_idx][band_m_idx] < NEAR_HORIZONTAL_PLANE_ELEVATION ) /* Computed only near horizontal plane */ + { + minAngleDist = 180.0f; + i1 = 0; + currentAzi = azimuth_m_values[block_m_idx][band_m_idx]; + for ( i = 0; i < hMcMasa->numHorizontalChannels; i++ ) + { + angleDist = fabsf( currentAzi - hMcMasa->ls_azimuth[i] ); + if ( angleDist > 180.0f ) + { + angleDist = fabsf( angleDist - 360.0f ); + } + if ( angleDist < minAngleDist ) + { + minAngleDist = angleDist; + i1 = i; + } + } + i2 = hMcMasa->leftNearest[i1]; + i3 = hMcMasa->rightNearest[i1]; + + if ( i2 < i3 ) + { + stereoCoh = absCOVls[i2][i3] / ( sqrtf( lsEnergy[i2] * lsEnergy[i3] + EPSILON ) ); + } + else + { + stereoCoh = absCOVls[i3][i2] / ( sqrtf( lsEnergy[i2] * lsEnergy[i3] + EPSILON ) ); + } + lsEnergyRelation = ( lsEnergy[i2] + lsEnergy[i3] ) / ( lsEnergy[i1] + lsEnergy[i2] + lsEnergy[i3] + EPSILON ); + stereoness = stereoCoh * lsEnergyRelation; + + if ( i1 < i2 ) + { + tempCoh = absCOVls[i1][i2] / ( sqrtf( lsEnergy[i1] * lsEnergy[i2] + EPSILON ) ); + } + else + { + tempCoh = absCOVls[i2][i1] / ( sqrtf( lsEnergy[i1] * lsEnergy[i2] + EPSILON ) ); + } + if ( i1 < i3 ) + { + tempCoh2 = absCOVls[i1][i3] / ( sqrtf( lsEnergy[i1] * lsEnergy[i3] + EPSILON ) ); + } + else + { + tempCoh2 = absCOVls[i3][i1] / ( sqrtf( lsEnergy[i1] * lsEnergy[i3] + EPSILON ) ); + } + cohPanCoh = ( tempCoh < tempCoh2 ) ? tempCoh : tempCoh2; + lsEnergyRelation = lsEnergy[i2] / ( lsEnergy[i1] + EPSILON ); + tempLsEnergyRelation = lsEnergy[i1] / ( lsEnergy[i2] + EPSILON ); + lsEnergyRelation = ( lsEnergyRelation < tempLsEnergyRelation ) ? lsEnergyRelation : tempLsEnergyRelation; + tempLsEnergyRelation = lsEnergy[i3] / ( lsEnergy[i1] + EPSILON ); + lsEnergyRelation = ( lsEnergyRelation < tempLsEnergyRelation ) ? lsEnergyRelation : tempLsEnergyRelation; + tempLsEnergyRelation = lsEnergy[i1] / ( lsEnergy[i3] + EPSILON ); + lsEnergyRelation = ( lsEnergyRelation < tempLsEnergyRelation ) ? lsEnergyRelation : tempLsEnergyRelation; + cohwideness = cohPanCoh * lsEnergyRelation; + + spreadCoh = ( cohwideness > stereoness ) ? cohwideness : stereoness; + if ( spreadCoh > 0.5f ) + { + if ( cohwideness > stereoness ) + { + tempCoh = stereoness - ( cohwideness - 0.5f ); + spreadCoh = ( tempCoh > 0.5f ) ? tempCoh : 0.5f; + } + } + spreadCoh = ( spreadCoh < 1.0f ) ? spreadCoh : 1.0f; + spreadCoh = ( spreadCoh > 0.0f ) ? spreadCoh : 0.0f; + + /* Compute energy ratio tuning parameter */ + lsEnergySum = sum_f( lsEnergy, numAnalysisChannels ) + EPSILON; + lsEnergyRelation = ( lsEnergy[i2] + lsEnergy[i3] ) / lsEnergySum; + stereoRatio = stereoCoh * lsEnergyRelation - surrCoh; + + lsEnergyRelation = ( lsEnergy[i1] + lsEnergy[i2] + lsEnergy[i3] ) / lsEnergySum; + cohPanRatio = cohPanCoh * lsEnergyRelation - surrCoh; + + cohRatio = ( stereoRatio > cohPanRatio ) ? stereoRatio : cohPanRatio; + cohRatio = ( cohRatio < 1.0f ) ? cohRatio : 1.0f; + cohRatio = ( cohRatio > 0.0f ) ? cohRatio : 0.0f; + } + else /* Otherwise, set spread coherence to zero */ + { + spreadCoh = 0.0f; + cohRatio = 0.0f; + lsEnergySum = sum_f( lsEnergy, numAnalysisChannels ); + } + + /* Store values */ + spreadCoherence[block_m_idx][band_m_idx] = spreadCoh; + + if ( hMcMasa->combineRatios ) + { + surroundingCoherence[0][band_m_idx] += lsEnergySum * surrCoh; + coherentEnergyRatio[0][band_m_idx] += lsEnergySum * cohRatio; + renormalization_factor_coh[band_m_idx] += lsEnergySum; + } + else + { + surroundingCoherence[block_m_idx][band_m_idx] = surrCoh; + coherentEnergyRatio[block_m_idx][band_m_idx] = cohRatio; + } + } + } + + if ( hMcMasa->combineRatios ) + { + for ( band_m_idx = 0; band_m_idx < hMcMasa->nbands; band_m_idx++ ) + { + if ( renormalization_factor_diff[band_m_idx] > EPSILON ) + { + diffuseness_m[0][band_m_idx] /= renormalization_factor_diff[band_m_idx]; + } + else + { + diffuseness_m[0][band_m_idx] = 0.f; + } + if ( renormalization_factor_coh[band_m_idx] > EPSILON ) + { + surroundingCoherence[0][band_m_idx] /= renormalization_factor_coh[band_m_idx]; + coherentEnergyRatio[0][band_m_idx] /= renormalization_factor_coh[band_m_idx]; + } + else + { + surroundingCoherence[0][band_m_idx] = 0.f; + coherentEnergyRatio[0][band_m_idx] = 0.f; + } + } + } + + /* Determine energy ratios */ + if ( hMcMasa->combineRatios ) + { + numSubFramesForRatio = 1; + } + else + { + numSubFramesForRatio = MAX_PARAM_SPATIAL_SUBFRAMES; + } + + for ( i = 0; i < numSubFramesForRatio; i++ ) + { + for ( j = 0; j < hMcMasa->nbands; j++ ) + { + energyRatio[i][j] = 1.0f - diffuseness_m[i][j]; + energyRatio[i][j] = ( energyRatio[i][j] > coherentEnergyRatio[i][j] ) ? energyRatio[i][j] : coherentEnergyRatio[i][j]; + } + } + + return; +} +#endif /*--------------------------------------------------------------------------* diff --git a/lib_enc/ivas_mct_core_enc.c b/lib_enc/ivas_mct_core_enc.c index e09f42e78..cc18b15cf 100644 --- a/lib_enc/ivas_mct_core_enc.c +++ b/lib_enc/ivas_mct_core_enc.c @@ -38,6 +38,9 @@ #include "ivas_prot.h" #include "rom_com.h" #include "wmc_auto.h" +#ifdef IVAS_FLOAT_FIXED +#include "ivas_prot_fx.h" +#endif /*----------------------------------------------------------* @@ -260,16 +263,28 @@ void ivas_mct_core_enc( if ( switch_bw ) { +#ifndef IVAS_FLOAT_FIXED initMdctStereoEncData( hMCT->hBlockData[ch]->hStereoMdct, ivas_format, sts[ch_core]->element_mode, sts[ch_core]->element_brate, sts[ch_core]->bwidth, sts[ch_core]->igf, sts[ch_core]->hIGFEnc->igfData.igfInfo.grid, 0 ); +#else + initMdctStereoEncData_fx( hMCT->hBlockData[ch]->hStereoMdct, ivas_format, sts[ch_core]->element_mode, sts[ch_core]->element_brate, sts[ch_core]->bwidth, + sts[ch_core]->igf, sts[ch_core]->hIGFEnc->igfData.igfInfo.grid, 0 ); +#endif } if ( sts[ch_core]->igf ) { +#ifndef IVAS_FLOAT_FIXED /* calculate the igf start band from the igf start line */ stereo_mdct_init_igf_start_band( &hMCT->hBlockData[ch]->hStereoMdct->stbParamsTCX20, 1.0f, sts[ch_core]->bwidth, sts[ch_core]->total_brate ); stereo_mdct_init_igf_start_band( &hMCT->hBlockData[ch]->hStereoMdct->stbParamsTCX10, 0.5f, sts[ch_core]->bwidth, sts[ch_core]->total_brate ); +#else + /* calculate the igf start band from the igf start line */ + stereo_mdct_init_igf_start_band_fx( &hMCT->hBlockData[ch]->hStereoMdct->stbParamsTCX20, 16384 /* 1.0f in Q14 */, sts[ch_core]->bwidth, sts[ch_core]->total_brate ); + + stereo_mdct_init_igf_start_band_fx( &hMCT->hBlockData[ch]->hStereoMdct->stbParamsTCX10, 8192 /* 0.5f in Q14 */, sts[ch_core]->bwidth, sts[ch_core]->total_brate ); +#endif } else { diff --git a/lib_enc/ivas_mct_enc.c b/lib_enc/ivas_mct_enc.c index 49364ad7f..e0e9d5cbc 100644 --- a/lib_enc/ivas_mct_enc.c +++ b/lib_enc/ivas_mct_enc.c @@ -224,7 +224,11 @@ ivas_error ivas_mct_enc( for ( n = 0; n < (int16_t) ( hMCT->nchan_out_woLFE * 0.5 ); n++ ) { +#ifndef IVAS_FLOAT_FIXED initMdctStereoEncData( hMCT->hBlockData[n]->hStereoMdct, ivas_format, IVAS_CPE_MDCT, cp_bitrate, max_bwidth, st_ivas->hCPE[0]->hCoreCoder[0]->igf, st_ivas->hCPE[0]->hCoreCoder[0]->igf ? st_ivas->hCPE[0]->hCoreCoder[0]->hIGFEnc->igfData.igfInfo.grid : NULL, 0 ); +#else + initMdctStereoEncData_fx( hMCT->hBlockData[n]->hStereoMdct, ivas_format, IVAS_CPE_MDCT, cp_bitrate, max_bwidth, st_ivas->hCPE[0]->hCoreCoder[0]->igf, st_ivas->hCPE[0]->hCoreCoder[0]->igf ? st_ivas->hCPE[0]->hCoreCoder[0]->hIGFEnc->igfData.igfInfo.grid : NULL, 0 ); +#endif } } @@ -375,7 +379,11 @@ ivas_error create_mct_enc( return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for MDCT Stereo \n" ) ); } +#ifndef IVAS_FLOAT_FIXED initMdctStereoEncData( hMCT->hBlockData[n]->hStereoMdct, ivas_format, IVAS_CPE_MDCT, cp_bitrate, st_ivas->hEncoderConfig->max_bwidth, st_ivas->hCPE[0]->hCoreCoder[0]->igf, st_ivas->hCPE[0]->hCoreCoder[0]->igf ? st_ivas->hCPE[0]->hCoreCoder[0]->hIGFEnc->igfData.igfInfo.grid : NULL, 1 ); +#else + initMdctStereoEncData_fx( hMCT->hBlockData[n]->hStereoMdct, ivas_format, IVAS_CPE_MDCT, cp_bitrate, st_ivas->hEncoderConfig->max_bwidth, st_ivas->hCPE[0]->hCoreCoder[0]->igf, st_ivas->hCPE[0]->hCoreCoder[0]->igf ? st_ivas->hCPE[0]->hCoreCoder[0]->hIGFEnc->igfData.igfInfo.grid : NULL, 1 ); +#endif } for ( ; n < MCT_MAX_BLOCKS; n++ ) @@ -529,7 +537,11 @@ ivas_error mct_enc_reconfigure( } } +#ifndef IVAS_FLOAT_FIXED initMdctStereoEncData( hMCT->hBlockData[n]->hStereoMdct, ivas_format, IVAS_CPE_MDCT, cp_bitrate, st_ivas->hEncoderConfig->max_bwidth, st_ivas->hCPE[0]->hCoreCoder[0]->igf, st_ivas->hCPE[0]->hCoreCoder[0]->igf ? st_ivas->hCPE[0]->hCoreCoder[0]->hIGFEnc->igfData.igfInfo.grid : NULL, mem_init ); +#else + initMdctStereoEncData_fx( hMCT->hBlockData[n]->hStereoMdct, ivas_format, IVAS_CPE_MDCT, cp_bitrate, st_ivas->hEncoderConfig->max_bwidth, st_ivas->hCPE[0]->hCoreCoder[0]->igf, st_ivas->hCPE[0]->hCoreCoder[0]->igf ? st_ivas->hCPE[0]->hCoreCoder[0]->hIGFEnc->igfData.igfInfo.grid : NULL, mem_init ); +#endif } for ( ; n < MCT_MAX_BLOCKS; n++ ) diff --git a/lib_enc/ivas_omasa_enc.c b/lib_enc/ivas_omasa_enc.c index 102a8307b..1f5499f07 100644 --- a/lib_enc/ivas_omasa_enc.c +++ b/lib_enc/ivas_omasa_enc.c @@ -36,7 +36,10 @@ #include #include "ivas_cnst.h" #include "ivas_prot.h" +#include "ivas_prot_fx.h" #include "prot.h" +#include "prot_fx1.h" +#include "prot_fx2.h" #include "ivas_rom_com.h" #include "ivas_rom_enc.h" #include "wmc_auto.h" @@ -737,6 +740,216 @@ int16_t ivas_omasa_ener_brate( *--------------------------------------------------------------------------*/ /* Estimate MASA parameters from the objects */ +#ifdef IVAS_FLOAT_FIXED +static void ivas_omasa_param_est_enc( + OMASA_ENC_HANDLE hOMasa, + OMASA_ENCODER_DATA_HANDLE hOmasaData, + ISM_METADATA_HANDLE hIsmMeta[], + float *data_f[], + float elevation_m_values[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS], + float azimuth_m_values[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS], + float energyRatio[MASA_FREQUENCY_BANDS], + float spreadCoherence[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS], + float surroundingCoherence[MASA_FREQUENCY_BANDS], + float diffuseness_m[MASA_FREQUENCY_BANDS], + const int16_t input_frame, + const int16_t nchan_ism ) +{ + float reference_power[CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; + int16_t ts, i, j, d, k; + int16_t num_freq_bins, num_freq_bands, index; + float dir_v[DIRAC_NUM_DIMS]; +#ifdef IVAS_FLOAT_FIXED_ + Word32 elevation_m_values_fx[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS]; + Word32 azimuth_m_values_fx[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS]; + Word32 dir_v_fx[DIRAC_NUM_DIMS]; +#endif + int16_t l_ts; + float Chnl_RealBuffer[MCMASA_MAX_ANA_CHANS][CLDFB_NO_CHANNELS_MAX]; + float Chnl_ImagBuffer[MCMASA_MAX_ANA_CHANS][CLDFB_NO_CHANNELS_MAX]; + float Foa_RealBuffer[FOA_CHANNELS][CLDFB_NO_CHANNELS_MAX]; + float Foa_ImagBuffer[FOA_CHANNELS][CLDFB_NO_CHANNELS_MAX]; + float intensity_real[DIRAC_NUM_DIMS][MASA_FREQUENCY_BANDS]; + float direction_vector[DIRAC_NUM_DIMS][MASA_FREQUENCY_BANDS]; + float diffuseness_vector[MASA_FREQUENCY_BANDS]; + int16_t band_m_idx, block_m_idx; + float renormalization_factor_diff[MASA_FREQUENCY_BANDS]; + float norm_tmp; + int16_t mrange[2], brange[2]; + + num_freq_bins = hOMasa->cldfbAnaEnc[0]->no_channels; + num_freq_bands = hOMasa->nbands; + l_ts = input_frame / CLDFB_NO_COL_MAX; + + /* Need to initialize renormalization_factors, and variables to be normalized */ + set_zero( renormalization_factor_diff, hOMasa->nbands ); + set_zero( diffuseness_m, hOMasa->nbands ); + + /* Compute ISM to FOA matrices */ + for ( i = 0; i < nchan_ism; i++ ) + { + hOMasa->chnlToFoaMtx[0][i] = 1.0f; + hOMasa->chnlToFoaMtx[1][i] = sinf( ( hIsmMeta[i]->azimuth / 180.0f * EVS_PI ) ) * cosf( ( hIsmMeta[i]->elevation / 180.0f * EVS_PI ) ); + hOMasa->chnlToFoaMtx[2][i] = sinf( ( hIsmMeta[i]->elevation / 180.0f * EVS_PI ) ); + hOMasa->chnlToFoaMtx[3][i] = cosf( ( hIsmMeta[i]->azimuth / 180.0f * EVS_PI ) ) * cosf( ( hIsmMeta[i]->elevation / 180.0f * EVS_PI ) ); + } + + /* do processing over all CLDFB time slots */ + for ( block_m_idx = 0; block_m_idx < hOMasa->nSubframes; block_m_idx++ ) + { + mrange[0] = hOMasa->block_grouping[block_m_idx]; + mrange[1] = hOMasa->block_grouping[block_m_idx + 1]; + + for ( band_m_idx = 0; band_m_idx < hOMasa->nbands; band_m_idx++ ) + { + hOMasa->direction_vector_m[0][block_m_idx][band_m_idx] = 0.0f; + hOMasa->direction_vector_m[1][block_m_idx][band_m_idx] = 0.0f; + hOMasa->direction_vector_m[2][block_m_idx][band_m_idx] = 0.0f; + } + + set_zero( hOmasaData->energy_ism[block_m_idx], num_freq_bands ); + + for ( ts = mrange[0]; ts < mrange[1]; ts++ ) + { + for ( i = 0; i < nchan_ism; i++ ) + { + cldfbAnalysis_ts_ivas( &( data_f[i][l_ts * ts] ), Chnl_RealBuffer[i], Chnl_ImagBuffer[i], l_ts, hOMasa->cldfbAnaEnc[i] ); + } + + /* Compute energy */ + for ( i = 0; i < num_freq_bands; i++ ) + { + brange[0] = hOMasa->band_grouping[i]; + brange[1] = hOMasa->band_grouping[i + 1]; + for ( j = brange[0]; j < brange[1]; j++ ) + { + for ( k = 0; k < nchan_ism; k++ ) + { + hOmasaData->energy_ism[block_m_idx][i] += Chnl_RealBuffer[k][j] * Chnl_RealBuffer[k][j] + Chnl_ImagBuffer[k][j] * Chnl_ImagBuffer[k][j]; + } + } + } + + /* Compute FOA */ + /* W */ + mvr2r( Chnl_RealBuffer[0], Foa_RealBuffer[0], num_freq_bins ); + mvr2r( Chnl_ImagBuffer[0], Foa_ImagBuffer[0], num_freq_bins ); + for ( i = 1; i < nchan_ism; i++ ) + { + v_add( Chnl_RealBuffer[i], Foa_RealBuffer[0], Foa_RealBuffer[0], num_freq_bins ); + v_add( Chnl_ImagBuffer[i], Foa_ImagBuffer[0], Foa_ImagBuffer[0], num_freq_bins ); + } + + /* Y */ + v_multc( Chnl_RealBuffer[0], hOMasa->chnlToFoaMtx[1][0], Foa_RealBuffer[1], num_freq_bins ); + v_multc( Chnl_ImagBuffer[0], hOMasa->chnlToFoaMtx[1][0], Foa_ImagBuffer[1], num_freq_bins ); + for ( i = 1; i < nchan_ism; i++ ) + { + v_multc_acc( Chnl_RealBuffer[i], hOMasa->chnlToFoaMtx[1][i], Foa_RealBuffer[1], num_freq_bins ); + v_multc_acc( Chnl_ImagBuffer[i], hOMasa->chnlToFoaMtx[1][i], Foa_ImagBuffer[1], num_freq_bins ); + } + + /* Z */ + v_multc( Chnl_RealBuffer[0], hOMasa->chnlToFoaMtx[2][0], Foa_RealBuffer[2], num_freq_bins ); + v_multc( Chnl_ImagBuffer[0], hOMasa->chnlToFoaMtx[2][0], Foa_ImagBuffer[2], num_freq_bins ); + for ( i = 1; i < nchan_ism; i++ ) + { + v_multc_acc( Chnl_RealBuffer[i], hOMasa->chnlToFoaMtx[2][i], Foa_RealBuffer[2], num_freq_bins ); + v_multc_acc( Chnl_ImagBuffer[i], hOMasa->chnlToFoaMtx[2][i], Foa_ImagBuffer[2], num_freq_bins ); + } + + /* X */ + v_multc( Chnl_RealBuffer[0], hOMasa->chnlToFoaMtx[3][0], Foa_RealBuffer[3], num_freq_bins ); + v_multc( Chnl_ImagBuffer[0], hOMasa->chnlToFoaMtx[3][0], Foa_ImagBuffer[3], num_freq_bins ); + for ( i = 1; i < nchan_ism; i++ ) + { + v_multc_acc( Chnl_RealBuffer[i], hOMasa->chnlToFoaMtx[3][i], Foa_RealBuffer[3], num_freq_bins ); + v_multc_acc( Chnl_ImagBuffer[i], hOMasa->chnlToFoaMtx[3][i], Foa_ImagBuffer[3], num_freq_bins ); + } + + /* Direction estimation */ + computeIntensityVector_enc( hOMasa->band_grouping, Foa_RealBuffer, Foa_ImagBuffer, num_freq_bands, intensity_real ); + computeDirectionVectors( intensity_real[0], intensity_real[1], intensity_real[2], 0, num_freq_bands, direction_vector[0], direction_vector[1], direction_vector[2] ); + + /* Power estimation for diffuseness */ + computeReferencePower_omasa( hOMasa->band_grouping, Foa_RealBuffer, Foa_ImagBuffer, reference_power[ts], 0, num_freq_bands ); + + /* Fill buffers of length "averaging_length" time slots for intensity and energy */ + hOMasa->index_buffer_intensity = ( hOMasa->index_buffer_intensity % DIRAC_NO_COL_AVG_DIFF ) + 1; /* averaging_length = 32 */ + index = hOMasa->index_buffer_intensity; + for ( i = 0; i < DIRAC_NUM_DIMS; i++ ) + { + /* only real part needed */ + mvr2r( intensity_real[i], &( hOMasa->buffer_intensity_real[i][index - 1][0] ), num_freq_bands ); + } + mvr2r( reference_power[ts], &( hOMasa->buffer_energy[( index - 1 ) * num_freq_bands] ), num_freq_bands ); + + computeDiffuseness( hOMasa->buffer_intensity_real, hOMasa->buffer_energy, num_freq_bands, diffuseness_vector ); + + for ( band_m_idx = 0; band_m_idx < hOMasa->nbands; band_m_idx++ ) + { + norm_tmp = reference_power[ts][band_m_idx] * ( 1 - diffuseness_vector[band_m_idx] ); + + hOMasa->direction_vector_m[0][block_m_idx][band_m_idx] += norm_tmp * direction_vector[0][band_m_idx]; + hOMasa->direction_vector_m[1][block_m_idx][band_m_idx] += norm_tmp * direction_vector[1][band_m_idx]; + hOMasa->direction_vector_m[2][block_m_idx][band_m_idx] += norm_tmp * direction_vector[2][band_m_idx]; + + diffuseness_m[band_m_idx] += reference_power[ts][band_m_idx] * diffuseness_vector[band_m_idx]; + renormalization_factor_diff[band_m_idx] += reference_power[ts][band_m_idx]; + } + } + + for ( band_m_idx = 0; band_m_idx < hOMasa->nbands; band_m_idx++ ) + { + for ( d = 0; d < DIRAC_NUM_DIMS; d++ ) + { + dir_v[d] = hOMasa->direction_vector_m[d][block_m_idx][band_m_idx]; + } + +#ifdef IVAS_FLOAT_FIXED_ + /*==========================================flt-2-fix======================================================*/ + Word16 q_dir_e = 0; + f2me_buf( dir_v, dir_v_fx, &q_dir_e, 3 ); + Scale_sig32( dir_v_fx, 3, -1 ); + /*==========================================flt-2-fix======================================================*/ + + ivas_qmetadata_direction_vector_to_azimuth_elevation_fx( dir_v_fx, Q30, &azimuth_m_values_fx[block_m_idx][band_m_idx], &elevation_m_values_fx[block_m_idx][band_m_idx] ); + + /*==========================================fix-2-flt======================================================*/ + azimuth_m_values[block_m_idx][band_m_idx] = fixedToFloat( azimuth_m_values_fx[block_m_idx][band_m_idx], Q22 ); + elevation_m_values[block_m_idx][band_m_idx] = fixedToFloat( elevation_m_values_fx[block_m_idx][band_m_idx], Q22 ); + /*==========================================fix-2-flt======================================================*/ +#else + ivas_qmetadata_direction_vector_to_azimuth_elevation( dir_v, &azimuth_m_values[block_m_idx][band_m_idx], &elevation_m_values[block_m_idx][band_m_idx] ); +#endif + } + + /* Set coherences to zero, as this mode is used at lowest bit rates where the coherences are not transmitted */ + for ( band_m_idx = 0; band_m_idx < hOMasa->nbands; band_m_idx++ ) + { + spreadCoherence[block_m_idx][band_m_idx] = 0.0f; + surroundingCoherence[band_m_idx] = 0.0f; + } + } + + /* Determine energy ratios */ + for ( band_m_idx = 0; band_m_idx < hOMasa->nbands; band_m_idx++ ) + { + if ( renormalization_factor_diff[band_m_idx] > EPSILON ) + { + diffuseness_m[band_m_idx] /= renormalization_factor_diff[band_m_idx]; + } + else + { + diffuseness_m[band_m_idx] = 0.0f; + } + + energyRatio[band_m_idx] = 1.0f - diffuseness_m[band_m_idx]; + } + + return; +} +#else static void ivas_omasa_param_est_enc( OMASA_ENC_HANDLE hOMasa, OMASA_ENCODER_DATA_HANDLE hOmasaData, @@ -925,6 +1138,7 @@ static void ivas_omasa_param_est_enc( return; } +#endif /* Estimate energies and ratios */ diff --git a/lib_enc/ivas_qmetadata_enc.c b/lib_enc/ivas_qmetadata_enc.c index 84ff09dd8..bc6e1f9de 100644 --- a/lib_enc/ivas_qmetadata_enc.c +++ b/lib_enc/ivas_qmetadata_enc.c @@ -133,6 +133,7 @@ static int16_t find_optimal_GR_orders( const int16_t *q_idx, const int16_t len, * Main function for quantizing and coding Spatial Metadata *-----------------------------------------------------------------------*/ +#ifdef IVAS_FLOAT_FIXED ivas_error ivas_qmetadata_enc_encode( BSTR_ENC_HANDLE hMetaData, /* i/o: metadata bitstream handle */ IVAS_QMETADATA *hQMetaData, /* i/o: metadata handle */ @@ -248,9 +249,18 @@ ivas_error ivas_qmetadata_enc_encode( { if ( hQMetaData->twoDirBands[j] == 1 ) { +#ifdef IVAS_FLOAT_FIXED + /*=====================================flt-2-fix============================================*/ + hQMetaData->q_direction[0].band_data[j].energy_ratio_fx[0] = floatToFixed( hQMetaData->q_direction[0].band_data[j].energy_ratio[0], Q30 ); + hQMetaData->q_direction[1].band_data[dir2band].energy_ratio_fx[0] = floatToFixed( hQMetaData->q_direction[1].band_data[dir2band].energy_ratio[0], Q30 ); + /*=====================================flt-2-fix============================================*/ + + index_dirRatio1Inv = masa_sq_fx( L_sub( ONE_IN_Q30, hQMetaData->q_direction[0].band_data[j].energy_ratio_fx[0] ), diffuseness_thresholds_fx, DIRAC_DIFFUSE_LEVELS ); + index_dirRatio2Inv = masa_sq_fx( L_sub( ONE_IN_Q30, hQMetaData->q_direction[1].band_data[dir2band].energy_ratio_fx[0] ), diffuseness_thresholds_fx, DIRAC_DIFFUSE_LEVELS ); +#else index_dirRatio1Inv = masa_sq( 1.0f - hQMetaData->q_direction[0].band_data[j].energy_ratio[0], diffuseness_thresholds, DIRAC_DIFFUSE_LEVELS ); index_dirRatio2Inv = masa_sq( 1.0f - hQMetaData->q_direction[1].band_data[dir2band].energy_ratio[0], diffuseness_thresholds, DIRAC_DIFFUSE_LEVELS ); - +#endif for ( k = 0; k < hQMetaData->q_direction[0].cfg.nblocks; k++ ) { hQMetaData->q_direction[0].band_data[j].energy_ratio_index[k] = index_dirRatio1Inv; @@ -482,7 +492,11 @@ ivas_error ivas_qmetadata_enc_encode( } } +#ifdef IVAS_FLOAT_FIXED + only_reduce_bits_direction_fx( &extra_bits, q_direction, reduce_bits, nbands, nblocks, ind_order ); +#else only_reduce_bits_direction( &extra_bits, q_direction, reduce_bits, nbands, nblocks, ind_order ); +#endif bits_dir[d] = hMetaData->nb_bits_tot; requantize_direction_EC_3( &extra_bits, q_direction, nbands, hMetaData, elevation_orig, azimuth_orig, ind_order ); bits_dir[d] = hMetaData->nb_bits_tot - bits_dir[d]; @@ -519,58 +533,68 @@ ivas_error ivas_qmetadata_enc_encode( return error; } - - -/*-----------------------------------------------------------------------* - * ivas_qmetadata_enc_encode_hr_384_512() - * - * Main function for quantizing and coding Spatial Metadata at HRs - *-----------------------------------------------------------------------*/ - -ivas_error ivas_qmetadata_enc_encode_hr_384_512( - BSTR_ENC_HANDLE hMetaData, /* i/o: metadata bitstream handle */ - IVAS_QMETADATA *hQMetaData, /* i/o: metadata handle */ - const int16_t bits_sph_idx, - const int16_t bits_sp_coh ) +#else +ivas_error ivas_qmetadata_enc_encode( + BSTR_ENC_HANDLE hMetaData, /* i/o: metadata bitstream handle */ + IVAS_QMETADATA *hQMetaData, /* i/o: metadata handle */ + const int16_t hodirac_flag /* i : flag to indicate HO-DirAC mode */ +) { - int16_t i, j; - int16_t bits_diff[QMETADATA_MAX_NO_DIRECTIONS]; + int16_t i, bit_pos_start, bit_pos_start_coh; + int16_t next_ind_start; + uint16_t diffuseness_index_max_ec_frame; + uint16_t diffuseness_index_max_ec_frame_pre[QMETADATA_MAX_NO_DIRECTIONS]; + int16_t bits_dir_raw_pre[QMETADATA_MAX_NO_DIRECTIONS]; + int16_t bits_diff_sum; + int16_t bits_diff[QMETADATA_MAX_NO_DIRECTIONS], bits_coherence[QMETADATA_MAX_NO_DIRECTIONS]; + int16_t bits_dir[QMETADATA_MAX_NO_DIRECTIONS], bits_dir_raw; + int16_t extra_bits; IVAS_QDIRECTION *q_direction; int16_t nbands, nblocks, start_band; int16_t ndirections, d; - int16_t all_coherence_zero; - int16_t bits_ec; float azimuth_orig[MASA_MAXIMUM_CODING_SUBBANDS][MAX_PARAM_SPATIAL_SUBFRAMES], elevation_orig[MASA_MAXIMUM_CODING_SUBBANDS][MAX_PARAM_SPATIAL_SUBFRAMES]; + int16_t all_coherence_zero; + int16_t bit_pos_0, total_bits_1dir, bits_no_dirs_coh; + int16_t bits_signaling[QMETADATA_MAX_NO_DIRECTIONS]; + int16_t indice_coherence; + int16_t bits_dir_bands[MASA_MAXIMUM_CODING_SUBBANDS], raw_flag[MASA_MAXIMUM_CODING_SUBBANDS]; + int16_t diff_bits, bits_ec, next_ind_raw_flag; + int16_t dfRatio_bits[MASA_MAXIMUM_CODING_SUBBANDS]; + int16_t bits_surround_coh, no_TF; + int16_t dir2_bands[MASA_MAXIMUM_TWO_DIR_BANDS]; + int16_t ind_order[MASA_MAXIMUM_CODING_SUBBANDS]; + int16_t reduce_bits; ivas_error error; error = IVAS_ERR_OK; + /* Save initial position in bitstream */ + bit_pos_0 = hMetaData->nb_bits_tot; + bit_pos_start = bit_pos_0; + ndirections = hQMetaData->no_directions; + extra_bits = 0; /* Check if coherence should be encoded */ all_coherence_zero = 1; - if ( hQMetaData->q_direction->cfg.inactiveBands > 0 ) - { - push_next_indice( hMetaData, 1, 1 ); - /* write the number of inactive higher bands */ - ivas_qmetadata_encode_extended_gr( hMetaData, hQMetaData->q_direction->cfg.inactiveBands - 1, MASA_MAXIMUM_CODING_SUBBANDS, 1 ); - } - else - { - /* no change */ - push_next_indice( hMetaData, 0, 1 ); - } + bits_no_dirs_coh = 0; + if ( hQMetaData->coherence_flag ) { all_coherence_zero = hQMetaData->all_coherence_zero; + push_next_indice( hMetaData, all_coherence_zero, 1 ); /* signal coherence */ + bits_no_dirs_coh += 1; } - /* encode 2 direction subbands position */ - if ( ndirections == 2 && bits_sph_idx == 11 ) + if ( ndirections > 1 ) { - write_2dir_info( hMetaData, hQMetaData->twoDirBands, hQMetaData->q_direction[0].cfg.nbands, hQMetaData->numTwoDirBands ); + /* Reorder 2dir bands for more efficient encoding. */ + if ( !hodirac_flag ) + { + ivas_qmetadata_reorder_2dir_bands( hQMetaData ); + } d = 0; for ( i = hQMetaData->q_direction[1].cfg.start_band; i < hQMetaData->q_direction[1].cfg.nbands; i++ ) { @@ -580,6 +604,8 @@ ivas_error ivas_qmetadata_enc_encode_hr_384_512( mvr2r( hQMetaData->q_direction[1].band_data[i].elevation, hQMetaData->q_direction[1].band_data[d].elevation, hQMetaData->q_direction[1].cfg.nblocks ); mvr2r( hQMetaData->q_direction[1].band_data[i].energy_ratio, hQMetaData->q_direction[1].band_data[d].energy_ratio, hQMetaData->q_direction[1].cfg.nblocks ); + dir2_bands[d] = i; + if ( hQMetaData->coherence_flag ) { mvc2c( hQMetaData->q_direction[1].coherence_band_data[i].spread_coherence, hQMetaData->q_direction[1].coherence_band_data[d].spread_coherence, hQMetaData->q_direction[1].cfg.nblocks ); @@ -587,7 +613,10 @@ ivas_error ivas_qmetadata_enc_encode_hr_384_512( d++; } } - for ( i = hQMetaData->numTwoDirBands; i < hQMetaData->q_direction[0].cfg.nbands; i++ ) + + bits_no_dirs_coh += write_2dir_info( hMetaData, hQMetaData->twoDirBands, hQMetaData->q_direction[0].cfg.nbands, hQMetaData->numTwoDirBands ); + + for ( i = d; i < hQMetaData->q_direction[0].cfg.nbands; i++ ) { set_f( hQMetaData->q_direction[1].band_data[i].energy_ratio, 0.0f, hQMetaData->q_direction[1].cfg.nblocks ); } @@ -595,23 +624,90 @@ ivas_error ivas_qmetadata_enc_encode_hr_384_512( hQMetaData->q_direction[1].cfg.nbands = hQMetaData->numTwoDirBands; } - /*Quantization and encoding of the Diffuseness */ - ivas_qmetadata_quantize_diffuseness_nrg_ratios_hr_512( hQMetaData, bits_diff, bits_sph_idx, hMetaData ); + /*Quantization of the Diffuseness */ + ivas_qmetadata_quantize_diffuseness_nrg_ratios( hQMetaData, bits_dir_raw_pre, bits_diff, dfRatio_bits, hodirac_flag ); + + bits_diff_sum = 0; + bits_diff[0] = ivas_qmetadata_entropy_encode_diffuseness( hMetaData, &( hQMetaData->q_direction[0] ), &diffuseness_index_max_ec_frame_pre[0] ); + bits_diff_sum += bits_diff[0]; + + if ( ndirections == 2 ) + { + bits_diff[1] = ivas_qmetadata_entropy_encode_df_ratio( hMetaData, &( hQMetaData->q_direction[1] ), dfRatio_bits ); + bits_diff_sum += bits_diff[1]; + } + + /* 2dir energy ratio encoding reuses index memory. Now that diffRatio and dFRatio have been encoded, + * we retrieve index_dirRatio1Inv and index_dirRatio1Inv for further parameter encoding. This is + * necessary only for bands that have two concurrent directions. */ + if ( hQMetaData->no_directions == 2 ) + { + int16_t j, k, dir2band, index_dirRatio1Inv, index_dirRatio2Inv; + + dir2band = 0; + for ( j = hQMetaData->q_direction[0].cfg.start_band; j < hQMetaData->q_direction[0].cfg.nbands; ++j ) + { + if ( hQMetaData->twoDirBands[j] == 1 ) + { + index_dirRatio1Inv = masa_sq( 1.0f - hQMetaData->q_direction[0].band_data[j].energy_ratio[0], diffuseness_thresholds, DIRAC_DIFFUSE_LEVELS ); + index_dirRatio2Inv = masa_sq( 1.0f - hQMetaData->q_direction[1].band_data[dir2band].energy_ratio[0], diffuseness_thresholds, DIRAC_DIFFUSE_LEVELS ); + + for ( k = 0; k < hQMetaData->q_direction[0].cfg.nblocks; k++ ) + { + hQMetaData->q_direction[0].band_data[j].energy_ratio_index[k] = index_dirRatio1Inv; + } + + for ( k = 0; k < hQMetaData->q_direction[1].cfg.nblocks; k++ ) + { + hQMetaData->q_direction[1].band_data[dir2band].energy_ratio_index[k] = index_dirRatio2Inv; + } + + dir2band++; + } + } + } /* Encode surround coherence */ - if ( all_coherence_zero == 0 ) + if ( ndirections == 2 ) { - encode_surround_coherence_hr( hQMetaData, hMetaData ); + no_TF = hQMetaData->q_direction[0].cfg.nbands * hQMetaData->q_direction[0].cfg.nblocks + hQMetaData->q_direction[1].cfg.nbands * hQMetaData->q_direction[1].cfg.nblocks; + if ( ( all_coherence_zero == 0 ) && ( hQMetaData->metadata_max_bits - bits_no_dirs_coh - 4.3f * no_TF - sum_s( bits_diff, ndirections ) >= MASA_MIN_BITS_SURR_COH ) ) + { + bits_surround_coh = encode_surround_coherence( hQMetaData, hMetaData ); + } + else + { + bits_surround_coh = 0; + for ( i = 0; i < hQMetaData->q_direction[0].cfg.nbands; i++ ) + { + if ( hQMetaData->surcoh_band_data != NULL ) + { + set_c( (int8_t *) hQMetaData->surcoh_band_data[i].surround_coherence, 0, hQMetaData->q_direction[0].cfg.nblocks ); + } + } + } + bits_no_dirs_coh += bits_surround_coh; + total_bits_1dir = ( ( hQMetaData->metadata_max_bits - bits_no_dirs_coh ) * hQMetaData->q_direction[0].cfg.nbands * hQMetaData->q_direction[0].cfg.nblocks ) / no_TF; } else { - for ( i = 0; i < hQMetaData->q_direction[0].cfg.nbands; i++ ) + no_TF = hQMetaData->q_direction[0].cfg.nbands * hQMetaData->q_direction[0].cfg.nblocks; + if ( ( all_coherence_zero == 0 ) && ( hQMetaData->metadata_max_bits - bits_no_dirs_coh - 4.3f * no_TF - bits_diff[0] >= MASA_MIN_BITS_SURR_COH ) ) { - if ( hQMetaData->surcoh_band_data != NULL ) + bits_surround_coh = encode_surround_coherence( hQMetaData, hMetaData ); + } + else + { + bits_surround_coh = 0; + for ( i = 0; i < hQMetaData->q_direction[0].cfg.nbands; i++ ) { - set_c( (int8_t *) hQMetaData->surcoh_band_data[i].surround_coherence, 0, hQMetaData->q_direction[0].cfg.nblocks ); + if ( hQMetaData->surcoh_band_data != NULL ) + { + set_c( (int8_t *) hQMetaData->surcoh_band_data[i].surround_coherence, 0, hQMetaData->q_direction[0].cfg.nblocks ); + } } } + total_bits_1dir = hQMetaData->metadata_max_bits - bits_no_dirs_coh - bits_surround_coh; } /* Loop over number of directions*/ @@ -619,1316 +715,2779 @@ ivas_error ivas_qmetadata_enc_encode_hr_384_512( { q_direction = &( hQMetaData->q_direction[d] ); + if ( d == 1 ) + { + transform_azimuth_dir2( hQMetaData, dir2_bands ); + } + nbands = q_direction->cfg.nbands; nblocks = q_direction->cfg.nblocks; start_band = q_direction->cfg.start_band; + diffuseness_index_max_ec_frame = diffuseness_index_max_ec_frame_pre[0]; + bits_dir_raw = bits_dir_raw_pre[d]; - - q_direction->not_in_2D = 0; - - /*Coherence */ - if ( all_coherence_zero == 0 ) + /* This sets bit budget correctly for the second direction */ + if ( d == 0 ) { - ivas_qmetadata_quantize_coherence_hr_512( hQMetaData, d, all_coherence_zero, hMetaData, bits_sp_coh ); + bits_diff[d] = bits_diff_sum; } - - /* write the spherical indexes */ - bits_ec = hMetaData->nb_bits_tot; - if ( bits_sph_idx == 11 ) + else { - /* do the quantization */ - quantize_direction_frame( q_direction, azimuth_orig, elevation_orig, 1 ); + bits_diff[d] = 0; } - for ( i = start_band; i < nbands; i++ ) + + bits_signaling[d] = 0; + + /*Coherence */ + bits_coherence[d] = 0; + bit_pos_start_coh = hMetaData->nb_bits_tot; + + if ( all_coherence_zero == 0 ) { - for ( j = 0; j < nblocks; j++ ) - { - push_next_indice( hMetaData, q_direction->band_data[i].spherical_index[j], bits_sph_idx ); - } + bits_coherence[d] = ivas_qmetadata_quantize_coherence( hQMetaData, d, all_coherence_zero, hMetaData, 0, &indice_coherence, 0 ); } - bits_ec = hMetaData->nb_bits_tot - bits_ec; - - /* Save quantized DOAs */ - if ( bits_sph_idx == 11 ) + if ( q_direction->cfg.mc_ls_setup == MC_LS_SETUP_5_1 || q_direction->cfg.mc_ls_setup == MC_LS_SETUP_7_1 ) { - for ( i = start_band; i < nbands; i++ ) - { - mvr2r( azimuth_orig[i], q_direction->band_data[i].azimuth, nblocks ); - mvr2r( elevation_orig[i], q_direction->band_data[i].elevation, nblocks ); - } + q_direction->not_in_2D = 0; + /* Quantize directions*/ + quantize_direction_frame2D( q_direction, azimuth_orig, elevation_orig ); } else { - for ( i = start_band; i < nbands; i++ ) - { - mvr2r( q_direction->band_data[i].azimuth, q_direction->band_data[i].q_azimuth, nblocks ); - mvr2r( q_direction->band_data[i].elevation, q_direction->band_data[i].q_elevation, nblocks ); - } + /* Quantize directions*/ + quantize_direction_frame( q_direction, azimuth_orig, elevation_orig, 0 ); } - } - if ( hQMetaData->q_direction->cfg.inactiveBands > 0 ) - { - hQMetaData->q_direction[0].cfg.nbands += hQMetaData->q_direction->cfg.inactiveBands; - if ( ndirections > 1 ) + /* Signalling 2D*/ + push_next_indice( hMetaData, ( q_direction->not_in_2D > 0 ), 1 ); /*2D flag*/ + bits_signaling[d] = 1; + + /* Save state of metadata bitstream buffer after writing energy ratios, number of dirs and save space for coherence*/ + bit_pos_start = hMetaData->nb_bits_tot; + next_ind_start = hMetaData->nb_ind_tot; + + /* Encode quantized directions with EC frame-wise*/ + if ( total_bits_1dir + bits_surround_coh <= hQMetaData->qmetadata_max_bit_req ) { - hQMetaData->q_direction[1].cfg.nbands += hQMetaData->q_direction->cfg.inactiveBands; + push_next_indice( hMetaData, 0, 1 ); /*Write 1 bit to signal EC frame-wise (EC1)*/ + bits_signaling[d]++; } - } - return error; -} + next_ind_raw_flag = hMetaData->nb_ind_tot; + push_next_indice( hMetaData, 0, 1 ); /* Raw coding flag*/ + bits_dir_bands[0] = ivas_qmetadata_raw_encode_dir( NULL, q_direction, q_direction->cfg.nbands, q_direction->cfg.start_band ); -/*-----------------------------------------------------------------------* - * ivas_qmetadata_enc_sid_encode() - * - * Main function for coding SID for Spatial Metadata - *-----------------------------------------------------------------------*/ - -/*! r: number of bits written */ -void ivas_qmetadata_enc_sid_encode( - BSTR_ENC_HANDLE hMetaData, /* i/o: metadata bitstream handle */ - IVAS_QMETADATA *q_metadata, /* i/o: metadata handle */ - const int16_t masa_sid_descriptor, /* i : description of MASA SID coding structure */ - const int16_t ivas_format /* i : IVAS format */ -) -{ - int16_t b, m; - int16_t bit_pos_start; - IVAS_QDIRECTION *q_direction; - int16_t nbands, nblocks, start_band; - float avg_direction_vector[3]; - float direction_vector[3]; - float avg_azimuth[MASA_MAXIMUM_CODING_SUBBANDS]; - float avg_elevation[MASA_MAXIMUM_CODING_SUBBANDS]; - int16_t bits_dir, bits_diff, bits_delta; - int16_t metadata_sid_bits; /* bits allocated to SID for metadata */ - - if ( ivas_format == SBA_FORMAT ) - { - metadata_sid_bits = (int16_t) ( IVAS_SID_5k2 - SID_2k40 ) / FRAMES_PER_SEC - ( SPAR_DTX_BANDS * SPAR_SID_BITS_TAR_PER_BAND ) - 2 - SID_FORMAT_NBITS; /* -1 for inactive mode header bit*/ - } - else - { - metadata_sid_bits = ( IVAS_SID_5k2 - SID_2k40 ) / FRAMES_PER_SEC - SID_FORMAT_NBITS; - } - - - /* Save initial position in bitstream */ - bit_pos_start = hMetaData->nb_bits_tot; - - /* write for MASA the number of transport channels used at coding and the CPE mode DFT/MDCT */ - if ( masa_sid_descriptor > -1 ) - { - push_next_indice( hMetaData, masa_sid_descriptor, 1 ); - } - - /* Code for one direction: diffuseness and average DOA(s)*/ - q_direction = &( q_metadata->q_direction[0] ); - nbands = q_direction->cfg.nbands; - nblocks = q_direction->cfg.nblocks; - start_band = 0; /*Start always with band 0 for SID*/ - - /* sanity checks*/ - assert( q_metadata->no_directions == 1 && "Qmetadata SID: only one direction supported!" ); - if ( ivas_format == SBA_FORMAT ) - { - assert( ( q_direction->cfg.nbands == DIRAC_DTX_BANDS ) && "Qmetadata SID: only 2 bands supported!" ); - } - else - { - assert( ( q_direction->cfg.nbands == 5 ) && "Qmetadata SID: only 5 bands supported!" ); - } + reduce_bits = hQMetaData->is_masa_ivas_format ? ( total_bits_1dir - ( bits_diff[d] + bits_coherence[d] + bits_signaling[d] ) - 1 ) : MASA_MAX_BITS; + bits_ec = ivas_qmetadata_entropy_encode_dir( hMetaData, q_direction, diffuseness_index_max_ec_frame, q_direction->cfg.nbands, q_direction->cfg.start_band, bits_dir_bands[0], reduce_bits, 0 ); - if ( ivas_format != SBA_FORMAT ) - { - /* Signalling 2D*/ - push_next_indice( hMetaData, ( q_direction->not_in_2D > 0 ), 1 ); /*2D flag*/ - } - else - { - q_direction->not_in_2D = 1; /* force for merged modes */ - } + if ( bits_ec < 0 ) + { + hMetaData->ind_list[next_ind_raw_flag].value = 1; /*rewrite flag*/ + bits_ec = ivas_qmetadata_raw_encode_dir( hMetaData, q_direction, q_direction->cfg.nbands, q_direction->cfg.start_band ); + } + bits_dir[d] = bits_ec + 1; + extra_bits = hQMetaData->metadata_max_bits - ( hMetaData->nb_bits_tot - bit_pos_0 ); - /*Encode the quantized diffuseness in raw coding*/ - bits_dir = 0; - bits_diff = 0; - if ( ivas_format != SBA_FORMAT ) - { - for ( b = start_band; b < nbands; b++ ) + /* Encode quantized directions with EC band-wise */ + if ( ( total_bits_1dir + bits_surround_coh <= hQMetaData->qmetadata_max_bit_req ) && ( bits_dir[d] + bits_diff[d] + bits_coherence[d] + bits_signaling[d] > total_bits_1dir ) && q_direction->cfg.nblocks > 1 ) { - q_direction->band_data[b].energy_ratio_index[0] = max( q_direction->band_data[b].energy_ratio_index[0], 4 ); - bits_diff += ivas_qmetadata_encode_quasi_uniform_length( q_direction->band_data[b].energy_ratio_index[0] - 4, DIRAC_DIFFUSE_LEVELS - 4 ); - q_direction->band_data[b].bits_sph_idx[0] = bits_direction_masa[q_direction->band_data[b].energy_ratio_index[0]]; + restore_metadata_buffer( hMetaData, next_ind_start, bit_pos_start ); - if ( q_direction->not_in_2D == 0 ) - { - q_direction->band_data[b].azimuth_m_alphabet[0] = 1 << ( min( 8, q_direction->band_data[b].bits_sph_idx[0] ) ); - bits_dir += ivas_qmetadata_encode_quasi_uniform_length( q_direction->band_data[b].azimuth_m_alphabet[0] - 1, q_direction->band_data[b].azimuth_m_alphabet[0] ); - } - else + /* Write signaling */ + push_next_indice( hMetaData, 1, 1 ); /*Write 1 bit to signal no EC frame-wise (EC1)*/ + push_next_indice( hMetaData, 0, 1 ); /*Write 1 bit to signal EC band-wise (EC2)*/ + bits_signaling[d] = 3; + + /* Write raw flags */ + next_ind_raw_flag = hMetaData->nb_ind_tot; + for ( i = start_band; i < nbands; i++ ) { - bits_dir += q_direction->band_data[b].bits_sph_idx[0]; + push_next_indice( hMetaData, 0, 1 ); /* Raw coding flag*/ } - } - /* Reduce bit demand by increasing diffuseness*/ - bits_delta = metadata_sid_bits - ( hMetaData->nb_bits_tot - bit_pos_start ) - bits_diff - bits_dir; - if ( bits_delta > 0 ) - { - while ( bits_delta > 0 ) + bits_dir[d] = 0; + diff_bits = bits_diff[d] + bits_coherence[d] + bits_signaling[d] - total_bits_1dir; + for ( i = start_band; i < nbands; i++ ) { - for ( b = start_band; b < nbands && ( bits_delta > 0 ); b++ ) + bits_dir_bands[i] = ivas_qmetadata_raw_encode_dir( NULL, q_direction, i + 1, i ); + + /* Write ec bits */ + bits_ec = ivas_qmetadata_entropy_encode_dir( hMetaData, q_direction, diffuseness_index_max_ec_frame, i + 1, i, bits_dir_bands[i], MASA_MAX_BITS, 0 ); + + if ( bits_ec >= 0 ) { - if ( q_direction->band_data[b].bits_sph_idx[0] < 11 ) - { - bits_delta -= 1; - q_direction->band_data[b].bits_sph_idx[0]++; - } + bits_dir_bands[i] = bits_ec; + raw_flag[i] = 0; } - } - - if ( q_direction->not_in_2D == 0 ) - { - for ( b = start_band; b < nbands; b++ ) + else { - q_direction->band_data[b].azimuth_m_alphabet[0] = 1 << ( min( 8, q_direction->band_data[b].bits_sph_idx[0] ) ); + raw_flag[i] = 1; } + diff_bits += bits_dir_bands[i] + 1; } - } - else - { - while ( bits_delta < 0 ) + + small_requantize_direction_frame( q_direction, azimuth_orig, elevation_orig, raw_flag, bits_dir_bands, &diff_bits ); + + for ( i = start_band; i < nbands; i++ ) { - for ( b = nbands - 1; b >= start_band && ( bits_delta < 0 ); b-- ) + if ( raw_flag[i] ) { - if ( q_direction->band_data[b].bits_sph_idx[0] >= 4 ) - { - bits_delta += 1; - q_direction->band_data[b].bits_sph_idx[0]--; - if ( q_direction->not_in_2D == 0 ) - { - q_direction->band_data[b].azimuth_m_alphabet[0] = 1 << ( min( 8, q_direction->band_data[b].bits_sph_idx[0] ) ); - } - } + /* Rewrite raw flag value */ + hMetaData->ind_list[next_ind_raw_flag + i - start_band].value = 1; + + /* Write ec bits */ + bits_ec = ivas_qmetadata_raw_encode_dir( hMetaData, q_direction, i + 1, i ); } + bits_dir[d] += bits_dir_bands[i] + 1; } + + extra_bits = hQMetaData->metadata_max_bits - ( hMetaData->nb_bits_tot - bit_pos_0 ); } - } - else - { - for ( b = start_band; b < nbands; b++ ) + + /* Requantized directions */ + if ( ( total_bits_1dir + bits_surround_coh <= hQMetaData->qmetadata_max_bit_req ) && ( bits_dir[d] + bits_diff[d] + bits_coherence[d] + bits_signaling[d] > total_bits_1dir ) ) { - q_direction->band_data[b].energy_ratio_index[0] = max( q_direction->band_data[b].energy_ratio_index[0], 4 ); - bits_diff += ivas_qmetadata_encode_quasi_uniform_length( q_direction->band_data[b].energy_ratio_index[0] - 4, DIRAC_DIFFUSE_LEVELS - 4 ); - q_direction->band_data[b].bits_sph_idx[0] = bits_direction_masa[q_direction->band_data[b].energy_ratio_index[0]]; - if ( q_direction->not_in_2D == 0 ) + /*Bit budget exceeded, bit reduction strategy?*/ + extra_bits = 0; + + restore_metadata_buffer( hMetaData, next_ind_start, bit_pos_start ); + + push_next_indice( hMetaData, 1, 1 ); /*Write 1 bit to signal no EC frame-wise (EC1)*/ + if ( nblocks > 1 ) { - q_direction->band_data[b].azimuth_m_alphabet[0] = 1 << ( min( 5, q_direction->band_data[b].bits_sph_idx[0] ) ); - bits_dir += ivas_qmetadata_encode_quasi_uniform_length( q_direction->band_data[b].azimuth_m_alphabet[0] - 1, q_direction->band_data[b].azimuth_m_alphabet[0] ); + push_next_indice( hMetaData, 1, 1 ); /*Write 1 bit to signal requantization stage (EC3)*/ + bits_signaling[d] = 3; } else { - bits_dir += q_direction->band_data[b].bits_sph_idx[0]; + bits_signaling[d] = 2; } - } - - /* Reduce bit demand by increasing diffuseness*/ - bits_delta = metadata_sid_bits - ( hMetaData->nb_bits_tot - bit_pos_start ) - bits_diff - bits_dir; - while ( bits_delta < 0 && ( q_direction->not_in_2D > 0 ) ) - { - for ( b = nbands - 1; b >= start_band && ( bits_delta < 0 ); b-- ) + if ( hQMetaData->is_masa_ivas_format == 0 ) { - if ( q_direction->band_data[b].energy_ratio_index[0] < ( DIRAC_DIFFUSE_LEVELS - 1 ) ) + reduce_bits = bits_dir_raw - ( total_bits_1dir - bits_diff[d] - bits_coherence[d] - bits_signaling[d] ); + ind_order[0] = -1; + } + else + { + ind_order[0] = 0; + reduce_bits = min( nbands * nblocks + MASA_BIT_REDUCT_PARAM, bits_dir_raw - ( total_bits_1dir - bits_diff[d] - bits_coherence[d] - bits_signaling[d] ) ); + + if ( reduce_bits > bits_dir_raw - nbands * nblocks ) { - bits_delta += q_direction->band_data[b].bits_sph_idx[0]; - q_direction->band_data[b].energy_ratio_index[0]++; - q_direction->band_data[b].bits_sph_idx[0] = bits_direction_masa[q_direction->band_data[b].energy_ratio_index[0]]; - bits_delta -= q_direction->band_data[b].bits_sph_idx[0]; + reduce_bits = bits_dir_raw - nbands * nblocks; } } - } - } - assert( ( bits_delta >= 0 ) && "Bit budget in Qmetadata SID is violated!!!" ); - - /*Code diffuseness*/ - for ( b = start_band; b < nbands; b++ ) - { - ivas_qmetadata_encode_quasi_uniform( hMetaData, q_direction->band_data[b].energy_ratio_index[0] - 4, DIRAC_DIFFUSE_LEVELS - 4 ); - } - /* Compute and Quantize an average direction per band*/ - for ( b = start_band; b < nbands; b++ ) - { - set_zero( avg_direction_vector, 3 ); - for ( m = 0; m < nblocks; m++ ) - { - /*compute the average direction */ - ivas_qmetadata_azimuth_elevation_to_direction_vector( q_direction->band_data[b].azimuth[m], q_direction->band_data[b].elevation[m], direction_vector ); - v_add( avg_direction_vector, direction_vector, avg_direction_vector, 3 ); + only_reduce_bits_direction( &extra_bits, q_direction, reduce_bits, nbands, nblocks, ind_order ); + bits_dir[d] = hMetaData->nb_bits_tot; + requantize_direction_EC_3( &extra_bits, q_direction, nbands, hMetaData, elevation_orig, azimuth_orig, ind_order ); + bits_dir[d] = hMetaData->nb_bits_tot - bits_dir[d]; } - ivas_qmetadata_direction_vector_to_azimuth_elevation( avg_direction_vector, &avg_azimuth[b], &avg_elevation[b] ); - - /* Quantize the average direction */ - if ( q_direction->not_in_2D == 0 ) + /* finalize writing coherence */ + if ( ( bits_coherence[d] > 0 ) && ( all_coherence_zero == 0 ) && ( nblocks > 1 ) ) { - avg_elevation[b] = 0; - q_direction->band_data[b].spherical_index[0] = quantize_direction2D( avg_azimuth[b], q_direction->band_data[b].azimuth_m_alphabet[0], &avg_azimuth[b], - &q_direction->band_data[b].azimuth_index[0], q_direction->cfg.mc_ls_setup ); + bit_pos_start = hMetaData->nb_bits_tot; + hMetaData->nb_bits_tot = bit_pos_start_coh; + ivas_qmetadata_quantize_coherence( hQMetaData, d, all_coherence_zero, hMetaData, 1, &indice_coherence, 0 ); + hMetaData->nb_bits_tot = bit_pos_start; } - else + + if ( d == 0 ) { - q_direction->band_data[b].spherical_index[0] = quantize_direction( avg_elevation[b], avg_azimuth[b], q_direction->band_data[b].bits_sph_idx[0], &avg_elevation[b], &avg_azimuth[b], - &q_direction->band_data[b].elevation_index[0], &q_direction->band_data[b].azimuth_index[0], q_direction->cfg.mc_ls_setup ); + total_bits_1dir = hQMetaData->metadata_max_bits - ( hMetaData->nb_bits_tot - bit_pos_0 ); } /* Save quantized DOAs */ - q_direction->band_data[b].q_azimuth[0] = avg_azimuth[b]; - q_direction->band_data[b].q_elevation[0] = avg_elevation[b]; - - if ( q_direction->band_data[b].azimuth_index[0] == MASA_NO_INDEX ) + for ( i = start_band; i < nbands; i++ ) { - q_direction->band_data[b].azimuth_index[0] = 0; + mvr2r( q_direction->band_data[i].azimuth, q_direction->band_data[i].q_azimuth, nblocks ); + mvr2r( q_direction->band_data[i].elevation, q_direction->band_data[i].q_elevation, nblocks ); } - } - /* quantize average elevation and azimuth angles */ - if ( q_direction->not_in_2D > 0 ) - { - for ( b = start_band; b < nbands; b++ ) - { - push_next_indice( hMetaData, q_direction->band_data[b].spherical_index[0], q_direction->band_data[b].bits_sph_idx[0] ); - } - } - else - { - for ( b = start_band; b < nbands; b++ ) + /* Copy original DOAs back to q_direction*/ + for ( i = start_band; i < nbands; i++ ) { - ivas_qmetadata_encode_quasi_uniform( hMetaData, q_direction->band_data[b].azimuth_index[0], q_direction->band_data[b].azimuth_m_alphabet[0] ); + mvr2r( azimuth_orig[i], q_direction->band_data[i].azimuth, nblocks ); + mvr2r( elevation_orig[i], q_direction->band_data[i].elevation, nblocks ); } } - - /* fill bits*/ - assert( ( hMetaData->nb_bits_tot - bit_pos_start ) <= metadata_sid_bits && "Too many written bits!" ); - while ( ( hMetaData->nb_bits_tot - bit_pos_start ) < metadata_sid_bits ) - { - push_next_indice( hMetaData, 0, 1 ); /*fill bit*/ - } - - return; + return error; } +#endif -/*------------------------------------------------------------------------- - * reset_metadata_spatial() +/*-----------------------------------------------------------------------* + * ivas_qmetadata_enc_encode_hr_384_512() * - * Reset metadata in spatial formats - *------------------------------------------------------------------------*/ + * Main function for quantizing and coding Spatial Metadata at HRs + *-----------------------------------------------------------------------*/ -void reset_metadata_spatial( - const IVAS_FORMAT ivas_format, /* i : IVAS format */ - BSTR_ENC_HANDLE hMetaData, /* i/o: metadata bitstream handle */ - const int32_t element_brate, /* i : element bitrate */ - int32_t *total_brate, /* o : total bitrate */ - const int32_t core_brate, /* i : core bitrate */ - const int16_t nb_bits_metadata /* i : number of meatdata bits */ -) +ivas_error ivas_qmetadata_enc_encode_hr_384_512( + BSTR_ENC_HANDLE hMetaData, /* i/o: metadata bitstream handle */ + IVAS_QMETADATA *hQMetaData, /* i/o: metadata handle */ + const int16_t bits_sph_idx, + const int16_t bits_sp_coh ) { - int16_t i, next_ind_sid, last_ind_sid; - int16_t j; - int16_t metadata_sid_bits; + int16_t i, j; + int16_t bits_diff[QMETADATA_MAX_NO_DIRECTIONS]; + IVAS_QDIRECTION *q_direction; + int16_t nbands, nblocks, start_band; + int16_t ndirections, d; + int16_t all_coherence_zero; + int16_t bits_ec; + float azimuth_orig[MASA_MAXIMUM_CODING_SUBBANDS][MAX_PARAM_SPATIAL_SUBFRAMES], elevation_orig[MASA_MAXIMUM_CODING_SUBBANDS][MAX_PARAM_SPATIAL_SUBFRAMES]; + ivas_error error; - if ( core_brate == SID_2k40 || core_brate == FRAME_NO_DATA ) - { - if ( ( ivas_format == SBA_FORMAT || ivas_format == MASA_FORMAT ) && core_brate != FRAME_NO_DATA ) - { - if ( ivas_format == SBA_FORMAT ) - { - hMetaData->ind_list[0].value = 1; - metadata_sid_bits = (int16_t) ( IVAS_SID_5k2 - SID_2k40 ) / FRAMES_PER_SEC - SID_FORMAT_NBITS; + error = IVAS_ERR_OK; - while ( hMetaData->nb_bits_tot < metadata_sid_bits ) - { - push_next_indice( hMetaData, 0, 1 ); /*fill bit*/ - } - } - else - { - /* Reset metadata and keep only SID metadata*/ - last_ind_sid = hMetaData->nb_ind_tot; - next_ind_sid = hMetaData->nb_ind_tot; - while ( hMetaData->nb_bits_tot > nb_bits_metadata ) - { - next_ind_sid--; - hMetaData->nb_bits_tot -= hMetaData->ind_list[next_ind_sid].nb_bits; - } - hMetaData->nb_bits_tot = 0; + ndirections = hQMetaData->no_directions; - for ( i = 0; i < next_ind_sid; i++ ) - { - hMetaData->ind_list[i].nb_bits = -1; - } + /* Check if coherence should be encoded */ + all_coherence_zero = 1; + if ( hQMetaData->q_direction->cfg.inactiveBands > 0 ) + { + push_next_indice( hMetaData, 1, 1 ); + /* write the number of inactive higher bands */ + ivas_qmetadata_encode_extended_gr( hMetaData, hQMetaData->q_direction->cfg.inactiveBands - 1, MASA_MAXIMUM_CODING_SUBBANDS, 1 ); + } + else + { + /* no change */ + push_next_indice( hMetaData, 0, 1 ); + } + if ( hQMetaData->coherence_flag ) + { + all_coherence_zero = hQMetaData->all_coherence_zero; + push_next_indice( hMetaData, all_coherence_zero, 1 ); /* signal coherence */ + } - for ( j = 0, i = next_ind_sid; i < last_ind_sid; i++, j++ ) + /* encode 2 direction subbands position */ + if ( ndirections == 2 && bits_sph_idx == 11 ) + { + write_2dir_info( hMetaData, hQMetaData->twoDirBands, hQMetaData->q_direction[0].cfg.nbands, hQMetaData->numTwoDirBands ); + d = 0; + for ( i = hQMetaData->q_direction[1].cfg.start_band; i < hQMetaData->q_direction[1].cfg.nbands; i++ ) + { + if ( hQMetaData->twoDirBands[i] == 1 ) + { + mvr2r( hQMetaData->q_direction[1].band_data[i].azimuth, hQMetaData->q_direction[1].band_data[d].azimuth, hQMetaData->q_direction[1].cfg.nblocks ); + mvr2r( hQMetaData->q_direction[1].band_data[i].elevation, hQMetaData->q_direction[1].band_data[d].elevation, hQMetaData->q_direction[1].cfg.nblocks ); + mvr2r( hQMetaData->q_direction[1].band_data[i].energy_ratio, hQMetaData->q_direction[1].band_data[d].energy_ratio, hQMetaData->q_direction[1].cfg.nblocks ); + + if ( hQMetaData->coherence_flag ) { - hMetaData->ind_list[j].value = hMetaData->ind_list[i].value; - hMetaData->ind_list[j].nb_bits = hMetaData->ind_list[i].nb_bits; - hMetaData->nb_bits_tot += hMetaData->ind_list[j].nb_bits; - hMetaData->ind_list[i].nb_bits = -1; + mvc2c( hQMetaData->q_direction[1].coherence_band_data[i].spread_coherence, hQMetaData->q_direction[1].coherence_band_data[d].spread_coherence, hQMetaData->q_direction[1].cfg.nblocks ); } - - hMetaData->nb_ind_tot = j; + d++; } } - else + for ( i = hQMetaData->numTwoDirBands; i < hQMetaData->q_direction[0].cfg.nbands; i++ ) { - /*Reset metadata*/ - reset_indices_enc( hMetaData, hMetaData->nb_ind_tot ); + set_f( hQMetaData->q_direction[1].band_data[i].energy_ratio, 0.0f, hQMetaData->q_direction[1].cfg.nblocks ); } - *total_brate = element_brate; - } - else if ( ivas_format != SBA_FORMAT ) - { - /* Reset SID metadata bits*/ - while ( hMetaData->nb_bits_tot > nb_bits_metadata ) - { - hMetaData->nb_ind_tot--; - hMetaData->nb_bits_tot -= hMetaData->ind_list[hMetaData->nb_ind_tot].nb_bits; - hMetaData->ind_list[hMetaData->nb_ind_tot].nb_bits = -1; - } + hQMetaData->q_direction[1].cfg.nbands = hQMetaData->numTwoDirBands; } - return; -} - - -/*------------------------------------------------------------------------- - * quantize_direction2D() - * - * - *------------------------------------------------------------------------*/ - -/*! r: quantized spherical index */ -int16_t quantize_direction2D( - float phi, /* i : input azimuth value */ - const int16_t no_cw, /* i : number of bits */ - float *phi_q, /* o : quantized azimuth value */ - uint16_t *index_phi, /* o : quantized azimuth index */ - const MC_LS_SETUP mc_format /* i : channel format if in MC-mode */ -) -{ - int16_t idx_sph; - uint16_t id_phi; - if ( no_cw < 2 ) - { - *phi_q = 0; - - return 0; - } + /*Quantization and encoding of the Diffuseness */ + ivas_qmetadata_quantize_diffuseness_nrg_ratios_hr_512( hQMetaData, bits_diff, bits_sph_idx, hMetaData ); - if ( mc_format != MC_LS_SETUP_INVALID ) + /* Encode surround coherence */ + if ( all_coherence_zero == 0 ) { - id_phi = quantize_phi_chan_compand( phi + 180, phi_q, no_cw, 0, mc_format ); + encode_surround_coherence_hr( hQMetaData, hMetaData ); } else { - id_phi = quantize_phi( phi + 180, 0, phi_q, no_cw ); + for ( i = 0; i < hQMetaData->q_direction[0].cfg.nbands; i++ ) + { + if ( hQMetaData->surcoh_band_data != NULL ) + { + set_c( (int8_t *) hQMetaData->surcoh_band_data[i].surround_coherence, 0, hQMetaData->q_direction[0].cfg.nblocks ); + } + } } - *phi_q -= 180; - *index_phi = ivas_qmetadata_reorder_generic( id_phi - ( no_cw >> 1 ) ); - idx_sph = id_phi; + /* Loop over number of directions*/ + for ( d = 0; d < ndirections; d++ ) + { + q_direction = &( hQMetaData->q_direction[d] ); - return idx_sph; -} + nbands = q_direction->cfg.nbands; + nblocks = q_direction->cfg.nblocks; + start_band = q_direction->cfg.start_band; -static void ivas_qmetadata_quantize_diffuseness_nrg_ratios_hr_512( - IVAS_QMETADATA_HANDLE hQMetaData, - int16_t *needed_bits, - const int16_t bits_dir_hr, - BSTR_ENC_HANDLE hMetaData ) -{ - int16_t j, k; - int16_t index; + q_direction->not_in_2D = 0; - needed_bits[0] = 0; - needed_bits[1] = 0; + /*Coherence */ + if ( all_coherence_zero == 0 ) + { + ivas_qmetadata_quantize_coherence_hr_512( hQMetaData, d, all_coherence_zero, hMetaData, bits_sp_coh ); + } - for ( j = hQMetaData->q_direction[0].cfg.start_band; j < hQMetaData->q_direction[0].cfg.nbands; ++j ) - { - for ( k = 0; k < hQMetaData->q_direction[0].cfg.nblocks; k++ ) + /* write the spherical indexes */ + bits_ec = hMetaData->nb_bits_tot; + if ( bits_sph_idx == 11 ) { - index = masa_sq( 1.0f - hQMetaData->q_direction[0].band_data[j].energy_ratio[k], diffuseness_thresholds_hr, HR_MASA_ER_LEVELS ); - push_next_indice( hMetaData, index, MASA_BITS_ER_HR ); - hQMetaData->q_direction[0].band_data[j].energy_ratio_index[k] = index; - hQMetaData->q_direction[0].band_data[j].energy_ratio_index_mod[k] = index; - hQMetaData->q_direction[0].band_data[j].energy_ratio[k] = 1.0f - diffuseness_reconstructions_hr[index]; - needed_bits[0] += MASA_BITS_ER_HR; - hQMetaData->q_direction[0].band_data[j].bits_sph_idx[k] = bits_dir_hr; + /* do the quantization */ + quantize_direction_frame( q_direction, azimuth_orig, elevation_orig, 1 ); } - } - if ( hQMetaData->no_directions == 2 ) - { - float ratioSum; - if ( bits_dir_hr == 16 ) + for ( i = start_band; i < nbands; i++ ) { - for ( j = hQMetaData->q_direction[1].cfg.start_band; j < hQMetaData->q_direction[1].cfg.nbands; j++ ) + for ( j = 0; j < nblocks; j++ ) { - for ( k = 0; k < hQMetaData->q_direction[1].cfg.nblocks; k++ ) - { - index = masa_sq( 1.0f - hQMetaData->q_direction[1].band_data[j].energy_ratio[k], diffuseness_thresholds_hr, HR_MASA_ER_LEVELS ); - push_next_indice( hMetaData, index, MASA_BITS_ER_HR ); - hQMetaData->q_direction[1].band_data[j].energy_ratio_index[k] = index; - hQMetaData->q_direction[1].band_data[j].energy_ratio[k] = 1.0f - diffuseness_reconstructions_hr[index]; + push_next_indice( hMetaData, q_direction->band_data[i].spherical_index[j], bits_sph_idx ); + } + } + bits_ec = hMetaData->nb_bits_tot - bits_ec; - ratioSum = hQMetaData->q_direction[0].band_data[j].energy_ratio[k] + hQMetaData->q_direction[1].band_data[j].energy_ratio[k]; - if ( ratioSum > 1.0f ) - { - hQMetaData->q_direction[0].band_data[j].energy_ratio[k] /= ratioSum; - hQMetaData->q_direction[1].band_data[j].energy_ratio[k] /= ratioSum; - } - needed_bits[1] += MASA_BITS_ER_HR; - hQMetaData->q_direction[1].band_data[j].bits_sph_idx[k] = bits_dir_hr; - } + /* Save quantized DOAs */ + if ( bits_sph_idx == 11 ) + { + for ( i = start_band; i < nbands; i++ ) + { + mvr2r( azimuth_orig[i], q_direction->band_data[i].azimuth, nblocks ); + mvr2r( elevation_orig[i], q_direction->band_data[i].elevation, nblocks ); } } else { - int16_t pos_2dir_band[MASA_MAXIMUM_CODING_SUBBANDS]; - k = 0; - for ( j = hQMetaData->q_direction[0].cfg.start_band; j < hQMetaData->q_direction[0].cfg.nbands; j++ ) + for ( i = start_band; i < nbands; i++ ) { - if ( hQMetaData->twoDirBands[j] == 1 ) - { - pos_2dir_band[k] = j; - k++; - } - else - { - pos_2dir_band[k] = 0; - } + mvr2r( q_direction->band_data[i].azimuth, q_direction->band_data[i].q_azimuth, nblocks ); + mvr2r( q_direction->band_data[i].elevation, q_direction->band_data[i].q_elevation, nblocks ); } - for ( j = hQMetaData->q_direction[1].cfg.start_band; j < hQMetaData->q_direction[1].cfg.nbands; j++ ) - { - for ( k = 0; k < hQMetaData->q_direction[1].cfg.nblocks; k++ ) - { - index = masa_sq( 1.0f - hQMetaData->q_direction[1].band_data[j].energy_ratio[k], diffuseness_thresholds_hr, HR_MASA_ER_LEVELS ); - push_next_indice( hMetaData, index, MASA_BITS_ER_HR ); - hQMetaData->q_direction[1].band_data[j].energy_ratio_index[k] = index; - hQMetaData->q_direction[1].band_data[j].energy_ratio[k] = 1.0f - diffuseness_reconstructions_hr[index]; - - ratioSum = hQMetaData->q_direction[0].band_data[pos_2dir_band[j]].energy_ratio[k] + hQMetaData->q_direction[1].band_data[j].energy_ratio[k]; - - if ( ratioSum > 1.0f ) - { - hQMetaData->q_direction[0].band_data[pos_2dir_band[j]].energy_ratio[k] /= ratioSum; - hQMetaData->q_direction[1].band_data[j].energy_ratio[k] /= ratioSum; - } + } + } - needed_bits[1] += MASA_BITS_ER_HR; - hQMetaData->q_direction[1].band_data[j].bits_sph_idx[k] = bits_dir_hr; - } - } + if ( hQMetaData->q_direction->cfg.inactiveBands > 0 ) + { + hQMetaData->q_direction[0].cfg.nbands += hQMetaData->q_direction->cfg.inactiveBands; + if ( ndirections > 1 ) + { + hQMetaData->q_direction[1].cfg.nbands += hQMetaData->q_direction->cfg.inactiveBands; } } - return; + return error; } -/*------------------------------------------------------------------------- - * ivas_qmetadata_quantize_diffuseness_nrg_ratios() +/*-----------------------------------------------------------------------* + * ivas_qmetadata_enc_sid_encode() * - * Quantize diffuseness - *------------------------------------------------------------------------*/ + * Main function for coding SID for Spatial Metadata + *-----------------------------------------------------------------------*/ -static void ivas_qmetadata_quantize_diffuseness_nrg_ratios( - IVAS_QMETADATA_HANDLE hQMetaData, - int16_t *needed_bits, - int16_t *nbits_diff, - int16_t *dfRatioBits, - const int16_t hodirac_flag ) +/*! r: number of bits written */ +#ifdef IVAS_FLOAT_FIXED +void ivas_qmetadata_enc_sid_encode( + BSTR_ENC_HANDLE hMetaData, /* i/o: metadata bitstream handle */ + IVAS_QMETADATA *q_metadata, /* i/o: metadata handle */ + const int16_t masa_sid_descriptor, /* i : description of MASA SID coding structure */ + const int16_t ivas_format /* i : IVAS format */ +) { - int16_t j, k, dir2band; - int16_t index_dirRatio1Inv, index_dirRatio2Inv, index_dirRatio1Inv_mod, index_dirRatio2Inv_mod; - int16_t index_diff; + int16_t b, m; + int16_t bit_pos_start; + IVAS_QDIRECTION *q_direction; + int16_t nbands, nblocks, start_band; + float avg_direction_vector[3]; + float direction_vector[3]; + float avg_azimuth[MASA_MAXIMUM_CODING_SUBBANDS]; + float avg_elevation[MASA_MAXIMUM_CODING_SUBBANDS]; +#ifdef IVAS_FLOAT_FIXED + // Word32 avg_direction_vector_fx[3]; + Word32 direction_vector_fx[3]; + // Word32 avg_azimuth_fx[MASA_MAXIMUM_CODING_SUBBANDS]; + // Word32 avg_elevation_fx[MASA_MAXIMUM_CODING_SUBBANDS]; +#endif + int16_t bits_dir, bits_diff, bits_delta; + int16_t metadata_sid_bits; /* bits allocated to SID for metadata */ - nbits_diff[0] = 0; - nbits_diff[1] = 0; - needed_bits[0] = 0; - needed_bits[1] = 0; - dir2band = 0; + if ( ivas_format == SBA_FORMAT ) + { + metadata_sid_bits = (int16_t) ( IVAS_SID_5k2 - SID_2k40 ) / FRAMES_PER_SEC - ( SPAR_DTX_BANDS * SPAR_SID_BITS_TAR_PER_BAND ) - 2 - SID_FORMAT_NBITS; /* -1 for inactive mode header bit*/ + } + else + { + metadata_sid_bits = ( IVAS_SID_5k2 - SID_2k40 ) / FRAMES_PER_SEC - SID_FORMAT_NBITS; + } - for ( j = hQMetaData->q_direction[0].cfg.start_band; j < hQMetaData->q_direction[0].cfg.nbands; ++j ) + + /* Save initial position in bitstream */ + bit_pos_start = hMetaData->nb_bits_tot; + + /* write for MASA the number of transport channels used at coding and the CPE mode DFT/MDCT */ + if ( masa_sid_descriptor > -1 ) { - if ( hQMetaData->no_directions == 2 && hQMetaData->twoDirBands[j] == 1 ) + push_next_indice( hMetaData, masa_sid_descriptor, 1 ); + } + + /* Code for one direction: diffuseness and average DOA(s)*/ + q_direction = &( q_metadata->q_direction[0] ); + nbands = q_direction->cfg.nbands; + nblocks = q_direction->cfg.nblocks; + start_band = 0; /*Start always with band 0 for SID*/ + + /* sanity checks*/ + assert( q_metadata->no_directions == 1 && "Qmetadata SID: only one direction supported!" ); + if ( ivas_format == SBA_FORMAT ) + { + assert( ( q_direction->cfg.nbands == DIRAC_DTX_BANDS ) && "Qmetadata SID: only 2 bands supported!" ); + } + else + { + assert( ( q_direction->cfg.nbands == 5 ) && "Qmetadata SID: only 5 bands supported!" ); + } + + if ( ivas_format != SBA_FORMAT ) + { + /* Signalling 2D*/ + push_next_indice( hMetaData, ( q_direction->not_in_2D > 0 ), 1 ); /*2D flag*/ + } + else + { + q_direction->not_in_2D = 1; /* force for merged modes */ + } + + /*Encode the quantized diffuseness in raw coding*/ + bits_dir = 0; + bits_diff = 0; + if ( ivas_format != SBA_FORMAT ) + { + for ( b = start_band; b < nbands; b++ ) { - float diffRatio, dfRatio, dfRatioQ, diffRatioQ, dirRatio1Q, dirRatio2Q; - float dirRatio1, dirRatio2, sumRatio; - int16_t dfRatio_index, dfRatio_qsteps, dfRatio_bits; + q_direction->band_data[b].energy_ratio_index[0] = max( q_direction->band_data[b].energy_ratio_index[0], 4 ); + bits_diff += ivas_qmetadata_encode_quasi_uniform_length( q_direction->band_data[b].energy_ratio_index[0] - 4, DIRAC_DIFFUSE_LEVELS - 4 ); + q_direction->band_data[b].bits_sph_idx[0] = bits_direction_masa[q_direction->band_data[b].energy_ratio_index[0]]; - /* With 2dir metadata, we quantize and transmit diffuse-to-total ratio (diffRatio) and - * distribution factor of direct-to-total ratios (dFRatio). This is more efficient and - * accurate than simple separate quantization of each direct-to-total ratio or their - * separate inverses. */ - if ( hodirac_flag ) + if ( q_direction->not_in_2D == 0 ) { - /* already encoded as total and ratios in HO-DirAC */ - diffRatio = 1.f - hQMetaData->q_direction[0].band_data[j].energy_ratio[0]; - dfRatio = hQMetaData->q_direction[1].band_data[dir2band].energy_ratio[0]; + q_direction->band_data[b].azimuth_m_alphabet[0] = 1 << ( min( 8, q_direction->band_data[b].bits_sph_idx[0] ) ); + bits_dir += ivas_qmetadata_encode_quasi_uniform_length( q_direction->band_data[b].azimuth_m_alphabet[0] - 1, q_direction->band_data[b].azimuth_m_alphabet[0] ); } else { - dirRatio1 = hQMetaData->q_direction[0].band_data[j].energy_ratio[0]; - dirRatio2 = hQMetaData->q_direction[1].band_data[dir2band].energy_ratio[0]; - sumRatio = dirRatio1 + dirRatio2; - diffRatio = 1.0f - sumRatio; - dfRatio = sumRatio < EPSILON ? 0.5f : dirRatio1 / sumRatio; + bits_dir += q_direction->band_data[b].bits_sph_idx[0]; } + } + /* Reduce bit demand by increasing diffuseness*/ + bits_delta = metadata_sid_bits - ( hMetaData->nb_bits_tot - bit_pos_start ) - bits_diff - bits_dir; + if ( bits_delta > 0 ) + { + while ( bits_delta > 0 ) + { + for ( b = start_band; b < nbands && ( bits_delta > 0 ); b++ ) + { + if ( q_direction->band_data[b].bits_sph_idx[0] < 11 ) + { + bits_delta -= 1; + q_direction->band_data[b].bits_sph_idx[0]++; + } + } + } - index_diff = masa_sq( diffRatio, diffuseness_thresholds, DIRAC_DIFFUSE_LEVELS ); - diffRatioQ = diffuseness_reconstructions[index_diff]; - - if ( hodirac_flag ) + if ( q_direction->not_in_2D == 0 ) { - dfRatio_bits = ivas_get_df_ratio_bits_hodirac( index_diff ); + for ( b = start_band; b < nbands; b++ ) + { + q_direction->band_data[b].azimuth_m_alphabet[0] = 1 << ( min( 8, q_direction->band_data[b].bits_sph_idx[0] ) ); + } } - else + } + else + { + while ( bits_delta < 0 ) { - dfRatio_bits = ivas_get_df_ratio_bits( index_diff ); + for ( b = nbands - 1; b >= start_band && ( bits_delta < 0 ); b-- ) + { + if ( q_direction->band_data[b].bits_sph_idx[0] >= 4 ) + { + bits_delta += 1; + q_direction->band_data[b].bits_sph_idx[0]--; + if ( q_direction->not_in_2D == 0 ) + { + q_direction->band_data[b].azimuth_m_alphabet[0] = 1 << ( min( 8, q_direction->band_data[b].bits_sph_idx[0] ) ); + } + } + } } + } + } + else + { + for ( b = start_band; b < nbands; b++ ) + { + q_direction->band_data[b].energy_ratio_index[0] = max( q_direction->band_data[b].energy_ratio_index[0], 4 ); + bits_diff += ivas_qmetadata_encode_quasi_uniform_length( q_direction->band_data[b].energy_ratio_index[0] - 4, DIRAC_DIFFUSE_LEVELS - 4 ); + q_direction->band_data[b].bits_sph_idx[0] = bits_direction_masa[q_direction->band_data[b].energy_ratio_index[0]]; - dfRatioBits[dir2band] = dfRatio_bits; - - dfRatio_qsteps = ( 1 << dfRatio_bits ); - if ( hodirac_flag ) + if ( q_direction->not_in_2D == 0 ) { - dfRatio_index = usquant( dfRatio, &dfRatioQ, 0.0f, 1.f / ( dfRatio_qsteps - 1 ), dfRatio_qsteps ); - dirRatio1Q = 1.f - diffRatioQ; - dirRatio2Q = dfRatioQ; + q_direction->band_data[b].azimuth_m_alphabet[0] = 1 << ( min( 5, q_direction->band_data[b].bits_sph_idx[0] ) ); + bits_dir += ivas_qmetadata_encode_quasi_uniform_length( q_direction->band_data[b].azimuth_m_alphabet[0] - 1, q_direction->band_data[b].azimuth_m_alphabet[0] ); } else { - dfRatio_index = usquant( dfRatio, &dfRatioQ, 0.5f, 0.5f / ( dfRatio_qsteps - 1 ), dfRatio_qsteps ); - - /* Direction quantization requires also separately quantized direct-to-total ratios. Thus, we calculate them. */ - dirRatio1Q = dfRatioQ * ( 1.0f - diffRatioQ ); - dirRatio2Q = ( 1.0f - diffRatioQ ) - dirRatio1Q; + bits_dir += q_direction->band_data[b].bits_sph_idx[0]; } + } - index_dirRatio1Inv = masa_sq( 1.0f - dirRatio1Q, diffuseness_thresholds, DIRAC_DIFFUSE_LEVELS ); + /* Reduce bit demand by increasing diffuseness*/ + bits_delta = metadata_sid_bits - ( hMetaData->nb_bits_tot - bit_pos_start ) - bits_diff - bits_dir; - /* Note: To save memory, we store temporarily index_diff and dfRatio_index into first and second direction - * energy ratio index variables until they have been encoded. index_dirRatio1Inv and index_dirRatio2Inv are - * then later retrieved for further use in encoding. */ - for ( k = 0; k < hQMetaData->q_direction[0].cfg.nblocks; k++ ) + while ( bits_delta < 0 && ( q_direction->not_in_2D > 0 ) ) + { + for ( b = nbands - 1; b >= start_band && ( bits_delta < 0 ); b-- ) { - hQMetaData->q_direction[0].band_data[j].energy_ratio_index[k] = index_diff; - hQMetaData->q_direction[0].band_data[j].energy_ratio[k] = dirRatio1Q; - } - nbits_diff[0] += MASA_BITS_ER; - - if ( hodirac_flag ) - { - float tmp; - index_dirRatio2Inv = usquant( dirRatio2Q, &tmp, 0.0f, 1.f / ( DIRAC_DIFFUSE_LEVELS - 1 ), DIRAC_DIFFUSE_LEVELS ); - } - else - { - index_dirRatio2Inv = masa_sq( 1.0f - dirRatio2Q, diffuseness_thresholds, DIRAC_DIFFUSE_LEVELS ); + if ( q_direction->band_data[b].energy_ratio_index[0] < ( DIRAC_DIFFUSE_LEVELS - 1 ) ) + { + bits_delta += q_direction->band_data[b].bits_sph_idx[0]; + q_direction->band_data[b].energy_ratio_index[0]++; + q_direction->band_data[b].bits_sph_idx[0] = bits_direction_masa[q_direction->band_data[b].energy_ratio_index[0]]; + bits_delta -= q_direction->band_data[b].bits_sph_idx[0]; + } } + } + } + assert( ( bits_delta >= 0 ) && "Bit budget in Qmetadata SID is violated!!!" ); - for ( k = 0; k < hQMetaData->q_direction[1].cfg.nblocks; k++ ) - { - hQMetaData->q_direction[1].band_data[dir2band].energy_ratio_index[k] = dfRatio_index; - hQMetaData->q_direction[1].band_data[dir2band].energy_ratio[k] = dirRatio2Q; - } - nbits_diff[1] += dfRatio_bits; + /*Code diffuseness*/ + for ( b = start_band; b < nbands; b++ ) + { + ivas_qmetadata_encode_quasi_uniform( hMetaData, q_direction->band_data[b].energy_ratio_index[0] - 4, DIRAC_DIFFUSE_LEVELS - 4 ); + } - /* Obtain compensated direct-to-total ratios for direction quantization. This compensates for the - * fact that with 2dir data, it is harder to achieve separate high direct-to-total ratio values - * which are assumed by the direction quantization system. In practice, this improves direction - * accuracy when it is perceptual meaningful. */ + /* Compute and Quantize an average direction per band*/ + for ( b = start_band; b < nbands; b++ ) + { + set_zero( avg_direction_vector, 3 ); + for ( m = 0; m < nblocks; m++ ) + { + /*compute the average direction */ #ifdef IVAS_FLOAT_FIXED - masa_compensate_two_dir_energy_ratio_index_fx( index_dirRatio1Inv, index_dirRatio2Inv, &index_dirRatio1Inv_mod, &index_dirRatio2Inv_mod, hodirac_flag ); + /*==========================================flt-2-fix======================================================*/ + q_direction->band_data[b].azimuth_fx[m] = floatToFixed( q_direction->band_data[b].azimuth[m], Q22 ); + q_direction->band_data[b].elevation_fx[m] = floatToFixed( q_direction->band_data[b].elevation[m], Q22 ); + /*==========================================flt-2-fix======================================================*/ + + ivas_qmetadata_azimuth_elevation_to_direction_vector_fx( q_direction->band_data[b].azimuth_fx[m], q_direction->band_data[b].elevation_fx[m], direction_vector_fx ); + + /*==========================================fix-2-flt======================================================*/ + fixedToFloat_arrL( direction_vector_fx, direction_vector, Q30, 3 ); + /*==========================================fix-2-flt======================================================*/ #else - masa_compensate_two_dir_energy_ratio_index( index_dirRatio1Inv, index_dirRatio2Inv, &index_dirRatio1Inv_mod, &index_dirRatio2Inv_mod, hodirac_flag ); + ivas_qmetadata_azimuth_elevation_to_direction_vector( q_direction->band_data[b].azimuth[m], q_direction->band_data[b].elevation[m], direction_vector ); #endif + v_add( avg_direction_vector, direction_vector, avg_direction_vector, 3 ); + } - for ( k = 0; k < hQMetaData->q_direction[0].cfg.nblocks; k++ ) - { - hQMetaData->q_direction[0].band_data[j].energy_ratio_index_mod[k] = index_dirRatio1Inv_mod; - hQMetaData->q_direction[0].band_data[j].bits_sph_idx[k] = bits_direction_masa[index_dirRatio1Inv_mod]; - } - needed_bits[0] += hQMetaData->q_direction[0].cfg.nblocks * bits_direction_masa[index_dirRatio1Inv_mod]; +#ifdef IVAS_FLOAT_FIXED_ + /*==========================================flt-2-fix======================================================*/ + Word16 q_dir_e = 0; + f2me_buf( avg_direction_vector, avg_direction_vector_fx, &q_dir_e, 3 ); + Scale_sig32( avg_direction_vector_fx, 3, -1 ); + /*==========================================flt-2-fix======================================================*/ - for ( k = 0; k < hQMetaData->q_direction[1].cfg.nblocks; k++ ) - { - hQMetaData->q_direction[1].band_data[dir2band].energy_ratio_index_mod[k] = index_dirRatio2Inv_mod; - hQMetaData->q_direction[1].band_data[dir2band].bits_sph_idx[k] = bits_direction_masa[index_dirRatio2Inv_mod]; - } - needed_bits[1] += hQMetaData->q_direction[1].cfg.nblocks * bits_direction_masa[index_dirRatio2Inv_mod]; + ivas_qmetadata_direction_vector_to_azimuth_elevation_fx( avg_direction_vector_fx, Q30, &avg_azimuth_fx[b], &avg_elevation_fx[b] ); - dir2band++; + /*==========================================fix-2-flt======================================================*/ + avg_azimuth[b] = fixedToFloat( avg_azimuth_fx[b], Q22 ); + avg_elevation[b] = fixedToFloat( avg_elevation_fx[b], Q22 ); + /*==========================================fix-2-flt======================================================*/ +#else + ivas_qmetadata_direction_vector_to_azimuth_elevation( avg_direction_vector, &avg_azimuth[b], &avg_elevation[b] ); +#endif + + /* Quantize the average direction */ + if ( q_direction->not_in_2D == 0 ) + { + avg_elevation[b] = 0; + q_direction->band_data[b].spherical_index[0] = quantize_direction2D( avg_azimuth[b], q_direction->band_data[b].azimuth_m_alphabet[0], &avg_azimuth[b], + &q_direction->band_data[b].azimuth_index[0], q_direction->cfg.mc_ls_setup ); } else { - index_dirRatio1Inv = masa_sq( 1.0f - hQMetaData->q_direction[0].band_data[j].energy_ratio[0], diffuseness_thresholds, DIRAC_DIFFUSE_LEVELS ); - - for ( k = 0; k < hQMetaData->q_direction[0].cfg.nblocks; k++ ) - { - hQMetaData->q_direction[0].band_data[j].energy_ratio_index[k] = index_dirRatio1Inv; - hQMetaData->q_direction[0].band_data[j].energy_ratio_index_mod[k] = index_dirRatio1Inv; - hQMetaData->q_direction[0].band_data[j].energy_ratio[k] = 1.0f - diffuseness_reconstructions[index_dirRatio1Inv]; - hQMetaData->q_direction[0].band_data[j].bits_sph_idx[k] = bits_direction_masa[index_dirRatio1Inv]; - } + q_direction->band_data[b].spherical_index[0] = quantize_direction( avg_elevation[b], avg_azimuth[b], q_direction->band_data[b].bits_sph_idx[0], &avg_elevation[b], &avg_azimuth[b], + &q_direction->band_data[b].elevation_index[0], &q_direction->band_data[b].azimuth_index[0], q_direction->cfg.mc_ls_setup ); + } - nbits_diff[0] += MASA_BITS_ER; + /* Save quantized DOAs */ + q_direction->band_data[b].q_azimuth[0] = avg_azimuth[b]; + q_direction->band_data[b].q_elevation[0] = avg_elevation[b]; - needed_bits[0] += hQMetaData->q_direction[0].cfg.nblocks * bits_direction_masa[index_dirRatio1Inv]; + if ( q_direction->band_data[b].azimuth_index[0] == MASA_NO_INDEX ) + { + q_direction->band_data[b].azimuth_index[0] = 0; } } - return; -} - - -/*------------------------------------------------------------------------- - * ivas_diffuseness_huff_ec_encode() - * - * - *------------------------------------------------------------------------*/ - -static int16_t ivas_diffuseness_huff_ec_encode( - BSTR_ENC_HANDLE hMetaData, - const uint16_t idx ) -{ - int16_t nbits; - nbits = 0; - if ( idx <= DIFF_EC_HUFF_GR0_LIMIT ) + /* quantize average elevation and azimuth angles */ + if ( q_direction->not_in_2D > 0 ) { - if ( idx > 0 ) + for ( b = start_band; b < nbands; b++ ) { - push_next_indice( hMetaData, ( 1 << idx ) - 1, idx ); - nbits += idx; + push_next_indice( hMetaData, q_direction->band_data[b].spherical_index[0], q_direction->band_data[b].bits_sph_idx[0] ); } - push_next_indice( hMetaData, 0, 1 ); - nbits += 1; } else { - push_next_indice( hMetaData, 511, DIFF_EC_HUFF_GR0_LIMIT + 1 ); - push_next_indice( hMetaData, idx - DIFF_EC_HUFF_GR0_LIMIT - 1, 2 ); - nbits += DIFF_EC_HUFF_GR0_LIMIT + 3; + for ( b = start_band; b < nbands; b++ ) + { + ivas_qmetadata_encode_quasi_uniform( hMetaData, q_direction->band_data[b].azimuth_index[0], q_direction->band_data[b].azimuth_m_alphabet[0] ); + } } - return nbits; -} -/*------------------------------------------------------------------------- - * ivas_diffuseness_huff_ec_prepare() - * - * - *------------------------------------------------------------------------*/ + /* fill bits*/ + assert( ( hMetaData->nb_bits_tot - bit_pos_start ) <= metadata_sid_bits && "Too many written bits!" ); + while ( ( hMetaData->nb_bits_tot - bit_pos_start ) < metadata_sid_bits ) + { + push_next_indice( hMetaData, 0, 1 ); /*fill bit*/ + } -static void ivas_diffuseness_huff_ec_prepare( - IVAS_QDIRECTION *q_direction, - int16_t *best_av, - uint16_t *avr_idx, - int16_t *diffuseness_bits_huff ) + return; +} +#else +void ivas_qmetadata_enc_sid_encode( + BSTR_ENC_HANDLE hMetaData, /* i/o: metadata bitstream handle */ + IVAS_QMETADATA *q_metadata, /* i/o: metadata handle */ + const int16_t masa_sid_descriptor, /* i : description of MASA SID coding structure */ + const int16_t ivas_format /* i : IVAS format */ +) { - int16_t bits; - int16_t av_crt; - int16_t av; - int16_t sh_idx; - uint16_t ui_sh_idx[MASA_MAXIMUM_CODING_SUBBANDS]; - int16_t b, start_band, nbands; - - start_band = q_direction->cfg.start_band; - nbands = q_direction->cfg.nbands; + int16_t b, m; + int16_t bit_pos_start; + IVAS_QDIRECTION *q_direction; + int16_t nbands, nblocks, start_band; + float avg_direction_vector[3]; + float direction_vector[3]; + float avg_azimuth[MASA_MAXIMUM_CODING_SUBBANDS]; + float avg_elevation[MASA_MAXIMUM_CODING_SUBBANDS]; + int16_t bits_dir, bits_diff, bits_delta; + int16_t metadata_sid_bits; /* bits allocated to SID for metadata */ - *diffuseness_bits_huff = 0; - av = 0; - for ( b = start_band; b < nbands; b++ ) + if ( ivas_format == SBA_FORMAT ) { - av += q_direction->band_data[b].energy_ratio_index[0]; + metadata_sid_bits = (int16_t) ( IVAS_SID_5k2 - SID_2k40 ) / FRAMES_PER_SEC - ( SPAR_DTX_BANDS * SPAR_SID_BITS_TAR_PER_BAND ) - 2 - SID_FORMAT_NBITS; /* -1 for inactive mode header bit*/ } - av = (int16_t) ( 0.5f + av / (float) nbands ); - *best_av = av; - - *diffuseness_bits_huff = MAX16B; - for ( av_crt = av - 1; av_crt <= av + 1; av_crt++ ) + else { - bits = 0; - for ( b = start_band; b < nbands; b++ ) - { - sh_idx = q_direction->band_data[b].energy_ratio_index[0] - av_crt; - ui_sh_idx[b] = ( sh_idx <= 0 ) ? ( -2 * sh_idx ) : sh_idx * 2 - 1; - if ( ui_sh_idx[b] >= 2 * DIRAC_DIFFUSE_LEVELS - 3 ) - { - bits = 100; /* to avoid difference larger than 6 in absolute value */ - } - - bits += ( ui_sh_idx[b] <= DIFF_EC_HUFF_GR0_LIMIT ) ? ( ui_sh_idx[b] + 1 ) : 11; - } - - if ( bits < *diffuseness_bits_huff ) - { - *diffuseness_bits_huff = bits; - mvs2s( (int16_t *) ui_sh_idx, (int16_t *) avr_idx, nbands ); - *best_av = av_crt; - } + metadata_sid_bits = ( IVAS_SID_5k2 - SID_2k40 ) / FRAMES_PER_SEC - SID_FORMAT_NBITS; } - *diffuseness_bits_huff += MASA_BITS_ER; /* for the average */ - - return; -} -/*------------------------------------------------------------------------- - * ivas_qmetadata_entropy_encode_diffuseness() - * - * encode diffuseness - *------------------------------------------------------------------------*/ + /* Save initial position in bitstream */ + bit_pos_start = hMetaData->nb_bits_tot; -static int16_t ivas_qmetadata_entropy_encode_diffuseness( - BSTR_ENC_HANDLE hMetaData, - IVAS_QDIRECTION *q_direction, - uint16_t *diffuseness_index_max_ec_frame ) -{ - int16_t start_bit_pos; - int16_t diffuseness_bits_raw; - int16_t b; - int16_t min_diffuseness_m_index, max_diffuseness_m_index; - int16_t nbands; - int16_t start_band; + /* write for MASA the number of transport channels used at coding and the CPE mode DFT/MDCT */ + if ( masa_sid_descriptor > -1 ) + { + push_next_indice( hMetaData, masa_sid_descriptor, 1 ); + } + /* Code for one direction: diffuseness and average DOA(s)*/ + q_direction = &( q_metadata->q_direction[0] ); nbands = q_direction->cfg.nbands; - start_band = q_direction->cfg.start_band; - - start_bit_pos = hMetaData->nb_bits_tot; + nblocks = q_direction->cfg.nblocks; + start_band = 0; /*Start always with band 0 for SID*/ - if ( nbands == 1 ) + /* sanity checks*/ + assert( q_metadata->no_directions == 1 && "Qmetadata SID: only one direction supported!" ); + if ( ivas_format == SBA_FORMAT ) { - /* If there is only one band, diffuseness should be coded directly as raw with no signaling. */ - push_next_indice( hMetaData, q_direction->band_data[0].energy_ratio_index[0], MASA_BITS_ER ); - *diffuseness_index_max_ec_frame = 5; - return ( hMetaData->nb_bits_tot - start_bit_pos ); + assert( ( q_direction->cfg.nbands == DIRAC_DTX_BANDS ) && "Qmetadata SID: only 2 bands supported!" ); } - - /* compute the number of raw coding bits */ - diffuseness_bits_raw = 0; - for ( b = start_band; b < nbands; b++ ) + else { - diffuseness_bits_raw += ivas_qmetadata_encode_quasi_uniform_length( q_direction->band_data[b].energy_ratio_index[0], DIRAC_DIFFUSE_LEVELS ); + assert( ( q_direction->cfg.nbands == 5 ) && "Qmetadata SID: only 5 bands supported!" ); } - min_diffuseness_m_index = q_direction->band_data[start_band].energy_ratio_index[0]; - max_diffuseness_m_index = q_direction->band_data[start_band].energy_ratio_index[0]; - - for ( b = start_band; b < nbands; b++ ) + if ( ivas_format != SBA_FORMAT ) { - if ( q_direction->band_data[b].energy_ratio_index[0] < min_diffuseness_m_index ) - { - min_diffuseness_m_index = q_direction->band_data[b].energy_ratio_index[0]; - } - - if ( q_direction->band_data[b].energy_ratio_index[0] > max_diffuseness_m_index ) - { - max_diffuseness_m_index = q_direction->band_data[b].energy_ratio_index[0]; - } + /* Signalling 2D*/ + push_next_indice( hMetaData, ( q_direction->not_in_2D > 0 ), 1 ); /*2D flag*/ + } + else + { + q_direction->not_in_2D = 1; /* force for merged modes */ } - if ( nbands < DIFF_EC_HUFF_BAND_LIMIT ) + /*Encode the quantized diffuseness in raw coding*/ + bits_dir = 0; + bits_diff = 0; + if ( ivas_format != SBA_FORMAT ) { - /* Use similarity coding approach or raw coding when there is a low number of bands. */ - /* one bit is used to indicate whether diffuseness values are entropy coded or coded raw */ - if ( min_diffuseness_m_index == max_diffuseness_m_index ) /* all values are equal */ - { - push_next_indice( hMetaData, 0, 1 ); /* dif_use_raw_coding */ - push_next_indice( hMetaData, 1, 1 ); /* dif_have_unique_value */ - ivas_qmetadata_encode_quasi_uniform( hMetaData, min_diffuseness_m_index, DIRAC_DIFFUSE_LEVELS ); /* dif_unique_value */ - } - else if ( min_diffuseness_m_index + 1 == max_diffuseness_m_index ) /* only two consecutive values are present */ + for ( b = start_band; b < nbands; b++ ) { - push_next_indice( hMetaData, 0, 1 ); /* dif_use_raw_coding */ - push_next_indice( hMetaData, 0, 1 ); /* dif_have_unique_value */ - ivas_qmetadata_encode_quasi_uniform( hMetaData, min_diffuseness_m_index, DIRAC_DIFFUSE_LEVELS - 1 ); /* dif_min_value */ + q_direction->band_data[b].energy_ratio_index[0] = max( q_direction->band_data[b].energy_ratio_index[0], 4 ); + bits_diff += ivas_qmetadata_encode_quasi_uniform_length( q_direction->band_data[b].energy_ratio_index[0] - 4, DIRAC_DIFFUSE_LEVELS - 4 ); + q_direction->band_data[b].bits_sph_idx[0] = bits_direction_masa[q_direction->band_data[b].energy_ratio_index[0]]; - for ( b = start_band; b < nbands; b++ ) + if ( q_direction->not_in_2D == 0 ) { - push_next_indice( hMetaData, q_direction->band_data[b].energy_ratio_index[0] - min_diffuseness_m_index, 1 ); /* dif_bit_offset_values */ + q_direction->band_data[b].azimuth_m_alphabet[0] = 1 << ( min( 8, q_direction->band_data[b].bits_sph_idx[0] ) ); + bits_dir += ivas_qmetadata_encode_quasi_uniform_length( q_direction->band_data[b].azimuth_m_alphabet[0] - 1, q_direction->band_data[b].azimuth_m_alphabet[0] ); } - } - else /* raw coding */ - { - push_next_indice( hMetaData, 1, 1 ); /* dif_use_raw_coding */ - - for ( b = start_band; b < nbands; b++ ) + else { - ivas_qmetadata_encode_quasi_uniform( hMetaData, q_direction->band_data[b].energy_ratio_index[0], DIRAC_DIFFUSE_LEVELS ); /* dif_values */ + bits_dir += q_direction->band_data[b].bits_sph_idx[0]; } } - } - else - { - /* Use Huffman-coding approach or raw coding when there is a high number of bands. */ - int16_t diffuseness_bits_huff; - int16_t best_av; - uint16_t avr_idx[MASA_MAXIMUM_CODING_SUBBANDS]; - /* First, obtain average indices and bit usage for Huffman-coding. */ - ivas_diffuseness_huff_ec_prepare( q_direction, &best_av, avr_idx, &diffuseness_bits_huff ); - - /* If there is benefit, use Huffman-coding. Otherwise, use raw coding. */ - if ( diffuseness_bits_huff < diffuseness_bits_raw ) + /* Reduce bit demand by increasing diffuseness*/ + bits_delta = metadata_sid_bits - ( hMetaData->nb_bits_tot - bit_pos_start ) - bits_diff - bits_dir; + if ( bits_delta > 0 ) { - /* Signal Huffman EC */ - push_next_indice( hMetaData, 0, 1 ); - push_next_indice( hMetaData, best_av, MASA_BITS_ER ); - for ( b = start_band; b < nbands; b++ ) + while ( bits_delta > 0 ) { - ivas_diffuseness_huff_ec_encode( hMetaData, avr_idx[b] ); + for ( b = start_band; b < nbands && ( bits_delta > 0 ); b++ ) + { + if ( q_direction->band_data[b].bits_sph_idx[0] < 11 ) + { + bits_delta -= 1; + q_direction->band_data[b].bits_sph_idx[0]++; + } + } + } + + if ( q_direction->not_in_2D == 0 ) + { + for ( b = start_band; b < nbands; b++ ) + { + q_direction->band_data[b].azimuth_m_alphabet[0] = 1 << ( min( 8, q_direction->band_data[b].bits_sph_idx[0] ) ); + } } } else { - /* Signal raw */ - push_next_indice( hMetaData, 1, 1 ); - for ( b = start_band; b < nbands; b++ ) + while ( bits_delta < 0 ) { - ivas_qmetadata_encode_quasi_uniform( hMetaData, q_direction->band_data[b].energy_ratio_index[0], DIRAC_DIFFUSE_LEVELS ); /* dif_values */ + for ( b = nbands - 1; b >= start_band && ( bits_delta < 0 ); b-- ) + { + if ( q_direction->band_data[b].bits_sph_idx[0] >= 4 ) + { + bits_delta += 1; + q_direction->band_data[b].bits_sph_idx[0]--; + if ( q_direction->not_in_2D == 0 ) + { + q_direction->band_data[b].azimuth_m_alphabet[0] = 1 << ( min( 8, q_direction->band_data[b].bits_sph_idx[0] ) ); + } + } + } } } } - - *diffuseness_index_max_ec_frame = 5; - /* adaptively select the diffuseness_index_max_ec threshold */ - if ( min_diffuseness_m_index > 5 ) + else { - *diffuseness_index_max_ec_frame = DIRAC_DIFFUSE_LEVELS - 1; - } - - - return ( hMetaData->nb_bits_tot - start_bit_pos ); -} - - -/*------------------------------------------------------------------------- - * ivas_qmetadata_entropy_encode_df_ratio() - * - * encode dfRatio - *------------------------------------------------------------------------*/ - -static int16_t ivas_qmetadata_entropy_encode_df_ratio( - BSTR_ENC_HANDLE hMetaData, - IVAS_QDIRECTION *q_direction, - int16_t *df_ratio_bits ) -{ - int16_t start_bit_pos; - int16_t bits_raw; - int16_t b; - int16_t min_index, max_index; - int16_t nbands, start_band; - int16_t max_df_ratio_bits; - int16_t ec_mode = 0; - int16_t max_alphabet_size; - - nbands = q_direction->cfg.nbands; - start_band = q_direction->cfg.start_band; + for ( b = start_band; b < nbands; b++ ) + { + q_direction->band_data[b].energy_ratio_index[0] = max( q_direction->band_data[b].energy_ratio_index[0], 4 ); + bits_diff += ivas_qmetadata_encode_quasi_uniform_length( q_direction->band_data[b].energy_ratio_index[0] - 4, DIRAC_DIFFUSE_LEVELS - 4 ); + q_direction->band_data[b].bits_sph_idx[0] = bits_direction_masa[q_direction->band_data[b].energy_ratio_index[0]]; - start_bit_pos = hMetaData->nb_bits_tot; + if ( q_direction->not_in_2D == 0 ) + { + q_direction->band_data[b].azimuth_m_alphabet[0] = 1 << ( min( 5, q_direction->band_data[b].bits_sph_idx[0] ) ); + bits_dir += ivas_qmetadata_encode_quasi_uniform_length( q_direction->band_data[b].azimuth_m_alphabet[0] - 1, q_direction->band_data[b].azimuth_m_alphabet[0] ); + } + else + { + bits_dir += q_direction->band_data[b].bits_sph_idx[0]; + } + } - if ( nbands == 1 ) - { - /* If there is only one band, ratio should be coded directly as raw with no signaling. */ - push_next_indice( hMetaData, q_direction->band_data[0].energy_ratio_index[0], df_ratio_bits[0] ); + /* Reduce bit demand by increasing diffuseness*/ + bits_delta = metadata_sid_bits - ( hMetaData->nb_bits_tot - bit_pos_start ) - bits_diff - bits_dir; - return ( hMetaData->nb_bits_tot - start_bit_pos ); + while ( bits_delta < 0 && ( q_direction->not_in_2D > 0 ) ) + { + for ( b = nbands - 1; b >= start_band && ( bits_delta < 0 ); b-- ) + { + if ( q_direction->band_data[b].energy_ratio_index[0] < ( DIRAC_DIFFUSE_LEVELS - 1 ) ) + { + bits_delta += q_direction->band_data[b].bits_sph_idx[0]; + q_direction->band_data[b].energy_ratio_index[0]++; + q_direction->band_data[b].bits_sph_idx[0] = bits_direction_masa[q_direction->band_data[b].energy_ratio_index[0]]; + bits_delta -= q_direction->band_data[b].bits_sph_idx[0]; + } + } + } } + assert( ( bits_delta >= 0 ) && "Bit budget in Qmetadata SID is violated!!!" ); - /* compute the number of raw coding bits */ - bits_raw = 0; - max_df_ratio_bits = 0; + /*Code diffuseness*/ for ( b = start_band; b < nbands; b++ ) { - bits_raw += df_ratio_bits[b]; - max_df_ratio_bits = max( df_ratio_bits[b], max_df_ratio_bits ); + ivas_qmetadata_encode_quasi_uniform( hMetaData, q_direction->band_data[b].energy_ratio_index[0] - 4, DIRAC_DIFFUSE_LEVELS - 4 ); } - min_index = q_direction->band_data[start_band].energy_ratio_index[0]; - max_index = q_direction->band_data[start_band].energy_ratio_index[0]; + /* Compute and Quantize an average direction per band*/ for ( b = start_band; b < nbands; b++ ) { - if ( q_direction->band_data[b].energy_ratio_index[0] < min_index ) + set_zero( avg_direction_vector, 3 ); + for ( m = 0; m < nblocks; m++ ) { - min_index = q_direction->band_data[b].energy_ratio_index[0]; + /*compute the average direction */ + ivas_qmetadata_azimuth_elevation_to_direction_vector( q_direction->band_data[b].azimuth[m], q_direction->band_data[b].elevation[m], direction_vector ); + v_add( avg_direction_vector, direction_vector, avg_direction_vector, 3 ); } - if ( q_direction->band_data[b].energy_ratio_index[0] > max_index ) + ivas_qmetadata_direction_vector_to_azimuth_elevation( avg_direction_vector, &avg_azimuth[b], &avg_elevation[b] ); + + /* Quantize the average direction */ + if ( q_direction->not_in_2D == 0 ) { - max_index = q_direction->band_data[b].energy_ratio_index[0]; + avg_elevation[b] = 0; + q_direction->band_data[b].spherical_index[0] = quantize_direction2D( avg_azimuth[b], q_direction->band_data[b].azimuth_m_alphabet[0], &avg_azimuth[b], + &q_direction->band_data[b].azimuth_index[0], q_direction->cfg.mc_ls_setup ); + } + else + { + q_direction->band_data[b].spherical_index[0] = quantize_direction( avg_elevation[b], avg_azimuth[b], q_direction->band_data[b].bits_sph_idx[0], &avg_elevation[b], &avg_azimuth[b], + &q_direction->band_data[b].elevation_index[0], &q_direction->band_data[b].azimuth_index[0], q_direction->cfg.mc_ls_setup ); } - } - /* Decide what modes are possible */ - if ( bits_raw >= max_df_ratio_bits + 2 + nbands ) - { - ec_mode = 2; - } - else if ( bits_raw >= max_df_ratio_bits + 1 ) - { - ec_mode = 1; - } - else - { - ec_mode = 0; - } - max_alphabet_size = 1 << max_df_ratio_bits; + /* Save quantized DOAs */ + q_direction->band_data[b].q_azimuth[0] = avg_azimuth[b]; + q_direction->band_data[b].q_elevation[0] = avg_elevation[b]; - if ( min_index == max_index && ec_mode > 0 ) /* all values are equal */ - { - push_next_indice( hMetaData, 0, 1 ); /* Signal between EC and raw */ - if ( ec_mode > 1 ) + if ( q_direction->band_data[b].azimuth_index[0] == MASA_NO_INDEX ) { - /* Only use bit for signaling if necessary */ - push_next_indice( hMetaData, 0, 1 ); /* Signal between one value or bandwise diff mode */ + q_direction->band_data[b].azimuth_index[0] = 0; } - - ivas_qmetadata_encode_quasi_uniform( hMetaData, min_index, max_alphabet_size ); } - else if ( min_index + 1 == max_index && ec_mode > 1 ) /* only two consecutive values are present */ - { - push_next_indice( hMetaData, 0, 1 ); - push_next_indice( hMetaData, 1, 1 ); - ivas_qmetadata_encode_quasi_uniform( hMetaData, min_index, max_alphabet_size - 1 ); + /* quantize average elevation and azimuth angles */ + if ( q_direction->not_in_2D > 0 ) + { for ( b = start_band; b < nbands; b++ ) { - push_next_indice( hMetaData, q_direction->band_data[b].energy_ratio_index[0] - min_index, 1 ); /* Band-wise offset values */ + push_next_indice( hMetaData, q_direction->band_data[b].spherical_index[0], q_direction->band_data[b].bits_sph_idx[0] ); } } - else /* raw coding */ + else { - if ( ec_mode > 0 ) + for ( b = start_band; b < nbands; b++ ) { - push_next_indice( hMetaData, 1, 1 ); /* Only signal raw mode if not implicitly using it */ + ivas_qmetadata_encode_quasi_uniform( hMetaData, q_direction->band_data[b].azimuth_index[0], q_direction->band_data[b].azimuth_m_alphabet[0] ); } + } - for ( b = start_band; b < nbands; b++ ) - { - ivas_qmetadata_encode_quasi_uniform( hMetaData, q_direction->band_data[b].energy_ratio_index[0], 1 << df_ratio_bits[b] ); /* dif_values */ - } + + /* fill bits*/ + assert( ( hMetaData->nb_bits_tot - bit_pos_start ) <= metadata_sid_bits && "Too many written bits!" ); + while ( ( hMetaData->nb_bits_tot - bit_pos_start ) < metadata_sid_bits ) + { + push_next_indice( hMetaData, 0, 1 ); /*fill bit*/ } - return ( hMetaData->nb_bits_tot - start_bit_pos ); + return; } +#endif /*------------------------------------------------------------------------- - * restore_metadata_buffer() + * reset_metadata_spatial() * - * Restore metadata buffer + * Reset metadata in spatial formats *------------------------------------------------------------------------*/ -void restore_metadata_buffer( - BSTR_ENC_HANDLE hMetaData, - const int16_t next_ind_start, - const int16_t bit_pos_start ) +void reset_metadata_spatial( + const IVAS_FORMAT ivas_format, /* i : IVAS format */ + BSTR_ENC_HANDLE hMetaData, /* i/o: metadata bitstream handle */ + const int32_t element_brate, /* i : element bitrate */ + int32_t *total_brate, /* o : total bitrate */ + const int32_t core_brate, /* i : core bitrate */ + const int16_t nb_bits_metadata /* i : number of meatdata bits */ +) { - int16_t i; + int16_t i, next_ind_sid, last_ind_sid; + int16_t j; + int16_t metadata_sid_bits; - for ( i = next_ind_start; i < hMetaData->nb_ind_tot; i++ ) + if ( core_brate == SID_2k40 || core_brate == FRAME_NO_DATA ) { - hMetaData->ind_list[i].nb_bits = -1; - } - hMetaData->nb_bits_tot = bit_pos_start; - hMetaData->nb_ind_tot = next_ind_start; + if ( ( ivas_format == SBA_FORMAT || ivas_format == MASA_FORMAT ) && core_brate != FRAME_NO_DATA ) + { + if ( ivas_format == SBA_FORMAT ) + { + hMetaData->ind_list[0].value = 1; + metadata_sid_bits = (int16_t) ( IVAS_SID_5k2 - SID_2k40 ) / FRAMES_PER_SEC - SID_FORMAT_NBITS; - return; -} + while ( hMetaData->nb_bits_tot < metadata_sid_bits ) + { + push_next_indice( hMetaData, 0, 1 ); /*fill bit*/ + } + } + else + { + /* Reset metadata and keep only SID metadata*/ + last_ind_sid = hMetaData->nb_ind_tot; + next_ind_sid = hMetaData->nb_ind_tot; + while ( hMetaData->nb_bits_tot > nb_bits_metadata ) + { + next_ind_sid--; + hMetaData->nb_bits_tot -= hMetaData->ind_list[next_ind_sid].nb_bits; + } + hMetaData->nb_bits_tot = 0; -/*------------------------------------------------------------------------- - * ivas_qmetadata_encode_quasi_uniform() - * - * encode value using a quasi-uniform code of b or b + 1 bits, where b = floor(log2(alphabet_size)) - *------------------------------------------------------------------------*/ + for ( i = 0; i < next_ind_sid; i++ ) + { + hMetaData->ind_list[i].nb_bits = -1; + } -static void ivas_qmetadata_encode_quasi_uniform( - BSTR_ENC_HANDLE hMetaData, - const uint16_t value, - const uint16_t alphabet_size ) -{ - int16_t bits; - uint16_t tresh; + for ( j = 0, i = next_ind_sid; i < last_ind_sid; i++, j++ ) + { + hMetaData->ind_list[j].value = hMetaData->ind_list[i].value; + hMetaData->ind_list[j].nb_bits = hMetaData->ind_list[i].nb_bits; + hMetaData->nb_bits_tot += hMetaData->ind_list[j].nb_bits; + hMetaData->ind_list[i].nb_bits = -1; + } - bits = 30 - norm_l( alphabet_size ); /* bits = floor(log2(alphabet_size)) */ - tresh = ( 1U << ( bits + 1 ) ) - alphabet_size; + hMetaData->nb_ind_tot = j; + } + } + else + { + /*Reset metadata*/ + reset_indices_enc( hMetaData, hMetaData->nb_ind_tot ); + } - if ( value < tresh ) - { - push_next_indice( hMetaData, value, bits ); + *total_brate = element_brate; } - else /* value >= tresh */ + else if ( ivas_format != SBA_FORMAT ) { - push_next_indice( hMetaData, value + tresh, bits + 1 ); + /* Reset SID metadata bits*/ + while ( hMetaData->nb_bits_tot > nb_bits_metadata ) + { + hMetaData->nb_ind_tot--; + hMetaData->nb_bits_tot -= hMetaData->ind_list[hMetaData->nb_ind_tot].nb_bits; + hMetaData->ind_list[hMetaData->nb_ind_tot].nb_bits = -1; + } } return; } -/*-----------------------------------------------------------------------* - * GR encoder function definitions - *-----------------------------------------------------------------------*/ /*------------------------------------------------------------------------- - * GR_bits_new() + * quantize_direction2D() * * *------------------------------------------------------------------------*/ -/*! r: number of bits using Golomb Rice code */ -static int16_t GR_bits_new( - uint16_t *data, /* i : data to encode with GR */ - int16_t *no_symb, /* i : number of symbols for each component*/ - const int16_t no_data, /* i : number of input data */ - const int16_t GR_order, /* i : GR order to be used */ - const int16_t check_two_orders, /* i : check also coding with GR_order-1 */ - int16_t *real_GR_ord /* o : the GR order that has been used */ +/*! r: quantized spherical index */ +int16_t quantize_direction2D( + float phi, /* i : input azimuth value */ + const int16_t no_cw, /* i : number of bits */ + float *phi_q, /* o : quantized azimuth value */ + uint16_t *index_phi, /* o : quantized azimuth index */ + const MC_LS_SETUP mc_format /* i : channel format if in MC-mode */ ) { - int16_t nbits = 0, i; - int16_t nbits1 = 0; - int16_t nb; - - for ( i = 0; i < no_data; i++ ) + int16_t idx_sph; + uint16_t id_phi; + if ( no_cw < 2 ) { - nb = ivas_qmetadata_encode_extended_gr_length( data[i], no_symb[i], GR_order ); - nbits += nb; + *phi_q = 0; + + return 0; } - if ( check_two_orders == 1 ) + if ( mc_format != MC_LS_SETUP_INVALID ) { - for ( i = 0; i < no_data; i++ ) - { - nb = ivas_qmetadata_encode_extended_gr_length( data[i], no_symb[i], GR_order - 1 ); - nbits1 += nb; - } - - if ( nbits1 < nbits ) - { - nbits = nbits1 + 1; - *real_GR_ord = GR_order - 1; - } - else - { - nbits += 1; - *real_GR_ord = GR_order; - } + id_phi = quantize_phi_chan_compand( phi + 180, phi_q, no_cw, 0, mc_format ); } else { - *real_GR_ord = GR_order; + id_phi = quantize_phi( phi + 180, 0, phi_q, no_cw ); } + *phi_q -= 180; + *index_phi = ivas_qmetadata_reorder_generic( id_phi - ( no_cw >> 1 ) ); - return nbits; -} - + idx_sph = id_phi; -/*------------------------------------------------------------------------- - * GR_bits_azimuth_context() - * - * Encoding azimuth indexes with GR code using context - *------------------------------------------------------------------------*/ + return idx_sph; +} -/*! r: numer of bits used for coding */ -static int16_t GR_bits_azimuth_context( - uint16_t *data_in, /* i : data to be encoded */ - int16_t *no_symb, /* i : number of symbols for each component */ - const int16_t no_data_in, /* i : number of input data */ - const int16_t GR_order, /* i : GR order (GR_order or GR_order-1 are used ) */ - const uint16_t *bits_dir, /* i : bits for encoding the direction for each TF tile */ - int16_t *real_GR_ord, /* o : which GR order has been used */ - int16_t *p_use_context /* o : flag telling if context has been used or not */ -) +#ifdef IVAS_FLOAT_FIXED +static void ivas_qmetadata_quantize_diffuseness_nrg_ratios_hr_512( + IVAS_QMETADATA_HANDLE hQMetaData, + int16_t *needed_bits, + const int16_t bits_dir_hr, + BSTR_ENC_HANDLE hMetaData ) { - int16_t i, nbits, nbits1, use_context; - uint16_t cdata[MAX_PARAM_SPATIAL_SUBFRAMES]; - uint16_t data[MAX_PARAM_SPATIAL_SUBFRAMES]; - int16_t min_val, max_val; - int16_t real_GR_ord1; - int16_t no_symb_local[MAX_PARAM_SPATIAL_SUBFRAMES]; - int16_t no_data = 0; - - for ( i = 0; i < no_data_in; i++ ) - { - if ( data_in[i] < MASA_NO_INDEX ) - { - no_symb_local[no_data] = no_symb[i]; - data[no_data++] = data_in[i]; - } - } - - if ( no_data == 0 ) - { - *p_use_context = -3; /* corresponding to nothing to be written */ - return 0; - } + int16_t j, k; + int16_t index; - nbits = 0; - use_context = 0; + needed_bits[0] = 0; + needed_bits[1] = 0; - for ( i = 0; i < no_data; i++ ) + for ( j = hQMetaData->q_direction[0].cfg.start_band; j < hQMetaData->q_direction[0].cfg.nbands; ++j ) { - if ( ( bits_dir[i] <= 1 ) ) - { - nbits += bits_dir[i]; - use_context = 1; - } - else + for ( k = 0; k < hQMetaData->q_direction[0].cfg.nblocks; k++ ) { - *real_GR_ord = GR_order - ( bits_dir[i] == 2 ); - nbits += ivas_qmetadata_encode_extended_gr_length( data[i], no_symb_local[i], *real_GR_ord ); +#ifdef IVAS_FLOAT_FIXED + /*=====================================flt-2-fix============================================*/ + hQMetaData->q_direction[0].band_data[j].energy_ratio_fx[k] = floatToFixed( hQMetaData->q_direction[0].band_data[j].energy_ratio[k], Q30 ); + /*=====================================flt-2-fix============================================*/ + + index = masa_sq_fx( L_sub( ONE_IN_Q30, hQMetaData->q_direction[0].band_data[j].energy_ratio_fx[k] ), diffuseness_thresholds_hr_fx, HR_MASA_ER_LEVELS ); +#else + index = masa_sq( 1.0f - hQMetaData->q_direction[0].band_data[j].energy_ratio[k], diffuseness_thresholds_hr, HR_MASA_ER_LEVELS ); +#endif + push_next_indice( hMetaData, index, MASA_BITS_ER_HR ); + hQMetaData->q_direction[0].band_data[j].energy_ratio_index[k] = index; + hQMetaData->q_direction[0].band_data[j].energy_ratio_index_mod[k] = index; + hQMetaData->q_direction[0].band_data[j].energy_ratio[k] = 1.0f - diffuseness_reconstructions_hr[index]; + needed_bits[0] += MASA_BITS_ER_HR; + hQMetaData->q_direction[0].band_data[j].bits_sph_idx[k] = bits_dir_hr; } } - real_GR_ord1 = 0; - if ( use_context == 0 ) + if ( hQMetaData->no_directions == 2 ) { - nbits = GR_bits_new( data, no_symb_local, no_data, GR_order, 1, real_GR_ord ); - nbits1 = nbits; - - min_val = data[0]; - for ( i = 1; i < no_data; i++ ) + float ratioSum; + if ( bits_dir_hr == 16 ) { - if ( data[i] < min_val ) + for ( j = hQMetaData->q_direction[1].cfg.start_band; j < hQMetaData->q_direction[1].cfg.nbands; j++ ) { - min_val = data[i]; - } + for ( k = 0; k < hQMetaData->q_direction[1].cfg.nblocks; k++ ) + { +#ifdef IVAS_FLOAT_FIXED + /*=====================================flt-2-fix============================================*/ + hQMetaData->q_direction[1].band_data[j].energy_ratio_fx[k] = floatToFixed( hQMetaData->q_direction[1].band_data[j].energy_ratio[k], Q30 ); + /*=====================================flt-2-fix============================================*/ + + index = masa_sq_fx( L_sub( ONE_IN_Q30, hQMetaData->q_direction[1].band_data[j].energy_ratio_fx[k] ), diffuseness_thresholds_hr_fx, HR_MASA_ER_LEVELS ); +#else + index = masa_sq( 1.0f - hQMetaData->q_direction[1].band_data[j].energy_ratio[k], diffuseness_thresholds_hr, HR_MASA_ER_LEVELS ); +#endif + push_next_indice( hMetaData, index, MASA_BITS_ER_HR ); + hQMetaData->q_direction[1].band_data[j].energy_ratio_index[k] = index; + hQMetaData->q_direction[1].band_data[j].energy_ratio[k] = 1.0f - diffuseness_reconstructions_hr[index]; + + ratioSum = hQMetaData->q_direction[0].band_data[j].energy_ratio[k] + hQMetaData->q_direction[1].band_data[j].energy_ratio[k]; + if ( ratioSum > 1.0f ) + { + hQMetaData->q_direction[0].band_data[j].energy_ratio[k] /= ratioSum; + hQMetaData->q_direction[1].band_data[j].energy_ratio[k] /= ratioSum; + } + + needed_bits[1] += MASA_BITS_ER_HR; + hQMetaData->q_direction[1].band_data[j].bits_sph_idx[k] = bits_dir_hr; + } + } } - for ( i = 0; i < no_data; i++ ) + else { - cdata[i] = data[i] - min_val; + int16_t pos_2dir_band[MASA_MAXIMUM_CODING_SUBBANDS]; + k = 0; + for ( j = hQMetaData->q_direction[0].cfg.start_band; j < hQMetaData->q_direction[0].cfg.nbands; j++ ) + { + if ( hQMetaData->twoDirBands[j] == 1 ) + { + pos_2dir_band[k] = j; + k++; + } + else + { + pos_2dir_band[k] = 0; + } + } + for ( j = hQMetaData->q_direction[1].cfg.start_band; j < hQMetaData->q_direction[1].cfg.nbands; j++ ) + { + for ( k = 0; k < hQMetaData->q_direction[1].cfg.nblocks; k++ ) + { +#ifdef IVAS_FLOAT_FIXED + /*=====================================flt-2-fix============================================*/ + hQMetaData->q_direction[1].band_data[j].energy_ratio_fx[k] = floatToFixed( hQMetaData->q_direction[1].band_data[j].energy_ratio[k], Q30 ); + /*=====================================flt-2-fix============================================*/ + + index = masa_sq_fx( L_sub( ONE_IN_Q30, hQMetaData->q_direction[1].band_data[j].energy_ratio_fx[k] ), diffuseness_thresholds_hr_fx, HR_MASA_ER_LEVELS ); +#else + index = masa_sq( 1.0f - hQMetaData->q_direction[1].band_data[j].energy_ratio[k], diffuseness_thresholds_hr, HR_MASA_ER_LEVELS ); +#endif + push_next_indice( hMetaData, index, MASA_BITS_ER_HR ); + hQMetaData->q_direction[1].band_data[j].energy_ratio_index[k] = index; + hQMetaData->q_direction[1].band_data[j].energy_ratio[k] = 1.0f - diffuseness_reconstructions_hr[index]; + + ratioSum = hQMetaData->q_direction[0].band_data[pos_2dir_band[j]].energy_ratio[k] + hQMetaData->q_direction[1].band_data[j].energy_ratio[k]; + + if ( ratioSum > 1.0f ) + { + hQMetaData->q_direction[0].band_data[pos_2dir_band[j]].energy_ratio[k] /= ratioSum; + hQMetaData->q_direction[1].band_data[j].energy_ratio[k] /= ratioSum; + } + + needed_bits[1] += MASA_BITS_ER_HR; + hQMetaData->q_direction[1].band_data[j].bits_sph_idx[k] = bits_dir_hr; + } + } } + } - maximum_s( no_symb_local, no_data, &max_val ); - nbits1 = GR_bits_new( cdata, no_symb_local, no_data, GR_order - 1, 1, &real_GR_ord1 ) + ivas_qmetadata_encode_extended_gr_length( min_val, max_val, MASA_GR_ORD_AZ ); + return; +} +#else +static void ivas_qmetadata_quantize_diffuseness_nrg_ratios_hr_512( + IVAS_QMETADATA_HANDLE hQMetaData, + int16_t *needed_bits, + const int16_t bits_dir_hr, + BSTR_ENC_HANDLE hMetaData ) +{ + int16_t j, k; + int16_t index; - if ( nbits1 < nbits ) + needed_bits[0] = 0; + needed_bits[1] = 0; + + for ( j = hQMetaData->q_direction[0].cfg.start_band; j < hQMetaData->q_direction[0].cfg.nbands; ++j ) + { + for ( k = 0; k < hQMetaData->q_direction[0].cfg.nblocks; k++ ) { - nbits = nbits1 + 1; - use_context = -2; - *real_GR_ord = real_GR_ord1; + index = masa_sq( 1.0f - hQMetaData->q_direction[0].band_data[j].energy_ratio[k], diffuseness_thresholds_hr, HR_MASA_ER_LEVELS ); + push_next_indice( hMetaData, index, MASA_BITS_ER_HR ); + hQMetaData->q_direction[0].band_data[j].energy_ratio_index[k] = index; + hQMetaData->q_direction[0].band_data[j].energy_ratio_index_mod[k] = index; + hQMetaData->q_direction[0].band_data[j].energy_ratio[k] = 1.0f - diffuseness_reconstructions_hr[index]; + needed_bits[0] += MASA_BITS_ER_HR; + hQMetaData->q_direction[0].band_data[j].bits_sph_idx[k] = bits_dir_hr; + } + } + + if ( hQMetaData->no_directions == 2 ) + { + float ratioSum; + if ( bits_dir_hr == 16 ) + { + for ( j = hQMetaData->q_direction[1].cfg.start_band; j < hQMetaData->q_direction[1].cfg.nbands; j++ ) + { + for ( k = 0; k < hQMetaData->q_direction[1].cfg.nblocks; k++ ) + { + index = masa_sq( 1.0f - hQMetaData->q_direction[1].band_data[j].energy_ratio[k], diffuseness_thresholds_hr, HR_MASA_ER_LEVELS ); + push_next_indice( hMetaData, index, MASA_BITS_ER_HR ); + hQMetaData->q_direction[1].band_data[j].energy_ratio_index[k] = index; + hQMetaData->q_direction[1].band_data[j].energy_ratio[k] = 1.0f - diffuseness_reconstructions_hr[index]; + + ratioSum = hQMetaData->q_direction[0].band_data[j].energy_ratio[k] + hQMetaData->q_direction[1].band_data[j].energy_ratio[k]; + if ( ratioSum > 1.0f ) + { + hQMetaData->q_direction[0].band_data[j].energy_ratio[k] /= ratioSum; + hQMetaData->q_direction[1].band_data[j].energy_ratio[k] /= ratioSum; + } + + needed_bits[1] += MASA_BITS_ER_HR; + hQMetaData->q_direction[1].band_data[j].bits_sph_idx[k] = bits_dir_hr; + } + } } else { - nbits = nbits + 1; - use_context = -1; + int16_t pos_2dir_band[MASA_MAXIMUM_CODING_SUBBANDS]; + k = 0; + for ( j = hQMetaData->q_direction[0].cfg.start_band; j < hQMetaData->q_direction[0].cfg.nbands; j++ ) + { + if ( hQMetaData->twoDirBands[j] == 1 ) + { + pos_2dir_band[k] = j; + k++; + } + else + { + pos_2dir_band[k] = 0; + } + } + for ( j = hQMetaData->q_direction[1].cfg.start_band; j < hQMetaData->q_direction[1].cfg.nbands; j++ ) + { + for ( k = 0; k < hQMetaData->q_direction[1].cfg.nblocks; k++ ) + { + index = masa_sq( 1.0f - hQMetaData->q_direction[1].band_data[j].energy_ratio[k], diffuseness_thresholds_hr, HR_MASA_ER_LEVELS ); + push_next_indice( hMetaData, index, MASA_BITS_ER_HR ); + hQMetaData->q_direction[1].band_data[j].energy_ratio_index[k] = index; + hQMetaData->q_direction[1].band_data[j].energy_ratio[k] = 1.0f - diffuseness_reconstructions_hr[index]; + + ratioSum = hQMetaData->q_direction[0].band_data[pos_2dir_band[j]].energy_ratio[k] + hQMetaData->q_direction[1].band_data[j].energy_ratio[k]; + + if ( ratioSum > 1.0f ) + { + hQMetaData->q_direction[0].band_data[pos_2dir_band[j]].energy_ratio[k] /= ratioSum; + hQMetaData->q_direction[1].band_data[j].energy_ratio[k] /= ratioSum; + } + + needed_bits[1] += MASA_BITS_ER_HR; + hQMetaData->q_direction[1].band_data[j].bits_sph_idx[k] = bits_dir_hr; + } + } } } - *p_use_context = use_context; - - return nbits; + return; } +#endif /*------------------------------------------------------------------------- - * mean_removed_GR_new() + * ivas_qmetadata_quantize_diffuseness_nrg_ratios() * - * Golomb Rice encoding with mean removing + * Quantize diffuseness *------------------------------------------------------------------------*/ -/*! r: number of bits used */ -static int16_t mean_removed_GR_new( - const uint16_t *idx, /* i : data to encode */ - const int16_t max_no_symb, - const int16_t len, /* i : number of data */ - const int16_t adapt_GR, /* i : flag for telling to use or nor two GR order values */ - int16_t *GR_ord, /* i/o: GR order */ - uint16_t *p_av, /* o : average index */ - uint16_t *mr_idx /* o : mean removed indexes */ -) +#ifdef IVAS_FLOAT_FIXED +static void ivas_qmetadata_quantize_diffuseness_nrg_ratios( + IVAS_QMETADATA_HANDLE hQMetaData, + int16_t *needed_bits, + int16_t *nbits_diff, + int16_t *dfRatioBits, + const int16_t hodirac_flag ) { - int16_t av, i, nbits; - int16_t sh_idx[MASA_MAXIMUM_CODING_SUBBANDS]; - int16_t max_ns[MASA_MAXIMUM_CODING_SUBBANDS]; + int16_t j, k, dir2band; + int16_t index_dirRatio1Inv, index_dirRatio2Inv, index_dirRatio1Inv_mod, index_dirRatio2Inv_mod; + int16_t index_diff; + + nbits_diff[0] = 0; + nbits_diff[1] = 0; + needed_bits[0] = 0; + needed_bits[1] = 0; + dir2band = 0; + + for ( j = hQMetaData->q_direction[0].cfg.start_band; j < hQMetaData->q_direction[0].cfg.nbands; ++j ) + { + if ( hQMetaData->no_directions == 2 && hQMetaData->twoDirBands[j] == 1 ) + { + float diffRatio, dfRatio, dfRatioQ, diffRatioQ, dirRatio1Q, dirRatio2Q; +#ifdef IVAS_FLOAT_FIXED + Word32 diffRatio_fx, dirRatio1Q_fx, dirRatio2Q_fx; +#endif + float dirRatio1, dirRatio2, sumRatio; + int16_t dfRatio_index, dfRatio_qsteps, dfRatio_bits; + + /* With 2dir metadata, we quantize and transmit diffuse-to-total ratio (diffRatio) and + * distribution factor of direct-to-total ratios (dFRatio). This is more efficient and + * accurate than simple separate quantization of each direct-to-total ratio or their + * separate inverses. */ + if ( hodirac_flag ) + { + /* already encoded as total and ratios in HO-DirAC */ + diffRatio = 1.f - hQMetaData->q_direction[0].band_data[j].energy_ratio[0]; + dfRatio = hQMetaData->q_direction[1].band_data[dir2band].energy_ratio[0]; + } + else + { + dirRatio1 = hQMetaData->q_direction[0].band_data[j].energy_ratio[0]; + dirRatio2 = hQMetaData->q_direction[1].band_data[dir2band].energy_ratio[0]; + sumRatio = dirRatio1 + dirRatio2; + diffRatio = 1.0f - sumRatio; + dfRatio = sumRatio < EPSILON ? 0.5f : dirRatio1 / sumRatio; + } + + +#ifdef IVAS_FLOAT_FIXED + /*=====================================flt-2-fix============================================*/ + diffRatio_fx = floatToFixed( diffRatio, Q30 ); + /*=====================================flt-2-fix============================================*/ + + index_diff = masa_sq_fx( diffRatio_fx, diffuseness_thresholds_fx, DIRAC_DIFFUSE_LEVELS ); +#else + index_diff = masa_sq( diffRatio, diffuseness_thresholds, DIRAC_DIFFUSE_LEVELS ); +#endif + diffRatioQ = diffuseness_reconstructions[index_diff]; + + if ( hodirac_flag ) + { + dfRatio_bits = ivas_get_df_ratio_bits_hodirac( index_diff ); + } + else + { + dfRatio_bits = ivas_get_df_ratio_bits( index_diff ); + } + + dfRatioBits[dir2band] = dfRatio_bits; + + dfRatio_qsteps = ( 1 << dfRatio_bits ); + if ( hodirac_flag ) + { + dfRatio_index = usquant( dfRatio, &dfRatioQ, 0.0f, 1.f / ( dfRatio_qsteps - 1 ), dfRatio_qsteps ); + dirRatio1Q = 1.f - diffRatioQ; + dirRatio2Q = dfRatioQ; + } + else + { + dfRatio_index = usquant( dfRatio, &dfRatioQ, 0.5f, 0.5f / ( dfRatio_qsteps - 1 ), dfRatio_qsteps ); + + /* Direction quantization requires also separately quantized direct-to-total ratios. Thus, we calculate them. */ + dirRatio1Q = dfRatioQ * ( 1.0f - diffRatioQ ); + dirRatio2Q = ( 1.0f - diffRatioQ ) - dirRatio1Q; + } + +#ifdef IVAS_FLOAT_FIXED + /*=====================================flt-2-fix============================================*/ + dirRatio1Q_fx = floatToFixed( dirRatio1Q, Q30 ); + /*=====================================flt-2-fix============================================*/ + + index_dirRatio1Inv = masa_sq_fx( L_sub( ONE_IN_Q30, dirRatio1Q_fx ), diffuseness_thresholds_fx, DIRAC_DIFFUSE_LEVELS ); +#else + index_dirRatio1Inv = masa_sq( 1.0f - dirRatio1Q, diffuseness_thresholds, DIRAC_DIFFUSE_LEVELS ); +#endif + + /* Note: To save memory, we store temporarily index_diff and dfRatio_index into first and second direction + * energy ratio index variables until they have been encoded. index_dirRatio1Inv and index_dirRatio2Inv are + * then later retrieved for further use in encoding. */ + for ( k = 0; k < hQMetaData->q_direction[0].cfg.nblocks; k++ ) + { + hQMetaData->q_direction[0].band_data[j].energy_ratio_index[k] = index_diff; + hQMetaData->q_direction[0].band_data[j].energy_ratio[k] = dirRatio1Q; + } + nbits_diff[0] += MASA_BITS_ER; + + if ( hodirac_flag ) + { + float tmp; + index_dirRatio2Inv = usquant( dirRatio2Q, &tmp, 0.0f, 1.f / ( DIRAC_DIFFUSE_LEVELS - 1 ), DIRAC_DIFFUSE_LEVELS ); + } + else + { +#ifdef IVAS_FLOAT_FIXED + /*=====================================flt-2-fix============================================*/ + dirRatio2Q_fx = floatToFixed( dirRatio2Q, Q30 ); + /*=====================================flt-2-fix============================================*/ + + index_dirRatio2Inv = masa_sq_fx( L_sub( ONE_IN_Q30, dirRatio2Q_fx ), diffuseness_thresholds_fx, DIRAC_DIFFUSE_LEVELS ); +#else + index_dirRatio2Inv = masa_sq( 1.0f - dirRatio2Q, diffuseness_thresholds, DIRAC_DIFFUSE_LEVELS ); +#endif + } + + for ( k = 0; k < hQMetaData->q_direction[1].cfg.nblocks; k++ ) + { + hQMetaData->q_direction[1].band_data[dir2band].energy_ratio_index[k] = dfRatio_index; + hQMetaData->q_direction[1].band_data[dir2band].energy_ratio[k] = dirRatio2Q; + } + nbits_diff[1] += dfRatio_bits; + + /* Obtain compensated direct-to-total ratios for direction quantization. This compensates for the + * fact that with 2dir data, it is harder to achieve separate high direct-to-total ratio values + * which are assumed by the direction quantization system. In practice, this improves direction + * accuracy when it is perceptual meaningful. */ +#ifdef IVAS_FLOAT_FIXED + masa_compensate_two_dir_energy_ratio_index_fx( index_dirRatio1Inv, index_dirRatio2Inv, &index_dirRatio1Inv_mod, &index_dirRatio2Inv_mod, hodirac_flag ); +#else + masa_compensate_two_dir_energy_ratio_index( index_dirRatio1Inv, index_dirRatio2Inv, &index_dirRatio1Inv_mod, &index_dirRatio2Inv_mod, hodirac_flag ); +#endif + + for ( k = 0; k < hQMetaData->q_direction[0].cfg.nblocks; k++ ) + { + hQMetaData->q_direction[0].band_data[j].energy_ratio_index_mod[k] = index_dirRatio1Inv_mod; + hQMetaData->q_direction[0].band_data[j].bits_sph_idx[k] = bits_direction_masa[index_dirRatio1Inv_mod]; + } + needed_bits[0] += hQMetaData->q_direction[0].cfg.nblocks * bits_direction_masa[index_dirRatio1Inv_mod]; + + for ( k = 0; k < hQMetaData->q_direction[1].cfg.nblocks; k++ ) + { + hQMetaData->q_direction[1].band_data[dir2band].energy_ratio_index_mod[k] = index_dirRatio2Inv_mod; + hQMetaData->q_direction[1].band_data[dir2band].bits_sph_idx[k] = bits_direction_masa[index_dirRatio2Inv_mod]; + } + needed_bits[1] += hQMetaData->q_direction[1].cfg.nblocks * bits_direction_masa[index_dirRatio2Inv_mod]; + + dir2band++; + } + else + { +#ifdef IVAS_FLOAT_FIXED + /*=====================================flt-2-fix============================================*/ + hQMetaData->q_direction[0].band_data[j].energy_ratio_fx[0] = floatToFixed( hQMetaData->q_direction[0].band_data[j].energy_ratio[0], Q30 ); + /*=====================================flt-2-fix============================================*/ + + index_dirRatio1Inv = masa_sq_fx( L_sub( ONE_IN_Q30, hQMetaData->q_direction[0].band_data[j].energy_ratio_fx[0] ), diffuseness_thresholds_fx, DIRAC_DIFFUSE_LEVELS ); +#else + index_dirRatio1Inv = masa_sq( 1.0f - hQMetaData->q_direction[0].band_data[j].energy_ratio[0], diffuseness_thresholds, DIRAC_DIFFUSE_LEVELS ); +#endif + + for ( k = 0; k < hQMetaData->q_direction[0].cfg.nblocks; k++ ) + { + hQMetaData->q_direction[0].band_data[j].energy_ratio_index[k] = index_dirRatio1Inv; + hQMetaData->q_direction[0].band_data[j].energy_ratio_index_mod[k] = index_dirRatio1Inv; + hQMetaData->q_direction[0].band_data[j].energy_ratio[k] = 1.0f - diffuseness_reconstructions[index_dirRatio1Inv]; + hQMetaData->q_direction[0].band_data[j].bits_sph_idx[k] = bits_direction_masa[index_dirRatio1Inv]; + } + + nbits_diff[0] += MASA_BITS_ER; + + needed_bits[0] += hQMetaData->q_direction[0].cfg.nblocks * bits_direction_masa[index_dirRatio1Inv]; + } + } + + return; +} +#else +static void ivas_qmetadata_quantize_diffuseness_nrg_ratios( + IVAS_QMETADATA_HANDLE hQMetaData, + int16_t *needed_bits, + int16_t *nbits_diff, + int16_t *dfRatioBits, + const int16_t hodirac_flag ) +{ + int16_t j, k, dir2band; + int16_t index_dirRatio1Inv, index_dirRatio2Inv, index_dirRatio1Inv_mod, index_dirRatio2Inv_mod; + int16_t index_diff; + + nbits_diff[0] = 0; + nbits_diff[1] = 0; + needed_bits[0] = 0; + needed_bits[1] = 0; + dir2band = 0; + + for ( j = hQMetaData->q_direction[0].cfg.start_band; j < hQMetaData->q_direction[0].cfg.nbands; ++j ) + { + if ( hQMetaData->no_directions == 2 && hQMetaData->twoDirBands[j] == 1 ) + { + float diffRatio, dfRatio, dfRatioQ, diffRatioQ, dirRatio1Q, dirRatio2Q; + float dirRatio1, dirRatio2, sumRatio; + int16_t dfRatio_index, dfRatio_qsteps, dfRatio_bits; + + /* With 2dir metadata, we quantize and transmit diffuse-to-total ratio (diffRatio) and + * distribution factor of direct-to-total ratios (dFRatio). This is more efficient and + * accurate than simple separate quantization of each direct-to-total ratio or their + * separate inverses. */ + if ( hodirac_flag ) + { + /* already encoded as total and ratios in HO-DirAC */ + diffRatio = 1.f - hQMetaData->q_direction[0].band_data[j].energy_ratio[0]; + dfRatio = hQMetaData->q_direction[1].band_data[dir2band].energy_ratio[0]; + } + else + { + dirRatio1 = hQMetaData->q_direction[0].band_data[j].energy_ratio[0]; + dirRatio2 = hQMetaData->q_direction[1].band_data[dir2band].energy_ratio[0]; + sumRatio = dirRatio1 + dirRatio2; + diffRatio = 1.0f - sumRatio; + dfRatio = sumRatio < EPSILON ? 0.5f : dirRatio1 / sumRatio; + } + + + index_diff = masa_sq( diffRatio, diffuseness_thresholds, DIRAC_DIFFUSE_LEVELS ); + diffRatioQ = diffuseness_reconstructions[index_diff]; + + if ( hodirac_flag ) + { + dfRatio_bits = ivas_get_df_ratio_bits_hodirac( index_diff ); + } + else + { + dfRatio_bits = ivas_get_df_ratio_bits( index_diff ); + } + + dfRatioBits[dir2band] = dfRatio_bits; + + dfRatio_qsteps = ( 1 << dfRatio_bits ); + if ( hodirac_flag ) + { + dfRatio_index = usquant( dfRatio, &dfRatioQ, 0.0f, 1.f / ( dfRatio_qsteps - 1 ), dfRatio_qsteps ); + dirRatio1Q = 1.f - diffRatioQ; + dirRatio2Q = dfRatioQ; + } + else + { + dfRatio_index = usquant( dfRatio, &dfRatioQ, 0.5f, 0.5f / ( dfRatio_qsteps - 1 ), dfRatio_qsteps ); + + /* Direction quantization requires also separately quantized direct-to-total ratios. Thus, we calculate them. */ + dirRatio1Q = dfRatioQ * ( 1.0f - diffRatioQ ); + dirRatio2Q = ( 1.0f - diffRatioQ ) - dirRatio1Q; + } + + index_dirRatio1Inv = masa_sq( 1.0f - dirRatio1Q, diffuseness_thresholds, DIRAC_DIFFUSE_LEVELS ); + + /* Note: To save memory, we store temporarily index_diff and dfRatio_index into first and second direction + * energy ratio index variables until they have been encoded. index_dirRatio1Inv and index_dirRatio2Inv are + * then later retrieved for further use in encoding. */ + for ( k = 0; k < hQMetaData->q_direction[0].cfg.nblocks; k++ ) + { + hQMetaData->q_direction[0].band_data[j].energy_ratio_index[k] = index_diff; + hQMetaData->q_direction[0].band_data[j].energy_ratio[k] = dirRatio1Q; + } + nbits_diff[0] += MASA_BITS_ER; + + if ( hodirac_flag ) + { + float tmp; + index_dirRatio2Inv = usquant( dirRatio2Q, &tmp, 0.0f, 1.f / ( DIRAC_DIFFUSE_LEVELS - 1 ), DIRAC_DIFFUSE_LEVELS ); + } + else + { + index_dirRatio2Inv = masa_sq( 1.0f - dirRatio2Q, diffuseness_thresholds, DIRAC_DIFFUSE_LEVELS ); + } + + for ( k = 0; k < hQMetaData->q_direction[1].cfg.nblocks; k++ ) + { + hQMetaData->q_direction[1].band_data[dir2band].energy_ratio_index[k] = dfRatio_index; + hQMetaData->q_direction[1].band_data[dir2band].energy_ratio[k] = dirRatio2Q; + } + nbits_diff[1] += dfRatio_bits; + + /* Obtain compensated direct-to-total ratios for direction quantization. This compensates for the + * fact that with 2dir data, it is harder to achieve separate high direct-to-total ratio values + * which are assumed by the direction quantization system. In practice, this improves direction + * accuracy when it is perceptual meaningful. */ + + masa_compensate_two_dir_energy_ratio_index( index_dirRatio1Inv, index_dirRatio2Inv, &index_dirRatio1Inv_mod, &index_dirRatio2Inv_mod, hodirac_flag ); + + for ( k = 0; k < hQMetaData->q_direction[0].cfg.nblocks; k++ ) + { + hQMetaData->q_direction[0].band_data[j].energy_ratio_index_mod[k] = index_dirRatio1Inv_mod; + hQMetaData->q_direction[0].band_data[j].bits_sph_idx[k] = bits_direction_masa[index_dirRatio1Inv_mod]; + } + needed_bits[0] += hQMetaData->q_direction[0].cfg.nblocks * bits_direction_masa[index_dirRatio1Inv_mod]; + + for ( k = 0; k < hQMetaData->q_direction[1].cfg.nblocks; k++ ) + { + hQMetaData->q_direction[1].band_data[dir2band].energy_ratio_index_mod[k] = index_dirRatio2Inv_mod; + hQMetaData->q_direction[1].band_data[dir2band].bits_sph_idx[k] = bits_direction_masa[index_dirRatio2Inv_mod]; + } + needed_bits[1] += hQMetaData->q_direction[1].cfg.nblocks * bits_direction_masa[index_dirRatio2Inv_mod]; + + dir2band++; + } + else + { + index_dirRatio1Inv = masa_sq( 1.0f - hQMetaData->q_direction[0].band_data[j].energy_ratio[0], diffuseness_thresholds, DIRAC_DIFFUSE_LEVELS ); + + for ( k = 0; k < hQMetaData->q_direction[0].cfg.nblocks; k++ ) + { + hQMetaData->q_direction[0].band_data[j].energy_ratio_index[k] = index_dirRatio1Inv; + hQMetaData->q_direction[0].band_data[j].energy_ratio_index_mod[k] = index_dirRatio1Inv; + hQMetaData->q_direction[0].band_data[j].energy_ratio[k] = 1.0f - diffuseness_reconstructions[index_dirRatio1Inv]; + hQMetaData->q_direction[0].band_data[j].bits_sph_idx[k] = bits_direction_masa[index_dirRatio1Inv]; + } + + nbits_diff[0] += MASA_BITS_ER; + + needed_bits[0] += hQMetaData->q_direction[0].cfg.nblocks * bits_direction_masa[index_dirRatio1Inv]; + } + } + + return; +} +#endif + + +/*------------------------------------------------------------------------- + * ivas_diffuseness_huff_ec_encode() + * + * + *------------------------------------------------------------------------*/ + +static int16_t ivas_diffuseness_huff_ec_encode( + BSTR_ENC_HANDLE hMetaData, + const uint16_t idx ) +{ + int16_t nbits; + nbits = 0; + if ( idx <= DIFF_EC_HUFF_GR0_LIMIT ) + { + if ( idx > 0 ) + { + push_next_indice( hMetaData, ( 1 << idx ) - 1, idx ); + nbits += idx; + } + push_next_indice( hMetaData, 0, 1 ); + nbits += 1; + } + else + { + push_next_indice( hMetaData, 511, DIFF_EC_HUFF_GR0_LIMIT + 1 ); + push_next_indice( hMetaData, idx - DIFF_EC_HUFF_GR0_LIMIT - 1, 2 ); + nbits += DIFF_EC_HUFF_GR0_LIMIT + 3; + } + return nbits; +} + + +/*------------------------------------------------------------------------- + * ivas_diffuseness_huff_ec_prepare() + * + * + *------------------------------------------------------------------------*/ + +static void ivas_diffuseness_huff_ec_prepare( + IVAS_QDIRECTION *q_direction, + int16_t *best_av, + uint16_t *avr_idx, + int16_t *diffuseness_bits_huff ) +{ + int16_t bits; + int16_t av_crt; + int16_t av; + int16_t sh_idx; + uint16_t ui_sh_idx[MASA_MAXIMUM_CODING_SUBBANDS]; + int16_t b, start_band, nbands; + + start_band = q_direction->cfg.start_band; + nbands = q_direction->cfg.nbands; + + *diffuseness_bits_huff = 0; + av = 0; + for ( b = start_band; b < nbands; b++ ) + { + av += q_direction->band_data[b].energy_ratio_index[0]; + } + av = (int16_t) ( 0.5f + av / (float) nbands ); + *best_av = av; + + *diffuseness_bits_huff = MAX16B; + for ( av_crt = av - 1; av_crt <= av + 1; av_crt++ ) + { + bits = 0; + for ( b = start_band; b < nbands; b++ ) + { + sh_idx = q_direction->band_data[b].energy_ratio_index[0] - av_crt; + ui_sh_idx[b] = ( sh_idx <= 0 ) ? ( -2 * sh_idx ) : sh_idx * 2 - 1; + if ( ui_sh_idx[b] >= 2 * DIRAC_DIFFUSE_LEVELS - 3 ) + { + bits = 100; /* to avoid difference larger than 6 in absolute value */ + } + + bits += ( ui_sh_idx[b] <= DIFF_EC_HUFF_GR0_LIMIT ) ? ( ui_sh_idx[b] + 1 ) : 11; + } + + if ( bits < *diffuseness_bits_huff ) + { + *diffuseness_bits_huff = bits; + mvs2s( (int16_t *) ui_sh_idx, (int16_t *) avr_idx, nbands ); + *best_av = av_crt; + } + } + + *diffuseness_bits_huff += MASA_BITS_ER; /* for the average */ + + return; +} + +/*------------------------------------------------------------------------- + * ivas_qmetadata_entropy_encode_diffuseness() + * + * encode diffuseness + *------------------------------------------------------------------------*/ + +static int16_t ivas_qmetadata_entropy_encode_diffuseness( + BSTR_ENC_HANDLE hMetaData, + IVAS_QDIRECTION *q_direction, + uint16_t *diffuseness_index_max_ec_frame ) +{ + int16_t start_bit_pos; + int16_t diffuseness_bits_raw; + int16_t b; + int16_t min_diffuseness_m_index, max_diffuseness_m_index; + int16_t nbands; + int16_t start_band; + + nbands = q_direction->cfg.nbands; + start_band = q_direction->cfg.start_band; + + start_bit_pos = hMetaData->nb_bits_tot; + + if ( nbands == 1 ) + { + /* If there is only one band, diffuseness should be coded directly as raw with no signaling. */ + push_next_indice( hMetaData, q_direction->band_data[0].energy_ratio_index[0], MASA_BITS_ER ); + *diffuseness_index_max_ec_frame = 5; + return ( hMetaData->nb_bits_tot - start_bit_pos ); + } + + /* compute the number of raw coding bits */ + diffuseness_bits_raw = 0; + for ( b = start_band; b < nbands; b++ ) + { + diffuseness_bits_raw += ivas_qmetadata_encode_quasi_uniform_length( q_direction->band_data[b].energy_ratio_index[0], DIRAC_DIFFUSE_LEVELS ); + } + + min_diffuseness_m_index = q_direction->band_data[start_band].energy_ratio_index[0]; + max_diffuseness_m_index = q_direction->band_data[start_band].energy_ratio_index[0]; + + for ( b = start_band; b < nbands; b++ ) + { + if ( q_direction->band_data[b].energy_ratio_index[0] < min_diffuseness_m_index ) + { + min_diffuseness_m_index = q_direction->band_data[b].energy_ratio_index[0]; + } + + if ( q_direction->band_data[b].energy_ratio_index[0] > max_diffuseness_m_index ) + { + max_diffuseness_m_index = q_direction->band_data[b].energy_ratio_index[0]; + } + } + + if ( nbands < DIFF_EC_HUFF_BAND_LIMIT ) + { + /* Use similarity coding approach or raw coding when there is a low number of bands. */ + /* one bit is used to indicate whether diffuseness values are entropy coded or coded raw */ + if ( min_diffuseness_m_index == max_diffuseness_m_index ) /* all values are equal */ + { + push_next_indice( hMetaData, 0, 1 ); /* dif_use_raw_coding */ + push_next_indice( hMetaData, 1, 1 ); /* dif_have_unique_value */ + ivas_qmetadata_encode_quasi_uniform( hMetaData, min_diffuseness_m_index, DIRAC_DIFFUSE_LEVELS ); /* dif_unique_value */ + } + else if ( min_diffuseness_m_index + 1 == max_diffuseness_m_index ) /* only two consecutive values are present */ + { + push_next_indice( hMetaData, 0, 1 ); /* dif_use_raw_coding */ + push_next_indice( hMetaData, 0, 1 ); /* dif_have_unique_value */ + ivas_qmetadata_encode_quasi_uniform( hMetaData, min_diffuseness_m_index, DIRAC_DIFFUSE_LEVELS - 1 ); /* dif_min_value */ + + for ( b = start_band; b < nbands; b++ ) + { + push_next_indice( hMetaData, q_direction->band_data[b].energy_ratio_index[0] - min_diffuseness_m_index, 1 ); /* dif_bit_offset_values */ + } + } + else /* raw coding */ + { + push_next_indice( hMetaData, 1, 1 ); /* dif_use_raw_coding */ + + for ( b = start_band; b < nbands; b++ ) + { + ivas_qmetadata_encode_quasi_uniform( hMetaData, q_direction->band_data[b].energy_ratio_index[0], DIRAC_DIFFUSE_LEVELS ); /* dif_values */ + } + } + } + else + { + /* Use Huffman-coding approach or raw coding when there is a high number of bands. */ + int16_t diffuseness_bits_huff; + int16_t best_av; + uint16_t avr_idx[MASA_MAXIMUM_CODING_SUBBANDS]; + + /* First, obtain average indices and bit usage for Huffman-coding. */ + ivas_diffuseness_huff_ec_prepare( q_direction, &best_av, avr_idx, &diffuseness_bits_huff ); + + /* If there is benefit, use Huffman-coding. Otherwise, use raw coding. */ + if ( diffuseness_bits_huff < diffuseness_bits_raw ) + { + /* Signal Huffman EC */ + push_next_indice( hMetaData, 0, 1 ); + push_next_indice( hMetaData, best_av, MASA_BITS_ER ); + for ( b = start_band; b < nbands; b++ ) + { + ivas_diffuseness_huff_ec_encode( hMetaData, avr_idx[b] ); + } + } + else + { + /* Signal raw */ + push_next_indice( hMetaData, 1, 1 ); + for ( b = start_band; b < nbands; b++ ) + { + ivas_qmetadata_encode_quasi_uniform( hMetaData, q_direction->band_data[b].energy_ratio_index[0], DIRAC_DIFFUSE_LEVELS ); /* dif_values */ + } + } + } + + *diffuseness_index_max_ec_frame = 5; + /* adaptively select the diffuseness_index_max_ec threshold */ + if ( min_diffuseness_m_index > 5 ) + { + *diffuseness_index_max_ec_frame = DIRAC_DIFFUSE_LEVELS - 1; + } + + + return ( hMetaData->nb_bits_tot - start_bit_pos ); +} + + +/*------------------------------------------------------------------------- + * ivas_qmetadata_entropy_encode_df_ratio() + * + * encode dfRatio + *------------------------------------------------------------------------*/ + +static int16_t ivas_qmetadata_entropy_encode_df_ratio( + BSTR_ENC_HANDLE hMetaData, + IVAS_QDIRECTION *q_direction, + int16_t *df_ratio_bits ) +{ + int16_t start_bit_pos; + int16_t bits_raw; + int16_t b; + int16_t min_index, max_index; + int16_t nbands, start_band; + int16_t max_df_ratio_bits; + int16_t ec_mode = 0; + int16_t max_alphabet_size; + + nbands = q_direction->cfg.nbands; + start_band = q_direction->cfg.start_band; + + start_bit_pos = hMetaData->nb_bits_tot; + + if ( nbands == 1 ) + { + /* If there is only one band, ratio should be coded directly as raw with no signaling. */ + push_next_indice( hMetaData, q_direction->band_data[0].energy_ratio_index[0], df_ratio_bits[0] ); + + return ( hMetaData->nb_bits_tot - start_bit_pos ); + } + + /* compute the number of raw coding bits */ + bits_raw = 0; + max_df_ratio_bits = 0; + for ( b = start_band; b < nbands; b++ ) + { + bits_raw += df_ratio_bits[b]; + max_df_ratio_bits = max( df_ratio_bits[b], max_df_ratio_bits ); + } + + min_index = q_direction->band_data[start_band].energy_ratio_index[0]; + max_index = q_direction->band_data[start_band].energy_ratio_index[0]; + for ( b = start_band; b < nbands; b++ ) + { + if ( q_direction->band_data[b].energy_ratio_index[0] < min_index ) + { + min_index = q_direction->band_data[b].energy_ratio_index[0]; + } + + if ( q_direction->band_data[b].energy_ratio_index[0] > max_index ) + { + max_index = q_direction->band_data[b].energy_ratio_index[0]; + } + } + + /* Decide what modes are possible */ + if ( bits_raw >= max_df_ratio_bits + 2 + nbands ) + { + ec_mode = 2; + } + else if ( bits_raw >= max_df_ratio_bits + 1 ) + { + ec_mode = 1; + } + else + { + ec_mode = 0; + } + max_alphabet_size = 1 << max_df_ratio_bits; + + if ( min_index == max_index && ec_mode > 0 ) /* all values are equal */ + { + push_next_indice( hMetaData, 0, 1 ); /* Signal between EC and raw */ + if ( ec_mode > 1 ) + { + /* Only use bit for signaling if necessary */ + push_next_indice( hMetaData, 0, 1 ); /* Signal between one value or bandwise diff mode */ + } + + ivas_qmetadata_encode_quasi_uniform( hMetaData, min_index, max_alphabet_size ); + } + else if ( min_index + 1 == max_index && ec_mode > 1 ) /* only two consecutive values are present */ + { + push_next_indice( hMetaData, 0, 1 ); + push_next_indice( hMetaData, 1, 1 ); + ivas_qmetadata_encode_quasi_uniform( hMetaData, min_index, max_alphabet_size - 1 ); + + for ( b = start_band; b < nbands; b++ ) + { + push_next_indice( hMetaData, q_direction->band_data[b].energy_ratio_index[0] - min_index, 1 ); /* Band-wise offset values */ + } + } + else /* raw coding */ + { + if ( ec_mode > 0 ) + { + push_next_indice( hMetaData, 1, 1 ); /* Only signal raw mode if not implicitly using it */ + } + + for ( b = start_band; b < nbands; b++ ) + { + ivas_qmetadata_encode_quasi_uniform( hMetaData, q_direction->band_data[b].energy_ratio_index[0], 1 << df_ratio_bits[b] ); /* dif_values */ + } + } + + return ( hMetaData->nb_bits_tot - start_bit_pos ); +} + + +/*------------------------------------------------------------------------- + * restore_metadata_buffer() + * + * Restore metadata buffer + *------------------------------------------------------------------------*/ + +void restore_metadata_buffer( + BSTR_ENC_HANDLE hMetaData, + const int16_t next_ind_start, + const int16_t bit_pos_start ) +{ + int16_t i; + + for ( i = next_ind_start; i < hMetaData->nb_ind_tot; i++ ) + { + hMetaData->ind_list[i].nb_bits = -1; + } + hMetaData->nb_bits_tot = bit_pos_start; + hMetaData->nb_ind_tot = next_ind_start; + + return; +} + + +/*------------------------------------------------------------------------- + * ivas_qmetadata_encode_quasi_uniform() + * + * encode value using a quasi-uniform code of b or b + 1 bits, where b = floor(log2(alphabet_size)) + *------------------------------------------------------------------------*/ + +static void ivas_qmetadata_encode_quasi_uniform( + BSTR_ENC_HANDLE hMetaData, + const uint16_t value, + const uint16_t alphabet_size ) +{ + int16_t bits; + uint16_t tresh; + + bits = 30 - norm_l( alphabet_size ); /* bits = floor(log2(alphabet_size)) */ + tresh = ( 1U << ( bits + 1 ) ) - alphabet_size; + + if ( value < tresh ) + { + push_next_indice( hMetaData, value, bits ); + } + else /* value >= tresh */ + { + push_next_indice( hMetaData, value + tresh, bits + 1 ); + } + + return; +} + + +/*-----------------------------------------------------------------------* + * GR encoder function definitions + *-----------------------------------------------------------------------*/ +/*------------------------------------------------------------------------- + * GR_bits_new() + * + * + *------------------------------------------------------------------------*/ + +/*! r: number of bits using Golomb Rice code */ +static int16_t GR_bits_new( + uint16_t *data, /* i : data to encode with GR */ + int16_t *no_symb, /* i : number of symbols for each component*/ + const int16_t no_data, /* i : number of input data */ + const int16_t GR_order, /* i : GR order to be used */ + const int16_t check_two_orders, /* i : check also coding with GR_order-1 */ + int16_t *real_GR_ord /* o : the GR order that has been used */ +) +{ + int16_t nbits = 0, i; + int16_t nbits1 = 0; + int16_t nb; + + for ( i = 0; i < no_data; i++ ) + { + nb = ivas_qmetadata_encode_extended_gr_length( data[i], no_symb[i], GR_order ); + nbits += nb; + } + + if ( check_two_orders == 1 ) + { + for ( i = 0; i < no_data; i++ ) + { + nb = ivas_qmetadata_encode_extended_gr_length( data[i], no_symb[i], GR_order - 1 ); + nbits1 += nb; + } + + if ( nbits1 < nbits ) + { + nbits = nbits1 + 1; + *real_GR_ord = GR_order - 1; + } + else + { + nbits += 1; + *real_GR_ord = GR_order; + } + } + else + { + *real_GR_ord = GR_order; + } + + return nbits; +} + + +/*------------------------------------------------------------------------- + * GR_bits_azimuth_context() + * + * Encoding azimuth indexes with GR code using context + *------------------------------------------------------------------------*/ + +/*! r: numer of bits used for coding */ +static int16_t GR_bits_azimuth_context( + uint16_t *data_in, /* i : data to be encoded */ + int16_t *no_symb, /* i : number of symbols for each component */ + const int16_t no_data_in, /* i : number of input data */ + const int16_t GR_order, /* i : GR order (GR_order or GR_order-1 are used ) */ + const uint16_t *bits_dir, /* i : bits for encoding the direction for each TF tile */ + int16_t *real_GR_ord, /* o : which GR order has been used */ + int16_t *p_use_context /* o : flag telling if context has been used or not */ +) +{ + int16_t i, nbits, nbits1, use_context; + uint16_t cdata[MAX_PARAM_SPATIAL_SUBFRAMES]; + uint16_t data[MAX_PARAM_SPATIAL_SUBFRAMES]; + int16_t min_val, max_val; + int16_t real_GR_ord1; + int16_t no_symb_local[MAX_PARAM_SPATIAL_SUBFRAMES]; + int16_t no_data = 0; + + for ( i = 0; i < no_data_in; i++ ) + { + if ( data_in[i] < MASA_NO_INDEX ) + { + no_symb_local[no_data] = no_symb[i]; + data[no_data++] = data_in[i]; + } + } + + if ( no_data == 0 ) + { + *p_use_context = -3; /* corresponding to nothing to be written */ + return 0; + } + + nbits = 0; + use_context = 0; + + for ( i = 0; i < no_data; i++ ) + { + if ( ( bits_dir[i] <= 1 ) ) + { + nbits += bits_dir[i]; + use_context = 1; + } + else + { + *real_GR_ord = GR_order - ( bits_dir[i] == 2 ); + nbits += ivas_qmetadata_encode_extended_gr_length( data[i], no_symb_local[i], *real_GR_ord ); + } + } + + real_GR_ord1 = 0; + if ( use_context == 0 ) + { + nbits = GR_bits_new( data, no_symb_local, no_data, GR_order, 1, real_GR_ord ); + nbits1 = nbits; + + min_val = data[0]; + for ( i = 1; i < no_data; i++ ) + { + if ( data[i] < min_val ) + { + min_val = data[i]; + } + } + for ( i = 0; i < no_data; i++ ) + { + cdata[i] = data[i] - min_val; + } + + maximum_s( no_symb_local, no_data, &max_val ); + nbits1 = GR_bits_new( cdata, no_symb_local, no_data, GR_order - 1, 1, &real_GR_ord1 ) + ivas_qmetadata_encode_extended_gr_length( min_val, max_val, MASA_GR_ORD_AZ ); + + if ( nbits1 < nbits ) + { + nbits = nbits1 + 1; + use_context = -2; + *real_GR_ord = real_GR_ord1; + } + else + { + nbits = nbits + 1; + use_context = -1; + } + } + + *p_use_context = use_context; + + return nbits; +} + + +/*------------------------------------------------------------------------- + * mean_removed_GR_new() + * + * Golomb Rice encoding with mean removing + *------------------------------------------------------------------------*/ + +/*! r: number of bits used */ +static int16_t mean_removed_GR_new( + const uint16_t *idx, /* i : data to encode */ + const int16_t max_no_symb, + const int16_t len, /* i : number of data */ + const int16_t adapt_GR, /* i : flag for telling to use or nor two GR order values */ + int16_t *GR_ord, /* i/o: GR order */ + uint16_t *p_av, /* o : average index */ + uint16_t *mr_idx /* o : mean removed indexes */ +) +{ + int16_t av, i, nbits; + int16_t sh_idx[MASA_MAXIMUM_CODING_SUBBANDS]; + int16_t max_ns[MASA_MAXIMUM_CODING_SUBBANDS]; + + av = (int16_t) ( 0.5f + sum_s( (const int16_t *) idx, len ) / (float) len ); + *p_av = av; + for ( i = 0; i < len; i++ ) + { + max_ns[i] = 2 * ( max_no_symb ); + sh_idx[i] = idx[i] - av; + } + + for ( i = 0; i < len; i++ ) + { + if ( sh_idx[i] < 0 ) + { + sh_idx[i] = -2 * sh_idx[i]; + } + else if ( sh_idx[i] > 0 ) + { + sh_idx[i] = sh_idx[i] * 2 - 1; + } + else + { + sh_idx[i] = 0; + } + mr_idx[i] = (uint16_t) sh_idx[i]; + } + + nbits = GR_bits_new( mr_idx, max_ns, len, *GR_ord, adapt_GR, GR_ord ); + + return nbits; +} + + +/*------------------------------------------------------------------------- + * ivas_qmetadata_encode_quasi_uniform_length() + * + *------------------------------------------------------------------------*/ + +static int16_t ivas_qmetadata_encode_quasi_uniform_length( + const uint16_t value, + const uint16_t alphabet_size ) +{ + int16_t bits; + uint16_t tresh; + + bits = 30 - norm_l( alphabet_size ); /* bits = floor(log2(alphabet_size)) */ + tresh = ( 1U << ( bits + 1 ) ) - alphabet_size; + + if ( value >= tresh ) + { + bits++; + } + + return bits; +} + + +/*------------------------------------------------------------------------- + * ivas_qmetadata_entropy_encode_dir() + * + * Main function for entropy coding of the directions + *------------------------------------------------------------------------*/ + +#ifdef IVAS_FLOAT_FIXED +static int16_t ivas_qmetadata_entropy_encode_dir( + BSTR_ENC_HANDLE hMetaData, + IVAS_QDIRECTION *q_direction, + const uint16_t diffuseness_index_max_ec_frame, + const int16_t nbands, + const int16_t start_band, + const int16_t direction_bits_raw, + int16_t max_bits, + const int16_t hrmasa_flag ) +{ + uint16_t diff_idx_min; + int16_t i, j; + int16_t nblocks; + + float avg_direction_vector[3], direction_vector[3], avg_azimuth, avg_elevation; +#ifdef IVAS_FLOAT_FIXED + Word32 /*avg_direction_vector_fx[3],*/ direction_vector_fx[3] /*, avg_azimuth_fx, avg_elevation_fx*/; +#endif + int16_t avg_azimuth_alphabet, avg_elevation_alphabet; + uint16_t avg_azimuth_index, avg_elevation_index; + int16_t avg_elevation_index_projected; + int16_t avg_azimuth_index_projected; + uint16_t avg_elevation_index_initial, avg_elevation_offset; + uint16_t avg_azimuth_index_initial, avg_azimuth_offset; + int16_t elevation_bits_ec_best, azimuth_bits_ec_best; + + int16_t gr_param_elevation_best = 0, avg_elevation_index_best = 0; + uint16_t dist_elevation_indexes_best[MAX_PARAM_SPATIAL_SUBFRAMES * MASA_MAXIMUM_CODING_SUBBANDS]; + int16_t gr_param_azimuth_best, avg_azimuth_index_best; + uint16_t dist_azimuth_indexes_best[MAX_PARAM_SPATIAL_SUBFRAMES * MASA_MAXIMUM_CODING_SUBBANDS]; + + uint16_t idx, dist_count; + int16_t direction_bits_ec; + + uint16_t dist_elevation_indexes[MAX_PARAM_SPATIAL_SUBFRAMES * MASA_MAXIMUM_CODING_SUBBANDS]; + uint16_t dist_elevation_alphabets[MAX_PARAM_SPATIAL_SUBFRAMES * MASA_MAXIMUM_CODING_SUBBANDS]; + uint16_t dist_azimuth_indexes[MAX_PARAM_SPATIAL_SUBFRAMES * MASA_MAXIMUM_CODING_SUBBANDS]; + uint16_t dist_azimuth_alphabets[MAX_PARAM_SPATIAL_SUBFRAMES * MASA_MAXIMUM_CODING_SUBBANDS]; + int16_t all_zero_dist_elevation_indexes = 1, all_zero_dist_azimuth_indexes = 1; + int16_t gr_param_elevation, gr_size_elevation, egr_size_elevation, gr_param_azimuth, gr_size_azimuth; + int16_t egr_size_azimuth, elevation_bits_ec, azimuth_bits_ec; + + float abs_theta; + float theta_cb[MAX_NO_THETA]; + int16_t sign_th, no_th; + int16_t avg_azimuth_index_upd = 0, use_adapt_avg; + int16_t make_gain = 0; + int16_t bits_gained = 0; + nblocks = q_direction->cfg.nblocks; + + /* estimate the number of bits for entropy coding of the direction values */ + direction_bits_ec = 0; + diff_idx_min = DIRAC_DIFFUSE_LEVELS; + idx = 0; + dist_count = 0; + set_zero( avg_direction_vector, 3 ); + + for ( i = start_band; i < nbands; i++ ) + { + if ( hrmasa_flag ) + { + diff_idx_min = 0; // min( q_direction->band_data[i].energy_ratio_index_mod[0]>>1, diff_idx_min ); + } + else + { + diff_idx_min = min( q_direction->band_data[i].energy_ratio_index_mod[0], diff_idx_min ); + } + + if ( q_direction->band_data[i].energy_ratio_index_mod[0] > diffuseness_index_max_ec_frame ) + { + /* estimate the raw part */ + if ( q_direction->not_in_2D > 0 ) + { + for ( j = 0; j < nblocks; j++ ) + { + direction_bits_ec += q_direction->band_data[i].bits_sph_idx[j]; + } + } + else + { + for ( j = 0; j < nblocks; j++ ) + { + direction_bits_ec += ivas_qmetadata_encode_quasi_uniform_length( q_direction->band_data[i].azimuth_index[j], q_direction->band_data[i].azimuth_m_alphabet[j] ); + } + } + } + else + { + dist_count += nblocks; + + for ( j = 0; j < nblocks; j++ ) + { + /*compute the average direction */ +#ifdef IVAS_FLOAT_FIXED + /*==========================================flt-2-fix======================================================*/ + q_direction->band_data[i].azimuth_fx[j] = floatToFixed( q_direction->band_data[i].azimuth[j], Q22 ); + q_direction->band_data[i].elevation_fx[j] = floatToFixed( q_direction->band_data[i].elevation[j], Q22 ); + /*==========================================flt-2-fix======================================================*/ + + ivas_qmetadata_azimuth_elevation_to_direction_vector_fx( q_direction->band_data[i].azimuth_fx[j], q_direction->band_data[i].elevation_fx[j], direction_vector_fx ); + + /*==========================================fix-2-flt======================================================*/ + fixedToFloat_arrL( direction_vector_fx, direction_vector, Q30, 3 ); + /*==========================================fix-2-flt======================================================*/ +#else + ivas_qmetadata_azimuth_elevation_to_direction_vector( q_direction->band_data[i].azimuth[j], q_direction->band_data[i].elevation[j], direction_vector ); +#endif + v_add( avg_direction_vector, direction_vector, avg_direction_vector, 3 ); + } + } + } + + /* quantize average elevation and azimuth angles using the best angle spacing and equatorial precision */ +#ifdef IVAS_FLOAT_FIXED_ + /*==========================================flt-2-fix======================================================*/ + Word16 q_dir_e = 0; + f2me_buf( avg_direction_vector, avg_direction_vector_fx, &q_dir_e, 3 ); + Scale_sig32( avg_direction_vector_fx, 3, -1 ); + /*==========================================flt-2-fix======================================================*/ + + ivas_qmetadata_direction_vector_to_azimuth_elevation_fx( avg_direction_vector_fx, Q30, &avg_azimuth_fx, &avg_elevation_fx ); + + /*==========================================fix-2-flt======================================================*/ + avg_azimuth = fixedToFloat( avg_azimuth_fx, Q22 ); + avg_elevation = fixedToFloat( avg_elevation_fx, Q22 ); + /*==========================================fix-2-flt======================================================*/ +#else + ivas_qmetadata_direction_vector_to_azimuth_elevation( avg_direction_vector, &avg_azimuth, &avg_elevation ); +#endif + + if ( q_direction->cfg.mc_ls_setup != MC_LS_SETUP_INVALID ) + { + avg_elevation_alphabet = no_theta_masa[bits_direction_masa[diff_idx_min] - 3]; + avg_azimuth_alphabet = no_phi_masa[bits_direction_masa[diff_idx_min] - 1][0]; /* average azimuth is quantized on the equatorial plane */ + } + else + { + avg_elevation_alphabet = no_theta_masa[bits_direction_masa[diff_idx_min] - 3] * 2 - 1; + avg_azimuth_alphabet = no_phi_masa[bits_direction_masa[diff_idx_min] - 1][0]; /* average azimuth is quantized on the equatorial plane */ + } + + no_th = no_theta_masa[bits_direction_masa[diff_idx_min] - 3]; + + for ( i = 0; i < no_th; i++ ) + { + theta_cb[i] = i * delta_theta_masa[bits_direction_masa[diff_idx_min] - 3]; + } + + if ( theta_cb[i - 1] > 90 ) + { + theta_cb[i - 1] = 90; + } + + if ( avg_elevation < 0 ) + { + abs_theta = -avg_elevation; + sign_th = -1; + } + else + { + abs_theta = avg_elevation; + sign_th = 1; + } + + avg_elevation_index = squant( abs_theta, &avg_elevation, theta_cb, no_th ); + + if ( q_direction->cfg.mc_ls_setup != MC_LS_SETUP_INVALID ) + { + assert( avg_elevation >= 0 ); + } + else + { + if ( sign_th < 0 ) + { + avg_elevation_index = ( avg_elevation_alphabet >> 1 ) - avg_elevation_index; + } + else + { + avg_elevation_index += ( avg_elevation_alphabet >> 1 ); + } + avg_elevation *= sign_th; + } + + avg_azimuth_index = (uint16_t) ( quantize_phi( avg_azimuth + 180, 0, &avg_azimuth, avg_azimuth_alphabet ) ); + + /* Elevation only if not 2D */ + if ( q_direction->not_in_2D > 0 ) + { + avg_elevation_index_initial = avg_elevation_index; + elevation_bits_ec_best = MAX16B; + avg_elevation_index_best = -1; /* out of range value */ + gr_param_elevation_best = -1; /* out of range value */ + + for ( avg_elevation_offset = 0; avg_elevation_offset < q_direction->cfg.search_effort; avg_elevation_offset++ ) + { + if ( q_direction->cfg.mc_ls_setup != MC_LS_SETUP_INVALID ) + { + avg_elevation_index = avg_elevation_index_initial + avg_elevation_offset; + } + else + { + avg_elevation_index = (uint16_t) ( avg_elevation_index_initial + ivas_qmetadata_dereorder_generic( avg_elevation_offset ) ); + } + avg_elevation_index = (uint16_t) ( ( avg_elevation_index + avg_elevation_alphabet ) % avg_elevation_alphabet ); + + all_zero_dist_elevation_indexes = 1; + if ( q_direction->cfg.mc_ls_setup != MC_LS_SETUP_INVALID ) + { + elevation_bits_ec = ivas_qmetadata_encode_quasi_uniform_length( avg_elevation_index, avg_elevation_alphabet ); + } + else + { + elevation_bits_ec = ivas_qmetadata_encode_quasi_uniform_length( ivas_qmetadata_reorder_generic( avg_elevation_index - ( avg_elevation_alphabet >> 1 ) ), avg_elevation_alphabet ); + } + idx = 0; + for ( i = start_band; i < nbands; i++ ) + { + if ( q_direction->band_data[i].energy_ratio_index_mod[0] <= diffuseness_index_max_ec_frame ) + { + for ( j = 0; j < nblocks; j++ ) + { + /* project the quantized average elevation to the same grid as the current sample */ + if ( q_direction->cfg.mc_ls_setup != MC_LS_SETUP_INVALID ) + { + avg_elevation_index_projected = ivas_chan_project_elevation_index( avg_elevation_index, avg_elevation_alphabet, q_direction->band_data[i].elevation_m_alphabet[j] ); + } + else + { + avg_elevation_index_projected = ivas_dirac_project_elevation_index( avg_elevation_index, avg_elevation_alphabet, q_direction->band_data[i].elevation_m_alphabet[j] ); + } + + if ( q_direction->cfg.mc_ls_setup != MC_LS_SETUP_INVALID ) + { + if ( q_direction->band_data[i].elevation_index[j] - avg_elevation_index_projected > 0 ) + { + dist_elevation_indexes[idx] = 2 * ( q_direction->band_data[i].elevation_index[j] - avg_elevation_index_projected ) - 1; + } + else + { + dist_elevation_indexes[idx] = -2 * ( q_direction->band_data[i].elevation_index[j] - avg_elevation_index_projected ); + } + } + else + { + dist_elevation_indexes[idx] = ivas_qmetadata_reorder_elevation_index( q_direction->band_data[i].elevation_index[j], avg_elevation_index_projected, q_direction->band_data[i].elevation_m_alphabet[j] ); + } + if ( q_direction->cfg.mc_ls_setup != MC_LS_SETUP_INVALID ) + { + dist_elevation_alphabets[idx] = 2 * q_direction->band_data[i].elevation_m_alphabet[j] - 1; + } + else + { + dist_elevation_alphabets[idx] = q_direction->band_data[i].elevation_m_alphabet[j]; + } + + if ( dist_elevation_indexes[idx] != 0 ) + { + all_zero_dist_elevation_indexes = 0; + } + idx++; + } + } + } + + if ( all_zero_dist_elevation_indexes ) + { + egr_size_elevation = 0; + gr_param_elevation = 4; + } + else + { + gr_param_elevation = ivas_qmetadata_get_optimal_gr_param( dist_elevation_indexes, idx, 4, &gr_size_elevation ); + egr_size_elevation = 0; + for ( i = 0; i < idx; i++ ) + { + egr_size_elevation += ivas_qmetadata_encode_extended_gr_length( dist_elevation_indexes[i], dist_elevation_alphabets[i], gr_param_elevation ); + } + } + elevation_bits_ec += ivas_qmetadata_encode_quasi_uniform_length( gr_param_elevation, 4 + 1 ) + egr_size_elevation; + + if ( elevation_bits_ec < elevation_bits_ec_best ) + { + elevation_bits_ec_best = elevation_bits_ec; + avg_elevation_index_best = avg_elevation_index; + gr_param_elevation_best = gr_param_elevation; + for ( idx = 0; idx < dist_count; idx++ ) + { + dist_elevation_indexes_best[idx] = dist_elevation_indexes[idx]; + } + } + } + + direction_bits_ec += elevation_bits_ec_best; + } + + /*Azimuth*/ + use_adapt_avg = 0; + if ( ( nbands - start_band >= 5 ) && ( q_direction->cfg.mc_ls_setup != MC_LS_SETUP_INVALID ) && ( nblocks > 1 ) ) + { + use_adapt_avg = calc_var_azi( q_direction, diffuseness_index_max_ec_frame, avg_azimuth - 180, &avg_azimuth ); + avg_azimuth_index = (uint16_t) ( quantize_phi( avg_azimuth + 180, 0, &avg_azimuth, avg_azimuth_alphabet ) ); + } + avg_azimuth_index_initial = avg_azimuth_index; /* avg_azimuth_index;*/ + azimuth_bits_ec_best = MAX16B; + avg_azimuth_index_best = -1; /* out of range value */ + gr_param_azimuth_best = -1; /* out of range value */ + + for ( avg_azimuth_offset = 0; avg_azimuth_offset < q_direction->cfg.search_effort; avg_azimuth_offset++ ) + { + set_zero( avg_direction_vector, 3 ); + avg_azimuth_index = (uint16_t) ( avg_azimuth_index_initial + ivas_qmetadata_dereorder_generic( avg_azimuth_offset ) ); + avg_azimuth_index = (uint16_t) ( ( avg_azimuth_index + avg_azimuth_alphabet ) % avg_azimuth_alphabet ); + all_zero_dist_azimuth_indexes = 1; + azimuth_bits_ec = ivas_qmetadata_encode_quasi_uniform_length( ivas_qmetadata_reorder_generic( avg_azimuth_index - ( avg_azimuth_alphabet >> 1 ) ), avg_azimuth_alphabet ); + + idx = 0; + for ( i = start_band; i < nbands; i++ ) + { + if ( q_direction->band_data[i].energy_ratio_index_mod[0] <= diffuseness_index_max_ec_frame ) + { + for ( j = 0; j < nblocks; j++ ) + { + + if ( ( idx > MASA_LIMIT_IDX_AVG_AZI ) && ( q_direction->cfg.mc_ls_setup != MC_LS_SETUP_INVALID ) && ( use_adapt_avg == 1 ) ) + { + avg_azimuth_index_projected = ivas_dirac_project_azimuth_index( avg_azimuth_index_upd, avg_azimuth_alphabet, q_direction->band_data[i].azimuth_m_alphabet[j] ); + } + else + { + if ( ( q_direction->cfg.mc_ls_setup != MC_LS_SETUP_INVALID ) && ( use_adapt_avg == 1 ) ) + { +#ifdef IVAS_FLOAT_FIXED + /*==========================================flt-2-fix======================================================*/ + q_direction->band_data[i].azimuth_fx[j] = floatToFixed( q_direction->band_data[i].azimuth[j], Q22 ); + q_direction->band_data[i].elevation_fx[j] = floatToFixed( q_direction->band_data[i].elevation[j], Q22 ); + /*==========================================flt-2-fix======================================================*/ + + ivas_qmetadata_azimuth_elevation_to_direction_vector_fx( q_direction->band_data[i].azimuth_fx[j], q_direction->band_data[i].elevation_fx[j], direction_vector_fx ); + + /*==========================================fix-2-flt======================================================*/ + fixedToFloat_arrL( direction_vector_fx, direction_vector, Q30, 3 ); + /*==========================================fix-2-flt======================================================*/ +#else + ivas_qmetadata_azimuth_elevation_to_direction_vector( q_direction->band_data[i].azimuth[j], q_direction->band_data[i].elevation[j], direction_vector ); +#endif + if ( idx < 4 ) + { + v_add( avg_direction_vector, direction_vector, avg_direction_vector, 3 ); + } + } + /* project the quantized average azimuth angle to the same grid as the current sample */ + avg_azimuth_index_projected = ivas_dirac_project_azimuth_index( avg_azimuth_index, avg_azimuth_alphabet, q_direction->band_data[i].azimuth_m_alphabet[j] ); + } + dist_azimuth_indexes[idx] = ivas_qmetadata_reorder_azimuth_index( ivas_qmetadata_dereorder_generic( q_direction->band_data[i].azimuth_index[j] ) + ( q_direction->band_data[i].azimuth_m_alphabet[j] >> 1 ), avg_azimuth_index_projected, q_direction->band_data[i].azimuth_m_alphabet[j] ); + dist_azimuth_alphabets[idx] = q_direction->band_data[i].azimuth_m_alphabet[j]; + + if ( dist_azimuth_indexes[idx] != 0 ) + { + all_zero_dist_azimuth_indexes = 0; + } + + if ( ( idx >= MASA_LIMIT_IDX_AVG_AZI ) && ( q_direction->cfg.mc_ls_setup != MC_LS_SETUP_INVALID ) && ( use_adapt_avg == 1 ) ) + { + if ( idx % nblocks == 0 ) + { + v_multc( avg_direction_vector, 0.5f, avg_direction_vector, 3 ); + } + + /*compute the average direction per already coded subband */ +#ifdef IVAS_FLOAT_FIXED + /*==========================================flt-2-fix======================================================*/ + q_direction->band_data[i].azimuth_fx[j] = floatToFixed( q_direction->band_data[i].azimuth[j], Q22 ); + q_direction->band_data[i].elevation_fx[j] = floatToFixed( q_direction->band_data[i].elevation[j], Q22 ); + /*==========================================flt-2-fix======================================================*/ + + ivas_qmetadata_azimuth_elevation_to_direction_vector_fx( q_direction->band_data[i].azimuth_fx[j], q_direction->band_data[i].elevation_fx[j], direction_vector_fx ); + + /*==========================================fix-2-flt======================================================*/ + fixedToFloat_arrL( direction_vector_fx, direction_vector, Q30, 3 ); + /*==========================================fix-2-flt======================================================*/ +#else + ivas_qmetadata_azimuth_elevation_to_direction_vector( q_direction->band_data[i].azimuth[j], q_direction->band_data[i].elevation[j], direction_vector ); +#endif + v_add( avg_direction_vector, direction_vector, avg_direction_vector, 3 ); +#ifdef IVAS_FLOAT_FIXED_ + /*==========================================flt-2-fix======================================================*/ + q_dir_e = 0; + f2me_buf( avg_direction_vector, avg_direction_vector_fx, &q_dir_e, 3 ); + Scale_sig32( avg_direction_vector_fx, 3, -1 ); + /*==========================================flt-2-fix======================================================*/ + + ivas_qmetadata_direction_vector_to_azimuth_elevation_fx( avg_direction_vector_fx, Q30, &avg_azimuth_fx, &avg_elevation_fx ); + + /*==========================================fix-2-flt======================================================*/ + avg_azimuth = fixedToFloat( avg_azimuth_fx, Q22 ); + avg_elevation = fixedToFloat( avg_elevation_fx, Q22 ); + /*==========================================fix-2-flt======================================================*/ +#else + ivas_qmetadata_direction_vector_to_azimuth_elevation( avg_direction_vector, &avg_azimuth, &avg_elevation ); +#endif + avg_azimuth_index_upd = quantize_phi( avg_azimuth + 180, 0, &avg_azimuth, avg_azimuth_alphabet ); + } + idx++; + } + } + } + + if ( all_zero_dist_azimuth_indexes ) + { + egr_size_azimuth = 0; + gr_param_azimuth = 5; + } + else + { + /* estimate the ExtendedGR part for azimuth */ + gr_param_azimuth = ivas_qmetadata_get_optimal_gr_param( dist_azimuth_indexes, idx, 5, &gr_size_azimuth ); + egr_size_azimuth = 0; + for ( i = 0; i < idx; i++ ) + { + egr_size_azimuth += ivas_qmetadata_encode_extended_gr_length( dist_azimuth_indexes[i], dist_azimuth_alphabets[i], gr_param_azimuth ); + } + } + + azimuth_bits_ec += ivas_qmetadata_encode_quasi_uniform_length( gr_param_azimuth, 5 + 1 ) + egr_size_azimuth; + + if ( azimuth_bits_ec < azimuth_bits_ec_best ) + { + azimuth_bits_ec_best = azimuth_bits_ec; + avg_azimuth_index_best = avg_azimuth_index; + gr_param_azimuth_best = gr_param_azimuth; + + for ( idx = 0; idx < dist_count; idx++ ) + { + dist_azimuth_indexes_best[idx] = dist_azimuth_indexes[idx]; + } + } + } - av = (int16_t) ( 0.5f + sum_s( (const int16_t *) idx, len ) / (float) len ); - *p_av = av; - for ( i = 0; i < len; i++ ) + if ( ( q_direction->cfg.mc_ls_setup != MC_LS_SETUP_INVALID ) && ( dist_count > 4 ) && ( gr_param_azimuth_best != 5 ) && ( nblocks > 1 ) ) { - max_ns[i] = 2 * ( max_no_symb ); - sh_idx[i] = idx[i] - av; + azimuth_bits_ec_best += 1; } - for ( i = 0; i < len; i++ ) + direction_bits_ec += azimuth_bits_ec_best; + + /*Decision raw or EC*/ + /* one bit is used to indicate whether the direction values are entropy coded or coded raw */ + if ( direction_bits_ec < direction_bits_raw ) /* entropy coding is better */ { - if ( sh_idx[i] < 0 ) + + /* encode the raw part first */ + for ( i = start_band; i < nbands; i++ ) { - sh_idx[i] = -2 * sh_idx[i]; + if ( q_direction->band_data[i].energy_ratio_index_mod[0] > diffuseness_index_max_ec_frame ) + { + if ( q_direction->not_in_2D > 0 ) + { + for ( j = 0; j < nblocks; j++ ) + { + push_next_indice( hMetaData, q_direction->band_data[i].spherical_index[j], q_direction->band_data[i].bits_sph_idx[j] ); + } + } + else + { + for ( j = 0; j < nblocks; j++ ) + { + ivas_qmetadata_encode_quasi_uniform( hMetaData, q_direction->band_data[i].azimuth_index[j], q_direction->band_data[i].azimuth_m_alphabet[j] ); + } + } + } } - else if ( sh_idx[i] > 0 ) + + if ( nbands > 1 && direction_bits_ec - max_bits > 0 && direction_bits_ec - max_bits < nblocks * nbands ) { - sh_idx[i] = sh_idx[i] * 2 - 1; + make_gain = 1; } - else + + if ( q_direction->not_in_2D > 0 ) { - sh_idx[i] = 0; - } - mr_idx[i] = (uint16_t) sh_idx[i]; - } + /* encode the ExtendedGR part for elevation */ + if ( q_direction->cfg.mc_ls_setup != MC_LS_SETUP_INVALID ) + { + ivas_qmetadata_encode_quasi_uniform( hMetaData, avg_elevation_index_best, avg_elevation_alphabet ); + } + else + { + ivas_qmetadata_encode_quasi_uniform( hMetaData, ivas_qmetadata_reorder_generic( avg_elevation_index_best - ( avg_elevation_alphabet >> 1 ) ), avg_elevation_alphabet ); + } - nbits = GR_bits_new( mr_idx, max_ns, len, *GR_ord, adapt_GR, GR_ord ); + ivas_qmetadata_encode_quasi_uniform( hMetaData, gr_param_elevation_best, 4 + 1 ); - return nbits; -} + if ( gr_param_elevation_best != 4 ) /* not all zero */ + { + for ( idx = 0; idx < dist_count; idx++ ) + { + ivas_qmetadata_encode_extended_gr( hMetaData, dist_elevation_indexes_best[idx], dist_elevation_alphabets[idx], gr_param_elevation_best ); + } + } + } + /* encode the ExtendedGR part for azimuth */ + ivas_qmetadata_encode_quasi_uniform( hMetaData, ivas_qmetadata_reorder_generic( avg_azimuth_index_best - ( avg_azimuth_alphabet >> 1 ) ), avg_azimuth_alphabet ); -/*------------------------------------------------------------------------- - * ivas_qmetadata_encode_quasi_uniform_length() - * - *------------------------------------------------------------------------*/ + ivas_qmetadata_encode_quasi_uniform( hMetaData, gr_param_azimuth_best, 5 + 1 ); -static int16_t ivas_qmetadata_encode_quasi_uniform_length( - const uint16_t value, - const uint16_t alphabet_size ) -{ - int16_t bits; - uint16_t tresh; + if ( gr_param_azimuth_best != 5 ) /* not all zero */ + { + for ( idx = 0; idx < min( nblocks, dist_count ); idx++ ) + { + if ( make_gain == 1 && bits_gained < direction_bits_ec - max_bits && dist_azimuth_alphabets[idx] > 40 ) + { + if ( dist_azimuth_indexes_best[idx] > 1 ) + { + ivas_qmetadata_encode_extended_gr( hMetaData, dist_azimuth_indexes_best[idx] - 2, dist_azimuth_alphabets[idx], gr_param_azimuth_best ); + bits_gained += ivas_qmetadata_encode_extended_gr_length( dist_azimuth_indexes_best[idx], dist_azimuth_alphabets[idx], gr_param_azimuth_best ) - + ivas_qmetadata_encode_extended_gr_length( dist_azimuth_indexes_best[idx] - 2, dist_azimuth_alphabets[idx], gr_param_azimuth_best ); + } + else if ( dist_azimuth_indexes_best[idx] == 1 ) + { + ivas_qmetadata_encode_extended_gr( hMetaData, dist_azimuth_indexes_best[idx] - 1, dist_azimuth_alphabets[idx], gr_param_azimuth_best ); + bits_gained += ivas_qmetadata_encode_extended_gr_length( dist_azimuth_indexes_best[idx], dist_azimuth_alphabets[idx], gr_param_azimuth_best ) - + ivas_qmetadata_encode_extended_gr_length( dist_azimuth_indexes_best[idx] - 1, dist_azimuth_alphabets[idx], gr_param_azimuth_best ); + } + else + { + ivas_qmetadata_encode_extended_gr( hMetaData, dist_azimuth_indexes_best[idx], dist_azimuth_alphabets[idx], gr_param_azimuth_best ); + } + } + else + { + ivas_qmetadata_encode_extended_gr( hMetaData, dist_azimuth_indexes_best[idx], dist_azimuth_alphabets[idx], gr_param_azimuth_best ); + } + } - bits = 30 - norm_l( alphabet_size ); /* bits = floor(log2(alphabet_size)) */ - tresh = ( 1U << ( bits + 1 ) ) - alphabet_size; + if ( dist_count > nblocks ) + { + if ( ( q_direction->cfg.mc_ls_setup != MC_LS_SETUP_INVALID ) && ( nblocks > 1 ) ) + { + push_next_indice( hMetaData, use_adapt_avg, 1 ); + } + for ( idx = nblocks; idx < dist_count; idx++ ) + { + if ( make_gain == 1 && bits_gained < direction_bits_ec - max_bits && dist_azimuth_alphabets[idx] > 40 ) + { + if ( dist_azimuth_indexes_best[idx] > 1 ) + { + ivas_qmetadata_encode_extended_gr( hMetaData, dist_azimuth_indexes_best[idx] - 2, dist_azimuth_alphabets[idx], gr_param_azimuth_best ); + bits_gained += ivas_qmetadata_encode_extended_gr_length( dist_azimuth_indexes_best[idx], dist_azimuth_alphabets[idx], gr_param_azimuth_best ) - + ivas_qmetadata_encode_extended_gr_length( dist_azimuth_indexes_best[idx] - 2, dist_azimuth_alphabets[idx], gr_param_azimuth_best ); + } + else if ( dist_azimuth_indexes_best[idx] == 1 ) + { + ivas_qmetadata_encode_extended_gr( hMetaData, dist_azimuth_indexes_best[idx] - 1, dist_azimuth_alphabets[idx], gr_param_azimuth_best ); + bits_gained += ivas_qmetadata_encode_extended_gr_length( dist_azimuth_indexes_best[idx], dist_azimuth_alphabets[idx], gr_param_azimuth_best ) - + ivas_qmetadata_encode_extended_gr_length( dist_azimuth_indexes_best[idx] - 1, dist_azimuth_alphabets[idx], gr_param_azimuth_best ); + } + else + { + ivas_qmetadata_encode_extended_gr( hMetaData, dist_azimuth_indexes_best[idx], dist_azimuth_alphabets[idx], gr_param_azimuth_best ); + } + } + else + { + ivas_qmetadata_encode_extended_gr( hMetaData, dist_azimuth_indexes_best[idx], dist_azimuth_alphabets[idx], gr_param_azimuth_best ); + } + } + } + } - if ( value >= tresh ) + direction_bits_ec -= bits_gained; + } + else { - bits++; + direction_bits_ec = -1; } - return bits; + return direction_bits_ec; } - - -/*------------------------------------------------------------------------- - * ivas_qmetadata_entropy_encode_dir() - * - * Main function for entropy coding of the directions - *------------------------------------------------------------------------*/ - +#else static int16_t ivas_qmetadata_entropy_encode_dir( BSTR_ENC_HANDLE hMetaData, IVAS_QDIRECTION *q_direction, @@ -2435,6 +3994,7 @@ static int16_t ivas_qmetadata_entropy_encode_dir( return direction_bits_ec; } +#endif /*------------------------------------------------------------------------- @@ -3296,31 +4856,128 @@ static int16_t encode_directions_subband( &q_direction->band_data[j].elevation_index[k], &q_direction->band_data[j].azimuth_index[k], q_direction->cfg.mc_ls_setup ); } - if ( allowed_bits > 0 ) - { - nbits = write_fixed_rate_direction( hMetaData, q_direction, j, no_subframes ); - } - } - } + if ( allowed_bits > 0 ) + { + nbits = write_fixed_rate_direction( hMetaData, q_direction, j, no_subframes ); + } + } + } + } + else + { + set_f( q_direction->band_data[j].elevation, 0.0f, no_subframes ); + set_f( q_direction->band_data[j].azimuth, 0.0f, no_subframes ); + } + + *p_diff = diff; + + return nbits; +} + + +/*-------------------------------------------------------------------* + * calc_var_azi() + * + * + *-------------------------------------------------------------------*/ + +#ifdef IVAS_FLOAT_FIXED +static int16_t calc_var_azi( + const IVAS_QDIRECTION *q_direction, + const int16_t diffuseness_index_max_ec_frame, + const float avg_azimuth, + float *avg_azimuth_out ) +{ + float var_band, dif; + float avg_direction_vector_band[3], avg_azimuth_band[24], direction_vector[3]; + float avg_elevation; +#ifdef IVAS_FLOAT_FIXED + Word32 /* avg_direction_vector_band_fx[3], avg_azimuth_band_fx[24],*/ direction_vector_fx[3]; + // Word32 avg_elevation_fx; +#endif + int16_t i, j, idx; + + idx = 0; + set_zero( avg_azimuth_band, 24 ); + + for ( i = 0; i < q_direction->cfg.nbands; i++ ) + { + set_zero( avg_direction_vector_band, 3 ); + if ( q_direction->band_data[i].energy_ratio_index_mod[0] <= diffuseness_index_max_ec_frame ) + { + for ( j = 0; j < q_direction->cfg.nblocks; j++ ) + { + /*compute the average direction */ +#ifdef IVAS_FLOAT_FIXED + /*==========================================flt-2-fix======================================================*/ + q_direction->band_data[i].azimuth_fx[j] = floatToFixed( q_direction->band_data[i].azimuth[j], Q22 ); + q_direction->band_data[i].elevation_fx[j] = floatToFixed( q_direction->band_data[i].elevation[j], Q22 ); + /*==========================================flt-2-fix======================================================*/ + + ivas_qmetadata_azimuth_elevation_to_direction_vector_fx( q_direction->band_data[i].azimuth_fx[j], q_direction->band_data[i].elevation_fx[j], direction_vector_fx ); + + /*==========================================fix-2-flt======================================================*/ + fixedToFloat_arrL( direction_vector_fx, direction_vector, Q30, 3 ); + /*==========================================fix-2-flt======================================================*/ +#else + ivas_qmetadata_azimuth_elevation_to_direction_vector( q_direction->band_data[i].azimuth[j], q_direction->band_data[i].elevation[j], direction_vector ); +#endif + v_add( avg_direction_vector_band, direction_vector, avg_direction_vector_band, 3 ); + } +#ifdef IVAS_FLOAT_FIXED_ + /*==========================================flt-2-fix======================================================*/ + Word16 q_dir_e = 0; + f2me_buf( avg_direction_vector_band, avg_direction_vector_band_fx, &q_dir_e, 3 ); + Scale_sig32( avg_direction_vector_band_fx, 3, -1 ); + /*==========================================flt-2-fix======================================================*/ + + ivas_qmetadata_direction_vector_to_azimuth_elevation_fx( avg_direction_vector_band_fx, Q30, &avg_azimuth_band_fx[idx], &avg_elevation_fx ); + + /*==========================================fix-2-flt======================================================*/ + avg_azimuth_band[idx] = fixedToFloat( avg_azimuth_band_fx[idx], Q22 ); + // avg_elevation = fixedToFloat( avg_elevation_fx, Q22 ); + /*==========================================fix-2-flt======================================================*/ +#else + ivas_qmetadata_direction_vector_to_azimuth_elevation( avg_direction_vector_band, &avg_azimuth_band[idx], &avg_elevation ); +#endif + idx++; + } + } + + var_band = 0.0f; + + for ( i = 0; i < idx; i++ ) + { + dif = ( avg_azimuth_band[idx] - avg_azimuth ); + if ( dif < 0 ) + { + dif = -dif; + } + if ( dif > 180 ) + { + dif = 360 - dif; + } + + var_band += dif * dif; + } + + if ( idx > 0 ) + { + var_band = var_band / idx; + } + + if ( var_band <= VAR_AZI_THRESH ) + { + *avg_azimuth_out = avg_azimuth; + return 0; } else { - set_f( q_direction->band_data[j].elevation, 0.0f, no_subframes ); - set_f( q_direction->band_data[j].azimuth, 0.0f, no_subframes ); + *avg_azimuth_out = avg_azimuth_band[0]; + return 1; } - - *p_diff = diff; - - return nbits; } - - -/*-------------------------------------------------------------------* - * calc_var_azi() - * - * - *-------------------------------------------------------------------*/ - +#else static int16_t calc_var_azi( const IVAS_QDIRECTION *q_direction, const int16_t diffuseness_index_max_ec_frame, @@ -3384,6 +5041,7 @@ static int16_t calc_var_azi( return 1; } } +#endif /*-------------------------------------------------------------------* @@ -4246,54 +5904,260 @@ static int16_t encode_spread_coherence_1sf( no_idx16 = (int16_t) round_f( ( nbits_fr1 / 16.0f + 0.5f ) ); } - assert( no_idx16 <= 4 ); + assert( no_idx16 <= 4 ); + + k = nbits_fr1; + for ( i = 0; i < no_idx16 - 1; i++ ) + { + k -= 16; + push_next_indice( hMasaMetaData, ( ( idx1 >> k ) & 65535 ), 16 ); /* 16 bits */ + } + push_next_indice( hMasaMetaData, ( idx1 & ( ( 1 << k ) - 1 ) ), k ); + } + } + else + { + /* write flag */ + nbits = 1; + + /* write flag*/ + push_next_indice( hMasaMetaData, 1, 1 ); + + /* write GR_ord */ + push_next_indice( hMasaMetaData, GR_ord, 1 ); + nbits += 1; + + /* write the min */ + bits_GR = hMasaMetaData->nb_bits_tot; + ivas_qmetadata_encode_extended_gr( hMasaMetaData, min_idx, MASA_MAX_NO_CV_SUR_COH + extra_cv, 0 ); + nbits += hMasaMetaData->nb_bits_tot - bits_GR; + + /* write GR data */ + for ( j = 0; j < idx_shift; j++ ) + { + bits_GR = hMasaMetaData->nb_bits_tot; + ivas_qmetadata_encode_extended_gr( hMasaMetaData, mr_idx_sp_coh[j], no_cv_shift[j], GR_ord ); + nbits += hMasaMetaData->nb_bits_tot - bits_GR; + } + } + + return nbits; +} + + +/*-------------------------------------------------------------------* + * encode_surround_coherence() + * + * encoding surround coherence + *-------------------------------------------------------------------*/ + +/*! r: number of bits written */ +#ifdef IVAS_FLOAT_FIXED +static int16_t encode_surround_coherence( + IVAS_QMETADATA *hQMetaData, /* i : quantized metadata */ + BSTR_ENC_HANDLE hMetaData /* i/o: metadata bitstream handle */ +) +{ + int16_t i, j, k; + int16_t idx_ER, idx16; + int16_t nbits, nbits_fr; + uint16_t idx_sur_coh[MASA_MAXIMUM_CODING_SUBBANDS]; + uint16_t mr_idx_sur_coh[MASA_MAXIMUM_CODING_SUBBANDS]; + int16_t GR_ord, bits_GR; + uint64_t idx, idx1; + int16_t no_idx16; + int16_t no_cv[MASA_MAXIMUM_CODING_SUBBANDS]; + float error_ratio_surr; +#ifdef IVAS_FLOAT_FIXED + Word32 error_ratio_surr_fx; +#endif + IVAS_QDIRECTION *q_direction; + int16_t half_coding_subbands, nbits_fr1, coding_subbands; + int16_t all_coherence_zero; + uint16_t idx_sur_coh_shift[MASA_MAXIMUM_CODING_SUBBANDS]; + uint8_t idx_shift; + int16_t max_val = 0, nbits_max; + int16_t no_cv_shift[MASA_MAXIMUM_CODING_SUBBANDS], min_idx; + + coding_subbands = hQMetaData->q_direction[0].cfg.nbands; + all_coherence_zero = hQMetaData->all_coherence_zero; + q_direction = &( hQMetaData->q_direction[0] ); + nbits = 0; + + if ( all_coherence_zero == 1 ) + { + nbits = 0; + } + else + { + GR_ord = 1; + k = 0; + idx_shift = 0; + for ( j = 0; j < coding_subbands; j++ ) + { + if ( hQMetaData->no_directions == 2 ) + { + k += hQMetaData->twoDirBands[j]; + idx16 = max( k - 1, 0 ); + error_ratio_surr = 1.0f - q_direction[0].band_data[j].energy_ratio[0] - q_direction[1].band_data[idx16].energy_ratio[0] * hQMetaData->twoDirBands[j]; + } + else + { + error_ratio_surr = 1.0f - q_direction[0].band_data[j].energy_ratio[0]; + } + + if ( error_ratio_surr <= 0 ) + { + error_ratio_surr = 0; + idx_sur_coh[j] = 0; + no_cv[j] = 1; + hQMetaData->surcoh_band_data[j].surround_coherence[0] = 0; /* sur_coherence_cb_masa[idx_cb_sur_coh_masa[DIRAC_DIFFUSE_LEVELS - 1] * MASA_MAX_NO_CV_SUR_COH]; */ + } + else + { +#ifdef IVAS_FLOAT_FIXED + /*=====================================flt-2-fix============================================*/ + error_ratio_surr_fx = floatToFixed( error_ratio_surr, Q30 ); + /*=====================================flt-2-fix============================================*/ + + idx_ER = masa_sq_fx( error_ratio_surr_fx, diffuseness_thresholds_fx, DIRAC_DIFFUSE_LEVELS ); +#else + idx_ER = masa_sq( error_ratio_surr, diffuseness_thresholds, DIRAC_DIFFUSE_LEVELS ); +#endif + + idx_sur_coh[j] = squant_int( hQMetaData->surcoh_band_data[j].surround_coherence[0], &hQMetaData->surcoh_band_data[j].surround_coherence[0], + &sur_coherence_cb_masa[idx_cb_sur_coh_masa[idx_ER] * MASA_MAX_NO_CV_SUR_COH], idx_cb_sur_coh_masa[idx_ER] + 2 ); + + no_cv[j] = idx_cb_sur_coh_masa[idx_ER] + 2; + no_cv_shift[idx_shift] = no_cv[j]; + idx_sur_coh_shift[idx_shift++] = idx_sur_coh[j]; + } + } + + if ( sum_s( no_cv, coding_subbands ) == coding_subbands ) + { + return 0; + } + + nbits_max = 0; + if ( coding_subbands > MASA_LIMIT_NO_BANDS_SUR_COH ) + { + j = maximum_s( (int16_t *) idx_sur_coh, coding_subbands, &max_val ); + for ( j = 0; j < coding_subbands; j++ ) + { + if ( no_cv[j] > max_val + 1 ) + { + no_cv[j] = max_val + 1; + } + } + nbits_max = MASA_MAX_NO_CV_SUR_COH - max_val; /* encoded with GR0 as max_no_vals - no_vals*/ + } + + nbits = coherence_coding_length( idx_sur_coh_shift, idx_shift, coding_subbands, no_cv, + mr_idx_sur_coh, no_cv_shift, &min_idx, &GR_ord, &nbits_fr, &nbits_fr1 ); + half_coding_subbands = coding_subbands / 2; + idx1 = 0; + + /* should check how to encode the average - check distribution */ + if ( nbits_fr + nbits_fr1 + nbits_max < nbits ) + { + /* write flag*/ + push_next_indice( hMetaData, 0, 1 ); + + /* create combined index */ + nbits = nbits_fr + nbits_fr1 + 1; + if ( coding_subbands > MASA_LIMIT_NO_BANDS_SUR_COH ) + { + /* write max value*/ + bits_GR = hMetaData->nb_bits_tot; + ivas_qmetadata_encode_extended_gr( hMetaData, MASA_MAX_NO_CV_SUR_COH - max_val - 1, MASA_MAX_NO_CV_SUR_COH, 0 ); + nbits += hMetaData->nb_bits_tot - bits_GR; + } + + if ( nbits_fr1 > 0 ) + { + idx = create_combined_index( idx_sur_coh, half_coding_subbands, no_cv ); + idx1 = create_combined_index( &idx_sur_coh[half_coding_subbands], half_coding_subbands, &no_cv[half_coding_subbands] ); + } + else + { + idx = create_combined_index( idx_sur_coh, coding_subbands, no_cv ); + } + + if ( nbits_fr % 16 == 0 ) + { + no_idx16 = nbits_fr / 16; + } + else + { + no_idx16 = (int16_t) round_f( ( nbits_fr / 16.0f + 0.5f ) ); + } + + /* write combined index */ + k = nbits_fr; + for ( i = 0; i < no_idx16 - 1; i++ ) + { + k -= 16; + push_next_indice( hMetaData, ( ( idx >> k ) & 65535 ), 16 ); /* 16 bits */ + } + + push_next_indice( hMetaData, ( idx & ( ( 1 << k ) - 1 ) ), k ); + + if ( nbits_fr1 > 0 ) + { + if ( nbits_fr1 % 16 == 0 ) + { + no_idx16 = nbits_fr1 / 16; + } + else + { + no_idx16 = (int16_t) round_f( ( nbits_fr1 / 16.0f + 0.5f ) ); + } + + assert( no_idx16 <= 4 ); + + k = nbits_fr1; + for ( i = 0; i < no_idx16 - 1; i++ ) + { + k -= 16; + push_next_indice( hMetaData, ( ( idx1 >> k ) & 65535 ), 16 ); /* 16 bits */ + } + + push_next_indice( hMetaData, ( idx1 & ( ( 1 << k ) - 1 ) ), k ); + } + } + else + { + /* write flag */ + nbits = 1; + + /* write flag*/ + push_next_indice( hMetaData, 1, 1 ); + + /* write GR_ord */ + push_next_indice( hMetaData, GR_ord, 1 ); + nbits += 1; + + /* write the min */ + bits_GR = hMetaData->nb_bits_tot; + ivas_qmetadata_encode_extended_gr( hMetaData, min_idx, MASA_MAX_NO_CV_SUR_COH, 0 ); + nbits += hMetaData->nb_bits_tot - bits_GR; - k = nbits_fr1; - for ( i = 0; i < no_idx16 - 1; i++ ) + /* write GR data */ + for ( j = 0; j < idx_shift; j++ ) { - k -= 16; - push_next_indice( hMasaMetaData, ( ( idx1 >> k ) & 65535 ), 16 ); /* 16 bits */ - } - push_next_indice( hMasaMetaData, ( idx1 & ( ( 1 << k ) - 1 ) ), k ); - } - } - else - { - /* write flag */ - nbits = 1; - - /* write flag*/ - push_next_indice( hMasaMetaData, 1, 1 ); - - /* write GR_ord */ - push_next_indice( hMasaMetaData, GR_ord, 1 ); - nbits += 1; + bits_GR = hMetaData->nb_bits_tot; - /* write the min */ - bits_GR = hMasaMetaData->nb_bits_tot; - ivas_qmetadata_encode_extended_gr( hMasaMetaData, min_idx, MASA_MAX_NO_CV_SUR_COH + extra_cv, 0 ); - nbits += hMasaMetaData->nb_bits_tot - bits_GR; + ivas_qmetadata_encode_extended_gr( hMetaData, mr_idx_sur_coh[j], no_cv_shift[j], GR_ord ); - /* write GR data */ - for ( j = 0; j < idx_shift; j++ ) - { - bits_GR = hMasaMetaData->nb_bits_tot; - ivas_qmetadata_encode_extended_gr( hMasaMetaData, mr_idx_sp_coh[j], no_cv_shift[j], GR_ord ); - nbits += hMasaMetaData->nb_bits_tot - bits_GR; + nbits += hMetaData->nb_bits_tot - bits_GR; + } } } return nbits; } - - -/*-------------------------------------------------------------------* - * encode_surround_coherence() - * - * encoding surround coherence - *-------------------------------------------------------------------*/ - -/*! r: number of bits written */ +#else static int16_t encode_surround_coherence( IVAS_QMETADATA *hQMetaData, /* i : quantized metadata */ BSTR_ENC_HANDLE hMetaData /* i/o: metadata bitstream handle */ @@ -4487,6 +6351,7 @@ static int16_t encode_surround_coherence( return nbits; } +#endif static int16_t encode_surround_coherence_hr( @@ -4931,6 +6796,214 @@ static int16_t ivas_qmetadata_quantize_coherence_hr_512( *-------------------------------------------------------------------*/ /*! r: number of bits written */ +#ifdef IVAS_FLOAT_FIXED +static int16_t ivas_qmetadata_quantize_coherence( + IVAS_QMETADATA *hQMetaData, /* i/o: quantized metadata */ + const int16_t idx_d, /* i : current direction index */ + const int16_t all_coherence_zero, /* i : all coherence is zero - flag */ + BSTR_ENC_HANDLE hMetaData, /* i : metadata handle */ + const int16_t write_flag, /* i : flag to actually write the data or not */ + int16_t *indice_coherence, + const int16_t hrmasa_flag /* i : flag indicating high-rate MASA MD coding */ +) +{ + int16_t j, k; + float dct_coh[MASA_MAXIMUM_CODING_SUBBANDS][MAX_PARAM_SPATIAL_SUBFRAMES]; +#ifdef IVAS_FLOAT_FIXED + Word32 dct_coh_fx[MASA_MAXIMUM_CODING_SUBBANDS][MAX_PARAM_SPATIAL_SUBFRAMES]; +#endif + uint16_t idx_dct[MAX_PARAM_SPATIAL_SUBFRAMES * MASA_MAXIMUM_CODING_SUBBANDS]; + int16_t coding_subbands; + int16_t nbits; + uint64_t no_cb; + int16_t MASA_grouping[MASA_MAXIMUM_CODING_SUBBANDS]; + int16_t nbits1; + int16_t coding_subbands_0, d; + int16_t two_dir_band[MASA_MAXIMUM_CODING_SUBBANDS]; + int16_t no_cb_vec[MASA_MAXIMUM_CODING_SUBBANDS]; + IVAS_QDIRECTION *q_direction; + int16_t min_index; + min_index = 0; + q_direction = &( hQMetaData->q_direction[idx_d] ); + coding_subbands = q_direction->cfg.nbands; + nbits = 0; + + if ( all_coherence_zero == 1 ) + { + return nbits; + } + + if ( hQMetaData->q_direction[idx_d].cfg.nblocks == 1 ) + { + nbits = encode_spread_coherence_1sf( hQMetaData, idx_d, hMetaData, hrmasa_flag ); + + return nbits; + } + else + { + k = 0; + no_cb = 1; + coding_subbands_0 = hQMetaData->q_direction[0].cfg.nbands; + if ( coding_subbands_0 <= 5 ) + { + for ( j = 0; j < 5; j++ ) + { + MASA_grouping[j] = j; + } + } + else + { + if ( coding_subbands_0 <= 8 ) + { + mvs2s( MASA_grouping_8_to_5, MASA_grouping, 8 ); + } + else if ( coding_subbands_0 <= 12 ) + { + mvs2s( MASA_grouping_12_to_5, MASA_grouping, 12 ); + } + else if ( coding_subbands_0 <= 18 ) + { + mvs2s( MASA_grouping_18_to_5, MASA_grouping, 18 ); + } + else + { + if ( coding_subbands_0 <= 24 ) + { + mvs2s( MASA_grouping_24_to_5, MASA_grouping, 24 ); + } + } + } + + if ( coding_subbands < coding_subbands_0 ) + { + d = 0; + for ( j = 0; j < coding_subbands_0; j++ ) + { + if ( hQMetaData->twoDirBands[j] == 1 ) + { + two_dir_band[d++] = j; + } + } + } + + for ( j = 0; j < coding_subbands; j++ ) + { + /* DCT transform */ + dct4_transform( hQMetaData->q_direction[idx_d].coherence_band_data[j].spread_coherence, dct_coh[j] ); + + if ( hrmasa_flag ) + { + minimum_s( (int16_t *) ( q_direction->band_data[j].energy_ratio_index ), q_direction->cfg.nblocks, &min_index ); + no_cb_vec[j] = len_cb_dct0_masa[min_index >> 1]; + } + else + { + no_cb_vec[j] = len_cb_dct0_masa[q_direction->band_data[j].energy_ratio_index[0]]; + } + + if ( write_flag ) + { + /* quantize first DCT parameter */ + dct_coh[j][0] = quantize_DCT_0_coh( dct_coh[j][0], j, coherence_cb0_masa, MASA_DELTA_AZI_DCT0, MASA_NO_CV_COH, q_direction, &idx_dct[k], &no_cb_vec[j], hrmasa_flag ); + } + + if ( coding_subbands < coding_subbands_0 ) + { + idx_dct[k + coding_subbands] = squant( dct_coh[j][1], &dct_coh[j][1], &coherence_cb1_masa[MASA_grouping[two_dir_band[j]] * MASA_NO_CV_COH1], MASA_NO_CV_COH1 ); + } + else + { + idx_dct[k + coding_subbands] = squant( dct_coh[j][1], &dct_coh[j][1], &coherence_cb1_masa[MASA_grouping[j] * MASA_NO_CV_COH1], MASA_NO_CV_COH1 ); + } + k++; + + dct_coh[j][2] = 0.0f; + dct_coh[j][3] = 0.0f; + } + + nbits1 = 0; + if ( sum_s( no_cb_vec, coding_subbands ) > MASA_COH_LIMIT_2IDX ) + { + /* make two indxes */ + no_cb = 1; + + for ( j = 0; j < coding_subbands / 2; j++ ) + { + no_cb *= no_cb_vec[j]; + } + + nbits = (int16_t) ceilf( logf( (float) no_cb ) * INV_LOG_2 ); + no_cb = 1; + + for ( j = coding_subbands / 2; j < coding_subbands; j++ ) + { + no_cb *= no_cb_vec[j]; + } + nbits1 = (int16_t) ceilf( logf( (float) no_cb ) * INV_LOG_2 ); + } + else + { + no_cb = 1; + + for ( j = 0; j < coding_subbands; j++ ) + { + no_cb *= no_cb_vec[j]; + } + + nbits = (int16_t) ceilf( logf( (float) no_cb ) * INV_LOG_2 ); + } + + if ( write_flag ) + { + for ( j = 0; j < coding_subbands; j++ ) + { + /* inverse DCT transform */ + +#ifdef IVAS_FLOAT_FIXED + + /*================================flt-2-fix========================================*/ + floatToFixed_arrL( dct_coh[j], dct_coh_fx[j], Q21, MAX_PARAM_SPATIAL_SUBFRAMES ); // Q21 is used in decoder hence chosed otherwise function can work with variable Q + /*================================fix-2-flt========================================*/ + + invdct4_transform_fx( dct_coh_fx[j], q_direction->coherence_band_data[j].spread_coherence, Q21 ); +#else + invdct4_transform( dct_coh[j], q_direction->coherence_band_data[j].spread_coherence ); +#endif + } + + nbits = encode_coherence_indexesDCT0( idx_dct, coding_subbands, no_cb_vec, hMetaData, *indice_coherence, nbits, nbits1 ); + } + else + { + /* write dummy data now and save the position */ + *indice_coherence = hMetaData->nb_ind_tot; + k = nbits; + while ( k > 0 ) + { + push_next_indice( hMetaData, 0, min( 16, k ) ); + k -= 16; + } + + if ( nbits1 > 0 ) + { + k = nbits1; + while ( k > 0 ) + { + push_next_indice( hMetaData, 0, min( 16, k ) ); + k -= 16; + } + } + nbits += nbits1; + set_s( no_cb_vec, MASA_NO_CV_COH1, coding_subbands ); + nbits += encode_coherence_indexesDCT1( &idx_dct[coding_subbands], coding_subbands, hMetaData ); + + return nbits; + } + } + + return nbits; +} +#else static int16_t ivas_qmetadata_quantize_coherence( IVAS_QMETADATA *hQMetaData, /* i/o: quantized metadata */ const int16_t idx_d, /* i : current direction index */ @@ -5124,6 +7197,7 @@ static int16_t ivas_qmetadata_quantize_coherence( return nbits; } +#endif /*-------------------------------------------------------------------* diff --git a/lib_enc/ivas_stereo_cng_enc.c b/lib_enc/ivas_stereo_cng_enc.c index 3763c8761..f8fa5aea4 100644 --- a/lib_enc/ivas_stereo_cng_enc.c +++ b/lib_enc/ivas_stereo_cng_enc.c @@ -42,6 +42,9 @@ #include "ivas_rom_com.h" #include "wmc_auto.h" #include "prot_fx1.h" +#ifdef IVAS_FLOAT_FIXED +#include "ivas_prot_fx.h" +#endif /*------------------------------------------------------------------- @@ -406,7 +409,11 @@ void stereo_dft_cng_side_gain( /* Use coarse band partitioning in inactive frames */ /* Rescale bands to the coarser partitioning taking the band size into account */ mvs2s( hStereoDft->band_limits, band_limits_full, STEREO_DFT_BAND_MAX + 1 ); +#ifndef IVAS_FLOAT_FIXED hStereoDft->nbands = stereo_dft_band_config( hStereoDft->band_limits, hStereoDft->hConfig->band_res, min( STEREO_DFT_N_32k_ENC, NFFT_inner ), ENC ); +#else + hStereoDft->nbands = stereo_dft_band_config_fx( hStereoDft->band_limits, hStereoDft->hConfig->band_res, s_min( STEREO_DFT_N_32k_ENC, NFFT_inner ), ENC ); +#endif if ( nbands_full > hStereoDft->nbands + 1 ) { for ( b = 0; b < hStereoDft->nbands; b++ ) diff --git a/lib_enc/ivas_stereo_dft_enc.c b/lib_enc/ivas_stereo_dft_enc.c index e25bc7d5e..2d48fa86d 100644 --- a/lib_enc/ivas_stereo_dft_enc.c +++ b/lib_enc/ivas_stereo_dft_enc.c @@ -281,7 +281,11 @@ ivas_error stereo_dft_enc_create( hStereoDft_loc->hConfig->force_mono_transmission = 0; +#ifndef IVAS_FLOAT_FIXED stereo_dft_config( hStereoDft_loc->hConfig, IVAS_24k4, &tmpS, &tmpS ); +#else + stereo_dft_config_fx( hStereoDft_loc->hConfig, IVAS_24k4, &tmpS, &tmpS ); +#endif stereo_dft_enc_open( hStereoDft_loc, input_Fs, max_bwidth ); @@ -416,8 +420,13 @@ static void stereo_dft_enc_open( /*Bands: find the number of bands, Nyquist freq. is not taken into account*/ NFFT_inner = STEREO_DFT_N_MAX_ENC * inner_frame_tbl[max_bwidth] / L_FRAME48k; +#ifndef IVAS_FLOAT_FIXED hStereoDft->nbands = stereo_dft_band_config( hStereoDft->band_limits, hStereoDft->hConfig->band_res, NFFT_inner, ENC ); hStereoDft->nbands_dmx = stereo_dft_band_config( hStereoDft->band_limits_dmx, 1, NFFT_inner, ENC ); +#else + hStereoDft->nbands = stereo_dft_band_config_fx( hStereoDft->band_limits, hStereoDft->hConfig->band_res, NFFT_inner, ENC ); + hStereoDft->nbands_dmx = stereo_dft_band_config_fx( hStereoDft->band_limits_dmx, 1, NFFT_inner, ENC ); +#endif /*Set configuration*/ set_s( hStereoDft->band_res, hStereoDft->hConfig->band_res, STEREO_DFT_ENC_DFT_NB ); @@ -911,8 +920,13 @@ void stereo_dft_enc_update( /* update band limits in case of rate switching assuming max_bwidth as BWD output not yet know here */ NFFT_inner = STEREO_DFT_N_MAX_ENC * inner_frame_tbl[max_bwidth] / L_FRAME48k; +#ifndef IVAS_FLOAT_FIXED hStereoDft->nbands = stereo_dft_band_config( hStereoDft->band_limits, hStereoDft->hConfig->band_res, NFFT_inner, ENC ); hStereoDft->nbands_dmx = stereo_dft_band_config( hStereoDft->band_limits_dmx, 1, NFFT_inner, ENC ); +#else + hStereoDft->nbands = stereo_dft_band_config_fx( hStereoDft->band_limits, hStereoDft->hConfig->band_res, NFFT_inner, ENC ); + hStereoDft->nbands_dmx = stereo_dft_band_config_fx( hStereoDft->band_limits_dmx, 1, NFFT_inner, ENC ); +#endif /*Compute main parameters*/ hStereoDft->gipd_band_max = dft_band_ipd[1][3]; @@ -2155,7 +2169,11 @@ void stereo_dft_enc_write_BS( } /* set number of bands according to bandwidth after BWD */ +#ifndef IVAS_FLOAT_FIXED hStereoDft->nbands = stereo_dft_band_config( hStereoDft->band_limits, hStereoDft->band_res[k_offset], NFFT_inner, ENC ); +#else + hStereoDft->nbands = stereo_dft_band_config_fx( hStereoDft->band_limits, hStereoDft->band_res[k_offset], NFFT_inner, ENC ); +#endif if ( core_brate == FRAME_NO_DATA ) { diff --git a/lib_enc/ivas_stereo_mdct_core_enc.c b/lib_enc/ivas_stereo_mdct_core_enc.c index 3c4b324c4..73081c98a 100644 --- a/lib_enc/ivas_stereo_mdct_core_enc.c +++ b/lib_enc/ivas_stereo_mdct_core_enc.c @@ -39,6 +39,9 @@ #include "ivas_prot.h" #include "rom_com.h" #include "wmc_auto.h" +#ifdef IVAS_FLOAT_FIXED +#include "ivas_prot_fx.h" +#endif /*-------------------------------------------------------------------* * sync_tcx_mode() @@ -186,11 +189,19 @@ void stereo_mdct_core_enc( if ( hCPE->hCoreCoder[0]->igf ) { +#ifndef IVAS_FLOAT_FIXED initMdctStereoEncData( hCPE->hStereoMdct, STEREO_FORMAT, IVAS_CPE_MDCT, hCPE->element_brate, hCPE->hCoreCoder[0]->bwidth, hCPE->hCoreCoder[0]->igf, hCPE->hCoreCoder[0]->hIGFEnc->igfData.igfInfo.grid, 0 ); stereo_mdct_init_igf_start_band( &( hCPE->hStereoMdct->stbParamsTCX20 ), 1.0f, hCPE->hCoreCoder[0]->bwidth, hCPE->element_brate ); stereo_mdct_init_igf_start_band( &( hCPE->hStereoMdct->stbParamsTCX10 ), 0.5f, hCPE->hCoreCoder[0]->bwidth, hCPE->element_brate ); stereo_mdct_init_igf_start_band( &( hCPE->hStereoMdct->stbParamsTCX20afterACELP ), 1.25f, hCPE->hCoreCoder[0]->bwidth, hCPE->element_brate ); +#else + initMdctStereoEncData_fx( hCPE->hStereoMdct, STEREO_FORMAT, IVAS_CPE_MDCT, hCPE->element_brate, hCPE->hCoreCoder[0]->bwidth, hCPE->hCoreCoder[0]->igf, hCPE->hCoreCoder[0]->hIGFEnc->igfData.igfInfo.grid, 0 ); + + stereo_mdct_init_igf_start_band_fx( &( hCPE->hStereoMdct->stbParamsTCX20 ), 16384 /* 1.0f in Q14 */, hCPE->hCoreCoder[0]->bwidth, hCPE->element_brate ); + stereo_mdct_init_igf_start_band_fx( &( hCPE->hStereoMdct->stbParamsTCX10 ), 8192 /* 0.5f in Q14 */, hCPE->hCoreCoder[0]->bwidth, hCPE->element_brate ); + stereo_mdct_init_igf_start_band_fx( &( hCPE->hStereoMdct->stbParamsTCX20afterACELP ), 20480 /* 1.25f in Q14 */, hCPE->hCoreCoder[0]->bwidth, hCPE->element_brate ); +#endif } else { @@ -415,7 +426,11 @@ void stereo_mdct_core_enc( nAvailBits -= meta_bits; nAvailBits -= SMDCT_NBBITS_SPLIT_RATIO; +#ifndef IVAS_FLOAT_FIXED splitAvailableBits( nAvailBits, hStereoMdct->split_ratio, hStereoMdct->isSBAStereoMode, &sts[0]->bits_frame_channel, &sts[1]->bits_frame_channel ); +#else + splitAvailableBits_fx( nAvailBits, hStereoMdct->split_ratio, hStereoMdct->isSBAStereoMode, &sts[0]->bits_frame_channel, &sts[1]->bits_frame_channel ); +#endif sts[0]->bits_frame_channel += sts[0]->core * SMDCT_MINIMUM_ARITH_BITS; sts[1]->bits_frame_channel += sts[1]->core * SMDCT_MINIMUM_ARITH_BITS; diff --git a/lib_enc/ivas_stereo_mdct_stereo_enc.c b/lib_enc/ivas_stereo_mdct_stereo_enc.c index 9ea4b937a..62206ccc3 100644 --- a/lib_enc/ivas_stereo_mdct_stereo_enc.c +++ b/lib_enc/ivas_stereo_mdct_stereo_enc.c @@ -1032,6 +1032,7 @@ static void MsStereoDecision( * initialize encoder mdct stereo structure *-----------------------------------------------------------------------*/ +#ifndef IVAS_FLOAT_FIXED void initMdctStereoEncData( STEREO_MDCT_ENC_DATA *hStereoMdct, /* i/o: mdct stereo parameters structure */ const IVAS_FORMAT ivas_format, /* i : IVAS format */ @@ -1090,7 +1091,7 @@ void initMdctStereoEncData( return; } -#ifdef IVAS_FLOAT_FIXED +#else void initMdctStereoEncData_fx( STEREO_MDCT_ENC_DATA *hStereoMdct, /* i/o: mdct stereo parameters structure */ const IVAS_FORMAT ivas_format, /* i : IVAS format */ @@ -1124,7 +1125,8 @@ void initMdctStereoEncData_fx( hStereoMdct->split_ratio = SMDCT_EQUAL_RATIO_RANGE; - set16_fx( hStereoMdct->global_ild, shr( SMDCT_ILD_RANGE, 1 ), 2 ); + move16(); + set16_fx( hStereoMdct->global_ild, SMDCT_ILD_RANGE >> 1, 2 ); IF( mem_init ) { @@ -1132,7 +1134,9 @@ void initMdctStereoEncData_fx( hStereoMdct->hDft_ana = NULL; } - IF( !( element_mode == IVAS_CPE_MDCT && element_brate <= MAX_MDCT_ITD_BRATE && ivas_format == STEREO_FORMAT ) ) + test(); + test(); + IF( !( EQ_16( element_mode, IVAS_CPE_MDCT ) && LE_32( element_brate, MAX_MDCT_ITD_BRATE ) && EQ_32( ivas_format, STEREO_FORMAT ) ) ) { IF( hStereoMdct->hDft_ana != NULL ) { @@ -1150,6 +1154,8 @@ void initMdctStereoEncData_fx( return; } #endif + + /*-----------------------------------------------------------------------* * initMdctItdHandling() * diff --git a/lib_enc/ivas_stereo_switching_enc.c b/lib_enc/ivas_stereo_switching_enc.c index 87e692f3b..03cf7bfe2 100644 --- a/lib_enc/ivas_stereo_switching_enc.c +++ b/lib_enc/ivas_stereo_switching_enc.c @@ -531,7 +531,11 @@ ivas_error stereo_memory_enc( return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for MDCT Stereo \n" ) ); } +#ifndef IVAS_FLOAT_FIXED initMdctStereoEncData( hCPE->hStereoMdct, ivas_format, hCPE->element_mode, hCPE->element_brate, hCPE->hCoreCoder[0]->max_bwidth, 0, NULL, 1 ); +#else + initMdctStereoEncData_fx( hCPE->hStereoMdct, ivas_format, hCPE->element_mode, hCPE->element_brate, hCPE->hCoreCoder[0]->max_bwidth, 0, NULL, 1 ); +#endif hCPE->hStereoMdct->isSBAStereoMode = ( ivas_format == SBA_FORMAT && nchan_transport == 2 ); diff --git a/lib_enc/lib_enc.c b/lib_enc/lib_enc.c index b2eaa4800..6de215c49 100644 --- a/lib_enc/lib_enc.c +++ b/lib_enc/lib_enc.c @@ -1365,6 +1365,7 @@ static ivas_error configureEncoder_fx( * *---------------------------------------------------------------------*/ +#ifndef IVAS_FLOAT_FIXED ivas_error IVAS_ENC_GetDelay( const IVAS_ENC_HANDLE hIvasEnc, /* i : IVAS encoder handle */ int16_t *delay /* o : encoder delay */ @@ -1390,6 +1391,35 @@ ivas_error IVAS_ENC_GetDelay( return IVAS_ERR_OK; } +#else +ivas_error IVAS_ENC_GetDelay( + const IVAS_ENC_HANDLE hIvasEnc, /* i : IVAS encoder handle */ + Word16 *delay /* o : encoder delay */ +) +{ + ENCODER_CONFIG_HANDLE hEncoderConfig; + + hEncoderConfig = hIvasEnc->st_ivas->hEncoderConfig; + + IF( !hIvasEnc->isConfigured ) + { + return IVAS_ERR_NOT_CONFIGURED; + } + + IF( delay == NULL ) + { + return IVAS_ERR_UNEXPECTED_NULL_POINTER; + } + + *delay = NS2SA( hEncoderConfig->input_Fs, get_delay_fx( ENC, hEncoderConfig->input_Fs, hEncoderConfig->ivas_format, NULL ) ); + move16(); + + *delay = imult1616( *delay, hEncoderConfig->nchan_inp ); + move16(); + + return IVAS_ERR_OK; +} +#endif /*---------------------------------------------------------------------* diff --git a/lib_enc/lib_enc.h b/lib_enc/lib_enc.h index 82aaf5a3c..1f7907ae8 100644 --- a/lib_enc/lib_enc.h +++ b/lib_enc/lib_enc.h @@ -299,10 +299,17 @@ ivas_error IVAS_ENC_SetChannelAwareConfig( /* Getter functions - retrieve information from an encoder through a handle */ /*! r: encoder error code */ +#ifndef IVAS_FLOAT_FIXED ivas_error IVAS_ENC_GetDelay( const IVAS_ENC_HANDLE hIvasEnc, /* i : IVAS encoder handle */ int16_t *delay /* o : encoder delay */ ); +#else +ivas_error IVAS_ENC_GetDelay( + const IVAS_ENC_HANDLE hIvasEnc, /* i : IVAS encoder handle */ + Word16 *delay /* o : encoder delay */ +); +#endif /*! r: encoder error code */ ivas_error IVAS_ENC_GetNumInChannels( -- GitLab From b033717ac0657366ca62297ce1e78f740a57c3d0 Mon Sep 17 00:00:00 2001 From: Sandesh Venkatesh Date: Wed, 19 Jun 2024 11:53:22 +0530 Subject: [PATCH 2/2] Clang formatting changes --- lib_dec/TonalComponentDetection.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib_dec/TonalComponentDetection.c b/lib_dec/TonalComponentDetection.c index 66333630f..12908a001 100644 --- a/lib_dec/TonalComponentDetection.c +++ b/lib_dec/TonalComponentDetection.c @@ -886,4 +886,4 @@ static void findTonalComponents( return; } -#endif \ No newline at end of file +#endif -- GitLab