view libgsmefr/dtx_dec.c @ 467:ad032051166a

doc: AMR-EFR-hybrid-emu new article
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 12 May 2024 23:54:43 +0000
parents 17f690749099
children
line wrap: on
line source

/*
 * This file is a product of splitting ETSI EFR dtx.c into parts;
 * the present module is the decoder-specific part.
 */

#include "gsm_efr.h"
#include "typedef.h"
#include "namespace.h"
#include "basic_op.h"
#include "cnst.h"
#include "sig_proc.h"
#include "memops.h"
#include "no_count.h"
#include "dtx.h"
#include "dtx_defs.h"
#include "dec_state.h"

/*************************************************************************
 *
 *   FUNCTION NAME: reset_rx_dtx
 *
 *   PURPOSE:  Resets the static variables of the RX DTX handler to their
 *             initial values
 *
 *************************************************************************/

void reset_rx_dtx (struct EFR_decoder_state *st)
{
    Word16 i;

    /* suppose infinitely long speech period before start */

    st->rxdtx_aver_period = DTX_HANGOVER;
    st->rxdtx_N_elapsed = 0x7fff;
    st->rxdtx_ctrl = RX_SP_FLAG;

    for (i = 0; i < DTX_HANGOVER; i++)
    {
        st->lsf_old_rx[i][0] = 1384;
        st->lsf_old_rx[i][1] = 2077;
        st->lsf_old_rx[i][2] = 3420;
        st->lsf_old_rx[i][3] = 5108;
        st->lsf_old_rx[i][4] = 6742;
        st->lsf_old_rx[i][5] = 8122;
        st->lsf_old_rx[i][6] = 9863;
        st->lsf_old_rx[i][7] = 11092;
        st->lsf_old_rx[i][8] = 12714;
        st->lsf_old_rx[i][9] = 13701;
    }

    for (i = 0; i < 4 * DTX_HANGOVER; i++)
    {
        st->gain_code_old_rx[i] = 0;
    }

    st->L_pn_seed_rx = PN_INITIAL_SEED;
    st->rx_dtx_state = CN_INT_PERIOD - 1;

    st->prev_SID_frames_lost = 0;
    st->buf_p_rx = 0;

    return;
}

/*************************************************************************
 *
 *   FUNCTION NAME: rx_dtx
 *
 *   PURPOSE: DTX handler of the speech decoder. Determines when to update
 *            the reference comfort noise parameters (LSF and gain) at the
 *            end of the speech burst. Also classifies the incoming frames
 *            according to SID flag and BFI flag
 *            and determines when the transmission is active during comfort
 *            noise insertion. This function also initializes the pseudo
 *            noise generator shift register.
 *
 *            Operation of the RX DTX handler is based on measuring the
 *            lengths of speech bursts and the lengths of the pauses between
 *            speech bursts to determine when there exists a hangover period
 *            at the end of a speech burst. The idea is to keep in sync with
 *            the TX DTX handler to be able to update the reference comfort
 *            noise parameters at the same time instances.
 *
 *   INPUTS:      *rxdtx_ctrl   Old decoder DTX control word
 *                TAF           Time alignment flag
 *                bfi           Bad frame indicator flag
 *                SID_flag      Silence descriptor flag
 *
 *   OUTPUTS:     *rxdtx_ctrl   Updated decoder DTX control word
 *                rx_dtx_state  Updated state of comfort noise interpolation
 *                              period (global variable)
 *                L_pn_seed_rx  Initialized pseudo noise generator shift
 *                              register (global variable)
 *
 *   RETURN VALUE: none
 *
 *************************************************************************/

void rx_dtx (
    struct EFR_decoder_state *st,
    Word16 TAF,
    Word16 bfi,
    Word16 SID_flag
)
{
    Word16 frame_type;

    /* Frame classification according to bfi-flag and ternary-valued
       SID flag. The frames between SID updates (not actually trans-
       mitted) are also classified here; they will be discarded later
       and provided with "NO TRANSMISSION"-flag */

    if ((SID_flag == 2) && (bfi == 0))
    {
        frame_type = VALID_SID_FRAME;                   move16 (); 
    }
    else if ((SID_flag == 0) && (bfi == 0))
    {
        frame_type = GOOD_SPEECH_FRAME;                 move16 (); 
    }
    else if ((SID_flag == 0) && (bfi != 0))
    {
        frame_type = UNUSABLE_FRAME;                    move16 (); 
    }
    else
    {
        frame_type = INVALID_SID_FRAME;                 move16 (); 
    }

    /* Update of decoder state */
    /* Previous frame was classified as a speech frame */
    if ((st->rxdtx_ctrl & RX_SP_FLAG) != 0)
    {
        if (frame_type == VALID_SID_FRAME)
        {
            st->rxdtx_ctrl = RX_FIRST_SID_UPDATE;
        }
        else if (frame_type == INVALID_SID_FRAME)
        {
            st->rxdtx_ctrl = RX_FIRST_SID_UPDATE
                           | RX_INVALID_SID_FRAME;
        }
        else if (frame_type == UNUSABLE_FRAME)
        {
            st->rxdtx_ctrl = RX_SP_FLAG;
        }
        else if (frame_type == GOOD_SPEECH_FRAME)
        {
            st->rxdtx_ctrl = RX_SP_FLAG;
        }
    }
    else
    {
        if (frame_type == VALID_SID_FRAME)
        {
            st->rxdtx_ctrl = RX_CONT_SID_UPDATE;
        }
        else if (frame_type == INVALID_SID_FRAME)
        {
            st->rxdtx_ctrl = RX_CONT_SID_UPDATE
                           | RX_INVALID_SID_FRAME;
        }
        else if (frame_type == UNUSABLE_FRAME)
        {
            st->rxdtx_ctrl = RX_CNI_BFI;
        }
        else if (frame_type == GOOD_SPEECH_FRAME)
        {
            /* If the previous frame (during CNI period) was muted,
               raise the RX_PREV_DTX_MUTING flag */
            if ((st->rxdtx_ctrl & RX_DTX_MUTING) != 0)
            {
                st->rxdtx_ctrl = RX_SP_FLAG | RX_FIRST_SP_FLAG
                               | RX_PREV_DTX_MUTING;
            }
            else
            {
                st->rxdtx_ctrl = RX_SP_FLAG | RX_FIRST_SP_FLAG;
            }
        }
    }

    if ((st->rxdtx_ctrl & RX_SP_FLAG) != 0)
    {
        st->prev_SID_frames_lost = 0;
        st->rx_dtx_state = CN_INT_PERIOD - 1;
    }
    else
    {
        /* First SID frame */
        if ((st->rxdtx_ctrl & RX_FIRST_SID_UPDATE) != 0)
        {
            st->prev_SID_frames_lost = 0;
            st->rx_dtx_state = CN_INT_PERIOD - 1;
        }

        /* SID frame detected, but not the first SID */
        if ((st->rxdtx_ctrl & RX_CONT_SID_UPDATE) != 0)
        {
            st->prev_SID_frames_lost = 0;

            if (frame_type == VALID_SID_FRAME)
            {
                st->rx_dtx_state = 0;
            }
            else if (frame_type == INVALID_SID_FRAME)
            {
                if (st->rx_dtx_state < (CN_INT_PERIOD - 1))
                {
                    st->rx_dtx_state++;
                }
            }
        }

        /* Bad frame received in CNI mode */
        if ((st->rxdtx_ctrl & RX_CNI_BFI) != 0)
        {
            if (st->rx_dtx_state < (CN_INT_PERIOD - 1))
            {
                st->rx_dtx_state++;
            }

            /* If an unusable frame is received during CNI period
               when TAF == 1, the frame is classified as a lost
               SID frame */
            if (TAF)
            {
                st->rxdtx_ctrl = st->rxdtx_ctrl | RX_LOST_SID_FRAME;
                st->prev_SID_frames_lost = add (st->prev_SID_frames_lost, 1);
            }
            else /* No transmission occurred */
            {
                st->rxdtx_ctrl = st->rxdtx_ctrl | RX_NO_TRANSMISSION;
            }

            if (st->prev_SID_frames_lost > 1)
            {
                st->rxdtx_ctrl = st->rxdtx_ctrl | RX_DTX_MUTING;
            }
        }
    }

    /* N_elapsed (frames since last SID update) is incremented. If SID
       is updated N_elapsed is cleared later in this function */

    st->rxdtx_N_elapsed = add (st->rxdtx_N_elapsed, 1);

    if ((st->rxdtx_ctrl & RX_SP_FLAG) != 0)
    {
        st->rxdtx_aver_period = DTX_HANGOVER;
    }
    else
    {
        if (st->rxdtx_N_elapsed > DTX_ELAPSED_THRESHOLD)
        {
            st->rxdtx_ctrl |= RX_UPD_SID_QUANT_MEM;
            st->rxdtx_N_elapsed = 0;
            st->rxdtx_aver_period = 0;
            st->L_pn_seed_rx = PN_INITIAL_SEED;
        }
        else if (st->rxdtx_aver_period == 0)
        {
            st->rxdtx_N_elapsed = 0;
        }
        else
        {
            st->rxdtx_aver_period--;
        }
    }

    return;
}

/*************************************************************************
 *
 *   FUNCTION NAME: update_gain_code_history_rx
 *
 *   PURPOSE: Update the fixed codebook gain parameter history of the
 *            decoder. The fixed codebook gain parameters kept in the buffer
 *            are used later for computing the reference fixed codebook
 *            gain parameter value.
 *
 *   INPUTS:      new_gain_code   New fixed codebook gain value
 *
 *                gain_code_old_tx[0..4*DTX_HANGOVER-1]
 *                                Old fixed codebook gain history of decoder
 *
 *   OUTPUTS:     gain_code_old_tx[0..4*DTX_HANGOVER-1]
 *                                Updated fixed codebk gain history of decoder
 *
 *   RETURN VALUE: none
 *
 *************************************************************************/

void update_gain_code_history_rx (
    struct EFR_decoder_state *st,
    Word16 new_gain_code
)
{
    /* Circular buffer */
    st->gain_code_old_rx[st->buf_p_rx] = new_gain_code;

    if (st->buf_p_rx == (4 * DTX_HANGOVER - 1))
    {
        st->buf_p_rx = 0;
    }
    else
    {
        st->buf_p_rx++;
    }

    return;
}

/*************************************************************************
 *
 *   FUNCTION NAME: interpolate_CN_param
 *
 *   PURPOSE: Interpolate a comfort noise parameter value over the comfort
 *            noise update period.
 *
 *   INPUTS:      old_param     The older parameter of the interpolation
 *                              (the endpoint the interpolation is started
 *                              from)
 *                new_param     The newer parameter of the interpolation
 *                              (the endpoint the interpolation is ended to)
 *                rx_dtx_state  State of the comfort noise insertion period
 *
 *   OUTPUTS:     none
 *
 *   RETURN VALUE: Interpolated CN parameter value
 *
 *************************************************************************/

Word16 interpolate_CN_param (
    Word16 old_param,
    Word16 new_param,
    Word16 rx_dtx_state
)
{
    static const Word16 interp_factor[CN_INT_PERIOD] =
    {
        0x0555, 0x0aaa, 0x1000, 0x1555, 0x1aaa, 0x2000,
        0x2555, 0x2aaa, 0x3000, 0x3555, 0x3aaa, 0x4000,
        0x4555, 0x4aaa, 0x5000, 0x5555, 0x5aaa, 0x6000,
        0x6555, 0x6aaa, 0x7000, 0x7555, 0x7aaa, 0x7fff};
    Word16 temp;
    Word32 L_temp;

    L_temp = L_mult (interp_factor[rx_dtx_state], new_param);
    temp = sub (0x7fff, interp_factor[rx_dtx_state]);
    temp = add (temp, 1);
    L_temp = L_mac (L_temp, temp, old_param);
    temp = round (L_temp);

    return temp;
}

/*************************************************************************
 *
 *   FUNCTION NAME:  interpolate_CN_lsf
 *
 *   PURPOSE: Interpolate comfort noise LSF parameter vector over the comfort
 *            noise update period.
 *
 *   INPUTS:      lsf_old_CN[0..9]
 *                              The older LSF parameter vector of the
 *                              interpolation (the endpoint the interpolation
 *                              is started from)
 *                lsf_new_CN[0..9]
 *                              The newer LSF parameter vector of the
 *                              interpolation (the endpoint the interpolation
 *                              is ended to)
 *                rx_dtx_state  State of the comfort noise insertion period
 *
 *   OUTPUTS:     lsf_interp_CN[0..9]
 *                              Interpolated LSF parameter vector
 *
 *   RETURN VALUE: none
 *
 *************************************************************************/

void interpolate_CN_lsf (
    Word16 lsf_old_CN[M],
    Word16 lsf_new_CN[M],
    Word16 lsf_interp_CN[M],
    Word16 rx_dtx_state
)
{
    Word16 i;

    for (i = 0; i < M; i++)
    {
        lsf_interp_CN[i] = interpolate_CN_param (lsf_old_CN[i],
                                                 lsf_new_CN[i],
                                                 rx_dtx_state); move16 (); 
    }

    return;
}