Commit fcfdadfa authored by Archit Tamarapu's avatar Archit Tamarapu
Browse files

fix for issue 194: introduce a delay buffer for LFE to binaural rendering

parent b492f395
Loading
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -183,6 +183,7 @@
#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 FIX_581_CLANG_OFFSET_TO_NULL                    /* FhG: issue 581: fix CLANG error about applying an offset to a NULL pointer */
#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 */

/* Fixes for bugs found during split rendering contribution development */
#define REND_STATIC_MEM_OPT                             /* Dlb: Static memory optimisation for external renderer */
+112 −3
Original line number Diff line number Diff line
@@ -185,6 +185,10 @@ typedef struct
    lfe_routing lfeRouting;
#ifdef REND_STATIC_MEM_OPT
    float *bufferData;
#endif
#ifdef FIX_194_LFE_DELAY_EXTREND
    int16_t binauralDelaySmp;
    float *lfeDelayBuffer;
#endif
    MCMASA_ANA_HANDLE hMcMasa;
} input_mc;
@@ -305,6 +309,30 @@ static void freeInputBaseBufferData( float **data )
}
#endif

#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 )
{
@@ -2174,6 +2202,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;

@@ -2292,6 +2323,15 @@ 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 != NULL ) ? inputMc->tdRendWrapper.binaural_latency_ns : 0 );
    inputMc->binauralDelaySmp = (int16_t) roundf( (float) binauralDelayNs * *inputMc->base.ctx.pOutSampleRate / 1000000000.f );

    assert( ( inputMc->binauralDelaySmp < L_FRAME48k >> 2 ) && "Invalid delay for LFE binaural rendering!" );

#endif /* FIX_194_LFE_DELAY_EXTREND */
    return IVAS_ERR_OK;
}

@@ -2408,6 +2448,13 @@ static ivas_error setRendInputActiveMc(
        return IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED;
    }

#ifdef FIX_194_LFE_DELAY_EXTREND
    if ( ( error = allocateMcLfeDelayBuffer( &inputMc->lfeDelayBuffer, L_FRAME48k >> 2 ) ) != IVAS_ERR_OK )
    {
        return error;
    }

#endif
#ifdef REND_STATIC_MEM_OPT
    if ( ( error = allocateInputBaseBufferData( &inputMc->bufferData, MAX_BUFFER_LENGTH ) ) != IVAS_ERR_OK )
    {
@@ -2428,6 +2475,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, L_FRAME48k >> 2 );
#endif

#ifdef SPLIT_REND_WITH_HEAD_ROT
    for ( i = 0; i < (int16_t) ( sizeof( inputMc->splitTdRendWrappers ) / sizeof( *inputMc->splitTdRendWrappers ) ); ++i )
@@ -2472,6 +2522,9 @@ static void clearInputMc(

    rendCtx = inputMc->base.ctx;

#ifdef FIX_194_LFE_DELAY_EXTREND
    freeMcLfeDelayBuffer( &inputMc->lfeDelayBuffer );
#endif
#ifdef REND_STATIC_MEM_OPT
    freeInputBaseBufferData( &inputMc->bufferData );
#endif
@@ -6287,11 +6340,17 @@ static ivas_error renderLfeToBinaural(
    IVAS_REND_AudioBuffer outAudio )
{
    int16_t i;
#ifdef FIX_194_LFE_DELAY_EXTREND
    int16_t ear_idx;
#endif
    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
    float *tmpLfeBuffer;
#endif
    float *readPtr, *writePtr;

#ifdef SPLIT_REND_WITH_HEAD_ROT
@@ -6318,8 +6377,38 @@ static ivas_error renderLfeToBinaural(
        return IVAS_ERR_OK;
    }

#ifdef FIX_194_LFE_DELAY_EXTREND
    /*  Render LFE first to a temporary buffer to avoid applying gain multiple times */
    tmpLfeBuffer = malloc( mcInput->base.inputBuffer.config.numSamplesPerChannel * sizeof( float ) );
    if ( tmpLfeBuffer == NULL )
    {
        return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Failed to allocate memory for temporary LFE to Binaural buffer" );
    }

    /* 1. read from the LFE delay buffer and acc. to temp buffer
       2. read remaining samples from the input LFE channel and acc. to temp buffer */
    readPtr = mcInput->lfeDelayBuffer;
    writePtr = tmpLfeBuffer;
    for ( i = 0; i < mcInput->binauralDelaySmp; i++ )
    {
        *writePtr++ += gain * ( *readPtr++ );
    }
    readPtr = getSmplPtr( mcInput->base.inputBuffer, lfe_idx, 0 );
    for ( ; i < ( mcInput->base.inputBuffer.config.numSamplesPerChannel - mcInput->binauralDelaySmp ); i++ )
    {
        *writePtr++ += gain * ( *readPtr++ );
    }

    /* save leftover samples in the LFE delay buffer for next frame */
    writePtr = mcInput->lfeDelayBuffer;
    for ( i = 0; i < mcInput->binauralDelaySmp; i++ )
    {
        *writePtr++ += gain * ( *readPtr++ );
    }

#endif /* FIX_194_LFE_DELAY_EXTREND */
#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;
@@ -6331,6 +6420,14 @@ 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 )
        {
            mvr2r( tmpLfeBuffer,
                   getSmplPtr( outAudio, pose_idx * BINAURAL_CHANNELS + ear_idx, 0 ),
                   mcInput->base.inputBuffer.config.numSamplesPerChannel );
        }
#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++ )
@@ -6344,9 +6441,18 @@ static ivas_error renderLfeToBinaural(
        {
            *writePtr++ += gain * ( *readPtr++ );
        }
#endif /* FIX_194_LFE_DELAY_EXTREND */
    }
#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 )
    {
        mvr2r( tmpLfeBuffer,
               getSmplPtr( outAudio, ear_idx, 0 ),
               mcInput->base.inputBuffer.config.numSamplesPerChannel );
    }
#else
    readPtr = getSmplPtr( mcInput->base.inputBuffer, lfe_idx, 0 );
    writePtr = getSmplPtr( outAudio, 0, 0 );
    for ( i = 0; i < mcInput->base.inputBuffer.config.numSamplesPerChannel; i++ )
@@ -6360,8 +6466,11 @@ static ivas_error renderLfeToBinaural(
    {
        *writePtr++ += gain * ( *readPtr++ );
    }
#endif /* FIX_194_LFE_DELAY_EXTREND */
#endif /* SPLIT_REND_WITH_HEAD_ROT */
    pop_wmops();
#ifdef FIX_194_LFE_DELAY_EXTREND
    free( tmpLfeBuffer );
#endif /* FIX_194_LFE_DELAY_EXTREND */

    return IVAS_ERR_OK;
}