view libgsmefr/dtx_enc.c @ 282:9ee8ad3d4d30

frtest: rm gsmfr-hand-test and gsmfr-max-out utils These hack programs were never properly documented and were written only as part of a debug chase, in pursuit of a bug that ultimately turned out to be in our then-hacky patch to osmo-bts-sysmo, before beginning of proper patches in Osmocom. These hack programs need to be dropped from the present sw package because they depend on old libgsm, and we are eliminating that dependency.
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 14 Apr 2024 05:44:47 +0000
parents cf39a90f5196
children
line wrap: on
line source

/*
 * This file is a product of splitting ETSI EFR dtx.c into parts;
 * the present module is the encoder-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 "enc_state.h"

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

void reset_tx_dtx (struct EFR_encoder_state *st)
{
    Word16 i;

    /* suppose infinitely long speech period before start */

    st->txdtx_hangover = DTX_HANGOVER;
    st->txdtx_N_elapsed = 0x7fff;
    st->txdtx_ctrl = TX_SP_FLAG | TX_VAD_FLAG;

    for (i = 0; i < 6; i++)
    {
        st->old_CN_mem_tx[i] = 0;
    }

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

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

    st->L_pn_seed_tx = PN_INITIAL_SEED;

    st->buf_p_tx = 0;
    return;
}

/*************************************************************************
 *
 *   FUNCTION NAME: tx_dtx
 *
 *   PURPOSE: DTX handler of the speech encoder. Determines when to add
 *            the hangover period to the end of the speech burst, and
 *            also determines when to use old SID parameters, and when
 *            to update the SID parameters. This function also initializes
 *            the pseudo noise generator shift register.
 *
 *            Operation of the TX DTX handler is based on the VAD flag
 *            given as input from the speech encoder.
 *
 *   INPUTS:      VAD_flag      Voice activity decision
 *                *txdtx_ctrl   Old encoder DTX control word
 *
 *   OUTPUTS:     *txdtx_ctrl   Updated encoder DTX control word
 *                L_pn_seed_tx  Initialized pseudo noise generator shift
 *                              register (global variable)
 *
 *   RETURN VALUE: none
 *
 *************************************************************************/

void tx_dtx (
    struct EFR_encoder_state *st,
    Word16 VAD_flag
)
{
    /* N_elapsed (frames since last SID update) is incremented. If SID
       is updated N_elapsed is cleared later in this function */

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

    /* If voice activity was detected, reset hangover counter */

    if (VAD_flag == 1)
    {
        st->txdtx_hangover = DTX_HANGOVER;
        st->txdtx_ctrl = TX_SP_FLAG | TX_VAD_FLAG;
    }
    else
    {
        if (st->txdtx_hangover == 0)
        {
            /* Hangover period is over, SID should be updated */

            st->txdtx_N_elapsed = 0;

            /* Check if this is the first frame after hangover period */
            if ((st->txdtx_ctrl & TX_HANGOVER_ACTIVE) != 0)
            {
                st->txdtx_ctrl = TX_PREV_HANGOVER_ACTIVE
                    | TX_SID_UPDATE;
                st->L_pn_seed_tx = PN_INITIAL_SEED;
            }
            else
            {
                st->txdtx_ctrl = TX_SID_UPDATE;
            }
        }
        else
        {
            /* Hangover period is not over, update hangover counter */
            st->txdtx_hangover--;

            /* Check if elapsed time from last SID update is greater than
               threshold. If not, set SP=0 (although hangover period is not
               over) and use old SID parameters for new SID frame.
               N_elapsed counter must be summed with hangover counter in order
               to avoid erroneus SP=1 decision in case when N_elapsed is grown
               bigger than threshold and hangover period is still active */

            if (add (st->txdtx_N_elapsed, st->txdtx_hangover) <
                DTX_ELAPSED_THRESHOLD)
            {
                /* old SID frame should be used */
                st->txdtx_ctrl = TX_USE_OLD_SID;
            }
            else
            {
                if ((st->txdtx_ctrl & TX_HANGOVER_ACTIVE) != 0)
                {
                    st->txdtx_ctrl = TX_PREV_HANGOVER_ACTIVE
                        | TX_HANGOVER_ACTIVE
                        | TX_SP_FLAG;
                }
                else
                {
                    st->txdtx_ctrl = TX_HANGOVER_ACTIVE
                        | TX_SP_FLAG;
                }
            }
        }
    }

    return;
}

/*************************************************************************
 *
 *   FUNCTION NAME: CN_encoding
 *
 *   PURPOSE:  Encoding of the comfort noise parameters into a SID frame.
 *             Use old SID parameters if necessary. Set the parameter
 *             indices not used by comfort noise parameters to zero.
 *
 *   INPUTS:      params[0..56]  Comfort noise parameter frame from the
 *                               speech encoder
 *                txdtx_ctrl     TX DTX handler control word
 *
 *   OUTPUTS:     params[0..56]  Comfort noise encoded parameter frame
 *
 *   RETURN VALUE: none
 *
 *************************************************************************/

void CN_encoding (
    struct EFR_encoder_state *st,
    Word16 params[],
    Word16 txdtx_ctrl
)
{
    Word16 i;

    if ((txdtx_ctrl & TX_SID_UPDATE) != 0)
    {
        /* Store new CN parameters in memory to be used later as old
           CN parameters */

        /* LPC parameter indices */
        for (i = 0; i < 5; i++)
        {
            st->old_CN_mem_tx[i] = params[i];
        }
        /* Codebook index computed in last subframe */
        st->old_CN_mem_tx[5] = params[56];
    }
    if ((txdtx_ctrl & TX_USE_OLD_SID) != 0)
    {
        /* Use old CN parameters previously stored in memory */
        for (i = 0; i < 5; i++)
        {
            params[i] = st->old_CN_mem_tx[i];
        }
        params[17] = st->old_CN_mem_tx[5];
        params[30] = st->old_CN_mem_tx[5];
        params[43] = st->old_CN_mem_tx[5];
        params[56] = st->old_CN_mem_tx[5];
    }
    /* Set all the rest of the parameters to zero (SID codeword will
       be written later) */
    for (i = 0; i < 12; i++)
    {
        params[i + 5] = 0;
        params[i + 18] = 0;
        params[i + 31] = 0;
        params[i + 44] = 0;
    }

    return;
}

/*************************************************************************
 *
 *   FUNCTION NAME: aver_lsf_history
 *
 *   PURPOSE: Compute the averaged LSF parameter vector. Computation is
 *            performed by averaging the LSF parameter vectors which exist
 *            in the LSF parameter history, together with the LSF
 *            parameter vectors of the current frame.
 *
 *   INPUTS:      lsf_old[0..DTX_HANGOVER-1][0..M-1]
 *                                   LSF parameter history
 *                lsf1[0..M-1]       LSF vector of the 1st half of the frame
 *                lsf2[0..M-1]       LSF vector of the 2nd half of the frame
 *
 *   OUTPUTS:     lsf_aver[0..M-1]   Averaged LSF parameter vector
 *
 *   RETURN VALUE: none
 *
 *************************************************************************/

void aver_lsf_history (
    Word16 lsf_old[DTX_HANGOVER][M],
    Word16 lsf1[M],
    Word16 lsf2[M],
    Word16 lsf_aver[M]
)
{
    Word16 i, j;
    Word32 L_temp;

    for (j = 0; j < M; j++)
    {
        L_temp = L_mult (0x3fff, lsf1[j]);
        L_temp = L_mac (L_temp, 0x3fff, lsf2[j]);
        L_temp = L_mult (INV_DTX_HANGOVER_P1, extract_h (L_temp));

        for (i = 0; i < DTX_HANGOVER; i++)
        {
            L_temp = L_mac (L_temp, INV_DTX_HANGOVER_P1, lsf_old[i][j]);
        }

        lsf_aver[j] = extract_h (L_temp);              move16 (); 
    }

    return;
}

/*************************************************************************
 *
 *   FUNCTION NAME: update_gain_code_history_tx
 *
 *   PURPOSE: Update the fixed codebook gain parameter history of the
 *            encoder. The fixed codebook gain parameters kept in the buffer
 *            are used later for computing the reference fixed codebook
 *            gain parameter value and the averaged 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 encoder
 *
 *   OUTPUTS:     gain_code_old_tx[0..4*DTX_HANGOVER-1]
 *                                Updated fixed codebook gain history of encoder
 *
 *   RETURN VALUE: none
 *
 *************************************************************************/

void update_gain_code_history_tx (
    struct EFR_encoder_state *st,
    Word16 new_gain_code
)
{
    /* Circular buffer */
    st->gain_code_old_tx[st->buf_p_tx] = new_gain_code;

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

    return;
}

/*************************************************************************
 *
 *   FUNCTION NAME: compute_CN_excitation_gain
 *
 *   PURPOSE: Compute the unquantized fixed codebook gain. Computation is
 *            based on the energy of the Linear Prediction residual signal.
 *
 *   INPUTS:      res2[0..39]   Linear Prediction residual signal
 *
 *   OUTPUTS:     none
 *
 *   RETURN VALUE: Unquantized fixed codebook gain
 *
 *************************************************************************/

Word16 compute_CN_excitation_gain (
    Word16 res2[L_SUBFR]
)
{
    Word16 i, norm, norm1, temp, overfl;
    Word32 L_temp;

    /* Compute the energy of the LP residual signal */

    norm = 0;                                          move16 (); 
    do
    {
        overfl = 0;                                    move16 ();

        L_temp = 0L;                                   move32 (); 
        for (i = 0; i < L_SUBFR; i++)
        {
            temp = shr (res2[i], norm);
            L_temp = L_mac (L_temp, temp, temp);
        }

        test (); 
        if (L_temp == MAX_32)
        {
            norm = add (norm, 1);
            overfl = 1;                 move16 (); /* Set the overflow flag */
        }
        test (); 
    }
    while (overfl != 0);

    L_temp = L_add (L_temp, 1L);             /* Avoid the case of all zeros */

    /* Take the square root of the obtained energy value (sqroot is a 2nd
       order Taylor series approximation) */

    norm1 = norm_l (L_temp);
    temp = extract_h (L_shl (L_temp, norm1));
    L_temp = L_mult (temp, temp);
    L_temp = L_sub (805306368L, L_shr (L_temp, 3));
    L_temp = L_add (L_temp, L_mult (24576, temp));

    temp = extract_h (L_temp);
    test (); logic16 (); 
    if ((norm1 & 0x0001) != 0)
    {
        temp = mult_r (temp, 23170);
        norm1 = sub (norm1, 1);
    }
    /* Divide the result of sqroot operation by sqroot(10) */

    temp = mult_r (temp, 10362);

    /* Re-scale to get the final value */

    norm1 = shr (norm1, 1);
    norm1 = sub (norm1, norm);

    test (); 
    if (norm1 >= 0)
    {
        temp = shr (temp, norm1);
    }
    else
    {
        temp = shl (temp, abs_s (norm1));
    }

    return temp;
}

/*************************************************************************
 *
 *   FUNCTION NAME: aver_gain_code_history
 *
 *   PURPOSE: Compute the averaged fixed codebook gain parameter value.
 *            Computation is performed by averaging the fixed codebook
 *            gain parameter values which exist in the fixed codebook
 *            gain parameter history, together with the fixed codebook
 *            gain parameter value of the current subframe.
 *
 *   INPUTS:      CN_excitation_gain
 *                              Unquantized fixed codebook gain value
 *                              of the current subframe
 *                gain_code_old[0..4*DTX_HANGOVER-1]
 *                              fixed codebook gain parameter history
 *
 *   OUTPUTS:     none
 *
 *   RETURN VALUE: Averaged fixed codebook gain value
 *
 *************************************************************************/

Word16 aver_gain_code_history (
    Word16 CN_excitation_gain,
    Word16 gain_code_old[4 * DTX_HANGOVER]
)
{
    Word16 i;
    Word32 L_ret;

    L_ret = L_mult (0x470, CN_excitation_gain);

    for (i = 0; i < (4 * DTX_HANGOVER); i++)
    {
        L_ret = L_mac (L_ret, 0x470, gain_code_old[i]);
    }
    return extract_h (L_ret);
}