diff --git a/lib_com/options.h b/lib_com/options.h index c068ea99094dda58cdb57a2f5bde2044c37c4d51..c2bc0b866b05b09d53460339bca577ae01a9052d 100755 --- a/lib_com/options.h +++ b/lib_com/options.h @@ -187,6 +187,7 @@ #define NONBE_FIX_589_JBM_TC_OFFSETS /* FhG: issue 589: wrong offset into the TC buffers is used in some rendering paths in the JBM main rendering function */ #define FIX_MEM_REALLOC_IND_LIST /* VA: issue 601: failure of the automatic memory re-allocation mechanism when ind_list[] buffer is depleted in MASA mode with 2 TC*/ #define JBM_PARAMUPMIX /* Dlb: Issue 471: Integrate the Multichannel Parametric Upmix into the JBM path */ +#define FIX_194_LFE_DELAY_EXTREND /* FhG: Issue 194: Fix delay alignment of LFE in external renderer */ #define FIX_582_INDEX_OUT_OF_BOUNDS_SNS_AVQ_DEC /* FhG: fix an undefined behaviour error in SNS AVQ decoding */ #define FIX_614_ADD_TO_NULL_PTR_DIRAC_SETUP /* FhG: Issue 614: prevent adding to a null pointer in dirac setup code */ #define UPDATE_REVERB_UTILS /* Use CLDFB HRTFs of the appropriate SBA order in get_IR_from_filter_taps() */ diff --git a/lib_rend/lib_rend.c b/lib_rend/lib_rend.c index 5a99ae0057ef80cb32e7c5f05c9f11971854fd7c..6dd53bdd025d3d6d75fe8c70f4b771223fa4c46d 100644 --- a/lib_rend/lib_rend.c +++ b/lib_rend/lib_rend.c @@ -61,6 +61,10 @@ #define MAX_CLDFB_BUFFER_LENGTH ( MAX_CLDFB_BUFFER_LENGTH_PER_CHANNEL * MAX_INPUT_CHANNELS ) #define MAX_BIN_BUFFER_LENGTH ( MAX_BUFFER_LENGTH_PER_CHANNEL * BINAURAL_CHANNELS ) +#ifdef FIX_194_LFE_DELAY_EXTREND +#define MAX_BIN_DELAY_SAMPLES 50 /* Maximum supported rendering latency for binaural IRs */ +#endif + #else #define MAX_BUFFER_LENGTH ( MAX_BUFFER_LENGTH_PER_CHANNEL * MAX_INPUT_CHANNELS ) #endif @@ -178,6 +182,10 @@ typedef struct float nonDiegeticPanGain; lfe_routing lfeRouting; float *bufferData; +#ifdef FIX_194_LFE_DELAY_EXTREND + int16_t binauralDelaySmp; + float *lfeDelayBuffer; +#endif MCMASA_ANA_HANDLE hMcMasa; } input_mc; @@ -289,6 +297,30 @@ static void freeInputBaseBufferData( float **data ) return; } +#ifdef FIX_194_LFE_DELAY_EXTREND +static ivas_error allocateMcLfeDelayBuffer( float **lfeDelayBuffer, const int16_t data_size ) +{ + *lfeDelayBuffer = (float *) malloc( data_size * sizeof( float ) ); + if ( *lfeDelayBuffer == NULL ) + { + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Cannot allocate memory for LFE delay buffer" ); + } + + return IVAS_ERR_OK; +} + +static void freeMcLfeDelayBuffer( float **lfeDelayBuffer ) +{ + if ( *lfeDelayBuffer != NULL ) + { + free( *lfeDelayBuffer ); + *lfeDelayBuffer = NULL; + } + + return; +} + +#endif static IVAS_QUATERNION quaternionInit( void ) { @@ -2136,6 +2168,9 @@ static ivas_error initMcBinauralRendering( ivas_error error; #ifdef SPLIT_REND_WITH_HEAD_ROT int16_t i; +#endif +#ifdef FIX_194_LFE_DELAY_EXTREND + int32_t binauralDelayNs; #endif int32_t outSampleRate; @@ -2254,6 +2289,18 @@ static ivas_error initMcBinauralRendering( } } +#ifdef FIX_194_LFE_DELAY_EXTREND + /* determine binaural delay ( used for aligning LFE to output signal ) */ + binauralDelayNs = max( ( inputMc->crendWrapper != NULL ) ? inputMc->crendWrapper->binaural_latency_ns : 0, + inputMc->tdRendWrapper.binaural_latency_ns ); + inputMc->binauralDelaySmp = (int16_t) roundf( (float) binauralDelayNs * *inputMc->base.ctx.pOutSampleRate / 1000000000.f ); + + if ( inputMc->binauralDelaySmp > MAX_BIN_DELAY_SAMPLES ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Invalid delay for LFE binaural rendering!)" ); + } + +#endif /* FIX_194_LFE_DELAY_EXTREND */ return IVAS_ERR_OK; } @@ -2370,6 +2417,13 @@ static ivas_error setRendInputActiveMc( return IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED; } +#ifdef FIX_194_LFE_DELAY_EXTREND + if ( ( error = allocateMcLfeDelayBuffer( &inputMc->lfeDelayBuffer, MAX_BIN_DELAY_SAMPLES ) ) != IVAS_ERR_OK ) + { + return error; + } + +#endif if ( ( error = allocateInputBaseBufferData( &inputMc->bufferData, MAX_BUFFER_LENGTH ) ) != IVAS_ERR_OK ) { return error; @@ -2384,6 +2438,9 @@ static ivas_error setRendInputActiveMc( inputMc->hMcMasa = NULL; initRotGains( inputMc->rot_gains_prev ); inputMc->lfeRouting = defaultLfeRouting( inConfig, inputMc->customLsInput, outConfig, *inputMc->base.ctx.pCustomLsOut ); +#ifdef FIX_194_LFE_DELAY_EXTREND + set_zero( inputMc->lfeDelayBuffer, MAX_BIN_DELAY_SAMPLES ); +#endif #ifdef SPLIT_REND_WITH_HEAD_ROT for ( i = 0; i < (int16_t) ( sizeof( inputMc->splitTdRendWrappers ) / sizeof( *inputMc->splitTdRendWrappers ) ); ++i ) @@ -2428,6 +2485,9 @@ static void clearInputMc( rendCtx = inputMc->base.ctx; +#ifdef FIX_194_LFE_DELAY_EXTREND + freeMcLfeDelayBuffer( &inputMc->lfeDelayBuffer ); +#endif freeInputBaseBufferData( &inputMc->bufferData ); initRendInputBase( &inputMc->base, IVAS_REND_AUDIO_CONFIG_UNKNOWN, 0, rendCtx, NULL, 0 ); @@ -3577,6 +3637,9 @@ ivas_error IVAS_REND_Open( hIvasRend->inputsMc[i].hReverb = NULL; hIvasRend->inputsMc[i].tdRendWrapper.hBinRendererTd = NULL; hIvasRend->inputsMc[i].bufferData = NULL; +#ifdef FIX_194_LFE_DELAY_EXTREND + hIvasRend->inputsMc[i].lfeDelayBuffer = NULL; +#endif hIvasRend->inputsMc[i].nonDiegeticPan = nonDiegeticPan; hIvasRend->inputsMc[i].nonDiegeticPanGain = nonDiegeticPanGain; hIvasRend->inputsMc[i].hMcMasa = NULL; @@ -6191,13 +6254,21 @@ static ivas_error renderLfeToBinaural( #endif IVAS_REND_AudioBuffer outAudio ) { - int16_t i; int16_t lfe_idx; #ifdef SPLIT_REND_WITH_HEAD_ROT int16_t pose_idx, num_poses; #endif float gain; +#ifdef FIX_194_LFE_DELAY_EXTREND + int16_t ear_idx; + float tmpLfeBuffer[MAX_BUFFER_LENGTH_PER_CHANNEL]; + int16_t frame_size, num_cpy_smpl_cur_frame, num_cpy_smpl_prev_frame; + const float *lfeInput; + float *writePtr; +#else + int16_t i; float *readPtr, *writePtr; +#endif #ifdef SPLIT_REND_WITH_HEAD_ROT assert( ( getAudioConfigType( outConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) && "Must be binaural output" ); @@ -6223,8 +6294,24 @@ static ivas_error renderLfeToBinaural( return IVAS_ERR_OK; } +#ifdef FIX_194_LFE_DELAY_EXTREND + /* --- Prepare LFE signal to be added to binaural output --- */ + lfeInput = getSmplPtr( mcInput->base.inputBuffer, lfe_idx, 0 ); + frame_size = mcInput->base.inputBuffer.config.numSamplesPerChannel; + num_cpy_smpl_prev_frame = mcInput->binauralDelaySmp; + num_cpy_smpl_cur_frame = frame_size - num_cpy_smpl_prev_frame; + /* Assuming LFE should be delayed by less that the duration of one frame */ + assert( mcInput->binauralDelaySmp < frame_size ); + /* Get delayed LFE signal from previous frame, apply gain and save in tmp buffer */ + v_multc( mcInput->lfeDelayBuffer, gain, tmpLfeBuffer, num_cpy_smpl_prev_frame ); + /* Continue filling tmp buffer, now with LFE signal from current frame */ + v_multc( lfeInput, gain, tmpLfeBuffer + num_cpy_smpl_prev_frame, num_cpy_smpl_cur_frame ); + /* Save remaining LFE samples of current frame for next frame */ + mvr2r( lfeInput + num_cpy_smpl_cur_frame, mcInput->lfeDelayBuffer, num_cpy_smpl_prev_frame ); +#endif + #ifdef SPLIT_REND_WITH_HEAD_ROT - /* Copy LFE to left and right binaural channels */ + /* Copy LFE to left and right binaural channels for all poses */ if ( mcInput->base.ctx.pSplitRendWrapper != NULL ) { num_poses = mcInput->base.ctx.pSplitRendWrapper->multiBinPoseData.num_poses; @@ -6236,6 +6323,13 @@ static ivas_error renderLfeToBinaural( for ( pose_idx = 0; pose_idx < num_poses; ++pose_idx ) { +#ifdef FIX_194_LFE_DELAY_EXTREND + for ( ear_idx = 0; ear_idx < BINAURAL_CHANNELS; ++ear_idx ) + { + writePtr = getSmplPtr( outAudio, pose_idx * BINAURAL_CHANNELS + ear_idx, 0 ); + v_add( writePtr, tmpLfeBuffer, writePtr, frame_size ); + } +#else readPtr = getSmplPtr( mcInput->base.inputBuffer, lfe_idx, 0 ); writePtr = getSmplPtr( outAudio, pose_idx * BINAURAL_CHANNELS, 0 ); for ( i = 0; i < mcInput->base.inputBuffer.config.numSamplesPerChannel; i++ ) @@ -6249,9 +6343,17 @@ static ivas_error renderLfeToBinaural( { *writePtr++ += gain * ( *readPtr++ ); } +#endif /* FIX_194_LFE_DELAY_EXTREND */ } -#else /* SPLIT_REND_WITH_HEAD_ROT */ +#else /* SPLIT_REND_WITH_HEAD_ROT */ /* Copy LFE to left and right ears */ +#ifdef FIX_194_LFE_DELAY_EXTREND + for ( ear_idx = 0; ear_idx < BINAURAL_CHANNELS; ++ear_idx ) + { + writePtr = getSmplPtr( outAudio, pose_idx * BINAURAL_CHANNELS + ear_idx, 0 ); + v_add( writePtr, tmpLfeBuffer, writePtr, frame_size ); + } +#else readPtr = getSmplPtr( mcInput->base.inputBuffer, lfe_idx, 0 ); writePtr = getSmplPtr( outAudio, 0, 0 ); for ( i = 0; i < mcInput->base.inputBuffer.config.numSamplesPerChannel; i++ ) @@ -6265,7 +6367,9 @@ static ivas_error renderLfeToBinaural( { *writePtr++ += gain * ( *readPtr++ ); } +#endif /* FIX_194_LFE_DELAY_EXTREND */ #endif /* SPLIT_REND_WITH_HEAD_ROT */ + pop_wmops(); return IVAS_ERR_OK;