Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

716 lines
16 KiB

  1. //
  2. // ITU-T G.723 Floating Point Speech Coder ANSI C Source Code. Version 1.00
  3. // copyright (c) 1995, AudioCodes, DSP Group, France Telecom,
  4. // Universite de Sherbrooke, Intel Corporation. All rights reserved.
  5. //
  6. #include <stdio.h>
  7. #include <math.h>
  8. #include "opt.h"
  9. #include "typedef.h"
  10. #include "cst_lbc.h"
  11. #include "tab_lbc.h"
  12. #include "util_lbc.h"
  13. #include "lsp.h"
  14. #include "timer.h"
  15. #include "mmxutil.h"
  16. #if COMPILE_MMX
  17. // This file includes all the Lsp related functions
  18. //--------------------------------------------------------------
  19. int mult(short x, short y)
  20. {
  21. return ( ((int)x)*((int)y) >> 16 );
  22. }
  23. //--------------------------------------------------------------
  24. int LspSearchInt(short *Lspw, short *LspTab)
  25. {
  26. #if ASM_SVQ
  27. int mem8000[2] = {0x80008000,0x80008000}, zero[2] = {0,0};
  28. short maxes[4],mx;
  29. int retu;
  30. int *ptr,tmp,t,i,k;
  31. #define lsp esi
  32. #define tab edi
  33. #define idx edx
  34. #define pidx eax // packed index: n+3 n+2 n+1 n
  35. #define maxi ecx
  36. #define r0 mm0
  37. #define r1 mm1
  38. #define r2 mm2
  39. #define r3 mm3
  40. #define r4 mm4
  41. #define max mm5
  42. // Expand Lspw table so it's 0000 1111 2222 3333 4444 5555 6666 7777
  43. ptr = (int *)Lspw;
  44. k = 14;
  45. for (i=7; i>=0; i--)
  46. {
  47. t = Lspw[i]; t = t & 0xffff;
  48. tmp = t;
  49. tmp = (tmp << 16) | t;
  50. ptr[k] = ptr[k+1] = tmp;
  51. k -= 2;
  52. }
  53. // Need LspTab to be ordered 0 4 8 12 1 5 9 13 etc.
  54. // so that lo word of each qword sees 0123, next sees 4567, etc.
  55. //
  56. // 'idx' counts iterations, so it goes 0 to 256 in steps of 4.
  57. // The 4 LspTab sets at any given time are 8*idx, 8*idx+8, +16, +24
  58. // Lspw[n] is lsp+8*n, as defined below
  59. #define a(n) [tab+8*idx+8*n]
  60. #define b(n) [lsp+8*n]
  61. ASM
  62. {
  63. push lsp;
  64. push tab;
  65. push idx;
  66. push pidx;
  67. push maxi;
  68. mov lsp,Lspw;
  69. mov tab,LspTab;
  70. xor idx,idx;
  71. xor maxi,maxi;
  72. mov pidx,003020100h;
  73. movq max,mem8000;
  74. /*
  75. The code below is interleaved with k=1.
  76. The structure is: four levels of indentation, one for each of the
  77. 4 terms of the sum. The instructions completely left-justified
  78. are the part of the loop that's wrapped around on itself.
  79. Note that the code reads 8 bytes past the end of the LspTab that's
  80. passed to it. This is made o.k. by making the table that's passed
  81. to it have 8 dummy bytes at the end.
  82. */
  83. // Start up the pipeline
  84. movq r0,a(0);
  85. movq r1,r0;
  86. pmulhw r0,b(4);
  87. psubsw r1,b(0);
  88. movq r2,a(1);
  89. movq r3,r2;
  90. psllw r0,2;
  91. pmulhw r0,r1;
  92. pmulhw r2,b(5);
  93. psubsw r3,b(1);
  94. movq r1,a(2);
  95. psllw r2,2;
  96. pmulhw r2,r3;
  97. movq r3,r1;
  98. pmulhw r1,b(6);
  99. psubsw r3,b(2);
  100. paddw r0,r2;
  101. movq r2,a(3);
  102. psllw r1,2;
  103. pmulhw r1,r3;
  104. movq r3,r2;
  105. pmulhw r2,b(7);
  106. psubsw r3,b(3);
  107. paddw r1,r0;
  108. loop1:
  109. movq r0,a(4);
  110. movq r4,r1; // save accum so not wiped out by first half of loop
  111. psllw r2,2;
  112. movq r1,r0;
  113. pmulhw r2,r3;
  114. pmulhw r0,b(4);
  115. psubsw r1,b(0);
  116. paddw r4,r2; // now final answer is in r4
  117. movq r2,a(5);
  118. paddw r4,mem8000 // make final sum unsigned
  119. movq r3,r2; // 0123
  120. psllw r0,2;
  121. psubusw max,r4 // start to compute max
  122. pmulhw r0,r1; // 0.23
  123. pmulhw r2,b(5);
  124. paddw max,r4 // max now done
  125. psubsw r3,b(1);
  126. pcmpeqw r4,max // now 1111's means a new max was found
  127. movq r1,a(6); // 0123
  128. packsswb r4,r4; // put all fields in low 32 bits
  129. psllw r2,2;
  130. movd ebx,r4;
  131. pmulhw r2,r3; // 012.
  132. xor ebx,0ffffffffh; // invert mask
  133. and maxi,ebx; // get old index to keep
  134. movq r3,r1; // 0123
  135. pmulhw r1,b(6);
  136. psubsw r3,b(2);
  137. xor ebx,0ffffffffh; // invert mask
  138. paddw r0,r2; // 01.3
  139. and ebx,pidx; // get new index
  140. psllw r1,2;
  141. movq r2,a(7);// 0123
  142. pmulhw r1,r3; // 012.
  143. movq r3,r2; // 0123
  144. or maxi,ebx; // now maxi is done
  145. pmulhw r2,b(7);
  146. psubsw r3,b(3);
  147. paddw r1,r0; // .123
  148. add idx,4;
  149. add pidx,004040404h;
  150. cmp idx,256;
  151. jl loop1;
  152. psubw max,mem8000;
  153. mov retu,maxi;
  154. movq maxes,max;
  155. pop maxi;
  156. pop pidx;
  157. pop idx;
  158. pop tab;
  159. pop lsp;
  160. }
  161. // find which of the 4 maxes is the max, and return the appropriate
  162. // one of the 4 maxindices.
  163. mx = maxes[0]; t = 0;
  164. if (maxes[1] >= mx) { mx = maxes[1]; t = 8; }
  165. if (maxes[2] >= mx) { mx = maxes[2]; t = 16; }
  166. if (maxes[3] >= mx) { mx = maxes[3]; t = 24; }
  167. ASM emms;
  168. retu = (retu >> t) & 0xff;
  169. return(retu);
  170. #undef a
  171. #undef b
  172. #undef idx
  173. #undef lsp
  174. #undef tab
  175. #undef max
  176. #undef maxi
  177. #else // if assembly code not selected, use C code
  178. int Indx[4],i,s,ret;
  179. short Max[4],Err,mx;
  180. short m0,m1,m2,m3,m4,m5,m6,m7,t;
  181. for (i=0; i<4; i++)
  182. {
  183. Max[i] = Indx[i] = 0;
  184. }
  185. for (i=0; i < LspCbSize; i++)
  186. {
  187. s = (i&3);
  188. m0 = mult(Lspw[4],LspTab[s+0]);
  189. t = LspTab[s+0]-Lspw[0]; m1 = mult(t,m0<<2);
  190. m2 = mult(Lspw[5],LspTab[s+4]);
  191. t = LspTab[s+4]-Lspw[1]; m3 = mult(t,m2<<2);
  192. m4 = mult(Lspw[6],LspTab[s+8]);
  193. t = LspTab[s+8]-Lspw[2]; m5 = mult(t,m4<<2);
  194. m6 = mult(Lspw[7],LspTab[s+12]);
  195. t = LspTab[s+12]-Lspw[3]; m7 = mult(t,m6<<2);
  196. Err = m1+m3+m5+m7;
  197. if (Err >= Max[s])
  198. {
  199. Max[s] = Err;
  200. Indx[s] = i;
  201. }
  202. if (s==3)
  203. LspTab += 16;
  204. }
  205. mx = Max[0]; ret = Indx[0];
  206. if (Max[1] >= mx) { mx = Max[1]; ret = Indx[1]; }
  207. if (Max[2] >= mx) { mx = Max[2]; ret = Indx[2]; }
  208. if (Max[3] >= mx) { mx = Max[3]; ret = Indx[3]; }
  209. return(ret);
  210. #endif
  211. }
  212. //--------------------------------------------------------------
  213. Word32 Svq_Int(float *Lsp, float *Wvect)
  214. {
  215. #define LSP_SCALE 256
  216. int i;
  217. Word32 Rez;
  218. int z;
  219. short Wint[LpcOrder],LspTemp[LpcOrder];
  220. DECLARE_SHORT(Lspw,32);
  221. ALIGN_ARRAY(Lspw);
  222. for (i=0; i<LpcOrder; i++)
  223. {
  224. z = (int)(LSP_SCALE*2*Lsp[i]);
  225. if (z > 32767) LspTemp[i] = 32767;
  226. else if (z < -32768) LspTemp[i] = -32768;
  227. else LspTemp[i] = z;
  228. }
  229. FloatToShortScaled(Wvect,Wint,10,0);
  230. Rez = (Word32) 0;
  231. // For each of the 3 bands
  232. Lspw[0] = LspTemp[0]; Lspw[1] = LspTemp[1]; Lspw[2] = LspTemp[2];
  233. Lspw[3] = 0;
  234. Lspw[4] = -Wint[0]; Lspw[5] = -Wint[1]; Lspw[6] = -Wint[2];
  235. Lspw[7] = 0;
  236. Rez = LspSearchInt(Lspw,LspTableInt);
  237. Lspw[0] = LspTemp[3]; Lspw[1] = LspTemp[4]; Lspw[2] = LspTemp[5];
  238. Lspw[3] = 0;
  239. Lspw[4] = -Wint[3]; Lspw[5] = -Wint[4]; Lspw[6] = -Wint[5];
  240. Lspw[7] = 0;
  241. Rez = (Rez<<8) + LspSearchInt(Lspw,&LspTableInt[1024]);
  242. Lspw[0] = LspTemp[6]; Lspw[1] = LspTemp[7]; Lspw[2] = LspTemp[8];
  243. Lspw[3] = LspTemp[9];
  244. Lspw[4] = -Wint[6]; Lspw[5] = -Wint[7]; Lspw[6] = -Wint[8];
  245. Lspw[7] = -Wint[9];
  246. Rez = (Rez<<8) + LspSearchInt(Lspw,&LspTableInt[2048]);
  247. return Rez;
  248. }
  249. #endif
  250. //---------------------------------------------------------------
  251. float Polynomial(float *Lpq, int CosPtr)
  252. {
  253. return(Lpq[LpcOrder]*CosineTable[0] +
  254. Lpq[LpcOrder-2]*CosineTable[CosPtr] +
  255. Lpq[LpcOrder-4]*CosineTable[(CosPtr*2)&(CosineTableSize-1)] +
  256. Lpq[LpcOrder-6]*CosineTable[(CosPtr*3)&(CosineTableSize-1)] +
  257. Lpq[LpcOrder-8]*CosineTable[(CosPtr*4)&(CosineTableSize-1)] +
  258. Lpq[LpcOrder-10]*CosineTable[(CosPtr*5)&(CosineTableSize-1)]);
  259. }
  260. //--------------------------------------------------------------
  261. void AtoLsp(float *LspVect, float *Lpc, float *PrevLsp)
  262. {
  263. int i,j,k;
  264. int LspCnt;
  265. float Lpq[LpcOrder+2];
  266. float PrevVal,CurrVal,AbsPrev,AbsCurr;
  267. // Small additional bandwidth expansion
  268. for (i=0; i < LpcOrder; i++)
  269. LspVect[i] = Lpc[i]*BandExpTable[i];
  270. // Compute Lp and Lq
  271. Lpq[0] = Lpq[1] = 1.0f;
  272. for (i=0; i < LpcOrder/2; i++)
  273. {
  274. Lpq[2*i+2] = -Lpq[2*i+0] - LspVect[i] - LspVect[LpcOrder-1-i];
  275. Lpq[2*i+3] = Lpq[2*i+1] - LspVect[i] + LspVect[LpcOrder-1-i];
  276. }
  277. Lpq[LpcOrder+0] *= 0.5f;
  278. Lpq[LpcOrder+1] *= 0.5f;
  279. // Do first evaluation
  280. k = 0;
  281. LspCnt = 0;
  282. PrevVal = Polynomial(Lpq,0);
  283. for (i=1; i < CosineTableSize/2; i++)
  284. {
  285. // Evaluate the polynomial
  286. CurrVal = Polynomial(&Lpq[k],i);
  287. // Test for sign change
  288. if ((asint(CurrVal) ^ asint(PrevVal)) < 0)
  289. {
  290. AbsPrev = (float)fabs(PrevVal);
  291. AbsCurr = (float)fabs(CurrVal);
  292. LspVect[LspCnt++] = (i-1 + AbsPrev/(AbsPrev+AbsCurr));
  293. // Check if all found
  294. if (LspCnt == LpcOrder)
  295. break;
  296. // Switch the pointer, evaluate again
  297. k ^= 1;
  298. CurrVal = Polynomial(&Lpq[k],i);
  299. }
  300. PrevVal = CurrVal;
  301. }
  302. // Check if all Lsp found
  303. if (LspCnt != LpcOrder)
  304. {
  305. for (j=0; j < LpcOrder; j++)
  306. LspVect[j] = PrevLsp[j];
  307. }
  308. return;
  309. }
  310. //--------------------------------------------------------------
  311. Word32 Lsp_Qnt(float *CurrLsp, float *PrevLsp, int UseMMX)
  312. {
  313. int i;
  314. float Wvect[LpcOrder];
  315. float Min,Tmp;
  316. // Compute the weighting vector
  317. Wvect[0] = 1.0f/(CurrLsp[1] - CurrLsp[0]);
  318. Wvect[LpcOrder-1] = 1.0f/(CurrLsp[LpcOrder-1] - CurrLsp[LpcOrder-2]);
  319. for (i=1; i < LpcOrder-1; i++)
  320. {
  321. Min = CurrLsp[i+1] - CurrLsp[i];
  322. Tmp = CurrLsp[i] - CurrLsp[i-1];
  323. if (Tmp < Min)
  324. Min = Tmp;
  325. if (Min > 0.0f)
  326. Wvect[i] = 1.0f/Min;
  327. else
  328. Wvect[i] = 1.0f;
  329. }
  330. // Generate predicted vector as (DC-removed-Curr) - b*(DC-removed-Prev)
  331. CurrLsp[0] = (CurrLsp[0] - LspDcTable[0]) -
  332. LspPred0*(PrevLsp[0] - LspDcTable[0]);
  333. CurrLsp[1] = (CurrLsp[1] - LspDcTable[1]) -
  334. LspPred0*(PrevLsp[1] - LspDcTable[1]);
  335. CurrLsp[2] = (CurrLsp[2] - LspDcTable[2]) -
  336. LspPred0*(PrevLsp[2] - LspDcTable[2]);
  337. CurrLsp[3] = (CurrLsp[3] - LspDcTable[3]) -
  338. LspPred0*(PrevLsp[3] - LspDcTable[3]);
  339. CurrLsp[4] = (CurrLsp[4] - LspDcTable[4]) -
  340. LspPred0*(PrevLsp[4] - LspDcTable[4]);
  341. CurrLsp[5] = (CurrLsp[5] - LspDcTable[5]) -
  342. LspPred0*(PrevLsp[5] - LspDcTable[5]);
  343. CurrLsp[6] = (CurrLsp[6] - LspDcTable[6]) -
  344. LspPred0*(PrevLsp[6] - LspDcTable[6]);
  345. CurrLsp[7] = (CurrLsp[7] - LspDcTable[7]) -
  346. LspPred0*(PrevLsp[7] - LspDcTable[7]);
  347. CurrLsp[8] = (CurrLsp[8] - LspDcTable[8]) -
  348. LspPred0*(PrevLsp[8] - LspDcTable[8]);
  349. CurrLsp[9] = (CurrLsp[9] - LspDcTable[9]) -
  350. LspPred0*(PrevLsp[9] - LspDcTable[9]);
  351. // Do the SVQ
  352. #if COMPILE_MMX
  353. if (UseMMX)
  354. return Svq_Int(CurrLsp, Wvect);
  355. else
  356. #endif
  357. return Lsp_Svq(CurrLsp, Wvect);
  358. }
  359. //--------------------------------------------------------------
  360. Word32 Lsp_Svq(float *Lsp, float *Wvect)
  361. {
  362. int i,k;
  363. Word32 Rez;
  364. int Indx,Start,Dim;
  365. float *LspQntPnt;
  366. float Max,Err,lsp0,lsp1,lsp2,lsp3,w0,w1,w2,w3;
  367. float LspTemp[LpcOrder];
  368. for (i=0; i<LpcOrder; i++)
  369. LspTemp[i] = 2.0f*Lsp[i];
  370. Rez = (Word32) 0;
  371. // For each of the 3 bands
  372. for (k=0; k < LspQntBands; k++)
  373. {
  374. // Initialize the search
  375. Max = 0.0f; //-1.0f;
  376. Indx = 0;
  377. LspQntPnt = BandQntTable[k];
  378. Start = BandInfoTable[k][0];
  379. Dim = BandInfoTable[k][1];
  380. lsp0 = LspTemp[Start+0];
  381. lsp1 = LspTemp[Start+1];
  382. lsp2 = LspTemp[Start+2];
  383. w0 = Wvect[Start+0];
  384. w1 = Wvect[Start+1];
  385. w2 = Wvect[Start+2];
  386. if (k < 2)
  387. {
  388. for (i=0; i < LspCbSize; i++)
  389. {
  390. Err = (lsp0 - LspQntPnt[0])*w0*LspQntPnt[0] +
  391. (lsp1 - LspQntPnt[1])*w1*LspQntPnt[1] +
  392. (lsp2 - LspQntPnt[2])*w2*LspQntPnt[2];
  393. LspQntPnt += 3;
  394. if (asint(Err) > asint(Max))
  395. {
  396. Max = Err;
  397. Indx = i;
  398. }
  399. }
  400. }
  401. else
  402. {
  403. lsp3 = LspTemp[Start+3];
  404. w3 = Wvect[Start+3];
  405. for (i=0; i < LspCbSize; i++)
  406. {
  407. Err = (lsp0 - LspQntPnt[0])*w0*LspQntPnt[0] +
  408. (lsp1 - LspQntPnt[1])*w1*LspQntPnt[1] +
  409. (lsp2 - LspQntPnt[2])*w2*LspQntPnt[2] +
  410. (lsp3 - LspQntPnt[3])*w3*LspQntPnt[3];
  411. LspQntPnt += 4;
  412. if (asint(Err) > asint(Max))
  413. {
  414. Max = Err;
  415. Indx = i;
  416. }
  417. }
  418. }
  419. Rez = (Rez << 8) | Indx;
  420. }
  421. return Rez;
  422. }
  423. //--------------------------------------------------------------
  424. Flag Lsp_Inq(float *Lsp, float *PrevLsp, Word32 LspId, int Crc)
  425. {
  426. int i,j;
  427. float *LspQntPnt;
  428. float Lprd,Scon,Tmpf,Scon2;
  429. int Tmp;
  430. Flag Test;
  431. if (Crc == 0)
  432. {
  433. Scon = 2.0f;
  434. Lprd = LspPred0;
  435. }
  436. else
  437. {
  438. LspId = (Word32) 0;
  439. Scon = 4.0f;
  440. Lprd = LspPred1;
  441. }
  442. Scon2 = Scon - 0.03125f;
  443. // Reconstruct the LSP vector
  444. for (i=LspQntBands-1; i >= 0; i--)
  445. {
  446. Tmp = LspId & (Word32) 0x000000ff;
  447. LspId >>= 8;
  448. LspQntPnt = BandQntTable[i];
  449. for (j=0; j < BandInfoTable[i][1]; j++)
  450. Lsp[BandInfoTable[i][0] + j] = LspQntPnt[Tmp*BandInfoTable[i][1] + j];
  451. }
  452. // Add predicted vector and DC to decoded vector
  453. for (j=0; j < LpcOrder; j++)
  454. Lsp[j] = Lsp[j] + (PrevLsp[j] - LspDcTable[j])*Lprd + LspDcTable[j];
  455. // Perform the stability check
  456. for (i=0; i < LpcOrder; i++)
  457. {
  458. // Test the first and last one
  459. if (Lsp[0] < 3.0)
  460. Lsp[0] = 3.0f;
  461. if (Lsp[LpcOrder-1] > 252.0f)
  462. Lsp[LpcOrder-1] = 252.0f;
  463. // Test the others
  464. for (j=1; j < LpcOrder; j++)
  465. {
  466. Tmpf = Scon + Lsp[j-1] - Lsp[j];
  467. if (Tmpf > 0)
  468. {
  469. Tmpf *= 0.5f;
  470. Lsp[j-1] -= Tmpf;
  471. Lsp[j] += Tmpf;
  472. }
  473. }
  474. // Test if stable
  475. Test = False;
  476. for (j=1; j < LpcOrder; j++)
  477. if ((Lsp[j] - Lsp[j-1]) < Scon2)
  478. Test = True;
  479. if (Test == False)
  480. break;
  481. }
  482. if (Test == True)
  483. for (j=0; j < LpcOrder; j++)
  484. Lsp[j] = PrevLsp[j];
  485. return Test;
  486. }
  487. //--------------------------------------------------------------
  488. void Lsp_Int(float *QntLpc, float *CurrLsp, float *PrevLsp)
  489. {
  490. int i,j;
  491. float *Dpnt;
  492. float Fac[4] = {0.25f, 0.5f, 0.75f, 1.0f};
  493. Dpnt = QntLpc;
  494. for (i=0; i < SubFrames; i++)
  495. {
  496. // Interpolate
  497. for (j=0; j < LpcOrder; j++)
  498. Dpnt[j] = (1.0f - Fac[i])*PrevLsp[j] + Fac[i]*CurrLsp[j];
  499. // Convert to Lpc
  500. LsptoA(Dpnt);
  501. Dpnt += LpcOrder;
  502. }
  503. // Copy the Lsp vector
  504. for (i=0; i < LpcOrder; i++)
  505. PrevLsp[i] = CurrLsp[i];
  506. }
  507. //--------------------------------------------------------------
  508. void LsptoA(float *Lsp)
  509. {
  510. int i,j;
  511. float P[LpcOrder/2+1];
  512. float Q[LpcOrder/2+1];
  513. float Fac[(LpcOrder/2)-2] = {1.0f,0.5f,0.25f};
  514. // Convert Lsp's to cosines
  515. for (i=0; i < LpcOrder; i++)
  516. {
  517. j = MyFloor(Lsp[i]);
  518. Lsp[i] = -(CosineTable[j] +
  519. (CosineTable[j+1]-CosineTable[j])*(Lsp[i]-j));
  520. }
  521. // Init P and Q. Note that P,Q * 2^26 correspond to fixed-point code
  522. P[0] = 0.5f;
  523. P[1] = Lsp[0] + Lsp[2];
  524. P[2] = 1.0f + 2.0f*Lsp[0]*Lsp[2];
  525. Q[0] = 0.5f;
  526. Q[1] = Lsp[1] + Lsp[3];
  527. Q[2] = 1.0f + 2.0f*Lsp[1]*Lsp[3];
  528. // Compute all the others
  529. for (i=2; i < LpcOrder/2; i++)
  530. {
  531. P[i+1] = P[i-1] + P[i]*Lsp[2*i+0];
  532. Q[i+1] = Q[i-1] + Q[i]*Lsp[2*i+1];
  533. // All update
  534. for (j=i; j >= 2; j--)
  535. {
  536. P[j] = P[j-1]*Lsp[2*i+0] + 0.5f*(P[j]+P[j-2]);
  537. Q[j] = Q[j-1]*Lsp[2*i+1] + 0.5f*(Q[j]+Q[j-2]);
  538. }
  539. // Update PQ[01]
  540. P[0] = P[0]*0.5f;
  541. Q[0] = Q[0]*0.5f;
  542. P[1] = (P[1] + Lsp[2*i+0]*Fac[i-2])*0.5f;
  543. Q[1] = (Q[1] + Lsp[2*i+1]*Fac[i-2])*0.5f;
  544. }
  545. // Convert to Lpc
  546. for (i=0; i < LpcOrder/2; i++)
  547. {
  548. Lsp[i] = (-P[i] - P[i+1] + Q[i] - Q[i+1])*8.0f;
  549. Lsp[LpcOrder-1-i] = (-P[i] - P[i+1] - Q[i] + Q[i+1])*8.0f;
  550. }
  551. }