diff --git a/lib_com/options.h b/lib_com/options.h index 1da007ad696ce783ca058ae3d0c182302c9e4036..a9501c3a93098de3bc41a2315c458f1674ce2905 100644 --- a/lib_com/options.h +++ b/lib_com/options.h @@ -138,7 +138,7 @@ #define NONBE_1329_FIX_OSBA_CRASH /* FhG: issue 1329: prevent assert when bit budget is low*/ #define NONBE_FIX_1128_OSBA_EXT_OUTPUT_ORDER /* FhG: issue 1128: set output ambisonics order to input order for EXT output */ #define FIX_1138_SBA_EXT_ERROR_PRINTOUT /* VA: issue 1138: Fix SBA EXT output call of audioCfg2channels() */ -#define NONBE_1244_FIX_SWB_BWE_MEMORY /* VA: issue 1244: fix to SWB BWE memory in case of switching from FB coding - pending a review by Huawei */ +#define NONBE_1244_FIX_SWB_BWE_MEMORY /* VA: issue 1244: fix to SWB BWE memory in case of switching from FB coding - pending a review by Huawei */ #define FIX_745_FIX_DATA_TYPE_CONVERSION /* VA: issue 745: implicit data type conversion when calling IVAS_DEC_Configure() */ #define NONBE_FIX_981_PARAMBIN_DEFAULT_EARLY_PART /* Nokia: Set default early part energy correction to unity for BINAURAL_ROOM_REVERB */ #define NONBE_FIX_1174_MCMASA_LBR_LOOP_ERROR /* Nokia: Fix issue 1174 by removing the unnecessary inner loop causing problems. */ @@ -167,6 +167,7 @@ #define NONBE_1214_PLC_LSF_MEMORY /* VA: issue 1224: reset ACELP PLC FEC memory in case of switching from MDCT stereo to TD/DFT stereo */ #define NONBE_1293_SR_HRTF /* VA: issue 1293: add support of external HRTFs in split rendering */ #define NONBE_1220_OMASA_JBM_BRATE_SW_FLUSH /* VA: issue 1220: fix bug in renderer flush in OMASA 1ISM JBM bitrate switching */ +#define FIX_1139_REV_COLORATION_SHORT_T60 /* Nokia,FhG: Fix issue 1139, prevent sound coloration artefacts at very low reverberation times */ /* #################### End BASOP porting switches ############################ */ diff --git a/lib_dec/ivas_binRenderer_internal_fx.c b/lib_dec/ivas_binRenderer_internal_fx.c index 5a96048be40768764b72e68a6750b5973c2144a6..92682ad019c4cd09e3c07dc8cc872affa8abc709 100644 --- a/lib_dec/ivas_binRenderer_internal_fx.c +++ b/lib_dec/ivas_binRenderer_internal_fx.c @@ -1361,7 +1361,11 @@ ivas_error ivas_binRenderer_open_fx( { pRoomAcoustics = &( st_ivas->hRenderConfig->roomAcoustics ); } +#ifdef FIX_1139_REV_COLORATION_SHORT_T60 + IF( NE_32( ( error = ivas_binaural_reverb_init( &( hBinRenderer->hReverb ), st_ivas->hHrtfStatistics, hBinRenderer->conv_band, hBinRenderer->timeSlots, pRoomAcoustics, st_ivas->hDecoderConfig->output_Fs, st_ivas->hHrtfFastConv->fastconvReverberationTimes_fx, st_ivas->hHrtfFastConv->fastconvReverberationEneCorrections_fx, NULL ) ), IVAS_ERR_OK ) ) +#else IF( NE_32( ( error = ivas_binaural_reverb_init( &( hBinRenderer->hReverb ), st_ivas->hHrtfStatistics, hBinRenderer->conv_band, hBinRenderer->timeSlots, pRoomAcoustics, st_ivas->hDecoderConfig->output_Fs, st_ivas->hHrtfFastConv->fastconvReverberationTimes_fx, st_ivas->hHrtfFastConv->fastconvReverberationEneCorrections_fx ) ), IVAS_ERR_OK ) ) +#endif #else IF( NE_32( ( error = ivas_binaural_reverb_init( &( hBinRenderer->hReverb ), st_ivas->hHrtfStatistics, hBinRenderer->conv_band, hBinRenderer->timeSlots, &( st_ivas->hRenderConfig->roomAcoustics ), st_ivas->hDecoderConfig->output_Fs, st_ivas->hHrtfFastConv->fastconvReverberationTimes_fx, st_ivas->hHrtfFastConv->fastconvReverberationEneCorrections_fx ) ), IVAS_ERR_OK ) ) #endif diff --git a/lib_dec/lib_dec_fx.c b/lib_dec/lib_dec_fx.c index 264cb0b44240f96cd1d38af092d10ef39ea7a405..66a890eda277db79c394fcdf04967013a0d618af 100644 --- a/lib_dec/lib_dec_fx.c +++ b/lib_dec/lib_dec_fx.c @@ -2926,7 +2926,11 @@ ivas_error IVAS_DEC_FeedRenderConfig( IF( hIvasDec->st_ivas->hDiracDecBin[0] != NULL && hIvasDec->st_ivas->hDiracDecBin[0]->hReverb != NULL ) { ivas_binaural_reverb_close_fx( &( hIvasDec->st_ivas->hDiracDecBin[0]->hReverb ) ); +#ifdef FIX_1139_REV_COLORATION_SHORT_T60 + IF( ( error = ivas_binaural_reverb_init( &( hIvasDec->st_ivas->hDiracDecBin[0]->hReverb ), hIvasDec->st_ivas->hHrtfStatistics, hIvasDec->st_ivas->hSpatParamRendCom->num_freq_bands, CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES, &( hRenderConfig->roomAcoustics ), hIvasDec->st_ivas->hDecoderConfig->output_Fs, NULL, NULL, NULL ) ) != IVAS_ERR_OK ) +#else IF( ( error = ivas_binaural_reverb_init( &( hIvasDec->st_ivas->hDiracDecBin[0]->hReverb ), hIvasDec->st_ivas->hHrtfStatistics, hIvasDec->st_ivas->hSpatParamRendCom->num_freq_bands, CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES, &( hRenderConfig->roomAcoustics ), hIvasDec->st_ivas->hDecoderConfig->output_Fs, NULL, NULL ) ) != IVAS_ERR_OK ) +#endif { return error; } @@ -2937,7 +2941,11 @@ ivas_error IVAS_DEC_FeedRenderConfig( IF( hIvasDec->st_ivas->hBinRenderer != NULL && hIvasDec->st_ivas->hBinRenderer->hReverb != NULL ) { ivas_binaural_reverb_close_fx( &( hIvasDec->st_ivas->hBinRenderer->hReverb ) ); +#ifdef FIX_1139_REV_COLORATION_SHORT_T60 + IF( ( error = ivas_binaural_reverb_init( &( hIvasDec->st_ivas->hBinRenderer->hReverb ), hIvasDec->st_ivas->hHrtfStatistics, hIvasDec->st_ivas->hBinRenderer->conv_band, hIvasDec->st_ivas->hBinRenderer->timeSlots, &( hRenderConfig->roomAcoustics ), hIvasDec->st_ivas->hDecoderConfig->output_Fs, NULL, NULL, NULL ) ) != IVAS_ERR_OK ) +#else IF( ( error = ivas_binaural_reverb_init( &( hIvasDec->st_ivas->hBinRenderer->hReverb ), hIvasDec->st_ivas->hHrtfStatistics, hIvasDec->st_ivas->hBinRenderer->conv_band, hIvasDec->st_ivas->hBinRenderer->timeSlots, &( hRenderConfig->roomAcoustics ), hIvasDec->st_ivas->hDecoderConfig->output_Fs, NULL, NULL ) ) != IVAS_ERR_OK ) +#endif { return error; } diff --git a/lib_rend/ivas_dirac_dec_binaural_functions_fx.c b/lib_rend/ivas_dirac_dec_binaural_functions_fx.c old mode 100755 new mode 100644 index 7dacb204b094aeee2cf84ec9471e3d0686ae19e4..e03429596f611384879007a08deec51f46a4d055 --- a/lib_rend/ivas_dirac_dec_binaural_functions_fx.c +++ b/lib_rend/ivas_dirac_dec_binaural_functions_fx.c @@ -339,7 +339,11 @@ ivas_error ivas_dirac_dec_init_binaural_data_fx( #ifdef NONBE_FIX_991_PARAMBIN_BINARY_HRTF #ifdef FIX_587_DEFAULT_REVERB +#ifdef FIX_1139_REV_COLORATION_SHORT_T60 + IF( NE_32( ( error = ivas_binaural_reverb_init( &hDiracDecBin->hReverb, st_ivas->hHrtfStatistics, nBins, CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES, pRoomAcoustics, output_Fs, ( *phHrtfParambin )->parametricReverberationTimes_fx, ( *phHrtfParambin )->parametricReverberationEneCorrections_fx, hDiracDecBin->earlyPartEneCorrection_fx ) ), IVAS_ERR_OK ) ) +#else if ( NE_32( ( error = ivas_binaural_reverb_init( &hDiracDecBin->hReverb, st_ivas->hHrtfStatistics, nBins, CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES, pRoomAcoustics, output_Fs, ( *phHrtfParambin )->parametricReverberationTimes_fx, ( *phHrtfParambin )->parametricReverberationEneCorrections_fx ) ), IVAS_ERR_OK ) ) +#endif #else if ( NE_32( ( error = ivas_binaural_reverb_init( &hDiracDecBin->hReverb, st_ivas->hHrtfStatistics, nBins, CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES, &( st_ivas->hRenderConfig->roomAcoustics ), output_Fs, ( *phHrtfParambin )->parametricReverberationTimes_fx, ( *phHrtfParambin )->parametricReverberationEneCorrections_fx ) ), IVAS_ERR_OK ) ) #endif diff --git a/lib_rend/ivas_prot_rend_fx.h b/lib_rend/ivas_prot_rend_fx.h index 186d4d1a2ce3ecbee9cdc8b3dd420f210cf1e544..ba20ad51b3fa962f5b44af04ff1679557f7defee 100644 --- a/lib_rend/ivas_prot_rend_fx.h +++ b/lib_rend/ivas_prot_rend_fx.h @@ -953,6 +953,10 @@ ivas_error ivas_binaural_reverb_init( const Word32 sampling_rate, /* i : sampling rate */ const Word32 *defaultTimes, /* i : default reverberation times */ const Word32 *defaultEne /* i : default reverberation energies */ +#ifdef FIX_1139_REV_COLORATION_SHORT_T60 + , + Word32 *earlyEne /* i/o: Early part energies to be modified */ +#endif ); void ivas_binaural_reverb_close_fx( diff --git a/lib_rend/ivas_reverb_fx.c b/lib_rend/ivas_reverb_fx.c index 3e9cd47413adfbe8b518ac511f85f0f7ed021f03..ddcd6ef15f9fc5cdb0947df6c57dbe7988be13f1 100644 --- a/lib_rend/ivas_reverb_fx.c +++ b/lib_rend/ivas_reverb_fx.c @@ -72,6 +72,12 @@ static Word16 wrap_rad_fixed( #define CLDFB_SLOTS_PER_SECOND 800 /* Used for initializing reverb */ +#ifdef FIX_1139_REV_COLORATION_SHORT_T60 +#define REV_TIME_THRESHOLD ( 13421773 ) /* 0.2f in Q26 */ +#define Q26_REV_TIME_THRESHOLD_TIMES_0_5 ( 6710886 ) /* 0.2 * 0.5 in Q26 */ +#define Q29_0_5_PER_REV_TIME_THRESHOLD ( 1342177280 ) /* 0.2 / 0.5 in Q29 */ +#endif + #define INNER_BLK_SIZE 80 /* size of data blocks used for more efficient delay line and IIR filter processing */ /* should be a divisor of the frame length at any sampling rate and an even number*/ #define FFT_FILTER_WND_FLAT_REGION ( 0.40f ) /* flat section (==1) length of FFT filter window, in proportion to overlap */ @@ -402,6 +408,25 @@ static void ivas_binaural_reverb_setReverbTimes_fx( currentEnergy_fx = Mpy_32_32( currentEnergy_fx, attenuationFactorPerSampleSq_fx ); currentEnergy_exp = currentEnergy_exp + attenuationFactorPerSampleSq_exp; } + +#ifdef FIX_1139_REV_COLORATION_SHORT_T60 + /* In some configurations with small T60s it is possible the number of taps randomizes to zero. + Ensure at least 1 filter tap. */ + IF( EQ_16( tap, 0 ) ) + { + hReverb->tapPhaseShiftType[bin][ch][0] = (Word16) ( binRend_rand( hReverb ) % 4 ); + move16(); + hReverb->tapPointersReal_fx[bin][ch][0] = &( hReverb->loopBufReal_fx[bin][0] ); + hReverb->tapPointersImag_fx[bin][ch][0] = &( hReverb->loopBufImag_fx[bin][0] ); + tap = 1; + move16(); + actualizedEnergy_fx = ONE_IN_Q30; + move32(); + actualizedEnergy_exp = 1; + move16(); + } +#endif + hReverb->taps[bin][ch] = tap; /* Number of taps determined at the above random procedure */ move16(); } @@ -2467,28 +2492,44 @@ ivas_error ivas_binaural_reverb_init( const Word32 sampling_rate, /* i : sampling rate */ const Word32 *defaultTimes, /* i : default reverberation times */ const Word32 *defaultEne /* i : default reverberation energies */ +#ifdef FIX_1139_REV_COLORATION_SHORT_T60 + , + Word32 *earlyEne /* i/o: Early part energies to be modified */ +#endif ) { ivas_error error; +#ifdef FIX_1139_REV_COLORATION_SHORT_T60 + Word16 preDelay, bin; + Word32 revTimes[CLDFB_NO_CHANNELS_MAX]; + Word32 revEne[CLDFB_NO_CHANNELS_MAX]; +#else const Word32 *revTimes; const Word32 *revEne; Word32 t60[CLDFB_NO_CHANNELS_MAX]; Word32 ene[CLDFB_NO_CHANNELS_MAX]; Word16 preDelay; +#endif Word32 temp32; error = IVAS_ERR_OK; #ifdef FIX_587_DEFAULT_REVERB - if ( roomAcoustics != NULL ) + IF( roomAcoustics != NULL ) #else if ( ( roomAcoustics != NULL ) && roomAcoustics->override ) #endif { +#ifndef FIX_1139_REV_COLORATION_SHORT_T60 revTimes = t60; revEne = ene; +#endif +#ifdef FIX_1139_REV_COLORATION_SHORT_T60 + IF( ( error = ivas_reverb_prepare_cldfb_params( roomAcoustics, hHrtfStatistics, sampling_rate, revTimes, revEne ) ) != IVAS_ERR_OK ) +#else if ( ( error = ivas_reverb_prepare_cldfb_params( roomAcoustics, hHrtfStatistics, sampling_rate, t60, ene ) ) != IVAS_ERR_OK ) +#endif { return error; } @@ -2496,13 +2537,76 @@ ivas_error ivas_binaural_reverb_init( temp32 = Mult_32_16( roomAcoustics->acousticPreDelay_fx, ( ( IVAS_48k / CLDFB_NO_CHANNELS_MAX ) >> 1 ) ); // Q11 preDelay = extract_l( L_shr( L_add( temp32, L_shl( 1, 10 ) ), 11 ) ); // Q0 } - else + ELSE { +#ifdef FIX_1139_REV_COLORATION_SHORT_T60 + FOR( bin = 0; bin < CLDFB_NO_CHANNELS_MAX; bin++ ) + { + revTimes[bin] = defaultTimes[bin]; + move32(); + revEne[bin] = defaultEne[bin]; + move32(); + } +#else revTimes = defaultTimes; revEne = defaultEne; +#endif preDelay = 10; } +#ifdef FIX_1139_REV_COLORATION_SHORT_T60 + FOR( bin = 0; bin < CLDFB_NO_CHANNELS_MAX; bin++ ) + { + /* Adjust the room effect parameters when the reverberation time is less than a threshold value, to avoid + spectral artefacts with the synthetic reverberator. */ + IF( LT_32( revTimes[bin], REV_TIME_THRESHOLD ) ) + { + Word32 adjustedEarlyEne; /* Q28 to match earlyEne */ + Word32 adjustedLateEne; /* Q31 to match revEne */ + Word32 adjustedRevTime; /* Q26 to match revTime */ + Word32 energyModifier; /* Q30 as range is [0,1] */ + Word16 scale; + + /* Adjust reverberation times, higher towards a threshold */ + /* Float code equivalent is: + * revTimeModifier = fmaxf( 0.0f, 1.0f - ( revTimes[bin] / REV_TIME_THRESHOLD ) ); + * adjustedRevTime = ( 1.0f - revTimeModifier ) * revTimes[bin]; + * adjustedRevTime += revTimeModifier * ( revTimes[bin] + REV_TIME_THRESHOLD ) * 0.5f; */ + adjustedRevTime = L_shl( revTimes[bin], 5 ); /* Store revTimes[bin] in Q31 for multiplication as it is under REV_TIME_THRESHOLD, i.e., smaller than 1 */ + /* Do revTimes[bin]^2 in Q31, result in Q31, multiply with constant in Q29, shift result from Q29 to Q26 for addition and result. */ + adjustedRevTime = L_add( L_shr( Mpy_32_32( Mpy_32_32( adjustedRevTime, adjustedRevTime ), Q29_0_5_PER_REV_TIME_THRESHOLD ), 3 ), Q26_REV_TIME_THRESHOLD_TIMES_0_5 ); + + energyModifier = L_sub( adjustedRevTime, revTimes[bin] ); /* Q26 */ + IF( GT_32( energyModifier, 0 ) ) /* Very close to threshold, numeric accuracy is not sufficient and energyModifier would be negative. Correct way is to not adjust here. */ + { + energyModifier = BASOP_Util_Divide3232_Scale_newton( energyModifier, adjustedRevTime, &scale ); /* Inputs in Q26 */ + energyModifier = L_shl_sat( energyModifier, sub( scale, 1 ) ); /* Store in Q30 as range is [0,1] */ + + /* Adjust early and late energies, by moving late energy to early energy */ + IF( earlyEne != NULL ) + { + adjustedEarlyEne = L_shr( Mpy_32_32( revEne[bin], energyModifier ), 2 ); /* Q31 * Q30 mult, shift from Q30 to Q28 */ + adjustedEarlyEne = L_add( adjustedEarlyEne, earlyEne[bin] ); /* Q28 */ + } + + adjustedLateEne = L_sub( ONE_IN_Q30, energyModifier ); /* Q30 */ + adjustedLateEne = L_shl_sat( Mpy_32_32( adjustedLateEne, revEne[bin] ), 1 ); /* Q30 * Q31 mult, shift back to Q31 */ + + /* Store adjusted room effect parameters to be used in reverb processing */ + revTimes[bin] = adjustedRevTime; + move32(); + revEne[bin] = adjustedLateEne; + move32(); + IF( earlyEne != NULL ) + { + earlyEne[bin] = adjustedEarlyEne; + move32(); + } + } + } + } +#endif + error = ivas_binaural_reverb_open_fx( hReverbPr, numBins, numCldfbSlotsPerFrame, sampling_rate, revTimes, revEne, preDelay ); return error; diff --git a/lib_rend/lib_rend_fx.c b/lib_rend/lib_rend_fx.c index 3e8f0dcee3ca0fc9838ab01e3b5583dbfa85ec6c..9f23458906f3c6342cffda6adcc197da98b4911e 100644 --- a/lib_rend/lib_rend_fx.c +++ b/lib_rend/lib_rend_fx.c @@ -4990,7 +4990,11 @@ Word16 IVAS_REND_FeedRenderConfig( if ( pMasaInput->hMasaExtRend->hDiracDecBin[0] != NULL && pMasaInput->hMasaExtRend->hDiracDecBin[0]->hReverb != NULL ) { ivas_binaural_reverb_close_fx( &pMasaInput->hMasaExtRend->hDiracDecBin[0]->hReverb ); +#ifdef FIX_1139_REV_COLORATION_SHORT_T60 + IF( NE_32( ( error = ivas_binaural_reverb_init( &pMasaInput->hMasaExtRend->hDiracDecBin[0]->hReverb, hIvasRend->hHrtfs.hHrtfStatistics, pMasaInput->hMasaExtRend->hSpatParamRendCom->num_freq_bands, CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES, &( hRenderConfig->roomAcoustics ), *pMasaInput->base.ctx.pOutSampleRate, NULL, NULL, NULL ) ), IVAS_ERR_OK ) ) +#else IF( NE_32( ( error = ivas_binaural_reverb_init( &pMasaInput->hMasaExtRend->hDiracDecBin[0]->hReverb, hIvasRend->hHrtfs.hHrtfStatistics, pMasaInput->hMasaExtRend->hSpatParamRendCom->num_freq_bands, CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES, &( hRenderConfig->roomAcoustics ), *pMasaInput->base.ctx.pOutSampleRate, NULL, NULL ) ), IVAS_ERR_OK ) ) +#endif { return error; } @@ -4998,7 +5002,11 @@ Word16 IVAS_REND_FeedRenderConfig( if ( pMasaInput->hMasaExtRend->hReverb != NULL ) { ivas_binaural_reverb_close_fx( &pMasaInput->hMasaExtRend->hReverb ); +#ifdef FIX_1139_REV_COLORATION_SHORT_T60 + IF( NE_32( ( error = ivas_binaural_reverb_init( &pMasaInput->hMasaExtRend->hReverb, hIvasRend->hHrtfs.hHrtfStatistics, pMasaInput->hMasaExtRend->hSpatParamRendCom->num_freq_bands, CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES, &( hRenderConfig->roomAcoustics ), *pMasaInput->base.ctx.pOutSampleRate, NULL, NULL, NULL ) ), IVAS_ERR_OK ) ) +#else IF( NE_32( ( error = ivas_binaural_reverb_init( &pMasaInput->hMasaExtRend->hReverb, hIvasRend->hHrtfs.hHrtfStatistics, pMasaInput->hMasaExtRend->hSpatParamRendCom->num_freq_bands, CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES, &( hRenderConfig->roomAcoustics ), *pMasaInput->base.ctx.pOutSampleRate, NULL, NULL ) ), IVAS_ERR_OK ) ) +#endif { return error; } @@ -10060,7 +10068,11 @@ static ivas_error ivas_masa_ext_rend_parambin_init( { #ifdef NONBE_FIX_991_PARAMBIN_BINARY_HRTF #ifdef FIX_587_DEFAULT_REVERB +#ifdef FIX_1139_REV_COLORATION_SHORT_T60 + IF( NE_32( ( error = ivas_binaural_reverb_init( &hDiracDecBin->hReverb, hHrtfStatistics, nBins, CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES, pRoomAcoustics, output_Fs, ( *phHrtfParambin )->parametricReverberationTimes_fx, ( *phHrtfParambin )->parametricReverberationEneCorrections_fx, hDiracDecBin->earlyPartEneCorrection_fx ) ), IVAS_ERR_OK ) ) +#else if ( NE_32( ( error = ivas_binaural_reverb_init( &hDiracDecBin->hReverb, hHrtfStatistics, nBins, CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES, pRoomAcoustics, output_Fs, ( *phHrtfParambin )->parametricReverberationTimes_fx, ( *phHrtfParambin )->parametricReverberationEneCorrections_fx ) ), IVAS_ERR_OK ) ) +#endif #else if ( NE_32( ( error = ivas_binaural_reverb_init( &hDiracDecBin->hReverb, hHrtfStatistics, nBins, CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES, &( hRendCfg->roomAcoustics ), output_Fs, ( *phHrtfParambin )->parametricReverberationTimes_fx, ( *phHrtfParambin )->parametricReverberationEneCorrections_fx ) ), IVAS_ERR_OK ) ) #endif