comparison libgsmhr1/rxfe.c @ 581:e2d5cad04cbf

libgsmhr1 RxFE: store CN R0+LPC separately from speech In the original GSM 06.06 code the ECU for speech mode is entirely separate from the CN generator, maintaining separate state. (The main intertie between them is the speech vs CN state variable, distinguishing between speech and CN BFIs, in addition to the CN-specific function of distinguishing between initial and update SIDs.) In the present RxFE implementation I initially thought that we could use the same saved_frame buffer for both ECU and CN, overwriting just the first 4 params (R0 and LPC) when a valid SID comes in. However, I now realize it was a bad idea: the original code has a corner case (long sequence of speech-mode BFIs to put the ECU in state 6, then SID and CN-mode BFIs, then a good speech frame) that would be broken by that buffer reuse approach. We could eliminate this corner case by resetting the ECU state when passing through a CN insertion period, but doing so would needlessly increase the behavioral diffs between GSM 06.06 and our version. Solution: use a separate CN-specific buffer for CN R0+LPC parameters, and match the behavior of GSM 06.06 code in this regard.
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 13 Feb 2025 10:02:45 +0000
parents d4979cdbc081
children
comparison
equal deleted inserted replaced
580:d4979cdbc081 581:e2d5cad04cbf
220 220
221 static void cn_output(struct gsmhr_rxfe_state *st, Shortword *prm_out) 221 static void cn_output(struct gsmhr_rxfe_state *st, Shortword *prm_out)
222 { 222 {
223 int i; 223 int i;
224 224
225 memcpy(prm_out, st->saved_frame, sizeof(Shortword) * 4); 225 memcpy(prm_out, st->cn_r0_lpc, sizeof(Shortword) * 4);
226 prm_out[4] = 1; /* soft interpolation */ 226 prm_out[4] = 1; /* soft interpolation */
227 prm_out[5] = 0; /* unvoiced mode */ 227 prm_out[5] = 0; /* unvoiced mode */
228 for (i = 0; i < N_SUB; i++) { 228 for (i = 0; i < N_SUB; i++) {
229 prm_out[6 + i * 3] = getPnBits(7, &st->cn_prng); 229 prm_out[6 + i * 3] = getPnBits(7, &st->cn_prng);
230 prm_out[7 + i * 3] = getPnBits(7, &st->cn_prng); 230 prm_out[7 + i * 3] = getPnBits(7, &st->cn_prng);
274 break; 274 break;
275 case CNIFIRSTSID: 275 case CNIFIRSTSID:
276 if (dtxd_sp) 276 if (dtxd_sp)
277 *dtxd_sp = 0; 277 *dtxd_sp = 0;
278 if (frame_class == VALIDSID) 278 if (frame_class == VALIDSID)
279 memcpy(st->saved_frame, prm_in, sizeof(Shortword) * 4); 279 memcpy(st->cn_r0_lpc, prm_in, sizeof(Shortword) * 4);
280 else
281 memcpy(st->cn_r0_lpc, st->saved_frame,
282 sizeof(Shortword) * 4);
280 init_cn_gen(st); 283 init_cn_gen(st);
281 cn_output(st, prm_out); 284 cn_output(st, prm_out);
282 break; 285 break;
283 case CNICONT: 286 case CNICONT:
284 if (dtxd_sp) 287 if (dtxd_sp)
285 *dtxd_sp = 0; 288 *dtxd_sp = 0;
286 if (frame_class == VALIDSID) 289 if (frame_class == VALIDSID)
287 memcpy(st->saved_frame, prm_in, sizeof(Shortword) * 4); 290 memcpy(st->cn_r0_lpc, prm_in, sizeof(Shortword) * 4);
288 else 291 else
289 deco_mode = CNIBFI; /* for interpolation */ 292 deco_mode = CNIBFI; /* for interpolation */
290 st->dtx_bfi_count = 0; 293 st->dtx_bfi_count = 0;
291 st->dtx_muting = 0; 294 st->dtx_muting = 0;
292 cn_output(st, prm_out); 295 cn_output(st, prm_out);
294 case CNIBFI: 297 case CNIBFI:
295 if (dtxd_sp) 298 if (dtxd_sp)
296 *dtxd_sp = 0; 299 *dtxd_sp = 0;
297 if (st->dtx_muting) { 300 if (st->dtx_muting) {
298 if (fast_cn_muting) 301 if (fast_cn_muting)
299 st->saved_frame[0] = 0; 302 st->cn_r0_lpc[0] = 0;
300 else { 303 else {
301 st->saved_frame[0] -= 2; 304 st->cn_r0_lpc[0] -= 2;
302 if (st->saved_frame[0] < 0) 305 if (st->cn_r0_lpc[0] < 0)
303 st->saved_frame[0] = 0; 306 st->cn_r0_lpc[0] = 0;
304 } 307 }
305 } 308 }
306 st->dtx_bfi_count++; 309 st->dtx_bfi_count++;
307 if (st->dtx_bfi_count >= (prm_in[21] ? 25 : 36)) 310 if (st->dtx_bfi_count >= (prm_in[21] ? 25 : 36))
308 st->dtx_muting = 1; 311 st->dtx_muting = 1;