FreeCalypso > hg > gsm-codec-lib
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; +}