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
34885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#define MAX_ITERATIONS_RESIDUAL_NRG         10
35885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#define REGULARIZATION_FACTOR               1e-8f
36885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
37885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */
38885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgsilk_float silk_residual_energy_covar_FLP(                              /* O    Weighted residual energy                    */
39885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const silk_float                *c,                                 /* I    Filter coefficients                         */
40885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_float                      *wXX,                               /* I/O  Weighted correlation matrix, reg. out       */
41885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const silk_float                *wXx,                               /* I    Weighted correlation vector                 */
42885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const silk_float                wxx,                                /* I    Weighted correlation value                  */
43885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const opus_int                  D                                   /* I    Dimension                                   */
44885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org)
45885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{
46885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int   i, j, k;
47885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_float tmp, nrg = 0.0f, regularization;
48885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
49885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* Safety checks */
50885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_assert( D >= 0 );
51885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
52885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    regularization = REGULARIZATION_FACTOR * ( wXX[ 0 ] + wXX[ D * D - 1 ] );
53885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    for( k = 0; k < MAX_ITERATIONS_RESIDUAL_NRG; k++ ) {
54885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        nrg = wxx;
55885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
56885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        tmp = 0.0f;
57885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        for( i = 0; i < D; i++ ) {
58885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            tmp += wXx[ i ] * c[ i ];
59885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        }
60885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        nrg -= 2.0f * tmp;
61885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
62885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        /* compute c' * wXX * c, assuming wXX is symmetric */
63885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        for( i = 0; i < D; i++ ) {
64885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            tmp = 0.0f;
65885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            for( j = i + 1; j < D; j++ ) {
66885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                tmp += matrix_c_ptr( wXX, i, j, D ) * c[ j ];
67885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            }
68885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            nrg += c[ i ] * ( 2.0f * tmp + matrix_c_ptr( wXX, i, i, D ) * c[ i ] );
69885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        }
70885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        if( nrg > 0 ) {
71885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            break;
72885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        } else {
73885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            /* Add white noise */
74885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            for( i = 0; i < D; i++ ) {
75885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                matrix_c_ptr( wXX, i, i, D ) +=  regularization;
76885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            }
77885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            /* Increase noise for next run */
78885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            regularization *= 2.0f;
79885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        }
80885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
81885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    if( k == MAX_ITERATIONS_RESIDUAL_NRG ) {
82885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        silk_assert( nrg == 0 );
83885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        nrg = 1.0f;
84885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
85885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
86885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    return nrg;
87885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
88885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
89885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/* Calculates residual energies of input subframes where all subframes have LPC_order   */
906b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org/* of preceding samples                                                                 */
91885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgvoid silk_residual_energy_FLP(
92885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_float                      nrgs[ MAX_NB_SUBFR ],               /* O    Residual energy per subframe                */
93885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const silk_float                x[],                                /* I    Input signal                                */
94885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_float                      a[ 2 ][ MAX_LPC_ORDER ],            /* I    AR coefs for each frame half                */
95885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const silk_float                gains[],                            /* I    Quantization gains                          */
96885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const opus_int                  subfr_length,                       /* I    Subframe length                             */
97885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const opus_int                  nb_subfr,                           /* I    number of subframes                         */
98885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const opus_int                  LPC_order                           /* I    LPC order                                   */
99885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org)
100885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{
101885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int     shift;
102885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_float   *LPC_res_ptr, LPC_res[ ( MAX_FRAME_LENGTH + MAX_NB_SUBFR * MAX_LPC_ORDER ) / 2 ];
103885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
104885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    LPC_res_ptr = LPC_res + LPC_order;
105885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    shift = LPC_order + subfr_length;
106885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
107885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* Filter input to create the LPC residual for each frame half, and measure subframe energies */
108885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_LPC_analysis_filter_FLP( LPC_res, a[ 0 ], x + 0 * shift, 2 * shift, LPC_order );
109885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    nrgs[ 0 ] = ( silk_float )( gains[ 0 ] * gains[ 0 ] * silk_energy_FLP( LPC_res_ptr + 0 * shift, subfr_length ) );
110885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    nrgs[ 1 ] = ( silk_float )( gains[ 1 ] * gains[ 1 ] * silk_energy_FLP( LPC_res_ptr + 1 * shift, subfr_length ) );
111885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
112885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    if( nb_subfr == MAX_NB_SUBFR ) {
113885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        silk_LPC_analysis_filter_FLP( LPC_res, a[ 1 ], x + 2 * shift, 2 * shift, LPC_order );
114885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        nrgs[ 2 ] = ( silk_float )( gains[ 2 ] * gains[ 2 ] * silk_energy_FLP( LPC_res_ptr + 0 * shift, subfr_length ) );
115885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        nrgs[ 3 ] = ( silk_float )( gains[ 3 ] * gains[ 3 ] * silk_energy_FLP( LPC_res_ptr + 1 * shift, subfr_length ) );
116885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
117885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
118