FreeCalypso > hg > gsm-codec-lib
view libgsmefr/dtx_dec.c @ 467:ad032051166a
doc: AMR-EFR-hybrid-emu new article
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sun, 12 May 2024 23:54:43 +0000 |
parents | 17f690749099 |
children |
line wrap: on
line source
/* * 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 ((SID_flag == 2) && (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 (frame_type == VALID_SID_FRAME) { st->rxdtx_ctrl = RX_FIRST_SID_UPDATE; } else if (frame_type == INVALID_SID_FRAME) { st->rxdtx_ctrl = RX_FIRST_SID_UPDATE | RX_INVALID_SID_FRAME; } else if (frame_type == UNUSABLE_FRAME) { st->rxdtx_ctrl = RX_SP_FLAG; } else if (frame_type == GOOD_SPEECH_FRAME) { st->rxdtx_ctrl = RX_SP_FLAG; } } else { if (frame_type == VALID_SID_FRAME) { st->rxdtx_ctrl = RX_CONT_SID_UPDATE; } else if (frame_type == INVALID_SID_FRAME) { st->rxdtx_ctrl = RX_CONT_SID_UPDATE | RX_INVALID_SID_FRAME; } else if (frame_type == UNUSABLE_FRAME) { st->rxdtx_ctrl = RX_CNI_BFI; } else if (frame_type == GOOD_SPEECH_FRAME) { /* 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 (frame_type == VALID_SID_FRAME) { st->rx_dtx_state = 0; } else if (frame_type == INVALID_SID_FRAME) { if (st->rx_dtx_state < (CN_INT_PERIOD - 1)) { st->rx_dtx_state++; } } } /* Bad frame received in CNI mode */ if ((st->rxdtx_ctrl & RX_CNI_BFI) != 0) { if (st->rx_dtx_state < (CN_INT_PERIOD - 1)) { st->rx_dtx_state++; } /* If an unusable frame is received during CNI period when TAF == 1, the frame is classified as a lost SID frame */ if (TAF) { 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 (st->prev_SID_frames_lost > 1) { 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 (st->rxdtx_N_elapsed > DTX_ELAPSED_THRESHOLD) { 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--; } } 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 (st->buf_p_rx == (4 * DTX_HANGOVER - 1)) { st->buf_p_rx = 0; } else { st->buf_p_rx++; } 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; }