# HG changeset patch # User Mychaela Falconia # Date 1715040312 0 # Node ID 5a1d18542f8a819de9a120085c428aab9c9e4423 # Parent 85e9768d497f7f00f9b4ec62d4b8908ab20c2c26 libtwamr: integrate dtx_dec.c and dtx_enc.c diff -r 85e9768d497f -r 5a1d18542f8a libtwamr/Makefile --- a/libtwamr/Makefile Mon May 06 23:32:59 2024 +0000 +++ b/libtwamr/Makefile Tue May 07 00:05:12 2024 +0000 @@ -5,17 +5,17 @@ c8_31pf.o c_g_aver.o calc_cor.o calc_en.o cbsearch.o cl_ltp.o \ convolve.o cor_h.o d1035pf.o d2_11pf.o d2_9pf.o d3_14pf.o d4_17pf.o \ d8_31pf.o d_gain_c.o d_gain_p.o d_plsf.o d_plsf_3.o d_plsf_5.o \ - dec_gain.o dec_lag3.o dec_lag6.o dhf_check.o dhf_tables.o e_homing.o \ - ec_gains.o enc_lag3.o enc_lag6.o ex_ctrl.o g_adapt.o g_code.o g_pitch.o\ - gain_q.o gains_tab.o gc_pred.o gmed_n.o graytab.o hp_max.o int_lpc.o \ - int_lsf.o inter_36.o inv_sqrt.o lag_wind.o levinson.o log2.o lpc.o \ - lsfwt.o lsp.o lsp_avg.o lsp_az.o lsp_lsf.o lsp_tab.o mac_32.o \ - oper_32b.o ph_disp.o pitch_fr.o post_pro.o pow2.o pre_big.o pre_proc.o \ - pred_lt.o preemph.o prm2bits.o prmno.o pstfilt.o q_gain_c.o q_gain_p.o \ - q_plsf.o q_plsf3_tab.o q_plsf5_tab.o q_plsf_3.o q_plsf_5.o qgain475.o \ - qgain795.o qua_gain.o qua_gain_tab.o reorder.o residu.o s10_8pf.o \ - set_sign.o sid_sync.o spreproc.o spstproc.o sqrt_l.o syn_filt.o \ - tls_flags.o ton_stab.o weight_a.o window.o + dec_gain.o dec_lag3.o dec_lag6.o dhf_check.o dhf_tables.o dtx_dec.o \ + dtx_enc.o e_homing.o ec_gains.o enc_lag3.o enc_lag6.o ex_ctrl.o \ + g_adapt.o g_code.o g_pitch.o gain_q.o gains_tab.o gc_pred.o gmed_n.o \ + graytab.o hp_max.o int_lpc.o int_lsf.o inter_36.o inv_sqrt.o lag_wind.o\ + levinson.o log2.o lpc.o lsfwt.o lsp.o lsp_avg.o lsp_az.o lsp_lsf.o \ + lsp_tab.o mac_32.o oper_32b.o ph_disp.o pitch_fr.o post_pro.o pow2.o \ + pre_big.o pre_proc.o pred_lt.o preemph.o prm2bits.o prmno.o pstfilt.o \ + q_gain_c.o q_gain_p.o q_plsf.o q_plsf3_tab.o q_plsf5_tab.o q_plsf_3.o \ + q_plsf_5.o qgain475.o qgain795.o qua_gain.o qua_gain_tab.o reorder.o \ + residu.o s10_8pf.o set_sign.o sid_sync.o spreproc.o spstproc.o sqrt_l.o\ + syn_filt.o tls_flags.o ton_stab.o weight_a.o window.o HDRS= namespace.h LIB= libtwamr.a diff -r 85e9768d497f -r 5a1d18542f8a libtwamr/dtx_common.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libtwamr/dtx_common.h Tue May 07 00:05:12 2024 +0000 @@ -0,0 +1,20 @@ +/* + * This header file contains some common definitions that have been + * factored out of dtx_enc.h; the original code used the construct of + * dtx_dec.h including dtx_enc.h, but in the opinion of this developer + * it is better to factor out the common bits. + */ + +#ifndef dtx_common_h +#define dtx_common_h + +/* +******************************************************************************** +* LOCAL VARIABLES AND TABLES +******************************************************************************** +*/ +#define DTX_HIST_SIZE 8 +#define DTX_ELAPSED_FRAMES_THRESH (24 + 7 -1) +#define DTX_HANG_CONST 7 /* yields eight frames of SP HANGOVER */ + +#endif diff -r 85e9768d497f -r 5a1d18542f8a libtwamr/dtx_dec.c --- /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 */ +} diff -r 85e9768d497f -r 5a1d18542f8a libtwamr/dtx_dec.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libtwamr/dtx_dec.h Tue May 07 00:05:12 2024 +0000 @@ -0,0 +1,133 @@ +/* +***************************************************************************** +* +* 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.h +* Purpose : Decode comfort noice when in DTX +* +***************************************************************************** +*/ +#ifndef dtx_dec_h +#define dtx_dec_h "$Id $" + +/* +***************************************************************************** +* INCLUDE FILES +***************************************************************************** +*/ +#include "tw_amr.h" +#include "typedef.h" +#include "dtx_common.h" +#include "d_plsf.h" +#include "gc_pred.h" +#include "c_g_aver.h" + +/* +***************************************************************************** +* LOCAL VARIABLES AND TABLES +***************************************************************************** +*/ +enum DTXStateType {SPEECH = 0, DTX, DTX_MUTE}; + +#define DTX_MAX_EMPTY_THRESH 50 + +/* +***************************************************************************** +* DEFINITION OF DATA TYPES +***************************************************************************** +*/ + +typedef struct { + Word16 since_last_sid; + Word16 true_sid_period_inv; + Word16 log_en; + Word16 old_log_en; + Word32 L_pn_seed_rx; + Word16 lsp[M]; + Word16 lsp_old[M]; + + Word16 lsf_hist[M*DTX_HIST_SIZE]; + Word16 lsf_hist_ptr; + Word16 lsf_hist_mean[M*DTX_HIST_SIZE]; + Word16 log_pg_mean; + Word16 log_en_hist[DTX_HIST_SIZE]; + Word16 log_en_hist_ptr; + + Word16 log_en_adjust; + + Word16 dtxHangoverCount; + Word16 decAnaElapsedCount; + + Word16 sid_frame; + Word16 valid_data; + Word16 dtxHangoverAdded; + + enum DTXStateType dtxGlobalState; /* contains previous state */ + /* updated in main decoder */ + + Word16 data_updated; /* marker to know if CNI data is ever renewed */ + +} dtx_decState; + +/* +***************************************************************************** +* DECLARATION OF PROTOTYPES +***************************************************************************** +*/ + +/* +************************************************************************** +* +* Function : dtx_dec_reset +* Purpose : Resets state memory +* Returns : 0 on success +* +************************************************************************** +*/ +void dtx_dec_reset (dtx_decState *st); + +/* +************************************************************************** +* +* Function : dtx_dec +* Purpose : +* Description : +* +************************************************************************** +*/ +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*/ + ); + +void dtx_dec_activity_update(dtx_decState *st, + Word16 lsf[], + Word16 frame[]); + +/* +************************************************************************** +* +* Function : rx_dtx_handler +* Purpose : reads the frame type and checks history +* Description : to decide what kind of DTX/CNI action to perform + +************************************************************************** +*/ +enum DTXStateType rx_dtx_handler(dtx_decState *st, /* i/o : State struct */ + enum RXFrameType frame_type /* i : Frame type */ + ); + +#endif diff -r 85e9768d497f -r 5a1d18542f8a libtwamr/dtx_enc.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libtwamr/dtx_enc.c Tue May 07 00:05:12 2024 +0000 @@ -0,0 +1,308 @@ +/* +******************************************************************************** +* +* 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_enc.c +* Purpose : DTX mode computation of SID parameters +* +******************************************************************************** +*/ + +/* +******************************************************************************** +* MODULE INCLUDE FILE AND VERSION ID +******************************************************************************** +*/ +#include "namespace.h" +#include "dtx_enc.h" + +/* +******************************************************************************** +* INCLUDE FILES +******************************************************************************** +*/ +#include "tw_amr.h" +#include "typedef.h" +#include "basic_op.h" +#include "oper_32b.h" +#include "q_plsf.h" +#include "memops.h" +#include "log2.h" +#include "lsp_lsf.h" +#include "reorder.h" +#include "no_count.h" +#include "lsp_tab.h" + +/* +******************************************************************************** +* PUBLIC PROGRAM CODE +******************************************************************************** +*/ + +/* +************************************************************************** +* +* Function : dtx_enc_reset +* +************************************************************************** +*/ +void dtx_enc_reset (dtx_encState *st) +{ + Word16 i; + + st->hist_ptr = 0; + st->log_en_index = 0; + st->init_lsf_vq_index = 0; + st->lsp_index[0] = 0; + st->lsp_index[1] = 0; + st->lsp_index[2] = 0; + + /* Init lsp_hist[] */ + for(i = 0; i < DTX_HIST_SIZE; i++) + { + Copy(lsp_init_data, &st->lsp_hist[i * M], M); + } + + /* Reset energy history */ + Set_zero(st->log_en_hist, M); + + st->dtxHangoverCount = DTX_HANG_CONST; + st->decAnaElapsedCount = 32767; +} + +/* +************************************************************************** +* +* Function : dtx_enc +* +************************************************************************** +*/ +int dtx_enc(dtx_encState *st, /* i/o : State struct */ + Word16 computeSidFlag, /* i : compute SID */ + Q_plsfState *qSt, /* i/o : Qunatizer state struct */ + gc_predState* predState, /* i/o : State struct */ + Word16 **anap /* o : analysis parameters */ + ) +{ + Word16 i,j; + Word16 log_en; + Word16 lsf[M]; + Word16 lsp[M]; + Word16 lsp_q[M]; + Word32 L_lsp[M]; + + /* VOX mode computation of SID parameters */ + test (); test (); + if ((computeSidFlag != 0)) + { + /* compute new SID frame if safe i.e don't + * compute immediately after a talk spurt */ + log_en = 0; move16 (); + for (i = 0; i < M; i++) + { + L_lsp[i] = 0; move16 (); + } + + /* average energy and lsp */ + for (i = 0; i < DTX_HIST_SIZE; i++) + { + log_en = add(log_en, + shr(st->log_en_hist[i],2)); + + for (j = 0; j < M; j++) + { + L_lsp[j] = L_add(L_lsp[j], + L_deposit_l(st->lsp_hist[i * M + j])); + } + } + + log_en = shr(log_en, 1); + for (j = 0; j < M; j++) + { + lsp[j] = extract_l(L_shr(L_lsp[j], 3)); /* divide by 8 */ + } + + /* quantize logarithmic energy to 6 bits */ + st->log_en_index = add(log_en, 2560); /* +2.5 in Q10 */ + st->log_en_index = add(st->log_en_index, 128); /* add 0.5/4 in Q10 */ + st->log_en_index = shr(st->log_en_index, 8); + + test (); + if (sub(st->log_en_index, 63) > 0) + { + st->log_en_index = 63; move16 (); + } + test (); + if (st->log_en_index < 0) + { + st->log_en_index = 0; move16 (); + } + + /* update gain predictor memory */ + log_en = shl(st->log_en_index, -2+10); /* Q11 and divide by 4 */ + log_en = sub(log_en, 2560); /* add 2.5 in Q11 */ + + log_en = sub(log_en, 9000); + test (); + if (log_en > 0) + { + log_en = 0; move16 (); + } + test (); + if (sub(log_en, -14436) < 0) + { + log_en = -14436; move16 (); + } + + /* past_qua_en for other modes than MR122 */ + predState->past_qua_en[0] = log_en; move16 (); + predState->past_qua_en[1] = log_en; move16 (); + predState->past_qua_en[2] = log_en; move16 (); + predState->past_qua_en[3] = log_en; move16 (); + + /* scale down by factor 20*log10(2) in Q15 */ + log_en = mult(5443, log_en); + + /* past_qua_en for mode MR122 */ + predState->past_qua_en_MR122[0] = log_en; move16 (); + predState->past_qua_en_MR122[1] = log_en; move16 (); + predState->past_qua_en_MR122[2] = log_en; move16 (); + predState->past_qua_en_MR122[3] = log_en; move16 (); + + /* make sure that LSP's are ordered */ + Lsp_lsf(lsp, lsf, M); + Reorder_lsf(lsf, LSF_GAP, M); + Lsf_lsp(lsf, lsp, M); + + /* Quantize lsp and put on parameter list */ + Q_plsf_3(qSt, MRDTX, lsp, lsp_q, st->lsp_index, + &st->init_lsf_vq_index); + } + + *(*anap)++ = st->init_lsf_vq_index; /* 3 bits */ move16 (); + + *(*anap)++ = st->lsp_index[0]; /* 8 bits */ move16 (); + *(*anap)++ = st->lsp_index[1]; /* 9 bits */ move16 (); + *(*anap)++ = st->lsp_index[2]; /* 9 bits */ move16 (); + + + *(*anap)++ = st->log_en_index; /* 6 bits */ move16 (); + /* = 35 bits */ + + return 0; +} + +/* +************************************************************************** +* +* Function : dtx_buffer +* Purpose : handles the DTX buffer +* +************************************************************************** +*/ +int dtx_buffer(dtx_encState *st, /* i/o : State struct */ + Word16 lsp_new[], /* i : LSP vector */ + Word16 speech[] /* i : speech samples */ + ) +{ + Word16 i; + Word32 L_frame_en; + Word16 log_en_e; + Word16 log_en_m; + Word16 log_en; + + /* update pointer to circular buffer */ + st->hist_ptr = add(st->hist_ptr, 1); + test (); + if (sub(st->hist_ptr, DTX_HIST_SIZE) == 0) + { + st->hist_ptr = 0; move16 (); + } + + /* copy lsp vector into buffer */ + Copy(lsp_new, &st->lsp_hist[st->hist_ptr * M], 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, speech[i], speech[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, 8521); + + /* insert into log energy buffer with division by 2 */ + log_en = shr(log_en, 1); + st->log_en_hist[st->hist_ptr] = log_en; /* Q10 */ move16 (); + + return 0; +} + +/* +************************************************************************** +* +* Function : tx_dtx_handler +* Purpose : adds extra speech hangover to analyze speech on the decoding side. +* +************************************************************************** +*/ +Word16 tx_dtx_handler(dtx_encState *st, /* i/o : State struct */ + Word16 vad_flag, /* i : vad decision */ + enum Mode *usedMode /* i/o : mode changed or not */ + ) +{ + Word16 compute_new_sid_possible; + + /* this state machine is in synch with the GSMEFR txDtx machine */ + st->decAnaElapsedCount = add(st->decAnaElapsedCount, 1); + + compute_new_sid_possible = 0; move16(); + + test(); + if (vad_flag != 0) + { + st->dtxHangoverCount = DTX_HANG_CONST; move16(); + } + else + { /* non-speech */ + test(); + if (st->dtxHangoverCount == 0) + { /* out of decoder analysis hangover */ + st->decAnaElapsedCount = 0; move16(); + *usedMode = MRDTX; move16(); + compute_new_sid_possible = 1; move16(); + } + else + { /* in possible analysis hangover */ + st->dtxHangoverCount = sub(st->dtxHangoverCount, 1); + + /* decAnaElapsedCount + dtxHangoverCount < DTX_ELAPSED_FRAMES_THRESH */ + test (); + if (sub(add(st->decAnaElapsedCount, st->dtxHangoverCount), + DTX_ELAPSED_FRAMES_THRESH) < 0) + { + *usedMode = MRDTX; move16(); + /* if short time since decoder update, do not add extra HO */ + } + /* + else + override VAD and stay in + speech mode *usedMode + and add extra hangover + */ + } + } + + return compute_new_sid_possible; +} diff -r 85e9768d497f -r 5a1d18542f8a libtwamr/dtx_enc.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libtwamr/dtx_enc.h Tue May 07 00:05:12 2024 +0000 @@ -0,0 +1,110 @@ +/* +******************************************************************************** +* +* 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_enc.h +* Purpose : DTX mode computation of SID parameters +* +******************************************************************************** +*/ +#ifndef dtx_enc_h +#define dtx_enc_h "$Id $" + +/* +******************************************************************************** +* INCLUDE FILES +******************************************************************************** +*/ +#include "tw_amr.h" +#include "typedef.h" +#include "cnst.h" +#include "q_plsf.h" +#include "gc_pred.h" +#include "dtx_common.h" + +/* +******************************************************************************** +* DEFINITION OF DATA TYPES +******************************************************************************** +*/ +typedef struct { + Word16 lsp_hist[M * DTX_HIST_SIZE]; + Word16 log_en_hist[DTX_HIST_SIZE]; + Word16 hist_ptr; + Word16 log_en_index; + Word16 init_lsf_vq_index; + Word16 lsp_index[3]; + + /* DTX handler stuff */ + Word16 dtxHangoverCount; + Word16 decAnaElapsedCount; + +} dtx_encState; +/* +******************************************************************************** +* DECLARATION OF PROTOTYPES +******************************************************************************** +*/ + +/* +************************************************************************** +* +* Function : dtx_enc_reset +* Purpose : Resets state memory +* Returns : 0 on success +* +************************************************************************** +*/ +void dtx_enc_reset (dtx_encState *st); + +/* +************************************************************************** +* +* Function : dtx_enc +* Purpose : +* Description : +* +************************************************************************** +*/ +int dtx_enc(dtx_encState *st, /* i/o : State struct */ + Word16 computeSidFlag, /* i : compute SID */ + Q_plsfState *qSt, /* i/o : Qunatizer state struct */ + gc_predState* predState, /* i/o : State struct */ + Word16 **anap /* o : analysis parameters */ + ); + +/* +************************************************************************** +* +* Function : dtx_buffer +* Purpose : handles the DTX buffer +* +************************************************************************** +*/ +int dtx_buffer(dtx_encState *st, /* i/o : State struct */ + Word16 lsp_new[], /* i : LSP vector */ + Word16 speech[] /* i : speech samples */ + ); + +/* +************************************************************************** +* +* Function : tx_dtx_handler +* Purpose : adds extra speech hangover to analyze speech on the decoding side. +* Description : returns 1 when a new SID analysis may be made +* otherwise it adds the appropriate hangover after a sequence +* with out updates of SID parameters . +* +************************************************************************** +*/ +Word16 tx_dtx_handler(dtx_encState *st, /* i/o : State struct */ + Word16 vadFlag, /* i : vad control variable */ + enum Mode *usedMode /* o : mode changed or not */ + ); + +#endif diff -r 85e9768d497f -r 5a1d18542f8a libtwamr/namespace.list --- a/libtwamr/namespace.list Mon May 06 23:32:59 2024 +0000 +++ b/libtwamr/namespace.list Tue May 07 00:05:12 2024 +0000 @@ -51,6 +51,9 @@ sid_sync sid_sync_reset sid_sync_set_handover_debt ton_stab_reset check_lsp check_gp_clipping update_gp_clipping +dtx_dec dtx_dec_reset dtx_dec_activity_update rx_dtx_handler +dtx_enc dtx_enc_reset dtx_buffer tx_dtx_handler + Bits2prm Prm2bits bitno prmno prmnofs gray dgray