Line data Source code
1 : /*====================================================================================
2 : EVS Codec 3GPP TS26.452 Aug 12, 2021. Version 16.3.0
3 : ====================================================================================*/
4 :
5 : #include <stdint.h>
6 : #include "options.h" /* Compilation switches */
7 : #include "cnst.h" /* Common constants */
8 : #include "rom_com.h" /* Static table prototypes */
9 : #include "prot_fx.h" /* Function prototypes */
10 :
11 :
12 : /*-------------------------------------------------------------------*
13 : * Local function prototypes
14 : *-------------------------------------------------------------------*/
15 :
16 : static Word16 re8_identify_absolute_leader_fx( const Word16 y[] );
17 : static void re8_coord_fx( const Word16 *y, Word16 *k );
18 :
19 :
20 : /*----------------------------------------------------------------*
21 : * re8_vor_fx()
22 : *
23 : * MULTI-RATE RE8 INDEXING BY VORONOI EXTENSION
24 : *----------------------------------------------------------------*/
25 1907335 : void re8_vor_fx(
26 : const Word16 y[], /* i : point in RE8 (8-dimensional integer vector) Q0*/
27 : Word16 *n, /* o : codebook number n=0,2,3,4,... (scalar integer) Q0*/
28 : Word16 k[], /* o : Voronoi index (integer vector of dimension 8) used only if n>4 Q0*/
29 : Word16 c[], /* o : codevector in Q0, Q2, Q3, or Q4 if n<=4, y=c Q0*/
30 : Word16 *ka /* o : identifier of absolute leader (to index c) Q0*/
31 : )
32 : {
33 : Word16 i, r, iter, ka_tmp, n_tmp, mask;
34 : Word16 k_tmp[8], v[8], c_tmp[8], k_mod[8];
35 : Word32 Ltmp, Lsphere;
36 :
37 : /*----------------------------------------------------------------*
38 : * verify if y is in Q0, Q2, Q3 or Q4
39 : * (a fast search is used here:
40 : * the codebooks Q0, Q2, Q3 or Q4 are specified in terms of RE8 absolute leaders
41 : * (see FORinstance Xie and Adoul's paper in ICASSP 96)
42 : * - a unique code identifying the absolute leader related to y is computed
43 : * in re8_identify_absolute_leader()
44 : * this code is searched FORin a pre-defined list which specifies Q0, Q2, Q3 or Q4)
45 : * the absolute leader is identified by ka
46 : * - a translation table maps ka to the codebook number n)
47 : *----------------------------------------------------------------*/
48 1907335 : *ka = re8_identify_absolute_leader_fx( y ); /* Q0 */
49 1907335 : move16();
50 :
51 : /*----------------------------------------------------------------*
52 : * compute codebook number n of Qn (by table look-up)
53 : * at this stage, n=0,2,3,4 or out=100
54 : *----------------------------------------------------------------*/
55 1907335 : *n = Da_nq[*ka]; /* Q0 */
56 1907335 : move16();
57 :
58 : /*----------------------------------------------------------------*
59 : * decompose y into :
60 : * (if n<=4:)
61 : * y = c where c is in Q0, Q2, Q3 or Q4
62 : * or
63 : * (if n>4:)
64 : * y = m c + v where c is in Q3 or Q4, v is a Voronoi codevector
65 : * m=2^r (r integer >=2)
66 : *
67 : * in the latter case (if n>4), as a side-product, compute the (Voronoi) index k[] of v
68 : * and replace n by n = n' + 2r where n' = 3 or 4 (c is in Qn') and r is defined above
69 : *----------------------------------------------------------------*/
70 :
71 1907335 : IF( LE_16( *n, 4 ) )
72 : {
73 1695007 : Copy( y, c, 8 ); /* Q0 */
74 : }
75 : ELSE
76 : {
77 : /*------------------------------------------------------------*
78 : * initialize r and m=2^r based on || y ||^2/8
79 : *------------------------------------------------------------*/
80 212328 : Ltmp = L_mult( y[0], y[0] ); /* Q1 */
81 1698624 : FOR( i = 1; i < 8; i++ )
82 : {
83 1486296 : Ltmp = L_mac( Ltmp, y[i], y[i] ); /* Q1 */
84 : }
85 :
86 212328 : Lsphere = L_shr( Ltmp, 5 + 1 ); /* *0.125*0.25 / 2 to remove L_mac effect */
87 :
88 212328 : r = 1;
89 212328 : move16();
90 236365 : FOR( ; Lsphere > 11; Lsphere >>= 2 )
91 : {
92 24037 : r = add( r, 1 );
93 : }
94 : /*------------------------------------------------------------*
95 : * compute the coordinates of y in the RE8 basis
96 : *------------------------------------------------------------*/
97 212328 : re8_coord_fx( y, k_mod );
98 :
99 : /*------------------------------------------------------------*
100 : * compute m and the mask needed for modulo m (for Voronoi coding)
101 : *------------------------------------------------------------*/
102 212328 : mask = sub( shl( 1, r ), 1 ); /* 0x0..011...1 Q0*/
103 :
104 : /*------------------------------------------------------------*
105 : * find the minimal value of r (or equivalently of m) in 2 iterations
106 : *------------------------------------------------------------*/
107 :
108 636984 : FOR( iter = 0; iter < 2; iter++ )
109 : {
110 : /*--------------------------------------------------------*
111 : * compute v such that y is in m RE_8 +v (by Voronoi coding)
112 : *--------------------------------------------------------*/
113 3821904 : FOR( i = 0; i < 8; i++ )
114 : {
115 3397248 : k_tmp[i] = s_and( k_mod[i], mask ); /* Q0 */
116 3397248 : move16();
117 : }
118 :
119 424656 : re8_k2y_fx( k_tmp, r, v );
120 :
121 : /*--------------------------------------------------------*
122 : * compute c = (y-v)/m
123 : * (y is in RE8, c is also in RE8 by definition of v)
124 : *--------------------------------------------------------*/
125 :
126 3821904 : FOR( i = 0; i < 8; i++ )
127 : {
128 3397248 : c_tmp[i] = shr( sub( y[i], v[i] ), r ); /* Q0 */
129 3397248 : move16();
130 : }
131 :
132 : /*--------------------------------------------------------*
133 : * verify if c_tmp is in Q2, Q3 or Q4
134 : *--------------------------------------------------------*/
135 424656 : ka_tmp = re8_identify_absolute_leader_fx( c_tmp ); /* Q0 */
136 :
137 : /*--------------------------------------------------------*
138 : * at this stage, n_tmp=2,3,4 or out = 100 -- n=0 is not possible
139 : *--------------------------------------------------------*/
140 424656 : n_tmp = Da_nq[ka_tmp]; /* Q0 */
141 424656 : move16();
142 :
143 424656 : IF( GT_16( n_tmp, 4 ) )
144 : {
145 : /*--------------------------------------------------------*
146 : * if c is not in Q2, Q3, or Q4 (i.e. n_tmp>4), use m = 2^(r+1) instead of 2^r
147 : *--------------------------------------------------------*/
148 212327 : r = add( r, 1 ); /* Q0 */
149 212327 : mask = add( shl( mask, 1 ), 1 ); /* mask = m-1 <- this is less complex */
150 : }
151 : ELSE
152 : {
153 : /*--------------------------------------------------------*
154 : * c is in Q2, Q3, or Q4 -> the decomposition of y as y = m c + v is valid
155 : *
156 : * since Q2 is a subset of Q3, indicate n=3 instead of n=2 (this is because
157 : * for n>4, n=n'+2r with n'=3 or 4, so n'=2 is not valid)
158 : *--------------------------------------------------------*/
159 212329 : n_tmp = s_max( n_tmp, 3 ); /* Q0 */
160 :
161 : /*--------------------------------------------------------*
162 : * save current values into ka, n, k and c
163 : *--------------------------------------------------------*/
164 212329 : *ka = ka_tmp; /* Q0 */
165 212329 : move16();
166 212329 : *n = add( n_tmp, shl( r, 1 ) ); /* Q0 */
167 212329 : move16();
168 212329 : Copy( k_tmp, k, 8 ); /* Q0 */
169 212329 : Copy( c_tmp, c, 8 ); /* Q0 */
170 :
171 : /*--------------------------------------------------------*
172 : * try m = 2^(r-1) instead of 2^r to be sure that m is minimal
173 : *--------------------------------------------------------*/
174 212329 : r = sub( r, 1 ); /* Q0 */
175 212329 : mask = shr( mask, 1 ); /* Q0 */
176 : }
177 : }
178 : }
179 :
180 1907335 : return;
181 : }
182 :
183 :
184 : /*-------------------------------------------------------------------------
185 : * re8_k2y_fx()
186 : *
187 : * VORONOI INDEXING (INDEX DECODING) k -> y
188 : -------------------------------------------------------------------------*/
189 504319 : void re8_k2y_fx(
190 : const Word16 *k, /* i : Voronoi index k[0..7] Q0*/
191 : const Word16 m, /* i : Voronoi modulo (m = 2^r = 1<<r, where r is integer >=2) Q0*/
192 : Word16 *y /* o : 8-dimensional point y[0..7] in RE8 Q0*/
193 : )
194 : {
195 : Word16 i, v[8], *ptr1, *ptr2, m_tmp, mm;
196 : Word32 ytp[8], z[8], Ltmp, Lsum;
197 :
198 : /*---------------------------------------------------------------*
199 : * compute y = k M and z=(y-a)/m, where
200 : * M = [4 ]
201 : * [2 2 ]
202 : * [| \ ]
203 : * [2 2 ]
204 : * [1 1 _ 1 1]
205 : * a=(2,0,...,0)
206 : *---------------------------------------------------------------*/
207 504319 : m_tmp = sub( 15, m ); /* Q0 */
208 :
209 504319 : Lsum = L_deposit_l( k[7] ); /* Q0 */
210 504319 : ytp[7] = Lsum;
211 504319 : move32();
212 504319 : z[7] = L_shl( Lsum, m_tmp ); /* m_tmp */
213 504319 : move32(); /* (int)(floor(y[7]*QR+0.5))>>m */
214 :
215 3530233 : FOR( i = 6; i >= 1; i-- )
216 : {
217 3025914 : Ltmp = L_deposit_l( shl( k[i], 1 ) ); /* Q0 */
218 3025914 : Lsum = L_add( Lsum, Ltmp ); /* Q0 */
219 3025914 : ytp[i] = L_add( ytp[7], Ltmp ); /* Q0 */
220 3025914 : move32();
221 3025914 : z[i] = L_shl( ytp[i], m_tmp ); /* m_tmp */
222 3025914 : move32(); /* (int)(floor(y[7]*QR+0.5))>>m */
223 : }
224 :
225 504319 : Lsum = L_add( Lsum, L_deposit_l( shl( k[0], 2 ) ) ); /* Q0 */
226 504319 : ytp[0] = Lsum;
227 504319 : move32();
228 504319 : z[0] = L_shl( L_sub( Lsum, 2 ), m_tmp ); /* m_tmp */
229 504319 : move32(); /* (int)(floor(y[7]*QR+0.5))>>m */
230 :
231 : /*---------------------------------------------------------------*
232 : * find nearest neighbor v of z in infinite RE8
233 : *---------------------------------------------------------------*/
234 504319 : re8_PPV_fx( z, v );
235 :
236 : /*---------------------------------------------------------------*
237 : * compute y -= m v
238 : *---------------------------------------------------------------*/
239 504319 : ptr1 = y; /* Q0 */
240 504319 : ptr2 = v; /* Q0 */
241 :
242 504319 : mm = shr( shl( 1, m ), 1 ); /* shr to remove effect of L_mult in L_msu */
243 :
244 4538871 : FOR( i = 0; i < 8; i++ )
245 : {
246 4034552 : Ltmp = L_msu( ytp[i], *ptr2++, mm ); /* Q0 */
247 4034552 : *ptr1++ = extract_l( Ltmp ); /* Q0 */
248 : }
249 :
250 504319 : return;
251 : }
252 :
253 :
254 : /*-----------------------------------------------------------------------*
255 : * re8_identify_absolute_leader:
256 : *
257 : * IDENTIFY THE ABSOLUTE LEADER RELATED TO y USING A PRE-DEFINED TABLE WHICH
258 : * SPECIFIES THE CODEBOOKS Q0, Q2, Q3 and Q4
259 : -----------------------------------------------------------------------*/
260 :
261 2331991 : static Word16 re8_identify_absolute_leader_fx( /* o : integer indicating if y if in Q0, Q2, Q3 or Q4 (or if y is an outlier) Q0*/
262 : const Word16 y[] /* i : point in RE8 (8-dimensional integer vector) Q0*/
263 : )
264 : {
265 : Word16 i, s, id, nb, pos, ka, tmp16;
266 : Word32 Ltmp, Ls;
267 : Word32 C;
268 : const Word16 *ptr;
269 :
270 : /*-----------------------------------------------------------------------*
271 : * compute the RE8 shell number s = (y1^2+...+y8^2)/8 and C=(y1^2, ..., y8^2)
272 : *-----------------------------------------------------------------------*/
273 2331991 : Ls = L_mult( y[0], y[0] ); /* Q1 */
274 18655928 : FOR( i = 1; i < 8; i++ )
275 : {
276 16323937 : Ls = L_mac( Ls, y[i], y[i] ); /* Q1 */
277 : }
278 2331991 : s = extract_h( L_shl_sat( Ls, 16 - ( 3 + 1 ) ) ); /* s can saturate here */
279 : /*-----------------------------------------------------------------------*
280 : * compute the index 0 <= ka <= NB_LEADER+1 which identifies an absolute leader of Q0, Q2, Q3 or Q4
281 : *
282 : * by default, ka=index of last element of the table (to indicate an outlier)
283 : *-----------------------------------------------------------------------*/
284 : /*-------------------------------------------------------------------*
285 : * if s=0, y=0 i.e. y is in Q0 -> ka=index of element indicating Q0
286 : *-------------------------------------------------------------------*/
287 2331991 : ka = NB_LEADER;
288 2331991 : move16();
289 2331991 : IF( s != 0 )
290 : {
291 2131464 : ka = NB_LEADER + 1;
292 2131464 : move16();
293 : /*-------------------------------------------------------------------*
294 : * the maximal value of s for y in Q0, Q2, Q3 or Q4 is NB_SPHERE
295 : * if s> NB_SPHERE, y is an outlier (the value of ka is set correctly)
296 : *-------------------------------------------------------------------*/
297 2131464 : IF( LE_16( s, NB_SPHERE ) )
298 : {
299 : /*---------------------------------------------------------------*
300 : * compute the unique identifier id of the absolute leader related to y:
301 : * s = (y1^4 + ... + y8^4)/8
302 : *---------------------------------------------------------------*/
303 2091675 : C = L_mult( y[0], y[0] ); /* Q1 */
304 2091675 : tmp16 = extract_h( L_shl( C, 16 - 1 ) ); /* Q0 */
305 2091675 : Ltmp = L_mult( tmp16, tmp16 ); /* Q1 */
306 16733400 : FOR( i = 1; i < 8; i++ )
307 : {
308 14641725 : C = L_mult( y[i], y[i] ); /* Q1 */
309 14641725 : tmp16 = extract_h( L_shl( C, 16 - 1 ) ); /* Q0 */
310 14641725 : Ltmp = L_mac( Ltmp, tmp16, tmp16 ); /* Q1 */
311 : }
312 2091675 : id = extract_h( L_shl( Ltmp, 16 - ( 3 + 1 ) ) ); /* id can saturate to 8192 */
313 :
314 : /*---------------------------------------------------------------*
315 : * search for id in table Da_id
316 : * (containing all possible values of id if y is in Q2, Q3 or Q4)
317 : * this search is focused based on the shell number s so that
318 : * only the id's related to the shell of number s are checked
319 : *---------------------------------------------------------------*/
320 :
321 2091675 : nb = Da_nb[s - 1]; /* get the number of absolute leaders used on the shell of number s Q0*/
322 2091675 : pos = Da_pos[s - 1]; /* get the position of the first absolute leader of shell s in Da_id Q0*/
323 2091675 : move16();
324 2091675 : move16();
325 :
326 2091675 : ptr = &Da_id[pos]; /* Q0 */
327 2091675 : move16();
328 3625790 : FOR( i = 0; i < nb; i++ )
329 : {
330 3240924 : IF( EQ_16( id, *ptr ) )
331 : {
332 1706809 : ka = pos;
333 1706809 : move16(); /* get ka */
334 1706809 : BREAK;
335 : }
336 1534115 : ptr++;
337 1534115 : pos = add( pos, 1 ); /* Q0 */
338 : }
339 : }
340 : }
341 :
342 2331991 : return ( ka );
343 : }
344 :
345 :
346 : /*-------------------------------------------------------------------------
347 : * Re8_coord:
348 : *
349 : * COMPUTATION OF RE8 COORDINATES
350 : -----------------------------------------------------------------------*/
351 :
352 212328 : static void re8_coord_fx(
353 : const Word16 *y, /* i : 8-dimensional point y[0..7] in RE8 Q0*/
354 : Word16 *k /* o : coordinates k[0..7] Q0*/
355 : )
356 : {
357 : Word16 i, tmp, sum;
358 :
359 : /*---------------------------------------------------------------*
360 : * compute k = y M^-1
361 : * M = 1/4 [ 1 ]
362 : * [-1 2 ]
363 : * [ | \ ]
364 : * [-1 2 ]
365 : * [ 5 -2 _ -2 4]
366 : *
367 : *---------------------------------------------------------------*/
368 212328 : k[7] = y[7]; /* Q0 */
369 212328 : move16();
370 212328 : tmp = y[7]; /* Q0 */
371 212328 : move16();
372 212328 : sum = add( y[7], shl( y[7], 2 ) ); /* Q0 */
373 :
374 1486296 : FOR( i = 6; i >= 1; i-- )
375 : {
376 : /* apply factor 2/4 from M^-1 */
377 1273968 : k[i] = shr( sub( y[i], tmp ), 1 ); /* Q0 */
378 1273968 : move16();
379 1273968 : sum = sub( sum, y[i] ); /* Q0 */
380 : }
381 : /* apply factor 1/4 from M^-1 */
382 212328 : k[0] = shr( add( y[0], sum ), 2 ); /* Q0 */
383 212328 : move16();
384 :
385 212328 : return;
386 : }
|