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 0 : 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 0 : *ka = re8_identify_absolute_leader_fx( y ); /* Q0 */
49 0 : 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 0 : *n = Da_nq[*ka]; /* Q0 */
56 0 : 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 0 : IF( LE_16( *n, 4 ) )
72 : {
73 0 : Copy( y, c, 8 ); /* Q0 */
74 : }
75 : ELSE
76 : {
77 : /*------------------------------------------------------------*
78 : * initialize r and m=2^r based on || y ||^2/8
79 : *------------------------------------------------------------*/
80 0 : Ltmp = L_mult( y[0], y[0] ); /* Q1 */
81 0 : FOR( i = 1; i < 8; i++ )
82 : {
83 0 : Ltmp = L_mac( Ltmp, y[i], y[i] ); /* Q1 */
84 : }
85 :
86 0 : Lsphere = L_shr( Ltmp, 5 + 1 ); /* *0.125*0.25 / 2 to remove L_mac effect */
87 :
88 0 : r = 1;
89 0 : move16();
90 0 : FOR( ; Lsphere > 11; Lsphere >>= 2 )
91 : {
92 0 : r = add( r, 1 );
93 : }
94 : /*------------------------------------------------------------*
95 : * compute the coordinates of y in the RE8 basis
96 : *------------------------------------------------------------*/
97 0 : re8_coord_fx( y, k_mod );
98 :
99 : /*------------------------------------------------------------*
100 : * compute m and the mask needed for modulo m (for Voronoi coding)
101 : *------------------------------------------------------------*/
102 0 : 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 0 : 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 0 : FOR( i = 0; i < 8; i++ )
114 : {
115 0 : k_tmp[i] = s_and( k_mod[i], mask ); /* Q0 */
116 0 : move16();
117 : }
118 :
119 0 : 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 0 : FOR( i = 0; i < 8; i++ )
127 : {
128 0 : c_tmp[i] = shr( sub( y[i], v[i] ), r ); /* Q0 */
129 0 : move16();
130 : }
131 :
132 : /*--------------------------------------------------------*
133 : * verify if c_tmp is in Q2, Q3 or Q4
134 : *--------------------------------------------------------*/
135 0 : 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 0 : n_tmp = Da_nq[ka_tmp]; /* Q0 */
141 0 : move16();
142 :
143 0 : 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 0 : r = add( r, 1 ); /* Q0 */
149 0 : 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 0 : n_tmp = s_max( n_tmp, 3 ); /* Q0 */
160 :
161 : /*--------------------------------------------------------*
162 : * save current values into ka, n, k and c
163 : *--------------------------------------------------------*/
164 0 : *ka = ka_tmp; /* Q0 */
165 0 : move16();
166 0 : *n = add( n_tmp, shl( r, 1 ) ); /* Q0 */
167 0 : move16();
168 0 : Copy( k_tmp, k, 8 ); /* Q0 */
169 0 : 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 0 : r = sub( r, 1 ); /* Q0 */
175 0 : mask = shr( mask, 1 ); /* Q0 */
176 : }
177 : }
178 : }
179 :
180 0 : return;
181 : }
182 :
183 :
184 : /*-------------------------------------------------------------------------
185 : * re8_k2y_fx()
186 : *
187 : * VORONOI INDEXING (INDEX DECODING) k -> y
188 : -------------------------------------------------------------------------*/
189 79663 : 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 79663 : m_tmp = sub( 15, m ); /* Q0 */
208 :
209 79663 : Lsum = L_deposit_l( k[7] ); /* Q0 */
210 79663 : ytp[7] = Lsum;
211 79663 : move32();
212 79663 : z[7] = L_shl( Lsum, m_tmp ); /* m_tmp */
213 79663 : move32(); /* (int)(floor(y[7]*QR+0.5))>>m */
214 :
215 557641 : FOR( i = 6; i >= 1; i-- )
216 : {
217 477978 : Ltmp = L_deposit_l( shl( k[i], 1 ) ); /* Q0 */
218 477978 : Lsum = L_add( Lsum, Ltmp ); /* Q0 */
219 477978 : ytp[i] = L_add( ytp[7], Ltmp ); /* Q0 */
220 477978 : move32();
221 477978 : z[i] = L_shl( ytp[i], m_tmp ); /* m_tmp */
222 477978 : move32(); /* (int)(floor(y[7]*QR+0.5))>>m */
223 : }
224 :
225 79663 : Lsum = L_add( Lsum, L_deposit_l( shl( k[0], 2 ) ) ); /* Q0 */
226 79663 : ytp[0] = Lsum;
227 79663 : move32();
228 79663 : z[0] = L_shl( L_sub( Lsum, 2 ), m_tmp ); /* m_tmp */
229 79663 : move32(); /* (int)(floor(y[7]*QR+0.5))>>m */
230 :
231 : /*---------------------------------------------------------------*
232 : * find nearest neighbor v of z in infinite RE8
233 : *---------------------------------------------------------------*/
234 79663 : re8_PPV_fx( z, v );
235 :
236 : /*---------------------------------------------------------------*
237 : * compute y -= m v
238 : *---------------------------------------------------------------*/
239 79663 : ptr1 = y; /* Q0 */
240 79663 : ptr2 = v; /* Q0 */
241 :
242 79663 : mm = shr( shl( 1, m ), 1 ); /* shr to remove effect of L_mult in L_msu */
243 :
244 716967 : FOR( i = 0; i < 8; i++ )
245 : {
246 637304 : Ltmp = L_msu( ytp[i], *ptr2++, mm ); /* Q0 */
247 637304 : *ptr1++ = extract_l( Ltmp ); /* Q0 */
248 : }
249 :
250 79663 : 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 0 : 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 0 : Ls = L_mult( y[0], y[0] ); /* Q1 */
274 0 : FOR( i = 1; i < 8; i++ )
275 : {
276 0 : Ls = L_mac( Ls, y[i], y[i] ); /* Q1 */
277 : }
278 0 : 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 0 : ka = NB_LEADER;
288 0 : move16();
289 0 : IF( s != 0 )
290 : {
291 0 : ka = NB_LEADER + 1;
292 0 : 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 0 : 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 0 : C = L_mult( y[0], y[0] ); /* Q1 */
304 0 : tmp16 = extract_h( L_shl( C, 16 - 1 ) ); /* Q0 */
305 0 : Ltmp = L_mult( tmp16, tmp16 ); /* Q1 */
306 0 : FOR( i = 1; i < 8; i++ )
307 : {
308 0 : C = L_mult( y[i], y[i] ); /* Q1 */
309 0 : tmp16 = extract_h( L_shl( C, 16 - 1 ) ); /* Q0 */
310 0 : Ltmp = L_mac( Ltmp, tmp16, tmp16 ); /* Q1 */
311 : }
312 0 : 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 0 : nb = Da_nb[s - 1]; /* get the number of absolute leaders used on the shell of number s Q0*/
322 0 : pos = Da_pos[s - 1]; /* get the position of the first absolute leader of shell s in Da_id Q0*/
323 0 : move16();
324 0 : move16();
325 :
326 0 : ptr = &Da_id[pos]; /* Q0 */
327 0 : move16();
328 0 : FOR( i = 0; i < nb; i++ )
329 : {
330 0 : IF( EQ_16( id, *ptr ) )
331 : {
332 0 : ka = pos;
333 0 : move16(); /* get ka */
334 0 : BREAK;
335 : }
336 0 : ptr++;
337 0 : pos = add( pos, 1 ); /* Q0 */
338 : }
339 : }
340 : }
341 :
342 0 : return ( ka );
343 : }
344 :
345 :
346 : /*-------------------------------------------------------------------------
347 : * Re8_coord:
348 : *
349 : * COMPUTATION OF RE8 COORDINATES
350 : -----------------------------------------------------------------------*/
351 :
352 0 : 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 0 : k[7] = y[7]; /* Q0 */
369 0 : move16();
370 0 : tmp = y[7]; /* Q0 */
371 0 : move16();
372 0 : sum = add( y[7], shl( y[7], 2 ) ); /* Q0 */
373 :
374 0 : FOR( i = 6; i >= 1; i-- )
375 : {
376 : /* apply factor 2/4 from M^-1 */
377 0 : k[i] = shr( sub( y[i], tmp ), 1 ); /* Q0 */
378 0 : move16();
379 0 : sum = sub( sum, y[i] ); /* Q0 */
380 : }
381 : /* apply factor 1/4 from M^-1 */
382 0 : k[0] = shr( add( y[0], sum ), 2 ); /* Q0 */
383 0 : move16();
384 :
385 0 : return;
386 : }
|