diff libgsmefr/dtx_dec.c @ 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 libgsmefr/dtx.c@58b64224d4ac
children 0303ba213e1c
line wrap: on
line diff
--- /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;
+}