view libgsmefr/dtx_common.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 7bc011aceb7f
children
line wrap: on
line source

/*
 * This file is a product of splitting ETSI EFR dtx.c into parts;
 * the present module is the common part for both the encoder and
 * the decoder.
 */

#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"

/*************************************************************************
 *
 *   FUNCTION NAME: update_lsf_history
 *
 *   PURPOSE: Update the LSF parameter history. The LSF parameters kept
 *            in the buffer are used later for computing the reference
 *            LSF parameter vector and the averaged LSF parameter vector.
 *
 *   INPUTS:      lsf1[0..9]    LSF vector of the 1st half of the frame
 *                lsf2[0..9]    LSF vector of the 2nd half of the frame
 *                lsf_old[0..DTX_HANGOVER-1][0..M-1]
 *                              Old LSF history
 *
 *   OUTPUTS:     lsf_old[0..DTX_HANGOVER-1][0..M-1]
 *                              Updated LSF history
 *
 *   RETURN VALUE: none
 *
 *************************************************************************/

void update_lsf_history (
    Word16 lsf1[M],
    Word16 lsf2[M],
    Word16 lsf_old[DTX_HANGOVER][M]
)
{
    Word16 i, j, temp;

    /* shift LSF data to make room for LSFs from current frame */
    /* This can also be implemented by using circular buffering */

    for (i = DTX_HANGOVER - 1; i > 0; i--)
    {
        for (j = 0; j < M; j++)
        {
            lsf_old[i][j] = lsf_old[i - 1][j];         move16 (); 
        }
    }

    /* Store new LSF data to lsf_old buffer */

    for (i = 0; i < M; i++)
    {
        temp = add (shr (lsf1[i], 1), shr (lsf2[i], 1));
        lsf_old[0][i] = temp;                          move16 (); 
    }

    return;
}

/*************************************************************************
 *
 *   FUNCTION NAME: update_lsf_p_CN
 *
 *   PURPOSE: Update the reference LSF parameter vector. The reference
 *            vector is computed by averaging the quantized LSF parameter
 *            vectors which exist in the LSF parameter history.
 *
 *   INPUTS:      lsf_old[0..DTX_HANGOVER-1][0..M-1]
 *                                 LSF parameter history
 *
 *   OUTPUTS:     lsf_p_CN[0..9]   Computed reference LSF parameter vector
 *
 *   RETURN VALUE: none
 *
 *************************************************************************/

void update_lsf_p_CN (
    Word16 lsf_old[DTX_HANGOVER][M],
    Word16 lsf_p_CN[M]
)
{
    Word16 i, j;
    Word32 L_temp;

    for (j = 0; j < M; j++)
    {
        L_temp = L_mult (INV_DTX_HANGOVER, lsf_old[0][j]);
        for (i = 1; i < DTX_HANGOVER; i++)
        {
            L_temp = L_mac (L_temp, INV_DTX_HANGOVER, lsf_old[i][j]);
        }
        lsf_p_CN[j] = round (L_temp);                  move16 (); 
    }

    return;
}

/*************************************************************************
 *
 *   FUNCTION NAME: update_gcode0_CN
 *
 *   PURPOSE: Update the reference fixed codebook gain parameter value.
 *            The reference value is computed by averaging the quantized
 *            fixed codebook gain parameter values which exist in the
 *            fixed codebook gain parameter history.
 *
 *   INPUTS:      gain_code_old[0..4*DTX_HANGOVER-1]
 *                              fixed codebook gain parameter history
 *
 *   OUTPUTS:     none
 *
 *   RETURN VALUE: Computed reference fixed codebook gain
 *
 *************************************************************************/

Word16 update_gcode0_CN (
    Word16 gain_code_old[4 * DTX_HANGOVER]
)
{
    Word16 i, j;
    Word32 L_temp, L_ret;

    L_ret = 0L;                                        move32 (); 
    for (i = 0; i < DTX_HANGOVER; i++)
    {
        L_temp = L_mult (0x1fff, gain_code_old[4 * i]);
        for (j = 1; j < 4; j++)
        {
            L_temp = L_mac (L_temp, 0x1fff, gain_code_old[4 * i + j]);
        }
        L_ret = L_mac (L_ret, INV_DTX_HANGOVER, extract_h (L_temp));
    }

    return extract_h (L_ret);
}

/*************************************************************************
 *
 *   FUNCTION NAME: build_CN_code
 *
 *   PURPOSE: Compute the comfort noise fixed codebook excitation. The
 *            gains of the pulses are always +/-1.
 *
 *   INPUTS:      *seed         Old CN generator shift register state
 *
 *   OUTPUTS:     cod[0..39]    Generated comfort noise fixed codebook vector
 *                *seed         Updated CN generator shift register state
 *
 *   RETURN VALUE: none
 *
 *************************************************************************/

void build_CN_code (
    Word16 cod[],
    Word32 *seed
)
{
    Word16 i, j, k;

    for (i = 0; i < L_SUBFR; i++)
    {
        cod[i] = 0;                                    move16 (); 
    }

    for (k = 0; k < NB_PULSE; k++)
    {
        i = pseudonoise (seed, 2);      /* generate pulse position */
        i *= 10;
        i += k;

        j = pseudonoise (seed, 1);      /* generate sign           */

        test (); 
        if (j > 0)
        {
            cod[i] = 4096;                             move16 (); 
        }
        else
        {
            cod[i] = -4096;                            move16 (); 
        }
    }

    return;
}

/*************************************************************************
 *
 *   FUNCTION NAME: pseudonoise
 *
 *   PURPOSE: Generate a random integer value to use in comfort noise
 *            generation. The algorithm uses polynomial x^31 + x^3 + 1
 *            (length of PN sequence is 2^31 - 1).
 *
 *   INPUTS:      *shift_reg    Old CN generator shift register state
 *
 *
 *   OUTPUTS:     *shift_reg    Updated CN generator shift register state
 *
 *   RETURN VALUE: Generated random integer value
 *
 *************************************************************************/

Word16 pseudonoise (
    Word32 *shift_reg,
    Word16 no_bits
)
{
    Word16 noise_bits, Sn, i;

    noise_bits = 0;                                    move16 (); 
    for (i = 0; i < no_bits; i++)
    {
        /* State n == 31 */
        test (); logic32 (); 
        if ((*shift_reg & 0x00000001L) != 0)
        {
            Sn = 1;                                    move16 (); 
        }
        else
        {
            Sn = 0;                                    move16 (); 
        }

        /* State n == 3 */
        test (); logic32 (); 
        if ((*shift_reg & 0x10000000L) != 0)
        {
            Sn = Sn ^ 1;                               logic16 (); 
        }
        else
        {
            Sn = Sn ^ 0;                               logic16 (); 
        }

        noise_bits <<= 1;
        noise_bits |= *shift_reg & 1;

        *shift_reg = L_shr (*shift_reg, 1);            move32 (); 
        if (Sn & 1)
        {
            *shift_reg = *shift_reg | 0x40000000L;     move32 (); logic32 (); 
        }
    }

    return noise_bits;
}