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 : /* initilize a short vector */
14 0 : void plc_phEcu_initWord16(Word16 * vec, /*i/o : short vector pointer */
15 : const Word16 value, /*i : short initialization value */
16 : const Word16 len) /*i : number of elements */
17 : {
18 : Counter n;
19 :
20 0 : FOR (n = 0; n < len; n++)
21 : {
22 0 : vec[n] = value; move16();
23 : }
24 0 : }
25 :
26 : /* scale inplace with allowed saturation in upscaling , function not available in basop_util */
27 0 : void Scale_sig_sat(Word16 x[], /* i/o: signal to scale Qx */
28 : const Word16 lg, /* i : size of x[] Q0 */
29 : const Word16 exp0 /* i : exponent: x = round(x << exp) Qx ?exp */
30 : )
31 : {
32 : Counter i;
33 : Word16 tmp;
34 0 : IF (exp0 > 0)
35 : {
36 0 : FOR (i = 0; i < lg; i++)
37 : {
38 0 : x[i] = shl_sat(x[i], exp0); move16(); /* no saturation warnings triggered here */
39 : }
40 0 : return;
41 : }
42 0 : IF (exp0 < 0)
43 : {
44 0 : tmp = shl(-32768, s_max(exp0, -15)); /* we use negative to correctly represent 1.0 */
45 0 : FOR (i = 0; i < lg; i++)
46 : {
47 0 : x[i] = msu_r(0, x[i], tmp); move16(); /* msu instead of mac because factor is negative */
48 : }
49 0 : return;
50 : }
51 : }
52 :
53 0 : void plc_phEcu_minval_fx(const Word16 *inp, /* i : vector */
54 : const Word16 len, /* i : length */
55 : Word16 *minvalPtr /* o : min value Ptr */
56 : )
57 : {
58 : Word16 minTmp;
59 : Counter pos;
60 :
61 0 : minTmp = inp[0]; move16();
62 0 : assert(len>1);
63 0 : FOR (pos = 1; pos < len; pos++)
64 : {
65 0 : minTmp = s_min(inp[pos], minTmp);
66 : }
67 :
68 0 : *minvalPtr = minTmp; move16();
69 0 : }
70 :
71 0 : void plc_phEcu_maxval_fx(const Word16 *inp, /* i : vector */
72 : const Word16 len, /* i : length */
73 : Word16 *maxvalPtr /* o : *maxvalPtr */
74 : )
75 : {
76 : Word16 maxTmp;
77 : Counter pos;
78 :
79 0 : maxTmp = inp[0]; move16();
80 :
81 0 : assert(len>1);
82 0 : FOR (pos = 1; pos < len; pos++)
83 : {
84 0 : maxTmp = s_max(inp[pos], maxTmp);
85 : }
86 0 : *maxvalPtr = maxTmp; move16();
87 0 : }
88 :
89 : /* in case a value (e.g max or min) is already known , find the first corresponding array index */
90 0 : Word16 plc_phEcu_find_ind_fx( /* o : output maximum indx 0.. len-1 */
91 : const Word16 *inp, /* i : vector */
92 : const Word16 len, /* i : length */
93 : const Word16 val /* i : value to find */
94 : )
95 : {
96 : Word16 val_ind;
97 : Counter pos;
98 :
99 0 : val_ind = -1; move16();
100 :
101 0 : FOR(pos = 0; pos < len; pos++)
102 : {
103 0 : if (sub(inp[pos], val) == 0)
104 : {
105 0 : val_ind = pos; move16();
106 : }
107 : }
108 0 : return val_ind;
109 : }
110 :
111 : /*-----------------------------------------------------------------------------
112 : * ratio_fx()
113 : *
114 : * Divide the numerator by the denominator.
115 : *----------------------------------------------------------------------------*/
116 0 : Word16 plc_phEcu_ratio_fx( /* o : quotient in Q14 */
117 : const Word32 numer, /* i : numerator */
118 : const Word32 denom, /* i : denominator */
119 : Word16 *expo) /* o : req shift of quotient */
120 : {
121 : Word16 expNumer, expDenom;
122 : Word16 manNumer, manDenom;
123 : Word16 quotient;
124 : #ifdef DYNMEM_COUNT
125 : Dyn_Mem_In("plc_phEcu_ratio_fx", sizeof(struct {
126 : Word16 expNumer, expDenom;
127 : Word16 manNumer, manDenom;
128 : Word16 quotient;
129 : }));
130 : #endif
131 :
132 0 : expDenom = norm_l(denom); /* exponent */
133 0 : manDenom = extract_h(L_shl(denom, expDenom)); /* mantissa */
134 0 : expNumer = norm_l(numer); /* exponent */
135 0 : manNumer = extract_h(L_shl(numer, expNumer)); /* mantissa */
136 0 : manNumer = shr_pos(manNumer, 1); /* Ensure the numerator < the denominator */
137 0 : quotient = div_s(manNumer, manDenom); /* in Q14 */
138 :
139 0 : *expo = sub(expNumer, expDenom);
140 : #ifdef DYNMEM_COUNT
141 : Dyn_Mem_Out();
142 : #endif
143 0 : return quotient; /* Q14 */
144 : }
145 :
146 0 : Word32 winEnCalc( /* o: output summed energy Ltot */
147 : const Word16 *x, /* i: Input signal */
148 : const Word16 headroom_shift, /* i: headroom_shift */
149 : const Word16 *win, /* i: left side Window coefficients */
150 : const Word16 rectLength, /* i: Offset in between the 1st and 2nd symmetric halves of the Hamming window */
151 : const Word16 halfLength, /* i: Half of the total length of a complete Hamming window. */
152 : Word16 *exp /* i/o : i exp of Word16 variable x , o:Lexp of output Word32 sum */
153 : )
154 : {
155 : Counter i;
156 : Word32 L_tot;
157 : const Word16 *pX, *pW;
158 : Word16 tmp, tmp_RL;
159 :
160 : #ifdef DYNMEM_COUNT
161 : Dyn_Mem_In("PhEcu::GF::winEnCalc", sizeof(struct {
162 : Counter i;
163 : Word32 L_tot;
164 : const Word16 *pX, *pW;
165 : Word16 tmp, tmp_RL;
166 : }));
167 : #endif
168 :
169 :
170 : #ifdef WMOPS
171 : push_wmops("PhECU::winEnCalc");
172 : #endif
173 :
174 0 : L_tot = INT32_MAX; move32(); /*acc is on negative side , but as all accumulation is positive, we make use of one extra bit */
175 0 : pX = x;
176 0 : pW = win;
177 :
178 :
179 0 : assert( headroom_shift>=0 );
180 0 : FOR (i = 0; i < halfLength; i++) /* 1st symmetric half of the Hamming window */
181 : {
182 0 : tmp = mult(*pX++, *pW++);
183 0 : tmp = shr_pos(tmp, headroom_shift); /* shr may/create bias on the negative side , costly options are shr_r or use msu_r */
184 0 : L_tot = L_msu0(L_tot, tmp, tmp); /* acc on negative energy side */
185 : }
186 :
187 : /* Periodic filter - one more rect sample before end tapering */
188 0 : tmp_RL = add(rectLength, 1);
189 0 : ASSERT(rectLength != 0);
190 :
191 0 : FOR (i = 0; i < tmp_RL; i++) /* If rectLength is zero, it's a pure Hamming window; otherwise Hamming-Rectangular. */
192 : {
193 0 : tmp = shr_pos( *pX++, headroom_shift);
194 0 : L_tot = L_msu0(L_tot, tmp, tmp); /* acc on negative side */
195 : }
196 :
197 0 : tmp_RL = sub(halfLength, 1);
198 0 : ASSERT(rectLength != 0);
199 :
200 0 : FOR (i = 0; i < tmp_RL; i++) /* 2nd symmetric half of the Hamming window. */
201 : {
202 0 : tmp = mult(*pX++, *(--pW));
203 0 : tmp = shr_pos(tmp, headroom_shift);
204 0 : L_tot = L_msu0(L_tot, tmp, tmp);
205 : }
206 :
207 : /* Lexp = 2*(incoming_exp + dnshift) + 1 , 2x for square + 1(for msu0 DSP dn shift)*/
208 0 : *exp = add(shl_pos(add(*exp, headroom_shift),1),1);
209 :
210 : /* handle wrap on zero point */
211 0 : IF( L_tot >= 0 )
212 : { /* L_tot positive --> less than 32 bits needed, */
213 0 : L_tot = L_add(L_tot,(INT32_MIN+1));
214 0 : if( L_tot == 0 )
215 : {
216 0 : *exp = LTOT_MIN_EXP; /* WC is actually (-(15+4)*2 + 1 +1 -31) */ ; move16();
217 : }
218 0 : L_tot = L_min(L_tot, -1); /* make sure there is energy for future ratio calculations */
219 : }
220 : ELSE
221 : { /* L_tot negative --> more than 31 bits needed for sum , scale 32 bit sum within 31 bits and adjust exp */
222 :
223 0 : L_tot = L_shr_pos(L_add(L_tot,1),1); /* rnd by adding 1, then use 50% contribution from negative side */
224 0 : L_tot = L_add(L_tot, INT32_MIN>>1); /* add 50% contribution from positive side */
225 :
226 0 : *exp = add(*exp, 1); move16();
227 : }
228 :
229 0 : L_tot = L_max( -(INT32_MAX), L_tot); /* guard against max accumulation on the negative side , should only occur for rectangle windows */
230 0 : L_tot = L_negate(L_tot); /* no saturation here */
231 :
232 : /* activate when xfp_exp is not used any longer */
233 : /* pre-maximize the mantissa for the following steps in burst_ana_dx */
234 0 : tmp = norm_l(L_tot);
235 0 : L_tot = L_shl(L_tot,tmp);
236 0 : *exp = sub(*exp, tmp); move16();
237 :
238 : #ifdef WMOPS
239 : pop_wmops();
240 : #endif
241 : #ifdef DYNMEM_COUNT
242 : Dyn_Mem_Out();
243 : #endif
244 :
245 0 : return L_tot;
246 : }
247 :
|