FreeCalypso > hg > gsm-codec-lib
diff libtwamr/dtx_dec.c @ 407:5a1d18542f8a
libtwamr: integrate dtx_dec.c and dtx_enc.c
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Tue, 07 May 2024 00:05:12 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libtwamr/dtx_dec.c Tue May 07 00:05:12 2024 +0000 @@ -0,0 +1,842 @@ +/* +***************************************************************************** +* +* GSM AMR-NB speech codec R98 Version 7.6.0 December 12, 2001 +* R99 Version 3.3.0 +* REL-4 Version 4.1.0 +* +***************************************************************************** +* +* File : dtx_dec.c +* Purpose : Decode comfort noise when in DTX +* +***************************************************************************** +*/ +/* +***************************************************************************** +* MODULE INCLUDE FILE AND VERSION ID +***************************************************************************** +*/ +#include "namespace.h" +#include "dtx_dec.h" + +/* +***************************************************************************** +* INCLUDE FILES +***************************************************************************** +*/ +#include "tw_amr.h" +#include "typedef.h" +#include "basic_op.h" +#include "oper_32b.h" +#include "memops.h" +#include "log2.h" +#include "lsp_az.h" +#include "pow2.h" +#include "a_refl.h" +#include "b_cn_cod.h" +#include "syn_filt.h" +#include "lsp_lsf.h" +#include "reorder.h" +#include "no_count.h" +#include "q_plsf5_tab.h" +#include "lsp_tab.h" + +/* +***************************************************************************** +* LOCAL VARIABLES AND TABLES +***************************************************************************** +*/ +#define PN_INITIAL_SEED 0x70816958L /* Pseudo noise generator seed value */ + +/*************************************************** + * Scaling factors for the lsp variability operation * + ***************************************************/ +static const Word16 lsf_hist_mean_scale[M] = { + 20000, + 20000, + 20000, + 20000, + 20000, + 18000, + 16384, + 8192, + 0, + 0 +}; + +/************************************************* + * level adjustment for different modes Q11 * + *************************************************/ +static const Word16 dtx_log_en_adjust[9] = +{ + -1023, /* MR475 */ + -878, /* MR515 */ + -732, /* MR59 */ + -586, /* MR67 */ + -440, /* MR74 */ + -294, /* MR795 */ + -148, /* MR102 */ + 0, /* MR122 */ + 0, /* MRDTX */ +}; + +/* +***************************************************************************** +* PUBLIC PROGRAM CODE +***************************************************************************** +*/ + +/* +************************************************************************** +* +* Function : dtx_dec_reset +* +************************************************************************** +*/ +void dtx_dec_reset (dtx_decState *st) +{ + int i; + + st->since_last_sid = 0; + st->true_sid_period_inv = (1 << 13); + + st->log_en = 3500; + st->old_log_en = 3500; + /* low level noise for better performance in DTX handover cases*/ + + st->L_pn_seed_rx = PN_INITIAL_SEED; + + /* Initialize state->lsp [] and state->lsp_old [] */ + Copy(lsp_init_data, &st->lsp[0], M); + Copy(lsp_init_data, &st->lsp_old[0], M); + + st->lsf_hist_ptr = 0; + st->log_pg_mean = 0; + st->log_en_hist_ptr = 0; + + /* initialize decoder lsf history */ + Copy(mean_lsf, &st->lsf_hist[0], M); + + for (i = 1; i < DTX_HIST_SIZE; i++) + { + Copy(&st->lsf_hist[0], &st->lsf_hist[M*i], M); + } + Set_zero(st->lsf_hist_mean, M*DTX_HIST_SIZE); + + /* initialize decoder log frame energy */ + for (i = 0; i < DTX_HIST_SIZE; i++) + { + st->log_en_hist[i] = st->log_en; + } + + st->log_en_adjust = 0; + + st->dtxHangoverCount = DTX_HANG_CONST; + st->decAnaElapsedCount = 32767; + + st->sid_frame = 0; + st->valid_data = 0; + st->dtxHangoverAdded = 0; + + st->dtxGlobalState = DTX; + st->data_updated = 0; +} + +/* +************************************************************************** +* +* Function : dtx_dec +* +************************************************************************** +*/ +int dtx_dec( + dtx_decState *st, /* i/o : State struct */ + Word16 mem_syn[], /* i/o : AMR decoder state */ + D_plsfState* lsfState, /* i/o : decoder lsf states */ + gc_predState* predState, /* i/o : prediction states */ + Cb_gain_averageState* averState, /* i/o : CB gain average states */ + enum DTXStateType new_state, /* i : new DTX state */ + enum Mode mode, /* i : AMR mode */ + Word16 parm[], /* i : Vector of synthesis parameters */ + Word16 synth[], /* o : synthesised speech */ + Word16 A_t[] /* o : decoded LP filter in 4 subframes*/ + ) +{ + Word16 log_en_index; + Word16 i, j; + Word16 int_fac; + Word32 L_log_en_int; + Word16 lsp_int[M]; + Word16 log_en_int_e; + Word16 log_en_int_m; + Word16 level; + Word16 acoeff[M + 1]; + Word16 refl[M]; + Word16 pred_err; + Word16 ex[L_SUBFR]; + Word16 ma_pred_init; + Word16 log_pg_e, log_pg_m; + Word16 log_pg; + Flag negative; + Word16 lsf_mean; + Word32 L_lsf_mean; + Word16 lsf_variab_index; + Word16 lsf_variab_factor; + Word16 lsf_int[M]; + Word16 lsf_int_variab[M]; + Word16 lsp_int_variab[M]; + Word16 acoeff_variab[M + 1]; + + Word16 lsf[M]; + Word32 L_lsf[M]; + Word16 ptr; + Word16 tmp_int_length; + + + /* This function is called if synthesis state is not SPEECH + * the globally passed inputs to this function are + * st->sid_frame + * st->valid_data + * st->dtxHangoverAdded + * new_state (SPEECH, DTX, DTX_MUTE) + */ + + test(); test(); + if ((st->dtxHangoverAdded != 0) && + (st->sid_frame != 0)) + { + /* sid_first after dtx hangover period */ + /* or sid_upd after dtxhangover */ + + /* set log_en_adjust to correct value */ + st->log_en_adjust = dtx_log_en_adjust[mode]; + + ptr = add(st->lsf_hist_ptr, M); move16(); + test(); + if (sub(ptr, 80) == 0) + { + ptr = 0; move16(); + } + Copy( &st->lsf_hist[st->lsf_hist_ptr],&st->lsf_hist[ptr],M); + + ptr = add(st->log_en_hist_ptr,1); move16(); + test(); + if (sub(ptr, DTX_HIST_SIZE) == 0) + { + ptr = 0; move16(); + } + move16(); + st->log_en_hist[ptr] = st->log_en_hist[st->log_en_hist_ptr]; /* Q11 */ + + /* compute mean log energy and lsp * + * from decoded signal (SID_FIRST) */ + st->log_en = 0; move16(); + for (i = 0; i < M; i++) + { + L_lsf[i] = 0; move16(); + } + + /* average energy and lsp */ + for (i = 0; i < DTX_HIST_SIZE; i++) + { + st->log_en = add(st->log_en, + shr(st->log_en_hist[i],3)); + for (j = 0; j < M; j++) + { + L_lsf[j] = L_add(L_lsf[j], + L_deposit_l(st->lsf_hist[i * M + j])); + } + } + + for (j = 0; j < M; j++) + { + lsf[j] = extract_l(L_shr(L_lsf[j],3)); /* divide by 8 */ move16(); + } + + Lsf_lsp(lsf, st->lsp, M); + + /* make log_en speech coder mode independent */ + /* added again later before synthesis */ + st->log_en = sub(st->log_en, st->log_en_adjust); + + /* compute lsf variability vector */ + Copy(st->lsf_hist, st->lsf_hist_mean, 80); + + for (i = 0; i < M; i++) + { + L_lsf_mean = 0; move32(); + /* compute mean lsf */ + for (j = 0; j < 8; j++) + { + L_lsf_mean = L_add(L_lsf_mean, + L_deposit_l(st->lsf_hist_mean[i+j*M])); + } + + lsf_mean = extract_l(L_shr(L_lsf_mean, 3)); move16(); + /* subtract mean and limit to within reasonable limits * + * moreover the upper lsf's are attenuated */ + for (j = 0; j < 8; j++) + { + /* subtract mean */ + st->lsf_hist_mean[i+j*M] = + sub(st->lsf_hist_mean[i+j*M], lsf_mean); + + /* attenuate deviation from mean, especially for upper lsf's */ + st->lsf_hist_mean[i+j*M] = + mult(st->lsf_hist_mean[i+j*M], lsf_hist_mean_scale[i]); + + /* limit the deviation */ + test(); + if (st->lsf_hist_mean[i+j*M] < 0) + { + negative = 1; move16(); + } + else + { + negative = 0; move16(); + } + st->lsf_hist_mean[i+j*M] = abs_s(st->lsf_hist_mean[i+j*M]); + + /* apply soft limit */ + test(); + if (sub(st->lsf_hist_mean[i+j*M], 655) > 0) + { + st->lsf_hist_mean[i+j*M] = + add(655, shr(sub(st->lsf_hist_mean[i+j*M], 655), 2)); + } + + /* apply hard limit */ + test(); + if (sub(st->lsf_hist_mean[i+j*M], 1310) > 0) + { + st->lsf_hist_mean[i+j*M] = 1310; move16(); + } + test(); + if (negative != 0) + { + st->lsf_hist_mean[i+j*M] = -st->lsf_hist_mean[i+j*M];move16(); + } + + } + } + } + + test(); + if (st->sid_frame != 0 ) + { + /* Set old SID parameters, always shift */ + /* even if there is no new valid_data */ + Copy(st->lsp, st->lsp_old, M); + st->old_log_en = st->log_en; move16(); + + test(); + if (st->valid_data != 0 ) /* new data available (no CRC) */ + { + /* Compute interpolation factor, since the division only works * + * for values of since_last_sid < 32 we have to limit the * + * interpolation to 32 frames */ + tmp_int_length = st->since_last_sid; move16(); + st->since_last_sid = 0; move16(); + + test(); + if (sub(tmp_int_length, 32) > 0) + { + tmp_int_length = 32; move16(); + } + test(); + if (sub(tmp_int_length, 2) >= 0) + { + move16(); + st->true_sid_period_inv = div_s(1 << 10, shl(tmp_int_length, 10)); + } + else + { + st->true_sid_period_inv = 1 << 14; /* 0.5 it Q15 */ move16(); + } + + Init_D_plsf_3(lsfState, parm[0]); /* temporay initialization */ + D_plsf_3(lsfState, MRDTX, 0, &parm[1], st->lsp); + Set_zero(lsfState->past_r_q, M); /* reset for next speech frame */ + + log_en_index = parm[4]; move16(); + /* Q11 and divide by 4 */ + st->log_en = shl(log_en_index, (11 - 2)); move16(); + + /* Subtract 2.5 in Q11 */ + st->log_en = sub(st->log_en, (2560 * 2)); + + /* Index 0 is reserved for silence */ + test(); + if (log_en_index == 0) + { + st->log_en = MIN_16; move16(); + } + + /* no interpolation at startup after coder reset */ + /* or when SID_UPD has been received right after SPEECH */ + test(); test(); + if ((st->data_updated == 0) || + (sub(st->dtxGlobalState, SPEECH) == 0) + ) + { + Copy(st->lsp, st->lsp_old, M); + st->old_log_en = st->log_en; move16(); + } + } /* endif valid_data */ + + /* initialize gain predictor memory of other modes */ + ma_pred_init = sub(shr(st->log_en,1), 9000); move16(); + test(); + if (ma_pred_init > 0) + { + ma_pred_init = 0; move16(); + } + test(); + if (sub(ma_pred_init, -14436) < 0) + { + ma_pred_init = -14436; move16(); + } + + predState->past_qua_en[0] = ma_pred_init; move16(); + predState->past_qua_en[1] = ma_pred_init; move16(); + predState->past_qua_en[2] = ma_pred_init; move16(); + predState->past_qua_en[3] = ma_pred_init; move16(); + + /* past_qua_en for other modes than MR122 */ + ma_pred_init = mult(5443, ma_pred_init); + /* scale down by factor 20*log10(2) in Q15 */ + predState->past_qua_en_MR122[0] = ma_pred_init; move16(); + predState->past_qua_en_MR122[1] = ma_pred_init; move16(); + predState->past_qua_en_MR122[2] = ma_pred_init; move16(); + predState->past_qua_en_MR122[3] = ma_pred_init; move16(); + } /* endif sid_frame */ + + /* CN generation */ + /* recompute level adjustment factor Q11 * + * st->log_en_adjust = 0.9*st->log_en_adjust + * + * 0.1*dtx_log_en_adjust[mode]); */ + move16(); + st->log_en_adjust = add(mult(st->log_en_adjust, 29491), + shr(mult(shl(dtx_log_en_adjust[mode],5),3277),5)); + + /* Interpolate SID info */ + int_fac = shl(add(1,st->since_last_sid), 10); /* Q10 */ move16(); + int_fac = mult(int_fac, st->true_sid_period_inv); /* Q10 * Q15 -> Q10 */ + + /* Maximize to 1.0 in Q10 */ + test(); + if (sub(int_fac, 1024) > 0) + { + int_fac = 1024; move16(); + } + int_fac = shl(int_fac, 4); /* Q10 -> Q14 */ + + L_log_en_int = L_mult(int_fac, st->log_en); /* Q14 * Q11->Q26 */ move32(); + for(i = 0; i < M; i++) + { + lsp_int[i] = mult(int_fac, st->lsp[i]);/* Q14 * Q15 -> Q14 */ move16(); + } + + int_fac = sub(16384, int_fac); /* 1-k in Q14 */ move16(); + + /* (Q14 * Q11 -> Q26) + Q26 -> Q26 */ + L_log_en_int = L_mac(L_log_en_int, int_fac, st->old_log_en); + for(i = 0; i < M; i++) + { + /* Q14 + (Q14 * Q15 -> Q14) -> Q14 */ + lsp_int[i] = add(lsp_int[i], mult(int_fac, st->lsp_old[i])); move16(); + lsp_int[i] = shl(lsp_int[i], 1); /* Q14 -> Q15 */ move16(); + } + + /* compute the amount of lsf variability */ + lsf_variab_factor = sub(st->log_pg_mean,2457); /* -0.6 in Q12 */ move16(); + /* *0.3 Q12*Q15 -> Q12 */ + lsf_variab_factor = sub(4096, mult(lsf_variab_factor, 9830)); + + /* limit to values between 0..1 in Q12 */ + test(); + if (sub(lsf_variab_factor, 4096) > 0) + { + lsf_variab_factor = 4096; move16(); + } + test(); + if (lsf_variab_factor < 0) + { + lsf_variab_factor = 0; move16(); + } + lsf_variab_factor = shl(lsf_variab_factor, 3); /* -> Q15 */ move16(); + + /* get index of vector to do variability with */ + lsf_variab_index = pseudonoise(&st->L_pn_seed_rx, 3); move16(); + + /* convert to lsf */ + Lsp_lsf(lsp_int, lsf_int, M); + + /* apply lsf variability */ + Copy(lsf_int, lsf_int_variab, M); + for(i = 0; i < M; i++) + { + move16(); + lsf_int_variab[i] = add(lsf_int_variab[i], + mult(lsf_variab_factor, + st->lsf_hist_mean[i+lsf_variab_index*M])); + } + + /* make sure that LSP's are ordered */ + Reorder_lsf(lsf_int, LSF_GAP, M); + Reorder_lsf(lsf_int_variab, LSF_GAP, M); + + /* copy lsf to speech decoders lsf state */ + Copy(lsf_int, lsfState->past_lsf_q, M); + + /* convert to lsp */ + Lsf_lsp(lsf_int, lsp_int, M); + Lsf_lsp(lsf_int_variab, lsp_int_variab, M); + + /* Compute acoeffs Q12 acoeff is used for level * + * normalization and postfilter, acoeff_variab is * + * used for synthesis filter * + * by doing this we make sure that the level * + * in high frequenncies does not jump up and down */ + + Lsp_Az(lsp_int, acoeff); + Lsp_Az(lsp_int_variab, acoeff_variab); + + /* For use in postfilter */ + Copy(acoeff, &A_t[0], M + 1); + Copy(acoeff, &A_t[M + 1], M + 1); + Copy(acoeff, &A_t[2 * (M + 1)], M + 1); + Copy(acoeff, &A_t[3 * (M + 1)], M + 1); + + /* Compute reflection coefficients Q15 */ + A_Refl(&acoeff[1], refl); + + /* Compute prediction error in Q15 */ + pred_err = MAX_16; /* 0.99997 in Q15 */ move16(); + for (i = 0; i < M; i++) + { + pred_err = mult(pred_err, sub(MAX_16, mult(refl[i], refl[i]))); + } + + /* compute logarithm of prediction gain */ + Log2(L_deposit_l(pred_err), &log_pg_e, &log_pg_m); + + /* convert exponent and mantissa to Word16 Q12 */ + log_pg = shl(sub(log_pg_e,15), 12); /* Q12 */ move16(); + log_pg = shr(sub(0,add(log_pg, shr(log_pg_m, 15-12))), 1); move16(); + st->log_pg_mean = add(mult(29491,st->log_pg_mean), + mult(3277, log_pg)); move16(); + + /* Compute interpolated log energy */ + L_log_en_int = L_shr(L_log_en_int, 10); /* Q26 -> Q16 */ move32(); + + /* Add 4 in Q16 */ + L_log_en_int = L_add(L_log_en_int, 4 * 65536L); move32(); + + /* subtract prediction gain */ + L_log_en_int = L_sub(L_log_en_int, L_shl(L_deposit_l(log_pg), 4));move32(); + + /* adjust level to speech coder mode */ + L_log_en_int = L_add(L_log_en_int, + L_shl(L_deposit_l(st->log_en_adjust), 5)); move32(); + + log_en_int_e = extract_h(L_log_en_int); move16(); + move16(); + log_en_int_m = extract_l(L_shr(L_sub(L_log_en_int, + L_deposit_h(log_en_int_e)), 1)); + level = extract_l(Pow2(log_en_int_e, log_en_int_m)); /* Q4 */ move16(); + + for (i = 0; i < 4; i++) + { + /* Compute innovation vector */ + build_CN_code(&st->L_pn_seed_rx, ex); + for (j = 0; j < L_SUBFR; j++) + { + ex[j] = mult(level, ex[j]); move16(); + } + /* Synthesize */ + Syn_filt(acoeff_variab, ex, &synth[i * L_SUBFR], L_SUBFR, + mem_syn, 1); + + } /* next i */ + + /* reset codebook averaging variables */ + averState->hangVar = 20; move16(); + averState->hangCount = 0; move16(); + + test(); + if (sub(new_state, DTX_MUTE) == 0) + { + /* mute comfort noise as it has been quite a long time since + * last SID update was performed */ + + tmp_int_length = st->since_last_sid; move16(); + test(); + if (sub(tmp_int_length, 32) > 0) + { + tmp_int_length = 32; move16(); + } + + /* safety guard against division by zero */ + test(); + if(tmp_int_length <= 0) { + tmp_int_length = 8; move16(); + } + + move16(); + st->true_sid_period_inv = div_s(1 << 10, shl(tmp_int_length, 10)); + + st->since_last_sid = 0; move16(); + Copy(st->lsp, st->lsp_old, M); + st->old_log_en = st->log_en; move16(); + /* subtract 1/8 in Q11 i.e -6/8 dB */ + st->log_en = sub(st->log_en, 256); move16(); + } + + /* reset interpolation length timer + * if data has been updated. */ + test(); test(); test(); test(); + if ((st->sid_frame != 0) && + ((st->valid_data != 0) || + ((st->valid_data == 0) && (st->dtxHangoverAdded) != 0))) + { + st->since_last_sid = 0; move16(); + st->data_updated = 1; move16(); + } + + return 0; +} + +void dtx_dec_activity_update(dtx_decState *st, + Word16 lsf[], + Word16 frame[]) +{ + Word16 i; + + Word32 L_frame_en; + Word16 log_en_e, log_en_m, log_en; + + /* update lsp history */ + st->lsf_hist_ptr = add(st->lsf_hist_ptr,M); move16(); + test(); + if (sub(st->lsf_hist_ptr, 80) == 0) + { + st->lsf_hist_ptr = 0; move16(); + } + Copy(lsf, &st->lsf_hist[st->lsf_hist_ptr], M); + + /* compute log energy based on frame energy */ + L_frame_en = 0; /* Q0 */ move32(); + for (i=0; i < L_FRAME; i++) + { + L_frame_en = L_mac(L_frame_en, frame[i], frame[i]); + } + Log2(L_frame_en, &log_en_e, &log_en_m); + + /* convert exponent and mantissa to Word16 Q10 */ + log_en = shl(log_en_e, 10); /* Q10 */ + log_en = add(log_en, shr(log_en_m, 15-10)); + + /* divide with L_FRAME i.e subtract with log2(L_FRAME) = 7.32193 */ + log_en = sub(log_en, 7497+1024); + + /* insert into log energy buffer, no division by two as * + * log_en in decoder is Q11 */ + st->log_en_hist_ptr = add(st->log_en_hist_ptr, 1); + test(); + if (sub(st->log_en_hist_ptr, DTX_HIST_SIZE) == 0) + { + st->log_en_hist_ptr = 0; move16(); + } + st->log_en_hist[st->log_en_hist_ptr] = log_en; /* Q11 */ move16(); +} + +/* + Table of new SPD synthesis states + + | previous SPD_synthesis_state + Incoming | + frame_type | SPEECH | DTX | DTX_MUTE + --------------------------------------------------------------- + RX_SPEECH_GOOD , | | | + RX_SPEECH_PR_DEGRADED | SPEECH | SPEECH | SPEECH + ---------------------------------------------------------------- + RX_SPEECH_BAD, | SPEECH | DTX | DTX_MUTE + ---------------------------------------------------------------- + RX_SID_FIRST, | DTX | DTX/(DTX_MUTE)| DTX_MUTE + ---------------------------------------------------------------- + RX_SID_UPDATE, | DTX | DTX | DTX + ---------------------------------------------------------------- + RX_SID_BAD, | DTX | DTX/(DTX_MUTE)| DTX_MUTE + ---------------------------------------------------------------- + RX_NO_DATA | SPEECH | DTX/(DTX_MUTE)| DTX_MUTE + |(class2 garb.)| | + ---------------------------------------------------------------- + RX_ONSET | SPEECH | DTX/(DTX_MUTE)| DTX_MUTE + |(class2 garb.)| | + ---------------------------------------------------------------- +*/ + +enum DTXStateType rx_dtx_handler( + dtx_decState *st, /* i/o : State struct */ + enum RXFrameType frame_type /* i : Frame type */ + ) +{ + enum DTXStateType newState; + enum DTXStateType encState; + + /* DTX if SID frame or previously in DTX{_MUTE} and (NO_RX OR BAD_SPEECH) */ + test(); test(); test(); + test(); test(); test(); + test(); test(); + if ((sub(frame_type, RX_SID_FIRST) == 0) || + (sub(frame_type, RX_SID_UPDATE) == 0) || + (sub(frame_type, RX_SID_BAD) == 0) || + (((sub(st->dtxGlobalState, DTX) == 0) || + (sub(st->dtxGlobalState, DTX_MUTE) == 0)) && + ((sub(frame_type, RX_NO_DATA) == 0) || + (sub(frame_type, RX_SPEECH_BAD) == 0) || + (sub(frame_type, RX_ONSET) == 0)))) + { + newState = DTX; move16(); + + /* stay in mute for these input types */ + test(); test(); test(); test(); test(); + if ((sub(st->dtxGlobalState, DTX_MUTE) == 0) && + ((sub(frame_type, RX_SID_BAD) == 0) || + (sub(frame_type, RX_SID_FIRST) == 0) || + (sub(frame_type, RX_ONSET) == 0) || + (sub(frame_type, RX_NO_DATA) == 0))) + { + newState = DTX_MUTE; move16(); + } + + /* evaluate if noise parameters are too old */ + /* since_last_sid is reset when CN parameters have been updated */ + st->since_last_sid = add(st->since_last_sid, 1); move16(); + + /* no update of sid parameters in DTX for a long while */ + /* Due to the delayed update of st->since_last_sid counter + SID_UPDATE frames need to be handled separately to avoid + entering DTX_MUTE for late SID_UPDATE frames + */ + test(); test(); logic16(); + if((sub(frame_type, RX_SID_UPDATE) != 0) && + (sub(st->since_last_sid, DTX_MAX_EMPTY_THRESH) > 0)) + { + newState = DTX_MUTE; move16(); + } + } + else + { + newState = SPEECH; move16(); + st->since_last_sid = 0; move16(); + } + + /* + reset the decAnaElapsed Counter when receiving CNI data the first + time, to robustify counter missmatch after handover + this might delay the bwd CNI analysis in the new decoder slightly. + */ + test(); test(); + if ((st->data_updated == 0) && + (sub(frame_type, RX_SID_UPDATE) == 0)) + { + st->decAnaElapsedCount = 0; move16(); + } + + /* update the SPE-SPD DTX hangover synchronization */ + /* to know when SPE has added dtx hangover */ + st->decAnaElapsedCount = add(st->decAnaElapsedCount, 1); move16(); + st->dtxHangoverAdded = 0; move16(); + + test(); test(); test(); test(); test(); + if ((sub(frame_type, RX_SID_FIRST) == 0) || + (sub(frame_type, RX_SID_UPDATE) == 0) || + (sub(frame_type, RX_SID_BAD) == 0) || + (sub(frame_type, RX_ONSET) == 0) || + (sub(frame_type, RX_NO_DATA) == 0)) + { + encState = DTX; move16(); + + /* + In frame errors simulations RX_NO_DATA may occasionally mean that + a speech packet was probably sent by the encoder, + the assumed _encoder_ state should be SPEECH in such cases. + */ + + test(); logic16(); + if((sub(frame_type, RX_NO_DATA) == 0) && + (sub(newState, SPEECH) == 0)) + { + encState = SPEECH; move16(); + } + + + /* Note on RX_ONSET operation differing from RX_NO_DATA operation: + If a RX_ONSET is received in the decoder (by "accident") + it is still most likely that the encoder state + for the "ONSET frame" was DTX. + */ + } + else + { + encState = SPEECH; move16(); + } + + test(); + if (sub(encState, SPEECH) == 0) + { + st->dtxHangoverCount = DTX_HANG_CONST; move16(); + } + else + { + test(); + if (sub(st->decAnaElapsedCount, DTX_ELAPSED_FRAMES_THRESH) > 0) + { + st->dtxHangoverAdded = 1; move16(); + st->decAnaElapsedCount = 0; move16(); + st->dtxHangoverCount = 0; move16(); + } + else if (test(), st->dtxHangoverCount == 0) + { + st->decAnaElapsedCount = 0; move16(); + } + else + { + st->dtxHangoverCount = sub(st->dtxHangoverCount, 1); move16(); + } + } + + if (sub(newState, SPEECH) != 0) + { + /* DTX or DTX_MUTE + * CN data is not in a first SID, first SIDs are marked as SID_BAD + * but will do backwards analysis if a hangover period has been added + * according to the state machine above + */ + + st->sid_frame = 0; move16(); + st->valid_data = 0; move16(); + + test(); + if (sub(frame_type, RX_SID_FIRST) == 0) + { + st->sid_frame = 1; move16(); + } + else if (test(), sub(frame_type, RX_SID_UPDATE) == 0) + { + st->sid_frame = 1; move16(); + st->valid_data = 1; move16(); + } + else if (test(), sub(frame_type, RX_SID_BAD) == 0) + { + st->sid_frame = 1; move16(); + st->dtxHangoverAdded = 0; /* use old data */ move16(); + } + } + + return newState; + /* newState is used by both SPEECH AND DTX synthesis routines */ +}