FreeCalypso > hg > gsm-codec-lib
view libgsmefr/dtx_common.c @ 537:f9eefb61fb2f
frtest: new program gsmfr-decode-tw5
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sat, 21 Sep 2024 23:31:25 +0000 |
parents | 7bc011aceb7f |
children |
line wrap: on
line source
/* * This file is a product of splitting ETSI EFR dtx.c into parts; * the present module is the common part for both the encoder and * the decoder. */ #include "gsm_efr.h" #include "typedef.h" #include "namespace.h" #include "basic_op.h" #include "cnst.h" #include "sig_proc.h" #include "memops.h" #include "no_count.h" #include "dtx.h" #include "dtx_defs.h" /************************************************************************* * * FUNCTION NAME: update_lsf_history * * PURPOSE: Update the LSF parameter history. The LSF parameters kept * in the buffer are used later for computing the reference * LSF parameter vector and the averaged LSF parameter vector. * * INPUTS: lsf1[0..9] LSF vector of the 1st half of the frame * lsf2[0..9] LSF vector of the 2nd half of the frame * lsf_old[0..DTX_HANGOVER-1][0..M-1] * Old LSF history * * OUTPUTS: lsf_old[0..DTX_HANGOVER-1][0..M-1] * Updated LSF history * * RETURN VALUE: none * *************************************************************************/ void update_lsf_history ( Word16 lsf1[M], Word16 lsf2[M], Word16 lsf_old[DTX_HANGOVER][M] ) { Word16 i, j, temp; /* shift LSF data to make room for LSFs from current frame */ /* This can also be implemented by using circular buffering */ for (i = DTX_HANGOVER - 1; i > 0; i--) { for (j = 0; j < M; j++) { lsf_old[i][j] = lsf_old[i - 1][j]; move16 (); } } /* Store new LSF data to lsf_old buffer */ for (i = 0; i < M; i++) { temp = add (shr (lsf1[i], 1), shr (lsf2[i], 1)); lsf_old[0][i] = temp; move16 (); } return; } /************************************************************************* * * FUNCTION NAME: update_lsf_p_CN * * PURPOSE: Update the reference LSF parameter vector. The reference * vector is computed by averaging the quantized LSF parameter * vectors which exist in the LSF parameter history. * * INPUTS: lsf_old[0..DTX_HANGOVER-1][0..M-1] * LSF parameter history * * OUTPUTS: lsf_p_CN[0..9] Computed reference LSF parameter vector * * RETURN VALUE: none * *************************************************************************/ void update_lsf_p_CN ( Word16 lsf_old[DTX_HANGOVER][M], Word16 lsf_p_CN[M] ) { Word16 i, j; Word32 L_temp; for (j = 0; j < M; j++) { L_temp = L_mult (INV_DTX_HANGOVER, lsf_old[0][j]); for (i = 1; i < DTX_HANGOVER; i++) { L_temp = L_mac (L_temp, INV_DTX_HANGOVER, lsf_old[i][j]); } lsf_p_CN[j] = round (L_temp); move16 (); } return; } /************************************************************************* * * FUNCTION NAME: update_gcode0_CN * * PURPOSE: Update the reference fixed codebook gain parameter value. * The reference value is computed by averaging the quantized * fixed codebook gain parameter values which exist in the * fixed codebook gain parameter history. * * INPUTS: gain_code_old[0..4*DTX_HANGOVER-1] * fixed codebook gain parameter history * * OUTPUTS: none * * RETURN VALUE: Computed reference fixed codebook gain * *************************************************************************/ Word16 update_gcode0_CN ( Word16 gain_code_old[4 * DTX_HANGOVER] ) { Word16 i, j; Word32 L_temp, L_ret; L_ret = 0L; move32 (); for (i = 0; i < DTX_HANGOVER; i++) { L_temp = L_mult (0x1fff, gain_code_old[4 * i]); for (j = 1; j < 4; j++) { L_temp = L_mac (L_temp, 0x1fff, gain_code_old[4 * i + j]); } L_ret = L_mac (L_ret, INV_DTX_HANGOVER, extract_h (L_temp)); } return extract_h (L_ret); } /************************************************************************* * * FUNCTION NAME: build_CN_code * * PURPOSE: Compute the comfort noise fixed codebook excitation. The * gains of the pulses are always +/-1. * * INPUTS: *seed Old CN generator shift register state * * OUTPUTS: cod[0..39] Generated comfort noise fixed codebook vector * *seed Updated CN generator shift register state * * RETURN VALUE: none * *************************************************************************/ void build_CN_code ( Word16 cod[], Word32 *seed ) { Word16 i, j, k; for (i = 0; i < L_SUBFR; i++) { cod[i] = 0; move16 (); } for (k = 0; k < NB_PULSE; k++) { i = pseudonoise (seed, 2); /* generate pulse position */ i *= 10; i += k; j = pseudonoise (seed, 1); /* generate sign */ test (); if (j > 0) { cod[i] = 4096; move16 (); } else { cod[i] = -4096; move16 (); } } return; } /************************************************************************* * * FUNCTION NAME: pseudonoise * * PURPOSE: Generate a random integer value to use in comfort noise * generation. The algorithm uses polynomial x^31 + x^3 + 1 * (length of PN sequence is 2^31 - 1). * * INPUTS: *shift_reg Old CN generator shift register state * * * OUTPUTS: *shift_reg Updated CN generator shift register state * * RETURN VALUE: Generated random integer value * *************************************************************************/ Word16 pseudonoise ( Word32 *shift_reg, Word16 no_bits ) { Word16 noise_bits, Sn, i; noise_bits = 0; move16 (); for (i = 0; i < no_bits; i++) { /* State n == 31 */ test (); logic32 (); if ((*shift_reg & 0x00000001L) != 0) { Sn = 1; move16 (); } else { Sn = 0; move16 (); } /* State n == 3 */ test (); logic32 (); if ((*shift_reg & 0x10000000L) != 0) { Sn = Sn ^ 1; logic16 (); } else { Sn = Sn ^ 0; logic16 (); } noise_bits <<= 1; noise_bits |= *shift_reg & 1; *shift_reg = L_shr (*shift_reg, 1); move32 (); if (Sn & 1) { *shift_reg = *shift_reg | 0x40000000L; move32 (); logic32 (); } } return noise_bits; }