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 "constants.h"
12 : #include "functions.h"
13 :
14 0 : void processPLCapply_fx(
15 : Word16 *concealMethod,
16 : Word16 nbLostFramesInRow, Word16 bfi, Word16 prev_bfi,
17 : Word16 frame_length, Word16 la_zeroes,
18 : #ifdef ENABLE_HR_MODE
19 : const Word32 w[],
20 : #else
21 : const Word16 w[],
22 : #endif
23 : Word16 x_fx[], Word16 ola_mem[],
24 : Word16 *ola_mem_exp, Word16 q_old_d_fx[], Word16 *q_old_fx_exp, Word32 q_d_fx[],
25 : Word16 *q_fx_exp, Word16 yLen, Word16 fs_idx, Word16 *damping, Word16 old_pitch_int,
26 : Word16 old_pitch_fr, Word16 *ns_cum_alpha, Word16 *ns_seed, Word16 frame_dms, AplcSetup *plcAd,
27 : Word8 *scratchBuffer
28 : #ifdef ENABLE_HR_MODE
29 : , Word16 hrmode
30 : #endif
31 : , Word32 rel_pitch_change
32 : , Word16 *alpha_type_2_table
33 : )
34 : {
35 : Dyn_Mem_Deluxe_In(
36 : Counter i;
37 : Word32 *d2_fx;
38 : Word32 *q_old_d_fx32;
39 : Word32 *r_fx;
40 : Word32 *tdc_A_32;
41 : Word16 d2_fx_exp;
42 : Word16 r_fx_exp;
43 : Word16 Q_syn;
44 : Word8 * buffer_perBandEnergy, *buffer_preEmphasis, *buffer_InverseODFT, *buffer_Levinson,
45 : *buffer_tdac, *buffer_phecu;
46 : Word16 y_e; /*exponent of L_ecu_rec */
47 : Word16 tmp_is_trans[2]; /* may be changed to a single variable */
48 : Word16 env_stab;
49 :
50 : Word16 n_bands, prev_bfi_plc2;
51 : const Word16 *band_offsets;
52 : Word32 * L_ecu_rec; /* local xtda output is MAX_LEN -> input buffer,
53 : as tmp buffer for w32 fft MAX_LPROT */
54 : );
55 0 : Word16 consecutiveLostThreshold = 0;
56 :
57 : #ifndef ENABLE_HR_MODE
58 : UNUSED(rel_pitch_change);
59 : #endif
60 :
61 : Word16 thresh_tdc_cnt;
62 : Word16 thresh_ns_cnt;
63 : Word16 thresh_tdc_ns_cnt;
64 :
65 0 : band_offsets = NULL;
66 :
67 0 : d2_fx = (Word32 *)scratchAlign(scratchBuffer, 0); /* Size = 4 * MAX_BANDS_NUMBER_PLC */
68 0 : q_old_d_fx32 = (Word32 *)scratchAlign(d2_fx, sizeof(*d2_fx) * MAX_BANDS_NUMBER_PLC); /* Size = 4 * MAX_BW */
69 0 : r_fx = (Word32 *)scratchAlign(d2_fx, sizeof(*d2_fx) * MAX_BANDS_NUMBER_PLC); /* Size = 4 * (M + 1) */
70 0 : tdc_A_32 = (Word32 *)scratchAlign(r_fx, sizeof(*r_fx) * (M + 1)); /* Size = 4 * (M + 1) */
71 :
72 0 : L_ecu_rec = (Word32 *)scratchAlign(tdc_A_32, sizeof(*tdc_A_32) * (M + 1)); /* Size = 4 * MAX_LPROT bytes */
73 :
74 0 : buffer_perBandEnergy =
75 0 : (Word8 *)scratchAlign(q_old_d_fx32, sizeof(*q_old_d_fx32) * (MAX_LEN)); /* Size = 2 * MAX_BANDS_NUMBER_PLC */
76 0 : buffer_preEmphasis =
77 0 : (Word8 *)scratchAlign(tdc_A_32, sizeof(*tdc_A_32) * (M + 1)); /* Size = 2 * MAX_BANDS_NUMBER_PLC */
78 0 : buffer_InverseODFT = buffer_preEmphasis; /* Size = 640 bytes */
79 0 : buffer_Levinson = buffer_preEmphasis; /* Size = 4 * (M + 1) */
80 :
81 0 : buffer_tdac = scratchBuffer; /* Size = 2 * MAX_LEN bytes */
82 0 : buffer_phecu = scratchBuffer; /* Size = 2 * MAX_LGW + 8 * MAX_LPROT + 12 * MAX_L_FRAME */
83 : /* Buffers overlap since they are not used at once */
84 :
85 :
86 : UNUSED(ns_cum_alpha);
87 : UNUSED(ns_seed);
88 :
89 : /* Apply/Prepare PLC in bfi-case */
90 0 : IF (sub(bfi, 1) == 0)
91 : {
92 0 : SWITCH(frame_dms)
93 : {
94 0 : case 25:
95 0 : consecutiveLostThreshold = 16;
96 0 : thresh_tdc_cnt = THRESH_025_DMS_TDC_CNT;
97 0 : thresh_ns_cnt = THRESH_025_DMS_NS_CNT;
98 0 : thresh_tdc_ns_cnt = THRESH_025_DMS_TDC_NS_CNT;
99 0 : break;
100 0 : case 50: consecutiveLostThreshold = 8;
101 0 : thresh_tdc_cnt = THRESH_050_DMS_TDC_CNT;
102 0 : thresh_ns_cnt = THRESH_050_DMS_NS_CNT;
103 0 : thresh_tdc_ns_cnt = THRESH_050_DMS_TDC_NS_CNT;
104 0 : break;
105 0 : case 75: consecutiveLostThreshold = 6;
106 0 : thresh_tdc_cnt = THRESH_075_DMS_TDC_CNT;
107 0 : thresh_ns_cnt = THRESH_075_DMS_NS_CNT;
108 0 : thresh_tdc_ns_cnt = THRESH_075_DMS_TDC_NS_CNT;
109 0 : break;
110 0 : case 100: consecutiveLostThreshold = 4;
111 0 : thresh_tdc_cnt = THRESH_100_DMS_TDC_CNT;
112 0 : thresh_ns_cnt = THRESH_100_DMS_NS_CNT;
113 0 : thresh_tdc_ns_cnt = THRESH_100_DMS_TDC_NS_CNT;
114 0 : break;
115 0 : default: assert(0);
116 : }
117 :
118 0 : IF (sub(fs_idx, 2) == 0 || sub(fs_idx, 4) >= 0)
119 : {
120 0 : if (sub(plcAd->longterm_counter_plcTdc, thresh_tdc_cnt) < 0){
121 0 : plcAd->plc_fadeout_type = 1;
122 : }
123 0 : else if (sub(plcAd->longterm_counter_plcNsAdv, thresh_ns_cnt) < 0){
124 0 : plcAd->plc_fadeout_type = 1;
125 : }
126 0 : else if (sub(plcAd->longterm_counter_plcTdc + plcAd->longterm_counter_plcNsAdv, thresh_tdc_ns_cnt) < 0){
127 0 : plcAd->plc_fadeout_type = 1;
128 : }
129 : else {
130 0 : plcAd->plc_fadeout_type = 0;
131 : }
132 :
133 0 : env_stab = norm_s(plcAd->longterm_analysis_counter_max);
134 0 : IF(sub(shl_pos(plcAd->overall_counter, env_stab), mult(shl_pos(plcAd->longterm_analysis_counter_max, env_stab), PLC_LONGTERM_ANALYSIS_STARTUP_FILL)) < 0)
135 : {
136 0 : plcAd->plc_fadeout_type = 0;
137 : }
138 : #ifdef ENABLE_HR_MODE
139 0 : IF (L_sub(rel_pitch_change,REL_PITCH_THRESH) > 0 && sub(hrmode,1) == 0 && (sub(frame_dms,50) == 0 || sub(frame_dms,25) == 0)){
140 0 : plcAd->plc_fadeout_type = 2;move16();
141 : } ELSE
142 : #endif
143 0 : IF((sub(nbLostFramesInRow, consecutiveLostThreshold) < 0) && (*concealMethod != LC3_CON_TEC_PHASE_ECU))
144 : {
145 0 : plcAd->plc_fadeout_type = 0;
146 : }
147 : } ELSE {
148 0 : plcAd->plc_fadeout_type = 0; /*fs_idx == 0,1,3 */
149 : }
150 :
151 0 : SWITCH (*concealMethod)
152 : {
153 0 : case LC3_CON_TEC_PHASE_ECU:
154 0 : ASSERT(frame_dms == 100);
155 : /* call phaseEcu */
156 0 : env_stab = 32767; move16(); /* 1.0=stable , 0.0=dynamic Q15*/
157 0 : tmp_is_trans[0] = plcAd->PhECU_short_flag_prev; move16();
158 0 : tmp_is_trans[1] = plcAd->PhECU_short_flag_prev; move16();
159 :
160 0 : ASSERT(prev_bfi == 0 || prev_bfi == 1|| prev_bfi == 2); /*PC prev_bfi has three states */
161 0 : prev_bfi_plc2 = prev_bfi; move16();
162 0 : if (sub(prev_bfi_plc2, 2) == 0)
163 : {
164 0 : prev_bfi_plc2 = 0; move16();
165 : }
166 :
167 0 : ASSERT(prev_bfi_plc2 == 0 || prev_bfi_plc2 == 1); /*PhEcu does not accept prev_bfi == 2 */
168 0 : IF(prev_bfi_plc2 == 0)
169 : { /* convert pitch lag info at current fs to a normalized fractional bin-frequency */
170 0 : plcAd->PhECU_f0hzLtpBinQ7 = plc_phEcuSetF0Hz_fx(fs_idx, old_pitch_int, old_pitch_fr); move16();
171 :
172 :
173 :
174 : /* first bfi frame calc decoded pcm energy 16,16 ms, in 26 ms buffer separated by 10 ms*/
175 :
176 : { /* compute energy normalization needed for concealment method 2 Xavg and transient analysis */
177 :
178 : /* left */
179 0 : processPLCUpdateXFP_w_E_hist_fx(0, 0,
180 0 : &(plcAd->x_old_tot_fx[ sub(plcAd->max_len_pcm_plc , add(num_FsByResQ0[fs_idx],rectLengthTab[fs_idx] )) ]), plcAd->q_fx_old_exp,0,
181 :
182 : fs_idx,
183 : &plcAd->PhECU_L_oold_xfp_w_E_fx, &plcAd->PhECU_oold_xfp_w_E_exp_fx,
184 : &plcAd->PhECU_L_old_xfp_w_E_fx, &plcAd->PhECU_old_xfp_w_E_exp_fx,
185 : &plcAd->PhECU_oold_Ltot_exp_fx, &plcAd->PhECU_old_Ltot_exp_fx);
186 :
187 : /* right */
188 0 : processPLCUpdateXFP_w_E_hist_fx(0, 0, plcAd->PhECU_xfp_fx, plcAd->PhECU_xfp_exp_fx,
189 0 : plcAd->PhECU_margin_xfp, fs_idx,
190 : &plcAd->PhECU_L_oold_xfp_w_E_fx, &plcAd->PhECU_oold_xfp_w_E_exp_fx,
191 : &plcAd->PhECU_L_old_xfp_w_E_fx, &plcAd->PhECU_old_xfp_w_E_exp_fx,
192 : &plcAd->PhECU_oold_Ltot_exp_fx, &plcAd->PhECU_old_Ltot_exp_fx);
193 : }
194 : }
195 :
196 0 : hq_phase_ecu_fx(
197 0 : plcAd->PhECU_xfp_fx, /* i : only valid first Bfi frame , buffer of previous synt signal length */
198 : L_ecu_rec, /* o : reconstructed frame in folded tda domain xtda Word32 Q x */
199 : &plcAd->PhECU_time_offs, /* i/o: Sample offset for consecutive frame losses*/
200 : plcAd->PhECU_X_sav_fx, /* i(prev_bfi==1)/o(prev_bfi==0): Stored Complex spectrum of prototype frame */
201 : &plcAd->PhECU_X_savQ_fx, /* i/o: Q value of stored spectrum */
202 : &plcAd->PhECU_num_plocs, /* i/o: Number of identified peaks */
203 : plcAd->PhECU_plocs, /* i/o: Peak locations Q0 */
204 : plcAd->PhECU_f0est, /* i/o: Interpolated peak locations Q16 */
205 : env_stab, /* i : Envelope stability parameter */
206 0 : plcAd->PhECU_f0hzLtpBinQ7, /* i: LTP bin frequency in normalized Hz Q7 */
207 0 : plcAd->norm_corrQ15_fx, /* i : correlation for lag at f0hzLtpBinQ7 */
208 : prev_bfi_plc2, /* i : indicating burst frame error */
209 : tmp_is_trans, /* i : flags indicating previous transient frames */
210 0 : plcAd->PhECU_mag_chg_1st, /* i/o: per band magnitude modifier for transients*/
211 : NULL, /* o: dbg per band magnitude modifier, incl. burst attenuation */
212 0 : plcAd->PhECU_Xavg, /* i/o: Frequency group average gain to fade to */
213 : &plcAd->PhECU_beta_mute, /* o : Factor for long-term mute */
214 : fs_idx, /* i : Encoded bandwidth "nb(0),WB,sWB,WB,FB" */
215 : frame_length, /* i : frame length */
216 : NULL , /* o : seed synch dbg */
217 : NULL , /* o : evolved Spectrum dbg */
218 0 : plcAd->PhECU_t_adv, /* i : time adjustment excluding time_offs */
219 : PhECU_wins[fs_idx][2], /* i: 2 ms initial part pre_tda = mdct-ana */
220 : PhECU_wins[fs_idx][1], /* i: 16 ms pretda combined part IWHR+MDCT-ana */
221 : PhECU_wins[fs_idx][0],
222 0 : plcAd->PhECU_xfp_exp_fx,
223 0 : plcAd->max_lprot,
224 0 : plcAd->max_plocs,
225 0 : plcAd->PhECU_L_oold_xfp_w_E_fx,plcAd->PhECU_oold_xfp_w_E_exp_fx, plcAd->PhECU_oold_Ltot_exp_fx,
226 0 : plcAd->PhECU_oold_grp_shape_fx,
227 0 : plcAd->PhECU_L_old_xfp_w_E_fx,plcAd->PhECU_old_xfp_w_E_exp_fx, plcAd->PhECU_old_Ltot_exp_fx,
228 0 : plcAd->PhECU_old_grp_shape_fx,
229 0 : plcAd->PhECU_margin_xfp,
230 0 : plcAd->plc_fadeout_type , /* i : fadeout scheme */
231 : &(plcAd->PhECU_nonpure_tone_flag), /* i/o : non-pure single tone indicator state */
232 : buffer_phecu);
233 :
234 0 : y_e = 18; move16(); /* the fixed exponent (exp) from Lecu_rec from PhaseECU is 18 */
235 :
236 0 : Processing_ITDA_WIN_OLA(
237 : L_ecu_rec, /* i: X_TDA buffer data = "y" DCT-IV output */
238 : &y_e, /* i/o: x_tda exponent "y_e" */
239 : w, /* i: window coefficients including normalization of sqrt(2/N) and scaled by 2^4 */
240 : ola_mem, /* i/o: overlap add memory */
241 : ola_mem_exp, /* i/o: overlap add exponent */
242 : x_fx, /* o: time signal out */
243 0 : LowDelayShapes_n960_len[fs_idx], /* i: window length */
244 : frame_length, /* i: block size */
245 0 : sub(frame_length, LowDelayShapes_n960_la_zeroes[fs_idx]) /* i: overlap add buffer size */
246 : );
247 0 : *q_fx_exp = y_e; move16(); /* assign updated Q */
248 0 : BREAK;
249 :
250 0 : case LC3_CON_TEC_TDPLC:
251 0 : IF (sub(nbLostFramesInRow, 1) == 0)
252 : {
253 0 : plcAd->tdc_fract = old_pitch_fr; move16();
254 0 : n_bands = s_min(frame_length, MAX_BANDS_NUMBER_PLC);
255 0 : SWITCH (frame_dms)
256 : {
257 0 : case 25:
258 0 : band_offsets = bands_offset_lin_2_5ms[fs_idx]; move16();
259 0 : IF (sub(fs_idx, 4) == 0)
260 : {
261 0 : n_bands = 60; move16();
262 : }
263 0 : BREAK;
264 0 : case 50:
265 0 : band_offsets = bands_offset_lin_5ms[fs_idx]; move16();
266 0 : IF (sub(fs_idx, 2) == 0)
267 : {
268 0 : n_bands = 40; move16();
269 : }
270 0 : BREAK;
271 0 : case 75:
272 0 : band_offsets = bands_offset_lin_7_5ms[fs_idx]; move16();
273 : #ifdef ENABLE_HR_MODE
274 0 : IF (sub(fs_idx, 5) != 0)
275 : {
276 : #endif
277 0 : IF (sub(fs_idx, 3) != 0)
278 : {
279 0 : n_bands = 60; move16();
280 : }
281 : #ifdef ENABLE_HR_MODE
282 : }
283 : #endif
284 0 : BREAK;
285 0 : case 100:
286 0 : band_offsets = bands_offset_lin[fs_idx]; move16();
287 0 : BREAK;
288 : }
289 :
290 0 : FOR (i = 0; i < yLen; i++)
291 : {
292 0 : q_old_d_fx32[i] = L_deposit_h(q_old_d_fx[i]);
293 : }
294 :
295 : /* LPC Analysis */
296 : /* calculate per band energy*/
297 0 : processPerBandEnergy_fx(d2_fx, &d2_fx_exp, q_old_d_fx32, *q_old_fx_exp, band_offsets, fs_idx, n_bands,
298 : 1, frame_dms, buffer_perBandEnergy
299 : #ifdef ENABLE_HR_MODE
300 : , hrmode
301 : #endif
302 : );
303 :
304 : /* calculate pre-emphasis */
305 0 : processPreEmphasis_fx(d2_fx, &d2_fx_exp, fs_idx, n_bands, frame_dms, buffer_preEmphasis);
306 :
307 : /* inverse ODFT */
308 0 : processInverseODFT_fx(r_fx, &r_fx_exp, d2_fx, d2_fx_exp, n_bands, plcAd->tdc_lpc_order, buffer_InverseODFT);
309 :
310 : /* lag windowing */
311 0 : processLagwin_fx(r_fx, lag_win[fs_idx], plcAd->tdc_lpc_order);
312 :
313 : /* Levinson Durbin */
314 0 : processLevinson_fx(tdc_A_32, r_fx, plcAd->tdc_lpc_order, NULL, NULL, buffer_Levinson);
315 :
316 : /* 32Q27 -> 16Qx */
317 0 : processPLCLpcScaling_fx(tdc_A_32, plcAd->tdc_A, add(plcAd->tdc_lpc_order, 1));
318 : }
319 :
320 : /* call TD-PLC */
321 : /* Q_syn = plcAd->q_fx_old_exp; */ /* makes q_fx_old_exp
322 : available in processTimeDomainConcealment_Apply_fx() for
323 : debugging */
324 0 : processTimeDomainConcealment_Apply_fx(
325 0 : old_pitch_int, plcAd->tdc_preemph_fac, plcAd->tdc_A, plcAd->tdc_lpc_order, plcAd->x_old_tot_fx, frame_length, frame_dms,
326 0 : fs_idx, nbLostFramesInRow, sub(frame_length, la_zeroes), plcAd->stab_fac, &plcAd->tdc_fract,
327 : &plcAd->tdc_seed,
328 : &plcAd->tdc_gain_c, x_fx, &Q_syn, damping,
329 0 : plcAd->max_len_pcm_plc,
330 0 : plcAd->harmonicBuf_fx, plcAd->synthHist_fx, &plcAd->harmonicBuf_Q, scratchBuffer
331 0 : , plcAd->plc_fadeout_type
332 : , alpha_type_2_table
333 : );
334 :
335 : /* exponent of TD-PLC output */
336 0 : Q_syn = add(Q_syn, sub(15, plcAd->q_fx_old_exp));
337 0 : *q_fx_exp = sub(15, Q_syn); move16();
338 :
339 : /* TDAC */
340 0 : processTdac_fx(ola_mem, ola_mem_exp, x_fx, *q_fx_exp, w, la_zeroes, frame_length, buffer_tdac);
341 0 : BREAK;
342 :
343 0 : case LC3_CON_TEC_NS_ADV:
344 0 : *q_fx_exp = *q_old_fx_exp; move16();
345 :
346 : /* call Noise Substitution */
347 0 : processPLCNoiseSubstitution_fx(q_d_fx, q_old_d_fx, yLen);
348 :
349 0 : BREAK;
350 0 : default: ASSERT(!"Unsupported PLC method!");
351 : }
352 0 : }
353 :
354 : Dyn_Mem_Deluxe_Out();
355 0 : }
356 :
357 :
|