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 : #include "math.h" /*dbg*/
13 :
14 : /*---------------------------------------------------------------------*
15 : * Local constants
16 : *---------------------------------------------------------------------*/
17 :
18 : #define DELTA_CORR 5 /* Tuning parameter - defining range for phase correction around peak */
19 : #define DELTA_CORR_F0_INT 2 /* Tuning parameter - defining range for phase correction around peak */
20 :
21 : #define MAX_INCREASE_GRPPOW_FX 0 /* max. amplification in case of transients (in dB scale) */
22 :
23 : #define ONE_SIDED_SINE_WIDTH (4) /* expected pure sine main lobe maximum width (4+1+4) bins *62.5 hz/bin => approx 560 Hz total width */
24 : #define SIDE_LIM 12539859L /* 10^ (4.5/20.0) = 2^(a); --> x= 0.747433821 -> Lx_Q24 = round((1L<<(24))*0.747433821)) = 12539859 */
25 : #define LFHF_LIM 16719812L /* 10^ (6.0/20.0) = 2^(b); --> x= 0.996578428 -> Lx_Q24 = round((1L<<(24))*0.996578428)) = 16719812 */
26 :
27 : #define CMPLMNT_PLOC_SENS_FX 2294 /* (1.0 - p_locator_sens) in Q15 */
28 : #define FEC_HQ_ECU_ROOT2 23170 /*(0x5a83) */ /* sqrt(2) in Q14 */
29 : #define FEC_TWOTHIRDS_Q15 21845 /* round(2^15*2/3) */
30 :
31 : static void get_sin_cosQ10opt(Word16 phase, /* Q10 0..1023 i.e. 1024=2*pi */
32 : Word16 *ptrSin, /* Q15 */
33 : Word16 *ptrCos); /* Q15 */
34 :
35 : static Word16 sqrt2ndOrder(const Word16);
36 :
37 : void my_wtda_fx(const Word16 *new_audio, /* i : input audio to be windowed Q0 20 ms , OPT can be output as well */
38 : const Word16 *const win2ms_init, /* i: 2 ms initial part of pre_tda window */
39 : const Word16 *const win16ms_center, /* i: 16 ms combined part of pre_tda IWHR+MDCT-ana */
40 : Word32 * L_wtda_audio, /* o : tda audio Q16 20 ms */
41 : const Word16 L, Word8 *scratchBuffer);
42 :
43 : static void windowing_L(const Word16 *, Word32 *, const Word16 *, const Word16, const Word16);
44 : static void windowing_ola(const Word16 *, Word16 *, const Word16 *, const Word16);
45 : static void ola_add(const Word16 *, const Word16 *, Word16 *, const Word16);
46 : static void intlvW32_2_flippedW16(Word32 *L_x, const Word16 numPairs, const Word16 L_prot, Word16 *x);
47 : static void flippedW16_2_intlvW32(Word16 *x, const Word16 numPairs, const Word16 Lprot, Word32 *L_x);
48 : static Word16 imax_fx(const Word16 *, const Word16);
49 :
50 :
51 : Word16 rand_phase_fx(const Word16 seed, Word16 *sin_F, Word16 *cos_F);
52 :
53 : static Word16 imax2_jacobsen_mag_fx(const Word16 *y_re, const Word16 *y_im, const Word16 special);
54 : static void fft_spec2_sqrt_approx_fx(const Word16 x[], Word16 xMagSqrt[], const Word16 N);
55 : static Word16 sqrtMagnApprox_fx(const Word16 re, const Word16 im);
56 :
57 : static Word16 plc_phEcu_nonpure_tone_ana_fx(const Word16* plocs, const Word16 n_plocs, const Word16* X,
58 : const Word32 *L_Xavg, /* i : Frequency group amp averages for tonal tilt analysis pref. Max upshifted */
59 : const Word16 Lprot, const Word16 fs_idx);
60 :
61 0 : static void rotate_W16_fx(Word16 re_in, Word16 im_in, Word16 cosFactor, Word16 sinFactor, Word16 *re_out_ptr,
62 : Word16 *im_out_ptr)
63 : {
64 : #ifdef WMOPS
65 : push_wmops("PhECU::rotate_W16_fx");
66 : #endif
67 0 : *re_out_ptr = msu_r(L_mult(re_in, cosFactor), im_in, sinFactor); /* 2 ops no move when inlined */
68 0 : *im_out_ptr = mac_r(L_mult(re_in, sinFactor), im_in, cosFactor); /* 2 ops no move when inlined */
69 : #ifdef WMOPS
70 : pop_wmops();
71 : #endif
72 0 : return;
73 : }
74 :
75 0 : static void valley_magnitude_adj_fx(Word16 *re_ptr, Word16 *im_ptr, Word16 uniFactor, Word16 cosFactor)
76 : {
77 : Word16 scale_fx;
78 : #ifdef WMOPS
79 : push_wmops("PhECU::valley_magnitude_adj_fx");
80 : #endif
81 :
82 : /* y = 0.5*((2*rand(1,10000) + 1*cos(2*pi*x)) - 1 */ /* y will be in -1 to 1 range */
83 : /* y = 1*((1*rand(1,10000) + 0.5*cos(2*pi*x)) - 1 */ /* y will be in -1 to 1 range */
84 :
85 0 : scale_fx /*Q15*/ = mac_r(L_mult(uniFactor, 16384), cosFactor, 16384);
86 : /* make gain distribution more like N(0,1) than uniform */
87 :
88 0 : scale_fx /*Q14*/ = round_fx(L_mac((Word32)(16384L << 16), scale_fx, 4096));
89 : /* create a random gain scaling value with mean 1.0 and max 1.25 and min 0.75 */
90 0 : ASSERT(scale_fx <= (16384 + 8192));
91 0 : ASSERT(scale_fx >= (-16384 - 8192));
92 0 : *re_ptr = mult_r(scale_fx, shl_sat(*re_ptr, 1)); /* no moves , should be inlined */
93 0 : *im_ptr = mult_r(scale_fx, shl_sat(*im_ptr, 1)); /* no moves , should be inlined */
94 :
95 : #ifdef WMOPS
96 : pop_wmops();
97 : #endif
98 0 : return;
99 : }
100 :
101 : /*------------------------------------------------------------------*
102 : * rand_phase()
103 : *
104 : * randomized phase in form of sin and cos components
105 : *------------------------------------------------------------------*/
106 0 : Word16 rand_phase_fx(const Word16 seed, Word16 *sin_F, Word16 *cos_F)
107 : {
108 : /* 4x8+8 lookup scheme requiring ~40 Words of ROM freqRes 90/8 = 11.25 degrees */
109 :
110 : /* x=(0:(5*8-1))*(2*pi)/32; y=sin(x);y_int=max(-32768,min(32767,round(y*32768))), y_int/32768 */
111 :
112 0 : const Word16 *sincos_lowres_tab_cosQ15_fx = sincos_lowres_tab_sinQ15_fx + 8;
113 : /* position at 90 degrees , ptr init */
114 : Word16 seed2;
115 : Word16 seed2_shift;
116 :
117 : #ifdef DYNMEM_COUNT
118 : Dyn_Mem_In("rand_phase_fx", sizeof(struct {
119 : const Word16 *sincos_lowres_tab_cosQ15_fx; /* position at 90 degrees */
120 : Word16 seed2; /* 16 bit signed */
121 : Word16 seed2_shift;
122 : }));
123 : #endif
124 :
125 : #ifdef WMOPS
126 : push_wmops("PhECU::rand_phase_fx");
127 : #endif
128 :
129 0 : seed2 = extract_l(L_mac0(13849, seed, 31821));
130 0 : seed2_shift = lshr(seed2, 11);
131 : /* logical shift to get uniform random 5 msb bits; 0-31 , 0 degrees to 31*360/32= 348.75 */
132 0 : *sin_F = sincos_lowres_tab_sinQ15_fx[seed2_shift]; move16(); /* these moves can often be avoided by returning seed2shift and inlining */
133 0 : *cos_F = sincos_lowres_tab_cosQ15_fx[seed2_shift]; move16(); /* these moves can often be avoided by inlining */
134 : /* total WC 5 ops */
135 : #ifdef DYNMEM_COUNT
136 : Dyn_Mem_Out();
137 : #endif
138 : #ifdef WMOPS
139 : pop_wmops();
140 : #endif
141 0 : return seed2;
142 : }
143 :
144 : /*-----------------------------------------------------------------------------
145 : * trans_burst_ana_fx()
146 : *
147 : * Transient analysis
148 : *----------------------------------------------------------------------------*/
149 0 : void trans_burst_ana_fx(
150 : const Word16 *xfp, /* i : Input signal (, only used if time_offset==0) now in up_scaled *Q_spec */
151 : Word16 * mag_chg, /* o : Magnitude modification vector Q15 */
152 : Word16 * ph_dith, /* o : Phase dither, 2*PI is not included (Q15, i.e., between 0.0 and 1.0) */
153 : Word16 * mag_chg_1st, /* i/o: per band magnitude modifier for transients Q15 */
154 : const Word16 output_frame, /* i : Frame length */
155 : const Word16 time_offs, /* i : Time offset (integral multiple of output_frame) */
156 : const Word16 est_stab_content, /* i : 0.0=dynamic ... 1.0=Stable (==st->env_stab ) */
157 : Word16 * alpha, /* o : Magnitude modification factors for fade to average */
158 : Word16 * beta, /* : Magnitude modification factors for fade to average */
159 : Word16 * beta_mute, /* i/o : Factor for long-term mute */
160 : Word16 * Xavg, /* o : Frequency group average gain to fade to in same Q as X_sav */
161 : Word16 Q_spec, Word32 L_oold_xfp_w_E_fx, Word16 oold_xfp_w_E_exp_fx, Word16 oold_Ltot_exp_fx,
162 : Word16 *oold_grp_shape_fx,
163 :
164 : Word32 L_old_xfp_w_E_fx, Word16 old_xfp_w_E_exp_fx, Word16 old_Ltot_exp_fx, Word16 *old_grp_shape_fx,
165 : Word16 fadeout,
166 : Word32 * L_Xavg, /* full scale band amplitudes */
167 : Word8 *scratchBuffer /* Size = 4*4 * MAX_LTRANA + (2*4 + 1*2) * MAX_LGW + 8 */
168 : )
169 : {
170 : Word16 att_val, attDegreeFrames;
171 : Word32 * L_pGrPowLeft, *L_pGrPowRight;
172 : Word32 * L_gr_pow_left, *L_gr_pow_right;
173 : Word16 Lgw, i, k, burst_len;
174 : Word16 man, expo;
175 0 : Word16 att_always = 0; /* fixed attenuation per frequency group if set to 1 */
176 : Word16 oneOverFrame, roundEstMusContent, tmp16;
177 : Word16 burst_att_thresh;
178 : Word16 att_per_frame;
179 : Word16 * tr_dec;
180 : Word32 L_acc;
181 : Word16 fs_scale;
182 : Word16 scale_sh;
183 :
184 : Word32 L_oold_tmp, L_old_tmp;
185 : Word16 oold_exp_fx, old_exp_fx;
186 : Word16 margin_oold, margin_old;
187 : Word16 fs_idx;
188 : Word16 exp_diff;
189 : Word16 Xavg_exp_fx, Xavg_mod_exp_fx;
190 : Word16 tr_rise[MAX_LGW];
191 : Word16 tr_decay[MAX_LGW];
192 : Word16 man_in, expo_in, tmp;
193 : Word32 L_tmp, L_tmp2;
194 : Word16 thresh_tr_rise_lin_Q15;
195 : Word16 thresh_tr_decay_lin_Q15;
196 : Word16 beta_mute_thr;
197 : Word16 fade_ms_ind;
198 :
199 : #ifdef DYNMEM_COUNT
200 : Dyn_Mem_In("trans_burst_ana_fx", sizeof(struct {
201 :
202 : Word16 att_val, attDegreeFrames;
203 : Word32 * pGrPowLeft_L, *pGrPowRight_L;
204 : Word32 * L_gr_pow_left, *L_gr_pow_right;
205 : Word16 Lprot;
206 : Word16 Lgw, i, k, burst_len;
207 : Word16 man, expo;
208 : Word16 att_always; /* fixed attenuation per frequency group if set to 1 */
209 : Word16 oneOverFrame, roundEstMusContent, tmp16;
210 :
211 : Word16 burst_att_thresh;
212 : Word16 att_per_frame;
213 :
214 : Word16 * tr_dec;
215 : UWord16 lsb;
216 : Word32 L_acc;
217 : Word16 fs_scale;
218 : Word16 scale_sh;
219 :
220 : Word32 L_oold_tmp;
221 : Word32 L_old_tmp;
222 : Word16 fs_idx;
223 : Word16 shift32;
224 : Word16 margin_old;
225 : Word16 margin_oold;
226 :
227 : Word16 Xavg_exp_fx, Xavg_mod_exp_fx;
228 : Word16 tr_rise[MAX_LGW];
229 : Word16 tr_decay[MAX_LGW];
230 :
231 : Word16 man_in, expo_in, tmp;
232 : Word32 L_tmp, L_tmp2;
233 : Word16 thresh_tr_rise_lin_Q15;
234 : Word16 thresh_tr_decay_lin_Q15;
235 :
236 : Word16 beta_mute_thr;
237 : Word16 fade_ms_ind;
238 : }));
239 : #endif
240 :
241 : UNUSED(xfp);
242 : UNUSED(oold_xfp_w_E_exp_fx);
243 : UNUSED(old_xfp_w_E_exp_fx);
244 :
245 : if (time_offs == 0)
246 : {
247 : #ifdef WMOPS
248 : push_wmops("PhECU::trans_burst_ana_fx(1st)");
249 : #endif
250 : }
251 : else
252 : {
253 : #ifdef WMOPS
254 : push_wmops("PhECU::trans_burst_ana_fx(N)");
255 : #endif
256 : }
257 :
258 0 : fs_idx = mult(output_frame, (Word16)(32768.0 / 99.0)); /* truncation needed , i.e no rounding can be applied here */
259 0 : ASSERT(fs_idx == (output_frame / 100));
260 :
261 0 : L_gr_pow_left = (Word32 *)scratchAlign(scratchBuffer, 0); /* Size = 4 * MAX_LGW */ /* Size = 4 * MAX_LGW */
262 :
263 0 : L_gr_pow_right = (Word32 *)scratchAlign(L_gr_pow_left, sizeof(*L_gr_pow_left) * MAX_LGW); /* Size = 4 * MAX_LGW */
264 :
265 0 : tr_dec = (Word16 *)scratchAlign(L_gr_pow_right, sizeof(*L_gr_pow_right) * MAX_LGW); /* Size = 2bytes * MAX_LGW */
266 :
267 0 : oneOverFrame = oneOverFrameQ15Tab[fs_idx];
268 0 : Lgw = s_min(add(fs_idx, LGW8K), LGW48K); /* 4,5,6,7, (7/8) */
269 :
270 0 : burst_len = add(mult_r(time_offs, oneOverFrame), 1);
271 :
272 : UNUSED(est_stab_content);
273 : UNUSED(roundEstMusContent);
274 :
275 0 : move16();
276 0 : fade_ms_ind = (PLC2_FADEOUT_IN_MS - PLC2_FADEOUT_IN_MS_MIN) / PLC2_FADEOUT_RES; /* a shorter fading entry in fade_scheme_tab_fx */
277 0 : test();
278 0 : if (fadeout != 0)
279 : {
280 0 : fade_ms_ind = (PLC2_FADEOUT_LONG_IN_MS - PLC2_FADEOUT_IN_MS_MIN) / PLC2_FADEOUT_RES; move16();
281 : /* a long fading table entry in fade_scheme_tab */
282 : }
283 :
284 0 : move16(); move16(); move16();
285 0 : att_per_frame = fade_scheme_tab_fx[fade_ms_ind][0];
286 0 : burst_att_thresh = fade_scheme_tab_fx[fade_ms_ind][1]; /* number of 1.0 frames before muting phase */
287 : /* band gain muting can take place earlier due to a band transient */
288 0 : beta_mute_thr = fade_scheme_tab_fx[fade_ms_ind][2]; /* faster muting of added noise starts when slow main signal fadeout is over */
289 :
290 : #ifdef PLC_FADEOUT_IN_MS
291 0 : ASSERT(att_per_frame >= 1 && att_per_frame <= 12); /* table based lookup restriction */
292 : #else
293 : ASSERT(att_per_frame == 1 || att_per_frame == 2); /* table based lookup restriction */
294 : #endif
295 :
296 0 : *ph_dith = 0; /* peak scrambling, not in use */
297 :
298 0 : attDegreeFrames = 0; move16();
299 0 : IF(sub(burst_len, burst_att_thresh) > 0)
300 : {
301 0 : att_always = 1; move16();
302 : /* increase degree of attenuation */
303 :
304 : /* N.B. To facilitate the subsequent 10^(-att_degree/20) implementation
305 : * so as to use direct table-lookup,
306 : * the first (burstLen - burst_att_thresh) are NOT multiplied by "att_per_frame". */
307 0 : attDegreeFrames = sub(burst_len, burst_att_thresh); /* multiplied by 1.0 , */
308 : /* Furthermore, in order to minimize the size of the lookup-table required to
309 : * implement 10^(-att_degree/10), hard limit attDegreeFrames to (30% of 100)=30.
310 : * If attDegreeFrames is greater than 30, it means there are more than 30 successive
311 : * bad frames. */
312 0 : if (sub(attDegreeFrames, OFF_FRAMES_LIMIT) > 0)
313 : {/* Hard limit the no. of frames, for table lookup */
314 0 : attDegreeFrames = OFF_FRAMES_LIMIT; move16();
315 : }
316 : }
317 :
318 0 : plc_phEcu_initWord16(alpha, 32767, MAX_LGW);
319 0 : basop_memset(beta, 0, (MAX_LGW) * sizeof(Word16));
320 0 : IF(sub(burst_len, 1) <= 0)
321 : {
322 0 : *beta_mute = BETA_MUTE_FAC_INI; move16();
323 0 : *beta_mute = shr_pos(*beta_mute , 1); /* perceptual decrease */
324 : }
325 :
326 0 : IF(sub(burst_len, 1) <= 0)
327 : {
328 0 : L_pGrPowLeft = &L_gr_pow_left[0]; /* ptr init*/
329 0 : L_pGrPowRight = &L_gr_pow_right[0]; /* ptr init*/
330 :
331 0 : fs_scale = xfp_wE_MDCT2FFTQ11[fs_idx]; move16();
332 0 : scale_sh = 4; /* 15-11 */ move16();
333 : /* L_*old_xfp_w_E_fx, always upscaled to max from the calculating function */
334 :
335 :
336 0 : L_oold_tmp = Mpy_32_16_lc3plus(L_oold_xfp_w_E_fx, fs_scale);
337 0 : L_old_tmp = Mpy_32_16_lc3plus(L_old_xfp_w_E_fx, fs_scale);
338 :
339 0 : oold_exp_fx = add(oold_Ltot_exp_fx, scale_sh);
340 0 : old_exp_fx = add(old_Ltot_exp_fx, scale_sh);
341 :
342 : /*re-normalize L_mantissas and adjust exps */
343 0 : margin_oold = norm_l(L_oold_tmp);
344 0 : L_oold_tmp = L_shl_pos(L_oold_tmp, margin_oold);
345 0 : oold_exp_fx = sub(oold_exp_fx, margin_oold);
346 :
347 0 : margin_old = norm_l(L_old_tmp);
348 0 : L_old_tmp = L_shl_pos(L_old_tmp, margin_old);
349 0 : old_exp_fx = sub(old_exp_fx, margin_old);
350 :
351 : /* now time to analyze how the actual L_tot exponent scaling should be done */
352 : /* bring up the lowest exp to the same exp as the higher exp, and scale down the corresponding mantissa */
353 0 : exp_diff = sub(old_exp_fx, oold_exp_fx); /* energy increase from oold to old in log2 shifts */
354 :
355 : /* Overflow2 fix */
356 0 : exp_diff = s_max(-31, exp_diff);
357 0 : exp_diff = s_min(31, exp_diff);
358 0 : if (exp_diff > 0)
359 : { /* oold_exp < old_exp */
360 : /* old_exp is limiting, shift down oold mantissa */
361 0 : L_oold_tmp = L_shr_pos(L_oold_tmp, exp_diff);
362 : }
363 0 : if (exp_diff < 0)
364 : { /* oold_exp > old_exp */
365 : /* oold_exp is limiting, shift down old mantissa */
366 0 : L_old_tmp = L_shr_pos(L_old_tmp, negate(exp_diff));
367 : }
368 0 : oold_exp_fx = s_max(oold_exp_fx, old_exp_fx);
369 0 : old_exp_fx = oold_exp_fx; move16();
370 :
371 : /* safety set lowest energy to 2 , as one bit is shifted away in avg calculation */
372 0 : L_oold_tmp = L_max(L_oold_tmp, 2L);
373 0 : L_old_tmp = L_max(L_old_tmp, 2L);
374 :
375 0 : FOR(k = 0; k < Lgw; k++) /* NB Lgw may be shorter than all defined bands , e.g at at 48k */
376 : {
377 0 : L_gr_pow_left[k] = Mpy_32_16_lc3plus(L_oold_tmp, oold_grp_shape_fx[k]); move32();
378 0 : L_gr_pow_right[k] = Mpy_32_16_lc3plus(L_old_tmp, old_grp_shape_fx[k]); move32();
379 :
380 : /*Xavg[k] = sqrt(0.5f*(gr_pow_left[k]+gr_pow_right[k])/(float)(gw[k+1]-gw[k]));*/
381 0 : Xavg_exp_fx = sub(old_exp_fx, 1); /* virtual pre divide X_avg by 2 too keep precision in summation */
382 0 : L_acc = L_add(L_shr_pos(L_gr_pow_left[k], 1), L_shr_pos(L_gr_pow_right[k], 1));
383 0 : L_acc = L_shr_pos(L_acc, gw_len_inv_shift_fx[k]); /* divide by (bandwidth/2) in bins */
384 :
385 : { /* new Xavg_fx calculation */
386 0 : L_acc = L_max(L_acc, 1L);
387 0 : tmp = norm_l(L_acc);
388 0 : Xavg_exp_fx = sub(Xavg_exp_fx, tmp);
389 0 : L_acc = L_shl_pos(L_acc, tmp); /* now between 0.5 an 1.0*/
390 :
391 0 : expo_in = add(Xavg_exp_fx, 0);
392 0 : man_in = round_fx_sat(L_acc);
393 :
394 : /* now allow both positive and negative expos into sqrt */
395 0 : man = sqrt2ndOrder(man_in);
396 0 : if (s_and(expo_in, 1) != 0)
397 : {
398 0 : man = mult_r(man, FEC_HQ_ECU_ROOT2); /* odd exp operation */ /* 1/sqrt(2) */
399 : }
400 0 : expo = shr_r(expo_in, 1); /* apply even part of exp , square root operation. shr_r needed for positive side exps */
401 :
402 :
403 :
404 0 : L_acc = L_deposit_h(man);
405 0 : Xavg_exp_fx = add(expo, 0);
406 : /*Note: sqrt approximaton may overshoot e.g- sqrt(1.0) may become 1.0001 i.e. saturation is needed when eventually applying expo */
407 :
408 :
409 : /* Xavg (unscaled flt in L_acc*2^(exp-31)) needs to be saved in the same scale + Q as the stored 16bit
410 : * Xsav_fx, for use in subst_spec() */
411 : /* move Xavg fft scale to fx domain fx-fft scale*/
412 0 : L_acc = Mpy_32_16_lc3plus(L_acc, PhEcu_Xsav_Flt2FxScaleQ15[fs_idx]); /* fs fixed fractional change */
413 0 : Xavg_mod_exp_fx = sub(Xavg_exp_fx, PhEcu_Xsav_Flt2FxDnShift[fs_idx]); /* fs fixed exp change*/
414 0 : Xavg_mod_exp_fx = add(Xavg_mod_exp_fx, Q_spec); /* signal adaptive exp change*/
415 :
416 : /* :: move to Q_spec domain of Xsav , Q fixed in first BFI frames */
417 :
418 : /* extract Q0 value shift so that the mantissa is in the high part with man*2,^(0-15) */
419 0 : exp_diff = sub(15, Xavg_mod_exp_fx);
420 :
421 :
422 0 : exp_diff = s_min(31, exp_diff); /* limit to meaningfull DSP shifts as described by up to 6 bits */
423 0 : exp_diff = s_max(-32, exp_diff);
424 0 : if (exp_diff > 0)
425 : {
426 0 : L_acc = L_shr_pos(L_acc, exp_diff); /* may underflow */
427 : }
428 :
429 0 : if (exp_diff < 0)
430 : {
431 0 : L_acc = L_shr_sat(L_acc, exp_diff);
432 : }
433 0 : L_Xavg[k] = L_acc; /* export full 31 bit scale band amplitude */
434 0 : Xavg[k] = round_fx_sat(L_acc); /* extract high part */
435 :
436 : } /*end of new Xavg_fx calculation */
437 : /* internal transition detection */
438 :
439 : { /* pure percentage based transient detection */
440 0 : thresh_tr_rise_lin_Q15 = PhEcu_frac_thr_rise_lin_Q15[k];
441 0 : thresh_tr_decay_lin_Q15 = PhEcu_frac_thr_decay_lin_Q15[k];
442 :
443 : /* analyse rise */
444 : /* one of L_left or L_right should be pre-upshifted to a near max mantissa, (in one band ) */
445 0 : L_tmp2 = L_deposit_h(0);
446 0 : L_tmp = Mpy_32_16_lc3plus(*L_pGrPowRight, thresh_tr_rise_lin_Q15);
447 0 : if (L_sub(*L_pGrPowLeft, L_tmp) <= 0)
448 : {
449 0 : L_tmp2 = L_deposit_l(1);
450 : }
451 :
452 0 : if (*L_pGrPowLeft == 0) /* denominator zero special cases */
453 : {
454 : /* rise: Right/Left ; " * / 0 " --> tr_rise=1 ; "0/0" --> tr_rise = 0 */
455 0 : L_tmp2 = L_min(*L_pGrPowRight, 1L);
456 : }
457 0 : tr_rise[k] = extract_l(L_tmp2); move16();
458 :
459 : /* analyse decay */
460 0 : L_tmp2 = L_deposit_h(0);
461 0 : L_tmp = Mpy_32_16_lc3plus(*L_pGrPowLeft, thresh_tr_decay_lin_Q15);
462 0 : if (L_sub(L_tmp, *L_pGrPowRight) >= 0)
463 : {
464 0 : L_tmp2 = L_deposit_l(1);
465 : }
466 0 : if (*L_pGrPowRight == 0) /* right side no energy , special cases */
467 : {
468 : /* decay: Right/Left ; " 0 / * " --> tr_decay=0 ; "0/0" --> tr_decay = 0 */
469 0 : L_tmp2 = L_deposit_h(0);
470 : }
471 0 : tr_decay[k] = extract_l(L_tmp2); move16();
472 :
473 0 : tr_dec[k] = s_max(tr_rise[k], tr_decay[k]); move16();
474 :
475 : } /* percentage tr_dec */
476 : /* magnitude modification, calculated for decay only */
477 0 : IF(add(tr_dec[k], att_always) != 0)
478 : {
479 :
480 : #if MAX_INCREASE_GRPPOW_FX != 0
481 : #error trans_burst_ana_fx-- The following implementation is incorrect
482 : #endif
483 0 : att_val = 32767; move16();
484 0 : IF(L_sub(*L_pGrPowRight, 0) > 0)
485 : {
486 0 : IF(L_sub(*L_pGrPowRight, *L_pGrPowLeft) < 0) /* decay , i.e., (gr_pow_right/gr_pow_left) < 1.0 */
487 : {
488 : /* Compute sqrt(grp_pow_chg), where grp_pow_chg = gr_pow_right/gr_pow_left. */
489 0 : tmp16 = plc_phEcu_ratio_fx(*L_pGrPowRight, *L_pGrPowLeft, &expo); /* output tmp16 in Q14 */
490 :
491 0 : expo = sub(expo, (15 - 14)); /* Now, tmp16 is considered in Q15 */
492 0 : i = norm_s(tmp16);
493 0 : man = shl_pos(tmp16, i); /* Mandatory normalization before sqrtNthOrder(). */
494 0 : expo = add(expo, i);
495 0 : man = sqrt2ndOrder(man);
496 0 : if (s_and(expo, 1) != 0) /* Check even or odd. */
497 : {
498 0 : man = mult_r(man, FEC_HQ_ECU_ROOT2);
499 : }
500 0 : expo = shr_pos(expo, 1); /* Divided by 2-- square root operation. */
501 0 : att_val = shr(man, expo); /* Denormalize the mantissa back to Q15. */
502 : }
503 : /* ELSE
504 : {
505 : do nothing because (gr_pow_right/gr_pow_left) >= 1.0
506 : }
507 : */
508 : }
509 :
510 0 : mag_chg_1st[k] = att_val; move16();
511 0 : mag_chg[k] = att_val; move16();
512 : }
513 : ELSE
514 : {
515 0 : mag_chg_1st[k] = 32767; move16();
516 0 : mag_chg[k] = 32767; move16(); /* Set to ]1.0 in Q15 */
517 : }
518 :
519 0 : L_pGrPowLeft++;
520 0 : L_pGrPowRight++;
521 : } /* FOR band k */
522 : }
523 : ELSE /* sub(burst_len, 1) <= 0) */
524 : {
525 : /* BURST path */
526 :
527 : /* Since attDegreeFrames is discrete (integer) and hard limited to OFF_FRAMES_LIMIT,
528 : * it is easier to implement 10^(-att_degree/20.0) by a simply direct
529 : * table-lookup. Also, att_per_frame is discrete as well and can be
530 : * either ATT_PER_FRAME-1 or ATT_PER_FRAME and nothing else. This
531 : * means only 2 tables of size=(OFF_FRAMES_LIMIT+1) each are required.
532 : * To take square root into account, it is divided by 20 instead of 10. */
533 :
534 0 : if (sub(burst_len, beta_mute_thr) > 0) /* beta_mute_thr coincides/close to stronger 6dB muting phase */
535 : {
536 0 : *beta_mute = shr_pos_pos(*beta_mute, 1);
537 : }
538 :
539 0 : FOR(k = 0; k < Lgw; k++) /* Lgw may be shorter than all bands at 48k */
540 : {
541 : /* global burst attenuation */
542 : #if PLC2_FADEOUT_IN_MS != 0
543 : /* att_per_frame idx = "1:12") */
544 0 : att_val = POW_ATT_TABLES[att_per_frame][s_min(OFF_FRAMES_LIMIT, attDegreeFrames)]; move16();
545 : #else
546 : /* att_per_frame idx = "1:2") */
547 : att_val = POW_ATT_TABLES[att_per_frame][s_min(OFF_FRAMES_LIMIT, attDegreeFrames)]; move16();
548 : /* 10^(-attDegreeFrames*(att_per_frame = "1 or 2")/20) */
549 : #endif
550 :
551 0 : mag_chg[k] = mult_r(mag_chg_1st[k], att_val); /* Q15 */
552 :
553 0 : alpha[k] = mag_chg[k]; move16();
554 0 : ASSERT(beta[k] == 0); /* initialization required */
555 0 : IF(sub(alpha[k], 32766) < 0)
556 : {
557 : /* beta_pre[k] = sqrt(1.0f - SQR(alpha[k])); */
558 : /* beta[k] = beta_pre[k]* *beta_mute;*/
559 : /* (1.0-alpha.^2), in exp 1 due to L_mult0; */
560 :
561 0 : L_acc = L_sub((INT32_MAX >> 1) + 1, L_mult0(alpha[k], alpha[k]));
562 : {
563 :
564 : /* use lower complex(WMOPS/ROM) 2nd-order sqrt approximation */
565 0 : Word32 L_man, L_acc2 = L_acc;
566 : Word16 tmp, expo_in, expo2, man_in, man;
567 : /* updated code using the 2nd order approximation routine */
568 : /* form is flt=(L_acc2*2.^(-31 + 1) */
569 :
570 0 : tmp = norm_l(L_acc2); /* tmp is always 1 or higher due to Lmac0 downshift */
571 0 : man_in = round_fx_sat(L_shl_pos(L_acc2, tmp));
572 0 : expo_in = sub(1, tmp); /* 1 due to original 1 bit margin gain in L_mult0 */
573 :
574 : /* both positive and negative expos into sqrt */
575 0 : man = sqrt2ndOrder(man_in);
576 0 : if (s_and(expo_in, 1) != 0)
577 : {
578 0 : man = mult_r(man, FEC_HQ_ECU_ROOT2); /* odd exp operation */ /* sqrt(2)/2 */
579 : }
580 :
581 0 : expo2 = shr_r(expo_in, 1); /* apply square root operation. shr_r needed for pos and neg exps */
582 0 : ASSERT(expo2 <= 1);
583 :
584 0 : L_man = L_deposit_h(man);
585 0 : L_man = L_shl_sat(L_man, expo2); /* move to a zero exp , _sat needed for 1.0 input (due to approximation overshoot) */
586 :
587 0 : man = round_fx_sat(L_man); /* better perf with round here */
588 :
589 :
590 0 : beta[k] = mult_r(*beta_mute, man); move16();
591 : }
592 :
593 : /* bw Lowpass shape additive component */
594 : /* tab[LGW48K + 1] = { 1.0, ....1.0, 0.5,0.5, ... 0.1, 0.1 } */
595 :
596 0 : IF(sub(k, LGW32K - 1) >= 0)
597 : {
598 0 : beta[k] = mult_r(beta[k], 3277); /* 0.1 in Q15 */
599 : }
600 0 : ELSE IF(sub(k, LGW16K - 1) >= 0)
601 : {
602 0 : beta[k] = mult_r(beta[k], 16384); /* 0.5 in Q15 */
603 : }
604 :
605 : /*
606 : % limit Xavg noise contribution further in case of offset/tr_decay
607 : % attenuation was already active
608 :
609 : if (burst_len <= burst_att_thresh) && ( stPhECU_mag_chg_1st(k) < (32766/32768) )
610 : XavgFadeinFactor = (burst_len-1)/burst_att_thresh;
611 : XavgFadeinFactor = min(1.0, XavgFadeinFactor);
612 : beta(k) = beta(k)*XavgFadeinFactor;
613 : % limit initial Xavg noise contribution until We have reached regular burst attenuation
614 : end
615 : end
616 : */
617 0 : IF( sub(mag_chg_1st[k], 32767) <0 )
618 : { /* offset muting was started before burst muting phase */
619 : /* Xavg noise gradually increased during a short period */
620 0 : Word16 XavgFadeinFactor = 32767;
621 0 : Word16 ratio2_3_4_5tab[4][5 - 1] = {
622 : {(Word16)(.5 * 32768.0), (Word16)(1.0 * 32767.0), (Word16)(1.0 * 32767.0), (Word16)(1.0 * 32767.0)}, /* 1/2*/
623 : {(Word16)(.333 * 32768.0), (Word16)(.666 * 32768.0), (Word16)(1.0 * 32767.0), (Word16)(1.0 * 32767.0)}, /* 1/3*/
624 : {(Word16)(.25 * 32768.0), (Word16)(.5 * 32768.0), (Word16)(.75 * 32768.0), (Word16)(1.0 * 32767.0)}, /* 1/4 */
625 : {(Word16)(.2 * 32768.0), (Word16)(.4 * 32768.0), (Word16)(.6 * 32768.0), (Word16)(.8 * 32768.0)} /* 1/5 */
626 :
627 : };
628 0 : ASSERT(burst_att_thresh >= 1 && burst_att_thresh <= 5);
629 0 : ASSERT(burst_len >= 2);
630 0 : if (sub(burst_len,burst_att_thresh) <= 0)
631 : {
632 0 : ASSERT(burst_len - 2 < (5-1));
633 0 : ASSERT(burst_att_thresh-1-1 < (4));
634 0 : XavgFadeinFactor = ratio2_3_4_5tab[burst_att_thresh-1-1][burst_len - 2]; /* second bfi frame burst_len= is 2 */
635 : }
636 0 : beta[k] = mult_r(beta[k], XavgFadeinFactor); /* n Q15 */
637 : }
638 : } /* IF (sub(alpha[k], 32766) < 0) */
639 : } /* FOR k*/
640 :
641 : } /* BURST */
642 :
643 :
644 :
645 0 : IF(sub(output_frame, L_FRAME48K) == 0)
646 : { /* for 48kHz set/handle scalings of last group/band the same way as previous lower freq band(s) */
647 :
648 0 : FOR(k = Lgw; k < MAX_LGW; k++)
649 : {
650 0 : tr_dec[k] = tr_dec[k - 1]; move16(); /* only available in first bfi frame */
651 0 : Xavg[k] = Xavg[k - 1]; move16();
652 0 : mag_chg_1st[k] = mag_chg_1st[k - 1]; move16();
653 0 : mag_chg[k] = mag_chg[k - 1]; move16();
654 0 : alpha[k] = alpha[k - 1]; move16();
655 0 : beta[k] = beta[k - 1]; move16();
656 : }
657 : }
658 :
659 : #ifdef DYNMEM_COUNT
660 : Dyn_Mem_Out();
661 : #endif
662 : #ifdef WMOPS
663 : pop_wmops();
664 : #endif
665 0 : }
666 :
667 : /*-----------------------------------------------------------------------------
668 : * imax_fx()
669 : *
670 : * Get interpolated maximum position
671 : *-----------------------------------------------------------------------------*/
672 0 : static Word16 imax_fx( /* o: The location, relative to the middle of the 3 given data point, of the maximum. (Q15) */
673 : const Word16 *y, /* i: The 3 given data points. */
674 : const Word16 special /* i: -1 = left edge special case, 0 = normal, +1 = right edge special case */
675 : )
676 : {
677 : Word16 posi;
678 : Word16 man, expo, edge;
679 : const Word16 *pY;
680 : Word32 L_y1, L_y2, L_y3, L_numer, L_denom, L_sign, L_acc, L_y3_y1;
681 :
682 : #ifdef DYNMEM_COUNT
683 : Dyn_Mem_In("imax_fx", sizeof(struct {
684 : Word16 posi;
685 : Word16 man, expo, edge;
686 : const Word16 *pY;
687 : Word32 L_y1, L_y2, L_y3, L_numer, L_denom, L_sign, L_acc, L_y3_y1;
688 : }));
689 : #endif
690 :
691 : #ifdef WMOPS
692 : push_wmops("PhECU::imax_fx");
693 : #endif
694 :
695 : /* Seek the extremum of the parabola P(x) defined by 3 consecutive points
696 : so that P([-1 0 1]) = [y1 y2 y3] */
697 0 : pY = y;
698 0 : L_y1 = L_deposit_l(*pY++), L_y2 = L_deposit_l(*pY++), L_y3 = L_deposit_l(*pY);
699 :
700 : /* The extremum value:
701 : * y2i = -0.125f * SQR(y3_y1) / (y1+y3-2*y2)+y2
702 : * is not computed. Alternatively, the derivative of the parabola evaluated at y=0,
703 : * dP/dy|y=0, is used to determine whether the extremum is maximum or not.
704 : */
705 :
706 : /* Compute the extremum location: posi = (y3 - y1)/(4*y2 - 2*y1 - 2*y3). */
707 0 : L_y3_y1 = L_sub(L_y3, L_y1);
708 0 : L_acc = L_shl_pos(L_y2, 1); /* N.B. y2 is multiplied by 2 not 4. */
709 0 : L_acc = L_sub(L_acc, L_y1); /* N.B. Y1 is not multiplied by 2. */
710 0 : L_denom = L_sub(L_acc, L_y3); /* N.B. Y3 is not multiplied by 2. */
711 0 : L_sign = L_xor(L_y3_y1, L_denom); /* Preserve the sign since div_s() only takes positive arguments. */
712 0 : L_numer = L_abs(L_y3_y1);
713 0 : L_denom = L_abs(L_denom);
714 :
715 0 : test();
716 0 : IF(L_numer == 0 || L_denom == 0)
717 : {
718 0 : posi = 0; move16(); /* flat top , exit with center freq. */
719 : }
720 : ELSE
721 : {
722 :
723 0 : IF(L_sub(L_denom, L_shr_pos_pos(L_numer, 1)) > 0)
724 : {
725 : /* Although the output of ratio() is in Q14, adding the missing factor of 2 (See above)
726 : * in the denominator, the output is now considered to be in Q15. */
727 0 : man = plc_phEcu_ratio_fx(L_numer, L_denom, &expo); /* The mantissa is considered in Q15 */
728 :
729 0 : posi = shr_sat(man, expo); /* in Q15 (Due to saturation, it is automatically bound inside [-1.0,1.0].) */
730 : }
731 : ELSE
732 : {
733 0 : posi = 0x7fff; move16();
734 : }
735 :
736 0 : if (L_sign < 0) /* Restore the sign. */
737 : {
738 0 : posi = negate(posi);
739 : }
740 :
741 : /* For both edges (left and right), the extremum found above may be minimum.
742 : * It needs to reject the minimum. */
743 0 : IF(special != 0) /* Either edge special case. */
744 : {
745 0 : edge = 0x7fff; /* 1 in Q15 for the right edge special case */ move16();
746 0 : if (special < 0)
747 : {
748 0 : edge = 0; /* Left edge special case */ move16();
749 : }
750 :
751 : /* The derivative (slope) of the interpolating parabola = 2*A*y + B,
752 : * where A = (y3 + y1)/2 - y2
753 : * and B = (y3 - y1)/2.
754 : * Therefore, the slope at y=0 is simply B. Use this slope to determine
755 : * if the parabola is concave upward or downward.
756 : */
757 0 : IF(posi > 0) /* The extremum is in between the middle and the right given data points. */
758 : {
759 0 : posi = sub(0x7fff, posi); /* maximum case */
760 0 : if (L_sub(L_y3, L_y1) <= 0) /* Check the slope at y=0, i.e., at the middle given data point. */
761 : {
762 0 : posi = edge; /* minimum case */ move16();
763 : }
764 : }
765 : ELSE /* The extremum is in between the left and the middle given data points. */
766 : {
767 0 : posi = add(0x7fff, posi); /* maximum case */
768 0 : if (L_sub(L_y3, L_y1) >= 0)
769 : {
770 0 : posi = edge; /* minimum case */ move16();
771 : }
772 : }
773 : }
774 : }
775 : #ifdef DYNMEM_COUNT
776 : Dyn_Mem_Out();
777 : #endif
778 : #ifdef WMOPS
779 : pop_wmops();
780 : #endif
781 0 : return posi;
782 : /* Q15. The position either left or right relative to the index of the middle of the 3 given data points. */
783 : }
784 :
785 : /*-----------------------------------------------------------------------------
786 : * spec_ana_fx()
787 : *
788 : * Spectral analysis
789 : *-----------------------------------------------------------------------------*/
790 : /* OPT add the FB transient input flags , and skip peakfinder if fullband transient is set */
791 0 : void spec_ana_fx(Word16 * xfp, /* i/o : Input 16ms pre-upscaled time signal, output xfp utility buffer */
792 : Word16 * plocs, /* o : The indicies of the identified peaks Q0 */
793 : Word32 * L_plocsi, /* o : Interpolated positions of the identified peaks Q16 */
794 : Word16 * num_plocs, /* o : Number of identified peaks Q0 */
795 : Word16 * X_sav, /* o : Stored fft spectrum */
796 : const Word16 output_frame, /* i : Frame length Q0 */
797 : const Word16 bwidth_fx, /* i : Encoded Fs index Q0 */
798 : const Word16 *sp_ana_win, /* i : spectral analysis window Q15 */
799 : const Word16 f0hzLtpBinQ7, /* i : LTP bin frequency in normalized Hz Q7 */
800 : const Word16 norm_corrQ15_fx, /* i : correlation for lag at f0hzLtpBinQ7 */
801 : Word16 maxLprot, Word16 maxPlocs,
802 : Word8 *scratchBuffer /* Size = 4 * (MAX_LPROT + MAX_LPROT_RED + 1) + 2 * MAX_PLOCS */
803 : )
804 : {
805 : Counter n, k;
806 0 : Word16 nJacob, Lprot, hamm_len2 = 0, Lprot2, Lprot2p1;
807 : Word32 *L_xfp;
808 :
809 : Word16 *pXfp;
810 : Word16 *pPlocs;
811 : Word16 Xmax, Xmin, sens;
812 : Word16 rectLength, fraction;
813 : Word32 *pPlocsi_L;
814 : Word32 L_acc;
815 : Word16 peak_range_1;
816 : Word16 stop_band_start;
817 : Word16 stop_band_length;
818 : Word16 fft_scale;
819 : Word8 * buffer_fft;
820 : Word16 currPlocs, endPlocs;
821 : Word16 P_in_plocs;
822 : Word16 n_real_interp_tail;
823 :
824 : #ifdef WMOPS
825 : push_wmops("PhECU::spec_ana_fx(1st)");
826 : #endif
827 : #ifdef DYNMEM_COUNT
828 : Dyn_Mem_In("spec_ana_fx", sizeof(struct {
829 : Counter n, k;
830 : Word16 nJacob ,Lprot, hamm_len2, Lprot2, Lprot2p1;
831 : Word32 *L_xfp;
832 : Word32 *pXfp_L;
833 : Word16 *y_re_ptr, *y_im_ptr; /* otrs to Xsav as xfp was overwritten */
834 : Word16 *pXfp, *pXfp1, *pPlocs;
835 : Word16 Xmax, Xmin, sel;
836 : Word16 rectLength, fraction, special;
837 : Word32 *pPlocsi_L;
838 : Word32 L_acc;
839 : Word16 peak_range_1;
840 : Word16 stop_band_start;
841 : Word16 stop_band_length;
842 : Word16 fft_scale;
843 : Word8 * buffer_fft;
844 : Word16 fft_scale_by4;
845 : Word16 currPlocs, endPlocs;
846 : Word16 P_in_plocs;
847 : Word16 n_real_interp_tail;
848 : }));
849 : #endif
850 : /* Initialize for 48k to avoid warnings
851 : Lprot - length of saved prototype samples
852 : hamm_len2 - half Hamming window length
853 : pFftTbl - Table for real input FFT
854 : LprotLog2Minus1 - FFT stages for complex input FFT
855 : */
856 :
857 :
858 0 : L_xfp = (Word32 *)scratchAlign(scratchBuffer, 0); /* Size = 4 * MAX_LPROT bytes */
859 0 : buffer_fft = scratchAlign(L_xfp, sizeof(*L_xfp) * maxLprot); /* Size = 4 * (MAX_LPROT_RED + 1) + 2 * MAX_PLOCS */
860 :
861 0 : ASSERT(bwidth_fx >= 0 && bwidth_fx <= 4); /* avoid bwidth_fx variable warning */
862 :
863 0 : Lprot = LprotSzPtr[bwidth_fx];
864 0 : move16();
865 0 : hamm_len2 = DEPR_i_mult(3, mult(output_frame, (Word16)(3277) /* divBy10 + floor */)); /* 3 ms */
866 0 : fft_scale = PhEcuFftScale[bwidth_fx];
867 0 : move16(); /* 32,16,8 kHz all have fft scale 0, 24 has 8, 48 has 4 */
868 0 : Lprot2 = shr_pos(Lprot, 1);
869 0 : Lprot2p1 = add(Lprot2, 1); /* Magnitude lengths */
870 0 : rectLength = sub(Lprot, shl_pos(hamm_len2, 1));
871 : /* The length of the rectangular portion of the Hamming-Rectangular window. */
872 : {
873 : #ifdef WMOPS
874 : push_wmops("PhECU::WhrAnaWin+fft");
875 : #endif
876 :
877 : /* Apply hamming-rect window */
878 0 : windowing_L(xfp, L_xfp, sp_ana_win, rectLength, hamm_len2);
879 0 : BASOP_rfftN(L_xfp, Lprot, &fft_scale, buffer_fft);
880 : }
881 : #ifdef WMOPS
882 : pop_wmops(); /* anawin+fft */
883 : #endif
884 :
885 : /* Convert 32 Bit intlv FFT into phecu 16 bit flipped fft format */
886 : /* can not yet be an inplace operation */
887 :
888 0 : intlvW32_2_flippedW16(L_xfp, sub(Lprot2, 1), Lprot, xfp);
889 :
890 : /* Apply zeroing of non-coded FFT spectrum above 20 kHz */
891 0 : IF(sub(output_frame, ((L_FRAME48K) * 40) / 48) >= 0) /* only relevant for 48kHz in LC3plus */
892 : {
893 0 : stop_band_start = ((LPROT48K / 2) * 40) / 48; /* initial start position in real part , 320 */
894 0 : stop_band_length = ((LPROT48K * 8) / 48) - 1; /* real tail and into Im parts , 128-1 */
895 0 : stop_band_start = add(stop_band_start, 1); /* exclude DC ... */
896 :
897 0 : basop_memset(xfp + stop_band_start, 0, (stop_band_length) * sizeof(Word16));
898 : }
899 :
900 0 : peak_range_1 = s_min(Lprot2p1, MAX_LPROT_RED / 2 + 1); /* limit preliminary only active for 48k to save WMOPS */
901 :
902 0 : basop_memmove(X_sav, xfp, (Lprot) * sizeof(Word16));
903 :
904 : /* Magnitude representation */
905 0 : fft_spec2_sqrt_approx_fx(xfp, xfp, Lprot);
906 : /* inplace, i.e. [ Dc, real part of xfp ,Fs/2 ] will be replaced by magnitude(scaled by .5) */
907 :
908 : /* Find global maximum and minimum. */
909 0 : plc_phEcu_maxval_fx(xfp, peak_range_1, &Xmax);
910 0 : plc_phEcu_minval_fx(xfp, peak_range_1, &Xmin);
911 0 : sens = mult_r(sub(Xmax, Xmin), CMPLMNT_PLOC_SENS_FX);
912 :
913 :
914 0 : plc_phEcu_peak_locator_fx(xfp, peak_range_1, plocs, num_plocs, sens, Xmax, Xmin, MAX_LPROT_RED, buffer_fft);
915 :
916 :
917 : #ifdef WMOPS
918 : push_wmops("PhECU::Peaks_refine");
919 : #endif
920 :
921 : /* Refine peaks */
922 0 : pPlocsi_L = L_plocsi;
923 0 : pPlocs = plocs;
924 : /* n = sub(*num_plocs, 1); */ /* -1 so as to exclude the very last peak. */
925 0 : n = *num_plocs; /* number of peaks to process */
926 : /* Special case-- The very 1st peak if it is at 0 index position (DC) */
927 : /* With DELTA_CORR_F0_INT == 2 one needs to handle both *pPlocs==0 and *pPlocs==1 */
928 0 : logic16();
929 0 : IF((n > 0) && (sub(*pPlocs, 0) == 0)) /* Very 1st peak position possible to have a peak at 0/DC index position. */
930 : {
931 0 : fraction = imax_fx(xfp, -1); /* -1 signifies special left edge case. */
932 0 : L_acc = L_deposit_h(*pPlocs++); /* N.B., (*pPlocs) must be zero here. */
933 0 : *pPlocsi_L++ = L_mac(L_acc, fraction, 1); move32(); /* in Q16 */
934 0 : n = sub(n, 1); /* This special case is taken care of -- one less peak to go */
935 : }
936 0 : logic16();
937 0 : IF((n > 0) && (sub(*pPlocs, 1) == 0)) /* Also 2nd peak position uses DC which makes jacobsen unsuitable. */
938 : {
939 0 : fraction = imax_fx(xfp, 0); /* for parabolic this is not a special case. */
940 0 : L_acc = L_deposit_h(*pPlocs++); /* N.B., (*pPlocs) must be 1 here. */
941 0 : *pPlocsi_L++ = L_mac(L_acc, fraction, 1); move32(); /* in Q16 */
942 0 : n = sub(n, 1); /* This special case is taken care of -- one less peak to go */
943 : }
944 :
945 : /* All remaining peaks except the very last two possible integer positions */
946 0 : currPlocs = *pPlocs++; move16();
947 0 : endPlocs = sub(Lprot2p1, DELTA_CORR_F0_INT); /* last *pPlocs position for Jacobsen */
948 :
949 : /* precompute number of turns based on endpoint integer location and make into a proper FOR loop */
950 0 : IF(n > 0)
951 : {
952 0 : nJacob = n; move16();
953 :
954 : /* catch all three xxx01 , xxx10 and xxx11 ,
955 : and not only xxx01, xxx10 */
956 :
957 0 : n_real_interp_tail = 0; move16();
958 0 : if (sub(endPlocs, plocs[sub(*num_plocs, 1)]) <= 0)
959 : {
960 0 : n_real_interp_tail = add(n_real_interp_tail, 1);
961 : }
962 :
963 0 : logic16();
964 0 : if (sub(n,1) > 0 && sub(endPlocs, plocs[sub(*num_plocs, 2)]) <= 0)
965 : {
966 0 : n_real_interp_tail = add(n_real_interp_tail, 1);
967 : }
968 :
969 0 : nJacob = sub(nJacob, n_real_interp_tail);
970 :
971 0 : FOR (k = 0; k < nJacob; k++)
972 : {
973 0 : fraction = imax2_jacobsen_mag_fx(&(X_sav[currPlocs - 1]), &(X_sav[Lprot - 1 - currPlocs]), 0); /* in Q15 */ /* not endpoint */
974 0 : move16(); move16(); /* account for inloop indirect ptrs into Xsav */
975 :
976 0 : L_acc = L_deposit_h(currPlocs);
977 0 : *pPlocsi_L++ = L_mac(L_acc, fraction, 1); move32(); /* in Q16. Append the fractional part to the integral part. */
978 0 : currPlocs = *pPlocs++; move16();
979 : }
980 0 : n = sub(n, nJacob);
981 : }
982 :
983 : /* At this point there should at most two plocs left to process */
984 : /* the position before fs/2 and fs/2 both use the same magnitude points */
985 :
986 0 : IF(n > 0)
987 : {
988 : /* [ . . . . . . . ] Lprot/2+1 positions */
989 : /* | | | */
990 : /* 0 (Lprot/2-2) (Lprot/2) */
991 :
992 0 : pXfp = xfp + sub(Lprot2, 2);
993 0 : IF(sub(currPlocs, sub(Lprot2p1, DELTA_CORR_F0_INT)) == 0)
994 : /* Also 2nd last peak position uses fs/2 which makes jacobsen less suitable. */
995 : {
996 0 : fraction = imax_fx(pXfp, 0); /* for parabolic this is not a special case. */
997 :
998 0 : L_acc = L_deposit_h(currPlocs); /* N.B., (*pPlocs) must be 1 here. */
999 0 : *pPlocsi_L++ = L_mac(L_acc, fraction, 1); move32(); /* in Q16 */
1000 0 : currPlocs = *pPlocs++; move16();
1001 0 : n = sub(n, 1); /* This special case is taken care of -- one less peak to go */
1002 :
1003 0 : if (n > 0)
1004 : {
1005 : /* allow for an additional consecutive final plocs after (Fs/2-1) at Fs/2 */
1006 0 : currPlocs = *pPlocs++; move16();
1007 : }
1008 : }
1009 :
1010 : /* Here the only remaining point would be a fs/2 plocs */
1011 : /* pXfp = xfp + sub(Lprot2,1); already set just a reminder where it whould point */
1012 0 : IF(n > 0) /* fs/2 which makes special case . */
1013 : {
1014 0 : fraction = imax_fx(pXfp, 1); /* for parabolic this is a special case. */
1015 :
1016 0 : L_acc = L_deposit_h(currPlocs); /* N.B., (*pPlocs) must be 1 here. */
1017 0 : *pPlocsi_L++ = L_mac(L_acc, fraction, 1); move32(); /* in Q16 */
1018 0 : currPlocs = *pPlocs++; move16();
1019 0 : n = sub(n, 1); /* This special case is taken care of -- one less peak to go */
1020 : }
1021 : }
1022 :
1023 : /* here n should be 0 if all peaks have been processed */
1024 0 : ASSERT(n == 0);
1025 :
1026 : /* Check number of plocs within an assumed pitch range */
1027 0 : P_in_plocs = 0; move16();
1028 0 : FOR(n = 0; n < *num_plocs; n++)
1029 : {
1030 : /* count number of peaks in locations 1,2,3,4,5,6 , ~= 60 Hz ... 380 Hz */
1031 0 : fraction = s_min(1, plocs[n]); /* 0 stays zero , otherwise 1 */
1032 0 : if (sub(plocs[n], 7) < 0)
1033 : {
1034 0 : P_in_plocs = add(P_in_plocs, fraction);
1035 : }
1036 : }
1037 :
1038 : #ifdef WMOPS
1039 : pop_wmops(); /* peaks refine */
1040 : #endif
1041 :
1042 0 : logic16();
1043 0 : IF(f0hzLtpBinQ7 > 0 && P_in_plocs > 0)
1044 : {
1045 : Word16 n_plocs_in, n_plocs_out;
1046 :
1047 0 : n_plocs_in = *num_plocs; move16();
1048 :
1049 : /* NB LF peak analysis may add adjacent peaks in { plocs, L_plocsi}, (output from peakfinder did not have
1050 : * adjacent peaks ) */
1051 0 : plc_phEcu_LF_peak_analysis_fx(plocs /* i/o */, num_plocs /* i/o */, L_plocsi /* i/o */, xfp, f0hzLtpBinQ7,
1052 : norm_corrQ15_fx, 2, maxPlocs, buffer_fft);
1053 0 : n_plocs_out = *num_plocs; move16();
1054 :
1055 0 : IF(sub(n_plocs_in, n_plocs_out) == 0)
1056 : {
1057 : /* adjust first peak coinciding with LTPF0 measures if it indicates so */
1058 0 : plc_phEcu_F0_refine_first_fx(plocs /* i/o */, *num_plocs, L_plocsi /* i/o */, f0hzLtpBinQ7, norm_corrQ15_fx,
1059 : 3);
1060 : }
1061 : }
1062 : /* moved inside spec_ana_fx , to include validated pitch peak P_in_plocs*/
1063 : {
1064 0 : Word16 peak_limits_fx[5] = { 14 /*NB*/, 14 /*WB*/, 14 /*sWB*/, 14 /*SWB*/,
1065 : 14 /* FB */ }; /* to be trained for each BW */
1066 :
1067 0 : test();
1068 0 : test();
1069 0 : IF((sub(norm_corrQ15_fx, 0) > 0) && /* == 0 indicates a negative correlation, which could be likely stable */
1070 : (sub((Word16)(0.5 * 32768), norm_corrQ15_fx) > 0) && (sub(*num_plocs, peak_limits_fx[bwidth_fx]) > 0))
1071 : {
1072 0 : if (P_in_plocs > 0)
1073 : {
1074 0 : *num_plocs = 0; move16(); /*activate noise only path only if normcorr vas valid energywise */
1075 : }
1076 : }
1077 : }
1078 :
1079 : #ifdef DYNMEM_COUNT
1080 : Dyn_Mem_Out();
1081 : #endif
1082 : #ifdef WMOPS
1083 : pop_wmops();
1084 : #endif
1085 0 : }
1086 :
1087 : /*-------------------------------------------------------------------*
1088 : * subst_spec_fx()
1089 : *
1090 : * Substitution spectrum calculation
1091 : *-------------------------------------------------------------------*/
1092 :
1093 0 : void subst_spec_fx(
1094 : const Word16 *plocs, /* i : The indices of the identified peaks Q0 */
1095 : const Word32 *L_plocsi, /* i : Interpolated positions of the identified peaks Q16 */
1096 : Word16 * num_plocs, /* i/o : Number of identified peaks Q0 */
1097 : const Word16 time_offs, /* i : Time offset Q0 */
1098 : Word16 * X, /* i/o : FFT spectrum */
1099 : const Word16 *mag_chg, /* i : Magnitude modification Q15 */
1100 : const Word16 ph_dith, /* i : Phase dither, 2*PI is not included. (Q15, i.e., between 0.0 and 1.0) */
1101 : const Word16 *is_trans, /* i : (Transient) noise generation flags (either 0 or not 1 ) */
1102 : const Word16 output_frame, /* i : Frame length Q0 */
1103 : Word16 * seed, /* i/o : Random seed */
1104 : const Word16 *alpha, /* i : Magnitude modification factors for fade to average Q15 */
1105 : const Word16 *beta, /* i : Magnitude modification factors for fade to average Q15 */
1106 : const Word16 *Xavg, /* i : Frequency group averages to fade to Q0 */
1107 : const Word16 t_adv /* i : time adjustement excluding time_offs Q0 */
1108 : ,const Word16 fadeout, /* need for DC muting */
1109 : Word16 * nonpure_tone_flag_ptr, /* i/o : non-pure single tone indicator state */
1110 : const Word32 * L_Xavg /* i : Frequency group amp averages for tonal tilt analysis Max upshifted */
1111 : )
1112 : {
1113 : Word16 Xph_short;
1114 : Word32 L_corr_phase[MAX_PLOCS], L_Xph;
1115 : Word32 *pCorrPhase_L;
1116 : Word16 cos_F, sin_F, tmp;
1117 0 : Word16 peak_sin_F = 0, peak_cos_F = 0;
1118 : Word16 sin_F_fade2avg, cos_F_fade2avg;
1119 : Word16 fs_idx;
1120 : Word16 Lprot, m, i, e, im_ind, delta_corr_up, delta_corr_dn, delta_tmp;
1121 : UWord16 lsb;
1122 : Word16 j, re, im, *pReX, *pImX, lastPeak, lprotBy2Minus1, segmentLen;
1123 : Word16 pkLocation_1, pkLocation, pkLocation1;
1124 : const Word16 *pPlocs;
1125 : const Word32 *pPlocsi_L;
1126 : Word32 L_acc;
1127 : Word16 Lprot_inv;
1128 : Word16 k;
1129 : Word16 tmp2;
1130 : Word16 alpha_local;
1131 : Word32 tmp_L;
1132 : Word16 mag_chg_local;
1133 : const Word16 *gwlpr_fxPlus1;
1134 : Word16 one_peak_flag_mask;
1135 : Word16 noise_mag_scale_neg;
1136 : Word16 up_shift_adj;
1137 :
1138 : #ifdef DYNMEM_COUNT
1139 : Dyn_Mem_In("subst_spec_fx", sizeof(struct {
1140 : Word16 Xph_short;
1141 : Word32 L_corr_phase[MAX_PLOCS], L_Xph;
1142 : Word32 *pCorrPhase_L;
1143 : Word16 cos_F, sin_F, tmp;
1144 : Word16 peak_sin_F, peak_cos_F;
1145 : Word16 sin_F_fade2avg, cos_F_fade2avg;
1146 : Word16 fs_idx;
1147 : Word16 Lprot, m, i, e, im_ind, delta_corr_up, delta_corr_dn, delta_tmp;
1148 : UWord16 lsb;
1149 : Word16 j, re, im, *pReX, *pImX, lastPeak, lprotBy2Minus1, segmentLen;
1150 : Word16 pkLocation_1, pkLocation, pkLocation1;
1151 : const Word16 *pPlocs;
1152 : const Word32 *pPlocsi_L;
1153 : Word32 L_acc;
1154 : Word16 Lprot_inv;
1155 : Word16 k;
1156 : Word16 tmp2;
1157 : Word16 alpha_local;
1158 : Word16 expo;
1159 : Word32 tmp_L;
1160 : Word16 mag_chg_local;
1161 : const Word16 *gwlpr_fxPlus1;
1162 : Word16 one_peak_flag_mask;
1163 : Word16 noise_mag_scale_neg;
1164 : Word16 up_shift_adj;
1165 : }));
1166 : #endif
1167 :
1168 : if (time_offs == 0)
1169 : {
1170 : #ifdef WMOPS
1171 : push_wmops("PhECU::subst_spec_fx(1st)");
1172 : #endif
1173 : }
1174 : else
1175 : {
1176 : #ifdef WMOPS
1177 : push_wmops("PhECU::subst_spec_fx(N)");
1178 : #endif
1179 : }
1180 :
1181 :
1182 0 : gwlpr_fxPlus1 = &(gwlpr_fx[1]); /* ptr init */
1183 0 : fs_idx = mult(output_frame, (Word16)(32768.0 / 99.0)); /* truncation needed , i.e no rounding can be applied here */
1184 0 : ASSERT(fs_idx == (output_frame / 100));
1185 0 : Lprot = LprotSzPtr[fs_idx];move16();
1186 0 : Lprot_inv = InvLprot_Q22[fs_idx]; move16();
1187 :
1188 0 : tmp2 = add(mult_r(time_offs, oneOverFrameQ15Tab[fs_idx]), 1);/* save a local burst_len for securing DC and fs/2 muting */
1189 :
1190 : /* Correction/evolution phase of the identified peaks */
1191 0 : IF(s_or(is_trans[0], is_trans[1]) != 0)
1192 : {
1193 0 : *num_plocs = 0; move16();
1194 : }
1195 : ELSE
1196 : {
1197 :
1198 0 : tmp = t_adv;
1199 :
1200 0 : tmp = add_sat(tmp, time_offs);
1201 : /* NB tmp can be stored in Word16 Q0 as max used value is 684+(OFF FRAMELIMIT==60)*480 = 29484 */
1202 0 : tmp_L = L_mult0(tmp, Lprot_inv);
1203 :
1204 :
1205 0 : tmp = norm_l(tmp_L);
1206 0 : up_shift_adj = s_max(0, sub(4, tmp)); /* 48kHz : PLC frame 1..49 -> tmp_L<<4 , frame 50..60 -> tmpL<<3 */
1207 0 : tmp_L = L_shl_sat(tmp_L, sub(4, up_shift_adj));
1208 0 : tmp = round_fx_sat( tmp_L);
1209 :
1210 :
1211 0 : pPlocsi_L = L_plocsi;
1212 0 : pCorrPhase_L = L_corr_phase;
1213 0 : FOR(m = 0; m < *num_plocs; m++)
1214 : {
1215 :
1216 : /* tmp has variable resolution 10 or 9 bits */
1217 0 : ASSERT( up_shift_adj >= 0);
1218 0 : Mpy_32_16_ss(L_shl_pos(*pPlocsi_L++, up_shift_adj), tmp, &L_acc, &lsb);
1219 0 : L_acc = L_add(L_shl_pos(L_acc, 5), lshr(lsb, 11));
1220 : /* 5 lsb's actually unused though, as 6 bits are shifted out */
1221 0 : *pCorrPhase_L++ = L_acc; move32();/* in Q16. 2*PI is not included. */
1222 : }
1223 : }
1224 :
1225 0 : one_peak_flag_mask = (Word16)0xFFFF; move16(); /* all ones mask -> keep */
1226 0 : test(); logic16();
1227 0 : IF((*num_plocs > 0) && sub(*num_plocs, 3) < 0)
1228 : {
1229 0 : one_peak_flag_mask = 0x0000; move16(); /* all zeroes mask -> zeroes in valleys, single clean tone assumed */
1230 :
1231 : /* revert initial pure tone decision in some cases */
1232 0 : logic16(); logic16();
1233 0 : IF((sub(*nonpure_tone_flag_ptr, 0) < 0) &&
1234 : ((sub(fs_idx, 2) == 0)/* SemiSWB 24 kHz */ || (sub(fs_idx, 4) >= 0)) /* FB 48 kHz */
1235 : )
1236 : {
1237 : /* in the first lost frame analyze spectra and spectral bands to possibly reverse an initial pure sine assumption */
1238 0 : *nonpure_tone_flag_ptr = plc_phEcu_nonpure_tone_ana_fx(plocs, *num_plocs, X, L_Xavg, Lprot, fs_idx);
1239 :
1240 : #ifdef LOCAL_PLC2_TON_ANA_DEACTIVATE
1241 : *nonpure_tone_flag_ptr = 0; /* dbg of inactive tone analysis */
1242 : #endif
1243 : }
1244 :
1245 :
1246 0 : if (sub(*nonpure_tone_flag_ptr, 0) > 0)
1247 : {
1248 : /* actually revert single pure tone detection */ /* 0-> mute all surrounding valley bins in evolution , 0xff -> generate noise in all valleys */
1249 0 : one_peak_flag_mask = (Word16)0xFFFF; move16(); /* all ones mask -> keep */
1250 : }
1251 : }
1252 :
1253 0 : noise_mag_scale_neg = 0; move16(); /* no change of valley noise magnitude */
1254 0 : logic16();
1255 0 : if ((*num_plocs == 0) || (time_offs != 0))
1256 : { /* only adj_scale noise amplitude when we have no WC path , or in all noise frame */
1257 0 : noise_mag_scale_neg = -32768; move16(); /* all ones --> scale_noise */
1258 : }
1259 :
1260 0 : IF(*num_plocs == 0)
1261 : {
1262 0 : X[0] = 0; move16(); /* reset DC if there are no peaks */
1263 0 : X[shr_pos(Lprot, 1)] = 0; move16(); /* also reset fs/2 if there are no peaks */
1264 : }
1265 :
1266 : /* the binary selection of fadeout scheme */
1267 0 : tmp = (PLC2_FADEOUT_IN_MS - PLC2_FADEOUT_IN_MS_MIN) / PLC2_FADEOUT_RES; move16();
1268 0 : if (fadeout != 0)
1269 : {
1270 0 : tmp = (PLC2_FADEOUT_LONG_IN_MS - PLC2_FADEOUT_IN_MS_MIN) / PLC2_FADEOUT_RES; move16();
1271 : }
1272 :
1273 0 : IF(sub(tmp2, add(fade_scheme_tab_fx[tmp][1],1) ) > 0)
1274 : {
1275 : /* also start DC scaling attenuation */
1276 0 : X[0] = mult(alpha[0], X[0]); move16();
1277 : /* start fs/by2 attenuation */
1278 0 : X[shr_pos(Lprot, 1)] = mult(alpha[s_min(add(fs_idx, LGW8K), LGW48K)], X[shr_pos(Lprot, 1)]); move16();
1279 : }
1280 :
1281 :
1282 0 : lprotBy2Minus1 = sub(shr_pos(Lprot, 1), 1);
1283 :
1284 : /* for 48k the last (63+1+63) 128/2-1 values above 20 kHz are always zeroes */
1285 : { /* after a last, peak no need to evolve above 20kHz , those coeffs have been/ will be zeroed already */
1286 : /* DC, Xused,ReZeroed, fs/2, ImZeroed, ImUsed */
1287 : /*N: 1, 320 , 63 , 1 , 63 , 320 */
1288 : /*Cind: 0, 1-320, 321-383 , 384 , 385-447, 448 -767 */
1289 0 : lprotBy2Minus1 = s_min( lprotBy2Minus1, 320);
1290 : /*only process up to bin X[320] , 63 coeffs X[321] fwd should already be zeroed */
1291 : }
1292 :
1293 0 : i = 1; move16(); /* index in the X[DC, ReX part of X_Sav ,i.e *pReX == X[i] */
1294 0 : k = 0; move16();
1295 :
1296 0 : pReX = X + i;
1297 0 : im_ind = (Lprot - 1); /* ptr init */
1298 0 : pImX = X + im_ind;
1299 0 : pPlocs = plocs;
1300 0 : pCorrPhase_L = L_corr_phase;
1301 :
1302 :
1303 0 : pkLocation_1 = -4; move16(); /* dummy value to avoid Out of Array Read */
1304 0 : pkLocation = -3; move16(); /* dummy value to avoid Out of Array Read for the *num_plocs==0 case */
1305 0 : pkLocation1 = -2; move16(); /* dummy value to avoid Out of Array Read */
1306 :
1307 0 : IF (*num_plocs != 0)
1308 : {
1309 :
1310 0 : pkLocation = *pPlocs; move16(); /* N.B. No post-increment */
1311 0 : lastPeak = sub(*num_plocs, 1);
1312 0 : if (lastPeak >= 0)
1313 : {
1314 0 : pkLocation1 = *pPlocs++; move16(); /* get a next peak */
1315 : }
1316 : }
1317 :
1318 0 : FOR(m = 0; m < *num_plocs; m++)
1319 : {
1320 0 : pkLocation_1 = pkLocation; /* plocs[m - 1] */ move16();
1321 0 : pkLocation = pkLocation1; /* plocs[m] */move16();
1322 :
1323 : /*location dependent update of plocs[m + 1] */
1324 0 : if ( sub(lastPeak, m) > 0)
1325 : { /* only read additional peak when teher is a valid position to read */
1326 0 : pkLocation1 = *pPlocs++; /* plocs[m + 1] */ move16();
1327 : }
1328 :
1329 0 : delta_tmp = shr_pos(sub(sub(pkLocation, pkLocation_1), 1), 1);
1330 0 : if (m == 0)
1331 : {
1332 0 : delta_tmp = DELTA_CORR; move16(); /* first peak special case */
1333 : }
1334 0 : delta_corr_dn = s_min(delta_tmp, DELTA_CORR);
1335 :
1336 0 : delta_tmp = shr_pos(sub(sub(pkLocation1, pkLocation), 1), 1);
1337 0 : if (sub(m, lastPeak) >= 0)
1338 : {
1339 0 : delta_tmp = DELTA_CORR; move16();
1340 : }
1341 0 : delta_corr_up = s_min(delta_tmp, DELTA_CORR); /* last peak special case */
1342 :
1343 :
1344 : /* Input Xph */
1345 0 : segmentLen = sub(sub(pkLocation, delta_corr_dn), i); /* may be negative */
1346 :
1347 0 : ASSERT(pReX == &(X[i]));
1348 0 : ASSERT(*pReX == X[i]); /*before first, nth valley*/
1349 :
1350 0 : FOR(j = 0; j < segmentLen; j++) /* valley section , may be skipped for segmentlen < 0 */
1351 : {
1352 :
1353 0 : *seed = rand_phase_fx(*seed, &sin_F, &cos_F);
1354 :
1355 : /* phase scrambling */
1356 0 : rotate_W16_fx(*pReX, *pImX, cos_F, sin_F, &tmp, &im); /* tmp=real part, should be inlined */
1357 : UNUSED(re);
1358 :
1359 : /* i.e. add a bit of magnitude scrambling around 1.0 in longer bursts */
1360 0 : *seed = rand_phase_fx(*seed, &sin_F_fade2avg, &cos_F_fade2avg);
1361 0 : IF(noise_mag_scale_neg != 0)
1362 : {
1363 0 : valley_magnitude_adj_fx(&tmp, &im, *seed, cos_F);
1364 : /* use two random variables */ /*reuse cosF from regular X scrambling, + reuse *seed from fade2avg
1365 : */
1366 : }
1367 :
1368 0 : IF( beta[k] != 0 )
1369 : {
1370 0 : alpha_local = alpha[k]; /* no move as alpha_local is only needed for debug */
1371 : /* the fade2avg mixing branch, fade2avg and transient downscaling and evolution rotation */
1372 0 : tmp2 = mult_r(beta[k], Xavg[k]);
1373 :
1374 : {
1375 0 : tmp2 = s_and(tmp2, one_peak_flag_mask);
1376 0 : tmp = s_and(tmp, one_peak_flag_mask);
1377 0 : im = s_and(im, one_peak_flag_mask);
1378 : }
1379 :
1380 0 : *pReX++ = mac_r(L_mult(alpha_local, tmp), tmp2, cos_F_fade2avg); move16();
1381 0 : *pImX-- = mac_r(L_mult(alpha_local, im), tmp2, sin_F_fade2avg); move16();
1382 : }
1383 : ELSE
1384 : { /* the no fade2avg mixing branch, only transient downscaling and evolution rotation */
1385 : {
1386 0 : tmp = s_and(tmp, one_peak_flag_mask);
1387 0 : im = s_and(im, one_peak_flag_mask);
1388 : }
1389 :
1390 :
1391 0 : *pReX++ = mult_r(mag_chg[k], tmp); move16();
1392 0 : *pImX-- = mult_r(mag_chg[k], im); move16();
1393 : }
1394 0 : i = add(i, 1);
1395 0 : ASSERT(pReX == &(X[i])); /* nth Valley */
1396 0 : ASSERT(*pReX == X[i]); /* nth Valley */
1397 0 : if (sub(i, gwlpr_fxPlus1[k]) >= 0)
1398 : {
1399 0 : k = add(k, 1);
1400 : }
1401 : } /* segment_len 1st++ etc valley excluding last */
1402 :
1403 : /* peak area section */
1404 :
1405 0 : e = s_min(lprotBy2Minus1, add(pkLocation, delta_corr_up));
1406 0 : segmentLen = sub(e, sub(i, 1));
1407 :
1408 :
1409 0 : L_Xph = *pCorrPhase_L; move32();
1410 : /* rounding here, add "0.5" before extracting the 10 bits for table lookup */
1411 0 : Xph_short = s_and(extract_l(L_shr_pos_pos(L_add(L_Xph, (1L << (16 - 10 - 1))), 16 - 10)), 0x3ff);
1412 : /* 10 bits precision after radix point, for a virtual 0-1023 sin/cos table lookup */
1413 :
1414 :
1415 0 : get_sin_cosQ10opt(Xph_short, &peak_sin_F, &peak_cos_F);
1416 :
1417 :
1418 0 : ASSERT(pReX == &(X[i])); /*before peak*/
1419 0 : FOR(j = 0; j < segmentLen; j++)
1420 : {
1421 0 : mag_chg_local = mag_chg[k]; /* mag_chg_local actually only need for debugging , no move16()*/
1422 :
1423 : UNUSED(ph_dith);
1424 0 : *seed = extract_l(L_mac0(13849, *seed, 31821));
1425 0 : rotate_W16_fx(*pReX, *pImX, peak_cos_F, peak_sin_F, &tmp, &im); /* should be inlined */
1426 : UNUSED(re);
1427 :
1428 0 : *seed = rand_phase_fx(*seed, &sin_F, &cos_F);
1429 :
1430 0 : IF( beta[k] != 0 )
1431 : { /* fade2avg path alpha*X_sav + beta *Xavg */
1432 0 : alpha_local = mag_chg_local; /* no move alpha_local only needed for dbg */
1433 0 : tmp2 = mult_r(beta[k], Xavg[k]);
1434 :
1435 :
1436 0 : *pReX++ = mac_r(L_mult(alpha_local, tmp), tmp2, cos_F); move16();
1437 0 : *pImX-- = mac_r(L_mult(alpha_local, im), tmp2, sin_F); move16();
1438 : }
1439 : ELSE
1440 : {
1441 0 : *pReX++ = mult_r(mag_chg_local, tmp); move16();
1442 0 : *pImX-- = mult_r(mag_chg_local, im); move16();
1443 : }
1444 :
1445 0 : i = add(i, 1);
1446 0 : ASSERT(pReX == &(X[i]));
1447 0 : ASSERT(*pReX == X[i]);
1448 0 : if (sub(i, gwlpr_fxPlus1[k]) > 0)
1449 : {
1450 0 : k = add(k, 1);
1451 : }
1452 : } /* segment_length Peak*/
1453 0 : pCorrPhase_L++;
1454 : }
1455 :
1456 0 : segmentLen = sub(lprotBy2Minus1, sub(i, 1)); /* tail/valley noise-bins */
1457 :
1458 : /* for 48k the last 63+1+63 = values above 20 kHz */
1459 : { /* after last, peak no need to scramble above 20kHz , those coeffs have been/ will be zeroed already */
1460 : /* DC, Xused,ReZeroed, fs/2, ImZeroed, ImUsed */
1461 : /*N: 1, 320 , 63 , 1 , 63 , 320 */
1462 : /*ind: 0, 1-320, 321-383 ,384 , 385-447, 448 -767 */
1463 : /* segmentLen = sub(320, i-1); */ /*only process up to bin X[320] , 63 coeffs X[321] fwd should already be
1464 : zeroed */
1465 : /* ASSERT(i-1+ segmentLen == lprotBy2Minus1 ); */
1466 : }
1467 :
1468 0 : ASSERT(*pReX == X[i]); /* before a final valley*/
1469 0 : FOR(j = 0; j < segmentLen; j++)
1470 : {
1471 :
1472 :
1473 0 : *seed = rand_phase_fx(*seed, &sin_F, &cos_F);
1474 0 : rotate_W16_fx(*pReX, *pImX, cos_F, sin_F, &tmp, &im); /* should be inlined , tmp=real part */
1475 :
1476 0 : *seed = rand_phase_fx(*seed, &sin_F_fade2avg, &cos_F_fade2avg);
1477 : /* i.e. add a bit of magnitude scrambling around 1.0 in longer bursts */
1478 0 : IF(noise_mag_scale_neg != 0)
1479 : {
1480 0 : valley_magnitude_adj_fx(&tmp, &im, *seed, cos_F);
1481 : /*reuse cosF from regular X scrambling, + reuse *seed from fade2avg */
1482 : }
1483 :
1484 0 : tmp = s_and(tmp, one_peak_flag_mask);
1485 0 : im = s_and(im, one_peak_flag_mask);
1486 0 : IF(beta[k] != 0)
1487 : { /* fade2avg path never in first BFI frame */
1488 :
1489 0 : alpha_local = alpha[k]; /* no move as alpha_local is only needed for debug */
1490 0 : tmp2 = mult_r(beta[k], Xavg[k]);
1491 : {
1492 0 : tmp2 = s_and(tmp2, one_peak_flag_mask);
1493 : }
1494 :
1495 :
1496 0 : *pReX++ = mac_r(L_mult(alpha_local, tmp), tmp2, cos_F_fade2avg); move16();
1497 0 : *pImX-- = mac_r(L_mult(alpha_local, im), tmp2, sin_F_fade2avg); move16();
1498 : }
1499 : ELSE
1500 : {
1501 :
1502 0 : *pReX++ = mult_r(mag_chg[k], tmp); move16();
1503 0 : *pImX-- = mult_r(mag_chg[k], im); move16();
1504 : }
1505 0 : i = add(i, 1);
1506 0 : ASSERT(*pReX == X[i]);
1507 0 : if (sub(i, gwlpr_fxPlus1[k]) > 0)
1508 : {
1509 0 : k = add(k, 1);
1510 : }
1511 : } /* segment_len last valley */
1512 :
1513 :
1514 :
1515 :
1516 : #ifdef DYNMEM_COUNT
1517 : Dyn_Mem_Out();
1518 : #endif
1519 : #ifdef WMOPS
1520 : pop_wmops();
1521 : #endif
1522 0 : }
1523 :
1524 0 : void my_wtda_fx(const Word16 *new_audio, /* i : input audio to be windowed Q0 20 ms , OPT can be output as well */
1525 : const Word16 *const win2ms_init, /* i: 2 ms initial part of pre_tda window */
1526 : const Word16 *const win16ms_center, /* i: 16 ms combined part of pre_tda IWHR+MDCT-ana */
1527 : Word32 *L_wtda_audio, /* o : tda audio Q16 20 ms */
1528 : const Word16 L, Word8 *scratchBuffer) /* Size = 8 * MAX_L_FRAME */
1529 : {
1530 : Word16 i, L2; /*,L4;*/
1531 : const Word16 *pX;
1532 : const Word16 *pW;
1533 : Word32 *p1_L, *p2_L, *p3_L, *p4_L;
1534 : Word32 *L_w_audio; /*OPt 1 use input buffer , OPT2, may be shortened from 20 ms to 16 ms due to
1535 : zeroed parts*/
1536 : Word32 *pY_L, *pa1_L, *pa2_L;
1537 :
1538 : #ifdef DYNMEM_COUNT
1539 : Dyn_Mem_In("my_wtda_fx", sizeof(struct {
1540 : Word16 i, L2; /*,L4;*/
1541 : const Word16 *pX;
1542 : const Word16 *pW;
1543 : Word32 *p1_L, *p2_L, *p3_L, *p4_L;
1544 : Word32 *L_w_audio; /*OPT 1 use input buffer, OPT2, may be shortened from 20 ms to 16.25+(1.75) ms
1545 : due to zeroed parts*/
1546 : Word32 *pY_L, *pa1_L, *pa2_L;
1547 : }));
1548 : #endif
1549 :
1550 : #ifdef WMOPS
1551 : push_wmops("PhECU::my_wtda_fx");
1552 : #endif
1553 :
1554 0 : L_w_audio = (Word32 *)scratchAlign(scratchBuffer, 0); /* Size = 4 * 2 * MAX_L_FRAME */
1555 :
1556 : /* |111111|222222|333333|444444 */
1557 : /* |p1 p2| p3||p4 */
1558 :
1559 : /* Apply analysis window */
1560 :
1561 0 : pX = new_audio;
1562 0 : pY_L = L_w_audio;
1563 :
1564 0 : pW = win2ms_init;
1565 0 : FOR(i = 0; i < ((2 * L / 10)); i++) /* Loop over 2ms window MDCT-ana length */
1566 : {
1567 0 : *pY_L++ = L_mult(*pX++, *pW++); move32();
1568 : }
1569 :
1570 0 : pW = win16ms_center;
1571 : /* 20 ms - 2ms - 3.75 ms = 14.25 ms */
1572 0 : FOR(i = 0; i < (2 * L - (2 * L / 10) - ((3 * 2 * L) / 16));
1573 : i++) /* Loop over remaining 14.25ms, currently out of a 16 ms stored length */
1574 : {
1575 0 : *pY_L++ = L_mult(*pX++, *pW++); move32();
1576 : }
1577 :
1578 :
1579 : /* tda */
1580 0 : L2 = shr_pos_pos(L, 1); /* length of tda blocks */
1581 :
1582 0 : p1_L = L_w_audio; /* block 1 fwd */
1583 0 : p2_L = L_w_audio + L - 1; /* block 2 rev */
1584 0 : p3_L = L_w_audio + L + L2 - 1; /* block 3 rev */
1585 0 : p4_L = L_w_audio + L + L2; /* block 4 fwd */
1586 :
1587 0 : pa1_L = L_wtda_audio; /* first part output */
1588 0 : pa2_L = L_wtda_audio + L2; /* second part output */
1589 :
1590 0 : FOR(i = 0; i < (L / 8); i++)
1591 : {
1592 : /* first 1.25ms part of tda signal -p3_rev -p4_fwd */
1593 0 : *pa1_L++ = L_negate(L_add_sat(*p3_L--, *p4_L++)); move32();
1594 : }
1595 0 : FOR(; i < L2; i++)
1596 : {
1597 : /* first front part 3.75 ms p4_l is zeroes -p3_rev + (-p4_fwd==0) */
1598 0 : *pa1_L++ = L_negate(*p3_L--); move32();
1599 : }
1600 :
1601 0 : FOR(i = 0; i < L2; i++)
1602 : {
1603 : /* second part of tda signal p1 -p2_rev */
1604 0 : *pa2_L++ = L_sub_sat(*p1_L++, *p2_L--); move32();
1605 : }
1606 :
1607 : #ifdef DYNMEM_COUNT
1608 : Dyn_Mem_Out();
1609 : #endif
1610 : #ifdef WMOPS
1611 : pop_wmops();
1612 : #endif
1613 0 : return;
1614 : }
1615 :
1616 : /*--------------------------------------------------------------------------
1617 : * rec_wtda()
1618 : *
1619 : * Windowing and TDA of reconstructed frame
1620 : *--------------------------------------------------------------------------*/
1621 :
1622 :
1623 : static void
1624 0 : rec_wtda_fx(
1625 : Word16 *X, /* i : iFFT(X-evolved) TD-signal o: dbg 16 ms */
1626 : Word32 *L_ecu_rec, /* o : Reconstructed frame in tda domain Qx? */
1627 : const Word16 output_frame, /* i : Frame length */
1628 : const Word16 Lprot, /* i : Prototype frame length */
1629 : const Word16 *const win2ms_init, /* i: 2 ms initial part of pre_tda window */
1630 : const Word16 *const win16ms_center, /* i: 16 ms combined part of pre_tda IWHR+MDCT-ana */
1631 : const Word16 maxLen,
1632 : const Word16 *prevsynth,
1633 : const Word16 Q_psMinus1, /*i: Q prev_synth minus 1 , (-1 to match Q of Xsav in first bfi frame ) */
1634 : Word8 *scratchBuffer) /* Size = 12 * MAX_L_FRAME */
1635 : {
1636 : Word16 l, Lprot2;
1637 : Word16 *rec_buf;
1638 : Word16 *xsubst_; /*,*out_ptr;*/
1639 :
1640 : Word16 ola_old[COPY_LEN_48K + OLA_LEN_48K]; /* 3.75 ms */
1641 : Word16 work_len;
1642 : Word16 copy_len;
1643 : Word16 ola_len;
1644 :
1645 :
1646 : Word8 *buffer_wtda;
1647 :
1648 : #ifdef DYNMEM_COUNT
1649 : Dyn_Mem_In("rec_wtda_fx", sizeof(struct {
1650 : Word16 l, Lprot2;
1651 : Word16 *rec_buf;
1652 : Word16 *xsubst_; /*,*out_ptr;*/
1653 : Word8 *buffer_wtda;
1654 : }));
1655 : #endif
1656 :
1657 : #ifdef WMOPS
1658 : push_wmops("PhECU::rec_wtda_fx");
1659 : #endif
1660 :
1661 0 : rec_buf = scratchAlign(scratchBuffer, 0); /* Size = 2 * 2 * MAX_L_FRAME */
1662 0 : buffer_wtda = (Word8 *)scratchAlign(rec_buf, sizeof(*rec_buf) * (2 * maxLen)); /* Size = 4 * 2 * MAX_L_FRAME */
1663 :
1664 0 : xsubst_ = rec_buf;
1665 0 : Lprot2 = shr_pos_pos(Lprot, 1);
1666 :
1667 : /* extract reconstructed frame with ld window into rec_buf */
1668 0 : l = sub(output_frame, Lprot2);
1669 0 : basop_memmove(xsubst_ + l, X, (Lprot) * sizeof(Word16)); /* 16 ms IFFT raw output */
1670 0 : copy_len = COPY_LEN[FRAME2FS_IDX(output_frame)];
1671 0 : ola_len = OLA_LEN[FRAME2FS_IDX(output_frame)];
1672 0 : work_len = add(copy_len, ola_len);
1673 : /* Copy and scale copy part 2ms from prevsynth */
1674 0 : basop_memmove(rec_buf, &prevsynth[Lprot - work_len], (copy_len) * sizeof(Word16)); /* 2ms out of 3.75 ms copied */
1675 0 : Scale_sig_sat(rec_buf, copy_len, sub(-3, Q_psMinus1)); /* inplace scaling by 2^(-Q_ps-4) */
1676 :
1677 :
1678 : /* Copy, window and scale 1.75 ms ola part from prevsynth , into a temporary buffer ola_old */
1679 :
1680 :
1681 0 : windowing_ola(&prevsynth[Lprot - ola_len], ola_old, w_old[FRAME2FS_IDX(output_frame)], ola_len); /* 1.75 ms */
1682 :
1683 0 : Scale_sig_sat(ola_old, ola_len, sub(-3, Q_psMinus1)); /* inplace scaling by 2^(-Qps-4) */
1684 :
1685 : /* Window 1.75 ms length inplace recreated X=IFFT(prototype) signal copied into rec_buf signal */
1686 0 : windowing_ola(&rec_buf[copy_len], &rec_buf[copy_len], w_new[FRAME2FS_IDX(output_frame)], ola_len);
1687 : /* mix add the two windowed components */
1688 0 : ola_add(&rec_buf[copy_len], ola_old, &rec_buf[copy_len], ola_len); /* OPT: sat check */
1689 :
1690 0 : my_wtda_fx(rec_buf,
1691 : win2ms_init, /* i: 2 ms initial part of pre_tda window */
1692 : win16ms_center, /* i: 16 ms combined part of pre_tda IWHR+MDCT-ana */
1693 : L_ecu_rec, output_frame, buffer_wtda); /* */
1694 :
1695 :
1696 : #ifdef DYNMEM_COUNT
1697 : Dyn_Mem_Out();
1698 : #endif
1699 : #ifdef WMOPS
1700 : pop_wmops();
1701 : #endif
1702 :
1703 0 : return;
1704 : }
1705 :
1706 : /*--------------------------------------------------------------------------
1707 : * rec_frame_fx()
1708 : *
1709 : * Frame reconstruction
1710 : *--------------------------------------------------------------------------*/
1711 0 : void rec_frame_fx(Word16 * x, /* i : FFT spectrum 16 ms, o: ifft() TD debug signal 16ms */
1712 : Word32 * L_ecu_rec, /* o : Reconstructed frame in tda domain 10ms buffer */
1713 : const Word16 output_frame, /* i : Frame length */
1714 : const Word16 Q, /* i : Xsav Q */
1715 : const Word16 *const win2ms_init, /* i: 2 ms initial part of pre_tda window */
1716 : const Word16 *const win16ms_center, /* i: 16 ms combined part of pre_tda IWHR+MDCT-ana */
1717 : Word16 maxLprot,
1718 : const Word16 *prevsynth,
1719 : const Word16 Q_prevsynthMinus1, /* i : prevsynthQ-1 or xfp Q */
1720 : Word8 *scratchBuffer /* Size = 4 * MAX_LPROT + 12 * MAX_L_FRAME */
1721 : )
1722 : {
1723 : Counter i;
1724 : Word16 Lprot;
1725 : Word32 *L_x;
1726 : Word32 *pX_L;
1727 : Word16 *pX;
1728 : Word16 fft_scale;
1729 : Word8 * buffer_fft;
1730 :
1731 : #ifdef DYNMEM_COUNT
1732 : Dyn_Mem_In("rec_frame_fx", sizeof(struct {
1733 : Counter i;
1734 : Word16 Lprot;
1735 : Word32 *L_x;
1736 : Word32 *pX_L;
1737 : Word16 *pX;
1738 : Word16 fft_scale;
1739 : Word8 * buffer_fft;
1740 : }));
1741 : #endif
1742 :
1743 : #ifdef WMOPS
1744 : push_wmops("PhECU::rec_frame_fx");
1745 : #endif
1746 :
1747 0 : L_x = (Word32 *)scratchAlign(scratchBuffer, 0); /* Size = 4 * MAX_LPROT */
1748 0 : buffer_fft = (Word8 *)scratchAlign(L_x, sizeof(*L_x) * maxLprot); /* Size = 4* (2+1) * MAX_L_FRAME */
1749 :
1750 : /* Initialize to FB constants */
1751 0 : Lprot = mult(output_frame, (Word16)(32768.0 / 99.0)); /* truncation needed , i.e no rounding can be applied here */
1752 0 : ASSERT(Lprot == (output_frame / 100));
1753 0 : Lprot = LprotSzPtr[Lprot]; move16();
1754 :
1755 :
1756 : /* Convert stored 16 bit into 32bit for fft */
1757 0 : flippedW16_2_intlvW32(x, sub(shr_pos_pos(Lprot, 1), 1), Lprot, L_x);
1758 : /*scratch x now free for re-use */
1759 :
1760 0 : fft_scale = -1; move16();
1761 :
1762 : #ifdef WMOPS
1763 : push_wmops("PhECU::IFFT_fx");
1764 : #endif
1765 0 : BASOP_irfftN(L_x, Lprot, &fft_scale, buffer_fft);
1766 : #ifdef WMOPS
1767 : pop_wmops();
1768 : #endif
1769 :
1770 0 : pX_L = &L_x[0];
1771 0 : pX = &x[0]; /* scratch x reused */
1772 :
1773 : {
1774 0 : FOR(i = 0; i < Lprot; i++)
1775 : {
1776 0 : *pX++ = extract_h(L_shl_sat(*pX_L++, fft_scale)); move16();
1777 : }
1778 : }
1779 : /* Scratch L_x may be released */
1780 :
1781 :
1782 : /* Saturation possible when rescaling to Q0 if there are random bit errors in the bit stream
1783 : * One may use one guard bit to better handle this - though it should not be needed for normal
1784 : * operation.
1785 : */
1786 0 : Scale_sig_sat(x, Lprot, negate(Q)); /* scale by 2^(-Q) */
1787 :
1788 : /*scratch x is Lprot word16 */
1789 : /* scatch need for win-TDA XXX */
1790 : /* scrcatch need for TDA XXX */
1791 :
1792 0 : rec_wtda_fx(x, L_ecu_rec, output_frame, Lprot,
1793 : win2ms_init, /* i: 2 ms initial part of pre_tda window */
1794 : win16ms_center, /* i: 16 ms combined part of pre_tda IWHR+MDCT-ana */
1795 0 : s_max(output_frame, 160),
1796 : prevsynth,
1797 : Q_prevsynthMinus1, /* NB: prevsynth Q may change from prev_bfi=0 to prev_bfi==1, due to phase
1798 : of signal or PLC2-muting */
1799 : buffer_fft);
1800 :
1801 :
1802 : #ifdef DYNMEM_COUNT
1803 : Dyn_Mem_Out();
1804 : #endif
1805 : #ifdef WMOPS
1806 : pop_wmops();
1807 : #endif
1808 0 : return;
1809 : }
1810 :
1811 : /*--------------------------------------------------------------------------
1812 : * hq_phase_ecu_fx()
1813 : *
1814 : * Main routine for HQ phase ECU
1815 : *--------------------------------------------------------------------------*/
1816 0 : void hq_phase_ecu_fx(
1817 : const Word16 *prevsynth, /* i : buffer of previously synthesized signal currently 16ms */
1818 : Word32 * L_ecu_rec, /* o : reconstructed frame in tda domain , also tmp w32_fft buffer */
1819 : Word16 * time_offs, /* i/o: Sample offset for consecutive frame losses*/
1820 : Word16 * X_sav, /* i/o: Stored spectrum of prototype frame */
1821 : Word16 * Q_spec, /* o: Q value of stored spectrum */
1822 : Word16 * num_p, /* i/o: Number of identified peaks */
1823 : Word16 * plocs, /* i/o: Peak locations */
1824 : Word32 * L_plocsi, /* i/o: Interpolated peak locations Q16 */
1825 : const Word16 env_stab, /* i : Envelope stability parameter */
1826 : const Word16 f0hzLtpBinQ7, /* i: LTP bin frequency in normalized Hz Q7 */
1827 : const Word16 norm_corrQ15_fx, /*i : correlation for lag at f0hzLtpBinQ7 */
1828 : const Word16 prev_bfi, /* i : indicating burst frame error */
1829 : Word16 old_is_transient[2], /* i/o : flags indicating noise generation frames */
1830 : Word16 * mag_chg_1st, /* i/o: per band magnitude modifier for transients*/
1831 : Word16 * mag_chg_gr, /* o: per band magnitude modifier, incl burst attenuation */
1832 : Word16 * Xavg, /* i/o: Frequency group average gain to fade to */
1833 : Word16 * beta_mute, /* o : Factor for long-term mute */
1834 : const Word16 bwidth_fx, /* i : Encoded bandwidth */
1835 : const Word16 output_frame, /* i : frame length */
1836 : Word16 * seed_out_fxPtr, /* o: utput dbg NULL may be used*/
1837 : Word16 * X_out, /* o: utput dbg NUll may be used */
1838 : const Word16 t_adv, /* i : time adjustment including time_offs */
1839 : const Word16 *const win2ms_init, /* i: 2 ms initial part of pre_tda window */
1840 : const Word16 *const win16ms_center, /* i: 16 ms combined part of pre_tda IWHR+MDCT-ana */
1841 : const Word16 *sp_ana_win, /* i : whr 3+10+3 window */
1842 : Word16 q_fx_old_exp, /* i : exp of prev_synth */
1843 :
1844 : Word16 maxLprot, /* i : maz spectrum buffer size */
1845 : Word16 maxPlocs, /* i : max nb of peaks */
1846 : Word32 L_oold_xfp_w_E_fx, Word16 oold_xfp_w_E_exp_fx, /* exp of time signale */
1847 : Word16 oold_Ltot_exp_fx, /*true exp of energy */
1848 : Word16 *oold_grp_shape_fx, Word32 L_old_xfp_w_E_fx, Word16 old_xfp_w_E_exp_fx, /* exp of time signale */
1849 : Word16 old_Ltot_exp_fx, /*true exp of energy */
1850 : Word16 *old_grp_shape_fx,
1851 : Word16 margin_prevsynth,
1852 : const Word16 fadeout,
1853 : Word16 *nonpure_tone_flag_ptr, /* i/o : non-pure single tone indicator state */
1854 : Word8 *scratchBuffer /* Size = 2 * MAX_LGW + 8 * MAX_LPROT + 12 * MAX_L_FRAME */
1855 : )
1856 : {
1857 : Word16 lprot;
1858 : Word16 *mag_chg, ph_dith, *X;
1859 : Word16 *xfp;
1860 : Word16 seed;
1861 : Word16 alpha[MAX_LGW], beta[MAX_LGW] ;
1862 : Word16 prevsynth_man_upshift;
1863 : Word16 Q_prevsynthMinus1;
1864 : Word8 *buffer;
1865 : Word32 L_Xavg[MAX_LGW]; /* i/o : Frequency group amp averages for tonal tilt analysis Max upshifted */
1866 : #ifdef DYNMEM_COUNT
1867 : Dyn_Mem_In("hq_phase_ecu_fx", sizeof(struct {
1868 : Counter i;
1869 : Word16 lprot;
1870 : Word16 *mag_chg, ph_dith, *X;
1871 : Word16 seed;
1872 : Word16 alpha[MAX_LGW], beta[MAX_LGW];
1873 : Word16 prevsynth_man_upshift;
1874 : Word16 Q_prevsynthMinus1;
1875 : Word8 *buffer;
1876 : // ToDO Word32 L_Xavg[MAX_LGW];
1877 : }));
1878 : #endif
1879 :
1880 : if (!prev_bfi)
1881 : {
1882 : #ifdef WMOPS
1883 : push_wmops("PhECU::hq_phase_ecu_fx(1st)");
1884 : #endif
1885 : }
1886 : else
1887 : {
1888 : #ifdef WMOPS
1889 : push_wmops("PhECU::hq_phase_ecu_fx(N)");
1890 : #endif
1891 : }
1892 :
1893 0 : mag_chg = (Word16 *)scratchAlign(scratchBuffer, 0); /* Size = 2 * MAX_LGW */
1894 0 : X = (Word16 *)scratchAlign(mag_chg, sizeof(*mag_chg) * MAX_LGW); /* Size = 2 * MAX_LPROT == 1 Word16*MAX_LPROT */
1895 0 : xfp = (Word16 *)scratchAlign(X, sizeof(*X) * maxLprot); /* Size = 2 * MAX_LPROT == 1 Word16*MAX_LPROT */
1896 0 : buffer = (Word8 *)scratchAlign(xfp, sizeof(*xfp) * maxLprot); /* Size = 4 * MAX_LPROT + 12 * MAX_L_FRAME */
1897 :
1898 : /* buffer size = Word32 * MAX_LPROT (FFT, IFFT) DRAM
1899 : + 3*Word32 * MAX_L_FRAME */
1900 :
1901 0 : basop_memset(alpha, 0, MAX_LGW*sizeof(Word16));
1902 0 : basop_memset(beta, 0, MAX_LGW*sizeof(Word16));
1903 :
1904 0 : lprot = LprotSzPtr[bwidth_fx]; move16();
1905 :
1906 0 : test();
1907 0 : ASSERT(prev_bfi >= 0 && prev_bfi <= 1);
1908 0 : IF( prev_bfi == 0 ) /* inside PhECU we can check vs 0 */
1909 : {
1910 0 : *time_offs = 0; move16();
1911 0 : *nonpure_tone_flag_ptr = -1; move16(); /* flag nonpure tone flag for new analysis */
1912 : /* analysis made outside, up/down scaling here from static RAM to dynamic RAM */
1913 : /* prevsynth_in_flt = prev_synth_man*2.^(-15 + exp_old) */
1914 : /* X_sav_flt = X_man/2.^(Q_spec) */
1915 :
1916 : /* 1 bit headroom needed in xfp_tmp_buf for FFT processing into X_sav */
1917 : /* margin_prevsynth = actual margin in incoming 16 ms xpf segment */
1918 : /* q_fx_old_exp was computed on full 21+ ms updatepcm buffer) */
1919 :
1920 0 : ASSERT(margin_prevsynth >= 0 && (margin_prevsynth <= 16));
1921 :
1922 : prevsynth_man_upshift =
1923 0 : sub(margin_prevsynth, 1); /* 0 --> -1(==down), 1--> 0 , 2 --> 1(==up), ... */
1924 0 : ASSERT(prevsynth_man_upshift >= -16 && prevsynth_man_upshift <= 15); /* avoid Overflow in shr, shl */
1925 0 : *Q_spec = sub(15, sub(q_fx_old_exp, prevsynth_man_upshift));
1926 : /* Q_spec target is to create 1 additional bit of margin in the xfp TD buffer , before converting to
1927 : * Xsav
1928 : */
1929 :
1930 0 : if (margin_prevsynth == 0)
1931 : {
1932 0 : Word16 Qold = 15 - (q_fx_old_exp + 1);
1933 0 : Word16 tmp_man_upshift = margin_prevsynth - 1; /* 1 .. -15 */
1934 0 : Word16 Qnew = 15 - (q_fx_old_exp - tmp_man_upshift);
1935 0 : assert(Qold == Qnew);
1936 : UNUSED(Qold);
1937 : UNUSED(Qnew);
1938 : }
1939 0 : if (margin_prevsynth == 1)
1940 : {
1941 0 : Word16 Qold = 15 - (q_fx_old_exp + 0);
1942 0 : assert(*Q_spec == Qold);
1943 : UNUSED(Qold);
1944 : }
1945 0 : if (margin_prevsynth == 2)
1946 : {
1947 0 : Word16 Qold = 15 - (q_fx_old_exp - 1);
1948 0 : assert(*Q_spec == Qold);
1949 : UNUSED(Qold);
1950 : }
1951 :
1952 0 : Q_prevsynthMinus1 = sub(15, add(q_fx_old_exp, +1)); /* dbg to use non-scaled prevsynth for OLA */
1953 :
1954 : /* Q of prev_synth now separated from prev_bfi=0 and prev_bfi==1 */
1955 :
1956 : #ifdef USE_TMPXFP_IN_OLA
1957 : Q_prevsynthMinus1 = *Q_spec; /* a possibly upscaled Q */
1958 : #endif
1959 :
1960 :
1961 0 : Copy_Scale_sig(
1962 : prevsynth, xfp, lprot,
1963 : prevsynth_man_upshift); /* unscaled prevsynth is still used by rec_frame, copy to a temporary
1964 : xfp analysis buffer, and scale down to a margin of 1 bit */
1965 :
1966 :
1967 0 : trans_burst_ana_fx(
1968 : ((void *)NULL),
1969 0 : mag_chg, &ph_dith, mag_chg_1st, output_frame, *time_offs, env_stab, alpha, beta, beta_mute, Xavg,
1970 0 : (*Q_spec), L_oold_xfp_w_E_fx, oold_xfp_w_E_exp_fx, oold_Ltot_exp_fx, oold_grp_shape_fx,
1971 : L_old_xfp_w_E_fx, old_xfp_w_E_exp_fx, old_Ltot_exp_fx, old_grp_shape_fx,
1972 : fadeout,
1973 : L_Xavg, /* full scale band amplitudes in first bfi frame */
1974 : buffer);
1975 :
1976 0 : spec_ana_fx(&(xfp[0]), plocs, L_plocsi, num_p, X_sav, output_frame, bwidth_fx,
1977 : sp_ana_win, f0hzLtpBinQ7, norm_corrQ15_fx, maxLprot, maxPlocs, buffer);
1978 : }
1979 : ELSE
1980 : {
1981 : /* analysis made outside, possible up/down scaling here from static RAM to dynamic RAM */
1982 0 : ASSERT(margin_prevsynth >= 0 && (margin_prevsynth <= 15));
1983 :
1984 : /* prev_synth may have been scaled outside by update_pcm() function */
1985 : /* prevsynth_in_flt = prev_synth_man*2.^(-15 + exp_old) */
1986 : /* first bfi frame: X_sav_flt = X_man/2.^(*Q_spec) */
1987 : /* this bfi frame prev_synth(TD) is mixed with ifft signal(TD,from Q_spec) in rec_frame_fx
1988 : variable Q_prevsynthMinus1 provided to rec_frame for this TD+TD mixing
1989 : */
1990 :
1991 0 : Q_prevsynthMinus1 = sub(15, add(q_fx_old_exp, +1)); /* for now, "old" use of unscaled prevsynth for added OLA */
1992 :
1993 : #ifdef USE_TMPXFP_IN_OLA
1994 : { /* DBG target here is to instead upshift to a zero margin */
1995 : /* but Q value is maintained to match the save Xsav *Q_spec which is used with an offset of " -1" */
1996 : /* prevsynth_man_upshift = -prevsynth_margin ; */
1997 : Word16 tmp, worklen = add(hamm_len2Tab[bwidth_fx], shr(hamm_len2Tab[bwidth_fx], 2));
1998 : tmp = mult(7680, lprot); /* needs to truncate to integer */
1999 : ASSERT(tmp == worklen);
2000 : Copy_Scale_sig(&prevsynth[lprot - worklen], &xfp[lprot - worklen], worklen,
2001 : margin_prevsynth); /* only scale up last 3.75 ms */
2002 : Q_prevsynthMinus1 = sub(15, add(q_fx_old_exp, margin_prevsynth)); /*-1 does not make sense */
2003 : }
2004 : #endif
2005 :
2006 0 : *time_offs = add_sat(*time_offs, output_frame);
2007 :
2008 0 : trans_burst_ana_fx(
2009 : ((void *)NULL),
2010 0 : mag_chg, &ph_dith, mag_chg_1st, output_frame, *time_offs, env_stab, alpha, beta, beta_mute, Xavg,
2011 : (0), /* *Q_spec input only used in first bfi frames for burst analysis */
2012 : L_oold_xfp_w_E_fx, oold_xfp_w_E_exp_fx, oold_Ltot_exp_fx, oold_grp_shape_fx, L_old_xfp_w_E_fx,
2013 : old_xfp_w_E_exp_fx, old_Ltot_exp_fx, old_grp_shape_fx,
2014 : fadeout,
2015 : NULL, /* full scale band amplitudes , only used in first bfi frame */
2016 : buffer);
2017 : }
2018 : /* cpy LPROT Word16 from Static RAM Xsav to working DRAM/scratch buffer X ;*/
2019 0 : basop_memmove(X, X_sav, (lprot) * sizeof(Word16));
2020 : /* seed for own_rand2 */
2021 0 : seed = *time_offs; move16();
2022 :
2023 0 : if (mag_chg_gr != NULL) /* o: dbg per band magnitude modifier, incl. burst attenuation */
2024 : {
2025 : Counter k;
2026 0 : Word16 lgw_local = s_min(add(bwidth_fx, LGW8K), LGW48K); /* 4,5,6,7, (7/8) */
2027 0 : for (k = 0; k < lgw_local; k++)
2028 : {
2029 0 : mag_chg_gr[k] = mag_chg[k]; /* dbg SNR output */
2030 : }
2031 : }
2032 :
2033 0 : subst_spec_fx(plocs, L_plocsi, num_p, *time_offs, X, mag_chg, ph_dith, old_is_transient, output_frame,
2034 : &seed, alpha, beta,
2035 : Xavg, t_adv
2036 : ,fadeout,
2037 : nonpure_tone_flag_ptr, /* i/o : non-pure single tone indicator state */
2038 : L_Xavg /*i : only used in first bfi frame */
2039 : );
2040 :
2041 0 : if (seed_out_fxPtr != NULL)
2042 : {
2043 0 : *seed_out_fxPtr = seed; /* verify seed synch after subst_spec */
2044 : }
2045 :
2046 :
2047 0 : if (X_out != NULL)
2048 : {
2049 : Word16 ii;
2050 0 : for (ii = 0; ii < lprot; ii++)
2051 : {
2052 0 : X_out[ii] = X[ii]; /* evolve spectrum, no moves counted as this is a dbg-vector info cpy */
2053 : }
2054 : }
2055 :
2056 : /* reconstructed frame in tda domain */
2057 : /* NB *Q_spec only updated in first bfi frame */
2058 :
2059 : /*Scratch Analysis at this point */
2060 : /* X fft input needed as evolved spectrum Lprot* Word16 */
2061 : /* xfp not needed any longer Word16* Lprot */
2062 : /* IFFT operation needs Word32*Lprot in and Word32*Lprot out */
2063 : /* MDCT win operation may be inplace 2x MAX_L_FRAME */
2064 : /* TDA output is 1x MAX_L_FRAME */
2065 :
2066 0 : rec_frame_fx(X, L_ecu_rec, output_frame, *Q_spec,
2067 : win2ms_init, win16ms_center,
2068 : maxLprot,
2069 : #ifdef USE_TMPXFP_IN_OLA
2070 : xfp, /* only last 3.75 ms used, in both prevbfi=0 and prevBfi=1 i.e frames, xfp is an
2071 : upscaled prev_synth */
2072 : #else
2073 : prevsynth, /*only last 3.75 ms used in both prevbfi=0 and prevBfi=1 i.e frames */
2074 : #endif
2075 : Q_prevsynthMinus1,
2076 : buffer);
2077 :
2078 :
2079 : #ifdef DYNMEM_COUNT
2080 : Dyn_Mem_Out();
2081 : #endif
2082 : #ifdef WMOPS
2083 : pop_wmops();
2084 : #endif
2085 0 : }
2086 :
2087 :
2088 0 : static Word16 sqrt2ndOrder( /* o: in Q15 (2nd order least square approx.) */
2089 : const Word16 x /* i: x must be in between 0.5 and 1.0 (Q15). */
2090 : )
2091 : {
2092 : Word32 acc;
2093 : Word16 z;
2094 : #ifdef WMOPS
2095 : push_wmops("PhECU::sqrt2ndOrder");
2096 : #endif
2097 :
2098 0 : ASSERT(x >= 16384);
2099 :
2100 0 : acc = 1890205600L; /* 0.880195572812922 in Q31 */ move32();
2101 0 : z = mac_r(acc, x, -6506); /* -0.198537395405340 in Q15 */
2102 0 : acc = 682030261L; /* 0.317595089462249 in Q31 */ move32();
2103 0 : z = mac_r(acc, z, x); /* in Q15 */
2104 :
2105 :
2106 : #ifdef WMOPS
2107 : pop_wmops();
2108 : #endif
2109 0 : return z;
2110 : }
2111 :
2112 :
2113 : /* Modified version to produce Word32 input to FFT */
2114 0 : static void windowing_L(
2115 : const Word16 *x, /* i: Input signal */
2116 : Word32 * L_y, /* o: Windowed output */
2117 : const Word16 *win, /* i: Window coefficients */
2118 : const Word16 rectLength, /* i: Offset in between the 1st and 2nd symmetric halves of the Hamming window */
2119 : const Word16 halfLength /* i: Half of the total length of a complete Hamming window. */
2120 : )
2121 : {
2122 : Counter i;
2123 : Word32 * pY_L;
2124 : const Word16 *pX, *pW;
2125 : Word16 tmp_RL;
2126 :
2127 : #ifdef DYNMEM_COUNT
2128 : Dyn_Mem_In("windowing_L", sizeof(struct {
2129 : Counter i;
2130 : Word32 * pY_L;
2131 : const Word16 *pX, *pW;
2132 : }));
2133 : #endif
2134 :
2135 : #ifdef WMOPS
2136 : push_wmops("PhECU::windowing_L");
2137 : #endif
2138 :
2139 0 : pX = x;
2140 0 : pW = win;
2141 0 : pY_L = L_y;
2142 :
2143 0 : FOR(i = 0; i < halfLength; i++) /* 1st symmetric half of the Hamming window */
2144 : {
2145 0 : *pY_L++ = L_mult(*pX++, *pW++); move32();
2146 : }
2147 : /* Periodic filter - one more rect sample before end tapering */
2148 :
2149 0 : tmp_RL = add(rectLength, 1);
2150 :
2151 0 : if (rectLength == 0)
2152 : {
2153 0 : tmp_RL = 0; move16();
2154 : }
2155 : /* If rectLength is zero, it's a pure Hamming window; otherwise Hamming-Rectangular. */
2156 0 : FOR(i = 0; i < tmp_RL;i++)
2157 : {
2158 0 : *pY_L++ = L_deposit_h(*pX++); move32();
2159 : }
2160 0 : tmp_RL = sub(halfLength, 1);
2161 0 : if (rectLength == 0)
2162 : {
2163 0 : tmp_RL = halfLength; move16();
2164 : }
2165 0 : FOR(i = 0; i < tmp_RL; i++) /* 2nd symmetric half of the Hamming window. */
2166 : {
2167 0 : *pY_L++ = L_mult(*pX++, *(--pW)); move32();
2168 : }
2169 :
2170 : #ifdef DYNMEM_COUNT
2171 : Dyn_Mem_Out();
2172 : #endif
2173 : #ifdef WMOPS
2174 : pop_wmops();
2175 : #endif
2176 0 : }
2177 :
2178 : /* Modified version to produce Word16 input to FFT */
2179 0 : static void windowing_ola(const Word16 *x, /* i: Input signal */
2180 : Word16 * y, /* o: Windowed output */
2181 : const Word16 *win, /* i: Window coefficients */
2182 : const Word16 Length /* i: Half of the total length of a complete Hamming window. */
2183 : )
2184 : {
2185 : Counter i;
2186 : Word16 * pY;
2187 : const Word16 *pX, *pW;
2188 :
2189 : #ifdef DYNMEM_COUNT
2190 : Dyn_Mem_In("windowing_ola", sizeof(struct {
2191 : Counter i;
2192 : Word16 * pY;
2193 : const Word16 *pX, *pW;
2194 : }));
2195 : #endif
2196 :
2197 : #ifdef WMOPS
2198 : push_wmops("PhECU::windowing_ola");
2199 : #endif
2200 :
2201 0 : pX = x;
2202 0 : pW = win;
2203 0 : pY = y;
2204 :
2205 0 : FOR(i = 0; i < Length; i++) /* 1st symmetric half of the Hamming window */
2206 : {
2207 0 : *pY++ = mult_r(*pX++, *pW++); move16();
2208 : }
2209 :
2210 : #ifdef DYNMEM_COUNT
2211 : Dyn_Mem_Out();
2212 : #endif
2213 : #ifdef WMOPS
2214 : pop_wmops();
2215 : #endif
2216 0 : }
2217 :
2218 : /* Modified version to produce Word16 input to FFT */
2219 0 : static void ola_add(const Word16 *x, /* i: Input signal 1 */
2220 : const Word16 *y, /* i: Input signal 2 */
2221 : Word16 * z, /* o: Output signal */
2222 : const Word16 Length /* i: Half of the total length of a complete window. */
2223 : )
2224 : {
2225 : Counter i;
2226 : Word16 * pZ;
2227 : const Word16 *pX, *pY;
2228 :
2229 : #ifdef DYNMEM_COUNT
2230 : Dyn_Mem_In("windowing_ola", sizeof(struct {
2231 : Counter i;
2232 : Word16 * pY;
2233 : const Word16 *pX, *pW;
2234 : }));
2235 : #endif
2236 :
2237 :
2238 :
2239 0 : pX = x;
2240 0 : pY = y;
2241 0 : pZ = z;
2242 :
2243 0 : FOR(i = 0; i < Length; i++) /* 1st symmetric half of the Hamming window */
2244 : {
2245 0 : *pZ++ = add_sat(*pX++, *pY++); move16();
2246 : }
2247 :
2248 : #ifdef DYNMEM_COUNT
2249 : Dyn_Mem_Out();
2250 : #endif
2251 :
2252 0 : }
2253 :
2254 : /*-----------------------------------------------------------------------------
2255 : * magnSqrtApprox_fx()
2256 : *
2257 : * Approximation of sqrt(Square magnitude) of fft spectrum
2258 : * if min_abs <= 0.4142135*max_abs
2259 : * abs = 0.99*max_abs + 0.197*min_abs
2260 : * else
2261 : * abs = 0.84*max_abs + 0.561*min_abs
2262 : * end
2263 : *
2264 : * Note: even to handle the dynamics of sqrt(re^2+im^2) located on
2265 : * a scaled unit circle. One need to scale down the results
2266 : * with a factor 2, that is Q_out = Q_in - 1
2267 : * sqrt(32768.^2+32768.^2) results in = 23170 Q0-1,
2268 : * which corresponds to 46341 in the Q0 domain
2269 : *----------------------------------------------------------------------------*/
2270 0 : Word16 sqrtMagnApprox_fx( /* o : sqrt of magnitude square spectrum Q_in-1*/
2271 : const Word16 re, /* i : Real part Q_in */
2272 : const Word16 im /* i : Imag part Q_in */
2273 : )
2274 : {
2275 : /* Constants for Approximation of sqrt(Square magnitude) of fft spectrum
2276 : * >> num2str(round(0.4142135]*2.^15))
2277 : * ans = 13573
2278 : * >> num2str(round([0.99 0.197 0.84 0.561]*2.^14))
2279 : * ans = 16220 3228 13763 9191
2280 : */
2281 :
2282 : #define C_0p4142135_Q15 13573
2283 :
2284 : #define C_0p99_Q14 16220
2285 : #define C_0p197_Q14 3228
2286 : #define C_0p84_Q14 13763
2287 : #define C_0p561_Q14 9191
2288 : Word16 sgn_bit, re_abs, im_abs, max_abs, min_abs, sum;
2289 0 : Word16 jcoeffs[2][2] = { {C_0p99_Q14, C_0p197_Q14}, {C_0p84_Q14, C_0p561_Q14} };
2290 :
2291 : #ifdef DYNMEM_COUNT
2292 : Dyn_Mem_In("sqrtMagnApprox_fx", sizeof(struct {
2293 : Word16 sgn_bit, re_abs, im_abs, max_abs, min_abs, sum;
2294 : Word16 jcoeffs[2][2];
2295 : }));
2296 : #endif
2297 :
2298 : #ifdef WMOPS
2299 : push_wmops("PhECU::sqrtMagnApprox_fx");
2300 : #endif
2301 :
2302 : /* Get values and move pointers */
2303 0 : re_abs = abs_s(re); /* 1 cycle */
2304 0 : im_abs = abs_s(im); /* 1 cycle */
2305 :
2306 : /* Find max and min value */
2307 0 : min_abs = s_min(re_abs, im_abs); /* 1 cycle */
2308 0 : max_abs = s_max(re_abs, im_abs); /* 1 cycle */
2309 :
2310 : /* Calc approximation depending on relation */
2311 0 : sgn_bit = lshr(sub(mult(max_abs, C_0p4142135_Q15), min_abs), 15); /* 3 cycles */
2312 0 : sum = mac_r(L_mult(max_abs, jcoeffs[sgn_bit][0]), min_abs, jcoeffs[sgn_bit][1]); /* 2 cycles */
2313 : #ifdef DYNMEM_COUNT
2314 : Dyn_Mem_Out();
2315 : #endif
2316 : #ifdef WMOPS
2317 : pop_wmops();
2318 : #endif
2319 0 : return sum;
2320 : }
2321 :
2322 : /*-----------------------------------------------------------------------------
2323 : * fft_spec2_sqrt_approx_fx()
2324 : *
2325 : * Approximation of sqrt(Square magnitude) of fft spectrum
2326 : * if min_abs <= 0.4142135*max_abs
2327 : * abs = 0.99 max_abs + 0.197*min_abs
2328 : * else
2329 : * abs = 0.84 max_abs + 0.561*min_abs
2330 : * end
2331 : *
2332 : * Note: even to handle the dynamics of sqrt(re^2+im^2) located on
2333 : * a scaled unit circle. One need to scale down the results
2334 : * with a factor 2, that is Q_out = Q_in - 1
2335 : * sqrt( -32768.^2 + -32768.^2 ) results in = 23170 Qin-1,
2336 : * which corresponds to 46341 in the Qin domain
2337 : *----------------------------------------------------------------------------*/
2338 :
2339 0 : void fft_spec2_sqrt_approx_fx(const Word16 x[], /* i : Input vector: complex spectrum , Qin */
2340 : Word16 xMagSqrt[], /* o : sqrt of magnitude square spectrum Qout=Qin-1*/
2341 : const Word16 N /* i : Input vector x length */
2342 : )
2343 : {
2344 : Counter i;
2345 : Word16 l;
2346 : const Word16 *pRe, *pIm;
2347 : Word16 * pMagSqrt;
2348 :
2349 : #ifdef DYNMEM_COUNT
2350 : Dyn_Mem_In("fft_spec2_sqrt_approx_fx", sizeof(struct {
2351 : Counter i;
2352 : Word16 l;
2353 : const Word16 *pRe, *pIm;
2354 : Word16 * pMagSqrt;
2355 : }));
2356 : #endif
2357 :
2358 : #ifdef WMOPS
2359 : push_wmops("PhECU::fft_spec2_sqrt_approx_fx");
2360 : #endif
2361 :
2362 : /* Magnitude at 0. only real component */
2363 0 : pMagSqrt = &xMagSqrt[0];
2364 0 : pRe = &x[0];
2365 0 : *pMagSqrt++ = mult(abs_s(*pRe++), C_0p99_Q14); move16();
2366 :
2367 : /* From 1 to (N/2 - 1). */
2368 0 : pIm = &x[N - 1];
2369 :
2370 0 : l = sub(shr_pos_pos(N, 1), 1); /* N/2 - 1. */
2371 0 : l = s_min(l, (LPROT48K_RED / 2 - 1) + DELTA_CORR_F0_INT);
2372 : /* at 48 k the top 8 khz are always zero, and further peaks are not
2373 : located above LPROT48K_RED 32 kHz */
2374 0 : FOR(i = 0; i < l; i++)
2375 : {
2376 0 : *pMagSqrt++ = sqrtMagnApprox_fx(*pRe++, *pIm--); move16();
2377 : }
2378 :
2379 : /* The sqrt magnitude square at N/2 - only real component */
2380 0 : *pMagSqrt = mult(abs_s(*pRe), C_0p99_Q14); move16();
2381 :
2382 : #ifdef DYNMEM_COUNT
2383 : Dyn_Mem_Out();
2384 : #endif
2385 : #ifdef WMOPS
2386 : pop_wmops();
2387 : #endif
2388 0 : return;
2389 : }
2390 :
2391 : Word16
2392 0 : imax2_jacobsen_mag_fx(/* o: The location, relative to the middle of the 3 given data point, of the maximum.
2393 : (Q15) */
2394 : const Word16 *y_re, /* i: The 3 given data points. real part order -1 0 1 */
2395 : const Word16 *y_im, /* i: The 3 given data points. imag part order 1 0 -1 (from FFT)*/
2396 : const Word16
2397 : special /* i: -1 = left edge special case, 0 = normal, +1 = right edge special case */
2398 : )
2399 : {
2400 : Word16 posi;
2401 : Word16 man, expo;
2402 : const Word16 *pY;
2403 : Word16 y_m1_re, y_0_re, y_p1_re;
2404 : Word16 y_m1_im, y_0_im, y_p1_im;
2405 :
2406 : Word16 D_re, D_im, N_re, N_im;
2407 :
2408 : Word32 L_sign, L_denom, L_numer;
2409 :
2410 : #ifdef DYNMEM_COUNT
2411 : Dyn_Mem_In("imax2_jacobsen_mag_fx", sizeof(struct {
2412 : Word16 posi;
2413 : Word16 man, expo;
2414 : const Word16 *pY;
2415 : Word16 y_m1_re, y_0_re, y_p1_re;
2416 : Word16 y_m1_im, y_0_im, y_p1_im;
2417 : Word16 D_re, D_im, N_re, N_im;
2418 : Word32 L_sign, L_denom, L_numer;
2419 : }));
2420 : #endif
2421 :
2422 : #ifdef WMOPS
2423 : push_wmops("PhECU::imax2_jacobsen_mag_fx");
2424 : #endif
2425 :
2426 : /* Jacobsen estimates peak offset relative y_0 using
2427 : * X_m1 - X_p1
2428 : * d = REAL ( ------------------- ) * c_jacob
2429 : * 2*X_0 - X_m1 -Xp1
2430 : *
2431 : * Where c_jacob is a window dependent constant
2432 : */
2433 : #define C_JACOB_Q14 18725 /* c_jacob = 1.1429; % assume 0.1875 hammrect window 'periodic' */
2434 :
2435 0 : ASSERT(special == 0); /* always use other imax for edges cases */
2436 : UNUSED(special);
2437 :
2438 : /* Get the bin parameters into variables */
2439 0 : pY = y_re;
2440 0 : y_m1_re = *pY++;
2441 0 : y_0_re = *pY++;
2442 0 : y_p1_re = *pY++;
2443 :
2444 : /* Same for imaginary parts - note reverse order from FFT */
2445 0 : pY = y_im;
2446 0 : y_p1_im = *pY++;
2447 0 : y_0_im = *pY++;
2448 0 : y_m1_im = *pY++;
2449 :
2450 0 : test();
2451 0 : IF( norm_s(y_0_re) == 0 || norm_s(y_0_im) == 0 )
2452 : {
2453 : #define JACOB_MARGIN 2
2454 : /* for very high peaks the Complex denominator values may need to be downshifted 2 steps */
2455 0 : y_0_re = shr_pos(y_0_re, JACOB_MARGIN);
2456 0 : y_0_im = shr_pos(y_0_im, JACOB_MARGIN);
2457 :
2458 0 : y_m1_re = shr_pos(y_m1_re, JACOB_MARGIN);
2459 0 : y_m1_im = shr_pos(y_m1_im, JACOB_MARGIN);
2460 :
2461 0 : y_p1_re = shr_pos(y_p1_re, JACOB_MARGIN);
2462 0 : y_p1_im = shr_pos(y_p1_im, JACOB_MARGIN);
2463 : }
2464 :
2465 : /* prepare numerator real and imaginary parts*/
2466 0 : N_re = sub(y_m1_re, y_p1_re);
2467 0 : N_im = sub(y_m1_im, y_p1_im);
2468 :
2469 : /* prepare denominator real and imaginary parts */
2470 :
2471 0 : D_re = sub(sub(shl_pos(y_0_re, 1), y_m1_re), y_p1_re);
2472 0 : D_im = sub(sub(shl_pos(y_0_im, 1), y_m1_im), y_p1_im);
2473 :
2474 : /* REAL part of complex division */
2475 0 : L_numer = L_mac0(L_mult0(N_re, D_re), N_im, D_im);
2476 0 : L_denom = L_mac0(L_mult0(D_re, D_re), D_im, D_im);
2477 0 : L_sign = L_xor(L_numer, L_denom); /* Preserve the sign since div_s() only takes positive arguments. */
2478 :
2479 0 : L_numer = L_abs(L_numer);
2480 0 : L_denom = L_abs(L_denom);
2481 :
2482 0 : test();
2483 0 : IF(L_numer != 0 && L_denom != 0)
2484 : {
2485 :
2486 0 : man = plc_phEcu_ratio_fx(L_numer, L_denom, &expo); /* The mantissa is considered in Q15 */
2487 :
2488 0 : man = mult_r(man, C_JACOB_Q14);
2489 0 : posi = shr_sat( man, sub(expo, 2));
2490 : /* to Q15 (and due to saturation, it is automatically bound inside [-1.0,1.0].) */
2491 :
2492 0 : if (L_sign < 0) /* Restore the sign. */
2493 : {
2494 0 : posi = negate(posi);
2495 : }
2496 : }
2497 : ELSE
2498 : {
2499 0 : posi = 0; move16(); /* flat top, division is not possible choose center freq */
2500 : }
2501 :
2502 : #ifdef DYNMEM_COUNT
2503 : Dyn_Mem_Out();
2504 : #endif
2505 : #ifdef WMOPS
2506 : pop_wmops();
2507 : #endif
2508 0 : return posi; /* Q15. The position either left or right relative to the index of the middle of the 3 given
2509 : data points. */
2510 : }
2511 :
2512 : /* Convert 32 Bit FFT into 16 bit fft domain */
2513 0 : static void intlvW32_2_flippedW16(
2514 : Word32 * L_x, /* i : interleaved coeffs DC, Fs/2, Re(1),Im(1), Re(2),Im(2), ... ] */
2515 : const Word16 numPairs, /* i: typically (fft-size/2 -1), re/im coeffs to copy */
2516 : const Word16 Lprot, /* i: fft size , including DC+fs/2 */
2517 : Word16 * x /* o : flipped coeffs , [DC, Re(1),.. Re(N-1/2) , Fs/2, Im(N-1/2) ... Im(1) ] */
2518 : )
2519 : {
2520 :
2521 : /* reorder real and imag components, and apply fractional scale for 24/48Khz */
2522 : Counter m;
2523 : Counter numPairsLocal;
2524 0 : Word32 *pX_L = &L_x[2]; /*ptr init*/
2525 0 : Word16 *pX_Re = &x[1]; /*ptr init*/
2526 0 : Word16 *pX_Im = &x[Lprot - 1]; /*ptr init*/
2527 :
2528 : #define FHG_FFT_UPSHIFT 2
2529 :
2530 : #ifdef WMOPS
2531 : push_wmops("PhECU::intlvW32_2_flippedW16");
2532 : #endif
2533 : #ifdef DYNMEM_COUNT
2534 : Dyn_Mem_In("intlvW32_2_flippedW16", sizeof(struct {
2535 : Counter m;
2536 : Counter numPairsLocal;
2537 : Word32 *pX_L;
2538 : Word16 *pX_Re;
2539 : Word16 *pX_Im;
2540 : }));
2541 : #endif
2542 :
2543 : /* make the scaling of 8/3= 4*0.666 here for 24 kHz and 48 kHz using 16x16 instead or 32x16 ops
2544 : a limited loss of SNR */
2545 :
2546 0 : test();
2547 0 : IF(sub(numPairs, 383) == 0 || sub(numPairs, 191) == 0)
2548 : { /* 24,48 kHz , 16 ms , scale by 8/3 = .666*4 */
2549 0 : numPairsLocal = s_min(numPairs, 383 - 63); /* do not copy bins above 20 kHz */
2550 : /* for 48 kHz is to only go up to 40 kHz pairs , */
2551 0 : FOR(m = 0; m < numPairsLocal; m++)
2552 : {
2553 : /* multiply by (8/3)*(2.^FHG_FFT_UPSHIFT) */
2554 : /* note: multiplication by 2/3 need to preceed upshift , due to FFT scaling being very close to the 48/24 3
2555 : * split kHz bit margin */
2556 0 : *pX_Re++ = extract_h(L_shl_pos(Mpy_32_16_lc3plus(*pX_L++, FEC_TWOTHIRDS_Q15), FHG_FFT_UPSHIFT + 2));
2557 0 : move16();
2558 0 : *pX_Im-- = extract_h(L_shl_pos(Mpy_32_16_lc3plus(*pX_L++, FEC_TWOTHIRDS_Q15), FHG_FFT_UPSHIFT + 2));
2559 0 : move16();
2560 : }
2561 : /* Place the two real only components */
2562 0 : x[0] = extract_h(L_shl_pos(Mpy_32_16_lc3plus(L_x[0], FEC_TWOTHIRDS_Q15), FHG_FFT_UPSHIFT + 2)); /* DC */
2563 0 : move16();
2564 0 : m = shr_pos_pos(Lprot, 1);
2565 0 : x[m] = extract_h(L_shl_pos(Mpy_32_16_lc3plus(L_x[1], FEC_TWOTHIRDS_Q15), FHG_FFT_UPSHIFT + 2)); /* fs/2 */
2566 0 : move16();
2567 : }
2568 : ELSE
2569 : { /* 8,16,32 kHz 16 ms no additional scaling by 8/3 */
2570 :
2571 0 : FOR(m = 0; m < numPairs; m++)
2572 : {
2573 0 : *pX_Re++ = extract_h(L_shl_pos(*pX_L++, FHG_FFT_UPSHIFT));
2574 0 : move16();
2575 0 : *pX_Im-- = extract_h(L_shl_pos(*pX_L++, FHG_FFT_UPSHIFT));
2576 0 : move16();
2577 : }
2578 :
2579 : /* Place the two real only components */
2580 0 : x[0] = extract_h(L_shl_pos(L_x[0], FHG_FFT_UPSHIFT)); /* DC */ move16();
2581 0 : m = shr_pos_pos(Lprot, 1);
2582 0 : x[m] = extract_h(L_shl_pos(L_x[1], FHG_FFT_UPSHIFT)); /* fs/2 */ move16();
2583 : }
2584 :
2585 : #ifdef DYNMEM_COUNT
2586 : Dyn_Mem_Out();
2587 : #endif
2588 : #ifdef WMOPS
2589 : pop_wmops();
2590 : #endif
2591 0 : }
2592 :
2593 0 : static void flippedW16_2_intlvW32(
2594 : Word16 * x, /* i : flipped coeffs , [DC, Re(1),.. Re(N-1/2) , Fs/2, Im(N-1/2) ... Im(1) ] */
2595 : const Word16 numPairs, /* i: typically (fft-size/2 -1), re/im coeffs to copy */
2596 : const Word16 Lprot, /* i: fft size , including DC+fs/2 */
2597 : Word32 * L_x /* o : interleaved coeffs DC, Fs/2, Re(1),Im(1), Re(2),Im(2), ... ] */
2598 : )
2599 : {
2600 : Counter i;
2601 : Counter numPairsLocal;
2602 : Word32 *pX_L;
2603 : Word16 *pX_re, *pX_im;
2604 : #ifdef WMOPS
2605 : push_wmops("PhECU::flippedW16_2_intlvW32");
2606 : #endif
2607 : #ifdef DYNMEM_COUNT
2608 : Dyn_Mem_In("flippedW16_2_intlvW32", sizeof(struct {
2609 : Counter i;
2610 : Counter numPairsLocal;
2611 : Word32 *pX_L;
2612 : Word16 *pX_re, *pX_im;
2613 : }));
2614 : #endif
2615 :
2616 : /* Convert stored 16 bit into 32bit for fft */
2617 : /* Note during save FFT output was left shifted FHG_FFT_UPSHIFT */
2618 : /* this needs to be restored before one calls ifft to avoid overflow */
2619 :
2620 0 : pX_L = &L_x[2]; /*ptr init*/
2621 0 : pX_re = &x[1]; /*ptr init*/
2622 0 : pX_im = &x[Lprot - 1]; /*ptr init*/
2623 :
2624 0 : numPairsLocal = s_min(320, numPairs); /* 48kHz optimization */
2625 0 : FOR(i = 0; i < numPairsLocal; i++)
2626 : {
2627 0 : *pX_L++ = L_shr_pos(L_deposit_h(*pX_re++), FHG_FFT_UPSHIFT); move32();
2628 0 : *pX_L++ = L_shr_pos(L_deposit_h(*pX_im--), FHG_FFT_UPSHIFT); move32();
2629 : }
2630 : /* at 48KHz zero tail 2x63= 126 bins for Word32 IFFT input */
2631 0 : basop_memset(pX_L, 0, sizeof(Word32) * shl_pos(sub(numPairs, numPairsLocal), 1));
2632 :
2633 : /* Place the two real only components */
2634 0 : L_x[0] = L_shr_pos(L_deposit_h(x[0]), FHG_FFT_UPSHIFT); move32();
2635 0 : L_x[1] = L_shr_pos(L_deposit_h(x[Lprot / 2]), FHG_FFT_UPSHIFT); move32();
2636 :
2637 : #ifdef DYNMEM_COUNT
2638 : Dyn_Mem_Out();
2639 : #endif
2640 : #ifdef WMOPS
2641 : pop_wmops();
2642 : #endif
2643 0 : }
2644 :
2645 0 : void get_sin_cosQ10opt(Word16 phase, /* Q10 0..1023 i.e. 1024=2*pi */
2646 : Word16 * ptrSin, /* Q15 */
2647 : Word16 * ptrCos /* Q15 */
2648 : )
2649 : {
2650 : Word16 sign_val, idx, idx2, idx3;
2651 :
2652 : #ifdef DYNMEM_COUNT
2653 : Dyn_Mem_In("get_sin_cosQ10", sizeof(struct { Word16 sign_val, idx, idx2, idx3; }));
2654 : #endif
2655 :
2656 : #ifdef WMOPS
2657 : push_wmops("PhECU::get_sin_cosQ10opt");
2658 : #endif
2659 :
2660 : /* sin table has a range up to pi/2 (256+1)=257 coeffs*/
2661 :
2662 0 : sign_val = shr_pos_pos(phase, 9); /* highest bit is the sinus sign */
2663 0 : idx = s_and(phase, 0x1ff); /* mask away sign */
2664 :
2665 0 : idx2 = sub(idx, 256);
2666 0 : if (idx2 < 0)
2667 : { /*rising sine part */
2668 0 : *ptrSin = sin_quarterQ15_fx[idx]; move16();
2669 : }
2670 :
2671 0 : idx3 = sub(512, idx);
2672 0 : if (idx2 >= 0)
2673 : { /* decaying part, reverse idx */
2674 0 : *ptrSin = sin_quarterQ15_fx[idx3]; move16();
2675 : }
2676 :
2677 0 : if (sign_val != 0)
2678 : {
2679 0 : *ptrSin = negate(*ptrSin); /*no move when inlined , no sat as max in table is 32767 */
2680 : }
2681 :
2682 : /*cos*/
2683 0 : idx = add(phase, 256); /* +pi/2, i.e. move to cos phase */
2684 0 : idx = s_and(idx, 0x3ff); /* wrap on 10 bits limit */
2685 :
2686 0 : sign_val = shr_pos_pos(idx, 9); /* highest bit is the sign */
2687 0 : idx = s_and(idx, 0x1ff); /* mask away sign */
2688 :
2689 0 : idx2 = sub(idx, 256);
2690 0 : if (idx2 < 0)
2691 : { /*rising sine part */
2692 0 : *ptrCos = sin_quarterQ15_fx[idx]; move16();
2693 : }
2694 :
2695 0 : idx3 = sub(512, idx);
2696 0 : if (idx2 >= 0)
2697 : { /* decaying part, reverse idx*/
2698 0 : *ptrCos = sin_quarterQ15_fx[idx3]; move16();
2699 : }
2700 :
2701 0 : if (sign_val != 0)
2702 : {
2703 0 : *ptrCos = negate(*ptrCos); /* no move when inlined , no sat as max in table is 32767 */
2704 : }
2705 :
2706 : #ifdef DYNMEM_COUNT
2707 : Dyn_Mem_Out();
2708 : #endif
2709 : #ifdef WMOPS
2710 : pop_wmops();
2711 : #endif
2712 0 : }
2713 :
2714 0 : static Word16 plc_phEcu_nonpure_tone_ana_fx(const Word16* plocs,
2715 : const Word16 n_plocs,
2716 : const Word16* X, /*i: { DC, Re1,Re2 ,.....ReN , Fs/2, ImN... , Im2, Im1} */
2717 : const Word32 *L_Xavg, /* i : Frequency group amp averages for tonal tilt analysis Max upshifted */
2718 : const Word16 Lprot,
2719 : const Word16 fs_idx)
2720 : {
2721 : #ifdef DYNMEM_COUNT
2722 : Dyn_Mem_In("PhECU::nonpure_tone_ana", sizeof(struct {
2723 : Word16 nonpure_tone_detect;
2724 : Word16 n_ind, tone_ind, low_ind, high_ind;
2725 : Word16 peak_amp, peak_amp2, valley_amp, x_abs[(1 + 2 * ONE_SIDED_SINE_WIDTH + 2 * 1)];
2726 : Word16 sineband_ind_low, sineband_ind_high;
2727 : Word16 i, N_grp;
2728 : Word16 tmp, tmp_dB;
2729 : Word32 L_tot_inc_HF, L_tot_inc_LF;
2730 : Word16* pRe;
2731 : Word16* pIm;
2732 : Word16* gwlpr_fxPlus1;
2733 : Word32 L_nf;
2734 : Word32 L_XavgL2_fx[MAX_LGW + 1];
2735 : Word32 L_XavgUp_fx[MAX_LGW + 1];
2736 : }));
2737 : #endif
2738 :
2739 : #ifdef WMOPS
2740 : push_wmops("PhEcu::nonpure_tone_ana_fx");
2741 : #endif
2742 :
2743 : Word16 nonpure_tone_detect; /* output variable */
2744 : Word16 n_ind, tone_ind, low_ind, high_ind;
2745 : Word16 peak_amp, peak_amp2, valley_amp, x_abs[(1 + 2 * ONE_SIDED_SINE_WIDTH + 2 * 1)];
2746 :
2747 : Word16 sineband_ind_low, sineband_ind_high;
2748 : Word16 i, N_grp;
2749 : Word16 tmp;
2750 :
2751 : Word32 L_Ltot_inc_HF, L_Ltot_inc_LF;
2752 : Word32 L_tmp_dB;
2753 :
2754 : const Word16* pRe;
2755 : const Word16* pIm;
2756 : const Word16* gwlpr_fxPlus1;
2757 : Word32 L_nf;
2758 : Word32 L_XavgL2_fx[MAX_LGW + 1], L_tmp ;
2759 : Word32 L_XavgUp_fx[MAX_LGW + 1]; /* upscaled values , excluding peak band(s) */
2760 :
2761 : /* use of a compressed hearing sensitivity curve allowing more energy deviation in highest and lowest bands */
2762 : /* ROM table Word16 scATHFx[MAX_LGW - 1] */
2763 :
2764 : /* init */
2765 0 : nonpure_tone_detect = 0; move16(); /* Word16 register with decisions */
2766 :
2767 0 : peak_amp = 0; move16();
2768 0 : peak_amp2 = 0; move16();
2769 :
2770 : /* limit single sine optimization to when 2 peaks are close enough to represent a single sinusoid */
2771 0 : test();
2772 0 : if ((sub(n_plocs, 2) == 0) &&
2773 0 : (sub(sub(plocs[1], plocs[0]), ONE_SIDED_SINE_WIDTH) >= 0)
2774 : ) /* NB, plocs is an ordered vector */
2775 : {
2776 0 : nonpure_tone_detect = s_or(nonpure_tone_detect, 0x01);
2777 : }
2778 :
2779 : /* local bin wise dynamics analysis, for 1 or 2 initial local maxima peaks ,
2780 : if 2 peaks , we do the analysis based on the location of the largest abs peak */
2781 : {
2782 0 : tone_ind = 0; move16(); /* one peak only , use position plocs[tone_ind], tone_ind==0 */
2783 :
2784 0 : peak_amp = shr(abs_s(X[0]), 1); /* plocs[0]=0, simply multiply DC*0.5 to match scaling in function sqrtMagnApprox_fx */
2785 0 : test();
2786 0 : IF(plocs[0] != 0)
2787 : {
2788 0 : peak_amp = sqrtMagnApprox_fx(X[plocs[0]], X[sub(Lprot, plocs[0])]);
2789 : }
2790 :
2791 0 : IF(sub(n_plocs, 2) == 0) /* locate abs max peak */
2792 : {
2793 0 : peak_amp2 = sqrtMagnApprox_fx(X[plocs[1]], X[sub(Lprot, plocs[1])]); /* Re-part and Im-part in different ends of array X */
2794 :
2795 0 : tmp = sub(peak_amp, peak_amp2);
2796 0 : tone_ind = lshr(tmp, 15); /* mask out sign bit 0(for peak_amp0), 1( for peak_amp2), lshr --> no sign extension in shift */
2797 0 : peak_amp = s_max(peak_amp, peak_amp2);
2798 : }
2799 :
2800 0 : low_ind = s_max(1, sub(plocs[tone_ind], (ONE_SIDED_SINE_WIDTH + 1))); /* DC is not allowed in the range */
2801 0 : high_ind = s_min(sub(shr(Lprot, 1), 2), add(plocs[tone_ind], (ONE_SIDED_SINE_WIDTH + 1))); /* Fs/2 is not allowed in the range */
2802 :
2803 0 : n_ind = add(sub(high_ind, low_ind), 1);
2804 : /* find lowest amplitude around the assumed main lobe center location */
2805 :
2806 0 : pRe = &(X[low_ind]); /* ptr init */
2807 0 : pIm = &(X[Lprot - low_ind]); /* ptr init*/
2808 0 : FOR(i = 0; i < n_ind; i++)
2809 : {
2810 0 : x_abs[i] = sqrtMagnApprox_fx(*pRe++, *pIm--); move16(); /* x_abs is downscaled by 0.5 in abs(complex) approximation */
2811 : }
2812 :
2813 0 : valley_amp = peak_amp; move16();
2814 0 : FOR(i = 0; i < n_ind; i++)
2815 : {
2816 0 : valley_amp = s_min(x_abs[i], valley_amp);
2817 : }
2818 :
2819 : /* at least a localized amplitude ratio of 16 (24 dB) required to declare a pure noise-free sinusoid */
2820 0 : if (sub(shr(peak_amp, 4), valley_amp) < 0) /* 1/16 */
2821 : {
2822 0 : nonpure_tone_detect = s_or(nonpure_tone_detect, 0x02); /* not a pure tone due to too low local SNR P2V */
2823 : }
2824 : }
2825 :
2826 :
2827 : /* analyze LF/ HF bands energy dynamics vs the assumed single tone band ( for one or two peaks found cases ) */
2828 : {
2829 : /* Xavg , is a vector of rather rough MDCT based band amplitude estimates in perceptually motivated bands. from approx the last 26 ms of synthesis */
2830 :
2831 : /* eval amplitude relations for assumed tonal band vs lower and higher bands */
2832 : /*N_grp = xavg_N_grp[fs_idx];*/ /* { 4 NB , 5 WB , 6 SSWB , 7 SWB, 8 FB }; */
2833 0 : N_grp = add(fs_idx, 4);
2834 0 : assert(fs_idx < 5);
2835 :
2836 :
2837 : /* establish band(s) with assumed sinusoid tone */
2838 : /* if tone freq location is below first MDCT-band definition, use first band as band location anyway */
2839 :
2840 : /* band 0 , 1 , 2 , 3 , ...*/
2841 : /* dct-inds "c" "0"...11, 12...19, 20...35, 36 ... */
2842 : /* gwplr_fx= [ 1 , 12(750Hz), 20(1250Hz) , 36 , ... */ /* lowest lim+1 in gwplr */
2843 :
2844 : /* for-loop BASOP version */
2845 0 : tmp = 0; move16();
2846 0 : gwlpr_fxPlus1 = &(gwlpr_fx[1]); /* ptr init */
2847 0 : FOR(i = 0; i < N_grp; i++)
2848 : {
2849 0 : if (sub(plocs[tone_ind], gwlpr_fxPlus1[i]) >= 0)
2850 : {
2851 0 : tmp = add(i, 1);
2852 : }
2853 : }
2854 :
2855 0 : sineband_ind_low = tmp; move16();
2856 0 : sineband_ind_high = tmp; move16(); /* typically in the same band as low */
2857 :
2858 : /* a single tone may end up on a band border
2859 : , handle case when assumed tone is more or less right in-between two perceptual bands +/- 4*62.5 Hz */
2860 :
2861 0 : test(); logic16();
2862 0 : if ((sineband_ind_high > 0) &&
2863 0 : (sub(sub(plocs[tone_ind], ONE_SIDED_SINE_WIDTH), gwlpr_fx[add(sineband_ind_high, 1)]) >= 0)
2864 : )
2865 : {
2866 0 : sineband_ind_low = sub(sineband_ind_high, 1);
2867 : }
2868 :
2869 0 : logic16();
2870 0 : if ((sub(sineband_ind_low, sub(N_grp, 1)) < 0) &&
2871 0 : (sub(add(plocs[tone_ind], ONE_SIDED_SINE_WIDTH), gwlpr_fx[add(sineband_ind_low, 1)]) >= 0)
2872 : )
2873 : {
2874 0 : sineband_ind_high = add(sineband_ind_low, 1);
2875 : }
2876 : }
2877 :
2878 : /* intraframe(26 ms), weighted LB and HB envelope dynamics/variation analysis */
2879 : /* envelope analysis ,
2880 : require at least two HF or two LF bands in the envelope taper/roll-off analysis , otherwise skip this condition */
2881 :
2882 0 : logic16();
2883 0 : test(); logic16();
2884 0 : IF( (nonpure_tone_detect == 0) &&
2885 : ( (sub( add(sineband_ind_high, 2), N_grp) < 0 ) ||
2886 : (sub(sineband_ind_low, 2+1 ) >= 0)
2887 : )
2888 : )
2889 : {
2890 :
2891 : /* delta taper-off analysis solution, less sensitive to input bandwidth limitation and levels */
2892 :
2893 : /* test Xavg Word16 result above vs a high resolution Word32 L_Xavg */
2894 : /* strong spectral tilt causes HF to be truncated in Word16 */
2895 :
2896 0 : basop_memcpy(L_XavgUp_fx, L_Xavg, N_grp * sizeof(Word32) ) ;
2897 :
2898 : /* first remove all energy from the assumed tonal peak band(s) */
2899 0 : L_XavgUp_fx[sineband_ind_low] = L_min(L_XavgUp_fx[sineband_ind_low], 1); move32();
2900 0 : L_XavgUp_fx[sineband_ind_high] = L_min(L_XavgUp_fx[sineband_ind_high], 1); move32();
2901 :
2902 0 : tmp = getScaleFactor32_0(L_XavgUp_fx, N_grp); /* o: measured headroom in range [0..32], 32 if all L_x[i] == 0 */
2903 0 : if (sub(tmp, 32) == 0)
2904 : {
2905 0 : nonpure_tone_detect = s_or(nonpure_tone_detect, 0x100); /* also set a flag for an all zero L_Xavg coarse spectrum estimate signal */
2906 : }
2907 :
2908 :
2909 : /* add noise floor to L_Xavg before log2 function call */
2910 0 : L_nf = L_shl(1L, sub(tmp, 1));
2911 0 : L_nf = L_max(L_nf, 1L);
2912 0 : for (i = 0; i < N_grp; i++)
2913 : {
2914 0 : L_XavgUp_fx[i] = L_shl_sat(L_XavgUp_fx[i], tmp); move32(); /* maximize precision before actual log2_fx(Word32) calc call */
2915 :
2916 0 : L_tmp = L_XavgUp_fx[i]; move32();
2917 0 : test();
2918 0 : if (L_tmp <= 0)
2919 : {
2920 0 : L_tmp = L_nf; move32();
2921 : }
2922 :
2923 : /* log2(Upshifted Word32) */
2924 : /* maximize precision in BASOP Log2 function */
2925 0 : L_XavgL2_fx[i] = BASOP_Util_Log2_lc3plus(L_tmp); /* L_input 1.0 or lower --> output always negative */
2926 : /* add 31.0 to store as fractional bits of an upscaled positive Word32 integer input ) */
2927 0 : L_XavgL2_fx[i] = L_add(31L << 25, L_XavgL2_fx[i]); /* only diffs added so 31.0 is cancelled out later , in total only values between +/- 2^6 = [-64 ... -64[ are possible */
2928 : } /* band i for L_Xavg calc*/
2929 : /* verify that an assumed clean sine does not have any odd HF content indications by thresholding the accumulated delta rise in LF/HF side lobes */
2930 0 : L_Ltot_inc_HF = 0; move32();
2931 0 : for (i = (sineband_ind_high + 1); i < (N_grp - 1); i++)
2932 : {
2933 0 : L_tmp_dB = 0; move32();
2934 0 : if (L_sub(L_Xavg[i], L_Xavg[i + 1]) < 0) /* only increases are accumulated */
2935 : {
2936 0 : L_tmp_dB = L_sub(L_XavgL2_fx[i + 1], L_XavgL2_fx[i]); /* obtain ratio in log2 domain */
2937 : }
2938 0 : L_tmp = Mpy_32_16_lc3plus(L_tmp_dB, scATHFx[i]); /* scATHFx[i] is the ATH weight for band i and band i+1 */
2939 0 : L_tmp = L_shr_pos(L_tmp, 1); /* Q25 -> Q24 */
2940 :
2941 0 : L_Ltot_inc_HF = L_add(L_Ltot_inc_HF, L_tmp); /* Q24 */
2942 : }
2943 :
2944 : /* verify that an assumed clean sine does not have any odd LF content by thresholding the accumulated LF reverse up tilt */
2945 :
2946 0 : L_Ltot_inc_LF = 0; move32();
2947 0 : tmp = s_max(0, sub(sineband_ind_low, 1)); /* could also be pointer init */
2948 0 : for (i = tmp; i > 0; i--)
2949 : {
2950 0 : L_tmp_dB = 0; move32();
2951 0 : if (L_sub(L_Xavg[i - 1], L_Xavg[i]) > 0) /* only increases are accumulated */
2952 : {
2953 0 : L_tmp_dB = L_sub(L_XavgL2_fx[i - 1], L_XavgL2_fx[i]); /* obtain ratio in log2 domain */
2954 : }
2955 0 : L_tmp = Mpy_32_16_lc3plus(L_tmp_dB, scATHFx[i-1]); /* scATHFx[i-1] is the ATH weight in between band i-1 and band i */
2956 0 : L_tmp = L_shr_pos(L_tmp, 1); /* Q25 -> Q24 */
2957 0 : L_Ltot_inc_LF = L_add(L_Ltot_inc_LF, L_tmp); /* Q24 */
2958 : }
2959 :
2960 0 : if (L_sub(L_Ltot_inc_HF, SIDE_LIM) > 0) /* side_lim=round(Q24x*0.7474) */
2961 : {
2962 : /* 4.5 dB in log2 is 0.7474 */
2963 0 : nonpure_tone_detect = s_or(nonpure_tone_detect, 0x10); /* still not a pure tone, too great HF side increase */
2964 : }
2965 :
2966 0 : if (L_sub(L_Ltot_inc_LF, SIDE_LIM) > 0) /* side_lim=round(Q24x*0.7474) */
2967 : {
2968 : /* 4.5 dB in log2 is 0.7474 */
2969 0 : nonpure_tone_detect = s_or(nonpure_tone_detect, 0x20); /* still not a pure tone, too great HF side increase */
2970 : }
2971 :
2972 : /* verify that an assumed clean sine does not have any odd LF+HF content by thresholding the accumulated LF+HF unexpected tilt */
2973 0 : if (L_sub(L_add_sat(L_Ltot_inc_LF, L_Ltot_inc_HF), LFHF_LIM) > 0) /* side_lim=round(Q24x*0.7474) */
2974 : {
2975 : /* 6.0 dB in log2 is 0.996578428 */
2976 0 : nonpure_tone_detect = s_or(nonpure_tone_detect, 0x40); /* still not a pure tone, too great LF+HF side increase */
2977 : }
2978 :
2979 : } /* bands available*/
2980 :
2981 : #ifdef WMOPS
2982 : pop_wmops();
2983 : #endif
2984 :
2985 0 : return nonpure_tone_detect;
2986 : }
|