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 0 : void processLevinson_fx(Word32 *lpc, Word32 *ac, Word16 N, Word16 *rc, Word32 *pred_err, Word8 *scratchBuffer)
13 : {
14 :
15 : Word32 *lpc_tmp;
16 : Word32 rc32, err, sum;
17 : Word16 shift, s, inv;
18 : Counter n, m;
19 :
20 :
21 : #ifdef DYNMEM_COUNT
22 : Dyn_Mem_In("processLevinson_fx", sizeof(struct {
23 : Word32 *lpc_tmp;
24 : Word32 rc32, err, sum;
25 : Word16 shift, s, inv;
26 : Counter n, m;
27 : Word32 params[2];
28 : }));
29 : #endif
30 :
31 0 : lpc_tmp = (Word32 *)scratchAlign(scratchBuffer, 0); /* Size = 4 * (M_LTPF + 1) = 100 bytes */
32 :
33 : /* Init Prediction Error */
34 0 : err = ac[0]; move32();
35 0 : shift = 0; move16();
36 :
37 : /* LPC Coefficient 0 */
38 0 : lpc[0] = 0x8000000; move32();
39 :
40 : /* Reflection Coefficient 0 */
41 0 : IF (ac[0] != 0)
42 : {
43 0 : inv = div_s(16383, extract_h(ac[0]));
44 0 : rc32 = L_shl_pos(Mpy_32_32_lc3plus(L_abs(ac[1]), Mpy_32_16_lc3plus(L_sub(MAX_32, Mpy_32_16_lc3plus(ac[0], inv)), inv)), 2);
45 : }
46 : ELSE
47 : {
48 0 : rc32 = 0; move32();
49 : }
50 0 : if (ac[1] > 0)
51 : {
52 0 : rc32 = L_negate(rc32);
53 : }
54 0 : if (rc != NULL)
55 : {
56 0 : rc[0] = round_fx(rc32); move16();
57 : }
58 :
59 : /* LPC Coefficient 1 */
60 0 : lpc[1] = L_shr_pos(rc32, 4); move32();
61 :
62 0 : FOR (n = 2; n <= N; n++)
63 : {
64 : /* Update Prediction Error */
65 0 : err = Mpy_32_32_lc3plus(err, L_sub(MAX_32, Mpy_32_32_lc3plus(rc32, rc32)));
66 0 : s = norm_l(err);
67 0 : err = L_shl_pos(err, s);
68 0 : shift = add(shift, s);
69 :
70 : /* Reflection Coefficient n-1 */
71 0 : sum = Mpy_32_32_lc3plus(ac[1], lpc[n - 1]);
72 0 : FOR (m = 2; m < n; m++)
73 : {
74 0 : sum = L_add(sum, Mpy_32_32_lc3plus(ac[m], lpc[n - m]));
75 : }
76 :
77 0 : sum = L_add(L_shl_pos(sum, 4), ac[n]);
78 0 : IF (err != 0)
79 : {
80 0 : inv = div_s(16383, extract_h(err));
81 0 : rc32 = L_shl_pos(Mpy_32_32_lc3plus(L_abs(sum), Mpy_32_16_lc3plus(L_sub(MAX_32, Mpy_32_16_lc3plus(err, inv)), inv)), 2);
82 : }
83 : ELSE
84 : {
85 0 : rc32 = 0;
86 : }
87 0 : if (sum > 0)
88 : {
89 0 : rc32 = L_negate(rc32);
90 : }
91 0 : rc32 = L_shl(rc32, shift);
92 0 : if (rc != NULL)
93 : {
94 0 : rc[n - 1] = round_fx(rc32); move16();
95 : }
96 :
97 : /* Recompute LPC Coefficients up to n-1 */
98 0 : FOR (m = 1; m < n; m++)
99 : {
100 0 : lpc_tmp[m] = L_add(lpc[m], Mpy_32_32_lc3plus(rc32, lpc[n - m])); move32();
101 : }
102 :
103 0 : basop_memmove(&lpc[1], &lpc_tmp[1], (n - 1) * sizeof(Word32));
104 :
105 : /* LPC Coefficient n */
106 0 : lpc[n] = L_shr_pos(rc32, 4); move32();
107 : }
108 :
109 : /* Final Prediction Error */
110 0 : IF (pred_err != NULL)
111 : {
112 0 : err = Mpy_32_32_lc3plus(err, L_sub(MAX_32, Mpy_32_32_lc3plus(rc32, rc32)));
113 0 : *pred_err = L_shr(err, shift);
114 : }
115 :
116 : #ifdef DYNMEM_COUNT
117 : Dyn_Mem_Out();
118 : #endif
119 0 : }
120 :
121 :
122 0 : void lpc2rc(Word32 *lpc, Word16 *rc, Word16 N)
123 : {
124 : Word32 lpc_tmp[MAXLAG + 1];
125 : Word32 rc32, tmp0, tmp1;
126 : Word16 inv;
127 : Counter n, m;
128 :
129 : #ifdef DYNMEM_COUNT
130 : Dyn_Mem_In("lpc2rc", sizeof(struct {
131 : Word32 lpc_tmp[MAXLAG + 1];
132 : Word32 rc32, tmp0, tmp1;
133 : Word16 inv;
134 : Counter n, m;
135 : }));
136 : #endif
137 :
138 0 : FOR (n = N; n >= 2; n--)
139 : {
140 0 : rc32 = L_shl_pos(lpc[n], 4);
141 0 : rc[n - 1] = round_fx(rc32); move16();
142 :
143 0 : tmp0 = L_sub(MAX_32, L_abs(Mpy_32_32_lc3plus(rc32, rc32)));
144 0 : FOR (m = 1; m < n; m++)
145 : {
146 0 : tmp1 = L_sub(lpc[m], Mpy_32_32_lc3plus(lpc[n - m], rc32));
147 0 : inv = div_s(16383, extract_h(tmp0));
148 0 : lpc_tmp[m] = L_shl_pos(Mpy_32_32_lc3plus(tmp1, Mpy_32_16_lc3plus(L_sub(MAX_32, Mpy_32_16_lc3plus(tmp0, inv)), inv)), 2); move32();
149 : }
150 :
151 0 : basop_memmove(&lpc[1], &lpc_tmp[1], (n - 1) * sizeof(Word32));
152 : }
153 :
154 0 : rc[0] = round_fx(L_shl_pos(lpc[1], 4)); move32();
155 :
156 : #ifdef DYNMEM_COUNT
157 : Dyn_Mem_Out();
158 : #endif
159 0 : }
160 :
|