diff --git a/lib_com/options.h b/lib_com/options.h index 499a45afcaccdbf438b8eba5bbfc75c275211997..2f1d9374911fca598474200561a8f69b43c0d9c1 100644 --- a/lib_com/options.h +++ b/lib_com/options.h @@ -100,6 +100,10 @@ #define FIX_BASOP_2530_IVAS_DECISION_MAT /* VA: Fix ambiguous usage of extract_l() */ +/*Harmonize SetTCXModeInfo, GetTCXMaxenergyChange*/ +#define HARMONIZE_2537_SetTCXModeInfo /* FhG: Harmonize SetTCXModeInfo - IVAS_VERSION OBVIOUSLY NOT FITTING FOR EVS - pipes not green */ +#define HARMONIZE_2537_GetTCXMaxenergyChange /* FhG: Harmonize GetTCXMaxenergyChange */ + /* #################### End BE switches ################################## */ /* #################### Start NON-BE switches ############################ */ diff --git a/lib_enc/cod_tcx_fx.c b/lib_enc/cod_tcx_fx.c index 72a8d01d37359fb0bb4b8a44c9ba66a676cbc116..3c77a6d3b1b025684665cd56fe9d035203048100 100644 --- a/lib_enc/cod_tcx_fx.c +++ b/lib_enc/cod_tcx_fx.c @@ -4906,7 +4906,11 @@ void TNSAnalysisStereo_fx( ELSE { Word16 maxEnergyChange_fx; +#ifdef HARMONIZE_2537_GetTCXMaxenergyChange + maxEnergyChange_fx = mac_r( L_mult( GetTCXMaxenergyChange_fx( sts[0]->hTranDet, isTCX10, NSUBBLOCKS, 3, 1 /*non-EVS*/ ), 16384 ), GetTCXMaxenergyChange_fx( sts[1]->hTranDet, isTCX10, NSUBBLOCKS, 3, 1 /*non-EVS*/ ), 16384 ); +#else maxEnergyChange_fx = mac_r( L_mult( GetTCXMaxenergyChange_ivas_fx( sts[0]->hTranDet, isTCX10, NSUBBLOCKS, 3 ), 16384 ), GetTCXMaxenergyChange_ivas_fx( sts[1]->hTranDet, isTCX10, NSUBBLOCKS, 3 ), 16384 ); +#endif IF( GE_16( maxEnergyChange_fx, shl( pTnsParameters[0]->minEnergyChange, Q3 - Q7 ) ) ) { @@ -5200,7 +5204,11 @@ void TNSAnalysisStereo_fx( } ELSE { +#ifdef HARMONIZE_2537_GetTCXMaxenergyChange + Word16 maxEnergyChange_fx = GetTCXMaxenergyChange_fx( sts[ch]->hTranDet, isTCX10, NSUBBLOCKS, 3, 1 /*non-EVS*/ ); +#else Word16 maxEnergyChange_fx = GetTCXMaxenergyChange_ivas_fx( sts[ch]->hTranDet, isTCX10, NSUBBLOCKS, 3 ); +#endif IF( GE_16( maxEnergyChange_fx, shl( pTnsParameters->minEnergyChange, Q3 - Q7 ) ) ) { diff --git a/lib_enc/ivas_core_pre_proc_fx.c b/lib_enc/ivas_core_pre_proc_fx.c index 019ccca6e5b8f84e64f8d5c7f2936212d60ff338..8f1a7b60b4df44a84143302853e21269310999e8 100644 --- a/lib_enc/ivas_core_pre_proc_fx.c +++ b/lib_enc/ivas_core_pre_proc_fx.c @@ -380,7 +380,11 @@ void pre_proc_ivas_fx( } IF( NE_16( st->element_mode, IVAS_CPE_MDCT ) ) { +#ifdef HARMONIZE_2537_SetTCXModeInfo + SetTCXModeInfo_fx( st, st->hTranDet, &st->hTcxCfg->tcx_curr_overlap_mode ); +#else SetTCXModeInfo_ivas_fx( st, st->hTranDet, &st->hTcxCfg->tcx_curr_overlap_mode ); +#endif } } ELSE IF( EQ_16( st->element_mode, IVAS_CPE_MDCT ) ) diff --git a/lib_enc/ivas_mdct_core_enc_fx.c b/lib_enc/ivas_mdct_core_enc_fx.c index 99ff751e4dbac1fa12cc6e0857f61bcd81f7eedf..3e1b3bc964bf94540c658fae202670bbd078864b 100644 --- a/lib_enc/ivas_mdct_core_enc_fx.c +++ b/lib_enc/ivas_mdct_core_enc_fx.c @@ -1290,7 +1290,11 @@ void ivas_mdct_core_whitening_enc_fx( FOR( ch = 0; ch < CPE_CHANNELS; ch++ ) { st = sts[ch]; +#ifdef HARMONIZE_2537_SetTCXModeInfo + SetTCXModeInfo_fx( st, st->hTranDet, &st->hTcxCfg->tcx_curr_overlap_mode ); +#else SetTCXModeInfo_ivas_fx( st, st->hTranDet, &st->hTcxCfg->tcx_curr_overlap_mode ); +#endif } } diff --git a/lib_enc/ivas_stereo_mdct_core_enc_fx.c b/lib_enc/ivas_stereo_mdct_core_enc_fx.c index 37996fe424b209d42f94575aebe085e0f3def993..74ccb14fc347b7beaa320931198bb70728ea41e1 100644 --- a/lib_enc/ivas_stereo_mdct_core_enc_fx.c +++ b/lib_enc/ivas_stereo_mdct_core_enc_fx.c @@ -211,7 +211,11 @@ void stereo_mdct_core_enc_fx( FOR( ch = 0; ch < CPE_CHANNELS; ch++ ) { st = sts[ch]; +#ifdef HARMONIZE_2537_SetTCXModeInfo + SetTCXModeInfo_fx( st, st->hTranDet, &st->hTcxCfg->tcx_curr_overlap_mode ); +#else SetTCXModeInfo_ivas_fx( st, st->hTranDet, &st->hTcxCfg->tcx_curr_overlap_mode ); +#endif } /* adaptively sync tcx modes*/ test(); diff --git a/lib_enc/prot_fx_enc.h b/lib_enc/prot_fx_enc.h index d5987061021a9e1c325279704c598954de0e8c1b..52e00e612b6b72f4e4aeda24769d21e3782ae188 100644 --- a/lib_enc/prot_fx_enc.h +++ b/lib_enc/prot_fx_enc.h @@ -932,6 +932,14 @@ Word32 GetTCXAvgTemporalFlatnessMeasure_ivas_fx( * @param nPrevSubblocks Number of subblocks from the previous frames to use for the calculation. * @param maximum energy change with exponent NRG_CHANGE_E */ +#ifdef HARMONIZE_2537_GetTCXMaxenergyChange +Word16 GetTCXMaxenergyChange_fx( + TRAN_DET_HANDLE hTranDet, + const Word8 isTCX10, + const Word16 nCurrentSubblocks, + const Word16 nPrevSubblocks, + Word16 element_mode ); +#else Word16 GetTCXMaxenergyChange_fx( TRAN_DET_HANDLE hTranDet, const Word8 isTCX10, @@ -943,7 +951,9 @@ Word16 GetTCXMaxenergyChange_ivas_fx( const Word8 isTCX10, const Word16 nCurrentSubblocks, const Word16 nPrevSubblocks ); +#endif +#ifndef HARMONIZE_2537_SetTCXModeInfo /** Set TCX window length and overlap configuration * @param prevEnergyHF previous HF energy. Exponent must be the same as for currEnergyHF. * @param currEnergyHF current HF energy. Exponent must be the same as for prevEnergyHF. @@ -953,6 +963,7 @@ void SetTCXModeInfo_ivas_fx( TRAN_DET_HANDLE hTranDet, /* i/o: transient detection handle */ Word16 *tcxModeOverlap /* o : window overlap of current frame */ ); +#endif /** Set TCX window length and overlap configuration * @param prevEnergyHF previous HF energy. Exponent must be the same as for currEnergyHF. diff --git a/lib_enc/tcx_ltp_enc_fx.c b/lib_enc/tcx_ltp_enc_fx.c index 5247f36042af45e6156595775d5fd75389e773f6..dde520d3aeaea69b144673685b2211bdb7dd9d4d 100644 --- a/lib_enc/tcx_ltp_enc_fx.c +++ b/lib_enc/tcx_ltp_enc_fx.c @@ -418,7 +418,11 @@ void tcx_ltp_encode_fx( tempFlatness = GetTCXAvgTemporalFlatnessMeasure_fx( hTranDet, NSUBBLOCKS, nPrevSubblocks ); +#ifdef HARMONIZE_2537_GetTCXMaxenergyChange + maxEnergyChange = GetTCXMaxenergyChange_fx( hTranDet, (const Word8) isTCX10, NSUBBLOCKS, nPrevSubblocks, EVS_MONO ); +#else maxEnergyChange = GetTCXMaxenergyChange_fx( hTranDet, (const Word8) isTCX10, NSUBBLOCKS, nPrevSubblocks ); +#endif /* Switch LTP on */ test(); @@ -768,12 +772,20 @@ void tcx_ltp_encode_ivas_fx( IF( EQ_16( st->element_mode, IVAS_CPE_DFT ) ) { tempFlatness_fx = extract_h( L_shl_sat( GetTCXAvgTemporalFlatnessMeasure_ivas_fx( st->hTranDet, NSUBBLOCKS - NSUBBLOCKS_SHIFT, add( nPrevSubblocks, NSUBBLOCKS_SHIFT ) ), 2 ) ); +#ifdef HARMONIZE_2537_GetTCXMaxenergyChange + maxEnergyChange_fx = GetTCXMaxenergyChange_fx( st->hTranDet, (const Word8) isTCX10, NSUBBLOCKS - NSUBBLOCKS_SHIFT, add( nPrevSubblocks, NSUBBLOCKS_SHIFT ), st->element_mode ); // Q3 +#else maxEnergyChange_fx = GetTCXMaxenergyChange_ivas_fx( st->hTranDet, (const Word8) isTCX10, NSUBBLOCKS - NSUBBLOCKS_SHIFT, add( nPrevSubblocks, NSUBBLOCKS_SHIFT ) ); // Q3 +#endif } ELSE { tempFlatness_fx = extract_h( L_shl_sat( ( GetTCXAvgTemporalFlatnessMeasure_ivas_fx( st->hTranDet, NSUBBLOCKS, nPrevSubblocks ) ), 2 ) ); // Q7 - maxEnergyChange_fx = GetTCXMaxenergyChange_ivas_fx( st->hTranDet, (const Word8) isTCX10, NSUBBLOCKS, nPrevSubblocks ); // Q3 +#ifdef HARMONIZE_2537_GetTCXMaxenergyChange + maxEnergyChange_fx = GetTCXMaxenergyChange_fx( st->hTranDet, (const Word8) isTCX10, NSUBBLOCKS, nPrevSubblocks, st->element_mode ); // Q3 +#else + maxEnergyChange_fx = GetTCXMaxenergyChange_ivas_fx( st->hTranDet, (const Word8) isTCX10, NSUBBLOCKS, nPrevSubblocks ); // Q3 +#endif } /* Switch LTP on */ diff --git a/lib_enc/tns_base_enc_fx.c b/lib_enc/tns_base_enc_fx.c index 0ad30427b641974328184e8c810722d7899f471b..08793acf48995a7be6fe04139128d2fe370a09b6 100644 --- a/lib_enc/tns_base_enc_fx.c +++ b/lib_enc/tns_base_enc_fx.c @@ -405,7 +405,11 @@ Word16 DetectTnsFilt_fx( } ELSE { +#ifdef HARMONIZE_2537_GetTCXMaxenergyChange + maxEnergyChange = GetTCXMaxenergyChange_fx( hTranDet, isTCX10, NSUBBLOCKS, 3, 1 /*non-EVS*/ ); +#else maxEnergyChange = GetTCXMaxenergyChange_ivas_fx( hTranDet, isTCX10, NSUBBLOCKS, 3 ); +#endif IF( sub( maxEnergyChange, shl( pTnsParameters->minEnergyChange, Q3 - Q7 ) ) >= 0 ) { diff --git a/lib_enc/transient_detection_fx.c b/lib_enc/transient_detection_fx.c index f671b8d9eef275a7c27505c68bbdf9f21f422b5a..2b906828d40518de996dbc309bd5bda6470a8f42 100644 --- a/lib_enc/transient_detection_fx.c +++ b/lib_enc/transient_detection_fx.c @@ -434,6 +434,7 @@ Word32 GetTCXAvgTemporalFlatnessMeasure_ivas_fx( return i; } +#ifndef HARMONIZE_2537_GetTCXMaxenergyChange Word16 GetTCXMaxenergyChange_fx( TRAN_DET_HANDLE hTranDet, const Word8 isTCX10, @@ -510,21 +511,36 @@ Word16 GetTCXMaxenergyChange_fx( return i; } +#endif - +#ifdef HARMONIZE_2537_GetTCXMaxenergyChange +Word16 GetTCXMaxenergyChange_fx( + TRAN_DET_HANDLE hTranDet, + const Word8 isTCX10, + const Word16 nCurrentSubblocks, + const Word16 nPrevSubblocks, + Word16 element_mode ) +#else Word16 GetTCXMaxenergyChange_ivas_fx( TRAN_DET_HANDLE hTranDet, const Word8 isTCX10, const Word16 nCurrentSubblocks, const Word16 nPrevSubblocks ) +#endif { Word16 i; TransientDetector const *pTransientDetector; SubblockEnergies const *pSubblockEnergies; Word16 nDelay; Word16 nRelativeDelay; +#ifdef HARMONIZE_2537_GetTCXMaxenergyChange + Word16 const *pSubblockNrgChange_16; + Word32 const *pSubblockNrgChange_32; + Word16 const *pSubblockNrgChange_32_exp; +#else Word32 const *pSubblockNrgChange; Word16 const *pSubblockNrgChange_exp; +#endif Word16 maxEnergyChange; Word16 nTotBlocks; @@ -533,15 +549,27 @@ Word16 GetTCXMaxenergyChange_ivas_fx( move16(); nDelay = pTransientDetector->nDelay; nRelativeDelay = sub( pSubblockEnergies->nDelay, nDelay ); +#ifdef HARMONIZE_2537_GetTCXMaxenergyChange + pSubblockNrgChange_16 = NULL; + pSubblockNrgChange_32 = NULL; +#else pSubblockNrgChange = NULL; +#endif nTotBlocks = add( nCurrentSubblocks, nPrevSubblocks ); assert( nTotBlocks > 0 ); - maxEnergyChange = 0 /*0.0f Q3*/; + maxEnergyChange = 0; move16(); + assert( ( nPrevSubblocks <= nRelativeDelay ) && ( nCurrentSubblocks <= NSUBBLOCKS + nDelay ) ); +#ifdef HARMONIZE_2537_GetTCXMaxenergyChange + pSubblockNrgChange_16 = &pSubblockEnergies->subblockNrgChange[nRelativeDelay - nPrevSubblocks]; + pSubblockNrgChange_32 = &pSubblockEnergies->subblockNrgChange_32fx[nRelativeDelay - nPrevSubblocks]; + pSubblockNrgChange_32_exp = &pSubblockEnergies->subblockNrgChange_exp[nRelativeDelay - nPrevSubblocks]; +#else pSubblockNrgChange = &pSubblockEnergies->subblockNrgChange_32fx[nRelativeDelay - nPrevSubblocks]; pSubblockNrgChange_exp = &pSubblockEnergies->subblockNrgChange_exp[nRelativeDelay - nPrevSubblocks]; +#endif IF( s_or( pTransientDetector->bIsAttackPresent, isTCX10 ) ) /* frame is TCX-10 */ { @@ -578,13 +606,26 @@ Word16 GetTCXMaxenergyChange_ivas_fx( } } - FOR( i = 0; i < nTotBlocks; i++ ) +#ifdef HARMONIZE_2537_GetTCXMaxenergyChange + IF( GT_16( element_mode, EVS_MONO ) ) { - maxEnergyChange = s_max( maxEnergyChange, extract_l( L_shl_sat( pSubblockNrgChange[i], sub( pSubblockNrgChange_exp[i], 28 ) ) ) ); // Q3 +#endif + FOR( i = 0; i < nTotBlocks; i++ ) + { + maxEnergyChange = s_max( maxEnergyChange, extract_l( L_shl_sat( pSubblockNrgChange_32[i], sub( pSubblockNrgChange_32_exp[i], 28 ) ) ) ); // Q3 + } +#ifdef HARMONIZE_2537_GetTCXMaxenergyChange } - + ELSE + { + FOR( i = 0; i < nTotBlocks; i++ ) + { + maxEnergyChange = s_max( maxEnergyChange, pSubblockNrgChange_16[i] ); + } + } +#endif move16(); - i = maxEnergyChange; // Q3 + i = maxEnergyChange; return i; } @@ -735,17 +776,30 @@ static Word16 isLongTermTransient_fx( } +/*HARMONIZATION DONE...*/ +#ifdef HARMONIZE_2537_SetTCXModeInfo +void SetTCXModeInfo_fx( + Encoder_State *st, /* i/o: encoder state structure */ + TRAN_DET_HANDLE hTranDet, /* i/o: transient detection handle */ + Word16 *tcxModeOverlap /* o : window overlap of current frame */ +) +#else void SetTCXModeInfo_ivas_fx( Encoder_State *st, /* i/o: encoder state structure */ TRAN_DET_HANDLE hTranDet, /* i/o: transient detection handle */ Word16 *tcxModeOverlap /* o : window overlap of current frame */ ) +#endif { TCX_ENC_HANDLE hTcxEnc = st->hTcxEnc; Word16 tmp, exp_diff; test(); test(); +#ifdef HARMONIZE_2537_SetTCXModeInfo + test(); + test(); +#endif IF( EQ_16( st->codec_mode, MODE2 ) || ( GT_16( st->element_mode, EVS_MONO ) && NE_16( st->core, HQ_CORE ) ) ) { assert( hTranDet != NULL ); @@ -755,6 +809,24 @@ void SetTCXModeInfo_ivas_fx( IF( st->tcx10Enabled && st->tcx20Enabled ) { /* window switching based on transient detector output */ +#ifdef HARMONIZE_2537_SetTCXModeInfo + Word16 currNrgGTprevNrg; + IF( GT_16( st->element_mode, EVS_MONO ) ) + { + test(); + currNrgGTprevNrg = (Word16) ( EQ_32( BASOP_Util_Cmp_Mant32Exp( Mpy_32_32( st->currEnergyHF_fx, 55063683 /*1.0f/39.0f Q31*/ ), st->currEnergyHF_e_fx, st->prevEnergyHF_fx, 17 ), 1 ) && NE_16( st->element_mode, IVAS_CPE_MDCT ) ); + } + ELSE + { + currNrgGTprevNrg = (Word16) ( GT_32( Mpy_32_16_1( st->currEnergyHF_fx, 840 /*1.0f/39.0f Q15*/ ), st->prevEnergyHF_fx ) ); + } + test(); + test(); + test(); + /* window switching based on transient detector output */ + IF( ( ( hTranDet->transientDetector.bIsAttackPresent ) || currNrgGTprevNrg ) && + ( ( NE_16( st->last_core, ACELP_CORE ) ) && ( NE_16( st->last_core, AMR_WB_CORE ) ) ) ) +#else test(); test(); test(); @@ -762,6 +834,7 @@ void SetTCXModeInfo_ivas_fx( /* window switching based on transient detector output */ IF( ( ( hTranDet->transientDetector.bIsAttackPresent ) || ( EQ_32( BASOP_Util_Cmp_Mant32Exp( Mpy_32_32( st->currEnergyHF_fx, 55063683 /*1.0f/39.0f Q31*/ ), st->currEnergyHF_e_fx, st->prevEnergyHF_fx, 17 ), 1 ) && NE_16( st->element_mode, IVAS_CPE_MDCT ) ) ) && ( ( NE_16( st->last_core, ACELP_CORE ) ) && ( NE_16( st->last_core, AMR_WB_CORE ) ) ) ) +#endif { hTcxEnc->tcxMode = TCX_10; move16(); @@ -841,16 +914,21 @@ void SetTCXModeInfo_ivas_fx( move16(); } } - tmp = BASOP_Util_Divide3232_Scale( ONE_IN_Q21, GetTCXAvgTemporalFlatnessMeasure_ivas_fx( hTranDet, NSUBBLOCKS, 0 ), &exp_diff ); - tmp = shl_sat( tmp, exp_diff ); // Q15 - test(); - IF( isLongTermTransient_fx( L_deposit_h( tmp ), &hTcxEnc->tfm_mem_fx ) && EQ_16( st->element_mode, IVAS_CPE_MDCT ) ) +#ifdef HARMONIZE_2537_SetTCXModeInfo + IF( GT_16( st->element_mode, EVS_MONO ) ) +#endif { + tmp = BASOP_Util_Divide3232_Scale( ONE_IN_Q21, GetTCXAvgTemporalFlatnessMeasure_ivas_fx( hTranDet, NSUBBLOCKS, 0 ), &exp_diff ); + tmp = shl_sat( tmp, exp_diff ); // Q15 test(); - IF( NE_16( *tcxModeOverlap, MIN_OVERLAP ) && LT_16( hTcxEnc->tcxltp_norm_corr_past, 18432 /* 0.5625f in Q15 */ ) ) + IF( isLongTermTransient_fx( L_deposit_h( tmp ), &hTcxEnc->tfm_mem_fx ) && EQ_16( st->element_mode, IVAS_CPE_MDCT ) ) { - *tcxModeOverlap = HALF_OVERLAP; - move16(); + test(); + IF( NE_16( *tcxModeOverlap, MIN_OVERLAP ) && LT_16( hTcxEnc->tcxltp_norm_corr_past, 18432 /* 0.5625f in Q15 */ ) ) + { + *tcxModeOverlap = HALF_OVERLAP; + move16(); + } } } } @@ -871,16 +949,21 @@ void SetTCXModeInfo_ivas_fx( *tcxModeOverlap = ALDO_WINDOW; move16(); } - tmp = BASOP_Util_Divide3232_Scale( ONE_IN_Q21, GetTCXAvgTemporalFlatnessMeasure_ivas_fx( hTranDet, NSUBBLOCKS, 0 ), &exp_diff ); - tmp = shl_sat( tmp, exp_diff ); // Q15 - test(); - IF( isLongTermTransient_fx( L_deposit_h( tmp ), &hTcxEnc->tfm_mem_fx ) && EQ_16( st->element_mode, IVAS_CPE_MDCT ) ) +#ifdef HARMONIZE_2537_SetTCXModeInfo + IF( GT_16( st->element_mode, EVS_MONO ) ) +#endif { + tmp = BASOP_Util_Divide3232_Scale( ONE_IN_Q21, GetTCXAvgTemporalFlatnessMeasure_ivas_fx( hTranDet, NSUBBLOCKS, 0 ), &exp_diff ); + tmp = shl_sat( tmp, exp_diff ); // Q15 test(); - if ( NE_16( *tcxModeOverlap, MIN_OVERLAP ) && LT_16( hTcxEnc->tcxltp_norm_corr_past, 18432 /* 0.5625f in Q15 */ ) ) + IF( isLongTermTransient_fx( L_deposit_h( tmp ), &hTcxEnc->tfm_mem_fx ) && EQ_16( st->element_mode, IVAS_CPE_MDCT ) ) { - *tcxModeOverlap = HALF_OVERLAP; - move16(); + test(); + if ( NE_16( *tcxModeOverlap, MIN_OVERLAP ) && LT_16( hTcxEnc->tcxltp_norm_corr_past, 18432 /* 0.5625f in Q15 */ ) ) + { + *tcxModeOverlap = HALF_OVERLAP; + move16(); + } } } } @@ -898,17 +981,24 @@ void SetTCXModeInfo_ivas_fx( /* for the ACELP -> TCX transition frames use full right window overlap */ test(); - IF( ( EQ_16( st->hTcxCfg->tcx_last_overlap_mode, TRANSITION_OVERLAP ) ) && ( EQ_16( *tcxModeOverlap, ALDO_WINDOW ) ) ) + if ( ( EQ_16( st->hTcxCfg->tcx_last_overlap_mode, TRANSITION_OVERLAP ) ) && ( EQ_16( *tcxModeOverlap, ALDO_WINDOW ) ) ) { *tcxModeOverlap = FULL_OVERLAP; move16(); } +#ifdef HARMONIZE_2537_SetTCXModeInfo + IF( EQ_16( st->element_mode, EVS_MONO ) ) + { + /* Sanity check */ + assert( *tcxModeOverlap != 1 ); + } +#endif } return; } - +#ifndef HARMONIZE_2537_SetTCXModeInfo /*-------------------------------------------------------------------* * SetTCXModeInfo() * @@ -1037,7 +1127,7 @@ void SetTCXModeInfo_fx( return; } - +#endif /************************************************/ /* */