Line data Source code
1 : /******************************************************************************************************
2 :
3 : (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB,
4 : Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
5 : Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
6 : Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
7 : contributors to this repository. All Rights Reserved.
8 :
9 : This software is protected by copyright law and by international treaties.
10 : The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB,
11 : Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
12 : Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
13 : Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
14 : contributors to this repository retain full ownership rights in their respective contributions in
15 : the software. This notice grants no license of any kind, including but not limited to patent
16 : license, nor is any license granted by implication, estoppel or otherwise.
17 :
18 : Contributors are required to enter into the IVAS codec Public Collaboration agreement before making
19 : contributions.
20 :
21 : This software is provided "AS IS", without any express or implied warranties. The software is in the
22 : development stage. It is intended exclusively for experts who have experience with such software and
23 : solely for the purpose of inspection. All implied warranties of non-infringement, merchantability
24 : and fitness for a particular purpose are hereby disclaimed and excluded.
25 :
26 : Any dispute, controversy or claim arising under or in relation to providing this software shall be
27 : submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in
28 : accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and
29 : the United Nations Convention on Contracts on the International Sales of Goods.
30 :
31 : *******************************************************************************************************/
32 :
33 : /*====================================================================================
34 : EVS Codec 3GPP TS26.452 Aug 12, 2021. Version 16.3.0
35 : ====================================================================================*/
36 :
37 : #include <stdint.h>
38 : #include "options.h" /* Compilation switches */
39 : #include "cnst.h" /* Common constants */
40 : #include "prot_fx.h" /* Function prototypes */
41 : #include "prot_fx_enc.h" /* Function prototypes */
42 : #include "basop_util.h"
43 :
44 : /*-------------------------------------------------------------------*
45 : * Local constants
46 : *-------------------------------------------------------------------*/
47 :
48 : #define DIST_ISF_MAX_IO 384 /* 150 Hz (6400Hz=16384) */
49 : #define DIST_ISF_MAX 307 /* 120 Hz (6400Hz=16384) */
50 : #define DIST_ISF_THRES 154 /* 60 (6400Hz=16384) */
51 : #define GAIN_PIT_THRES 14746 /* 0.9 in Q14 */
52 : #define GAIN_PIT_MIN 9830 /* 0.6 in Q14 */
53 :
54 : #define ALPHA1 32113 /* 0.98f */
55 : #define ALPHA4 32440 /* 0.99f */
56 : #define WINDOW_SIZE 50
57 : #define THRESH_TYPE 13926 /* 0.85f in Q14 */
58 : #define THRESH_VOICING 14090 /* 0.86f in Q14 */
59 :
60 : #define GPCLIP_E ( 6 + 2 )
61 :
62 : #define ALPHA1_M1 21474836l /*1.0f-0.98 Q30*/
63 : #define ALPHA4_M1 10737408l /*1.0f-0.99f Q30*/
64 :
65 : /*-------------------------------------------------------------------*
66 : * init_gp_clip
67 : *
68 : * Pitch Gain clipping initializations
69 : *-------------------------------------------------------------------*/
70 32374 : void init_gp_clip_fx(
71 : Word16 mem[] /* o : memory of gain of pitch clipping algorithm [2.56x,Q14,Q8,Q0,Q14,Q14]*/
72 : )
73 : {
74 32374 : mem[0] = DIST_ISF_MAX;
75 32374 : move16(); /* Q0 */
76 32374 : mem[1] = GAIN_PIT_MIN;
77 32374 : move16(); /* 1Q14 */
78 32374 : mem[2] = 0;
79 32374 : move16(); /* 8Q7 */ /* old energy of target (dB) */
80 32374 : mem[3] = 0;
81 32374 : move16(); /* Q0 */
82 32374 : mem[4] = 0;
83 32374 : move16(); /* Q14 */
84 32374 : mem[5] = 13107; /*0.8*/
85 32374 : move16(); /* Q14 */
86 :
87 32374 : return;
88 : }
89 :
90 : /*-------------------------------------------------------------------*
91 : * Function gp_clip
92 : *
93 : * The gain needs to be limited (gain pitch < 1.0) when one of the
94 : * following cases occurs:
95 : * - a resonance on LPC filter (lp_disp < 60 Hz) AND a good pitch
96 : * prediction (lp_gp > 0.9)
97 : * - target energy drops by 6 dB AND a good pitch prediction (lp_gp>1.0)
98 : *-------------------------------------------------------------------*/
99 :
100 613414 : Word16 gp_clip_fx(
101 : const Word16 element_mode, /* i : element mode Q0*/
102 : const Word32 core_brate, /* i : core bitrate Q0*/
103 : const Word16 *voicing, /* i : normalized correlations (from OL pitch) Q15*/
104 : const Word16 i_subfr, /* i : subframe index Q0*/
105 : const Word16 coder_type, /* i : type of coder Q0*/
106 : const Word16 xn[], /* i : target vector Q_new*/
107 : Word16 mem[], /* i/o: memory of gain of pitch clipping algorithm [2.56x,Q14,Q8,Q0,Q14,Q14]*/
108 : const Word16 Q_new /* i : scaling factor */
109 : )
110 : {
111 : Word16 clip;
112 : Word16 i, wener;
113 : Word16 e_ener, f_ener;
114 : Word32 ener;
115 : Word32 L_tmp;
116 : Word16 thres;
117 : #ifndef ISSUE_1867_replace_overflow_libenc
118 : #ifdef BASOP_NOGLOB_DECLARE_LOCAL
119 : Flag Overflow = 0;
120 : move32();
121 : #endif
122 : #endif
123 :
124 613414 : clip = 0;
125 613414 : move16();
126 613414 : test();
127 613414 : test();
128 613414 : IF( EQ_32( core_brate, ACELP_6k60 ) || EQ_32( core_brate, ACELP_8k85 ) || element_mode > EVS_MONO )
129 : {
130 607136 : thres = add( 14746 /* 0.9 in Q14 */, mult( 1638 /* 0.1 in Q14 */, extract_l( L_mult( mem[0], (Word16) ( 16384 / DIST_ISF_MAX_IO ) ) ) ) ); /* clipping is activated when filtered pitch gain > threshold (0.94 to 1 in Q14) */
131 607136 : if ( GT_16( mem[1], thres ) )
132 : {
133 0 : clip = 1;
134 0 : move16();
135 : }
136 : }
137 : ELSE
138 : {
139 6278 : test();
140 6278 : if ( LT_16( mem[0], DIST_ISF_THRES ) && GT_16( mem[1], GAIN_PIT_THRES ) )
141 : {
142 16 : clip = 1;
143 16 : move16();
144 : }
145 : }
146 :
147 : #ifdef ISSUE_1867_replace_overflow_libenc
148 613414 : ener = L_mac_sat( 1L, xn[0], xn[0] );
149 : #else
150 : ener = L_mac_o( 1L, xn[0], xn[0], &Overflow );
151 : #endif
152 39258496 : FOR( i = 1; i < L_SUBFR; i++ )
153 : {
154 : #ifdef ISSUE_1867_replace_overflow_libenc
155 38645082 : ener = L_mac_sat( ener, xn[i], xn[i] );
156 : #else
157 : ener = L_mac_o( ener, xn[i], xn[i], &Overflow );
158 : #endif
159 : }
160 :
161 : /* ener = 10.0f*(float)log10(ener) */
162 613414 : e_ener = norm_l( ener );
163 613414 : f_ener = Log2_norm_lc( L_shl( ener, e_ener ) );
164 613414 : e_ener = sub( 30, e_ener );
165 613414 : IF( element_mode > EVS_MONO )
166 : {
167 607136 : e_ener = sub( e_ener, Q_new * 2 + 1 );
168 : }
169 : ELSE
170 : {
171 6278 : e_ener = sub( e_ener, Q_new );
172 : }
173 613414 : ener = Mpy_32_16( e_ener, f_ener, LG10 ); /* Q14 */
174 613414 : wener = round_fx( L_shl( ener, 10 ) ); /* Q8 */
175 :
176 613414 : test();
177 613414 : if ( LT_16( wener, sub( mem[2], 1536 /* 6.0f in Q8 */ ) ) && GT_16( mem[1], 16384 /* 1 in Q14 */ ) )
178 : {
179 0 : clip = 1;
180 0 : move16();
181 : }
182 :
183 613414 : mem[2] = wener; /* Q8 */
184 613414 : move16();
185 :
186 613414 : L_tmp = L_mult( ALPHA1, mem[4] ); /* Q30 */
187 :
188 613414 : test();
189 613414 : test();
190 613414 : if ( EQ_16( coder_type, GENERIC ) || EQ_16( coder_type, TRANSITION ) || EQ_16( coder_type, INACTIVE ) )
191 : {
192 : /* mem[4] = (1-ALPHA1) + ALPHA1 * mem[4], if branch taken */
193 : /* mem[4] = ALPHA1 * mem[4], otherwise */
194 548802 : L_tmp = L_add( L_tmp, 32768L * ( 32768 - ALPHA1 ) ); /* Q30 */
195 : }
196 613414 : mem[4] = round_fx( L_tmp ); /* Q14 */
197 :
198 613414 : L_tmp = L_mult( ALPHA4, mem[5] );
199 613414 : IF( i_subfr == 0 )
200 : {
201 : /* mem[5] = (1-ALPHA4) * voicing[0] + ALPHA4 * mem[5] */
202 141020 : mem[5] = mac_r( L_tmp, ( 32768 - ALPHA4 ) / 2, voicing[0] );
203 141020 : move16(); /* /2 to put voicing from Q15 to Q14 */
204 : }
205 :
206 613414 : IF( EQ_16( i_subfr, 2 * L_SUBFR ) )
207 : {
208 : /* mem[5] = (1-ALPHA4) * voicing[1] + ALPHA4 * mem[5] */
209 135947 : mem[5] = mac_r( L_tmp, ( 32768 - ALPHA4 ) / 2, voicing[1] );
210 135947 : move16(); /* /2 to put voicing from Q15 to Q14 */
211 : }
212 :
213 613414 : IF( GT_16( mem[3], WINDOW_SIZE ) )
214 : {
215 427918 : test();
216 427918 : if ( GT_16( mem[4], THRESH_TYPE ) && GT_16( mem[5], THRESH_VOICING ) )
217 : {
218 6109 : clip = 1;
219 6109 : move16();
220 : }
221 : }
222 : ELSE
223 : {
224 185496 : mem[3] = add( mem[3], 1 ); /* Q0 */
225 185496 : move16();
226 : }
227 :
228 613414 : return ( clip );
229 : }
230 :
231 : /*-------------------------------------------------------------------*
232 : * gp_clip_test_lsf()
233 : *
234 : * check the minimum distance of LSFs for pitch gain clipping flag
235 : *-------------------------------------------------------------------*/
236 :
237 0 : void gp_clip_test_isf_fx(
238 : const Word16 element_mode, /* i : element mode Q0*/
239 : const Word32 core_brate, /* i : core bitrate Q0*/
240 : const Word16 isf[], /* i : isf values (in frequency domain) Q2.56*/
241 : Word16 mem[], /* i/o: memory of gain of pitch clipping algorithm Q15*/
242 : const Word16 Opt_AMR_WB /* i : flag indicating AMR-WB IO mode Q0*/
243 : )
244 : {
245 : Word16 i, dist, dist_min, m;
246 :
247 0 : dist_min = sub( isf[1], isf[0] ); /* Q2.56 */
248 :
249 0 : m = M;
250 0 : move16();
251 0 : if ( EQ_16( Opt_AMR_WB, 1 ) )
252 : {
253 0 : m = M - 1;
254 0 : move16();
255 : }
256 :
257 0 : move16(); /* ptr init*/
258 0 : FOR( i = 2; i < m; i++ )
259 : {
260 0 : dist = sub( isf[i], isf[i - 1] ); /* Q2.56 */
261 0 : dist_min = s_min( dist, dist_min ); /* Q2.56 */
262 : }
263 :
264 0 : dist = extract_h( L_mac( L_mult( 26214 /* 0.8f in Q15 */, mem[0] ), 6554 /* 0.2f in Q15 */, dist_min ) ); /* Q15 */
265 :
266 0 : test();
267 0 : test();
268 0 : IF( EQ_32( core_brate, ACELP_6k60 ) || EQ_32( core_brate, ACELP_8k85 ) || element_mode > EVS_MONO )
269 : {
270 0 : dist = s_min( dist, DIST_ISF_MAX_IO );
271 : }
272 : ELSE
273 : {
274 0 : dist = s_min( dist, DIST_ISF_MAX );
275 : }
276 0 : mem[0] = dist; /* Q15 */
277 0 : move16();
278 :
279 0 : return;
280 : }
281 :
282 : /*-------------------------------------------------------------------*
283 : * gp_clip_test_gain_pit()
284 : *
285 : * low-pass filtering of the pitch gain for pitch gain clipping flag
286 : *-------------------------------------------------------------------*/
287 :
288 645417 : void gp_clip_test_gain_pit_fx(
289 : const Word16 element_mode, /* i : element mode Q0*/
290 : const Word32 core_brate, /* i : core bitrate Q0*/
291 : const Word16 gain_pit, /* i : gain of quantized pitch Q14*/
292 : Word16 mem[] /* i/o: memory of gain of pitch clipping algorithm 1Q14*/
293 : )
294 : {
295 : Word16 gain;
296 : Word32 L_tmp;
297 :
298 645417 : test();
299 645417 : test();
300 645417 : IF( EQ_32( core_brate, ACELP_6k60 ) || EQ_32( core_brate, ACELP_8k85 ) || element_mode > EVS_MONO )
301 : {
302 635982 : L_tmp = L_mult( 32113 /* 0.98 in Q15 */, mem[1] ); /* long term LTP gain average (>250ms) */
303 635982 : L_tmp = L_mac( L_tmp, 655 /* 0.02 in Q15 */, gain_pit );
304 : }
305 : ELSE
306 : {
307 9435 : L_tmp = L_mult( 29491 /* 0.9 in Q15 */, mem[1] );
308 9435 : L_tmp = L_mac( L_tmp, 3277 /* 0.1 in Q15 */, gain_pit );
309 : }
310 645417 : gain = extract_h( L_tmp );
311 645417 : gain = s_max( gain, GAIN_PIT_MIN );
312 645417 : mem[1] = gain; /* Q14 */
313 645417 : move16();
314 :
315 645417 : return;
316 : }
317 :
318 :
319 : /*-------------------------------------------------------------------*
320 : * Function gp_clip
321 : *
322 : * The gain needs to be limited (gain pitch < 1.0) when one of the
323 : * following cases occurs:
324 : * - a resonance on LPC filter (lp_disp < 60 Hz) AND a good pitch
325 : * prediction (lp_gp > 0.9)
326 : * - target energy drops by 6 dB AND a good pitch prediction (lp_gp>1.0)
327 : *-------------------------------------------------------------------*/
328 11120 : Word16 Mode2_gp_clip_fx(
329 : const Word16 *voicing, /* i : normalized correlations from OL pitch Q15 */
330 : const Word16 i_subfr, /* i : subframe index Q0 */
331 : const Word16 coder_type, /* i : type of coder Q0 */
332 : const Word16 xn[], /* i : target vector Q_xn */
333 : Word16 mem[], /* i/o: memory of gain of pitch clipping algorithm */
334 : /* mem[0]: Q0 */
335 : /* mem[1]: 1Q14 */
336 : /* mem[2]: 8Q7 */
337 : /* mem[3]: Q0 (integer) */
338 : /* mem[4]: Q14 */
339 : /* mem[5]: Q14 */
340 : const Word16 L_subfr, /* Q0 */
341 : const Word16 Q_xn /* i : scaling factor of vector xn[] */
342 : )
343 : {
344 : Word16 clip, tmp, exp_xn;
345 : Word16 i;
346 : Word32 wener, Ltmp;
347 : #ifndef ISSUE_1867_replace_overflow_libenc
348 : #ifdef BASOP_NOGLOB_DECLARE_LOCAL
349 : Flag Overflow = 0;
350 : move32();
351 : #endif
352 : #endif
353 11120 : move16();
354 11120 : clip = 0;
355 :
356 11120 : test();
357 11120 : if ( ( LT_16( mem[0], DIST_ISF_THRES ) ) && ( GT_16( mem[1], GAIN_PIT_THRES ) ) )
358 : {
359 0 : move16();
360 0 : clip = 1;
361 : }
362 :
363 : /*ener_exp = exp_xn * 2 + 1*/
364 11120 : exp_xn = add( shl( sub( 15, Q_xn ), 1 ), 1 );
365 11120 : wener = L_shr( 21474836l /*0.01f Q31*/, s_min( 31, exp_xn ) );
366 11120 : wener = L_max( 1, wener );
367 :
368 722800 : FOR( i = 0; i < L_subfr; i++ )
369 : {
370 : #ifdef ISSUE_1867_replace_overflow_libenc
371 711680 : wener = L_mac0_sat( wener, xn[i], xn[i] );
372 : #else
373 : wener = L_mac0_o( wener, xn[i], xn[i], &Overflow );
374 : #endif
375 : }
376 :
377 : /*wener = 10.0f*(float)log10(wener);*/
378 11120 : wener = BASOP_Util_Log2( wener );
379 11120 : wener = L_add( wener, L_shl( exp_xn, 31 - LD_DATA_SCALE ) );
380 11120 : wener = Mpy_32_16_1( wener, LG10 ); /* wener in 8Q7 */
381 : #if ( GPCLIP_E != 6 + 2 )
382 : wener = shl( wener, GPCLIP_E - ( 6 + 2 ) );
383 : #endif
384 11120 : tmp = round_fx( wener );
385 : /* exponent of wener = 6+2 */
386 :
387 11120 : test();
388 12067 : if ( LT_16( tmp, sub( mem[2], 768 /*6.0f Q7*/ ) ) &&
389 947 : GT_16( mem[1], 16384 /*1.0f Q14*/ ) )
390 : {
391 0 : move16();
392 0 : clip = 1;
393 : }
394 :
395 11120 : move16();
396 11120 : mem[2] = tmp; /* wener in 8Q7 format */
397 11120 : Ltmp = Mpy_32_16_1( ALPHA1, mem[4] ); /* mem[4] in Q14 format, Ltmp in Q14 */
398 :
399 11120 : if ( s_or( (Word16) EQ_16( coder_type, GENERIC ), (Word16) EQ_16( coder_type, TRANSITION ) ) )
400 : {
401 1575 : Ltmp = L_add( Ltmp, ALPHA1_M1 ); /* Q30 */
402 : }
403 11120 : mem[4] = round_fx( Ltmp ); /* Q14 */
404 :
405 11120 : Ltmp = Mpy_32_16_1( ALPHA4, mem[5] ); /* mem[5] in Q14 format, Ltmp in Q14 */
406 11120 : IF( i_subfr == 0 )
407 : {
408 2627 : move16(); /* voicing: Q15 */
409 2627 : mem[5] = round_fx( L_add( Mpy_32_16_1( ALPHA4_M1, voicing[0] ), Ltmp ) ); /* Q14 */
410 : }
411 8493 : ELSE IF( EQ_16( i_subfr, shl( L_subfr, 1 ) ) )
412 : {
413 2627 : move16();
414 2627 : mem[5] = round_fx( L_add( Mpy_32_16_1( ALPHA4_M1, voicing[1] ), Ltmp ) ); /* Q14 */
415 : }
416 :
417 11120 : IF( GT_16( mem[3], WINDOW_SIZE ) )
418 : {
419 7691 : test();
420 7691 : if ( ( GT_16( mem[4], THRESH_TYPE ) ) && ( GT_16( mem[5], THRESH_VOICING ) ) )
421 : {
422 0 : move16();
423 0 : clip = 1;
424 : }
425 : }
426 : ELSE
427 : {
428 3429 : move16();
429 3429 : mem[3] = add( mem[3], 1 ); /* Q0 */
430 : }
431 :
432 :
433 11120 : return ( clip );
434 : }
435 :
436 : /*-------------------------------------------------------------------*
437 : * gp_clip_test_lsf:
438 : *
439 : * check the minimum distance of LSFs for pitch gain clipping flag
440 : *-------------------------------------------------------------------*/
441 2669 : void gp_clip_test_lsf_fx(
442 : const Word16 element_mode, /* i : element mode Q0*/
443 : const Word16 lsf[], /* i : lsf values (in frequency domain) 14Q1*1.28*/
444 : Word16 mem[], /* i/o: memory of gain of pitch clipping algorithm [2.56x,Q14,Q8,Q0,Q14,Q14]*/
445 : const Word16 m /* i : dimension of lsf Q0*/
446 : )
447 : {
448 : Word16 i;
449 : Word16 dist, dist_min, dist_max;
450 :
451 2669 : dist_max = DIST_ISF_MAX;
452 2669 : move16();
453 2669 : if ( element_mode > EVS_MONO )
454 : {
455 0 : dist_max = DIST_ISF_MAX_IO;
456 0 : move16();
457 : }
458 2669 : dist_min = sub( lsf[1], lsf[0] ); /* 14Q1*1.28 */
459 :
460 18867 : FOR( i = 2; i < m - 1; i++ )
461 : {
462 16198 : dist = sub( lsf[i], lsf[i - 1] ); /* 14Q1*1.28 */
463 16198 : dist_min = s_min( dist, dist_min );
464 : }
465 : /*dist = 0.8f*mem[0] + 0.2f*dist_min;*/
466 2669 : dist = s_min( dist_max, mac_r( L_mult( 26214 /*0.8f Q15*/, mem[0] ), 6554 /*0.2f Q15*/, dist_min ) ); /* x2.56 */
467 :
468 2669 : mem[0] = dist; /* x2.56 */
469 2669 : move16();
470 :
471 :
472 2669 : return;
473 : }
474 :
475 174472 : void gp_clip_test_lsf_ivas_fx(
476 : const Word16 element_mode, /* i : element mode Q0*/
477 : const Word32 core_brate, /* i : core bitrate Q0*/
478 : const Word16 lsf[], /* i : LSF vector 14Q1*1.28*/
479 : Word16 mem[], /* i/o: memory of gain of pitch clipping algorithm [2.56x,Q14,Q8,Q0,Q14,Q14]*/
480 : const Word16 Opt_AMR_WB /* i : flag indicating AMR-WB IO mode Q0*/
481 : )
482 : {
483 : Word16 i;
484 : Word16 m;
485 : Word16 dist, dist_min;
486 :
487 174472 : dist_min = sub( lsf[1], lsf[0] ); /* 14Q1*1.28 */
488 :
489 174472 : IF( Opt_AMR_WB )
490 : {
491 0 : m = M - 1;
492 0 : move16();
493 : }
494 : ELSE
495 : {
496 174472 : m = M;
497 174472 : move16();
498 : }
499 :
500 2617080 : FOR( i = 2; i < m; i++ )
501 : {
502 2442608 : dist = sub( lsf[i], lsf[i - 1] ); /* 14Q1*1.28 */
503 2442608 : dist_min = s_min( dist, dist_min );
504 : }
505 :
506 : // dist = 0.8f * mem[0] + 0.2f * dist_min;
507 174472 : dist = mac_r( L_mult( 26214 /*0.8f Q15*/, mem[0] ), 6554 /*0.2f Q15*/, dist_min ); /* 2.56x */
508 :
509 174472 : test();
510 174472 : test();
511 174472 : IF( EQ_32( core_brate, ACELP_6k60 ) || EQ_32( core_brate, ACELP_8k85 ) || ( element_mode > EVS_MONO ) )
512 : {
513 174472 : if ( GT_16( dist, DIST_ISF_MAX_IO ) )
514 : {
515 74076 : dist = DIST_ISF_MAX_IO;
516 74076 : move16();
517 : }
518 : }
519 0 : ELSE IF( GT_16( dist, DIST_ISF_MAX ) )
520 : {
521 0 : dist = DIST_ISF_MAX;
522 0 : move16();
523 : }
524 :
525 174472 : mem[0] = dist; /* 2.56x */
526 174472 : move16();
527 :
528 174472 : return;
529 : }
|