FreeCalypso > hg > gsm-codec-lib
diff libgsmefr/dtx_enc.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 | cf39a90f5196 |
line wrap: on
line diff
--- /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); +}