Line data Source code
1 : /******************************************************************************
2 : * ETSI TS 103 634 V1.5.1 *
3 : * Low Complexity Communication Codec Plus (LC3plus) *
4 : * *
5 : * Copyright licence is solely granted through ETSI Intellectual Property *
6 : * Rights Policy, 3rd April 2019. No patent licence is granted by implication, *
7 : * estoppel or otherwise. *
8 : ******************************************************************************/
9 :
10 : #include "defines.h"
11 : #include "functions.h"
12 :
13 : #define RES_fx 1 /* fixed point resolution */
14 :
15 : /*-----------------------------------------------------------------------------
16 : * peak_locator_fx()
17 : *----------------------------------------------------------------------------*/
18 0 : void plc_phEcu_peak_locator_fx(const Word16 *inp, /* i: vector with values >=0 ,Qx */
19 : const Word16 inp_len, /* i: length of inp */
20 : Word16 * int_plocs, /* o: array of filtered integer plocs Q0 */
21 : Word16 * n_fsc, /* o: total_ number of filtered located highs Q0 */
22 : const Word16 sens, /* i sensitivity, Qx */
23 : const Word16 inp_high, /* i global high , Qx */
24 : const Word16 inp_low, /* i: global low, Qx */
25 : Word16 maxLprot_Red, /* i: optional size for wc memory alloc of scratch buffer */
26 : Word8 *scratchBuffer /* i: : scratch buffer 2* 3*(1+1+(maxLprot_Red/2)+1) */
27 : )
28 : {
29 : Counter j, k, n, idx_high, idx_low;
30 : Word16 inp_len_minus1 ;
31 : Word16 pairs_start, pairs_end;
32 : Word16 *p_tmp;
33 : Word16 prev_delta, curr_delta;
34 : Word16 delta_predc, delta_fin;
35 : Word16 add_dc_flag, add_fin_flag;
36 : Word16 low_val_cand_pairs, val_range;
37 : Word16 num_pairs, n_tail_values;
38 : Word16 cand_phase_start, cand_idx, prev_low_plus_sens, tmp;
39 :
40 : Word16 cand_high, prev_low;
41 : Word16 *sc_idx; /* 1+ 128/2+1, or 1+ 256/2+1 ... 1+ 640/2+1 or 1+ 768/2+1*/
42 : Word16 *cand_pairs_buf ; /* actually lowVal + [DC ] + (368/2)pairs + [FS/2] */
43 : Word16 *cand_pairs; /* actually [DC ] + pairs + [FS/2] */
44 : Word16 * fsc_idx; /* list of high locations in sc__idx 1+368/2+1 */
45 :
46 :
47 :
48 :
49 : #ifdef DYNMEM_COUNT
50 : Dyn_Mem_In("peak_locator_fx", sizeof(struct {
51 : Counter j, k, n, idx_high, idx_low;
52 : Word16 inp_len_minus1;
53 : Word16 pairs_start, pairs_end;
54 : Word16 *p_tmp;
55 : Word16 prev_delta, curr_delta;
56 : Word16 delta_predc, delta_fin;
57 : Word16 add_dc_flag, add_fin_flag;
58 : Word16 low_val_cand_pairs, val_range;
59 : Word16 num_pairs, n_tail_values;
60 : Word16 cand_phase_start, cand_idx, prev_low_plus_sens, tmp;
61 : Word16 cand_high, prev_low;
62 : Word16 *sc_idx;
63 : Word16 *cand_pairs_buf;
64 : Word16 *cand_pairs;
65 : Word16 *fsc_idx;
66 : }));
67 : #endif
68 : #ifdef WMOPS
69 : push_wmops("PhECU::peak_locator_fx(1st)");
70 : #endif
71 0 : sc_idx = (Word16 *)scratchAlign(scratchBuffer, 0); /* ByteSize = 2 * (1+ inp_len+1) */
72 0 : cand_pairs_buf = (Word16 *)scratchAlign(sc_idx, sizeof(*sc_idx) * (1+inp_len+1)); /* ByteSize = 2 * (1+ 1+ inp_len+1 ) */
73 0 : fsc_idx = (Word16 *)scratchAlign(cand_pairs_buf , sizeof(*cand_pairs_buf) * (1+ 1+ inp_len+1)); /* ByteSize = 2 * ( 1+ inp_len + 1) */
74 0 : ASSERT((4 * maxLprot_Red) >= 3 * (1 + 1 + inp_len + 1)); /* basic buffer check */
75 : UNUSED(maxLprot_Red);
76 :
77 0 : inp_len_minus1 = sub(inp_len, 1); /* size of delta=derivative array ,and last index in inp */
78 :
79 0 : cand_pairs = &cand_pairs_buf[1]; /* ptr init , make space for storing a lowest amplitude value in location -1 */
80 0 : pairs_start = 1; move16(); /* adjusted to zero or 1 or 2 when/if, DC is injected as sc_idx[0], or initial plateau skipped */
81 :
82 0 : p_tmp = &(sc_idx[pairs_start]); /* ptr init */
83 :
84 :
85 : /* xor high/low pairs of delta_inp and save sign changes */
86 0 : prev_delta = sub(inp[1], inp[0]); /* precompute very first delta */
87 :
88 0 : FOR(n = 1; n < inp_len_minus1; n++)
89 : { /* sign change analysis */
90 0 : curr_delta = sub(inp[n + 1], inp[n]); /* n+1 ,n , are loop ptrs */
91 0 : if (s_xor(prev_delta, curr_delta) < 0) /* a "0" delta treated as a positive sign */
92 : {
93 0 : *p_tmp++ = n; move16(); /* store sign change bin locations , location n in the inp[] signal */
94 : }
95 0 : prev_delta = curr_delta; move16();
96 : }
97 :
98 0 : L_sub(0, 0); /* account for length calculaton */
99 0 : k = (Word16)(p_tmp - &(sc_idx[pairs_start]));
100 :
101 :
102 : /* copy sign change location values to a pairs array */
103 : /* leave one initial sc_idx location open for a potential initial DC value */
104 :
105 0 : ASSERT(pairs_start >= 0 && ((k - 1) + pairs_start) < (inp_len +2));
106 0 : FOR(j = 0; j < k; j++)
107 : {
108 0 : cand_pairs[j + pairs_start] = inp[sc_idx[j + pairs_start]]; move16(); move16(); /* the indirect should be calculated */
109 : }
110 :
111 :
112 : /* filter away a potential single initial/trailing plateau
113 : to enable correct analysis for adding DC or fs/2 bins */
114 :
115 0 : logic16();
116 0 : IF((sub(k, 2) >= 0) &&
117 : (sub(cand_pairs[pairs_start], cand_pairs[pairs_start + 1]) == 0))
118 : {
119 0 : pairs_start = add(pairs_start, 1);
120 0 : k = sub(k, 1);
121 : }
122 :
123 : /* filter away potential single trailing plateu */
124 0 : pairs_end = sub(add(pairs_start,k), 1); /* point to last established sign change element */
125 0 : logic16();
126 0 : if ((sub(k, 2) >= 0) &&
127 0 : (sub(cand_pairs[sub(pairs_end,1)], cand_pairs[pairs_end]) == 0))
128 : {
129 0 : k = sub(k, 1);
130 : }
131 0 : pairs_end = sub(add(pairs_start,k), 1); /* recalc ptr to last element */
132 :
133 :
134 : /* conditionally add high/lows on both sides of input (pre_dc or fin) as candidates */
135 0 : add_dc_flag = 0; move16();
136 0 : add_fin_flag = 0; move16();
137 :
138 :
139 0 : IF(sub(k, 1) == 0) /* one single sign change found special case */
140 : {
141 0 : if (sub(inp[0], cand_pairs[pairs_start]) != 0)
142 : {
143 0 : add_dc_flag = 1; move16(); /* not plateau */
144 : }
145 :
146 0 : if (sub(cand_pairs[pairs_end], inp[inp_len_minus1]) != 0)
147 : {
148 0 : add_fin_flag = 1; move16(); /* not plateau */
149 : }
150 : }
151 :
152 0 : IF(sub(k, 2) >= 0)
153 : {
154 0 : delta_predc = sub(cand_pairs[pairs_start + 1], cand_pairs[pairs_start]);
155 0 : delta_fin = sub(cand_pairs[pairs_end], cand_pairs[pairs_end - 1]);
156 :
157 : /* plateaus are allowed to be detected by xor sign change,
158 : but still not allowed at the start nor at the end */
159 :
160 0 : add_dc_flag = 1; move16();
161 0 : if (sub(inp[0], cand_pairs[pairs_start]) == 0)
162 : {
163 0 : add_dc_flag = 0; move16(); /* plateau down or , plateus up., --> do not add DC */
164 : }
165 :
166 0 : logic16();
167 0 : if ((sub(inp[0], cand_pairs[pairs_start]) < 0) && (delta_predc > 0))
168 : {
169 0 : add_dc_flag = -1; move16(); /*UP - up ... replace */
170 : }
171 0 : logic16();
172 0 : if ((sub(inp[0], cand_pairs[pairs_start]) > 0) && (delta_predc < 0))
173 : {
174 0 : add_dc_flag = -1; move16(); /* DOWN - down ... % replace */
175 : }
176 :
177 0 : add_fin_flag = 1; move16();
178 0 : if (sub(cand_pairs[pairs_end], inp[inp_len_minus1]) == 0)
179 : {
180 0 : add_fin_flag = 0; move16(); /* up - plateau ... */
181 : }
182 0 : logic16();
183 0 : if ((delta_fin > 0) && (sub(cand_pairs[pairs_end], inp[inp_len_minus1]) < 0))
184 : {
185 0 : add_fin_flag = -1; move16(); /* up - UP ... % replace , hard to hit */
186 : }
187 0 : logic16();
188 0 : if ((delta_fin < 0) && (sub(cand_pairs[pairs_end], inp[inp_len_minus1]) > 0))
189 : {
190 0 : add_fin_flag = -1; move16(); /*down - DOWN ... % replace */
191 : }
192 :
193 : }
194 :
195 0 : IF(add_dc_flag > 0)
196 : { /* add DC */
197 0 : pairs_start = sub(pairs_start, 1);
198 0 : cand_pairs[pairs_start] = inp[0]; move16();
199 0 : sc_idx[pairs_start] = 0; move16();
200 0 : ASSERT(pairs_start >= 0 && pairs_start <= 2);
201 0 : k = add(k, 1);
202 : }
203 0 : IF(add_dc_flag < 0)
204 : { /* -1 --> replace with DC*/
205 0 : cand_pairs[pairs_start] = inp[0]; move16();
206 0 : sc_idx[pairs_start] = 0; move16();
207 0 : ASSERT(pairs_start >=0 && pairs_start <= 2);
208 : }
209 :
210 0 : IF(add_fin_flag > 0)
211 : { /* add FS/2 */
212 0 : pairs_end = add(pairs_end, 1);
213 0 : cand_pairs[pairs_end] = inp[inp_len_minus1]; move16();
214 0 : sc_idx[pairs_end] = inp_len_minus1; move16();
215 0 : k = add(k, 1);
216 : }
217 0 : IF(add_fin_flag < 0)
218 : { /* -1, replace tail with FS/2*/
219 0 : cand_pairs[pairs_end] = inp[inp_len_minus1]; move16();
220 0 : sc_idx[pairs_end] = inp_len_minus1; move16();
221 : }
222 : /* preliminary cand_pairs now only have highs , lows , no initial/trailing plateaus */
223 :
224 :
225 : /* we allow the DC/FsBy2 lows to be used as the candidatelLow */
226 0 : low_val_cand_pairs = inp_low; move16();
227 0 : val_range = sub( inp_high, low_val_cand_pairs); /* used to determine if search is useful at all */
228 :
229 0 : logic16();
230 0 : if ((sub(val_range, RES_fx) < 0) ||
231 0 : (sub( inp_high, sens) < 0))
232 : {
233 0 : k = 0; move16();
234 : }
235 :
236 0 : logic16();
237 0 : if ((k == 0) && (sub(val_range, sens) >= 0))
238 : {
239 0 : k = 1; move16();
240 : }
241 :
242 :
243 0 : IF(sub(k, 2) > 0)
244 : {
245 : /* low, high, low, ... or
246 : high, low, high, ...*/
247 :
248 0 : cand_phase_start = pairs_start; move16(); /*assume first candidate is a high */
249 0 : if (sub(cand_pairs[pairs_start], cand_pairs[pairs_start + 1]) < 0)
250 : {
251 0 : cand_phase_start = add(pairs_start, 1); /* first is a low, --> skip to next higher cand */
252 : }
253 :
254 : /* high, low, high, ... */
255 0 : tmp = k; move16();
256 0 : if (sub(cand_phase_start, pairs_start) != 0)
257 : {
258 0 : tmp = sub(tmp, 1);
259 : }
260 0 : num_pairs = shr(tmp, 1);
261 0 : n_tail_values = sub(tmp, shl(num_pairs, 1));
262 :
263 : /* filter preliminary sign changes into sensitivity filtered sign changes */
264 :
265 0 : *n_fsc = 0; move16(); /* counter of filtered fsc_idx */
266 0 : cand_high = low_val_cand_pairs; move16();
267 0 : cand_idx = -1; move16(); /* sentinel location for no high cand found yet. */
268 0 : cand_pairs[-1] = low_val_cand_pairs; move16();
269 :
270 0 : prev_low = low_val_cand_pairs; move16();
271 0 : prev_low_plus_sens = add(prev_low, sens);
272 :
273 : /* filter loop for high - low sign change pairs */
274 : /* idx_high, idx_low are raw pointers into the cand_pairs and sc_idx arrays */
275 :
276 0 : FOR( idx_high = cand_phase_start; idx_high < (cand_phase_start + 2 * num_pairs); idx_high += 2)
277 : {
278 0 : idx_low = idx_high+1; /* loop ptr increase */
279 :
280 : /* new high candidate larger than previous candidate and */
281 : /* sensitivity still larger than the the previous low */
282 0 : tmp = s_max(cand_high, prev_low_plus_sens);
283 0 : if(sub(cand_pairs[idx_high], tmp) > 0)
284 : {
285 0 : cand_idx = idx_high; move16(); /* enable or shift candidate position fwd */
286 : }
287 0 : cand_high = cand_pairs[cand_idx]; move16(); /* NB, cand_pairs[-1] , has the low_val_cand_pairs value stored */
288 :
289 : /* now check the fwd idx_low of the current {high,low} pair */
290 0 : prev_low = s_min(cand_pairs[idx_low], prev_low);
291 :
292 0 : tmp = sub(cand_high, sens);
293 0 : IF(sub(tmp, cand_pairs[idx_low]) > 0)
294 : {
295 : /* this low point is now low enough to fix a previous high candidate */
296 :
297 0 : fsc_idx[*n_fsc] = cand_idx; move16(); /*% add cand high idx -> output idx list*/
298 0 : *n_fsc = add(*n_fsc, 1);
299 :
300 0 : prev_low = cand_pairs[idx_low]; move16(); /* use this value as new low estimate */
301 0 : cand_idx = -1; move16(); /* no candidate until next pair or tail bin, and pt to lowVal */
302 0 : cand_high = low_val_cand_pairs; move16(); /* enable next candidate to be selected immediately */
303 : }
304 0 : prev_low_plus_sens = add(prev_low, sens);
305 : } /* { high, low} FOR loop */
306 :
307 0 : logic16();
308 0 : IF((n_tail_values == 0) && (cand_idx >= 0))
309 : {
310 : /* no tail low or high value to analyze
311 : still may need to lock a non-locked but qualified candidate */
312 0 : fsc_idx[*n_fsc] = cand_idx; move16();
313 0 : *n_fsc = add(*n_fsc, 1);
314 : }
315 :
316 :
317 : /* cand_pairs vector may have a last orphan value */
318 0 : IF(n_tail_values > 0)
319 : {
320 : /* cand_pairs vector may have a last orphan tail value */
321 : /*
322 : logic boils down to if (nTailValues > 0) && (cand_pairs(n_end) > tmp)
323 : there is a last one trailing high to process
324 :
325 : a) the last high, may be a new high Peak if we have not yet
326 : locked the current candidate
327 : b) if we have locked the last candidate, the last high may also be
328 : a highpeak if it is high enough from the(newly set previous) valley floor.
329 :
330 : tmp=a||b
331 : */
332 :
333 0 : tmp = s_max(cand_high, prev_low_plus_sens);
334 0 : tmp = sub(cand_pairs[pairs_end], tmp);
335 0 : IF(tmp > 0)
336 : {
337 0 : fsc_idx[*n_fsc] = pairs_end; move16();
338 0 : *n_fsc = add(*n_fsc, 1);
339 : }
340 : ELSE
341 : {
342 0 : IF(cand_idx >= 0)
343 : { /* we have a previously established high candidate */
344 0 : fsc_idx[*n_fsc] = cand_idx; move16();
345 0 : *n_fsc = add(*n_fsc, 1);
346 : }
347 :
348 : }
349 : }
350 : /* move high locations info from fsc_idx , to output */
351 0 : FOR(j = 0; j < *n_fsc; j++)
352 : {
353 0 : ASSERT(fsc_idx[j] >= 0 && fsc_idx[j] < (inp_len+2));
354 0 : int_plocs[j] = sc_idx[fsc_idx[j]]; move16(); move16(); /* the indirect moves are calculated */
355 : }
356 :
357 : } /* end of pairs + [tail] section filtering */
358 : ELSE
359 : {
360 : /* constant/single rise or constant decay or very low overall values, cases */
361 0 : *n_fsc = 0; move16();
362 :
363 0 : logic16();
364 0 : tmp = sub(inp_high, sens);
365 0 : IF((k != 0) && (sub(tmp, low_val_cand_pairs) > 0))
366 : {
367 : /* low,high */
368 : /* high,low */
369 0 : tmp = plc_phEcu_find_ind_fx(inp, inp_len, inp_high); move16();
370 0 : int_plocs[0] = tmp; move16(); /* simply locate the high peak*/
371 0 : *n_fsc = 1; move16();
372 0 : if (tmp < 0)
373 : { /*safety in case max value index was not found */
374 0 : *n_fsc = 0; move16();
375 : }
376 : }
377 : }
378 : #ifdef DYNMEM_COUNT
379 : Dyn_Mem_Out();
380 : #endif
381 : #ifdef WMOPS
382 : pop_wmops();
383 : #endif
384 0 : }
385 :
|