Commit 22c5527c authored by multrus's avatar multrus
Browse files

Merge branch 'basop-2436-isar-do-not-reuse-cldfb-handles' into 'main'

[Split non-BE] Fix reused CLDFB state in rendering of OMASA to SR with lib_rend

See merge request !2872
parents 00960c4f 0126251e
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -108,6 +108,9 @@
#define FIX_2471_REMOVE_POSSIBLE_OVRF                   /* VA: basop issue 2471: correcting undesired overflow */
#define FIX_2465_Q_BWE_EXC                              /* VA: basop issue 2465: fix calculation of Q_bwe_exc in SWB TBE encoder */

#define FIX_2436_CLDFBANAHANDLE_ADRESS                  /*FhG: cldfb handle pointer were handed over in faulty manner*/
#define FIX_BASOP_2436_REUSED_CLDFB_IN_OMASA_SR         /*FhG: basop issue 2436 (related to basop 2283): fix garbage output for >1 object OMASA with extrend as ISAR prerenderer */

/* ##################### End NON-BE switches ########################### */

/* ################## End MAINTENANCE switches ######################### */
+174 −1
Original line number Diff line number Diff line
@@ -529,6 +529,92 @@ static void accumulate2dArrayToBuffer_fx(

    return;
}


#ifdef FIX_BASOP_2436_REUSED_CLDFB_IN_OMASA_SR
/*-------------------------------------------------------------------*
 * audio_buffer_td_to_cldfb_fx()
 *
 * Performs CLDFB analysis on contents of td_buffer and mixes the result into cldfb_buffer.
 *
 * This function **does not** clear the destination buffer before writing.
 *
 * The number of valid CLDFB handles in cldfbAna must be a least equal to the number of channels
 * in the audio buffers.
 *-------------------------------------------------------------------*/
static void audio_buffer_td_to_cldfb_fx(
    IVAS_REND_AudioBuffer td_buffer,
    IVAS_REND_AudioBuffer cldfb_buffer,
    Word32 fs,
    HANDLE_CLDFB_FILTER_BANK *cldfbAna )
{
    Word16 ch, slot_idx;
    Word32 *td_read_ptr;
    Word32 *cldfb_write_ptr;
    Word16 num_bands, num_slots;
    const Word32 inv48000_Q15r = 0x57619F10 /*1/48000 in Q15, rounded*/;

    assert( !td_buffer.config.is_cldfb );
    assert( cldfb_buffer.config.is_cldfb );

    assert( EQ_16( td_buffer.config.numChannels, cldfb_buffer.config.numChannels ) );
    assert( EQ_16( shl( td_buffer.config.numSamplesPerChannel, 1 ), cldfb_buffer.config.numSamplesPerChannel ) );

    td_read_ptr = td_buffer.data_fx;
    cldfb_write_ptr = cldfb_buffer.data_fx;
    num_bands = shl( extract_h( Mpy_32_32( imult3216( fs, CLDFB_NO_CHANNELS_MAX ), inv48000_Q15r ) ), 1 ) /*CLDFB*fs/48000 in Q0*/;
    assert( td_buffer.config.numSamplesPerChannel % num_bands == 0 );
    num_slots = idiv1616( td_buffer.config.numSamplesPerChannel, num_bands );

    FOR( ch = 0; ch < cldfb_buffer.config.numChannels; ++ch )
    {
        FOR( slot_idx = 0; slot_idx < num_slots; ++slot_idx )
        {
            Word32 re[CLDFB_NO_CHANNELS_MAX];
            Word32 im[CLDFB_NO_CHANNELS_MAX];
            Word16 q_cldfb = *( cldfb_buffer.pq_fact );

            cldfbAnalysis_ts_fx( td_read_ptr,
                                 re,
                                 im,
                                 num_bands,
                                 cldfbAna[ch],
                                 &q_cldfb );

            td_read_ptr += num_bands;

            /* scale re and im according to exp-q_cldfb */
            {
                Word16 exp = *( cldfb_buffer.pq_fact );
                Word16 noChannels = cldfbAna[ch]->no_channels;

                Word16 scale = sub( exp, q_cldfb );
                FOR( Word16 j = 0; j < noChannels; j++ )
                {
                    re[j] = L_shl( re[j], scale ); /*Q(exp)*/
                    im[j] = L_shl( im[j], scale ); /*Q(exp)*/
                }
            }

            FOR( int smplIdx = 0; smplIdx < num_bands; smplIdx++ )
            {
                *cldfb_write_ptr = L_add( *cldfb_write_ptr, re[smplIdx] );
                move32();
                cldfb_write_ptr++;
            }

            FOR( int smplIdx = 0; smplIdx < num_bands; smplIdx++ )
            {
                *cldfb_write_ptr = L_add( *cldfb_write_ptr, im[smplIdx] );
                move32();
                cldfb_write_ptr++;
            }
        }
    }
}
#endif


/*-------------------------------------------------------------------*
 * limitRendererOutput()
 *
@@ -7069,16 +7155,25 @@ static ivas_error renderIsmToSplitBinaural(
    const SPLIT_REND_WRAPPER *pSplitRendWrapper;
    IVAS_QUATERNION originalHeadRot[MAX_PARAM_SPATIAL_SUBFRAMES];
    IVAS_QUATERNION localHeadRot[MAX_PARAM_SPATIAL_SUBFRAMES];
    Word16 i, ch, slot_idx, num_bands;
    Word16 i;
    Word32 tmpBinaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][L_FRAME48k];
#ifndef FIX_BASOP_2436_REUSED_CLDFB_IN_OMASA_SR
    Word16 ch, slot_idx, num_bands;
    Word32 tmpBinaural_CldfbRe[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
    Word32 tmpBinaural_CldfbIm[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
#endif
    Word16 output_frame = ismInput->base.inputBuffer.config.numSamplesPerChannel;
    COMBINED_ORIENTATION_HANDLE pCombinedOrientationData;
    Word16 ism_md_subframe_update_ext, exp;

    push_wmops( "renderIsmToSplitBinaural" );

#ifdef FIX_BASOP_2436_REUSED_CLDFB_IN_OMASA_SR
    assert( !outAudio.config.is_cldfb &&
            "ISM renderering only supports TD output. If CLDFB output was requested, "
            "we convert to CLDFB higher up the stack after rendering all ISMs" );
#endif

    pSplitRendWrapper = ismInput->base.ctx.pSplitRendWrapper;
    pMultiBinPoseData = &pSplitRendWrapper->multiBinPoseData;

@@ -7160,6 +7255,7 @@ static ivas_error renderIsmToSplitBinaural(
            }
        }

#ifndef FIX_BASOP_2436_REUSED_CLDFB_IN_OMASA_SR
        IF( NE_16( outAudio.config.is_cldfb, 0 ) )
        {
            /* Perform CLDFB analysis on rendered audio, since the output buffer is CLDFB domain */
@@ -7175,7 +7271,11 @@ static ivas_error renderIsmToSplitBinaural(
                                         &tmpBinaural_CldfbRe[BINAURAL_CHANNELS * pos_idx + ch][slot_idx][0],
                                         &tmpBinaural_CldfbIm[BINAURAL_CHANNELS * pos_idx + ch][slot_idx][0],
                                         num_bands,
#ifdef FIX_2436_CLDFBANAHANDLE_ADRESS
                                         ismInput->base.ctx.pSplitRendWrapper->hCldfbHandles->cldfbAna[BINAURAL_CHANNELS * pos_idx + ch],
#else
                                         ismInput->base.ctx.pSplitRendWrapper->hCldfbHandles->cldfbAna[pos_idx + ch],
#endif
                                         &q_cldfb );
                    /* scale re and im according to exp-q_cldfb */
                    {
@@ -7196,12 +7296,15 @@ static ivas_error renderIsmToSplitBinaural(
        }
        ELSE
        {
#endif /*FIX_BASOP_2436_REUSED_CLDFB_IN_OMASA_SR*/

            /* Copy rendered audio to tmp storage buffer. Copying directly to output would
             * overwrite original audio, which is still needed for rendering next head pose. */
            Copy32( tmpProcessing[0], tmpBinaural[i_mult( 2, pos_idx )], output_frame );
            Copy32( tmpProcessing[1], tmpBinaural[add( i_mult( 2, pos_idx ), 1 )], output_frame );
#ifndef FIX_BASOP_2436_REUSED_CLDFB_IN_OMASA_SR
        }
#endif

        /* Overwrite processing buffer with original input audio again */
        copyBufferTo2dArray_fx( ismInput->base.inputBuffer, tmpProcessing );
@@ -7213,14 +7316,18 @@ static ivas_error renderIsmToSplitBinaural(
        Copy_Quat_fx( &originalHeadRot[i], &pCombinedOrientationData->Quaternions[i] );
    }

#ifndef FIX_BASOP_2436_REUSED_CLDFB_IN_OMASA_SR
    if ( outAudio.config.is_cldfb )
    {
        accumulateCLDFBArrayToBuffer_fx( tmpBinaural_CldfbRe, tmpBinaural_CldfbIm, exp, &outAudio );
    }
    else
    {
#endif /*FIX_BASOP_2436_REUSED_CLDFB_IN_OMASA_SR*/
        accumulate2dArrayToBuffer_fx( tmpBinaural, &outAudio );
#ifndef FIX_BASOP_2436_REUSED_CLDFB_IN_OMASA_SR
    }
#endif
    pop_wmops();

    /* Encoding to split rendering bitstream done at a higher level */
@@ -7373,6 +7480,57 @@ static ivas_error renderActiveInputsIsm(
    ivas_error error;
    Word16 input_q = outAudio.q_factor;
    move16();

#ifdef FIX_BASOP_2436_REUSED_CLDFB_IN_OMASA_SR
    Word16 num_active_inputs;
    IVAS_REND_AudioBuffer work_buffer;
    Word32 tmp_td_binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS * L_FRAME48k];

    // Early return in case there are no active ISM inputs
    num_active_inputs = 0;
    move16();
    pCurrentInput = hIvasRend->inputsIsm;

    FOR( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i )
    {
        if ( NE_32( pCurrentInput->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
        {
            num_active_inputs = add( num_active_inputs, 1 );
        }
        ++pCurrentInput;
    }
    IF( num_active_inputs == 0 )
    {
        return IVAS_ERR_OK;
    }

    // By default (TD output), use outAudio as work_buffer. This means we render individual ISMs
    // directly to outAudio, since the `data` member of both these structs is pointing to the same memory.
    // Initializing this way also fixes MSVC's false-positive warning about work_buffer being used
    // without initialization in code below, as well as some WMC tool instrumentation problems.
    work_buffer = outAudio;
    move16();
    move16();
    move16();
    move16();
    move32();
    move32();

    // ISM rendering only supports TD output. If CLDFB output was requested, we first render
    // to TD in a temporary buffer and then convert to CLDFB. We do this by swapping out the
    // underlying memory of work_buffer and modifying its config to TD.
    IF( outAudio.config.is_cldfb )
    {
        work_buffer.config.numSamplesPerChannel = shr( work_buffer.config.numSamplesPerChannel, 1 );
        work_buffer.config.is_cldfb = false;
        move16();

        work_buffer.data_fx = tmp_td_binaural;
        move32();
        set32_fx( tmp_td_binaural, 0, MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS * L_FRAME48k );
    }
#endif

    FOR( ( i = 0, pCurrentInput = hIvasRend->inputsIsm ); i < RENDERER_MAX_ISM_INPUTS; ( ++i, ++pCurrentInput ) )
    {
        IF( EQ_32( pCurrentInput->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
@@ -7383,10 +7541,15 @@ static ivas_error renderActiveInputsIsm(

        *outAudio.pq_fact = input_q;
        move16();
#ifdef FIX_BASOP_2436_REUSED_CLDFB_IN_OMASA_SR
        IF( NE_32( ( error = renderInputIsm( pCurrentInput, hIvasRend->outputConfig, work_buffer ) ), IVAS_ERR_OK ) )
#else
        IF( NE_32( ( error = renderInputIsm( pCurrentInput, hIvasRend->outputConfig, outAudio ) ), IVAS_ERR_OK ) )
#endif
        {
            return error;
        }

        FOR( Word16 j = 0; j < outAudio.config.numSamplesPerChannel * outAudio.config.numChannels; ++j )
        {
            outAudio.data_fx[j] = L_shl( outAudio.data_fx[j], sub( sub( input_q, 1 ), ( *outAudio.pq_fact ) ) ); /* Q(input_q - 1) */
@@ -7396,6 +7559,16 @@ static ivas_error renderActiveInputsIsm(
        move16();
    }

#ifdef FIX_BASOP_2436_REUSED_CLDFB_IN_OMASA_SR
    IF( outAudio.config.is_cldfb )
    {
        audio_buffer_td_to_cldfb_fx( work_buffer,
                                     outAudio,
                                     hIvasRend->sampleRateOut,
                                     hIvasRend->splitRendWrapper->hCldfbHandles->cldfbAna );
    }
#endif

    return IVAS_ERR_OK;
}