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#ifdef HAVE_CONFIG_H
29885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "config.h"
30885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#endif
31885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
32885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/* conversion between prediction filter coefficients and LSFs   */
33885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/* order should be even                                         */
34885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/* a piecewise linear approximation maps LSF <-> cos(LSF)       */
35885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/* therefore the result is not accurate LSFs, but the two       */
36885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/* functions are accurate inverses of each other                */
37885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
38885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "SigProc_FIX.h"
39885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "tables.h"
40885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
41885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#define QA      16
42885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
43885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/* helper function for NLSF2A(..) */
443c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.comstatic OPUS_INLINE void silk_NLSF2A_find_poly(
45885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int32          *out,      /* O    intermediate polynomial, QA [dd+1]        */
46885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const opus_int32    *cLSF,     /* I    vector of interleaved 2*cos(LSFs), QA [d] */
47885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int            dd         /* I    polynomial order (= 1/2 * filter order)   */
48885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org)
49885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{
50885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int   k, n;
51885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int32 ftmp;
52885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
53885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    out[0] = silk_LSHIFT( 1, QA );
54885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    out[1] = -cLSF[0];
55885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    for( k = 1; k < dd; k++ ) {
56885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        ftmp = cLSF[2*k];            /* QA*/
57885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        out[k+1] = silk_LSHIFT( out[k-1], 1 ) - (opus_int32)silk_RSHIFT_ROUND64( silk_SMULL( ftmp, out[k] ), QA );
58885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        for( n = k; n > 1; n-- ) {
59885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            out[n] += out[n-2] - (opus_int32)silk_RSHIFT_ROUND64( silk_SMULL( ftmp, out[n-1] ), QA );
60885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        }
61885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        out[1] -= ftmp;
62885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
63885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
64885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
65885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/* compute whitening filter coefficients from normalized line spectral frequencies */
66885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgvoid silk_NLSF2A(
67885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int16                  *a_Q12,             /* O    monic whitening filter coefficients in Q12,  [ d ]          */
68885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const opus_int16            *NLSF,              /* I    normalized line spectral frequencies in Q15, [ d ]          */
69885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const opus_int              d                   /* I    filter order (should be even)                               */
70885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org)
71885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{
72885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* This ordering was found to maximize quality. It improves numerical accuracy of
73885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org       silk_NLSF2A_find_poly() compared to "standard" ordering. */
74885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    static const unsigned char ordering16[16] = {
75885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      0, 15, 8, 7, 4, 11, 12, 3, 2, 13, 10, 5, 6, 9, 14, 1
76885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    };
77885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    static const unsigned char ordering10[10] = {
78885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      0, 9, 6, 3, 4, 5, 8, 1, 2, 7
79885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    };
80885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const unsigned char *ordering;
81885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int   k, i, dd;
82885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int32 cos_LSF_QA[ SILK_MAX_ORDER_LPC ];
83885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int32 P[ SILK_MAX_ORDER_LPC / 2 + 1 ], Q[ SILK_MAX_ORDER_LPC / 2 + 1 ];
84885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int32 Ptmp, Qtmp, f_int, f_frac, cos_val, delta;
85885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int32 a32_QA1[ SILK_MAX_ORDER_LPC ];
86885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int32 maxabs, absval, idx=0, sc_Q16;
87885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
88885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_assert( LSF_COS_TAB_SZ_FIX == 128 );
89885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_assert( d==10||d==16 );
90885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
91885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* convert LSFs to 2*cos(LSF), using piecewise linear curve from table */
92885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    ordering = d == 16 ? ordering16 : ordering10;
93885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    for( k = 0; k < d; k++ ) {
94885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        silk_assert(NLSF[k] >= 0 );
95885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
96885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        /* f_int on a scale 0-127 (rounded down) */
97885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        f_int = silk_RSHIFT( NLSF[k], 15 - 7 );
98885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
99885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        /* f_frac, range: 0..255 */
100885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        f_frac = NLSF[k] - silk_LSHIFT( f_int, 15 - 7 );
101885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
102885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        silk_assert(f_int >= 0);
103885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        silk_assert(f_int < LSF_COS_TAB_SZ_FIX );
104885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
105885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        /* Read start and end value from table */
106885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        cos_val = silk_LSFCosTab_FIX_Q12[ f_int ];                /* Q12 */
107885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        delta   = silk_LSFCosTab_FIX_Q12[ f_int + 1 ] - cos_val;  /* Q12, with a range of 0..200 */
108885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
109885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        /* Linear interpolation */
110885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        cos_LSF_QA[ordering[k]] = silk_RSHIFT_ROUND( silk_LSHIFT( cos_val, 8 ) + silk_MUL( delta, f_frac ), 20 - QA ); /* QA */
111885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
112885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
113885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    dd = silk_RSHIFT( d, 1 );
114885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
115885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* generate even and odd polynomials using convolution */
116885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_NLSF2A_find_poly( P, &cos_LSF_QA[ 0 ], dd );
117885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_NLSF2A_find_poly( Q, &cos_LSF_QA[ 1 ], dd );
118885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
119885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* convert even and odd polynomials to opus_int32 Q12 filter coefs */
120885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    for( k = 0; k < dd; k++ ) {
121885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        Ptmp = P[ k+1 ] + P[ k ];
122885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        Qtmp = Q[ k+1 ] - Q[ k ];
123885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
124885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        /* the Ptmp and Qtmp values at this stage need to fit in int32 */
125885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        a32_QA1[ k ]     = -Qtmp - Ptmp;        /* QA+1 */
126885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        a32_QA1[ d-k-1 ] =  Qtmp - Ptmp;        /* QA+1 */
127885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
128885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
129885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* Limit the maximum absolute value of the prediction coefficients, so that they'll fit in int16 */
130885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    for( i = 0; i < 10; i++ ) {
131885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        /* Find maximum absolute value and its index */
132885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        maxabs = 0;
133885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        for( k = 0; k < d; k++ ) {
134885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            absval = silk_abs( a32_QA1[k] );
135885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            if( absval > maxabs ) {
136885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                maxabs = absval;
137885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                idx    = k;
138885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            }
139885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        }
140885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        maxabs = silk_RSHIFT_ROUND( maxabs, QA + 1 - 12 );                                          /* QA+1 -> Q12 */
141885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
142885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        if( maxabs > silk_int16_MAX ) {
143885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            /* Reduce magnitude of prediction coefficients */
144885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            maxabs = silk_min( maxabs, 163838 );  /* ( silk_int32_MAX >> 14 ) + silk_int16_MAX = 163838 */
145885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            sc_Q16 = SILK_FIX_CONST( 0.999, 16 ) - silk_DIV32( silk_LSHIFT( maxabs - silk_int16_MAX, 14 ),
146885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                                        silk_RSHIFT32( silk_MUL( maxabs, idx + 1), 2 ) );
147885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            silk_bwexpander_32( a32_QA1, d, sc_Q16 );
148885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        } else {
149885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            break;
150885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        }
151885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
152885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
153885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    if( i == 10 ) {
154885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        /* Reached the last iteration, clip the coefficients */
155885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        for( k = 0; k < d; k++ ) {
156885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            a_Q12[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( a32_QA1[ k ], QA + 1 - 12 ) );  /* QA+1 -> Q12 */
157885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            a32_QA1[ k ] = silk_LSHIFT( (opus_int32)a_Q12[ k ], QA + 1 - 12 );
158885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        }
159885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    } else {
160885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        for( k = 0; k < d; k++ ) {
161885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            a_Q12[ k ] = (opus_int16)silk_RSHIFT_ROUND( a32_QA1[ k ], QA + 1 - 12 );                /* QA+1 -> Q12 */
162885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        }
163885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
164885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
165885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    for( i = 0; i < MAX_LPC_STABILIZE_ITERATIONS; i++ ) {
166885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        if( silk_LPC_inverse_pred_gain( a_Q12, d ) < SILK_FIX_CONST( 1.0 / MAX_PREDICTION_POWER_GAIN, 30 ) ) {
167885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            /* Prediction coefficients are (too close to) unstable; apply bandwidth expansion   */
168885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            /* on the unscaled coefficients, convert to Q12 and measure again                   */
169885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            silk_bwexpander_32( a32_QA1, d, 65536 - silk_LSHIFT( 2, i ) );
170885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            for( k = 0; k < d; k++ ) {
171885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                a_Q12[ k ] = (opus_int16)silk_RSHIFT_ROUND( a32_QA1[ k ], QA + 1 - 12 );            /* QA+1 -> Q12 */
172885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            }
173885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        } else {
174885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            break;
175885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        }
176885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
177885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
178885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
179