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 "functions.h"
11 :
12 : #define SIGNBIT_FX 0x80000000u
13 : #define SIGNBIT_SHRT_FX 0x8000
14 :
15 0 : static void initOffsets_fx(Word16 dim_in, UWord32 *h_mem,
16 : Word16 k_val_in) /* may be removed with tables for N=16,10,6 */
17 : {
18 : UWord32 k_val_prev, k_val_curr;
19 : UWord32 k_val, UL_k_val_in;
20 : #ifdef DYNMEM_COUNT
21 : Dyn_Mem_In("initOffsets_fx", sizeof(struct {
22 : UWord32 k_val_prev, k_val_curr;
23 : UWord32 k_val, UL_k_val_in;
24 : }));
25 : #endif
26 :
27 0 : h_mem[0] = UL_deposit_l(0);
28 0 : h_mem[1] = UL_deposit_l(1);
29 :
30 0 : UL_k_val_in = UL_deposit_l(k_val_in);
31 0 : IF (sub(dim_in, 2) == 0)
32 : {
33 0 : FOR (k_val = 2; k_val <= UL_k_val_in; k_val++)
34 : {
35 0 : h_mem[k_val] = UL_subNsD(UL_lshl(k_val, 1), 1U); move32();
36 : }
37 0 : h_mem[k_val] = UL_k_val_in; move32();
38 : }
39 : ELSE
40 : {
41 0 : k_val_prev = UL_deposit_l(1U);
42 0 : FOR (k_val_curr = 2; k_val_curr <= UL_k_val_in; k_val_curr++)
43 : {
44 0 : h_mem[k_val_curr] = UL_addNsD(1U, UL_Mpy_32_32(k_val_curr, UL_lshl(k_val_prev, 1))); move32();
45 0 : k_val_prev = UL_addNsD(k_val_curr, 0U);
46 : }
47 0 : h_mem[k_val_curr] = UL_Mpy_32_32(k_val_curr, k_val_prev); move32();
48 : }
49 :
50 : #ifdef DYNMEM_COUNT
51 : Dyn_Mem_Out();
52 : #endif
53 0 : }
54 :
55 0 : static void a_fwd_fx(UWord32 *a_in, /* i/o: offsets */
56 : Word16 n_items /* i : items, k's */
57 : )
58 : {
59 : UWord32 a_1, a_in0;
60 : Counter i;
61 : UWord32 *a_in_prev_ptr;
62 :
63 : #ifdef DYNMEM_COUNT
64 : Dyn_Mem_In("a_fwd_fx", sizeof(struct {
65 : UWord32 a_1, a_in0;
66 : Counter i;
67 : UWord32 *a_in_prev_ptr;
68 : }));
69 : #endif
70 :
71 0 : a_in0 = UL_deposit_l(1);
72 :
73 0 : a_in_prev_ptr = &(a_in[-1]);
74 0 : FOR (i = 1; i <= n_items; i++)
75 : {
76 0 : a_1 = UL_addNsD(a_in0, UL_addNsD(a_in_prev_ptr[i], a_in[i]));
77 0 : a_in_prev_ptr[i] = a_in0; move32();
78 0 : a_in0 = UL_addNsD(a_1, 0U);
79 : }
80 0 : a_in_prev_ptr[i] = a_in0; move32();
81 :
82 : #ifdef DYNMEM_COUNT
83 : Dyn_Mem_Out();
84 : #endif
85 0 : }
86 :
87 0 : static void a_bwd_fx(UWord32 *a_in, /* i/o: offsets */
88 : Word16 n_items /* i: n_items */
89 : )
90 : {
91 : UWord32 a_1, a_in0;
92 : Counter i;
93 : UWord32 *a_in_prev_ptr;
94 :
95 : #ifdef DYNMEM_COUNT
96 : Dyn_Mem_In("a_bwd_fx", sizeof(struct {
97 : UWord32 a_1, a_in0;
98 : Counter i;
99 : UWord32 *a_in_prev_ptr;
100 : }));
101 : #endif
102 :
103 0 : a_in0 = UL_deposit_l(0);
104 0 : a_in_prev_ptr = &(a_in[-1]);
105 :
106 0 : FOR (i = 1; i <= n_items; i++)
107 : {
108 0 : a_1 = UL_subNsD(UL_subNsD(a_in[i], a_in0), a_in_prev_ptr[i]);
109 0 : a_in_prev_ptr[i] = a_in0; move32();
110 0 : a_in0 = UL_addNsD(a_1, 0U);
111 : }
112 0 : a_in_prev_ptr[i] = a_in0; move32();
113 :
114 : #ifdef DYNMEM_COUNT
115 : Dyn_Mem_Out();
116 : #endif
117 0 : }
118 :
119 0 : static void a_u_fwd_fx(UWord32 *a_u_in, Word16 k_val_in, Word16 mem_size_m1)
120 : {
121 : UWord32 u_kp1_prev, u_kp1;
122 : UWord32 u_k_prev;
123 :
124 : #ifdef DYNMEM_COUNT
125 : Dyn_Mem_In("a_u_fwd_fx", sizeof(struct {
126 : UWord32 u_kp1_prev, u_kp1;
127 : UWord32 u_k_prev;
128 : }));
129 : #endif
130 :
131 0 : u_kp1_prev = a_u_in[mem_size_m1]; move32();
132 0 : u_k_prev = UL_lshr(a_u_in[k_val_in], 1);
133 :
134 0 : a_fwd_fx(&a_u_in[1], k_val_in);
135 :
136 0 : u_kp1 = UL_lshr(a_u_in[k_val_in], 1);
137 0 : a_u_in[mem_size_m1] = UL_addNsD(1U, UL_addNsD(u_kp1_prev, UL_addNsD(u_k_prev, u_kp1)));
138 :
139 : #ifdef DYNMEM_COUNT
140 : Dyn_Mem_Out();
141 : #endif
142 0 : }
143 :
144 0 : static Word16 get_lead_sign_fx(UWord32 *ind)
145 : {
146 : Word16 leading_sign;
147 :
148 : #ifdef DYNMEM_COUNT
149 : Dyn_Mem_In("get_lead_sign_fx", sizeof(struct { Word16 leading_sign; }));
150 : #endif
151 :
152 0 : leading_sign = 1; move16();
153 0 : if (UL_and(*ind, 1) != 0)
154 : {
155 0 : leading_sign = -1; move16();
156 : }
157 0 : (*ind) = UL_lshr(*ind, 1);
158 :
159 : #ifdef DYNMEM_COUNT
160 : Dyn_Mem_Out();
161 : #endif
162 :
163 0 : return leading_sign;
164 : }
165 :
166 : /*-------------------------------------------------------------------*
167 : * mind2vec_one_fx()
168 : *-------------------------------------------------------------------*/
169 0 : static void mind2vec_one_fx(Word16 k_val_in, /* i: nb unit pulses , [ 0...K_MAX ] */
170 : Word16 leading_sign, /* i: leading sign -1, 0, 1*/
171 : UWord32 ind, /* i: index */ /* parameter could be omitted */
172 : Word16 *vec_out /* o: pulse train */
173 : )
174 : {
175 0 : *vec_out = (Word16)ind; /* dummy assignment to handle the common ind parameter warning */
176 :
177 0 : if (leading_sign < 0)
178 : {
179 0 : k_val_in = negate(k_val_in);
180 : }
181 0 : *vec_out = k_val_in; move16();
182 0 : }
183 :
184 0 : static Word16 setval_update_sign_fx(Word16 k_delta, Word16 k_max_local, Word16 *leading_sign, UWord32 *ind_in,
185 : Word16 *vec_out)
186 : {
187 0 : IF (k_delta != 0)
188 : {
189 0 : mind2vec_one_fx(k_delta, *leading_sign, *ind_in, vec_out);
190 0 : *leading_sign = get_lead_sign_fx(ind_in);
191 0 : k_max_local = sub(k_max_local, k_delta);
192 : }
193 0 : return k_max_local;
194 : }
195 :
196 : /*-------------------------------------------------------------------*
197 : * mind2vec_fx()
198 : *-------------------------------------------------------------------*/
199 0 : static void mind2vec_fx(Word16 dim_in, /* i: dimension */
200 : Word16 k_max_local, /* i: nb unit pulses */
201 : Word16 leading_sign, /* i: leading sign */
202 : UWord32 ind, /* i: index */
203 : Word16 * vec_out, /* o: pulse train */
204 : UWord32 *h_in /* i: offset vector A=1+2U */
205 : )
206 : {
207 : Counter pos;
208 : Word16 k_acc, k_delta;
209 : UWord32 UL_tmp_offset, UL_diff;
210 : UWord16 sgn;
211 :
212 : #ifdef DYNMEM_COUNT
213 : Dyn_Mem_In("mind2vec_fx", sizeof(struct {
214 : Counter pos;
215 : Word16 k_acc, k_delta;
216 : UWord32 UL_tmp_offset, UL_diff;
217 : UWord16 sgn;
218 : }));
219 : #endif
220 :
221 0 : k_acc = k_max_local; move16();
222 0 : FOR (pos = 0; pos < dim_in; pos++)
223 : {
224 :
225 0 : IF (ind != 0)
226 : {
227 :
228 0 : k_acc = k_max_local; move16();
229 :
230 0 : UL_tmp_offset = UL_addNsD(h_in[k_acc], 0U);
231 :
232 0 : UL_diff = UL_subNs(ind, UL_tmp_offset, &sgn);
233 :
234 0 : WHILE (sgn)
235 : {
236 0 : UL_diff = UL_subNs(ind, h_in[--k_acc], &sgn);
237 : }
238 :
239 0 : ind = UL_addNsD(UL_diff, 0U);
240 :
241 0 : k_delta = sub(k_max_local, k_acc);
242 : }
243 : ELSE
244 : {
245 0 : mind2vec_one_fx(k_max_local, leading_sign, ind, &vec_out[pos]);
246 0 : BREAK;
247 : }
248 :
249 0 : k_max_local = setval_update_sign_fx(k_delta, k_max_local, &leading_sign, &ind, &vec_out[pos]);
250 :
251 0 : a_bwd_fx(h_in, add(k_max_local, 1));
252 : }
253 :
254 : #ifdef DYNMEM_COUNT
255 : Dyn_Mem_Out();
256 : #endif
257 0 : }
258 :
259 0 : PvqEntry_fx get_size_mpvq_calc_offset_fx( /* o : size, dim, k_val */
260 : Word16 dim_in, /* i : dimension */
261 : Word16 k_val_in, /* i : nb unit pulses */
262 : UWord32 *h_mem /* o : offsets */
263 : )
264 : {
265 : Counter i;
266 : PvqEntry_fx entry;
267 : Word16 kp1;
268 :
269 : #ifdef DYNMEM_COUNT
270 : Dyn_Mem_In("get_size_mpvq_calc_offset_fx", sizeof(struct {
271 : Counter i;
272 : PvqEntry_fx entry;
273 : Word16 kp1;
274 : }));
275 : #endif
276 :
277 0 : entry.dim = dim_in; move16();
278 0 : entry.k_val = k_val_in; move16();
279 :
280 0 : entry.index = L_deposit_l(0);
281 0 : entry.lead_sign_ind = 0; move16();
282 :
283 0 : ASSERT(dim_in <= M);
284 0 : ASSERT(tabledKMAX[dim_in] != 0);
285 :
286 : /* tabled values for worst case K */ /* made into table lookup for N=16, 10, 6 */
287 0 : kp1 = add(k_val_in, 1);
288 0 : FOR (i = 0; i <= kp1; i++) /* A+U copying */
289 : {
290 0 : h_mem[i] =
291 0 : UL_addNsD(MPVQ_offs_ptr[dim_in][i], 0U); /* a vector copying is needed as MPVQ recursion is in place */
292 : }
293 : /* special handling of last U offset in k+1 column */
294 0 : if (sub(k_val_in, tabledKMAX[dim_in]) != 0)
295 : {
296 0 : h_mem[kp1] = UL_lshr(h_mem[kp1], 1); /* (A+1)/2 , convert from A(K+1) to U(K+1) domain */
297 : }
298 0 : entry.size =
299 0 : UL_addNsD(1U, UL_addNsD(h_mem[kp1], UL_lshr(h_mem[k_val_in], 1))); /* MPVQ size calc. 1 + H(K+1) + (A(K)>>1) */
300 :
301 : #ifdef DYNMEM_COUNT
302 : Dyn_Mem_Out();
303 : #endif
304 :
305 0 : return entry;
306 : }
307 :
308 : /*-------------------------------------------------------------------*
309 : * mpvq_deindex_fx()
310 : *-------------------------------------------------------------------*/
311 0 : void mpvq_deindex_fx( /* o : void */
312 : const PvqEntry_fx *entry, /* i : sign_ind, index, dim, k_val */
313 : UWord32 * h_mem, /* i : A/U offsets */
314 : Word16 * vec_out /* o : pulse train */
315 : )
316 : {
317 : Word16 leading_sign;
318 : #ifdef DYNMEM_COUNT
319 : Dyn_Mem_In("mpvq_deindex_fx", sizeof(struct { Word16 leading_sign; }));
320 : #endif
321 : #ifdef WMOPS
322 : push_wmops("mpvq_deindex_fx");
323 : #endif
324 :
325 0 : basop_memset(vec_out, 0, (entry->dim) * sizeof(Word16));
326 :
327 0 : leading_sign = 1; move16();
328 0 : if (entry->lead_sign_ind != 0)
329 : {
330 0 : leading_sign = -1; move16();
331 : }
332 :
333 0 : IF (entry->k_val != 0)
334 : {
335 0 : mind2vec_fx(entry->dim, entry->k_val, leading_sign, entry->index, vec_out, h_mem);
336 : }
337 : #ifdef DYNMEM_COUNT
338 : Dyn_Mem_Out();
339 : #endif
340 : #ifdef WMOPS
341 : pop_wmops();
342 : #endif
343 0 : }
344 :
345 : /*-------------------------------------------------------------------*
346 : * vec2mind_two_fx()
347 : *-------------------------------------------------------------------*/
348 0 : static void vec2mind_two_fx(const Word16 *vec_in, /* i : PVQ pulse train */
349 : Word16 * k_val_out_ptr, /* o : number of unit pulses */
350 : UWord32 * next_sign_ind, /* i/o: next sign ind */
351 : UWord32 * ind /* o: MPVQ index */
352 : )
353 : {
354 : UWord32 lead_sign_ind_add;
355 : Word16 abs0, abs1, abs01, sptr;
356 :
357 : #ifdef DYNMEM_COUNT
358 : Dyn_Mem_In("vec2mind_two_fx", sizeof(struct {
359 : UWord32 lead_sign_ind_add;
360 : Word16 abs0, abs1, abs01, sptr;
361 : }));
362 : #endif
363 :
364 0 : abs0 = abs_s(vec_in[0]);
365 0 : abs1 = abs_s(vec_in[1]);
366 0 : abs01 = add(abs0, abs1);
367 0 : *k_val_out_ptr = abs01; move16();
368 0 : *ind = UL_deposit_l(0);
369 :
370 0 : *next_sign_ind = UL_deposit_h(SIGNBIT_SHRT_FX);
371 :
372 0 : IF (abs01 != 0)
373 : {
374 0 : sptr = 0; move16();
375 0 : *next_sign_ind = UL_deposit_l(sptr);
376 :
377 0 : test();
378 0 : IF (abs0 != 0 && abs1 != 0)
379 : {
380 0 : lead_sign_ind_add = UL_deposit_l(1);
381 0 : if (vec_in[1] < 0)
382 : {
383 0 : lead_sign_ind_add = UL_deposit_l(2);
384 : }
385 0 : *ind = UL_addNsD(UL_deposit_l((UWord16)lshl(sub(abs1, 1), 1)), lead_sign_ind_add);
386 : }
387 : ELSE
388 : {
389 0 : IF (abs0 == 0)
390 : {
391 0 : *ind = UL_deposit_l((UWord16)sub(lshl(abs1, 1), 1));
392 0 : sptr = 1; move16();
393 : }
394 : }
395 :
396 0 : if (vec_in[sptr] < 0)
397 : {
398 0 : *next_sign_ind = UL_deposit_l(1);
399 : }
400 : }
401 :
402 : #ifdef DYNMEM_COUNT
403 : Dyn_Mem_Out();
404 : #endif
405 0 : }
406 :
407 0 : static void enc_push_sign(Word16 val, UWord32 *next_sign_ind, UWord32 *index)
408 : {
409 0 : test();
410 0 : IF ((UL_and(*next_sign_ind, SIGNBIT_FX) == 0) && (val != 0))
411 : {
412 0 : *index = UL_addNsD(UL_lshl(*index, 1), *next_sign_ind);
413 : }
414 0 : if (val < 0)
415 : {
416 0 : *next_sign_ind = UL_deposit_l(1);
417 : }
418 0 : if (val > 0)
419 : {
420 0 : *next_sign_ind = UL_deposit_l(0);
421 : }
422 0 : }
423 :
424 0 : static void vec2mind_fx(Word16 dim_in, /* i : dim */
425 : Word16 k_val_in, /* i : number of unit pulses */
426 : const Word16 *vec_in, /* i : PVQ pulse train */
427 : UWord32 * next_sign_ind, /* o : pushed leading sign */
428 : UWord32 * index, /* o : MPVQ index */
429 : UWord32 * N_MPVQ_ptr, /* o : size(N_MPVQ(dim,K_val_in))*/
430 : UWord32 * h_mem) /* o : offsets */
431 : {
432 : Counter pos;
433 : Word16 mem_size_m1, k_val_acc, tmp_val;
434 : UWord32 tmp_h;
435 :
436 : #ifdef DYNMEM_COUNT
437 : Dyn_Mem_In("vec2mind_fx", sizeof(struct {
438 : Counter pos;
439 : Word16 mem_size_m1, k_val_acc, tmp_val;
440 : UWord32 tmp_h;
441 : }));
442 : #endif
443 :
444 0 : mem_size_m1 = add(k_val_in, 1);
445 0 : *next_sign_ind = UL_deposit_h(SIGNBIT_SHRT_FX);
446 :
447 0 : pos = sub(dim_in, 2);
448 0 : vec2mind_two_fx(&vec_in[pos], &k_val_acc, next_sign_ind, index);
449 0 : initOffsets_fx(3, h_mem, k_val_in);
450 :
451 0 : tmp_h = h_mem[k_val_acc]; move32();
452 0 : FOR (pos--; pos >= 0; pos--)
453 : {
454 0 : tmp_val = vec_in[pos]; move16();
455 0 : enc_push_sign(tmp_val, next_sign_ind, index);
456 :
457 0 : *index = UL_addNsD(*index, tmp_h);
458 :
459 0 : k_val_acc = add(k_val_acc, abs_s(tmp_val));
460 :
461 0 : IF (pos != 0)
462 : {
463 0 : a_u_fwd_fx(h_mem, k_val_in, mem_size_m1);
464 : }
465 0 : tmp_h = UL_addNsD(h_mem[k_val_acc], 0U);
466 : }
467 0 : *N_MPVQ_ptr = UL_addNsD(1U, UL_addNsD(UL_lshr(tmp_h, 1), h_mem[mem_size_m1])); move32();
468 :
469 : #ifdef DYNMEM_COUNT
470 : Dyn_Mem_Out();
471 : #endif
472 0 : }
473 :
474 0 : PvqEntry_fx mpvq_index_fx( /* o : leading_sign_index, index, size, k_val */
475 : const Word16 *vec_in, /* i : signed pulse train */
476 : Word16 dim_in, /* i : dimension */
477 : Word16 k_val_local /* i : nb unit pulses */
478 : )
479 : {
480 : PvqEntry_fx result;
481 : UWord32 h_mem[1 + KMAX_FX + 1];
482 : UWord32 lead_sign_ind;
483 :
484 : #ifdef DYNMEM_COUNT
485 : Dyn_Mem_In("mpvq_index_fx", sizeof(struct {
486 : PvqEntry_fx result;
487 : UWord32 h_mem[1 + KMAX_FX + 1];
488 : UWord32 lead_sign_ind;
489 : }));
490 : #endif
491 : #ifdef WMOPS
492 : push_wmops("mpvq_index_fx");
493 : #endif
494 :
495 0 : ASSERT(k_val_local <= KMAX_FX);
496 :
497 0 : result.k_val = k_val_local; move16();
498 0 : result.dim = dim_in; move16();
499 :
500 0 : vec2mind_fx(dim_in, k_val_local, vec_in, &lead_sign_ind, &result.index, &result.size, h_mem);
501 :
502 0 : result.lead_sign_ind = u_extract_l(lead_sign_ind);
503 :
504 : #ifdef DYNMEM_COUNT
505 : Dyn_Mem_Out();
506 : #endif
507 : #ifdef WMOPS
508 : pop_wmops();
509 : #endif
510 :
511 0 : return result;
512 : }
513 :
|