1885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/***********************************************************************
2885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgCopyright (c) 2006-2011, Skype Limited. All rights reserved.
3885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgRedistribution and use in source and binary forms, with or without
4885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgmodification, are permitted provided that the following conditions
5885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgare met:
6885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org- Redistributions of source code must retain the above copyright notice,
7885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgthis list of conditions and the following disclaimer.
8885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org- Redistributions in binary form must reproduce the above copyright
9885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgnotice, this list of conditions and the following disclaimer in the
10885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgdocumentation and/or other materials provided with the distribution.
11e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org- Neither the name of Internet Society, IETF or IETF Trust, nor the
12885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgnames of specific contributors, may be used to endorse or promote
13885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgproducts derived from this software without specific prior written
14885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgpermission.
15e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.orgTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgPOSSIBILITY OF SUCH DAMAGE.
26885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org***********************************************************************/
27885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
28885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/* Conversion between prediction filter coefficients and NLSFs  */
29885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/* Requires the order to be an even number                      */
30885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/* A piecewise linear approximation maps LSF <-> cos(LSF)       */
31885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/* Therefore the result is not accurate NLSFs, but the two      */
32885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/* functions are accurate inverses of each other                */
33885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
34885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#ifdef HAVE_CONFIG_H
35885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "config.h"
36885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#endif
37885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
38885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "SigProc_FIX.h"
39885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "tables.h"
40885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
41885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/* Number of binary divisions, when not in low complexity mode */
42885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#define BIN_DIV_STEPS_A2NLSF_FIX      3 /* must be no higher than 16 - log2( LSF_COS_TAB_SZ_FIX ) */
43885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#define MAX_ITERATIONS_A2NLSF_FIX    30
44885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
45885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/* Helper function for A2NLSF(..)                    */
46885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/* Transforms polynomials from cos(n*f) to cos(f)^n  */
473c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.comstatic OPUS_INLINE void silk_A2NLSF_trans_poly(
48885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int32          *p,                     /* I/O    Polynomial                                */
49885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const opus_int      dd                      /* I      Polynomial order (= filter order / 2 )    */
50885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org)
51885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{
52885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int k, n;
53885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
54885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    for( k = 2; k <= dd; k++ ) {
55885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        for( n = dd; n > k; n-- ) {
56885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            p[ n - 2 ] -= p[ n ];
57885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        }
58885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        p[ k - 2 ] -= silk_LSHIFT( p[ k ], 1 );
59885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
60885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
61885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/* Helper function for A2NLSF(..) */
62885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/* Polynomial evaluation          */
633c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.comstatic OPUS_INLINE opus_int32 silk_A2NLSF_eval_poly( /* return the polynomial evaluation, in Q16     */
64885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int32          *p,                     /* I    Polynomial, Q16                         */
65885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const opus_int32    x,                      /* I    Evaluation point, Q12                   */
66885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const opus_int      dd                      /* I    Order                                   */
67885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org)
68885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{
69885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int   n;
70885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int32 x_Q16, y32;
71885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
72885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    y32 = p[ dd ];                                  /* Q16 */
73885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    x_Q16 = silk_LSHIFT( x, 4 );
74885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    for( n = dd - 1; n >= 0; n-- ) {
75885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        y32 = silk_SMLAWW( p[ n ], y32, x_Q16 );    /* Q16 */
76885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
77885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    return y32;
78885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
79885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
803c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.comstatic OPUS_INLINE void silk_A2NLSF_init(
81885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org     const opus_int32    *a_Q16,
82885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org     opus_int32          *P,
83885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org     opus_int32          *Q,
84885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org     const opus_int      dd
85885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org)
86885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{
87885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int k;
88885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
89885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* Convert filter coefs to even and odd polynomials */
90885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    P[dd] = silk_LSHIFT( 1, 16 );
91885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    Q[dd] = silk_LSHIFT( 1, 16 );
92885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    for( k = 0; k < dd; k++ ) {
93885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        P[ k ] = -a_Q16[ dd - k - 1 ] - a_Q16[ dd + k ];    /* Q16 */
94885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        Q[ k ] = -a_Q16[ dd - k - 1 ] + a_Q16[ dd + k ];    /* Q16 */
95885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
96885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
97885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* Divide out zeros as we have that for even filter orders, */
98885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* z =  1 is always a root in Q, and                        */
99885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* z = -1 is always a root in P                             */
100885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    for( k = dd; k > 0; k-- ) {
101885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        P[ k - 1 ] -= P[ k ];
102885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        Q[ k - 1 ] += Q[ k ];
103885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
104885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
105885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* Transform polynomials from cos(n*f) to cos(f)^n */
106885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_A2NLSF_trans_poly( P, dd );
107885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_A2NLSF_trans_poly( Q, dd );
108885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
109885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
110885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/* Compute Normalized Line Spectral Frequencies (NLSFs) from whitening filter coefficients      */
111885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/* If not all roots are found, the a_Q16 coefficients are bandwidth expanded until convergence. */
112885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgvoid silk_A2NLSF(
113885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int16                  *NLSF,              /* O    Normalized Line Spectral Frequencies in Q15 (0..2^15-1) [d] */
114885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int32                  *a_Q16,             /* I/O  Monic whitening filter coefficients in Q16 [d]              */
115885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const opus_int              d                   /* I    Filter order (must be even)                                 */
116885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org)
117885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{
118885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int      i, k, m, dd, root_ix, ffrac;
119885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int32 xlo, xhi, xmid;
120885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int32 ylo, yhi, ymid, thr;
121885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int32 nom, den;
122885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int32 P[ SILK_MAX_ORDER_LPC / 2 + 1 ];
123885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int32 Q[ SILK_MAX_ORDER_LPC / 2 + 1 ];
124885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int32 *PQ[ 2 ];
125885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int32 *p;
126885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
127885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* Store pointers to array */
128885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    PQ[ 0 ] = P;
129885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    PQ[ 1 ] = Q;
130885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
131885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    dd = silk_RSHIFT( d, 1 );
132885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
133885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_A2NLSF_init( a_Q16, P, Q, dd );
134885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
135885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* Find roots, alternating between P and Q */
136885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    p = P;                          /* Pointer to polynomial */
137885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
138885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    xlo = silk_LSFCosTab_FIX_Q12[ 0 ]; /* Q12*/
139885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    ylo = silk_A2NLSF_eval_poly( p, xlo, dd );
140885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
141885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    if( ylo < 0 ) {
142885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        /* Set the first NLSF to zero and move on to the next */
143885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        NLSF[ 0 ] = 0;
144885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        p = Q;                      /* Pointer to polynomial */
145885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        ylo = silk_A2NLSF_eval_poly( p, xlo, dd );
146885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        root_ix = 1;                /* Index of current root */
147885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    } else {
148885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        root_ix = 0;                /* Index of current root */
149885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
150885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    k = 1;                          /* Loop counter */
151885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    i = 0;                          /* Counter for bandwidth expansions applied */
152885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    thr = 0;
153885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    while( 1 ) {
154885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        /* Evaluate polynomial */
155885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        xhi = silk_LSFCosTab_FIX_Q12[ k ]; /* Q12 */
156885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        yhi = silk_A2NLSF_eval_poly( p, xhi, dd );
157885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
158885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        /* Detect zero crossing */
159885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        if( ( ylo <= 0 && yhi >= thr ) || ( ylo >= 0 && yhi <= -thr ) ) {
160885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            if( yhi == 0 ) {
161885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                /* If the root lies exactly at the end of the current       */
162885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                /* interval, look for the next root in the next interval    */
163885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                thr = 1;
164885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            } else {
165885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                thr = 0;
166885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            }
167885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            /* Binary division */
168885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            ffrac = -256;
169885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            for( m = 0; m < BIN_DIV_STEPS_A2NLSF_FIX; m++ ) {
170885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                /* Evaluate polynomial */
171885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                xmid = silk_RSHIFT_ROUND( xlo + xhi, 1 );
172885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                ymid = silk_A2NLSF_eval_poly( p, xmid, dd );
173885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
174885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                /* Detect zero crossing */
175885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                if( ( ylo <= 0 && ymid >= 0 ) || ( ylo >= 0 && ymid <= 0 ) ) {
176885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                    /* Reduce frequency */
177885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                    xhi = xmid;
178885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                    yhi = ymid;
179885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                } else {
180885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                    /* Increase frequency */
181885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                    xlo = xmid;
182885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                    ylo = ymid;
183885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                    ffrac = silk_ADD_RSHIFT( ffrac, 128, m );
184885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                }
185885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            }
186885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
187885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            /* Interpolate */
188885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            if( silk_abs( ylo ) < 65536 ) {
189885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                /* Avoid dividing by zero */
190885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                den = ylo - yhi;
191885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                nom = silk_LSHIFT( ylo, 8 - BIN_DIV_STEPS_A2NLSF_FIX ) + silk_RSHIFT( den, 1 );
192885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                if( den != 0 ) {
193885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                    ffrac += silk_DIV32( nom, den );
194885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                }
195885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            } else {
196885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                /* No risk of dividing by zero because abs(ylo - yhi) >= abs(ylo) >= 65536 */
197885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                ffrac += silk_DIV32( ylo, silk_RSHIFT( ylo - yhi, 8 - BIN_DIV_STEPS_A2NLSF_FIX ) );
198885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            }
199885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            NLSF[ root_ix ] = (opus_int16)silk_min_32( silk_LSHIFT( (opus_int32)k, 8 ) + ffrac, silk_int16_MAX );
200885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
201885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            silk_assert( NLSF[ root_ix ] >= 0 );
202885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
203885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            root_ix++;        /* Next root */
204885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            if( root_ix >= d ) {
205885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                /* Found all roots */
206885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                break;
207885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            }
208885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            /* Alternate pointer to polynomial */
209885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            p = PQ[ root_ix & 1 ];
210885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
211885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            /* Evaluate polynomial */
212885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            xlo = silk_LSFCosTab_FIX_Q12[ k - 1 ]; /* Q12*/
213885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            ylo = silk_LSHIFT( 1 - ( root_ix & 2 ), 12 );
214885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        } else {
215885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            /* Increment loop counter */
216885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            k++;
217885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            xlo = xhi;
218885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            ylo = yhi;
219885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            thr = 0;
220885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
221885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            if( k > LSF_COS_TAB_SZ_FIX ) {
222885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                i++;
223885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                if( i > MAX_ITERATIONS_A2NLSF_FIX ) {
224885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                    /* Set NLSFs to white spectrum and exit */
225885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                    NLSF[ 0 ] = (opus_int16)silk_DIV32_16( 1 << 15, d + 1 );
226885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                    for( k = 1; k < d; k++ ) {
227885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                        NLSF[ k ] = (opus_int16)silk_SMULBB( k + 1, NLSF[ 0 ] );
228885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                    }
229885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                    return;
230885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                }
231885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
232885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                /* Error: Apply progressively more bandwidth expansion and run again */
233885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                silk_bwexpander_32( a_Q16, d, 65536 - silk_SMULBB( 10 + i, i ) ); /* 10_Q16 = 0.00015*/
234885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
235885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                silk_A2NLSF_init( a_Q16, P, Q, dd );
236885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                p = P;                            /* Pointer to polynomial */
237885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                xlo = silk_LSFCosTab_FIX_Q12[ 0 ]; /* Q12*/
238885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                ylo = silk_A2NLSF_eval_poly( p, xlo, dd );
239885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                if( ylo < 0 ) {
240885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                    /* Set the first NLSF to zero and move on to the next */
241885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                    NLSF[ 0 ] = 0;
242885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                    p = Q;                        /* Pointer to polynomial */
243885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                    ylo = silk_A2NLSF_eval_poly( p, xlo, dd );
244885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                    root_ix = 1;                  /* Index of current root */
245885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                } else {
246885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                    root_ix = 0;                  /* Index of current root */
247885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                }
248885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                k = 1;                            /* Reset loop counter */
249885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            }
250885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        }
251885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
252885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
253