Skip to content
FEC_HQ_phase_ecu.c 73.9 KiB
Newer Older
Marek Szczerba's avatar
Marek Szczerba committed
    }

    mvr2r( synthesis, synthesis + kk, 2 * L - kk );
    mvr2r( synthesis + L, gapsynth, L );

    mvr2r( prevsynth + alignment_point - kk, synthesis, kk );

    return;
}


/*--------------------------------------------------------------------------
 *  fec_alg()
 *
 *  Pitch based error-concealment algorithm with adaptive analysis frame
 *  length
 *--------------------------------------------------------------------------*/

static void fec_alg(
    const float *prevsynth,       /* i  : previous synthesis                         */
    const float *prevsynth_LP,    /* i  : down-sampled synthesis                     */
    float *ecu_rec,               /* o  : ECU frame with Windowing/TDA               */
    const int16_t output_frame,   /* i  : Output frame length                        */
    const int16_t N,              /* i  : Analysis frame length in 8 kHz (corr. max) */
    const int16_t decimatefactor, /* i  : Downsampling factor                        */
    const int16_t HqVoicing,      /* i  : HQ voicing flag                            */
    float *gapsynth,              /* o  : Buffer for crossfade to good frame         */
    int16_t *ni_seed_forfec,      /* i/o: Random seed for picking noise segments     */
    const int16_t element_mode,   /* i  : IVAS element mode                          */
    const float *old_out

)
{
    int16_t n, Nfft;
    float sum_Tf_abs;
    float Tfr[FEC_FFT_MAX_SIZE];
    float Tfi[FEC_FFT_MAX_SIZE];
    float Tf_abs[FEC_FFT_MAX_SIZE / 2];
    float synthesis[2 * L_FRAME48k];

    fec_ecu_dft( prevsynth_LP, N, Tfr, Tfi, &sum_Tf_abs, Tf_abs, &Nfft, element_mode );

    sinusoidal_synthesis( Tfr, Tfi, Tf_abs, N, output_frame, decimatefactor, Nfft, sum_Tf_abs, synthesis, HqVoicing );

    fec_noise_filling( prevsynth, synthesis, output_frame, N * decimatefactor, HqVoicing, gapsynth, ni_seed_forfec, element_mode, old_out );

Jonas Svedberg's avatar
Jonas Svedberg committed
    n = (int16_t) ( (float) output_frame * N_ZERO_MDCT_NS / FRAME_SIZE_NS );
Marek Szczerba's avatar
Marek Szczerba committed
    wtda( synthesis + ( output_frame - n ), ecu_rec, NULL, ALDO_WINDOW, ALDO_WINDOW, output_frame );

    return;
}


/*--------------------------------------------------------------------------
 *  hq_phase_ecu()
 *
 *  Main routine for HQ phase ECU
 *--------------------------------------------------------------------------*/

static void hq_phase_ecu(
    const float *prevsynth,            /* i  : buffer of previously synthesized signal   */
    float *ecu_rec,                    /* o  : reconstructed frame in tda domain         */
    int16_t *time_offs,                /* i/o: Sample offset for consecutive frame losses*/
    float *X_sav,                      /* i/o: Stored spectrum of prototype frame        */
    int16_t *num_p,                    /* i/o: Number of identified peaks                */
    int16_t *plocs,                    /* i/o: Peak locations                            */
    float *plocsi,                     /* i/o: Interpolated peak locations               */
    const float env_stab,              /* i  : Envelope stability parameter              */
    int16_t *last_fec,                 /* i/o: Flag for usage of pitch dependent ECU     */
    const int16_t prev_bfi,            /* i  : indicating burst frame error              */
    const int16_t old_is_transient[2], /* i  : flags indicating previous transient frames*/
    float *mag_chg_1st,                /* i/o: per band magnitude modifier for transients*/
    float Xavg[LGW_MAX],               /* i/o: Frequency group average gain to fade to   */
    float *beta_mute,                  /* o  : Factor for long-term mute                 */
    const int16_t bwidth,              /* i  : Encoded bandwidth                         */
    const int16_t output_frame,        /* i  : frame length                              */
    const float pcorr,                 /* i  : pitch correlation                         */
    const int16_t element_mode         /* i  : IVAS element mode                         */
)
{
    int16_t Lprot;
    float mag_chg[LGW_MAX], ph_dith, X[L_PROT48k];
    int16_t seed;
    float alpha[LGW_MAX], beta[LGW_MAX];
    const float *old_dec;
    float noise_fac;
    int16_t ph_ecu_lookahead;

    noise_fac = 1.0f;

    if ( element_mode == EVS_MONO )
    {
        ph_ecu_lookahead = NS2SA( output_frame * FRAMES_PER_SEC, PH_ECU_LOOKAHEAD_NS );
    }
    else
    {
        ph_ecu_lookahead = 0;
    }


    Lprot = ( 2 * output_frame * 4 ) / 5;

    if ( !prev_bfi || ( prev_bfi && *last_fec && ( *time_offs == output_frame ) ) )
    {
        if ( !( prev_bfi && *last_fec && ( element_mode == EVS_MONO ) ) )
        {
            *time_offs = 0; /* IVAS reset of offset time counter, timeoffset variable later also used to calculate burst length */
        }
Marek Szczerba's avatar
Marek Szczerba committed

        trans_ana( prevsynth + 2 * output_frame - Lprot - *time_offs + ph_ecu_lookahead, mag_chg, &ph_dith, mag_chg_1st, output_frame, *time_offs, env_stab, *last_fec, element_mode, alpha, beta, beta_mute, Xavg );
Marek Szczerba's avatar
Marek Szczerba committed
        spec_ana( prevsynth + 2 * output_frame - Lprot - *time_offs + ph_ecu_lookahead, plocs, plocsi, num_p, X_sav, output_frame, bwidth, element_mode, &noise_fac, pcorr );

        if ( prev_bfi && *last_fec )
        {
            if ( element_mode != EVS_MONO )
Jonas Svedberg's avatar
Jonas Svedberg committed
            {
                *time_offs = (int16_t) ( *time_offs + output_frame ); /* USAN avoid risk of internal int32_t  in "+="  */
Jonas Svedberg's avatar
Jonas Svedberg committed
                {                                     /* detected wrap around  of st->time_offs */
                    *time_offs = (int16_t) INT16_MAX; /* keep a very high value so that the long term muting stays on */
Jonas Svedberg's avatar
Jonas Svedberg committed
                *time_offs = (int16_t) ( *time_offs + output_frame ); /* EVS_MONO BE compatible, but EVS CR needed as wrap will cause burst length muting envelope instability issues */
Jonas Svedberg's avatar
Jonas Svedberg committed
        *time_offs = (int16_t) ( *time_offs + output_frame ); /* cast added for USAN, "+=" avoided as it may creat a truncation from int to int16_t  */
Marek Szczerba's avatar
Marek Szczerba committed
        if ( *time_offs <= 0 )
        {
            /* detect wrap around  of st->time_offs */
            *time_offs = (int16_t) INT16_MAX; /* high value --> continued muting will ensure that the now saturated  seed is not creating tones */
        trans_ana( prevsynth + 2 * output_frame - Lprot, mag_chg, &ph_dith, mag_chg_1st, output_frame, *time_offs, env_stab, 0, element_mode, alpha, beta, beta_mute, Xavg ); /* 1.0 stable-music,  0.0 speech-like */
Marek Szczerba's avatar
Marek Szczerba committed
    }

    mvr2r( X_sav, X, Lprot );

    /* seed for own_rand2 */
    seed = *time_offs;
    if ( *num_p > 0 )
    {
Jonas Svedberg's avatar
Jonas Svedberg committed
        seed = (int16_t) ( seed + plocs[*num_p - 1] ); /* explicit cast and "+="  not used,  as it "+="  may create a cast from 32 bit to 16 bit, triggering USAN   */
Marek Szczerba's avatar
Marek Szczerba committed
    }

    subst_spec( plocs, plocsi, num_p, *time_offs, X, mag_chg, ph_dith, old_is_transient, output_frame, &seed, alpha, beta, *beta_mute, Xavg, element_mode, ph_ecu_lookahead, noise_fac );

    /* reconstructed frame in tda domain */
    old_dec = prevsynth + 2 * output_frame - NS2SA( output_frame * FRAMES_PER_SEC, N_ZERO_MDCT_NS );
    rec_frame( X, ecu_rec, output_frame, old_dec, element_mode, num_p, plocs );

    return;
}


/*--------------------------------------------------------------------------
 *  hq_ecu()
 *
 *  Main routine for HQ ECU
 *--------------------------------------------------------------------------*/

void hq_ecu(
    const float *prevsynth,            /* i  : buffer of previously synthesized signal   */
    float *ecu_rec,                    /* o  : reconstructed frame in tda domain         */
    int16_t *time_offs,                /* i/o: Sample offset for consecutive frame losses*/
    float *X_sav,                      /* i/o: Stored spectrum of prototype frame        */
    int16_t *num_p,                    /* i/o: Number of identified peaks                */
    int16_t *plocs,                    /* i/o: Peak locations                            */
    float *plocsi,                     /* i/o: Interpolated peak locations               */
    const float env_stab,              /* i  : Envelope stability parameter              */
    int16_t *last_fec,                 /* i/o: Flag for usage of pitch dependent ECU     */
    const int16_t ph_ecu_HqVoicing,    /* i  : HQ Voicing flag                           */
    int16_t *ph_ecu_active,            /* i  : Phase ECU active flag                     */
    float *gapsynth,                   /* o  : Gap synthesis for crossfade to good frame */
    const int16_t prev_bfi,            /* i  : indicating burst frame error              */
    const int16_t old_is_transient[2], /* i  : flags indicating previous transient frames*/
    float *mag_chg_1st,                /* i/o: per band magnitude modifier for transients*/
    float Xavg[LGW_MAX],               /* i/o: Frequency group average gain to fade to   */
vaclav's avatar
vaclav committed
    float *beta_mute,                  /* o  : Factor for long-term mute                 */
Marek Szczerba's avatar
Marek Szczerba committed
    const int16_t output_frame,        /* i  : frame length                              */
    Decoder_State *st                  /* i/o: decoder state structure                   */
)
{
    int16_t N;
    float corr = 0.0f;
    int16_t decimatefactor;
    float prevsynth_LP[2 * L_FRAME8k];
    HQ_DEC_HANDLE hHQ_core;
    const float *fec_alg_input;
    int16_t evs_mode_selection;
    int16_t ivas_mode_selection;

    hHQ_core = st->hHQ_core;
    if ( st->element_mode == EVS_MONO )
    {
        fec_alg_input = prevsynth + NS2SA( output_frame * FRAMES_PER_SEC, ACELP_LOOK_NS / 2 - PH_ECU_LOOKAHEAD_NS );
    }
    else
    {
        fec_alg_input = prevsynth - NS2SA( output_frame * FRAMES_PER_SEC, PH_ECU_LOOKAHEAD_NS );
    }

    /* find pitch and R value */
    if ( !( output_frame < L_FRAME16k ) )
    {
        fec_ecu_pitch( fec_alg_input, prevsynth_LP, output_frame, &N, &corr, &decimatefactor, ph_ecu_HqVoicing );
    }
    else
    {
        corr = 0.0f;
        decimatefactor = 4;
        N = output_frame / 4;
    }

    evs_mode_selection = ( st->total_brate >= 48000 && ( output_frame >= L_FRAME16k && !prev_bfi && ( !old_is_transient[0] || old_is_transient[1] ) &&
                                                         ( ph_ecu_HqVoicing || ( ( ( hHQ_core->env_stab_plc > 0.5 ) && ( corr < 0.6 ) ) || ( hHQ_core->env_stab_plc < 0.5 && ( corr > 0.85 ) ) ) ) ) ) ||
                         ( st->total_brate < 48000 && ( ( ph_ecu_HqVoicing || corr > 0.85 ) && !prev_bfi && ( !old_is_transient[0] || old_is_transient[1] ) ) );

    ivas_mode_selection = ( N < PH_ECU_N_LIMIT ) || ( corr < PH_ECU_CORR_LIMIT );

    if ( ( ( st->element_mode == EVS_MONO ) && evs_mode_selection ) ||
         ( ( st->element_mode != EVS_MONO ) && evs_mode_selection && ivas_mode_selection ) )

    {
        fec_alg( fec_alg_input, prevsynth_LP, ecu_rec, output_frame, N, decimatefactor, ph_ecu_HqVoicing, gapsynth, &hHQ_core->ni_seed_forfec, st->element_mode, st->hHQ_core->old_out );
        *last_fec = 1;
        *ph_ecu_active = 0;
        *time_offs = output_frame;
    }
    else
    {
        hq_phase_ecu( prevsynth - NS2SA( output_frame * FRAMES_PER_SEC, PH_ECU_LOOKAHEAD_NS ), ecu_rec, time_offs, X_sav, num_p, plocs, plocsi, env_stab, last_fec, prev_bfi, old_is_transient, mag_chg_1st, Xavg, beta_mute, st->bwidth, output_frame, corr, st->element_mode );

        *last_fec = 0;
        *ph_ecu_active = 1;
    }

    return;
}