Line data Source code
1 : /******************************************************************************
2 : * ETSI TS 103 634 V1.5.1 *
3 : * Low Complexity Communication Codec Plus (LC3plus) *
4 : * *
5 : * Copyright licence is solely granted through ETSI Intellectual Property *
6 : * Rights Policy, 3rd April 2019. No patent licence is granted by implication, *
7 : * estoppel or otherwise. *
8 : ******************************************************************************/
9 :
10 : #include "defines.h"
11 : #include "functions.h"
12 :
13 : static void processPLCcomputeStabFac(Word16 scf_q[], Word16 old_scf_q[], Word16 prev_bfi, Word16 *stab_fac);
14 :
15 0 : void processPLCUpdateAfterIMDCT_fx(Word16 x_fx[], Word16 q_fx_exp, Word16 concealMethod, Word16 xLen, Word16 fs_idx,
16 : Word16 *nbLostFramesInRow, Word16 *prev_prev_bfi, Word16 *prev_bfi, Word16 bfi, Word16 scf_q[],
17 : Word16 *ns_cum_alpha, AplcSetup *plcAd)
18 : {
19 : Word16 oldLen, usedHistlen;
20 : Word16 scale_fac_old, scale_fac_new, q_theo_new_old, q_theo_new_new, q_new, shift_old, shift_new;
21 : Word16 frontLen, pastLen;
22 : Word16 marginOldPast;
23 : Word16 marginNewXlen, marginOldFront;
24 :
25 : #ifdef DYNMEM_COUNT
26 : Dyn_Mem_In("processPLCUpdateAfterIMDCT_fx", sizeof(struct {
27 : Word16 oldLen, usedHistlen;
28 : Counter i;
29 : Word16 scale_fac_old, scale_fac_new, q_theo_new_old, q_theo_new_new, q_new, shift_old, shift_new;
30 : Word16 frontLen, pastLen;
31 : Word16 marginOldPast;
32 : Word16 scale_fac_old_dual;
33 : Word16 marginNewXlen, marginOldFront;
34 : }));
35 : #endif
36 :
37 :
38 :
39 :
40 : #ifdef WMOPS
41 : push_wmops("processPLCUpdateAfterIMDCT ");
42 : #endif
43 :
44 :
45 0 : if (plcAd)
46 : {
47 : /* for short NB frames(2.5 ms) TDC-filtering requires more PCM samples than the plc_xcorr function */
48 0 : usedHistlen = plcAd->max_len_pcm_plc;
49 :
50 :
51 0 : logic16();
52 0 : IF( (sub(bfi,1) == 0) && sub(concealMethod, LC3_CON_TEC_PHASE_ECU) == 0 && xLen == (Word16)(((double)LprotSzPtr[fs_idx])*0.625))
53 : { /* % reduced buffering update length during concealment method 2 as Xsav_fx is stored in the joint q_old_fx and pcmbufHist buffer */
54 0 : usedHistlen = sub(usedHistlen, sub(LprotSzPtr[fs_idx], s_min(MAX_BW_BIN, xLen)));
55 0 : ASSERT(xLen == (Word16)(((double)LprotSzPtr[fs_idx])*0.625)); /*/ only enter here for 10 ms cases */
56 :
57 : /* actually one can select to always update xLen(10 ms) less samples of x_old_tot, also in TDC-PLC bfi frames ,, and for PhECU.PLC */
58 : }
59 0 : oldLen = sub(usedHistlen, xLen);
60 :
61 : /* update ltpf-free pcm history buffer for TD-PLC */
62 :
63 0 : basop_memmove(&plcAd->x_old_tot_fx[plcAd->max_len_pcm_plc - usedHistlen],
64 0 : &plcAd->x_old_tot_fx[plcAd->max_len_pcm_plc - usedHistlen + xLen], oldLen * sizeof(Word16));
65 :
66 0 : basop_memcpy(&plcAd->x_old_tot_fx[plcAd->max_len_pcm_plc - xLen], &x_fx[0], xLen * sizeof(Word16));
67 :
68 : #ifdef ENABLE_HR_MODE
69 0 : frontLen = 0;
70 0 : IF (sub(fs_idx, 5) < 0)
71 : #endif
72 : {
73 0 : frontLen = sub(LprotSzPtr[fs_idx], xLen); /*16-10 = 6ms of the prev_synth/xfp part */
74 : }
75 0 : pastLen = sub(oldLen, frontLen); /* ~11.8 ms*/
76 :
77 0 : marginOldPast = getScaleFactor16_0(&(plcAd->x_old_tot_fx[plcAd->max_len_pcm_plc - usedHistlen]), pastLen);
78 0 : marginOldFront = getScaleFactor16_0(&(plcAd->x_old_tot_fx[plcAd->max_len_pcm_plc - usedHistlen + pastLen]), frontLen);
79 :
80 0 : scale_fac_old = s_min(marginOldFront, marginOldPast);
81 :
82 0 : frontLen = 0; move16();
83 0 : logic16(); logic16();
84 0 : IF(bfi == 1 && *prev_bfi == 0 && sub(concealMethod, LC3_CON_TEC_PHASE_ECU) == 0)
85 : { /* prepare localized margin_xfp value for a next bad concealment Method 2 frame */
86 0 : frontLen = *nbLostFramesInRow;
87 0 : frontLen = add(hamm_len2Tab[fs_idx], shr(hamm_len2Tab[fs_idx], 2)); /* find margin in the 3.75 ms front part */
88 0 : pastLen = sub(xLen, frontLen);
89 0 : scale_fac_new = getScaleFactor16_0(&(x_fx[0]), pastLen);
90 0 : marginNewXlen = getScaleFactor16_0(&(x_fx[0]) + pastLen, frontLen); /* for pHEcuprev_synth in 2nd+ bfi frame */
91 :
92 0 : scale_fac_new = s_min(scale_fac_new, marginNewXlen);
93 : }
94 : ELSE
95 : { /* prepare margin value for any coming good frame or any coming first bad frame */
96 :
97 0 : marginNewXlen = getScaleFactor16_0(&(x_fx[0]),xLen); /* prevsynth in first bfi frame */
98 0 : scale_fac_new = marginNewXlen; move16();
99 : }
100 :
101 0 : q_theo_new_old = s_max(plcAd->q_fx_old_exp - scale_fac_old, 0);
102 0 : q_theo_new_new = s_max(q_fx_exp - scale_fac_new, 0);
103 :
104 0 : q_new = s_max(q_theo_new_old, q_theo_new_new);
105 :
106 0 : shift_old = plcAd->q_fx_old_exp - q_new;
107 0 : shift_new = q_fx_exp - q_new;
108 :
109 0 : IF(shift_old != 0)
110 : {
111 0 : Scale_sig(&plcAd->x_old_tot_fx[plcAd->max_len_pcm_plc - usedHistlen], oldLen, shift_old);
112 0 : logic16();
113 0 : test();
114 0 : IF ((sub(bfi,1) == 0) && (sub(concealMethod, LC3_CON_TEC_TDPLC) == 0))
115 : {
116 0 : plcAd->harmonicBuf_Q -= shift_old;
117 0 : plcAd->tdc_gain_c = L_shl_sat(plcAd->tdc_gain_c, shift_old);
118 : }
119 0 : move16(); /* count move to static RAM */
120 :
121 0 : marginOldFront = s_min(16, sub(marginOldFront, shift_old));
122 : }
123 0 : IF(shift_new)
124 : {
125 0 : Scale_sig(&plcAd->x_old_tot_fx[plcAd->max_len_pcm_plc - xLen], xLen, shift_new); /* positive shift_new means upshift=less margin */
126 0 : marginNewXlen = s_min(16, sub(marginNewXlen, shift_new));
127 : }
128 :
129 0 : plcAd->q_fx_old_exp = sub(q_fx_exp, shift_new);
130 :
131 0 : plcAd->PhECU_margin_xfp = s_min(marginNewXlen, marginOldFront); move16(); /* for pHECU winEncalc xfp energy calculations */
132 0 : if (frontLen != 0)
133 : { /* prepare margin value for a first pHECU(16 ms) or a consecutive bad PhEcu frame (3.75ms) */
134 0 : plcAd->PhECU_margin_xfp = marginNewXlen; move16();
135 : }
136 0 : if (sub(plcAd->PhECU_margin_xfp, 16) == 0)
137 : {
138 0 : plcAd->PhECU_margin_xfp = 1; move16(); /* "1" --> does not rescale the all-zero vector, inside PhECU */
139 : }
140 : }
141 :
142 : /* Update PLC params */
143 0 : IF(sub(bfi, 1) != 0)
144 : {
145 : /* % reset counters in GF */
146 0 : *nbLostFramesInRow = 0; move16();
147 0 : *ns_cum_alpha = 32767; move16();
148 :
149 0 : if (plcAd)
150 : {
151 0 : basop_memmove(plcAd->old_old_scf_q, plcAd->old_scf_q, M * sizeof(Word16));
152 0 : basop_memmove(plcAd->old_scf_q, scf_q, M * sizeof(Word16));
153 :
154 : /* PLC fullband transient detector setting for non-bfi frames */
155 0 : plcAd->PhECU_short_flag_prev = 0; move16(); /* fullband transient not active */
156 : }
157 : }
158 :
159 : /* values may be {0,1,2} */
160 0 : *prev_prev_bfi = *prev_bfi; move16();
161 0 : *prev_bfi = bfi; move16();
162 :
163 : #ifdef WMOPS
164 : pop_wmops();
165 : #endif
166 :
167 : #ifdef DYNMEM_COUNT
168 : Dyn_Mem_Out();
169 : #endif
170 0 : }
171 :
172 0 : void processPLCcomputeStabFac_main(Word16 scf_q[], Word16 old_scf_q[], Word16 old_old_scf_q[], Word16 bfi, Word16 prev_bfi,
173 : Word16 prev_prev_bfi, Word16 *stab_fac)
174 : {
175 0 : IF (sub(bfi, 1) == 0)
176 : {
177 0 : IF (sub(prev_bfi, 1) != 0)
178 : {
179 0 : processPLCcomputeStabFac(old_scf_q, old_old_scf_q, prev_prev_bfi, stab_fac);
180 : }
181 : }
182 0 : ELSE IF(sub(bfi, 2) == 0)
183 : {
184 0 : processPLCcomputeStabFac(scf_q, old_scf_q, prev_bfi, stab_fac);
185 : }
186 0 : }
187 :
188 0 : static void processPLCcomputeStabFac(Word16 scf_q[], Word16 old_scf_q[], Word16 prev_bfi, Word16 *stab_fac)
189 : {
190 : Counter i;
191 : Word32 tmp32;
192 : Word16 d;
193 :
194 : #ifdef DYNMEM_COUNT
195 : Dyn_Mem_In("calculateStabFac", sizeof(struct {
196 : Counter i;
197 : Word32 tmp32;
198 : Word16 d;
199 : }));
200 : #endif
201 :
202 : /* calculate stability factor */
203 0 : IF (sub(prev_bfi, 1) == 0)
204 : {
205 0 : *stab_fac = 26214; move16();
206 : }
207 : ELSE
208 : {
209 0 : tmp32 = 0; move32();
210 0 : FOR (i = 0; i < M; i++)
211 : {
212 0 : d = sub(scf_q[i], old_scf_q[i]);
213 0 : tmp32 = L_mac_sat(tmp32, d, d);
214 : }
215 0 : tmp32 = L_shl_sat(tmp32, 3);
216 0 : IF (tmp32 > 0x7D000000 /*1.25*25*/)
217 : {
218 0 : *stab_fac = 0; move16();
219 : }
220 0 : ELSE IF (tmp32 < 0x19003E82 /*0.25*25*/)
221 : {
222 0 : *stab_fac = 0x7FFF; move16();
223 : }
224 : ELSE
225 : {
226 0 : tmp32 = L_shl_pos(L_sub(0x50000000 /*1.25/2*/, Mpy_32_16_lc3plus(tmp32, 0x51EC /*16/25*/)), 1);
227 0 : *stab_fac = round_fx(tmp32); move16();
228 : }
229 : }
230 :
231 : #ifdef DYNMEM_COUNT
232 : Dyn_Mem_Out();
233 : #endif
234 0 : }
235 :
236 0 : void processPLCUpdateXFP_w_E_hist_fx(Word16 prev_bfi, Word16 bfi, Word16 *xfp_fx, Word16 xfp_exp_fx, Word16 margin_xfp,
237 : Word16 fs_idx,
238 : Word32 *L_oold_xfp_w_E_fx, Word16 *oold_xfp_w_E_exp_fx,
239 : Word32 *L_old_xfp_w_E_fx, Word16 *old_xfp_w_E_exp_fx,
240 :
241 : Word16 *oold_Ltot_exp_fx ,Word16 *old_Ltot_exp_fx )
242 :
243 : {
244 : Word32 L_tot ;
245 : Word16 dn_scale, exp_shift;
246 : Word16 used_xfp_exp_fx;
247 : Word16 exp_out ;
248 :
249 : #ifdef DYNMEM_COUNT
250 : Dyn_Mem_In("PLCUpdateXFP_w_E_hist", sizeof(struct {
251 : Word32 L_tot;
252 : Word16 dn_scale, exp_shift;
253 : Word16 used_xfp_exp_fx;
254 : Word16 exp_out;
255 : }));
256 : #endif
257 : #ifdef WMOPS
258 : push_wmops("PhECU::UpdateXfp_w_E_hist_fx");
259 : #endif
260 :
261 0 : IF (sub(bfi,1) != 0)
262 : {
263 :
264 0 : if (sub(prev_bfi,1) == 0)
265 : {
266 : /* only a single historic frame available in the next frame
267 : , force artifical update of oold energy to be the same as old */
268 0 : *old_xfp_w_E_exp_fx = LTOT_INIT_FLAG ; move16();
269 : }
270 :
271 : /* Time shift energy state and xfp exp */
272 0 : IF (sub_sat(*old_xfp_w_E_exp_fx, LTOT_INIT_FLAG ) == 0)
273 : {
274 0 : *L_oold_xfp_w_E_fx = LTOT_MIN_MAN ; move32();
275 0 : *oold_xfp_w_E_exp_fx = UNINIT_OR_UNSAFE_OOLD_SENTINEL ; move16();
276 : }
277 : ELSE
278 : {
279 0 : *L_oold_xfp_w_E_fx = *L_old_xfp_w_E_fx; move32(); /* regular update */
280 0 : *oold_xfp_w_E_exp_fx = *old_xfp_w_E_exp_fx; move16();
281 : }
282 :
283 : /* Time shift L_tot energy state and L_tot_exp */
284 0 : IF (sub_sat(*old_Ltot_exp_fx, LTOT_INIT_FLAG ) == 0)
285 : {
286 0 : *L_oold_xfp_w_E_fx = LTOT_MIN_MAN ; move32();
287 0 : *oold_Ltot_exp_fx = UNINIT_OR_UNSAFE_OOLD_SENTINEL ; move16();
288 : }
289 : ELSE
290 : {
291 0 : *L_oold_xfp_w_E_fx = *L_old_xfp_w_E_fx; move32(); /* regular update */
292 0 : *oold_Ltot_exp_fx = *old_Ltot_exp_fx; move16();
293 : }
294 :
295 :
296 0 : dn_scale = e_tot_headroom[fs_idx]; /* allowed minimum dn_scale for a max upshifted signal */
297 0 : used_xfp_exp_fx = xfp_exp_fx;
298 :
299 0 : IF( margin_xfp > 0 ) /* xfp_fx was normalized on a larger area than 16ms part of pcmBuffer */
300 : {
301 0 : ASSERT(bfi !=1) ; /* if bfi was set the margin_xfp does not reflect the correct 16ms part of pcm_buf hist, prev_synth */
302 0 : dn_scale = s_max(0, sub(e_tot_headroom[fs_idx], margin_xfp));
303 :
304 0 : exp_shift = sub(e_tot_headroom[fs_idx], dn_scale);
305 0 : used_xfp_exp_fx = sub(xfp_exp_fx, exp_shift); /* the virtual change of the xfp_buffer due to reduced downscaling in L_tot calc */
306 : }
307 :
308 : /* use semifixed dn_scale as adjusted by margin_xfp in 16 ms region */
309 0 : exp_out = xfp_exp_fx; move16();
310 0 : L_tot = winEnCalc(xfp_fx, dn_scale , PhECU_wins[fs_idx][0], rectLengthTab[fs_idx], hamm_len2Tab[fs_idx], &exp_out );
311 :
312 0 : *L_old_xfp_w_E_fx = L_tot; move32();
313 :
314 0 : *old_xfp_w_E_exp_fx = used_xfp_exp_fx ; move16();
315 : /* this now needs to be in Q1 , used_fx_exp , (exp_out-1-2*e_tot_headroom[fs_idx])/2 */
316 :
317 0 : *old_Ltot_exp_fx = exp_out; /* new proper _Ltot value from winEnCalc function */
318 :
319 :
320 : /* use true Word32 exponent of L_tot */
321 :
322 :
323 : /* restart oold and old from same state for init or prevBFI cases */
324 0 : logic16();
325 0 : IF (sub_sat(*oold_xfp_w_E_exp_fx, UNINIT_OR_UNSAFE_OOLD_SENTINEL) <= 0 || /* old xfp_Exp */
326 : sub_sat(*oold_Ltot_exp_fx, UNINIT_OR_UNSAFE_OOLD_SENTINEL) <= 0 ) /* new L_tot_exp */
327 : {
328 0 : *L_oold_xfp_w_E_fx = L_tot; move32();
329 0 : *oold_xfp_w_E_exp_fx = used_xfp_exp_fx; move16();
330 0 : *oold_Ltot_exp_fx = *old_Ltot_exp_fx; /* use Ltot exp value */
331 : }
332 : }
333 :
334 : #ifdef WMOPS
335 : pop_wmops();
336 : #endif
337 : #ifdef DYNMEM_COUNT
338 : Dyn_Mem_Out();
339 : #endif
340 0 : }
341 :
342 :
343 :
|