Line  | Count  | Source (jump to first uncovered line)  | 
1  |  | /********************************************************************  | 
2  |  |  *                                                                  *  | 
3  |  |  * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *  | 
4  |  |  * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *  | 
5  |  |  * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *  | 
6  |  |  * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *  | 
7  |  |  *                                                                  *  | 
8  |  |  * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009             *  | 
9  |  |  * by the Xiph.Org Foundation https://xiph.org/                     *  | 
10  |  |  *                                                                  *  | 
11  |  |  ********************************************************************  | 
12  |  |  | 
13  |  |   function: LSP (also called LSF) conversion routines  | 
14  |  |  | 
15  |  |   The LSP generation code is taken (with minimal modification and a  | 
16  |  |   few bugfixes) from "On the Computation of the LSP Frequencies" by  | 
17  |  |   Joseph Rothweiler (see http://www.rothweiler.us for contact info).  | 
18  |  |  | 
19  |  |   The paper is available at:  | 
20  |  |  | 
21  |  |   https://web.archive.org/web/20110810174000/http://home.myfairpoint.net/vzenxj75/myown1/joe/lsf/index.html  | 
22  |  |  | 
23  |  |  ********************************************************************/  | 
24  |  |  | 
25  |  | /* Note that the lpc-lsp conversion finds the roots of polynomial with  | 
26  |  |    an iterative root polisher (CACM algorithm 283).  It *is* possible  | 
27  |  |    to confuse this algorithm into not converging; that should only  | 
28  |  |    happen with absurdly closely spaced roots (very sharp peaks in the  | 
29  |  |    LPC f response) which in turn should be impossible in our use of  | 
30  |  |    the code.  If this *does* happen anyway, it's a bug in the floor  | 
31  |  |    finder; find the cause of the confusion (probably a single bin  | 
32  |  |    spike or accidental near-float-limit resolution problems) and  | 
33  |  |    correct it. */  | 
34  |  |  | 
35  |  | #include <math.h>  | 
36  |  | #include <string.h>  | 
37  |  | #include <stdlib.h>  | 
38  |  | #include "lsp.h"  | 
39  |  | #include "os.h"  | 
40  |  | #include "misc.h"  | 
41  |  | #include "lookup.h"  | 
42  |  | #include "scales.h"  | 
43  |  |  | 
44  |  | /* three possible LSP to f curve functions; the exact computation  | 
45  |  |    (float), a lookup based float implementation, and an integer  | 
46  |  |    implementation.  The float lookup is likely the optimal choice on  | 
47  |  |    any machine with an FPU.  The integer implementation is *not* fixed  | 
48  |  |    point (due to the need for a large dynamic range and thus a  | 
49  |  |    separately tracked exponent) and thus much more complex than the  | 
50  |  |    relatively simple float implementations. It's mostly for future  | 
51  |  |    work on a fully fixed point implementation for processors like the  | 
52  |  |    ARM family. */  | 
53  |  |  | 
54  |  | /* define either of these (preferably FLOAT_LOOKUP) to have faster  | 
55  |  |    but less precise implementation. */  | 
56  |  | #undef FLOAT_LOOKUP  | 
57  |  | #undef INT_LOOKUP  | 
58  |  |  | 
59  |  | #ifdef FLOAT_LOOKUP  | 
60  |  | #include "lookup.c" /* catch this in the build system; we #include for  | 
61  |  |                        compilers (like gcc) that can't inline across  | 
62  |  |                        modules */  | 
63  |  |  | 
64  |  | /* side effect: changes *lsp to cosines of lsp */  | 
65  |  | void vorbis_lsp_to_curve(float *curve,int *map,int n,int ln,float *lsp,int m,  | 
66  |  |                             float amp,float ampoffset){ | 
67  |  |   int i;  | 
68  |  |   float wdel=M_PI/ln;  | 
69  |  |   vorbis_fpu_control fpu;  | 
70  |  |  | 
71  |  |   vorbis_fpu_setround(&fpu);  | 
72  |  |   for(i=0;i<m;i++)lsp[i]=vorbis_coslook(lsp[i]);  | 
73  |  |  | 
74  |  |   i=0;  | 
75  |  |   while(i<n){ | 
76  |  |     int k=map[i];  | 
77  |  |     int qexp;  | 
78  |  |     float p=.7071067812f;  | 
79  |  |     float q=.7071067812f;  | 
80  |  |     float w=vorbis_coslook(wdel*k);  | 
81  |  |     float *ftmp=lsp;  | 
82  |  |     int c=m>>1;  | 
83  |  |  | 
84  |  |     while(c--){ | 
85  |  |       q*=ftmp[0]-w;  | 
86  |  |       p*=ftmp[1]-w;  | 
87  |  |       ftmp+=2;  | 
88  |  |     }  | 
89  |  |  | 
90  |  |     if(m&1){ | 
91  |  |       /* odd order filter; slightly assymetric */  | 
92  |  |       /* the last coefficient */  | 
93  |  |       q*=ftmp[0]-w;  | 
94  |  |       q*=q;  | 
95  |  |       p*=p*(1.f-w*w);  | 
96  |  |     }else{ | 
97  |  |       /* even order filter; still symmetric */  | 
98  |  |       q*=q*(1.f+w);  | 
99  |  |       p*=p*(1.f-w);  | 
100  |  |     }  | 
101  |  |  | 
102  |  |     q=frexp(p+q,&qexp);  | 
103  |  |     q=vorbis_fromdBlook(amp*  | 
104  |  |                         vorbis_invsqlook(q)*  | 
105  |  |                         vorbis_invsq2explook(qexp+m)-  | 
106  |  |                         ampoffset);  | 
107  |  |  | 
108  |  |     do{ | 
109  |  |       curve[i++]*=q;  | 
110  |  |     }while(map[i]==k);  | 
111  |  |   }  | 
112  |  |   vorbis_fpu_restore(fpu);  | 
113  |  | }  | 
114  |  |  | 
115  |  | #else  | 
116  |  |  | 
117  |  | #ifdef INT_LOOKUP  | 
118  |  | #include "lookup.c" /* catch this in the build system; we #include for  | 
119  |  |                        compilers (like gcc) that can't inline across  | 
120  |  |                        modules */  | 
121  |  |  | 
122  |  | static const int MLOOP_1[64]={ | 
123  |  |    0,10,11,11, 12,12,12,12, 13,13,13,13, 13,13,13,13,  | 
124  |  |   14,14,14,14, 14,14,14,14, 14,14,14,14, 14,14,14,14,  | 
125  |  |   15,15,15,15, 15,15,15,15, 15,15,15,15, 15,15,15,15,  | 
126  |  |   15,15,15,15, 15,15,15,15, 15,15,15,15, 15,15,15,15,  | 
127  |  | };  | 
128  |  |  | 
129  |  | static const int MLOOP_2[64]={ | 
130  |  |   0,4,5,5, 6,6,6,6, 7,7,7,7, 7,7,7,7,  | 
131  |  |   8,8,8,8, 8,8,8,8, 8,8,8,8, 8,8,8,8,  | 
132  |  |   9,9,9,9, 9,9,9,9, 9,9,9,9, 9,9,9,9,  | 
133  |  |   9,9,9,9, 9,9,9,9, 9,9,9,9, 9,9,9,9,  | 
134  |  | };  | 
135  |  |  | 
136  |  | static const int MLOOP_3[8]={0,1,2,2,3,3,3,3}; | 
137  |  |  | 
138  |  |  | 
139  |  | /* side effect: changes *lsp to cosines of lsp */  | 
140  |  | void vorbis_lsp_to_curve(float *curve,int *map,int n,int ln,float *lsp,int m,  | 
141  |  |                             float amp,float ampoffset){ | 
142  |  |  | 
143  |  |   /* 0 <= m < 256 */  | 
144  |  |  | 
145  |  |   /* set up for using all int later */  | 
146  |  |   int i;  | 
147  |  |   int ampoffseti=rint(ampoffset*4096.f);  | 
148  |  |   int ampi=rint(amp*16.f);  | 
149  |  |   long *ilsp=alloca(m*sizeof(*ilsp));  | 
150  |  |   for(i=0;i<m;i++)ilsp[i]=vorbis_coslook_i(lsp[i]/M_PI*65536.f+.5f);  | 
151  |  |  | 
152  |  |   i=0;  | 
153  |  |   while(i<n){ | 
154  |  |     int j,k=map[i];  | 
155  |  |     unsigned long pi=46341; /* 2**-.5 in 0.16 */  | 
156  |  |     unsigned long qi=46341;  | 
157  |  |     int qexp=0,shift;  | 
158  |  |     long wi=vorbis_coslook_i(k*65536/ln);  | 
159  |  |  | 
160  |  |     qi*=labs(ilsp[0]-wi);  | 
161  |  |     pi*=labs(ilsp[1]-wi);  | 
162  |  |  | 
163  |  |     for(j=3;j<m;j+=2){ | 
164  |  |       if(!(shift=MLOOP_1[(pi|qi)>>25]))  | 
165  |  |         if(!(shift=MLOOP_2[(pi|qi)>>19]))  | 
166  |  |           shift=MLOOP_3[(pi|qi)>>16];  | 
167  |  |       qi=(qi>>shift)*labs(ilsp[j-1]-wi);  | 
168  |  |       pi=(pi>>shift)*labs(ilsp[j]-wi);  | 
169  |  |       qexp+=shift;  | 
170  |  |     }  | 
171  |  |     if(!(shift=MLOOP_1[(pi|qi)>>25]))  | 
172  |  |       if(!(shift=MLOOP_2[(pi|qi)>>19]))  | 
173  |  |         shift=MLOOP_3[(pi|qi)>>16];  | 
174  |  |  | 
175  |  |     /* pi,qi normalized collectively, both tracked using qexp */  | 
176  |  |  | 
177  |  |     if(m&1){ | 
178  |  |       /* odd order filter; slightly assymetric */  | 
179  |  |       /* the last coefficient */  | 
180  |  |       qi=(qi>>shift)*labs(ilsp[j-1]-wi);  | 
181  |  |       pi=(pi>>shift)<<14;  | 
182  |  |       qexp+=shift;  | 
183  |  |  | 
184  |  |       if(!(shift=MLOOP_1[(pi|qi)>>25]))  | 
185  |  |         if(!(shift=MLOOP_2[(pi|qi)>>19]))  | 
186  |  |           shift=MLOOP_3[(pi|qi)>>16];  | 
187  |  |  | 
188  |  |       pi>>=shift;  | 
189  |  |       qi>>=shift;  | 
190  |  |       qexp+=shift-14*((m+1)>>1);  | 
191  |  |  | 
192  |  |       pi=((pi*pi)>>16);  | 
193  |  |       qi=((qi*qi)>>16);  | 
194  |  |       qexp=qexp*2+m;  | 
195  |  |  | 
196  |  |       pi*=(1<<14)-((wi*wi)>>14);  | 
197  |  |       qi+=pi>>14;  | 
198  |  |  | 
199  |  |     }else{ | 
200  |  |       /* even order filter; still symmetric */  | 
201  |  |  | 
202  |  |       /* p*=p(1-w), q*=q(1+w), let normalization drift because it isn't  | 
203  |  |          worth tracking step by step */  | 
204  |  |  | 
205  |  |       pi>>=shift;  | 
206  |  |       qi>>=shift;  | 
207  |  |       qexp+=shift-7*m;  | 
208  |  |  | 
209  |  |       pi=((pi*pi)>>16);  | 
210  |  |       qi=((qi*qi)>>16);  | 
211  |  |       qexp=qexp*2+m;  | 
212  |  |  | 
213  |  |       pi*=(1<<14)-wi;  | 
214  |  |       qi*=(1<<14)+wi;  | 
215  |  |       qi=(qi+pi)>>14;  | 
216  |  |  | 
217  |  |     }  | 
218  |  |  | 
219  |  |  | 
220  |  |     /* we've let the normalization drift because it wasn't important;  | 
221  |  |        however, for the lookup, things must be normalized again.  We  | 
222  |  |        need at most one right shift or a number of left shifts */  | 
223  |  |  | 
224  |  |     if(qi&0xffff0000){ /* checks for 1.xxxxxxxxxxxxxxxx */ | 
225  |  |       qi>>=1; qexp++;  | 
226  |  |     }else  | 
227  |  |       while(qi && !(qi&0x8000)){ /* checks for 0.0xxxxxxxxxxxxxxx or less*/ | 
228  |  |         qi<<=1; qexp--;  | 
229  |  |       }  | 
230  |  |  | 
231  |  |     amp=vorbis_fromdBlook_i(ampi*                     /*  n.4         */  | 
232  |  |                             vorbis_invsqlook_i(qi,qexp)-  | 
233  |  |                                                       /*  m.8, m+n<=8 */  | 
234  |  |                             ampoffseti);              /*  8.12[0]     */  | 
235  |  |  | 
236  |  |     curve[i]*=amp;  | 
237  |  |     while(map[++i]==k)curve[i]*=amp;  | 
238  |  |   }  | 
239  |  | }  | 
240  |  |  | 
241  |  | #else  | 
242  |  |  | 
243  |  | /* old, nonoptimized but simple version for any poor sap who needs to  | 
244  |  |    figure out what the hell this code does, or wants the other  | 
245  |  |    fraction of a dB precision */  | 
246  |  |  | 
247  |  | /* side effect: changes *lsp to cosines of lsp */  | 
248  |  | void vorbis_lsp_to_curve(float *curve,int *map,int n,int ln,float *lsp,int m,  | 
249  | 0  |                             float amp,float ampoffset){ | 
250  | 0  |   int i;  | 
251  | 0  |   float wdel=M_PI/ln;  | 
252  | 0  |   for(i=0;i<m;i++)lsp[i]=2.f*cos(lsp[i]);  | 
253  |  | 
  | 
254  | 0  |   i=0;  | 
255  | 0  |   while(i<n){ | 
256  | 0  |     int j,k=map[i];  | 
257  | 0  |     float p=.5f;  | 
258  | 0  |     float q=.5f;  | 
259  | 0  |     float w=2.f*cos(wdel*k);  | 
260  | 0  |     for(j=1;j<m;j+=2){ | 
261  | 0  |       q *= w-lsp[j-1];  | 
262  | 0  |       p *= w-lsp[j];  | 
263  | 0  |     }  | 
264  | 0  |     if(j==m){ | 
265  |  |       /* odd order filter; slightly assymetric */  | 
266  |  |       /* the last coefficient */  | 
267  | 0  |       q*=w-lsp[j-1];  | 
268  | 0  |       p*=p*(4.f-w*w);  | 
269  | 0  |       q*=q;  | 
270  | 0  |     }else{ | 
271  |  |       /* even order filter; still symmetric */  | 
272  | 0  |       p*=p*(2.f-w);  | 
273  | 0  |       q*=q*(2.f+w);  | 
274  | 0  |     }  | 
275  |  | 
  | 
276  | 0  |     q=fromdB(amp/sqrt(p+q)-ampoffset);  | 
277  |  | 
  | 
278  | 0  |     curve[i]*=q;  | 
279  | 0  |     while(map[++i]==k)curve[i]*=q;  | 
280  | 0  |   }  | 
281  | 0  | }  | 
282  |  |  | 
283  |  | #endif  | 
284  |  | #endif  | 
285  |  |  | 
286  | 0  | static void cheby(float *g, int ord) { | 
287  | 0  |   int i, j;  | 
288  |  | 
  | 
289  | 0  |   g[0] *= .5f;  | 
290  | 0  |   for(i=2; i<= ord; i++) { | 
291  | 0  |     for(j=ord; j >= i; j--) { | 
292  | 0  |       g[j-2] -= g[j];  | 
293  | 0  |       g[j] += g[j];  | 
294  | 0  |     }  | 
295  | 0  |   }  | 
296  | 0  | }  | 
297  |  |  | 
298  | 0  | static int comp(const void *a,const void *b){ | 
299  | 0  |   return (*(float *)a<*(float *)b)-(*(float *)a>*(float *)b);  | 
300  | 0  | }  | 
301  |  |  | 
302  |  | /* Newton-Raphson-Maehly actually functioned as a decent root finder,  | 
303  |  |    but there are root sets for which it gets into limit cycles  | 
304  |  |    (exacerbated by zero suppression) and fails.  We can't afford to  | 
305  |  |    fail, even if the failure is 1 in 100,000,000, so we now use  | 
306  |  |    Laguerre and later polish with Newton-Raphson (which can then  | 
307  |  |    afford to fail) */  | 
308  |  |  | 
309  | 0  | #define EPSILON 10e-7  | 
310  | 0  | static int Laguerre_With_Deflation(float *a,int ord,float *r){ | 
311  | 0  |   int i,m;  | 
312  | 0  |   double *defl=alloca(sizeof(*defl)*(ord+1));  | 
313  | 0  |   for(i=0;i<=ord;i++)defl[i]=a[i];  | 
314  |  | 
  | 
315  | 0  |   for(m=ord;m>0;m--){ | 
316  | 0  |     double new=0.f,delta;  | 
317  |  |  | 
318  |  |     /* iterate a root */  | 
319  | 0  |     while(1){ | 
320  | 0  |       double p=defl[m],pp=0.f,ppp=0.f,denom;  | 
321  |  |  | 
322  |  |       /* eval the polynomial and its first two derivatives */  | 
323  | 0  |       for(i=m;i>0;i--){ | 
324  | 0  |         ppp = new*ppp + pp;  | 
325  | 0  |         pp  = new*pp  + p;  | 
326  | 0  |         p   = new*p   + defl[i-1];  | 
327  | 0  |       }  | 
328  |  |  | 
329  |  |       /* Laguerre's method */  | 
330  | 0  |       denom=(m-1) * ((m-1)*pp*pp - m*p*ppp);  | 
331  | 0  |       if(denom<0)  | 
332  | 0  |         return(-1);  /* complex root!  The LPC generator handed us a bad filter */  | 
333  |  |  | 
334  | 0  |       if(pp>0){ | 
335  | 0  |         denom = pp + sqrt(denom);  | 
336  | 0  |         if(denom<EPSILON)denom=EPSILON;  | 
337  | 0  |       }else{ | 
338  | 0  |         denom = pp - sqrt(denom);  | 
339  | 0  |         if(denom>-(EPSILON))denom=-(EPSILON);  | 
340  | 0  |       }  | 
341  |  | 
  | 
342  | 0  |       delta  = m*p/denom;  | 
343  | 0  |       new   -= delta;  | 
344  |  | 
  | 
345  | 0  |       if(delta<0.f)delta*=-1;  | 
346  |  | 
  | 
347  | 0  |       if(fabs(delta/new)<10e-12)break;  | 
348  | 0  |     }  | 
349  |  |  | 
350  | 0  |     r[m-1]=new;  | 
351  |  |  | 
352  |  |     /* forward deflation */  | 
353  |  | 
  | 
354  | 0  |     for(i=m;i>0;i--)  | 
355  | 0  |       defl[i-1]+=new*defl[i];  | 
356  | 0  |     defl++;  | 
357  |  | 
  | 
358  | 0  |   }  | 
359  | 0  |   return(0);  | 
360  | 0  | }  | 
361  |  |  | 
362  |  |  | 
363  |  | /* for spit-and-polish only */  | 
364  | 0  | static int Newton_Raphson(float *a,int ord,float *r){ | 
365  | 0  |   int i, k, count=0;  | 
366  | 0  |   double error=1.f;  | 
367  | 0  |   double *root=alloca(ord*sizeof(*root));  | 
368  |  | 
  | 
369  | 0  |   for(i=0; i<ord;i++) root[i] = r[i];  | 
370  |  | 
  | 
371  | 0  |   while(error>1e-20){ | 
372  | 0  |     error=0;  | 
373  |  | 
  | 
374  | 0  |     for(i=0; i<ord; i++) { /* Update each point. */ | 
375  | 0  |       double pp=0.,delta;  | 
376  | 0  |       double rooti=root[i];  | 
377  | 0  |       double p=a[ord];  | 
378  | 0  |       for(k=ord-1; k>= 0; k--) { | 
379  |  | 
  | 
380  | 0  |         pp= pp* rooti + p;  | 
381  | 0  |         p = p * rooti + a[k];  | 
382  | 0  |       }  | 
383  |  | 
  | 
384  | 0  |       delta = p/pp;  | 
385  | 0  |       root[i] -= delta;  | 
386  | 0  |       error+= delta*delta;  | 
387  | 0  |     }  | 
388  |  | 
  | 
389  | 0  |     if(count>40)return(-1);  | 
390  |  |  | 
391  | 0  |     count++;  | 
392  | 0  |   }  | 
393  |  |  | 
394  |  |   /* Replaced the original bubble sort with a real sort.  With your  | 
395  |  |      help, we can eliminate the bubble sort in our lifetime. --Monty */  | 
396  |  |  | 
397  | 0  |   for(i=0; i<ord;i++) r[i] = root[i];  | 
398  | 0  |   return(0);  | 
399  | 0  | }  | 
400  |  |  | 
401  |  |  | 
402  |  | /* Convert lpc coefficients to lsp coefficients */  | 
403  | 0  | int vorbis_lpc_to_lsp(float *lpc,float *lsp,int m){ | 
404  | 0  |   int order2=(m+1)>>1;  | 
405  | 0  |   int g1_order,g2_order;  | 
406  | 0  |   float *g1=alloca(sizeof(*g1)*(order2+1));  | 
407  | 0  |   float *g2=alloca(sizeof(*g2)*(order2+1));  | 
408  | 0  |   float *g1r=alloca(sizeof(*g1r)*(order2+1));  | 
409  | 0  |   float *g2r=alloca(sizeof(*g2r)*(order2+1));  | 
410  | 0  |   int i;  | 
411  |  |  | 
412  |  |   /* even and odd are slightly different base cases */  | 
413  | 0  |   g1_order=(m+1)>>1;  | 
414  | 0  |   g2_order=(m)  >>1;  | 
415  |  |  | 
416  |  |   /* Compute the lengths of the x polynomials. */  | 
417  |  |   /* Compute the first half of K & R F1 & F2 polynomials. */  | 
418  |  |   /* Compute half of the symmetric and antisymmetric polynomials. */  | 
419  |  |   /* Remove the roots at +1 and -1. */  | 
420  |  | 
  | 
421  | 0  |   g1[g1_order] = 1.f;  | 
422  | 0  |   for(i=1;i<=g1_order;i++) g1[g1_order-i] = lpc[i-1]+lpc[m-i];  | 
423  | 0  |   g2[g2_order] = 1.f;  | 
424  | 0  |   for(i=1;i<=g2_order;i++) g2[g2_order-i] = lpc[i-1]-lpc[m-i];  | 
425  |  | 
  | 
426  | 0  |   if(g1_order>g2_order){ | 
427  | 0  |     for(i=2; i<=g2_order;i++) g2[g2_order-i] += g2[g2_order-i+2];  | 
428  | 0  |   }else{ | 
429  | 0  |     for(i=1; i<=g1_order;i++) g1[g1_order-i] -= g1[g1_order-i+1];  | 
430  | 0  |     for(i=1; i<=g2_order;i++) g2[g2_order-i] += g2[g2_order-i+1];  | 
431  | 0  |   }  | 
432  |  |  | 
433  |  |   /* Convert into polynomials in cos(alpha) */  | 
434  | 0  |   cheby(g1,g1_order);  | 
435  | 0  |   cheby(g2,g2_order);  | 
436  |  |  | 
437  |  |   /* Find the roots of the 2 even polynomials.*/  | 
438  | 0  |   if(Laguerre_With_Deflation(g1,g1_order,g1r) ||  | 
439  | 0  |      Laguerre_With_Deflation(g2,g2_order,g2r))  | 
440  | 0  |     return(-1);  | 
441  |  |  | 
442  | 0  |   Newton_Raphson(g1,g1_order,g1r); /* if it fails, it leaves g1r alone */  | 
443  | 0  |   Newton_Raphson(g2,g2_order,g2r); /* if it fails, it leaves g2r alone */  | 
444  |  | 
  | 
445  | 0  |   qsort(g1r,g1_order,sizeof(*g1r),comp);  | 
446  | 0  |   qsort(g2r,g2_order,sizeof(*g2r),comp);  | 
447  |  | 
  | 
448  | 0  |   for(i=0;i<g1_order;i++)  | 
449  | 0  |     lsp[i*2] = acos(g1r[i]);  | 
450  |  | 
  | 
451  | 0  |   for(i=0;i<g2_order;i++)  | 
452  | 0  |     lsp[i*2+1] = acos(g2r[i]);  | 
453  | 0  |   return(0);  | 
454  | 0  | }  |