view src/dec_12k2.c @ 5:799b56cbccb6

EFR2 decoder: add post-processing step from AMR
author Mychaela Falconia <falcon@freecalypso.org>
date Wed, 03 Apr 2024 06:09:10 +0000
parents 56410792419a
children
line wrap: on
line source

/***************************************************************************
 *
 *  FILE NAME:    dec_12k2.c
 *
 *  FUNCTIONS DEFINED IN THIS FILE:
 *                   Init_Decoder_12k2   and  Decoder_12k2
 *
 *
 *  Init_Decoder_12k2():
 *      Initialization of variables for the decoder section.
 *
 *  Decoder_12k2():
 *      Speech decoder routine operating on a frame basis.
 *
 ***************************************************************************/

#include "typedef.h"
#include "basic_op.h"
#include "sig_proc.h"
#include "count.h"
#include "codec.h"
#include "cnst.h"

#include "dtx.h"

extern Word16 dtx_mode;

/*---------------------------------------------------------------*
 *   Decoder constant parameters (defined in "cnst.h")           *
 *---------------------------------------------------------------*
 *   L_FRAME     : Frame size.                                   *
 *   L_FRAME_BY2 : Half the frame size.                          *
 *   L_SUBFR     : Sub-frame size.                               *
 *   M           : LPC order.                                    *
 *   MP1         : LPC order+1                                   *
 *   PIT_MIN     : Minimum pitch lag.                            *
 *   PIT_MAX     : Maximum pitch lag.                            *
 *   L_INTERPOL  : Length of filter for interpolation            *
 *   PRM_SIZE    : size of vector containing analysis parameters *
 *---------------------------------------------------------------*/

/*--------------------------------------------------------*
 *         Static memory allocation.                      *
 *--------------------------------------------------------*/

 /* Excitation vector */

static Word16 old_exc[L_FRAME + PIT_MAX + L_INTERPOL];
static Word16 *exc;

 /* Lsp (Line spectral pairs) */

static Word16 lsp_old[M];

 /* Filter's memory */

static Word16 mem_syn[M];

 /* Memories for bad frame handling */

static Word16 prev_bf;
static Word16 state;

/***************************************************************************
 *
 *   FUNCTION:  Init_Decoder_12k2
 *
 *   PURPOSE: Initialization of variables for the decoder section.
 *
 ***************************************************************************/

void Init_Decoder_12k2 (void)
{
    /* Initialize static pointer */

    exc = old_exc + PIT_MAX + L_INTERPOL;

    /* Static vectors to zero */

    Set_zero (old_exc, PIT_MAX + L_INTERPOL);
    Set_zero (mem_syn, M);

    /* Initialize lsp_old [] */

    lsp_old[0] = 30000;
    lsp_old[1] = 26000;
    lsp_old[2] = 21000;
    lsp_old[3] = 15000;
    lsp_old[4] = 8000;
    lsp_old[5] = 0;
    lsp_old[6] = -8000;
    lsp_old[7] = -15000;
    lsp_old[8] = -21000;
    lsp_old[9] = -26000;

    /* Initialize memories of bad frame handling */

    prev_bf = 0;
    state = 0;

    return;
}

/***************************************************************************
 *
 *   FUNCTION:  Decoder_12k2
 *
 *   PURPOSE:   Speech decoder routine.
 *
 ***************************************************************************/

void Decoder_12k2 (
    Word16 parm[], /* input : vector of synthesis parameters
                      parm[0] = bad frame indicator (bfi)       */
    Word16 synth[],/* output: synthesis speech                  */
    Word16 A_t[],  /* output: decoded LP filter in 4 subframes  */
    Word16 TAF,
    Word16 SID_flag
)
{

    /* LPC coefficients */

    Word16 *Az;                 /* Pointer on A_t */

    /* LSPs */

    Word16 lsp_new[M];
    Word16 lsp_mid[M];

    /* Algebraic codevector */

    Word16 code[L_SUBFR];

    /* excitation */

    Word16 excp[L_SUBFR];

    /* Scalars */

    Word16 i, i_subfr;
    Word16 T0, T0_frac, index;
    Word16 gain_pit, gain_code, bfi, pit_sharp;
    Word16 temp;
    Word32 L_temp;

    extern Word16 rxdtx_ctrl, rx_dtx_state;
    extern Word32 L_pn_seed_rx;

    /* Test bad frame indicator (bfi) */

    bfi = *parm++;              move16 (); 

    /* Set state machine */

    test (); test (); 
    if (bfi != 0)
    {
        state = add (state, 1);
    }
    else if (sub (state, 6) == 0)
    {
        state = 5;
    }
    else
    {
        state = 0;
    }

    test (); 
    if (sub (state, 6) > 0)
    {
        state = 6;
    }
    rx_dtx (&rxdtx_ctrl, TAF, bfi, SID_flag);

    /* If this frame is the first speech frame after CNI period,     */
    /* set the BFH state machine to an appropriate state depending   */
    /* on whether there was DTX muting before start of speech or not */
    /* If there was DTX muting, the first speech frame is muted.     */
    /* If there was no DTX muting, the first speech frame is not     */
    /* muted. The BFH state machine starts from state 5, however, to */
    /* keep the audible noise resulting from a SID frame which is    */
    /* erroneously interpreted as a good speech frame as small as    */
    /* possible (the decoder output in this case is quickly muted)   */
    test (); logic16 ();
    if ((rxdtx_ctrl & RX_FIRST_SP_FLAG) != 0)
    {
        test (); logic16 ();
        if ((rxdtx_ctrl & RX_PREV_DTX_MUTING) != 0)
        {
            state = 5;    move16 ();
            prev_bf = 1;  move16 ();
        }
        else
        {
            state = 5;    move16 ();
            prev_bf = 0;  move16 ();
        }
    }

#if (WMOPS)
    fwc ();                     /* function worst case */

    /* Note! The following test is performed only for determining
       whether or not DTX mode is active, in order to switch off
       worst worst case complexity printout when DTX mode is active
    */
    if ((rxdtx_ctrl & RX_SP_FLAG) == 0)
    {
        dtx_mode = 1;
    }
#endif

    D_plsf_5 (parm, lsp_mid, lsp_new, bfi, rxdtx_ctrl, rx_dtx_state);

#if (WMOPS)
    fwc ();                     /* function worst case */
#endif
    /* Advance synthesis parameters pointer */
    parm += 5;                  move16 (); 

    test (); logic16 (); 
    if ((rxdtx_ctrl & RX_SP_FLAG) != 0)
    {
        /* Interpolation of LPC for the 4 subframes */

        Int_lpc (lsp_old, lsp_mid, lsp_new, A_t);
    }
    else
    {
        /* Comfort noise: use the same parameters in each subframe */
        Lsp_Az (lsp_new, A_t);

        for (i = 0; i < MP1; i++)
        {
            A_t[i + MP1] = A_t[i];      move16 (); 
            A_t[i + 2 * MP1] = A_t[i];  move16 (); 
            A_t[i + 3 * MP1] = A_t[i];  move16 (); 
        }
    }

    /* update the LSPs for the next frame */
    for (i = 0; i < M; i++)
    {
        lsp_old[i] = lsp_new[i];        move16 (); 
    }
#if (WMOPS)
    fwc ();                     /* function worst case */
#endif

    /*---------------------------------------------------------------------*
     *       Loop for every subframe in the analysis frame                 *
     *---------------------------------------------------------------------*
     * The subframe size is L_SUBFR and the loop is repeated               *
     * L_FRAME/L_SUBFR times                                               *
     *     - decode the pitch delay                                        *
     *     - decode algebraic code                                         *
     *     - decode pitch and codebook gains                               *
     *     - find the excitation and compute synthesis speech              *
     *---------------------------------------------------------------------*/

    /* pointer to interpolated LPC parameters */
    Az = A_t;                           move16 (); 

    for (i_subfr = 0; i_subfr < L_FRAME; i_subfr += L_SUBFR)
    {

        index = *parm++;                move16 (); /* pitch index */

        test (); logic16 (); 
        if ((rxdtx_ctrl & RX_SP_FLAG) != 0)
        {
            T0 = Dec_lag6 (index, PIT_MIN, PIT_MAX, i_subfr, L_FRAME_BY2,
                           &T0_frac, bfi);
#if (WMOPS)
            fwc ();             /* function worst case */
#endif

            /*-------------------------------------------------*
             * - Find the adaptive codebook vector.            *
             *-------------------------------------------------*/

            Pred_lt_6 (&exc[i_subfr], T0, T0_frac, L_SUBFR);
#if (WMOPS)
            fwc ();             /* function worst case */
#endif
        }
        else
        {
            T0 = L_SUBFR;               move16 (); 
        }

        /*-------------------------------------------------------*
         * - Decode pitch gain.                                  *
         *-------------------------------------------------------*/

        index = *parm++;                move16 (); 

        gain_pit = d_gain_pitch (index, bfi, state, prev_bf, rxdtx_ctrl);
        move16 (); 
#if (WMOPS)
        fwc ();                 /* function worst case */
#endif

        /*-------------------------------------------------------*
         * - Decode innovative codebook.                         *
         *-------------------------------------------------------*/

        test (); logic16 (); 
        if ((rxdtx_ctrl & RX_SP_FLAG) != 0)
        {
            dec_10i40_35bits (parm, code);
        }
        else
        {   /* Use pseudo noise for excitation when SP_flag == 0 */
            build_CN_code (code, &L_pn_seed_rx);
        }

        parm += 10;                     move16 (); 
#if (WMOPS)
        fwc ();                 /* function worst case */
#endif

        /*-------------------------------------------------------*
         * - Add the pitch contribution to code[].               *
         *-------------------------------------------------------*/

        /* pit_sharp = gain_pit;                   */
        /* if (pit_sharp > 1.0) pit_sharp = 1.0;   */

        pit_sharp = shl (gain_pit, 3);

        /* This loop is not entered when SP_FLAG is 0 */
        for (i = T0; i < L_SUBFR; i++)
        {
            temp = mult (code[i - T0], pit_sharp);
            code[i] = add (code[i], temp);
                                        move16 (); 
        }
#if (WMOPS)
        fwc ();                 /* function worst case */
#endif
        /* post processing of excitation elements */

        test (); /* This test is not passed when SP_FLAG is 0 */
        if (sub (pit_sharp, 16384) > 0)
        {
            for (i = 0; i < L_SUBFR; i++)
            {
                temp = mult (exc[i + i_subfr], pit_sharp);
                L_temp = L_mult (temp, gain_pit);
                L_temp = L_shl (L_temp, 1);
                excp[i] = round (L_temp);
                                        move16 (); 
            }
        }
        /*-------------------------------------------------*
         * - Decode codebook gain.                         *
         *-------------------------------------------------*/

        index = *parm++;                move16 (); /* index of energy VQ */

        d_gain_code (index, code, L_SUBFR, &gain_code, bfi, state, prev_bf,
                     rxdtx_ctrl, i_subfr, rx_dtx_state);
#if (WMOPS)
        fwc ();                 /* function worst case */
#endif

        /*-------------------------------------------------------*
         * - Find the total excitation.                          *
         * - Find synthesis speech corresponding to exc[].       *
         *-------------------------------------------------------*/
        for (i = 0; i < L_SUBFR; i++)
        {
            /* exc[i] = gain_pit*exc[i] + gain_code*code[i]; */

            L_temp = L_mult (exc[i + i_subfr], gain_pit);
            L_temp = L_mac (L_temp, code[i], gain_code);
            L_temp = L_shl (L_temp, 3);

            exc[i + i_subfr] = round (L_temp);
                                        move16 (); 
        }
#if (WMOPS)
        fwc ();                 /* function worst case */
#endif

        test (); 
        if (sub (pit_sharp, 16384) > 0)
        {
            for (i = 0; i < L_SUBFR; i++)
            {
                excp[i] = add (excp[i], exc[i + i_subfr]);
                                        move16 (); 
            }
            agc2 (&exc[i_subfr], excp, L_SUBFR);
            Syn_filt (Az, excp, &synth[i_subfr], L_SUBFR, mem_syn, 1);
        }
        else
        {
            Syn_filt (Az, &exc[i_subfr], &synth[i_subfr], L_SUBFR, mem_syn, 1);
        }

#if (WMOPS)
        fwc ();                 /* function worst case */
#endif
        /* interpolated LPC parameters for next subframe */
        Az += MP1;                      move16 (); 
    }

    /*--------------------------------------------------*
     * Update signal for next frame.                    *
     * -> shift to the left by L_FRAME  exc[]           *
     *--------------------------------------------------*/

    Copy (&old_exc[L_FRAME], &old_exc[0], PIT_MAX + L_INTERPOL);
#if (WMOPS)
    fwc ();                     /* function worst case */
#endif
    prev_bf = bfi;                      move16 (); 

    return;
}