Line data Source code
1 : /******************************************************************************
2 : * ETSI TS 103 634 V1.5.1 *
3 : * Low Complexity Communication Codec Plus (LC3plus) *
4 : * *
5 : * Copyright licence is solely granted through ETSI Intellectual Property *
6 : * Rights Policy, 3rd April 2019. No patent licence is granted by implication, *
7 : * estoppel or otherwise. *
8 : ******************************************************************************/
9 :
10 : #include "defines.h"
11 : #include "constants.h"
12 : #include "functions.h"
13 :
14 : #define BLOCK_SIZE 3
15 : #define THR1 8
16 : #define FAC 9830 /* 0.3 */
17 :
18 : void peakDetector_fx(Word16 in_sig[], Word16 yLen, Word16 *xover);
19 :
20 0 : void processPCclassify_fx(Word16 pitch_present, Word16 frame_dms, Word16 q_old_d_fx[], Word16 q_old_res_fx[],
21 : Word16 yLen, Word16 spec_inv_idx, Word16 stab_fac, Word16 *bfi)
22 : {
23 : Dyn_Mem_Deluxe_In(
24 : Word16 maxPitchBin, xover;
25 : Counter i;
26 : Word16 s, tmp16, full_nrg16, part_nrg16;
27 : Word32 full_nrg, part_nrg;
28 : );
29 :
30 : /* Apply classifier only if lower than 2kHz signal */
31 0 : IF (sub(DEPR_i_mult(spec_inv_idx, 10), shl_pos(frame_dms, 2)) < 0 )
32 : {
33 0 : IF (sub(stab_fac, 16384 /* 0.5 */) < 0)
34 : {
35 0 : *bfi = 1;
36 : }
37 0 : ELSE IF (sub(pitch_present, 1) == 0)
38 : {
39 0 : maxPitchBin = 8; move16();
40 0 : IF (sub(frame_dms, 50) == 0)
41 : {
42 0 : maxPitchBin = 4; move16();
43 : }
44 :
45 : /* avoid phase discontinuity in low frequencies */
46 0 : peakDetector_fx(q_old_d_fx, yLen, &xover);
47 0 : test();
48 0 : IF (sub(spec_inv_idx, xover) < 0 || sub(spec_inv_idx, maxPitchBin) < 0)
49 : {
50 0 : *bfi = 1;
51 : }
52 : }
53 : ELSE
54 : {
55 0 : s = getScaleFactor16(q_old_res_fx, yLen);
56 :
57 0 : part_nrg = 0; move32();
58 0 : FOR (i = 0; i < spec_inv_idx; i++)
59 : {
60 0 : tmp16 = shl_sat(q_old_res_fx[i], sub(s, 4));
61 0 : part_nrg = L_mac0(part_nrg, tmp16, tmp16); /* exp = 2s - 8 */
62 : }
63 :
64 0 : full_nrg = part_nrg; move32();
65 0 : FOR (i = spec_inv_idx; i < yLen; i++)
66 : {
67 0 : tmp16 = shl_sat(q_old_res_fx[i], sub(s, 4));
68 0 : full_nrg = L_mac0(full_nrg, tmp16, tmp16); /* exp = 2s - 8 */
69 : }
70 :
71 0 : s = getScaleFactor32_lc3plus(&full_nrg, 1);
72 0 : full_nrg16 = extract_h(L_shl(full_nrg, s));
73 0 : part_nrg16 = extract_h(L_shl(part_nrg, s));
74 :
75 0 : tmp16 = mult(full_nrg16, 9830 /* 0.3 */);
76 :
77 0 : IF (part_nrg16 < tmp16)
78 : {
79 0 : *bfi = 1;
80 : }
81 : }
82 : }
83 :
84 : Dyn_Mem_Deluxe_Out();
85 0 : }
86 :
87 0 : void peakDetector_fx(Word16 in_sig[], Word16 yLen, Word16 *xover)
88 : {
89 : Dyn_Mem_Deluxe_In(
90 : Counter i, j;
91 : Word16 tmp16, c, s, s2, mean_block_nrg16;
92 : Word32 maxPeak, tmp32;
93 : Word32 mean_block_nrg, block_cent;
94 : Word16 cur_max, prev_max, next_max;
95 : );
96 :
97 0 : *xover = 0;
98 :
99 0 : s = getScaleFactor16(in_sig, yLen);
100 :
101 0 : mean_block_nrg = 0; move32();
102 0 : FOR (i = 0; i < yLen; i++)
103 : {
104 0 : tmp16 = shl_sat(in_sig[i], sub(s, 4));
105 0 : mean_block_nrg = L_mac0(mean_block_nrg, tmp16, tmp16); /* exp = 2s - 8 */
106 : }
107 :
108 0 : s2 = getScaleFactor16(&yLen, 1);
109 0 : c = shl(yLen, s2);
110 0 : mean_block_nrg16 = div_l(mean_block_nrg, c); /* exp = 2s - 8 - s2 - 1 */
111 0 : mean_block_nrg = L_shl(L_mult0(mean_block_nrg16, BLOCK_SIZE * THR1), add(4, s2)); /* exp = 2s - 5 */
112 :
113 0 : maxPeak = 0; move32();
114 0 : c = sub(yLen, 2 * BLOCK_SIZE);
115 :
116 0 : test();
117 0 : IF (abs_s(in_sig[0]) >= abs_s(in_sig[1]))
118 : {
119 0 : block_cent = 0; move32();
120 0 : FOR (j = 0; j <= 1; j++)
121 : {
122 0 : tmp16 = shl_sat(in_sig[j], sub(s, 2));
123 0 : block_cent = L_mac0(block_cent, tmp16, tmp16); /* -> exp = 2s - 4 */
124 : }
125 0 : block_cent = L_shr(block_cent, 1); /* exp = 2s - 5 */
126 :
127 0 : IF (L_sub(block_cent, mean_block_nrg) > 0)
128 : {
129 0 : cur_max = abs_s(in_sig[0]);
130 0 : cur_max = MAX(abs_s(in_sig[1]), cur_max);
131 :
132 0 : next_max = abs_s(in_sig[-1 + BLOCK_SIZE]);
133 0 : next_max = MAX(abs_s(in_sig[-1 + BLOCK_SIZE + 1]), next_max);
134 0 : next_max = MAX(abs_s(in_sig[-1 + BLOCK_SIZE + 2]), next_max);
135 :
136 0 : IF (sub(cur_max, next_max) > 0)
137 : {
138 0 : maxPeak = block_cent; move32();
139 0 : *xover = 1;
140 : }
141 : }
142 : }
143 :
144 0 : FOR (i = 0; i < BLOCK_SIZE; i++)
145 : {
146 0 : test();
147 0 : IF (abs_s(in_sig[i + 1]) >= abs_s(in_sig[i]) && abs_s(in_sig[i + 1]) >= abs_s(in_sig[i + 2]))
148 : {
149 0 : block_cent = 0; move32();
150 0 : FOR (j = 0; j < BLOCK_SIZE; j++)
151 : {
152 0 : tmp16 = shl_sat(in_sig[i + j], sub(s, 2));
153 0 : block_cent = L_mac0(block_cent, tmp16, tmp16); /* -> exp = 2s - 4 */
154 : }
155 0 : block_cent = L_shr(block_cent, 1); /* exp = 2s - 5 */
156 :
157 0 : IF (L_sub(block_cent, mean_block_nrg) > 0)
158 : {
159 0 : cur_max = abs_s(in_sig[i]);
160 0 : cur_max = MAX(abs_s(in_sig[i + 1]), cur_max);
161 0 : cur_max = MAX(abs_s(in_sig[i + 2]), cur_max);
162 :
163 0 : prev_max = 0; move16();
164 0 : FOR (j = i - BLOCK_SIZE; j <= i - 1; j++)
165 : {
166 0 : IF (j > 0)
167 : {
168 0 : prev_max = MAX(abs_s(in_sig[j]), prev_max);
169 : }
170 : }
171 :
172 0 : next_max = abs_s(in_sig[i + BLOCK_SIZE]);
173 0 : next_max = MAX(abs_s(in_sig[i + BLOCK_SIZE + 1]), next_max);
174 0 : next_max = MAX(abs_s(in_sig[i + BLOCK_SIZE + 2]), next_max);
175 :
176 0 : test();
177 0 : IF (sub(cur_max, prev_max) >= 0 && sub(cur_max, next_max) > 0)
178 : {
179 0 : IF (L_sub(block_cent, maxPeak) >= 0)
180 : {
181 0 : maxPeak = block_cent; move32();
182 0 : *xover = sub(add(i, BLOCK_SIZE), 1);
183 : }
184 : ELSE
185 : {
186 0 : tmp32 = L_mult(FAC, extract_h(maxPeak));
187 :
188 0 : tmp16 = extract_l(L_shr(maxPeak, 1));
189 0 : tmp16 = s_and(tmp16, 0x7fff);
190 0 : tmp16 = mult(FAC, tmp16);
191 0 : tmp32 = L_add_sat(tmp32, tmp16);
192 :
193 0 : IF (L_sub(block_cent, tmp32) > 0)
194 : {
195 0 : *xover = sub(add(i, BLOCK_SIZE), 1);
196 : }
197 : }
198 : }
199 : }
200 : }
201 : }
202 :
203 0 : FOR (i = BLOCK_SIZE; i <= c; i++)
204 : {
205 0 : test();
206 0 : IF (abs_s(in_sig[i + 1]) >= abs_s(in_sig[i]) && abs_s(in_sig[i + 1]) >= abs_s(in_sig[i + 2]))
207 : {
208 0 : block_cent = 0; move32();
209 0 : FOR (j = 0; j < BLOCK_SIZE; j++)
210 : {
211 0 : tmp16 = shl_sat(in_sig[i + j], sub(s, 2));
212 0 : block_cent = L_mac0(block_cent, tmp16, tmp16); /* -> exp = 2s - 4 */
213 : }
214 0 : block_cent = L_shr(block_cent, 1); /* exp = 2s - 5 */
215 :
216 0 : IF (L_sub(block_cent, mean_block_nrg) > 0)
217 : {
218 0 : cur_max = abs_s(in_sig[i]);
219 0 : cur_max = MAX(abs_s(in_sig[i + 1]), cur_max);
220 0 : cur_max = MAX(abs_s(in_sig[i + 2]), cur_max);
221 :
222 0 : prev_max = abs_s(in_sig[i - BLOCK_SIZE]);
223 0 : prev_max = MAX(abs_s(in_sig[i - BLOCK_SIZE + 1]), prev_max);
224 0 : prev_max = MAX(abs_s(in_sig[i - BLOCK_SIZE + 2]), prev_max);
225 :
226 0 : next_max = abs_s(in_sig[i + BLOCK_SIZE]);
227 0 : next_max = MAX(abs_s(in_sig[i + BLOCK_SIZE + 1]), next_max);
228 0 : next_max = MAX(abs_s(in_sig[i + BLOCK_SIZE + 2]), next_max);
229 :
230 0 : test();
231 0 : IF (sub(cur_max, prev_max) >= 0 && sub(cur_max, next_max) > 0)
232 : {
233 0 : IF (L_sub(block_cent, maxPeak) >= 0)
234 : {
235 0 : maxPeak = block_cent; move32();
236 0 : *xover = sub(add(i, BLOCK_SIZE), 1);
237 : }
238 : ELSE
239 : {
240 0 : tmp32 = L_mult(FAC, extract_h(maxPeak));
241 :
242 0 : tmp16 = extract_l(L_shr(maxPeak, 1));
243 0 : tmp16 = s_and(tmp16, 0x7fff);
244 0 : tmp16 = mult(FAC, tmp16);
245 0 : tmp32 = L_add_sat(tmp32, tmp16);
246 :
247 0 : IF (L_sub(block_cent, tmp32) > 0)
248 : {
249 0 : *xover = sub(add(i, BLOCK_SIZE), 1);
250 : }
251 : }
252 : }
253 : }
254 : }
255 : }
256 :
257 : Dyn_Mem_Deluxe_Out();
258 0 : }
259 :
260 :
|