FreeCalypso > hg > gsm-codec-lib
view libgsmhr1/rxfe.c @ 579:1dc5d9320e96
libgsmhr1: implement RxFE block
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Thu, 13 Feb 2025 09:10:12 +0000 |
parents | |
children | d4979cdbc081 |
line wrap: on
line source
/* * Rx front end implementation, common between the full decoder and TFO. */ #include <stdint.h> #include <string.h> #include "tw_gsmhr.h" #include "typedefs.h" #include "namespace.h" #include "rxfe.h" #include "dtx_const.h" #include "dtx_rxfe.h" /* * If the very first frame(s) we have to process out of reset (or after DHF) * are either BFI or invalid SID, what is our default fallback frame? * In the original GSM 06.06 code it is a frame of all zero params - but * because that code provides only a full decoder and not TFO, this oddity * is not readily visible. (The PCM output from the full decoder is all * zeros.) OTOH, if we feed all zeros as PCM input to a homed standard * encoder, we get this frame, repeating endlessly as long as all-zeros * PCM input continues: * * R0=00 LPC=164,171,cb Int=0 Mode=0 * s1=00,00,00 s2=00,00,00 s3=00,00,00 s4=00,00,00 * * This frame differs from all-zero params only in the LPC set, and this * sane-LPC silence frame is the one we shall use as our reset-default * fallback frame. */ static const Shortword default_lpc[3] = {0x164, 0x171, 0xcb}; /* * UFI R0 handling tables: when we get a speech frame marked with BFI=0 UFI=1, * we look at the R0 parameter, both in the received frame and in the saved * one. Both of the following LUTs are indexed by old R0 just like in the * original GSM 06.06 code, but the values in them are absolute thresholds * for the new R0, instead of diff values used in the original code. */ static const Shortword ufi_r0_thresh_bfi[32] = { 15, 16, 17, 15, 16, 17, 18, 18, 18, 19, 19, 20, 21, 22, 22, 23, 23, 23, 23, 24, 25, 25, 26, 26, 26, 27, 28, 29, 30, 31, 32, 32 }; static const Shortword ufi_r0_thresh_mute[32] = { 14, 13, 13, 12, 13, 14, 15, 14, 15, 16, 17, 18, 18, 19, 20, 20, 21, 21, 21, 22, 23, 24, 25, 25, 25, 26, 27, 28, 29, 30, 30, 30 }; /* state transition tables for ECU state machine */ static const uint8_t ecu_state_trans_good[8] = {0, 0, 0, 0, 0, 0, 7, 0}; static const uint8_t ecu_state_trans_bad[8] = {1, 2, 3, 4, 5, 6, 6, 6}; void gsmhr_rxfe_reset(struct gsmhr_rxfe_state *st) { memset(st, 0, sizeof(struct gsmhr_rxfe_state)); memcpy(st->saved_frame + 1, default_lpc, sizeof(Shortword) * 3); st->ecu_state = 7; } static Shortword input_frame_class(Shortword bfi, Shortword ufi, Shortword sid) { Shortword bfi_dtx; bfi_dtx = bfi || ufi; if (sid == 2 && bfi_dtx == 0) return VALIDSID; if (sid == 0 && bfi_dtx == 0) return GOODSPEECH; if (sid == 0 && bfi_dtx != 0) return UNUSABLE; return INVALIDSID; } static Shortword compute_last_lag(const Shortword *prm_in) { Shortword accum, delta, i; accum = prm_in[6]; for (i = 0; i < 3; i++) { delta = prm_in[9 + i * 3] - 8; accum += delta; if (accum > 0xFF) accum = 0xFF; else if (accum < 0) accum = 0; } return accum; } static void save_speech_frame(struct gsmhr_rxfe_state *st, const Shortword *prm_in) { memcpy(st->saved_frame, prm_in, sizeof(Shortword) * 6); if (prm_in[5]) { /* voiced modes */ st->saved_frame[6] = compute_last_lag(prm_in); st->saved_frame[7] = prm_in[7]; st->saved_frame[9] = 8; st->saved_frame[10] = prm_in[10]; st->saved_frame[12] = 8; st->saved_frame[13] = prm_in[13]; st->saved_frame[15] = 8; st->saved_frame[16] = prm_in[16]; } else { /* unvoiced mode */ st->saved_frame[6] = prm_in[6]; st->saved_frame[7] = prm_in[7]; st->saved_frame[9] = prm_in[9]; st->saved_frame[10] = prm_in[10]; st->saved_frame[12] = prm_in[12]; st->saved_frame[13] = prm_in[13]; st->saved_frame[15] = prm_in[15]; st->saved_frame[16] = prm_in[16]; } /* all 4 gsp0 params come from the last subframe */ st->saved_frame[8] = prm_in[17]; st->saved_frame[11] = prm_in[17]; st->saved_frame[14] = prm_in[17]; st->saved_frame[17] = prm_in[17]; } static void speech_ecu(struct gsmhr_rxfe_state *st, const Shortword *prm_in, Shortword *prm_out, Shortword *mute_permit, Shortword *dtxd_sp) { Shortword bfi = prm_in[18]; Shortword ufi = prm_in[19]; uint8_t prev_state = st->ecu_state; if (ufi && !bfi) { if (prm_in[0] >= ufi_r0_thresh_bfi[st->saved_frame[0]]) bfi = 1; else if (prm_in[0] >= ufi_r0_thresh_mute[st->saved_frame[0]]) { if (mute_permit) *mute_permit = 1; } } if (bfi) st->ecu_state = ecu_state_trans_bad[prev_state]; else st->ecu_state = ecu_state_trans_good[prev_state]; switch (st->ecu_state) { case 0: memcpy(prm_out, prm_in, sizeof(Shortword) * GSMHR_NUM_PARAMS); save_speech_frame(st, prm_in); return; /* all remaining cases return the saved frame, differ only in R0 */ case 1: case 2: /* no muting yet */ break; case 3: case 4: case 5: st->saved_frame[0] -= 2; if (st->saved_frame[0] < 0) st->saved_frame[0] = 0; break; case 6: case 7: st->saved_frame[0] = 0; break; } memcpy(prm_out, st->saved_frame, sizeof(Shortword) * GSMHR_NUM_PARAMS); if (bfi < 2) { if (st->saved_frame[5] == 0 && prm_in[5] == 0) { /* both unvoiced */ prm_out[6] = prm_in[6]; prm_out[7] = prm_in[7]; prm_out[9] = prm_in[9]; prm_out[10] = prm_in[10]; prm_out[12] = prm_in[12]; prm_out[13] = prm_in[13]; prm_out[15] = prm_in[15]; prm_out[16] = prm_in[16]; } else if (st->saved_frame[5] != 0 && prm_in[5] != 0) { /* both voiced */ prm_out[7] = prm_in[7]; prm_out[10] = prm_in[10]; prm_out[13] = prm_in[13]; prm_out[16] = prm_in[16]; } } if (dtxd_sp && prev_state >= 6) *dtxd_sp = 0; } static void save_speech_gs(struct gsmhr_rxfe_state *st, const Shortword *sp_param) { Shortword vmode = sp_param[5]; uint8_t ptr = st->gs_history_ptr; int i; for (i = 0; i < N_SUB; i++) { st->gs_history[ptr] = ppLr_gsTable[vmode][sp_param[8 + i * 3]]; ptr++; if (ptr >= GS_HISTORY_SIZE) ptr = 0; } st->gs_history_ptr = ptr; } static void init_cn_gen(struct gsmhr_rxfe_state *st) { Longword L_RxDTXGs; st->cn_prng = PN_INIT_SEED; avgGsHistQntz(st->gs_history, &L_RxDTXGs); st->gs_cn_out = gsQuant(L_RxDTXGs, 0); st->dtx_bfi_count = 0; st->dtx_muting = 0; } static void cn_output(struct gsmhr_rxfe_state *st, Shortword *prm_out) { int i; memcpy(prm_out, st->saved_frame, sizeof(Shortword) * 4); prm_out[4] = 1; /* soft interpolation */ prm_out[5] = 0; /* unvoiced mode */ for (i = 0; i < N_SUB; i++) { prm_out[6 + i * 3] = getPnBits(7, &st->cn_prng); prm_out[7 + i * 3] = getPnBits(7, &st->cn_prng); prm_out[8 + i * 3] = st->gs_cn_out; } } void rxfe_main(struct gsmhr_rxfe_state *st, const Shortword *prm_in, Shortword *prm_out, int fast_cn_muting, Shortword *deco_mode_out, Shortword *mute_permit, Shortword *dtxd_sp) { Shortword frame_class, deco_mode; frame_class = input_frame_class(prm_in[18], prm_in[19], prm_in[20]); if (!st->in_dtx) { /* speech decoding mode */ if (frame_class == VALIDSID || frame_class == INVALIDSID) deco_mode = CNIFIRSTSID; else deco_mode = SPEECH; } else { /* comfort noise insertion mode */ if (frame_class == VALIDSID || frame_class == INVALIDSID) deco_mode = CNICONT; else if (frame_class == UNUSABLE) deco_mode = CNIBFI; else deco_mode = SPEECH; } /* Muting permission for the full decoder will be set only in one * special case of speech UFI - default it to 0. */ if (mute_permit) *mute_permit = 0; /* now real per-mode processing */ switch (deco_mode) { case SPEECH: /* Except for the special case of prolonged BFI that * led to total muting, TFO with DTXd gets SP=1. */ if (dtxd_sp) *dtxd_sp = 1; st->in_dtx = 0; speech_ecu(st, prm_in, prm_out, mute_permit, dtxd_sp); save_speech_gs(st, prm_out); break; case CNIFIRSTSID: if (dtxd_sp) *dtxd_sp = 0; st->in_dtx = 1; if (frame_class == VALIDSID) memcpy(st->saved_frame, prm_in, sizeof(Shortword) * 4); init_cn_gen(st); cn_output(st, prm_out); break; case CNICONT: if (dtxd_sp) *dtxd_sp = 0; st->in_dtx = 1; if (frame_class == VALIDSID) memcpy(st->saved_frame, prm_in, sizeof(Shortword) * 4); else deco_mode = CNIBFI; /* for interpolation */ st->dtx_bfi_count = 0; st->dtx_muting = 0; cn_output(st, prm_out); break; case CNIBFI: if (dtxd_sp) *dtxd_sp = 0; st->in_dtx = 1; if (st->dtx_muting) { if (fast_cn_muting) st->saved_frame[0] = 0; else { st->saved_frame[0] -= 2; if (st->saved_frame[0] < 0) st->saved_frame[0] = 0; } } st->dtx_bfi_count++; if (st->dtx_bfi_count >= (prm_in[21] ? 25 : 36)) st->dtx_muting = 1; cn_output(st, prm_out); break; } if (deco_mode_out) *deco_mode_out = deco_mode; }