changeset 119:c1d53064b410

libgsmefr: split dtx.c into dtx_{common,dec,enc}.c
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 10 Dec 2022 02:25:20 +0000
parents cc08498ed21b
children bd832a456339
files libgsmefr/Makefile libgsmefr/dtx.c libgsmefr/dtx_common.c libgsmefr/dtx_dec.c libgsmefr/dtx_defs.h libgsmefr/dtx_enc.c
diffstat 6 files changed, 1129 insertions(+), 1141 deletions(-) [+]
line wrap: on
line diff
--- a/libgsmefr/Makefile	Sat Dec 10 01:28:05 2022 +0000
+++ b/libgsmefr/Makefile	Sat Dec 10 02:25:20 2022 +0000
@@ -2,16 +2,17 @@
 CFLAGS=	-O2
 OBJS=	agc.o autocorr.o az_lsp.o basicop2.o bfi_nodata.o c1035pf.o cod_12k2.o \
 	convolve.o d1035pf.o d_gains.o d_homing.o d_plsf_5.o dec_12k2.o \
-	dec_create.o dec_lag6.o dec_main.o dec_wrap.o dtx.o e_homing.o \
-	enc_create.o enc_lag6.o enc_main.o enc_wrap.o frame2params.o g_code.o \
-	g_pitch.o int_lpc.o inter_6.o inv_sqrt.o lag_wind.o levinson.o log2.o \
-	lsp_az.o lsp_lsf.o oper_32b.o params2frame.o pitch_f6.o pitch_ol.o \
-	pow2.o pre_proc.o pred_lt6.o preemph.o pstfilt2.o q_gains.o \
-	q_plsf5_tab.o q_plsf_5.o reorder.o residu.o sid_class.o sid_insert.o \
-	syn_filt.o tls_flags.o vad.o weight_a.o
-HDRS=	basic_op.h cnst.h codec.h d_homing.h dec_state.h dtx.h e_homing.h \
-	enc_state.h gains_tb.h gsm_efr.h memops.h namespace.h no_count.h \
-	oper_32b.h q_plsf5_tab.h sig_proc.h typedef.h vad.h
+	dec_create.o dec_lag6.o dec_main.o dec_wrap.o dtx_common.o dtx_dec.o \
+	dtx_enc.o e_homing.o enc_create.o enc_lag6.o enc_main.o enc_wrap.o \
+	frame2params.o g_code.o g_pitch.o int_lpc.o inter_6.o inv_sqrt.o \
+	lag_wind.o levinson.o log2.o lsp_az.o lsp_lsf.o oper_32b.o \
+	params2frame.o pitch_f6.o pitch_ol.o pow2.o pre_proc.o pred_lt6.o \
+	preemph.o pstfilt2.o q_gains.o q_plsf5_tab.o q_plsf_5.o reorder.o \
+	residu.o sid_class.o sid_insert.o syn_filt.o tls_flags.o vad.o \
+	weight_a.o
+HDRS=	basic_op.h cnst.h codec.h d_homing.h dec_state.h dtx.h dtx_defs.h \
+	e_homing.h enc_state.h gains_tb.h gsm_efr.h memops.h namespace.h \
+	no_count.h oper_32b.h q_plsf5_tab.h sig_proc.h typedef.h vad.h
 LIB=	libgsmefr.a
 
 INSTALL_PREFIX=	/usr/local
--- a/libgsmefr/dtx.c	Sat Dec 10 01:28:05 2022 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1131 +0,0 @@
-/***************************************************************************
- *
- *   File Name: dtx.c
- *
- *   Purpose:   Contains functions for performing DTX operation and comfort
- *              noise generation.
- *
- *     Below is a listing of all the functions appearing in the file.
- *     The functions are arranged according to their purpose.  Under
- *     each heading, the ordering is hierarchical.
- *
- *     Resetting of static variables of TX DTX:
- *       reset_tx_dtx()
- *     Resetting of static variables of RX DTX:
- *       reset_rx_dtx()
- *
- *     TX DTX handler (called by the speech encoder):
- *       tx_dtx()
- *     RX DTX handler (called by the speech decoder):
- *       rx_dtx()
- *     Encoding of comfort noise parameters into SID frame:
- *       CN_encoding()
- *     Encoding of SID codeword into SID frame:
- *       sid_codeword_encoding()
- *     Detecting of SID codeword from a frame:
- *       sid_frame_detection()
- *     Update the LSF parameter history:
- *       update_lsf_history()
- *     Update the reference LSF parameter vector:
- *       update_lsf_p_CN()
- *     Compute the averaged LSF parameter vector:
- *       aver_lsf_history()
- *     Update the fixed codebook gain parameter history of the encoder:
- *       update_gain_code_history_tx()
- *     Update the fixed codebook gain parameter history of the decoder:
- *       update_gain_code_history_rx()
- *     Compute the unquantized fixed codebook gain:
- *       compute_CN_excitation_gain()
- *     Update the reference fixed codebook gain:
- *       update_gcode0_CN()
- *     Compute the averaged fixed codebook gain:
- *       aver_gain_code_history()
- *     Compute the comfort noise fixed codebook excitation:
- *       build_CN_code()
- *       Generate a random integer value:
- *         pseudonoise()
- *     Interpolate a comfort noise parameter value over the comfort noise
- *       update period:
- *       interpolate_CN_param()
- *     Interpolate comfort noise LSF pparameter values over the comfort
- *       noise update period:
- *       interpolate_CN_lsf()
- *         interpolate_CN_param()
- *
- **************************************************************************/
-
-#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 "enc_state.h"
-#include "dec_state.h"
-
-/* Inverse values of DTX hangover period and DTX hangover period + 1 */
-
-#define INV_DTX_HANGOVER (0x7fff / DTX_HANGOVER)
-#define INV_DTX_HANGOVER_P1 (0x7fff / (DTX_HANGOVER+1))
-
-#define NB_PULSE 10 /* Number of pulses in fixed codebook excitation */
-
-/* Constant DTX_ELAPSED_THRESHOLD is used as threshold for allowing
-   SID frame updating without hangover period in case when elapsed
-   time measured from previous SID update is below 24 */
-
-#define DTX_ELAPSED_THRESHOLD (24 + DTX_HANGOVER - 1)
-
-/*************************************************************************
- *
- *   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: 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: 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 (sub (VAD_flag, 1) == 0)
-    {
-        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 = sub (st->txdtx_hangover, 1);
-
-            /* 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 (sub (add (st->txdtx_N_elapsed, st->txdtx_hangover),
-                     DTX_ELAPSED_THRESHOLD) < 0)
-            {
-                /* 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: 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 ((sub (SID_flag, 2) == 0) && (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 (sub (frame_type, VALID_SID_FRAME) == 0)
-        {
-            st->rxdtx_ctrl = RX_FIRST_SID_UPDATE;
-        }
-        else if (sub (frame_type, INVALID_SID_FRAME) == 0)
-        {
-            st->rxdtx_ctrl = RX_FIRST_SID_UPDATE
-                           | RX_INVALID_SID_FRAME;
-        }
-        else if (sub (frame_type, UNUSABLE_FRAME) == 0)
-        {
-            st->rxdtx_ctrl = RX_SP_FLAG;
-        }
-        else if (sub (frame_type, GOOD_SPEECH_FRAME) == 0)
-        {
-            st->rxdtx_ctrl = RX_SP_FLAG;
-        }
-    }
-    else
-    {
-        if (sub (frame_type, VALID_SID_FRAME) == 0)
-        {
-            st->rxdtx_ctrl = RX_CONT_SID_UPDATE;
-        }
-        else if (sub (frame_type, INVALID_SID_FRAME) == 0)
-        {
-            st->rxdtx_ctrl = RX_CONT_SID_UPDATE
-                           | RX_INVALID_SID_FRAME;
-        }
-        else if (sub (frame_type, UNUSABLE_FRAME) == 0)
-        {
-            st->rxdtx_ctrl = RX_CNI_BFI;
-        }
-        else if (sub (frame_type, GOOD_SPEECH_FRAME) == 0)
-        {
-            /* 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 (sub (frame_type, VALID_SID_FRAME) == 0)
-            {
-                st->rx_dtx_state = 0;
-            }
-            else if (sub (frame_type, INVALID_SID_FRAME) == 0)
-            {
-                if (sub(st->rx_dtx_state, (CN_INT_PERIOD - 1)) < 0)
-                {
-                    st->rx_dtx_state = add(st->rx_dtx_state, 1);
-                }
-            }
-        }
-
-        /* Bad frame received in CNI mode */
-        if ((st->rxdtx_ctrl & RX_CNI_BFI) != 0)
-        {
-            if (sub (st->rx_dtx_state, (CN_INT_PERIOD - 1)) < 0)
-            {
-                st->rx_dtx_state = add (st->rx_dtx_state, 1);
-            }
-
-            /* If an unusable frame is received during CNI period
-               when TAF == 1, the frame is classified as a lost
-               SID frame */
-            if (sub (TAF, 1) == 0)
-            {
-                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 (sub (st->prev_SID_frames_lost, 1) > 0)
-            {
-                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 (sub (st->rxdtx_N_elapsed, DTX_ELAPSED_THRESHOLD) > 0)
-        {
-            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 = sub (st->rxdtx_aver_period, 1);
-        }
-    }
-
-    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: 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: 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 (sub (st->buf_p_tx, (4 * DTX_HANGOVER - 1)) == 0)
-    {
-        st->buf_p_tx = 0;
-    }
-    else
-    {
-        st->buf_p_tx = add (st->buf_p_tx, 1);
-    }
-
-    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 (sub (st->buf_p_rx, (4 * DTX_HANGOVER - 1)) == 0)
-    {
-        st->buf_p_rx = 0;
-    }
-    else
-    {
-        st->buf_p_rx = add (st->buf_p_rx, 1);
-    }
-
-    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_sub (L_temp, MAX_32) == 0)
-        {
-            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: 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: 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);
-}
-
-/*************************************************************************
- *
- *   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 = shr (extract_l (L_mult (i, 10)), 1);
-        i = add (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 = shl (noise_bits, 1);
-        noise_bits = noise_bits | (extract_l (*shift_reg) & 1);
-        logic16 (); logic16 (); 
-
-        *shift_reg = L_shr (*shift_reg, 1);            move32 (); 
-        test (); logic16 (); 
-        if (Sn & 1)
-        {
-            *shift_reg = *shift_reg | 0x40000000L;     move32 (); logic32 (); 
-        }
-    }
-
-    return noise_bits;
-}
-
-/*************************************************************************
- *
- *   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;
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgsmefr/dtx_common.c	Sat Dec 10 02:25:20 2022 +0000
@@ -0,0 +1,257 @@
+/*
+ * 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 = shr (extract_l (L_mult (i, 10)), 1);
+        i = add (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 = shl (noise_bits, 1);
+        noise_bits = noise_bits | (extract_l (*shift_reg) & 1);
+        logic16 (); logic16 (); 
+
+        *shift_reg = L_shr (*shift_reg, 1);            move32 (); 
+        test (); logic16 (); 
+        if (Sn & 1)
+        {
+            *shift_reg = *shift_reg | 0x40000000L;     move32 (); logic32 (); 
+        }
+    }
+
+    return noise_bits;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgsmefr/dtx_dec.c	Sat Dec 10 02:25:20 2022 +0000
@@ -0,0 +1,400 @@
+/*
+ * 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 ((sub (SID_flag, 2) == 0) && (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 (sub (frame_type, VALID_SID_FRAME) == 0)
+        {
+            st->rxdtx_ctrl = RX_FIRST_SID_UPDATE;
+        }
+        else if (sub (frame_type, INVALID_SID_FRAME) == 0)
+        {
+            st->rxdtx_ctrl = RX_FIRST_SID_UPDATE
+                           | RX_INVALID_SID_FRAME;
+        }
+        else if (sub (frame_type, UNUSABLE_FRAME) == 0)
+        {
+            st->rxdtx_ctrl = RX_SP_FLAG;
+        }
+        else if (sub (frame_type, GOOD_SPEECH_FRAME) == 0)
+        {
+            st->rxdtx_ctrl = RX_SP_FLAG;
+        }
+    }
+    else
+    {
+        if (sub (frame_type, VALID_SID_FRAME) == 0)
+        {
+            st->rxdtx_ctrl = RX_CONT_SID_UPDATE;
+        }
+        else if (sub (frame_type, INVALID_SID_FRAME) == 0)
+        {
+            st->rxdtx_ctrl = RX_CONT_SID_UPDATE
+                           | RX_INVALID_SID_FRAME;
+        }
+        else if (sub (frame_type, UNUSABLE_FRAME) == 0)
+        {
+            st->rxdtx_ctrl = RX_CNI_BFI;
+        }
+        else if (sub (frame_type, GOOD_SPEECH_FRAME) == 0)
+        {
+            /* 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 (sub (frame_type, VALID_SID_FRAME) == 0)
+            {
+                st->rx_dtx_state = 0;
+            }
+            else if (sub (frame_type, INVALID_SID_FRAME) == 0)
+            {
+                if (sub(st->rx_dtx_state, (CN_INT_PERIOD - 1)) < 0)
+                {
+                    st->rx_dtx_state = add(st->rx_dtx_state, 1);
+                }
+            }
+        }
+
+        /* Bad frame received in CNI mode */
+        if ((st->rxdtx_ctrl & RX_CNI_BFI) != 0)
+        {
+            if (sub (st->rx_dtx_state, (CN_INT_PERIOD - 1)) < 0)
+            {
+                st->rx_dtx_state = add (st->rx_dtx_state, 1);
+            }
+
+            /* If an unusable frame is received during CNI period
+               when TAF == 1, the frame is classified as a lost
+               SID frame */
+            if (sub (TAF, 1) == 0)
+            {
+                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 (sub (st->prev_SID_frames_lost, 1) > 0)
+            {
+                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 (sub (st->rxdtx_N_elapsed, DTX_ELAPSED_THRESHOLD) > 0)
+        {
+            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 = sub (st->rxdtx_aver_period, 1);
+        }
+    }
+
+    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 (sub (st->buf_p_rx, (4 * DTX_HANGOVER - 1)) == 0)
+    {
+        st->buf_p_rx = 0;
+    }
+    else
+    {
+        st->buf_p_rx = add (st->buf_p_rx, 1);
+    }
+
+    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;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgsmefr/dtx_defs.h	Sat Dec 10 02:25:20 2022 +0000
@@ -0,0 +1,19 @@
+/*
+ * The definitions contained in this header file originally lived in
+ * dtx.c; they are being factored out into a new header file as part of
+ * splitting of dtx.c code into common, encoder-only and decoder-only
+ * parts.
+ */
+
+/* Inverse values of DTX hangover period and DTX hangover period + 1 */
+
+#define INV_DTX_HANGOVER (0x7fff / DTX_HANGOVER)
+#define INV_DTX_HANGOVER_P1 (0x7fff / (DTX_HANGOVER+1))
+
+#define NB_PULSE 10 /* Number of pulses in fixed codebook excitation */
+
+/* Constant DTX_ELAPSED_THRESHOLD is used as threshold for allowing
+   SID frame updating without hangover period in case when elapsed
+   time measured from previous SID update is below 24 */
+
+#define DTX_ELAPSED_THRESHOLD (24 + DTX_HANGOVER - 1)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgsmefr/dtx_enc.c	Sat Dec 10 02:25:20 2022 +0000
@@ -0,0 +1,442 @@
+/*
+ * 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 (sub (VAD_flag, 1) == 0)
+    {
+        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 = sub (st->txdtx_hangover, 1);
+
+            /* 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 (sub (add (st->txdtx_N_elapsed, st->txdtx_hangover),
+                     DTX_ELAPSED_THRESHOLD) < 0)
+            {
+                /* 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 (sub (st->buf_p_tx, (4 * DTX_HANGOVER - 1)) == 0)
+    {
+        st->buf_p_tx = 0;
+    }
+    else
+    {
+        st->buf_p_tx = add (st->buf_p_tx, 1);
+    }
+
+    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_sub (L_temp, MAX_32) == 0)
+        {
+            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);
+}