/* ------------------------------------------------------------------
 * Copyright (C) 1998-2009 PacketVideo
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 * -------------------------------------------------------------------
 */
/****************************************************************************************
Portions of this file are derived from the following 3GPP standard:

    3GPP TS 26.073
    ANSI-C code for the Adaptive Multi-Rate (AMR) speech codec
    Available from http://www.3gpp.org

(C) 2004, 3GPP Organizational Partners (ARIB, ATIS, CCSA, ETSI, TTA, TTC)
Permission to distribute, modify and use this file under the standard license
terms listed above has been obtained from the copyright holder.
****************************************************************************************/
/*
------------------------------------------------------------------------------



 Pathname: ./audio/gsm-amr/c/src/dtx_dec.c
 Functions:
           dtx_dec_reset
           dtx_dec
           dtx_dec_activity_update
           rx_dtx_handler

------------------------------------------------------------------------------
 MODULE DESCRIPTION

 These modules decode the comfort noise when in DTX.

------------------------------------------------------------------------------
*/


/*----------------------------------------------------------------------------
; INCLUDES
----------------------------------------------------------------------------*/
#include <string.h>

#include "dtx_dec.h"
#include "typedef.h"
#include "basic_op.h"
#include "copy.h"
#include "set_zero.h"
#include "mode.h"
#include "log2.h"
#include "lsp_az.h"
#include "pow2.h"
#include "a_refl.h"
#include "b_cn_cod.h"
#include "syn_filt.h"
#include "lsp_lsf.h"
#include "reorder.h"
#include "lsp_tab.h"

/*----------------------------------------------------------------------------
; MACROS
; Define module specific macros here
----------------------------------------------------------------------------*/


/*----------------------------------------------------------------------------
; DEFINES
; Include all pre-processor statements here. Include conditional
; compile variables also.
----------------------------------------------------------------------------*/
#define PN_INITIAL_SEED 0x70816958L   /* Pseudo noise generator seed value  */

/*----------------------------------------------------------------------------
; LOCAL FUNCTION DEFINITIONS
; Function Prototype declaration
----------------------------------------------------------------------------*/


/*----------------------------------------------------------------------------
; LOCAL VARIABLE DEFINITIONS
; Variable declaration - defined here and used outside this module
----------------------------------------------------------------------------*/

/***************************************************
 * Scaling factors for the lsp variability operation *
 ***************************************************/
static const Word16 lsf_hist_mean_scale[M] =
{
    20000,
    20000,
    20000,
    20000,
    20000,
    18000,
    16384,
    8192,
    0,
    0
};

/*************************************************
 * level adjustment for different modes Q11      *
 *************************************************/
static const Word16 dtx_log_en_adjust[9] =
{
    -1023, /* MR475 */
    -878, /* MR515 */
    -732, /* MR59  */
    -586, /* MR67  */
    -440, /* MR74  */
    -294, /* MR795 */
    -148, /* MR102 */
    0, /* MR122 */
    0, /* MRDTX */
};


/*
------------------------------------------------------------------------------
 FUNCTION NAME: dtx_dec_reset
------------------------------------------------------------------------------
 INPUT AND OUTPUT DEFINITIONS

 Inputs:
    st = pointer to a structure of type dtx_decState

 Outputs:
    Structure pointed to by st is initialized to a set of initial values.

 Returns:
    return_value = 0 if memory was successfully initialized,
        otherwise returns -1 (int)

 Global Variables Used:
    None.

 Local Variables Needed:
    None.

------------------------------------------------------------------------------
 FUNCTION DESCRIPTION

 Reset of state memory for dtx_dec.

------------------------------------------------------------------------------
 REQUIREMENTS

 None.

------------------------------------------------------------------------------
 REFERENCES

 dtx_dec.c, UMTS GSM AMR speech codec, R99 - Version 3.3.0, December 12, 2001

------------------------------------------------------------------------------
 PSEUDO-CODE

int dtx_dec_reset (dtx_decState *st)
{
   int i;

   if (st == (dtx_decState *) NULL){
      fprintf(stderr, "dtx_dec_reset: invalid parameter\n");
      return -1;
   }

   st->since_last_sid = 0;
   st->true_sid_period_inv = (1 << 13);

   st->log_en = 3500;
   st->old_log_en = 3500;
   // low level noise for better performance in  DTX handover cases

   st->L_pn_seed_rx = PN_INITIAL_SEED;

   // Initialize state->lsp [] and state->lsp_old []
   Copy(lsp_init_data, &st->lsp[0], M);
   Copy(lsp_init_data, &st->lsp_old[0], M);

   st->lsf_hist_ptr = 0;
   st->log_pg_mean = 0;
   st->log_en_hist_ptr = 0;

   // initialize decoder lsf history
   Copy(mean_lsf, &st->lsf_hist[0], M);

   for (i = 1; i < DTX_HIST_SIZE; i++)
   {
      Copy(&st->lsf_hist[0], &st->lsf_hist[M*i], M);
   }
   Set_zero(st->lsf_hist_mean, M*DTX_HIST_SIZE);

   // initialize decoder log frame energy
   for (i = 0; i < DTX_HIST_SIZE; i++)
   {
      st->log_en_hist[i] = st->log_en;
   }

   st->log_en_adjust = 0;

   st->dtxHangoverCount = DTX_HANG_CONST;
   st->decAnaElapsedCount = 32767;

   st->sid_frame = 0;
   st->valid_data = 0;
   st->dtxHangoverAdded = 0;

   st->dtxGlobalState = DTX;
   st->data_updated = 0;
   return 0;
}

------------------------------------------------------------------------------
 RESOURCES USED [optional]

 When the code is written for a specific target processor the
 the resources used should be documented below.

 HEAP MEMORY USED: x bytes

 STACK MEMORY USED: x bytes

 CLOCK CYCLES: (cycle count equation for this function) + (variable
                used to represent cycle count for each subroutine
                called)
     where: (cycle count variable) = cycle count for [subroutine
                                     name]

------------------------------------------------------------------------------
 CAUTION [optional]
 [State any special notes, constraints or cautions for users of this function]

------------------------------------------------------------------------------
*/

Word16 dtx_dec_reset(dtx_decState *st)
{
    Word16 i;

    if (st == (dtx_decState *) NULL)
    {
        /* fprint(stderr, "dtx_dec_reset: invalid parameter\n");  */
        return(-1);
    }

    st->since_last_sid = 0;
    st->true_sid_period_inv = (1 << 13);

    st->log_en = 3500;
    st->old_log_en = 3500;
    /* low level noise for better performance in  DTX handover cases*/

    st->L_pn_seed_rx = PN_INITIAL_SEED;

    /* Initialize state->lsp [] */
    st->lsp[0] = 30000;
    st->lsp[1] = 26000;
    st->lsp[2] = 21000;
    st->lsp[3] = 15000;
    st->lsp[4] = 8000;
    st->lsp[5] = 0;
    st->lsp[6] = -8000;
    st->lsp[7] = -15000;
    st->lsp[8] = -21000;
    st->lsp[9] = -26000;

    /* Initialize state->lsp_old [] */
    st->lsp_old[0] = 30000;
    st->lsp_old[1] = 26000;
    st->lsp_old[2] = 21000;
    st->lsp_old[3] = 15000;
    st->lsp_old[4] = 8000;
    st->lsp_old[5] = 0;
    st->lsp_old[6] = -8000;
    st->lsp_old[7] = -15000;
    st->lsp_old[8] = -21000;
    st->lsp_old[9] = -26000;

    st->lsf_hist_ptr = 0;
    st->log_pg_mean = 0;
    st->log_en_hist_ptr = 0;

    /* initialize decoder lsf history */
    st->lsf_hist[0] =  1384;
    st->lsf_hist[1] =  2077;
    st->lsf_hist[2] =  3420;
    st->lsf_hist[3] =  5108;
    st->lsf_hist[4] =  6742;
    st->lsf_hist[5] =  8122;
    st->lsf_hist[6] =  9863;
    st->lsf_hist[7] = 11092;
    st->lsf_hist[8] = 12714;
    st->lsf_hist[9] = 13701;

    for (i = 1; i < DTX_HIST_SIZE; i++)
    {
        Copy(&st->lsf_hist[0], &st->lsf_hist[M*i], M);
    }
    memset(st->lsf_hist_mean, 0, sizeof(Word16)*M*DTX_HIST_SIZE);

    /* initialize decoder log frame energy */
    for (i = 0; i < DTX_HIST_SIZE; i++)
    {
        st->log_en_hist[i] = st->log_en;
    }

    st->log_en_adjust = 0;

    st->dtxHangoverCount = DTX_HANG_CONST;
    st->decAnaElapsedCount = 32767;

    st->sid_frame = 0;
    st->valid_data = 0;
    st->dtxHangoverAdded = 0;

    st->dtxGlobalState = DTX;
    st->data_updated = 0;

    return(0);
}

/****************************************************************************/

/*
------------------------------------------------------------------------------
 FUNCTION NAME: dtx_dec
------------------------------------------------------------------------------
 INPUT AND OUTPUT DEFINITIONS

 Inputs:
    st = pointer to a structure of type dtx_decState
    mem_syn = AMR decoder state
    lsfState = decoder lsf states
    predState = prediction states
    averState = CB gain average states
    new_state = new DTX state
    mode = AMR mode
    parm = Vector of synthesis parameters

 Outputs:
    st points to an updated structure of type dtx_decState
    mem_syn = AMR decoder state
    lsfState = decoder lsf states
    predState = prediction states
    averState = CB gain average states
    synth = synthesised speech
    A_t = decoded LP filter in 4 subframes

 Returns:
    return_value = 0 (int)

 Global Variables Used:
    None.

 Local Variables Needed:
    None.

------------------------------------------------------------------------------
 FUNCTION DESCRIPTION

 Decode comfort noise when in DTX.

------------------------------------------------------------------------------
 REQUIREMENTS

 None

------------------------------------------------------------------------------
 REFERENCES

 dtx_dec.c, UMTS GSM AMR speech codec, R99 - Version 3.3.0, December 12, 2001

------------------------------------------------------------------------------
 PSEUDO-CODE

int dtx_dec(
   dtx_decState *st,                // i/o : State struct
   Word16 mem_syn[],                // i/o : AMR decoder state
   D_plsfState* lsfState,           // i/o : decoder lsf states
   gc_predState* predState,         // i/o : prediction states
   Cb_gain_averageState* averState, // i/o : CB gain average states
   enum DTXStateType new_state,     // i   : new DTX state
   enum Mode mode,                  // i   : AMR mode
   Word16 parm[],                   // i   : Vector of synthesis parameters
   Word16 synth[],                  // o   : synthesised speech
   Word16 A_t[]                     // o   : decoded LP filter in 4 subframes
   )
{
   Word16 log_en_index;
   Word16 i, j;
   Word16 int_fac;
   Word32 L_log_en_int;
   Word16 lsp_int[M];
   Word16 log_en_int_e;
   Word16 log_en_int_m;
   Word16 level;
   Word16 acoeff[M + 1];
   Word16 refl[M];
   Word16 pred_err;
   Word16 ex[L_SUBFR];
   Word16 ma_pred_init;
   Word16 log_pg_e, log_pg_m;
   Word16 log_pg;
   Flag negative;
   Word16 lsf_mean;
   Word32 L_lsf_mean;
   Word16 lsf_variab_index;
   Word16 lsf_variab_factor;
   Word16 lsf_int[M];
   Word16 lsf_int_variab[M];
   Word16 lsp_int_variab[M];
   Word16 acoeff_variab[M + 1];

   Word16 lsf[M];
   Word32 L_lsf[M];
   Word16 ptr;
   Word16 tmp_int_length;


    // This function is called if synthesis state is not SPEECH
    // the globally passed  inputs to this function are
    // st->sid_frame
    // st->valid_data
    // st->dtxHangoverAdded
    // new_state  (SPEECH, DTX, DTX_MUTE)

   if ((st->dtxHangoverAdded != 0) &&
       (st->sid_frame != 0))
   {
      // sid_first after dtx hangover period
      // or sid_upd after dtxhangover

      // set log_en_adjust to correct value
      st->log_en_adjust = dtx_log_en_adjust[mode];

      ptr = add(st->lsf_hist_ptr, M);
      if (sub(ptr, 80) == 0)
      {
         ptr = 0;
      }
      Copy( &st->lsf_hist[st->lsf_hist_ptr],&st->lsf_hist[ptr],M);

      ptr = add(st->log_en_hist_ptr,1);
      if (sub(ptr, DTX_HIST_SIZE) == 0)
      {
         ptr = 0;
      }
      st->log_en_hist[ptr] = st->log_en_hist[st->log_en_hist_ptr]; // Q11

      // compute mean log energy and lsp
      // from decoded signal (SID_FIRST)
      st->log_en = 0;
      for (i = 0; i < M; i++)
      {
         L_lsf[i] = 0;
      }

      // average energy and lsp
      for (i = 0; i < DTX_HIST_SIZE; i++)
      {
         st->log_en = add(st->log_en,
                          shr(st->log_en_hist[i],3));
         for (j = 0; j < M; j++)
         {
            L_lsf[j] = L_add(L_lsf[j],
                             L_deposit_l(st->lsf_hist[i * M + j]));
         }
      }

      for (j = 0; j < M; j++)
      {
         lsf[j] = extract_l(L_shr(L_lsf[j],3)); // divide by 8
      }

      Lsf_lsp(lsf, st->lsp, M);

      // make log_en speech coder mode independent
      // added again later before synthesis
      st->log_en = sub(st->log_en, st->log_en_adjust);

      // compute lsf variability vector
      Copy(st->lsf_hist, st->lsf_hist_mean, 80);

      for (i = 0; i < M; i++)
      {
         L_lsf_mean = 0;
         // compute mean lsf
         for (j = 0; j < 8; j++)
         {
            L_lsf_mean = L_add(L_lsf_mean,
                               L_deposit_l(st->lsf_hist_mean[i+j*M]));
         }

         lsf_mean = extract_l(L_shr(L_lsf_mean, 3));
          // subtract mean and limit to within reasonable limits
          // moreover the upper lsf's are attenuated
         for (j = 0; j < 8; j++)
         {
            // subtract mean
            st->lsf_hist_mean[i+j*M] =
               sub(st->lsf_hist_mean[i+j*M], lsf_mean);

            // attenuate deviation from mean, especially for upper lsf's
            st->lsf_hist_mean[i+j*M] =
               mult(st->lsf_hist_mean[i+j*M], lsf_hist_mean_scale[i]);

            // limit the deviation
            if (st->lsf_hist_mean[i+j*M] < 0)
            {
               negative = 1;
            }
            else
            {
               negative = 0;
            }
            st->lsf_hist_mean[i+j*M] = abs_s(st->lsf_hist_mean[i+j*M]);

            // apply soft limit
            if (sub(st->lsf_hist_mean[i+j*M], 655) > 0)
            {
               st->lsf_hist_mean[i+j*M] =
                  add(655, shr(sub(st->lsf_hist_mean[i+j*M], 655), 2));
            }

            // apply hard limit
            if (sub(st->lsf_hist_mean[i+j*M], 1310) > 0)
            {
               st->lsf_hist_mean[i+j*M] = 1310;
            }
            if (negative != 0)
            {
               st->lsf_hist_mean[i+j*M] = -st->lsf_hist_mean[i+j*M];
            }

         }
      }
   }

   if (st->sid_frame != 0 )
   {
      // Set old SID parameters, always shift
      // even if there is no new valid_data
      Copy(st->lsp, st->lsp_old, M);
      st->old_log_en = st->log_en;

      if (st->valid_data != 0 )  // new data available (no CRC)
      {
         // Compute interpolation factor, since the division only works
         // for values of since_last_sid < 32 we have to limit the
         // interpolation to 32 frames
         tmp_int_length = st->since_last_sid;
         st->since_last_sid = 0;

         if (sub(tmp_int_length, 32) > 0)
         {
            tmp_int_length = 32;
         }
         if (sub(tmp_int_length, 2) >= 0)
         {
            st->true_sid_period_inv = div_s(1 << 10, shl(tmp_int_length, 10));
         }
         else
         {
            st->true_sid_period_inv = 1 << 14; // 0.5 it Q15
         }

         Init_D_plsf_3(lsfState, parm[0]);  // temporay initialization
         D_plsf_3(lsfState, MRDTX, 0, &parm[1], st->lsp);
         Set_zero(lsfState->past_r_q, M);   // reset for next speech frame

         log_en_index = parm[4];
         // Q11 and divide by 4
         st->log_en = shl(log_en_index, (11 - 2));

         // Subtract 2.5 in Q11
         st->log_en = sub(st->log_en, (2560 * 2));

         // Index 0 is reserved for silence
         if (log_en_index == 0)
         {
            st->log_en = MIN_16;
         }

         // no interpolation at startup after coder reset
         // or when SID_UPD has been received right after SPEECH
         if ((st->data_updated == 0) ||
             (sub(st->dtxGlobalState, SPEECH) == 0)
             )
         {
            Copy(st->lsp, st->lsp_old, M);
            st->old_log_en = st->log_en;
         }
      } // endif valid_data

      // initialize gain predictor memory of other modes
      ma_pred_init = sub(shr(st->log_en,1), 9000);
      if (ma_pred_init > 0)
      {
         ma_pred_init = 0;
      }
      if (sub(ma_pred_init, -14436) < 0)
      {
         ma_pred_init = -14436;
      }

      predState->past_qua_en[0] = ma_pred_init;
      predState->past_qua_en[1] = ma_pred_init;
      predState->past_qua_en[2] = ma_pred_init;
      predState->past_qua_en[3] = ma_pred_init;

      // past_qua_en for other modes than MR122
      ma_pred_init = mult(5443, ma_pred_init);
      // scale down by factor 20*log10(2) in Q15
      predState->past_qua_en_MR122[0] = ma_pred_init;
      predState->past_qua_en_MR122[1] = ma_pred_init;
      predState->past_qua_en_MR122[2] = ma_pred_init;
      predState->past_qua_en_MR122[3] = ma_pred_init;
   } // endif sid_frame

   // CN generation
   // recompute level adjustment factor Q11
   // st->log_en_adjust = 0.9*st->log_en_adjust +
   //                     0.1*dtx_log_en_adjust[mode]);
   st->log_en_adjust = add(mult(st->log_en_adjust, 29491),
                           shr(mult(shl(dtx_log_en_adjust[mode],5),3277),5));

   // Interpolate SID info
   int_fac = shl(add(1,st->since_last_sid), 10); // Q10
   int_fac = mult(int_fac, st->true_sid_period_inv); // Q10 * Q15 -> Q10

   // Maximize to 1.0 in Q10
   if (sub(int_fac, 1024) > 0)
   {
      int_fac = 1024;
   }
   int_fac = shl(int_fac, 4); // Q10 -> Q14

   L_log_en_int = L_mult(int_fac, st->log_en); // Q14 * Q11->Q26
   for(i = 0; i < M; i++)
   {
      lsp_int[i] = mult(int_fac, st->lsp[i]);// Q14 * Q15 -> Q14
   }

   int_fac = sub(16384, int_fac); // 1-k in Q14

   // (Q14 * Q11 -> Q26) + Q26 -> Q26
   L_log_en_int = L_mac(L_log_en_int, int_fac, st->old_log_en);
   for(i = 0; i < M; i++)
   {
      // Q14 + (Q14 * Q15 -> Q14) -> Q14
      lsp_int[i] = add(lsp_int[i], mult(int_fac, st->lsp_old[i]));
      lsp_int[i] = shl(lsp_int[i], 1); // Q14 -> Q15
   }

   // compute the amount of lsf variability
   lsf_variab_factor = sub(st->log_pg_mean,2457); // -0.6 in Q12
   // *0.3 Q12*Q15 -> Q12
   lsf_variab_factor = sub(4096, mult(lsf_variab_factor, 9830));

   // limit to values between 0..1 in Q12
   if (sub(lsf_variab_factor, 4096) > 0)
   {
      lsf_variab_factor = 4096;
   }
   if (lsf_variab_factor < 0)
   {
      lsf_variab_factor = 0;
   }
   lsf_variab_factor = shl(lsf_variab_factor, 3); // -> Q15

   // get index of vector to do variability with
   lsf_variab_index = pseudonoise(&st->L_pn_seed_rx, 3);

   // convert to lsf
   Lsp_lsf(lsp_int, lsf_int, M);

   // apply lsf variability
   Copy(lsf_int, lsf_int_variab, M);
   for(i = 0; i < M; i++)
   {
      lsf_int_variab[i] = add(lsf_int_variab[i],
                              mult(lsf_variab_factor,
                                   st->lsf_hist_mean[i+lsf_variab_index*M]));
   }

   // make sure that LSP's are ordered
   Reorder_lsf(lsf_int, LSF_GAP, M);
   Reorder_lsf(lsf_int_variab, LSF_GAP, M);

   // copy lsf to speech decoders lsf state
   Copy(lsf_int, lsfState->past_lsf_q, M);

   // convert to lsp
   Lsf_lsp(lsf_int, lsp_int, M);
   Lsf_lsp(lsf_int_variab, lsp_int_variab, M);

   // Compute acoeffs Q12 acoeff is used for level
   // normalization and postfilter, acoeff_variab is
   // used for synthesis filter
   // by doing this we make sure that the level
   // in high frequenncies does not jump up and down

   Lsp_Az(lsp_int, acoeff);
   Lsp_Az(lsp_int_variab, acoeff_variab);

   // For use in postfilter
   Copy(acoeff, &A_t[0],           M + 1);
   Copy(acoeff, &A_t[M + 1],       M + 1);
   Copy(acoeff, &A_t[2 * (M + 1)], M + 1);
   Copy(acoeff, &A_t[3 * (M + 1)], M + 1);

   // Compute reflection coefficients Q15
   A_Refl(&acoeff[1], refl);

   // Compute prediction error in Q15
   pred_err = MAX_16; // 0.99997 in Q15
   for (i = 0; i < M; i++)
   {
      pred_err = mult(pred_err, sub(MAX_16, mult(refl[i], refl[i])));
   }

   // compute logarithm of prediction gain
   Log2(L_deposit_l(pred_err), &log_pg_e, &log_pg_m);

   // convert exponent and mantissa to Word16 Q12
   log_pg = shl(sub(log_pg_e,15), 12);  // Q12
   log_pg = shr(sub(0,add(log_pg, shr(log_pg_m, 15-12))), 1);
   st->log_pg_mean = add(mult(29491,st->log_pg_mean),
                         mult(3277, log_pg));

   // Compute interpolated log energy
   L_log_en_int = L_shr(L_log_en_int, 10); // Q26 -> Q16

   // Add 4 in Q16
   L_log_en_int = L_add(L_log_en_int, 4 * 65536L);

   // subtract prediction gain
   L_log_en_int = L_sub(L_log_en_int, L_shl(L_deposit_l(log_pg), 4));

   // adjust level to speech coder mode
   L_log_en_int = L_add(L_log_en_int,
                        L_shl(L_deposit_l(st->log_en_adjust), 5));

   log_en_int_e = extract_h(L_log_en_int);
   log_en_int_m = extract_l(L_shr(L_sub(L_log_en_int,
                                        L_deposit_h(log_en_int_e)), 1));
   level = extract_l(Pow2(log_en_int_e, log_en_int_m)); // Q4

   for (i = 0; i < 4; i++)
   {
      // Compute innovation vector
      build_CN_code(&st->L_pn_seed_rx, ex);
      for (j = 0; j < L_SUBFR; j++)
      {
         ex[j] = mult(level, ex[j]);
      }
      // Synthesize
      Syn_filt(acoeff_variab, ex, &synth[i * L_SUBFR], L_SUBFR,
               mem_syn, 1);

   } // next i

   // reset codebook averaging variables
   averState->hangVar = 20;
   averState->hangCount = 0;

   if (sub(new_state, DTX_MUTE) == 0)
   {
      // mute comfort noise as it has been quite a long time since
       * last SID update  was performed

      tmp_int_length = st->since_last_sid;
      if (sub(tmp_int_length, 32) > 0)
      {
         tmp_int_length = 32;
      }

      // safety guard against division by zero
      if(tmp_int_length <= 0) {
         tmp_int_length = 8;
      }

      st->true_sid_period_inv = div_s(1 << 10, shl(tmp_int_length, 10));

      st->since_last_sid = 0;
      Copy(st->lsp, st->lsp_old, M);
      st->old_log_en = st->log_en;
      // subtract 1/8 in Q11 i.e -6/8 dB
      st->log_en = sub(st->log_en, 256);
   }

   // reset interpolation length timer
   // if data has been updated.
   if ((st->sid_frame != 0) &&
       ((st->valid_data != 0) ||
        ((st->valid_data == 0) &&  (st->dtxHangoverAdded) != 0)))
   {
      st->since_last_sid =  0;
      st->data_updated = 1;
   }

   return 0;
}


------------------------------------------------------------------------------
 RESOURCES USED [optional]

 When the code is written for a specific target processor the
 the resources used should be documented below.

 HEAP MEMORY USED: x bytes

 STACK MEMORY USED: x bytes

 CLOCK CYCLES: (cycle count equation for this function) + (variable
                used to represent cycle count for each subroutine
                called)
     where: (cycle count variable) = cycle count for [subroutine
                                     name]

------------------------------------------------------------------------------
 CAUTION [optional]
 [State any special notes, constraints or cautions for users of this function]

------------------------------------------------------------------------------
*/

void dtx_dec(
    dtx_decState *st,                /* i/o : State struct                    */
    Word16 mem_syn[],                /* i/o : AMR decoder state               */
    D_plsfState* lsfState,           /* i/o : decoder lsf states              */
    gc_predState* predState,         /* i/o : prediction states               */
    Cb_gain_averageState* averState, /* i/o : CB gain average states          */
    enum DTXStateType new_state,     /* i   : new DTX state                   */
    enum Mode mode,                  /* i   : AMR mode                        */
    Word16 parm[],                   /* i   : Vector of synthesis parameters  */
    Word16 synth[],                  /* o   : synthesised speech              */
    Word16 A_t[],                    /* o   : decoded LP filter in 4 subframes*/
    Flag   *pOverflow
)
{
    Word16 log_en_index;
    Word16 i;
    Word16 j;
    Word16 int_fac;
    Word32 L_log_en_int;
    Word16 lsp_int[M];
    Word16 log_en_int_e;
    Word16 log_en_int_m;
    Word16 level;
    Word16 acoeff[M + 1];
    Word16 refl[M];
    Word16 pred_err;
    Word16 ex[L_SUBFR];
    Word16 ma_pred_init;
    Word16 log_pg_e;
    Word16 log_pg_m;
    Word16 log_pg;
    Flag negative;
    Word16 lsf_mean;
    Word32 L_lsf_mean;
    Word16 lsf_variab_index;
    Word16 lsf_variab_factor;
    Word16 lsf_int[M];
    Word16 lsf_int_variab[M];
    Word16 lsp_int_variab[M];
    Word16 acoeff_variab[M + 1];

    Word16 lsf[M];
    Word32 L_lsf[M];
    Word16 ptr;
    Word16 tmp_int_length;

    Word32 L_temp;
    Word16 temp;

    /*  This function is called if synthesis state is not SPEECH
     *  the globally passed  inputs to this function are
     * st->sid_frame
     * st->valid_data
     * st->dtxHangoverAdded
     * new_state  (SPEECH, DTX, DTX_MUTE)
     */

    if ((st->dtxHangoverAdded != 0) &&
            (st->sid_frame != 0))
    {
        /* sid_first after dtx hangover period */
        /* or sid_upd after dtxhangover        */

        /* set log_en_adjust to correct value */
        st->log_en_adjust = dtx_log_en_adjust[mode];

        ptr = st->lsf_hist_ptr + M;

        if (ptr == 80)
        {
            ptr = 0;
        }
        Copy(&st->lsf_hist[st->lsf_hist_ptr], &st->lsf_hist[ptr], M);

        ptr = st->log_en_hist_ptr + 1;

        if (ptr == DTX_HIST_SIZE)
        {
            ptr = 0;
        }

        st->log_en_hist[ptr] = st->log_en_hist[st->log_en_hist_ptr]; /* Q11 */

        /* compute mean log energy and lsp *
         * from decoded signal (SID_FIRST) */
        st->log_en = 0;
        for (i = M - 1; i >= 0; i--)
        {
            L_lsf[i] = 0;
        }

        /* average energy and lsp */
        for (i = DTX_HIST_SIZE - 1; i >= 0; i--)
        {
            if (st->log_en_hist[i] < 0)
            {
                temp = ~((~st->log_en_hist[i]) >> 3);
            }
            else
            {
                temp = st->log_en_hist[i] >> 3;
            }
            st->log_en = add(st->log_en, temp, pOverflow);
            for (j = M - 1; j >= 0; j--)
            {
                L_lsf[j] = L_add(L_lsf[j],
                                 L_deposit_l(st->lsf_hist[i * M + j]), pOverflow);
            }
        }

        for (j = M - 1; j >= 0; j--)
        {
            if (L_lsf[j] < 0)
            {
                lsf[j] = (Word16)(~((~L_lsf[j]) >> 3));
            }
            else
            {
                lsf[j] = (Word16)(L_lsf[j] >> 3);
            }
        }

        Lsf_lsp(lsf, st->lsp, M, pOverflow);

        /* make log_en speech coder mode independent */
        /* added again later before synthesis        */
        st->log_en = sub(st->log_en, st->log_en_adjust, pOverflow);

        /* compute lsf variability vector */
        Copy(st->lsf_hist, st->lsf_hist_mean, 80);

        for (i = M - 1; i >= 0; i--)
        {
            L_lsf_mean = 0;
            /* compute mean lsf */
            for (j = 8 - 1; j >= 0; j--)
            {
                L_lsf_mean = L_add(L_lsf_mean,
                                   L_deposit_l(st->lsf_hist_mean[i+j*M]), pOverflow);
            }

            if (L_lsf_mean < 0)
            {
                lsf_mean = (Word16)(~((~L_lsf_mean) >> 3));
            }
            else
            {
                lsf_mean = (Word16)(L_lsf_mean >> 3);
            }
            /* subtract mean and limit to within reasonable limits  *
            * moreover the upper lsf's are attenuated              */
            for (j = 8 - 1; j >= 0; j--)
            {
                /* subtract mean */
                st->lsf_hist_mean[i+j*M] =
                    sub(st->lsf_hist_mean[i+j*M], lsf_mean, pOverflow);

                /* attenuate deviation from mean, especially for upper lsf's */
                st->lsf_hist_mean[i+j*M] =
                    mult(st->lsf_hist_mean[i+j*M], lsf_hist_mean_scale[i], pOverflow);

                /* limit the deviation */
                if (st->lsf_hist_mean[i+j*M] < 0)
                {
                    negative = 1;
                }
                else
                {
                    negative = 0;
                }
                st->lsf_hist_mean[i+j*M] = abs_s(st->lsf_hist_mean[i+j*M]);

                /* apply soft limit */
                if (st->lsf_hist_mean[i+j*M] > 655)
                {
                    st->lsf_hist_mean[i+j*M] = 655 + ((st->lsf_hist_mean[i+j*M]
                                                       - 655) >> 2);
                }

                /* apply hard limit */
                if (st->lsf_hist_mean[i+j*M] > 1310)
                {
                    st->lsf_hist_mean[i+j*M] = 1310;
                }

                if (negative != 0)
                {
                    st->lsf_hist_mean[i+j*M] = -st->lsf_hist_mean[i+j*M];
                }
            }
        }
    }


    if (st->sid_frame != 0)
    {
        /* Set old SID parameters, always shift */
        /* even if there is no new valid_data   */
        Copy(st->lsp, st->lsp_old, M);
        st->old_log_en = st->log_en;

        if (st->valid_data != 0)   /* new data available (no CRC) */
        {
            /* Compute interpolation factor, since the division only works *
             * for values of since_last_sid < 32 we have to limit the      *
             * interpolation to 32 frames                                  */
            tmp_int_length = st->since_last_sid;
            st->since_last_sid = 0;

            if (tmp_int_length >= 32)
            {
                tmp_int_length = 32;
            }

            L_temp = ((Word32) tmp_int_length) << 10;
            if (L_temp != (Word32)((Word16) L_temp))
            {
                *pOverflow = 1;
                L_temp = (Word32)((tmp_int_length > 0) ? MAX_16 : MIN_16);
            }
            temp = (Word16) L_temp;

            if (tmp_int_length >= 2)
            {
                st->true_sid_period_inv = div_s(1 << 10, temp);
            }
            else
            {
                st->true_sid_period_inv = 1 << 14; /* 0.5 it Q15 */
            }

            Init_D_plsf_3(lsfState, parm[0]);
            D_plsf_3(lsfState, MRDTX, 0, &parm[1], st->lsp, pOverflow);
            Set_zero(lsfState->past_r_q, M);   /* reset for next speech frame */

            log_en_index = parm[4];
            /* Q11 and divide by 4 */
            if ((log_en_index > 63) || (log_en_index < -64))
            {
                st->log_en = (log_en_index > 0) ? MAX_16 : MIN_16;
            }
            else
            {
                st->log_en = (log_en_index) << (11 - 2);
            }

            /* Subtract 2.5 in Q11 */
            st->log_en = sub(st->log_en, (2560 * 2), pOverflow);

            /* Index 0 is reserved for silence */
            if (log_en_index == 0)
            {
                st->log_en = MIN_16;
            }

            /* no interpolation at startup after coder reset        */
            /* or when SID_UPD has been received right after SPEECH */

            if ((st->data_updated == 0) ||
                    (st->dtxGlobalState == SPEECH))
            {
                Copy(st->lsp, st->lsp_old, M);
                st->old_log_en = st->log_en;
            }
        } /* endif valid_data */

        /* initialize gain predictor memory of other modes */
        if (st->log_en < 0)
        {
            temp = ~((~st->log_en) >> 1);
        }
        else
        {
            temp = st->log_en >> 1;
        }
        ma_pred_init = sub(temp, 9000, pOverflow);

        if (ma_pred_init > 0)
        {
            ma_pred_init = 0;
        }
        else if (ma_pred_init < -14436)
        {
            ma_pred_init = -14436;
        }

        predState->past_qua_en[0] = ma_pred_init;
        predState->past_qua_en[1] = ma_pred_init;
        predState->past_qua_en[2] = ma_pred_init;
        predState->past_qua_en[3] = ma_pred_init;

        /* past_qua_en for other modes than MR122 */
        ma_pred_init = mult(5443, ma_pred_init, pOverflow);
        /* scale down by factor 20*log10(2) in Q15 */
        predState->past_qua_en_MR122[0] = ma_pred_init;
        predState->past_qua_en_MR122[1] = ma_pred_init;
        predState->past_qua_en_MR122[2] = ma_pred_init;
        predState->past_qua_en_MR122[3] = ma_pred_init;
    } /* endif sid_frame */

    /* CN generation */
    /* recompute level adjustment factor Q11             *
     * st->log_en_adjust = 0.9*st->log_en_adjust +       *
     *                     0.1*dtx_log_en_adjust[mode]); */
    if (dtx_log_en_adjust[mode] > 1023)
    {
        temp = MAX_16;
    }
    else if (dtx_log_en_adjust[mode] < -1024)
    {
        temp = MIN_16;
    }
    else
    {
        temp = mult((Word16)((Word32)dtx_log_en_adjust[mode] << 5), 3277, pOverflow);
    }

    if (temp < 0)
    {
        temp = ~((~temp) >> 5);
    }
    else
    {
        temp >>= 5;
    }
    st->log_en_adjust = add(mult(st->log_en_adjust, 29491, pOverflow), temp, pOverflow);

    /* Interpolate SID info */
    int_fac = shl(add(1, st->since_last_sid, pOverflow), 10, pOverflow); /* Q10 */
    int_fac = mult(int_fac, st->true_sid_period_inv, pOverflow); /* Q10 * Q15 -> Q10 */

    /* Maximize to 1.0 in Q10 */
    if (int_fac > 1024)
    {
        int_fac = 16384;
    }
    else if (int_fac < -2048)
    {
        int_fac = MIN_16;
    }
    else
    {
        int_fac <<= 4;      /* Q10 -> Q14 */
    }

    L_log_en_int = L_mult(int_fac, st->log_en, pOverflow); /* Q14 * Q11->Q26 */
    for (i = M - 1; i >= 0; i--)
    {
        lsp_int[i] = mult(int_fac, st->lsp[i], pOverflow);/* Q14 * Q15 -> Q14 */
    }

    int_fac = sub(16384, int_fac, pOverflow); /* 1-k in Q14 */

    /* (Q14 * Q11 -> Q26) + Q26 -> Q26 */
    L_log_en_int = L_mac(L_log_en_int, int_fac, st->old_log_en, pOverflow);
    for (i = M - 1; i >= 0; i--)
    {
        /* Q14 + (Q14 * Q15 -> Q14) -> Q14 */
        lsp_int[i] = add(lsp_int[i], mult(int_fac, st->lsp_old[i], pOverflow), pOverflow);

        L_temp = ((Word32) lsp_int[i]) << 1;    /* Q14 -> Q15 */
        if (L_temp != (Word32)((Word16) L_temp))
        {
            *pOverflow = 1;
            L_temp = (Word32)((lsp_int[i] > 0) ? MAX_16 : MIN_16);
        }
        lsp_int[i] = (Word16) L_temp;
    }

    /* compute the amount of lsf variability */
    lsf_variab_factor = sub(st->log_pg_mean, 2457, pOverflow); /* -0.6 in Q12 */
    /* *0.3 Q12*Q15 -> Q12 */
    lsf_variab_factor = sub(4096, mult(lsf_variab_factor, 9830, pOverflow), pOverflow);

    /* limit to values between 0..1 in Q12 */
    if (lsf_variab_factor > 4095)
    {
        lsf_variab_factor = MAX_16;
    }
    else if (lsf_variab_factor < 0)
    {
        lsf_variab_factor = 0;
    }
    else
    {
        lsf_variab_factor <<= 3; /* -> Q15 */
    }

    /* get index of vector to do variability with */
    lsf_variab_index = pseudonoise(&st->L_pn_seed_rx, 3);

    /* convert to lsf */
    Lsp_lsf(lsp_int, lsf_int, M, pOverflow);

    /* apply lsf variability */
    Copy(lsf_int, lsf_int_variab, M);
    for (i = M - 1; i >= 0; i--)
    {
        lsf_int_variab[i] = add(lsf_int_variab[i],
                                mult(lsf_variab_factor,
                                     st->lsf_hist_mean[i+lsf_variab_index*M], pOverflow)
                                , pOverflow);
    }

    /* make sure that LSP's are ordered */
    Reorder_lsf(lsf_int, LSF_GAP, M, pOverflow);
    Reorder_lsf(lsf_int_variab, LSF_GAP, M, pOverflow);

    /* copy lsf to speech decoders lsf state */
    Copy(lsf_int, lsfState->past_lsf_q, M);

    /* convert to lsp */
    Lsf_lsp(lsf_int, lsp_int, M, pOverflow);
    Lsf_lsp(lsf_int_variab, lsp_int_variab, M, pOverflow);

    /* Compute acoeffs Q12 acoeff is used for level    *
     * normalization and postfilter, acoeff_variab is  *
     * used for synthesis filter                       *
     * by doing this we make sure that the level       *
     * in high frequenncies does not jump up and down  */

    Lsp_Az(lsp_int, acoeff, pOverflow);
    Lsp_Az(lsp_int_variab, acoeff_variab, pOverflow);

    /* For use in postfilter */
    Copy(acoeff, &A_t[0],           M + 1);
    Copy(acoeff, &A_t[M + 1],       M + 1);
    Copy(acoeff, &A_t[2 *(M + 1)], M + 1);
    Copy(acoeff, &A_t[3 *(M + 1)], M + 1);

    /* Compute reflection coefficients Q15 */
    A_Refl(&acoeff[1], refl, pOverflow);

    /* Compute prediction error in Q15 */
    pred_err = MAX_16; /* 0.99997 in Q15 */
    for (i = 0; i < M; i++)
    {
        L_temp = (((Word32) refl[i]) * refl[i]) >> 15;
        if (L_temp <= 0x00007fffL)
        {
            temp = MAX_16 - (Word16) L_temp;
        }
        else
        {
            *pOverflow = 1;
            temp = 0;
        }
        pred_err = mult(pred_err, temp, pOverflow);
    }

    /* compute logarithm of prediction gain */
    Log2(L_deposit_l(pred_err), &log_pg_e, &log_pg_m, pOverflow);

    /* convert exponent and mantissa to Word16 Q12 */
    log_pg = shl(sub(log_pg_e, 15, pOverflow), 12, pOverflow); /* Q12 */
    log_pg = shr(sub(0, add(log_pg, shr(log_pg_m, 15 - 12, pOverflow),
                            pOverflow), pOverflow), 1, pOverflow);
    st->log_pg_mean = add(mult(29491, st->log_pg_mean, pOverflow),
                          mult(3277, log_pg, pOverflow), pOverflow);

    /* Compute interpolated log energy */
    L_log_en_int = L_shr(L_log_en_int, 10, pOverflow); /* Q26 -> Q16 */

    /* Add 4 in Q16 */
    L_log_en_int = L_add(L_log_en_int, 4 * 65536L, pOverflow);

    /* subtract prediction gain */
    L_log_en_int = L_sub(L_log_en_int, L_shl(L_deposit_l(log_pg), 4, pOverflow), pOverflow);

    /* adjust level to speech coder mode */
    L_log_en_int = L_add(L_log_en_int,
                         L_shl(L_deposit_l(st->log_en_adjust), 5, pOverflow), pOverflow);

    log_en_int_e = (Word16)(L_log_en_int >> 16);

    log_en_int_m = (Word16)(L_shr(L_sub(L_log_en_int,
                                        L_deposit_h(log_en_int_e), pOverflow), 1, pOverflow));
    level = (Word16)(Pow2(log_en_int_e, log_en_int_m, pOverflow));  /* Q4 */

    for (i = 0; i < 4; i++)
    {
        /* Compute innovation vector */
        build_CN_code(&st->L_pn_seed_rx, ex, pOverflow);
        for (j = L_SUBFR - 1; j >= 0; j--)
        {
            ex[j] = mult(level, ex[j], pOverflow);
        }
        /* Synthesize */
        Syn_filt(acoeff_variab, ex, &synth[i * L_SUBFR], L_SUBFR,
                 mem_syn, 1);

    } /* next i */

    /* reset codebook averaging variables */
    averState->hangVar = 20;
    averState->hangCount = 0;

    if (new_state == DTX_MUTE)
    {
        /* mute comfort noise as it has been quite a long time since
         * last SID update  was performed                            */

        tmp_int_length = st->since_last_sid;

        if (tmp_int_length > 32)
        {
            tmp_int_length = 32;
        }
        else if (tmp_int_length <= 0)
        {
            /* safety guard against division by zero */
            tmp_int_length = 8;
        }

        L_temp = ((Word32) tmp_int_length) << 10;
        if (L_temp != (Word32)((Word16) L_temp))
        {
            *pOverflow = 1;
            L_temp = (Word32)((tmp_int_length > 0) ? MAX_16 : MIN_16);
        }
        temp = (Word16) L_temp;

        st->true_sid_period_inv = div_s(1 << 10, temp);

        st->since_last_sid = 0;
        Copy(st->lsp, st->lsp_old, M);
        st->old_log_en = st->log_en;
        /* subtract 1/8 in Q11 i.e -6/8 dB */
        st->log_en = sub(st->log_en, 256, pOverflow);
    }

    /* reset interpolation length timer
     * if data has been updated.        */
    if ((st->sid_frame != 0) &&
            ((st->valid_data != 0) ||
             ((st->valid_data == 0) && (st->dtxHangoverAdded) != 0)))
    {
        st->since_last_sid =  0;
        st->data_updated = 1;
    }

    return;
}


/****************************************************************************/

/*
------------------------------------------------------------------------------
 FUNCTION NAME: dtx_dec_activity_update
------------------------------------------------------------------------------
 INPUT AND OUTPUT DEFINITIONS

 Inputs:
    st = pointer to a structure of type dtx_decState
    lsf =
        frame =

 Outputs:
    st points to an updated structure of type dtx_decState

 Returns:
    None.

 Global Variables Used:
    None.

 Local Variables Needed:
    None.

------------------------------------------------------------------------------
 FUNCTION DESCRIPTION

 This function updates the DTX parameters.

------------------------------------------------------------------------------
 REQUIREMENTS

 None

------------------------------------------------------------------------------
 REFERENCES

 dtx_dec.c, UMTS GSM AMR speech codec, R99 - Version 3.3.0, December 12, 2001

------------------------------------------------------------------------------
 PSEUDO-CODE

void dtx_dec_activity_update(dtx_decState *st,
                             Word16 lsf[],
                             Word16 frame[])
{
   Word16 i;

   Word32 L_frame_en;
   Word16 log_en_e, log_en_m, log_en;

   // update lsp history
   st->lsf_hist_ptr = add(st->lsf_hist_ptr,M);
   if (sub(st->lsf_hist_ptr, 80) == 0)
   {
      st->lsf_hist_ptr = 0;
   }
   Copy(lsf, &st->lsf_hist[st->lsf_hist_ptr], M);

   // compute log energy based on frame energy
   L_frame_en = 0;     // Q0
   for (i=0; i < L_FRAME; i++)
   {
      L_frame_en = L_mac(L_frame_en, frame[i], frame[i]);
   }
   Log2(L_frame_en, &log_en_e, &log_en_m);

   // convert exponent and mantissa to Word16 Q10
   log_en = shl(log_en_e, 10);  // Q10
   log_en = add(log_en, shr(log_en_m, 15-10));

   // divide with L_FRAME i.e subtract with log2(L_FRAME) = 7.32193
   log_en = sub(log_en, 7497+1024);

   // insert into log energy buffer, no division by two as  *
    * log_en in decoder is Q11
   st->log_en_hist_ptr = add(st->log_en_hist_ptr, 1);
   if (sub(st->log_en_hist_ptr, DTX_HIST_SIZE) == 0)
   {
      st->log_en_hist_ptr = 0;
   }
   st->log_en_hist[st->log_en_hist_ptr] = log_en; // Q11
}

------------------------------------------------------------------------------
 RESOURCES USED [optional]

 When the code is written for a specific target processor the
 the resources used should be documented below.

 HEAP MEMORY USED: x bytes

 STACK MEMORY USED: x bytes

 CLOCK CYCLES: (cycle count equation for this function) + (variable
                used to represent cycle count for each subroutine
                called)
     where: (cycle count variable) = cycle count for [subroutine
                                     name]

------------------------------------------------------------------------------
 CAUTION [optional]
 [State any special notes, constraints or cautions for users of this function]

------------------------------------------------------------------------------
*/

void dtx_dec_activity_update(dtx_decState *st,
                             Word16 lsf[],
                             Word16 frame[],
                             Flag   *pOverflow)
{
    Word16 i;

    Word32 L_frame_en;
    Word32 L_temp;
    Word16 log_en_e;
    Word16 log_en_m;
    Word16 log_en;

    /* update lsp history */
    st->lsf_hist_ptr += M;

    if (st->lsf_hist_ptr == 80)
    {
        st->lsf_hist_ptr = 0;
    }
    Copy(lsf, &st->lsf_hist[st->lsf_hist_ptr], M);

    /* compute log energy based on frame energy */
    L_frame_en = 0;     /* Q0 */
    for (i = L_FRAME - 1; i >= 0; i--)
    {
        L_temp = ((Word32) frame[i]) * frame[i];
        if (L_temp != (Word32) 0x40000000L)
        {
            L_temp = L_temp << 1;
        }
        else
        {
            L_temp = MAX_32;
        }
        L_frame_en = L_add(L_frame_en, L_temp, pOverflow);
    }
    Log2(L_frame_en, &log_en_e, &log_en_m, pOverflow);

    /* convert exponent and mantissa to Word16 Q10 */
    L_temp = ((Word32) log_en_e) << 10;

    if (L_temp != (Word32)((Word16) L_temp))
    {
        *pOverflow = 1;
        L_temp = (Word32)((log_en_e > 0) ? MAX_16 : MIN_16);
    }
    log_en_e = (Word16) L_temp;

    if (log_en_m < 0)
    {
        log_en_m = ~((~log_en_m) >> 5);
    }
    else
    {
        log_en_m >>= 5;
    }
    log_en = add(log_en_e, log_en_m, pOverflow);

    /* divide with L_FRAME i.e subtract with log2(L_FRAME) = 7.32193 */
    log_en = sub(log_en, 7497 + 1024, pOverflow);

    /* insert into log energy buffer, no division by two as  *
    * log_en in decoder is Q11                              */
    st->log_en_hist_ptr += 1;

    if (st->log_en_hist_ptr == DTX_HIST_SIZE)
    {
        st->log_en_hist_ptr = 0;
    }
    st->log_en_hist[st->log_en_hist_ptr] = log_en; /* Q11 */

    return;
}

/****************************************************************************/

/*
------------------------------------------------------------------------------
 FUNCTION NAME: rx_dtx_handler
------------------------------------------------------------------------------
 INPUT AND OUTPUT DEFINITIONS

 Inputs:
    st = pointer to a structure of type dtx_decState
    frame_type = RX frame type

 Returns:
    newState = variable of type DTXStateType

 Outputs:
    st points to an updated structure of type dtx_decState

 Global Variables Used:
    None.

 Local Variables Needed:
    None.

------------------------------------------------------------------------------
 FUNCTION DESCRIPTION

 This function determines the new state of the decoder based on the frame_type
 and sets up the decoder parameters according to newState.

 Table of new SPD synthesis states

                           |     previous SPD_synthesis_state
     Incoming              |
     frame_type            | SPEECH       | DTX           | DTX_MUTE
     ---------------------------------------------------------------
     RX_SPEECH_GOOD ,      |              |               |
     RX_SPEECH_PR_DEGRADED | SPEECH       | SPEECH        | SPEECH
     ----------------------------------------------------------------
     RX_SPEECH_PR_BAD,     |              |               |
     RX_SPEECH_BAD,        | SPEECH       | DTX           | DTX_MUTE
     ----------------------------------------------------------------
     RX_SID_FIRST,         | DTX          | DTX/(DTX_MUTE)| DTX_MUTE
     ----------------------------------------------------------------
     RX_SID_UPDATE,        | DTX          | DTX           | DTX
     ----------------------------------------------------------------
     RX_SID_BAD,           | DTX          | DTX/(DTX_MUTE)| DTX_MUTE
     ----------------------------------------------------------------
     RX_NO_DATA            | SPEECH       | DTX/(DTX_MUTE)| DTX_MUTE
                           |(class2 garb.)|               |
     ----------------------------------------------------------------
     RX_ONSET              | SPEECH       | DTX/(DTX_MUTE)| DTX_MUTE
                           |(class2 garb.)|               |
     ----------------------------------------------------------------

------------------------------------------------------------------------------
 REQUIREMENTS

 None

------------------------------------------------------------------------------
 REFERENCES

 dtx_dec.c, UMTS GSM AMR speech codec, R99 - Version 3.3.0, December 12, 2001

------------------------------------------------------------------------------
 PSEUDO-CODE

enum DTXStateType rx_dtx_handler(
                      dtx_decState *st,           // i/o : State struct
                      enum RXFrameType frame_type // i   : Frame type
                      )
{
   enum DTXStateType newState;
   enum DTXStateType encState;

   // DTX if SID frame or previously in DTX{_MUTE} and (NO_RX OR BAD_SPEECH)
   if ((sub(frame_type, RX_SID_FIRST) == 0)   ||
       (sub(frame_type, RX_SID_UPDATE) == 0)  ||
       (sub(frame_type, RX_SID_BAD) == 0)     ||
       (((sub(st->dtxGlobalState, DTX) == 0) ||
         (sub(st->dtxGlobalState, DTX_MUTE) == 0)) &&
        ((sub(frame_type, RX_NO_DATA) == 0) ||
         (sub(frame_type, RX_SPEECH_BAD) == 0) ||
         (sub(frame_type, RX_ONSET) == 0))))
   {
      newState = DTX;

      // stay in mute for these input types
      if ((sub(st->dtxGlobalState, DTX_MUTE) == 0) &&
          ((sub(frame_type, RX_SID_BAD) == 0) ||
           (sub(frame_type, RX_SID_FIRST) ==  0) ||
           (sub(frame_type, RX_ONSET) ==  0) ||
           (sub(frame_type, RX_NO_DATA) == 0)))
      {
         newState = DTX_MUTE;
      }

      // evaluate if noise parameters are too old
      // since_last_sid is reset when CN parameters have been updated
      st->since_last_sid = add(st->since_last_sid, 1);

      // no update of sid parameters in DTX for a long while
      // Due to the delayed update of  st->since_last_sid counter
      // SID_UPDATE frames need to be handled separately to avoid
      // entering DTX_MUTE for late SID_UPDATE frames
      if((sub(frame_type, RX_SID_UPDATE) != 0) &&
         (sub(st->since_last_sid, DTX_MAX_EMPTY_THRESH) > 0))
      {
         newState = DTX_MUTE;
      }
   }
   else
   {
      newState = SPEECH;
      st->since_last_sid = 0;
   }

    // reset the decAnaElapsed Counter when receiving CNI data the first
    // time, to robustify counter missmatch after handover
    // this might delay the bwd CNI analysis in the new decoder slightly.

   if ((st->data_updated == 0) &&
       (sub(frame_type, RX_SID_UPDATE) == 0))
   {
      st->decAnaElapsedCount = 0;
   }

   // update the SPE-SPD DTX hangover synchronization
   // to know when SPE has added dtx hangover
   st->decAnaElapsedCount = add(st->decAnaElapsedCount, 1);
   st->dtxHangoverAdded = 0;

   if ((sub(frame_type, RX_SID_FIRST) == 0)  ||
       (sub(frame_type, RX_SID_UPDATE) == 0) ||
       (sub(frame_type, RX_SID_BAD) == 0)    ||
       (sub(frame_type, RX_ONSET) == 0)      ||
       (sub(frame_type, RX_NO_DATA) == 0))
   {
      encState = DTX;

      // In frame errors simulations RX_NO_DATA may occasionally mean that
      // a speech packet was probably sent by the encoder,
      // the assumed _encoder_ state should be SPEECH in such cases.
      if((sub(frame_type, RX_NO_DATA) == 0) &&
         (sub(newState, SPEECH) == 0))
      {
         encState = SPEECH;
      }

      // Note on RX_ONSET operation differing from RX_NO_DATA operation:
      // If a  RX_ONSET is received in the decoder (by "accident")
      // it is still most likely that the encoder  state
      // for the "ONSET frame" was DTX.

   }
   else
   {
      encState = SPEECH;
   }

   if (sub(encState, SPEECH) == 0)
   {
      st->dtxHangoverCount = DTX_HANG_CONST;
   }
   else
   {
      if (sub(st->decAnaElapsedCount, DTX_ELAPSED_FRAMES_THRESH) > 0)
      {
         st->dtxHangoverAdded = 1;
         st->decAnaElapsedCount = 0;
         st->dtxHangoverCount = 0;
      }
      else if (st->dtxHangoverCount == 0)
      {
         st->decAnaElapsedCount = 0;
      }
      else
      {
         st->dtxHangoverCount = sub(st->dtxHangoverCount, 1);
      }
   }

   if (sub(newState, SPEECH) != 0)
   {
      // DTX or DTX_MUTE
      // CN data is not in a first SID, first SIDs are marked as SID_BAD
      //  but will do backwards analysis if a hangover period has been added
      // according to the state machine above

      st->sid_frame = 0;
      st->valid_data = 0;

      if (sub(frame_type, RX_SID_FIRST) == 0)
      {
         st->sid_frame = 1;
      }
      else if (sub(frame_type, RX_SID_UPDATE) == 0)
      {
         st->sid_frame = 1;
         st->valid_data = 1;
      }
      else if (sub(frame_type, RX_SID_BAD) == 0)
      {
         st->sid_frame = 1;
         st->dtxHangoverAdded = 0; // use old data
      }
   }

   return newState;
   // newState is used by both SPEECH AND DTX synthesis routines
}

------------------------------------------------------------------------------
 RESOURCES USED [optional]

 When the code is written for a specific target processor the
 the resources used should be documented below.

 HEAP MEMORY USED: x bytes

 STACK MEMORY USED: x bytes

 CLOCK CYCLES: (cycle count equation for this function) + (variable
                used to represent cycle count for each subroutine
                called)
     where: (cycle count variable) = cycle count for [subroutine
                                     name]

------------------------------------------------------------------------------
 CAUTION [optional]
 [State any special notes, constraints or cautions for users of this function]

------------------------------------------------------------------------------
*/

enum DTXStateType rx_dtx_handler(
    dtx_decState *st,           /* i/o : State struct     */
    enum RXFrameType frame_type,/* i   : Frame type       */
    Flag *pOverflow)
{
    enum DTXStateType newState;
    enum DTXStateType encState;


    /* DTX if SID frame or previously in DTX{_MUTE} and (NO_RX OR BAD_SPEECH) */

    if ((frame_type == RX_SID_FIRST)   ||
            (frame_type == RX_SID_UPDATE)  ||
            (frame_type == RX_SID_BAD)     ||
            (((st->dtxGlobalState == DTX) || (st->dtxGlobalState == DTX_MUTE)) &&
             ((frame_type == RX_NO_DATA) || (frame_type == RX_SPEECH_BAD) ||
              (frame_type == RX_ONSET))))
    {
        newState = DTX;

        /* stay in mute for these input types */

        if ((st->dtxGlobalState == DTX_MUTE) &&
                ((frame_type == RX_SID_BAD) ||
                 (frame_type == RX_SID_FIRST) ||
                 (frame_type == RX_ONSET) ||
                 (frame_type == RX_NO_DATA)))
        {
            newState = DTX_MUTE;
        }

        /* evaluate if noise parameters are too old                     */
        /* since_last_sid is reset when CN parameters have been updated */
        st->since_last_sid = add(st->since_last_sid, 1, pOverflow);

        /* no update of sid parameters in DTX for a long while      */
        /* Due to the delayed update of  st->since_last_sid counter */
        /* SID_UPDATE frames need to be handled separately to avoid */
        /* entering DTX_MUTE for late SID_UPDATE frames             */
        if ((frame_type != RX_SID_UPDATE) &&
                (st->since_last_sid > DTX_MAX_EMPTY_THRESH))
        {
            newState = DTX_MUTE;
        }
    }
    else
    {
        newState = SPEECH;
        st->since_last_sid = 0;
    }

    /*
    reset the decAnaElapsed Counter when receiving CNI data the first
    time, to robustify counter missmatch after handover
    this might delay the bwd CNI analysis in the new decoder slightly.
    */

    if ((st->data_updated == 0) &&
            (frame_type == RX_SID_UPDATE))
    {
        st->decAnaElapsedCount = 0;
    }

    /* update the SPE-SPD DTX hangover synchronization */
    /* to know when SPE has added dtx hangover         */
    st->decAnaElapsedCount = add(st->decAnaElapsedCount, 1, pOverflow);
    st->dtxHangoverAdded = 0;

    if ((frame_type == RX_SID_FIRST)  ||
            (frame_type == RX_SID_UPDATE) ||
            (frame_type == RX_SID_BAD)    ||
            (frame_type == RX_ONSET) ||
            (frame_type == RX_NO_DATA))
    {
        encState = DTX;

        /*
         In frame errors simulations RX_NO_DATA may occasionally mean that
         a speech packet was probably sent by the encoder,
         the assumed _encoder_ state should be SPEECH in such cases.
        */
        if ((frame_type == RX_NO_DATA) &&
                (newState == SPEECH))
        {
            encState = SPEECH;
        }

        /*
         Note on RX_ONSET operation differing from RX_NO_DATA operation:
         If a  RX_ONSET is received in the decoder (by "accident")
         it is still most likely that the encoder  state
         for the "ONSET frame" was DTX.
        */
    }
    else
    {
        encState = SPEECH;
    }


    if (encState == SPEECH)
    {
        st->dtxHangoverCount = DTX_HANG_CONST;
    }
    else
    {

        if (st->decAnaElapsedCount > DTX_ELAPSED_FRAMES_THRESH)
        {
            st->dtxHangoverAdded = 1;
            st->decAnaElapsedCount = 0;
            st->dtxHangoverCount = 0;
        }
        else if (st->dtxHangoverCount == 0)
        {
            st->decAnaElapsedCount = 0;
        }
        else
        {
            st->dtxHangoverCount -= 1;
        }
    }

    if (newState != SPEECH)
    {
        /* DTX or DTX_MUTE
         * CN data is not in a first SID, first SIDs are marked as SID_BAD
         *  but will do backwards analysis if a hangover period has been added
         *  according to the state machine above
        */

        st->sid_frame = 0;
        st->valid_data = 0;

        if (frame_type == RX_SID_FIRST)
        {
            st->sid_frame = 1;
        }
        else if (frame_type == RX_SID_UPDATE)
        {
            st->sid_frame = 1;
            st->valid_data = 1;
        }
        else if (frame_type == RX_SID_BAD)
        {
            st->sid_frame = 1;
            st->dtxHangoverAdded = 0; /* use old data */
        }
    }

    /* newState is used by both SPEECH AND DTX synthesis routines */
    return(newState);
}
