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#include "main_FLP.h"
33885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "tuning_parameters.h"
34885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
35885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgvoid silk_find_LTP_FLP(
36885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_float                      b[ MAX_NB_SUBFR * LTP_ORDER ],      /* O    LTP coefs                                   */
37885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_float                      WLTP[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O    Weight for LTP quantization       */
38885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_float                      *LTPredCodGain,                     /* O    LTP coding gain                             */
39885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const silk_float                r_lpc[],                            /* I    LPC residual                                */
40885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const opus_int                  lag[  MAX_NB_SUBFR ],               /* I    LTP lags                                    */
41885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const silk_float                Wght[ MAX_NB_SUBFR ],               /* I    Weights                                     */
42885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const opus_int                  subfr_length,                       /* I    Subframe length                             */
43885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const opus_int                  nb_subfr,                           /* I    number of subframes                         */
44885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const opus_int                  mem_offset                          /* I    Number of samples in LTP memory             */
45885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org)
46885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{
47885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int   i, k;
48885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_float *b_ptr, temp, *WLTP_ptr;
49885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_float LPC_res_nrg, LPC_LTP_res_nrg;
50885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_float d[ MAX_NB_SUBFR ], m, g, delta_b[ LTP_ORDER ];
51885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_float w[ MAX_NB_SUBFR ], nrg[ MAX_NB_SUBFR ], regu;
52885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_float Rr[ LTP_ORDER ], rr[ MAX_NB_SUBFR ];
53885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const silk_float *r_ptr, *lag_ptr;
54885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
55885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    b_ptr    = b;
56885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    WLTP_ptr = WLTP;
57885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    r_ptr    = &r_lpc[ mem_offset ];
58885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    for( k = 0; k < nb_subfr; k++ ) {
59885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        lag_ptr = r_ptr - ( lag[ k ] + LTP_ORDER / 2 );
60885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
61885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        silk_corrMatrix_FLP( lag_ptr, subfr_length, LTP_ORDER, WLTP_ptr );
62885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        silk_corrVector_FLP( lag_ptr, r_ptr, subfr_length, LTP_ORDER, Rr );
63885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
64885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        rr[ k ] = ( silk_float )silk_energy_FLP( r_ptr, subfr_length );
65885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        regu = 1.0f + rr[ k ] +
66885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            matrix_ptr( WLTP_ptr, 0, 0, LTP_ORDER ) +
67885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            matrix_ptr( WLTP_ptr, LTP_ORDER-1, LTP_ORDER-1, LTP_ORDER );
68885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        regu *= LTP_DAMPING / 3;
69885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        silk_regularize_correlations_FLP( WLTP_ptr, &rr[ k ], regu, LTP_ORDER );
70885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        silk_solve_LDL_FLP( WLTP_ptr, LTP_ORDER, Rr, b_ptr );
71885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
72885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        /* Calculate residual energy */
73885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        nrg[ k ] = silk_residual_energy_covar_FLP( b_ptr, WLTP_ptr, Rr, rr[ k ], LTP_ORDER );
74885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
75885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        temp = Wght[ k ] / ( nrg[ k ] * Wght[ k ] + 0.01f * subfr_length );
76885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        silk_scale_vector_FLP( WLTP_ptr, temp, LTP_ORDER * LTP_ORDER );
77885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        w[ k ] = matrix_ptr( WLTP_ptr, LTP_ORDER / 2, LTP_ORDER / 2, LTP_ORDER );
78885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
79885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        r_ptr    += subfr_length;
80885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        b_ptr    += LTP_ORDER;
81885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        WLTP_ptr += LTP_ORDER * LTP_ORDER;
82885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
83885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
84885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* Compute LTP coding gain */
85885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    if( LTPredCodGain != NULL ) {
86885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        LPC_LTP_res_nrg = 1e-6f;
87885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        LPC_res_nrg     = 0.0f;
88885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        for( k = 0; k < nb_subfr; k++ ) {
89885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            LPC_res_nrg     += rr[  k ] * Wght[ k ];
90885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            LPC_LTP_res_nrg += nrg[ k ] * Wght[ k ];
91885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        }
92885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
93885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        silk_assert( LPC_LTP_res_nrg > 0 );
94885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        *LTPredCodGain = 3.0f * silk_log2( LPC_res_nrg / LPC_LTP_res_nrg );
95885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
96885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
97885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* Smoothing */
98885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* d = sum( B, 1 ); */
99885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    b_ptr = b;
100885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    for( k = 0; k < nb_subfr; k++ ) {
101885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        d[ k ] = 0;
102885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        for( i = 0; i < LTP_ORDER; i++ ) {
103885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            d[ k ] += b_ptr[ i ];
104885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        }
105885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        b_ptr += LTP_ORDER;
106885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
107885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* m = ( w * d' ) / ( sum( w ) + 1e-3 ); */
108885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    temp = 1e-3f;
109885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    for( k = 0; k < nb_subfr; k++ ) {
110885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        temp += w[ k ];
111885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
112885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    m = 0;
113885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    for( k = 0; k < nb_subfr; k++ ) {
114885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        m += d[ k ] * w[ k ];
115885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
116885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    m = m / temp;
117885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
118885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    b_ptr = b;
119885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    for( k = 0; k < nb_subfr; k++ ) {
120885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        g = LTP_SMOOTHING / ( LTP_SMOOTHING + w[ k ] ) * ( m - d[ k ] );
121885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        temp = 0;
122885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        for( i = 0; i < LTP_ORDER; i++ ) {
123885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            delta_b[ i ] = silk_max_float( b_ptr[ i ], 0.1f );
124885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            temp += delta_b[ i ];
125885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        }
126885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        temp = g / temp;
127885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        for( i = 0; i < LTP_ORDER; i++ ) {
128885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            b_ptr[ i ] = b_ptr[ i ] + delta_b[ i ] * temp;
129885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        }
130885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        b_ptr += LTP_ORDER;
131885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
132885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
133