# HG changeset patch # User Mychaela Falconia # Date 1670639120 0 # Node ID c1d53064b410f3b69283aa14eec0d25b84648062 # Parent cc08498ed21bf37ac3b2ce745650dac30a2f9904 libgsmefr: split dtx.c into dtx_{common,dec,enc}.c diff -r cc08498ed21b -r c1d53064b410 libgsmefr/Makefile --- a/libgsmefr/Makefile Sat Dec 10 01:28:05 2022 +0000 +++ b/libgsmefr/Makefile Sat Dec 10 02:25:20 2022 +0000 @@ -2,16 +2,17 @@ CFLAGS= -O2 OBJS= agc.o autocorr.o az_lsp.o basicop2.o bfi_nodata.o c1035pf.o cod_12k2.o \ convolve.o d1035pf.o d_gains.o d_homing.o d_plsf_5.o dec_12k2.o \ - dec_create.o dec_lag6.o dec_main.o dec_wrap.o dtx.o e_homing.o \ - enc_create.o enc_lag6.o enc_main.o enc_wrap.o frame2params.o g_code.o \ - g_pitch.o int_lpc.o inter_6.o inv_sqrt.o lag_wind.o levinson.o log2.o \ - lsp_az.o lsp_lsf.o oper_32b.o params2frame.o pitch_f6.o pitch_ol.o \ - pow2.o pre_proc.o pred_lt6.o preemph.o pstfilt2.o q_gains.o \ - q_plsf5_tab.o q_plsf_5.o reorder.o residu.o sid_class.o sid_insert.o \ - syn_filt.o tls_flags.o vad.o weight_a.o -HDRS= basic_op.h cnst.h codec.h d_homing.h dec_state.h dtx.h e_homing.h \ - enc_state.h gains_tb.h gsm_efr.h memops.h namespace.h no_count.h \ - oper_32b.h q_plsf5_tab.h sig_proc.h typedef.h vad.h + dec_create.o dec_lag6.o dec_main.o dec_wrap.o dtx_common.o dtx_dec.o \ + dtx_enc.o e_homing.o enc_create.o enc_lag6.o enc_main.o enc_wrap.o \ + frame2params.o g_code.o g_pitch.o int_lpc.o inter_6.o inv_sqrt.o \ + lag_wind.o levinson.o log2.o lsp_az.o lsp_lsf.o oper_32b.o \ + params2frame.o pitch_f6.o pitch_ol.o pow2.o pre_proc.o pred_lt6.o \ + preemph.o pstfilt2.o q_gains.o q_plsf5_tab.o q_plsf_5.o reorder.o \ + residu.o sid_class.o sid_insert.o syn_filt.o tls_flags.o vad.o \ + weight_a.o +HDRS= basic_op.h cnst.h codec.h d_homing.h dec_state.h dtx.h dtx_defs.h \ + e_homing.h enc_state.h gains_tb.h gsm_efr.h memops.h namespace.h \ + no_count.h oper_32b.h q_plsf5_tab.h sig_proc.h typedef.h vad.h LIB= libgsmefr.a INSTALL_PREFIX= /usr/local diff -r cc08498ed21b -r c1d53064b410 libgsmefr/dtx.c --- a/libgsmefr/dtx.c Sat Dec 10 01:28:05 2022 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1131 +0,0 @@ -/*************************************************************************** - * - * File Name: dtx.c - * - * Purpose: Contains functions for performing DTX operation and comfort - * noise generation. - * - * Below is a listing of all the functions appearing in the file. - * The functions are arranged according to their purpose. Under - * each heading, the ordering is hierarchical. - * - * Resetting of static variables of TX DTX: - * reset_tx_dtx() - * Resetting of static variables of RX DTX: - * reset_rx_dtx() - * - * TX DTX handler (called by the speech encoder): - * tx_dtx() - * RX DTX handler (called by the speech decoder): - * rx_dtx() - * Encoding of comfort noise parameters into SID frame: - * CN_encoding() - * Encoding of SID codeword into SID frame: - * sid_codeword_encoding() - * Detecting of SID codeword from a frame: - * sid_frame_detection() - * Update the LSF parameter history: - * update_lsf_history() - * Update the reference LSF parameter vector: - * update_lsf_p_CN() - * Compute the averaged LSF parameter vector: - * aver_lsf_history() - * Update the fixed codebook gain parameter history of the encoder: - * update_gain_code_history_tx() - * Update the fixed codebook gain parameter history of the decoder: - * update_gain_code_history_rx() - * Compute the unquantized fixed codebook gain: - * compute_CN_excitation_gain() - * Update the reference fixed codebook gain: - * update_gcode0_CN() - * Compute the averaged fixed codebook gain: - * aver_gain_code_history() - * Compute the comfort noise fixed codebook excitation: - * build_CN_code() - * Generate a random integer value: - * pseudonoise() - * Interpolate a comfort noise parameter value over the comfort noise - * update period: - * interpolate_CN_param() - * Interpolate comfort noise LSF pparameter values over the comfort - * noise update period: - * interpolate_CN_lsf() - * interpolate_CN_param() - * - **************************************************************************/ - -#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 "enc_state.h" -#include "dec_state.h" - -/* Inverse values of DTX hangover period and DTX hangover period + 1 */ - -#define INV_DTX_HANGOVER (0x7fff / DTX_HANGOVER) -#define INV_DTX_HANGOVER_P1 (0x7fff / (DTX_HANGOVER+1)) - -#define NB_PULSE 10 /* Number of pulses in fixed codebook excitation */ - -/* Constant DTX_ELAPSED_THRESHOLD is used as threshold for allowing - SID frame updating without hangover period in case when elapsed - time measured from previous SID update is below 24 */ - -#define DTX_ELAPSED_THRESHOLD (24 + DTX_HANGOVER - 1) - -/************************************************************************* - * - * FUNCTION NAME: reset_tx_dtx - * - * PURPOSE: Resets the static variables of the TX DTX handler to their - * initial values - * - *************************************************************************/ - -void reset_tx_dtx (struct EFR_encoder_state *st) -{ - Word16 i; - - /* suppose infinitely long speech period before start */ - - st->txdtx_hangover = DTX_HANGOVER; - st->txdtx_N_elapsed = 0x7fff; - st->txdtx_ctrl = TX_SP_FLAG | TX_VAD_FLAG; - - for (i = 0; i < 6; i++) - { - st->old_CN_mem_tx[i] = 0; - } - - for (i = 0; i < DTX_HANGOVER; i++) - { - st->lsf_old_tx[i][0] = 1384; - st->lsf_old_tx[i][1] = 2077; - st->lsf_old_tx[i][2] = 3420; - st->lsf_old_tx[i][3] = 5108; - st->lsf_old_tx[i][4] = 6742; - st->lsf_old_tx[i][5] = 8122; - st->lsf_old_tx[i][6] = 9863; - st->lsf_old_tx[i][7] = 11092; - st->lsf_old_tx[i][8] = 12714; - st->lsf_old_tx[i][9] = 13701; - } - - for (i = 0; i < 4 * DTX_HANGOVER; i++) - { - st->gain_code_old_tx[i] = 0; - } - - st->L_pn_seed_tx = PN_INITIAL_SEED; - - st->buf_p_tx = 0; - return; -} - -/************************************************************************* - * - * 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: tx_dtx - * - * PURPOSE: DTX handler of the speech encoder. Determines when to add - * the hangover period to the end of the speech burst, and - * also determines when to use old SID parameters, and when - * to update the SID parameters. This function also initializes - * the pseudo noise generator shift register. - * - * Operation of the TX DTX handler is based on the VAD flag - * given as input from the speech encoder. - * - * INPUTS: VAD_flag Voice activity decision - * *txdtx_ctrl Old encoder DTX control word - * - * OUTPUTS: *txdtx_ctrl Updated encoder DTX control word - * L_pn_seed_tx Initialized pseudo noise generator shift - * register (global variable) - * - * RETURN VALUE: none - * - *************************************************************************/ - -void tx_dtx ( - struct EFR_encoder_state *st, - Word16 VAD_flag -) -{ - /* N_elapsed (frames since last SID update) is incremented. If SID - is updated N_elapsed is cleared later in this function */ - - st->txdtx_N_elapsed = add (st->txdtx_N_elapsed, 1); - - /* If voice activity was detected, reset hangover counter */ - - if (sub (VAD_flag, 1) == 0) - { - st->txdtx_hangover = DTX_HANGOVER; - st->txdtx_ctrl = TX_SP_FLAG | TX_VAD_FLAG; - } - else - { - if (st->txdtx_hangover == 0) - { - /* Hangover period is over, SID should be updated */ - - st->txdtx_N_elapsed = 0; - - /* Check if this is the first frame after hangover period */ - if ((st->txdtx_ctrl & TX_HANGOVER_ACTIVE) != 0) - { - st->txdtx_ctrl = TX_PREV_HANGOVER_ACTIVE - | TX_SID_UPDATE; - st->L_pn_seed_tx = PN_INITIAL_SEED; - } - else - { - st->txdtx_ctrl = TX_SID_UPDATE; - } - } - else - { - /* Hangover period is not over, update hangover counter */ - st->txdtx_hangover = sub (st->txdtx_hangover, 1); - - /* Check if elapsed time from last SID update is greater than - threshold. If not, set SP=0 (although hangover period is not - over) and use old SID parameters for new SID frame. - N_elapsed counter must be summed with hangover counter in order - to avoid erroneus SP=1 decision in case when N_elapsed is grown - bigger than threshold and hangover period is still active */ - - if (sub (add (st->txdtx_N_elapsed, st->txdtx_hangover), - DTX_ELAPSED_THRESHOLD) < 0) - { - /* old SID frame should be used */ - st->txdtx_ctrl = TX_USE_OLD_SID; - } - else - { - if ((st->txdtx_ctrl & TX_HANGOVER_ACTIVE) != 0) - { - st->txdtx_ctrl = TX_PREV_HANGOVER_ACTIVE - | TX_HANGOVER_ACTIVE - | TX_SP_FLAG; - } - else - { - st->txdtx_ctrl = TX_HANGOVER_ACTIVE - | TX_SP_FLAG; - } - } - } - } - - 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: CN_encoding - * - * PURPOSE: Encoding of the comfort noise parameters into a SID frame. - * Use old SID parameters if necessary. Set the parameter - * indices not used by comfort noise parameters to zero. - * - * INPUTS: params[0..56] Comfort noise parameter frame from the - * speech encoder - * txdtx_ctrl TX DTX handler control word - * - * OUTPUTS: params[0..56] Comfort noise encoded parameter frame - * - * RETURN VALUE: none - * - *************************************************************************/ - -void CN_encoding ( - struct EFR_encoder_state *st, - Word16 params[], - Word16 txdtx_ctrl -) -{ - Word16 i; - - if ((txdtx_ctrl & TX_SID_UPDATE) != 0) - { - /* Store new CN parameters in memory to be used later as old - CN parameters */ - - /* LPC parameter indices */ - for (i = 0; i < 5; i++) - { - st->old_CN_mem_tx[i] = params[i]; - } - /* Codebook index computed in last subframe */ - st->old_CN_mem_tx[5] = params[56]; - } - if ((txdtx_ctrl & TX_USE_OLD_SID) != 0) - { - /* Use old CN parameters previously stored in memory */ - for (i = 0; i < 5; i++) - { - params[i] = st->old_CN_mem_tx[i]; - } - params[17] = st->old_CN_mem_tx[5]; - params[30] = st->old_CN_mem_tx[5]; - params[43] = st->old_CN_mem_tx[5]; - params[56] = st->old_CN_mem_tx[5]; - } - /* Set all the rest of the parameters to zero (SID codeword will - be written later) */ - for (i = 0; i < 12; i++) - { - params[i + 5] = 0; - params[i + 18] = 0; - params[i + 31] = 0; - params[i + 44] = 0; - } - - return; -} - -/************************************************************************* - * - * 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: aver_lsf_history - * - * PURPOSE: Compute the averaged LSF parameter vector. Computation is - * performed by averaging the LSF parameter vectors which exist - * in the LSF parameter history, together with the LSF - * parameter vectors of the current frame. - * - * INPUTS: lsf_old[0..DTX_HANGOVER-1][0..M-1] - * LSF parameter history - * lsf1[0..M-1] LSF vector of the 1st half of the frame - * lsf2[0..M-1] LSF vector of the 2nd half of the frame - * - * OUTPUTS: lsf_aver[0..M-1] Averaged LSF parameter vector - * - * RETURN VALUE: none - * - *************************************************************************/ - -void aver_lsf_history ( - Word16 lsf_old[DTX_HANGOVER][M], - Word16 lsf1[M], - Word16 lsf2[M], - Word16 lsf_aver[M] -) -{ - Word16 i, j; - Word32 L_temp; - - for (j = 0; j < M; j++) - { - L_temp = L_mult (0x3fff, lsf1[j]); - L_temp = L_mac (L_temp, 0x3fff, lsf2[j]); - L_temp = L_mult (INV_DTX_HANGOVER_P1, extract_h (L_temp)); - - for (i = 0; i < DTX_HANGOVER; i++) - { - L_temp = L_mac (L_temp, INV_DTX_HANGOVER_P1, lsf_old[i][j]); - } - - lsf_aver[j] = extract_h (L_temp); move16 (); - } - - return; -} - -/************************************************************************* - * - * FUNCTION NAME: update_gain_code_history_tx - * - * PURPOSE: Update the fixed codebook gain parameter history of the - * encoder. The fixed codebook gain parameters kept in the buffer - * are used later for computing the reference fixed codebook - * gain parameter value and the averaged 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 encoder - * - * OUTPUTS: gain_code_old_tx[0..4*DTX_HANGOVER-1] - * Updated fixed codebook gain history of encoder - * - * RETURN VALUE: none - * - *************************************************************************/ - -void update_gain_code_history_tx ( - struct EFR_encoder_state *st, - Word16 new_gain_code -) -{ - /* Circular buffer */ - st->gain_code_old_tx[st->buf_p_tx] = new_gain_code; - - if (sub (st->buf_p_tx, (4 * DTX_HANGOVER - 1)) == 0) - { - st->buf_p_tx = 0; - } - else - { - st->buf_p_tx = add (st->buf_p_tx, 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: compute_CN_excitation_gain - * - * PURPOSE: Compute the unquantized fixed codebook gain. Computation is - * based on the energy of the Linear Prediction residual signal. - * - * INPUTS: res2[0..39] Linear Prediction residual signal - * - * OUTPUTS: none - * - * RETURN VALUE: Unquantized fixed codebook gain - * - *************************************************************************/ - -Word16 compute_CN_excitation_gain ( - Word16 res2[L_SUBFR] -) -{ - Word16 i, norm, norm1, temp, overfl; - Word32 L_temp; - - /* Compute the energy of the LP residual signal */ - - norm = 0; move16 (); - do - { - overfl = 0; move16 (); - - L_temp = 0L; move32 (); - for (i = 0; i < L_SUBFR; i++) - { - temp = shr (res2[i], norm); - L_temp = L_mac (L_temp, temp, temp); - } - - test (); - if (L_sub (L_temp, MAX_32) == 0) - { - norm = add (norm, 1); - overfl = 1; move16 (); /* Set the overflow flag */ - } - test (); - } - while (overfl != 0); - - L_temp = L_add (L_temp, 1L); /* Avoid the case of all zeros */ - - /* Take the square root of the obtained energy value (sqroot is a 2nd - order Taylor series approximation) */ - - norm1 = norm_l (L_temp); - temp = extract_h (L_shl (L_temp, norm1)); - L_temp = L_mult (temp, temp); - L_temp = L_sub (805306368L, L_shr (L_temp, 3)); - L_temp = L_add (L_temp, L_mult (24576, temp)); - - temp = extract_h (L_temp); - test (); logic16 (); - if ((norm1 & 0x0001) != 0) - { - temp = mult_r (temp, 23170); - norm1 = sub (norm1, 1); - } - /* Divide the result of sqroot operation by sqroot(10) */ - - temp = mult_r (temp, 10362); - - /* Re-scale to get the final value */ - - norm1 = shr (norm1, 1); - norm1 = sub (norm1, norm); - - test (); - if (norm1 >= 0) - { - temp = shr (temp, norm1); - } - else - { - temp = shl (temp, abs_s (norm1)); - } - - return temp; -} - -/************************************************************************* - * - * 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: aver_gain_code_history - * - * PURPOSE: Compute the averaged fixed codebook gain parameter value. - * Computation is performed by averaging the fixed codebook - * gain parameter values which exist in the fixed codebook - * gain parameter history, together with the fixed codebook - * gain parameter value of the current subframe. - * - * INPUTS: CN_excitation_gain - * Unquantized fixed codebook gain value - * of the current subframe - * gain_code_old[0..4*DTX_HANGOVER-1] - * fixed codebook gain parameter history - * - * OUTPUTS: none - * - * RETURN VALUE: Averaged fixed codebook gain value - * - *************************************************************************/ - -Word16 aver_gain_code_history ( - Word16 CN_excitation_gain, - Word16 gain_code_old[4 * DTX_HANGOVER] -) -{ - Word16 i; - Word32 L_ret; - - L_ret = L_mult (0x470, CN_excitation_gain); - - for (i = 0; i < (4 * DTX_HANGOVER); i++) - { - L_ret = L_mac (L_ret, 0x470, gain_code_old[i]); - } - 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 = shr (extract_l (L_mult (i, 10)), 1); - i = add (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 = shl (noise_bits, 1); - noise_bits = noise_bits | (extract_l (*shift_reg) & 1); - logic16 (); logic16 (); - - *shift_reg = L_shr (*shift_reg, 1); move32 (); - test (); logic16 (); - if (Sn & 1) - { - *shift_reg = *shift_reg | 0x40000000L; move32 (); logic32 (); - } - } - - return noise_bits; -} - -/************************************************************************* - * - * 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; -} diff -r cc08498ed21b -r c1d53064b410 libgsmefr/dtx_common.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgsmefr/dtx_common.c Sat Dec 10 02:25:20 2022 +0000 @@ -0,0 +1,257 @@ +/* + * 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 = shr (extract_l (L_mult (i, 10)), 1); + i = add (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 = shl (noise_bits, 1); + noise_bits = noise_bits | (extract_l (*shift_reg) & 1); + logic16 (); logic16 (); + + *shift_reg = L_shr (*shift_reg, 1); move32 (); + test (); logic16 (); + if (Sn & 1) + { + *shift_reg = *shift_reg | 0x40000000L; move32 (); logic32 (); + } + } + + return noise_bits; +} diff -r cc08498ed21b -r c1d53064b410 libgsmefr/dtx_dec.c --- /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; +} diff -r cc08498ed21b -r c1d53064b410 libgsmefr/dtx_defs.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgsmefr/dtx_defs.h Sat Dec 10 02:25:20 2022 +0000 @@ -0,0 +1,19 @@ +/* + * The definitions contained in this header file originally lived in + * dtx.c; they are being factored out into a new header file as part of + * splitting of dtx.c code into common, encoder-only and decoder-only + * parts. + */ + +/* Inverse values of DTX hangover period and DTX hangover period + 1 */ + +#define INV_DTX_HANGOVER (0x7fff / DTX_HANGOVER) +#define INV_DTX_HANGOVER_P1 (0x7fff / (DTX_HANGOVER+1)) + +#define NB_PULSE 10 /* Number of pulses in fixed codebook excitation */ + +/* Constant DTX_ELAPSED_THRESHOLD is used as threshold for allowing + SID frame updating without hangover period in case when elapsed + time measured from previous SID update is below 24 */ + +#define DTX_ELAPSED_THRESHOLD (24 + DTX_HANGOVER - 1) diff -r cc08498ed21b -r c1d53064b410 libgsmefr/dtx_enc.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgsmefr/dtx_enc.c Sat Dec 10 02:25:20 2022 +0000 @@ -0,0 +1,442 @@ +/* + * This file is a product of splitting ETSI EFR dtx.c into parts; + * the present module is the encoder-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 "enc_state.h" + +/************************************************************************* + * + * FUNCTION NAME: reset_tx_dtx + * + * PURPOSE: Resets the static variables of the TX DTX handler to their + * initial values + * + *************************************************************************/ + +void reset_tx_dtx (struct EFR_encoder_state *st) +{ + Word16 i; + + /* suppose infinitely long speech period before start */ + + st->txdtx_hangover = DTX_HANGOVER; + st->txdtx_N_elapsed = 0x7fff; + st->txdtx_ctrl = TX_SP_FLAG | TX_VAD_FLAG; + + for (i = 0; i < 6; i++) + { + st->old_CN_mem_tx[i] = 0; + } + + for (i = 0; i < DTX_HANGOVER; i++) + { + st->lsf_old_tx[i][0] = 1384; + st->lsf_old_tx[i][1] = 2077; + st->lsf_old_tx[i][2] = 3420; + st->lsf_old_tx[i][3] = 5108; + st->lsf_old_tx[i][4] = 6742; + st->lsf_old_tx[i][5] = 8122; + st->lsf_old_tx[i][6] = 9863; + st->lsf_old_tx[i][7] = 11092; + st->lsf_old_tx[i][8] = 12714; + st->lsf_old_tx[i][9] = 13701; + } + + for (i = 0; i < 4 * DTX_HANGOVER; i++) + { + st->gain_code_old_tx[i] = 0; + } + + st->L_pn_seed_tx = PN_INITIAL_SEED; + + st->buf_p_tx = 0; + return; +} + +/************************************************************************* + * + * FUNCTION NAME: tx_dtx + * + * PURPOSE: DTX handler of the speech encoder. Determines when to add + * the hangover period to the end of the speech burst, and + * also determines when to use old SID parameters, and when + * to update the SID parameters. This function also initializes + * the pseudo noise generator shift register. + * + * Operation of the TX DTX handler is based on the VAD flag + * given as input from the speech encoder. + * + * INPUTS: VAD_flag Voice activity decision + * *txdtx_ctrl Old encoder DTX control word + * + * OUTPUTS: *txdtx_ctrl Updated encoder DTX control word + * L_pn_seed_tx Initialized pseudo noise generator shift + * register (global variable) + * + * RETURN VALUE: none + * + *************************************************************************/ + +void tx_dtx ( + struct EFR_encoder_state *st, + Word16 VAD_flag +) +{ + /* N_elapsed (frames since last SID update) is incremented. If SID + is updated N_elapsed is cleared later in this function */ + + st->txdtx_N_elapsed = add (st->txdtx_N_elapsed, 1); + + /* If voice activity was detected, reset hangover counter */ + + if (sub (VAD_flag, 1) == 0) + { + st->txdtx_hangover = DTX_HANGOVER; + st->txdtx_ctrl = TX_SP_FLAG | TX_VAD_FLAG; + } + else + { + if (st->txdtx_hangover == 0) + { + /* Hangover period is over, SID should be updated */ + + st->txdtx_N_elapsed = 0; + + /* Check if this is the first frame after hangover period */ + if ((st->txdtx_ctrl & TX_HANGOVER_ACTIVE) != 0) + { + st->txdtx_ctrl = TX_PREV_HANGOVER_ACTIVE + | TX_SID_UPDATE; + st->L_pn_seed_tx = PN_INITIAL_SEED; + } + else + { + st->txdtx_ctrl = TX_SID_UPDATE; + } + } + else + { + /* Hangover period is not over, update hangover counter */ + st->txdtx_hangover = sub (st->txdtx_hangover, 1); + + /* Check if elapsed time from last SID update is greater than + threshold. If not, set SP=0 (although hangover period is not + over) and use old SID parameters for new SID frame. + N_elapsed counter must be summed with hangover counter in order + to avoid erroneus SP=1 decision in case when N_elapsed is grown + bigger than threshold and hangover period is still active */ + + if (sub (add (st->txdtx_N_elapsed, st->txdtx_hangover), + DTX_ELAPSED_THRESHOLD) < 0) + { + /* old SID frame should be used */ + st->txdtx_ctrl = TX_USE_OLD_SID; + } + else + { + if ((st->txdtx_ctrl & TX_HANGOVER_ACTIVE) != 0) + { + st->txdtx_ctrl = TX_PREV_HANGOVER_ACTIVE + | TX_HANGOVER_ACTIVE + | TX_SP_FLAG; + } + else + { + st->txdtx_ctrl = TX_HANGOVER_ACTIVE + | TX_SP_FLAG; + } + } + } + } + + return; +} + +/************************************************************************* + * + * FUNCTION NAME: CN_encoding + * + * PURPOSE: Encoding of the comfort noise parameters into a SID frame. + * Use old SID parameters if necessary. Set the parameter + * indices not used by comfort noise parameters to zero. + * + * INPUTS: params[0..56] Comfort noise parameter frame from the + * speech encoder + * txdtx_ctrl TX DTX handler control word + * + * OUTPUTS: params[0..56] Comfort noise encoded parameter frame + * + * RETURN VALUE: none + * + *************************************************************************/ + +void CN_encoding ( + struct EFR_encoder_state *st, + Word16 params[], + Word16 txdtx_ctrl +) +{ + Word16 i; + + if ((txdtx_ctrl & TX_SID_UPDATE) != 0) + { + /* Store new CN parameters in memory to be used later as old + CN parameters */ + + /* LPC parameter indices */ + for (i = 0; i < 5; i++) + { + st->old_CN_mem_tx[i] = params[i]; + } + /* Codebook index computed in last subframe */ + st->old_CN_mem_tx[5] = params[56]; + } + if ((txdtx_ctrl & TX_USE_OLD_SID) != 0) + { + /* Use old CN parameters previously stored in memory */ + for (i = 0; i < 5; i++) + { + params[i] = st->old_CN_mem_tx[i]; + } + params[17] = st->old_CN_mem_tx[5]; + params[30] = st->old_CN_mem_tx[5]; + params[43] = st->old_CN_mem_tx[5]; + params[56] = st->old_CN_mem_tx[5]; + } + /* Set all the rest of the parameters to zero (SID codeword will + be written later) */ + for (i = 0; i < 12; i++) + { + params[i + 5] = 0; + params[i + 18] = 0; + params[i + 31] = 0; + params[i + 44] = 0; + } + + return; +} + +/************************************************************************* + * + * FUNCTION NAME: aver_lsf_history + * + * PURPOSE: Compute the averaged LSF parameter vector. Computation is + * performed by averaging the LSF parameter vectors which exist + * in the LSF parameter history, together with the LSF + * parameter vectors of the current frame. + * + * INPUTS: lsf_old[0..DTX_HANGOVER-1][0..M-1] + * LSF parameter history + * lsf1[0..M-1] LSF vector of the 1st half of the frame + * lsf2[0..M-1] LSF vector of the 2nd half of the frame + * + * OUTPUTS: lsf_aver[0..M-1] Averaged LSF parameter vector + * + * RETURN VALUE: none + * + *************************************************************************/ + +void aver_lsf_history ( + Word16 lsf_old[DTX_HANGOVER][M], + Word16 lsf1[M], + Word16 lsf2[M], + Word16 lsf_aver[M] +) +{ + Word16 i, j; + Word32 L_temp; + + for (j = 0; j < M; j++) + { + L_temp = L_mult (0x3fff, lsf1[j]); + L_temp = L_mac (L_temp, 0x3fff, lsf2[j]); + L_temp = L_mult (INV_DTX_HANGOVER_P1, extract_h (L_temp)); + + for (i = 0; i < DTX_HANGOVER; i++) + { + L_temp = L_mac (L_temp, INV_DTX_HANGOVER_P1, lsf_old[i][j]); + } + + lsf_aver[j] = extract_h (L_temp); move16 (); + } + + return; +} + +/************************************************************************* + * + * FUNCTION NAME: update_gain_code_history_tx + * + * PURPOSE: Update the fixed codebook gain parameter history of the + * encoder. The fixed codebook gain parameters kept in the buffer + * are used later for computing the reference fixed codebook + * gain parameter value and the averaged 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 encoder + * + * OUTPUTS: gain_code_old_tx[0..4*DTX_HANGOVER-1] + * Updated fixed codebook gain history of encoder + * + * RETURN VALUE: none + * + *************************************************************************/ + +void update_gain_code_history_tx ( + struct EFR_encoder_state *st, + Word16 new_gain_code +) +{ + /* Circular buffer */ + st->gain_code_old_tx[st->buf_p_tx] = new_gain_code; + + if (sub (st->buf_p_tx, (4 * DTX_HANGOVER - 1)) == 0) + { + st->buf_p_tx = 0; + } + else + { + st->buf_p_tx = add (st->buf_p_tx, 1); + } + + return; +} + +/************************************************************************* + * + * FUNCTION NAME: compute_CN_excitation_gain + * + * PURPOSE: Compute the unquantized fixed codebook gain. Computation is + * based on the energy of the Linear Prediction residual signal. + * + * INPUTS: res2[0..39] Linear Prediction residual signal + * + * OUTPUTS: none + * + * RETURN VALUE: Unquantized fixed codebook gain + * + *************************************************************************/ + +Word16 compute_CN_excitation_gain ( + Word16 res2[L_SUBFR] +) +{ + Word16 i, norm, norm1, temp, overfl; + Word32 L_temp; + + /* Compute the energy of the LP residual signal */ + + norm = 0; move16 (); + do + { + overfl = 0; move16 (); + + L_temp = 0L; move32 (); + for (i = 0; i < L_SUBFR; i++) + { + temp = shr (res2[i], norm); + L_temp = L_mac (L_temp, temp, temp); + } + + test (); + if (L_sub (L_temp, MAX_32) == 0) + { + norm = add (norm, 1); + overfl = 1; move16 (); /* Set the overflow flag */ + } + test (); + } + while (overfl != 0); + + L_temp = L_add (L_temp, 1L); /* Avoid the case of all zeros */ + + /* Take the square root of the obtained energy value (sqroot is a 2nd + order Taylor series approximation) */ + + norm1 = norm_l (L_temp); + temp = extract_h (L_shl (L_temp, norm1)); + L_temp = L_mult (temp, temp); + L_temp = L_sub (805306368L, L_shr (L_temp, 3)); + L_temp = L_add (L_temp, L_mult (24576, temp)); + + temp = extract_h (L_temp); + test (); logic16 (); + if ((norm1 & 0x0001) != 0) + { + temp = mult_r (temp, 23170); + norm1 = sub (norm1, 1); + } + /* Divide the result of sqroot operation by sqroot(10) */ + + temp = mult_r (temp, 10362); + + /* Re-scale to get the final value */ + + norm1 = shr (norm1, 1); + norm1 = sub (norm1, norm); + + test (); + if (norm1 >= 0) + { + temp = shr (temp, norm1); + } + else + { + temp = shl (temp, abs_s (norm1)); + } + + return temp; +} + +/************************************************************************* + * + * FUNCTION NAME: aver_gain_code_history + * + * PURPOSE: Compute the averaged fixed codebook gain parameter value. + * Computation is performed by averaging the fixed codebook + * gain parameter values which exist in the fixed codebook + * gain parameter history, together with the fixed codebook + * gain parameter value of the current subframe. + * + * INPUTS: CN_excitation_gain + * Unquantized fixed codebook gain value + * of the current subframe + * gain_code_old[0..4*DTX_HANGOVER-1] + * fixed codebook gain parameter history + * + * OUTPUTS: none + * + * RETURN VALUE: Averaged fixed codebook gain value + * + *************************************************************************/ + +Word16 aver_gain_code_history ( + Word16 CN_excitation_gain, + Word16 gain_code_old[4 * DTX_HANGOVER] +) +{ + Word16 i; + Word32 L_ret; + + L_ret = L_mult (0x470, CN_excitation_gain); + + for (i = 0; i < (4 * DTX_HANGOVER); i++) + { + L_ret = L_mac (L_ret, 0x470, gain_code_old[i]); + } + return extract_h (L_ret); +}