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/*****************************************************************************
33885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org* Pitch analyser function
34885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org******************************************************************************/
35885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "SigProc_FLP.h"
36885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "SigProc_FIX.h"
37885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "pitch_est_defines.h"
38e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#include "pitch.h"
39885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
40885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#define SCRATCH_SIZE        22
41885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
42885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/************************************************************/
43885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/* Internally used functions                                */
44885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/************************************************************/
45885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgstatic void silk_P_Ana_calc_corr_st3(
46885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_float cross_corr_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ], /* O 3 DIM correlation array */
47885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const silk_float    frame[],            /* I vector to correlate                                            */
48885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int            start_lag,          /* I start lag                                                      */
49885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int            sf_length,          /* I sub frame length                                               */
50885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int            nb_subfr,           /* I number of subframes                                            */
513c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com    opus_int            complexity,         /* I Complexity setting                                             */
523c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com    int                 arch                /* I Run-time architecture                                          */
53885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org);
54885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
55885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgstatic void silk_P_Ana_calc_energy_st3(
56885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_float energies_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ], /* O 3 DIM correlation array */
57885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const silk_float    frame[],            /* I vector to correlate                                            */
58885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int            start_lag,          /* I start lag                                                      */
59885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int            sf_length,          /* I sub frame length                                               */
60885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int            nb_subfr,           /* I number of subframes                                            */
61885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int            complexity          /* I Complexity setting                                             */
62885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org);
63885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
64885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/************************************************************/
65885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/* CORE PITCH ANALYSIS FUNCTION                             */
66885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/************************************************************/
67885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgopus_int silk_pitch_analysis_core_FLP(      /* O    Voicing estimate: 0 voiced, 1 unvoiced                      */
68885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const silk_float    *frame,             /* I    Signal of length PE_FRAME_LENGTH_MS*Fs_kHz                  */
69885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int            *pitch_out,         /* O    Pitch lag values [nb_subfr]                                 */
70885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int16          *lagIndex,          /* O    Lag Index                                                   */
71885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int8           *contourIndex,      /* O    Pitch contour Index                                         */
72885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_float          *LTPCorr,           /* I/O  Normalized correlation; input: value from previous frame    */
73885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int            prevLag,            /* I    Last lag of previous frame; set to zero is unvoiced         */
74885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const silk_float    search_thres1,      /* I    First stage threshold for lag candidates 0 - 1              */
75885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const silk_float    search_thres2,      /* I    Final threshold for lag candidates 0 - 1                    */
76885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const opus_int      Fs_kHz,             /* I    sample frequency (kHz)                                      */
77885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const opus_int      complexity,         /* I    Complexity setting, 0-2, where 2 is highest                 */
783c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com    const opus_int      nb_subfr,           /* I    Number of 5 ms subframes                                    */
793c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com    int                 arch                /* I    Run-time architecture                                       */
80885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org)
81885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{
82885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int   i, k, d, j;
83885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_float frame_8kHz[  PE_MAX_FRAME_LENGTH_MS * 8 ];
84885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_float frame_4kHz[  PE_MAX_FRAME_LENGTH_MS * 4 ];
85885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int16 frame_8_FIX[ PE_MAX_FRAME_LENGTH_MS * 8 ];
86885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int16 frame_4_FIX[ PE_MAX_FRAME_LENGTH_MS * 4 ];
87885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int32 filt_state[ 6 ];
88885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_float threshold, contour_bias;
89885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_float C[ PE_MAX_NB_SUBFR][ (PE_MAX_LAG >> 1) + 5 ];
90e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org    opus_val32 xcorr[ PE_MAX_LAG_MS * 4 - PE_MIN_LAG_MS * 4 + 1 ];
91885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_float CC[ PE_NB_CBKS_STAGE2_EXT ];
92885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const silk_float *target_ptr, *basis_ptr;
93885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    double    cross_corr, normalizer, energy, energy_tmp;
94885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int   d_srch[ PE_D_SRCH_LENGTH ];
95885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int16 d_comp[ (PE_MAX_LAG >> 1) + 5 ];
96885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int   length_d_srch, length_d_comp;
97885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_float Cmax, CCmax, CCmax_b, CCmax_new_b, CCmax_new;
98885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int   CBimax, CBimax_new, lag, start_lag, end_lag, lag_new;
99885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int   cbk_size;
100885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_float lag_log2, prevLag_log2, delta_lag_log2_sqr;
101885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_float energies_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ];
102885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_float cross_corr_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ];
103885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int   lag_counter;
104885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int   frame_length, frame_length_8kHz, frame_length_4kHz;
105885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int   sf_length, sf_length_8kHz, sf_length_4kHz;
106885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int   min_lag, min_lag_8kHz, min_lag_4kHz;
107885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int   max_lag, max_lag_8kHz, max_lag_4kHz;
108885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int   nb_cbk_search;
109885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const opus_int8 *Lag_CB_ptr;
110885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
111885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* Check for valid sampling frequency */
112885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_assert( Fs_kHz == 8 || Fs_kHz == 12 || Fs_kHz == 16 );
113885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
114885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* Check for valid complexity setting */
115885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_assert( complexity >= SILK_PE_MIN_COMPLEX );
116885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_assert( complexity <= SILK_PE_MAX_COMPLEX );
117885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
118885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_assert( search_thres1 >= 0.0f && search_thres1 <= 1.0f );
119885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_assert( search_thres2 >= 0.0f && search_thres2 <= 1.0f );
120885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
121885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* Set up frame lengths max / min lag for the sampling frequency */
122885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    frame_length      = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * Fs_kHz;
123885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    frame_length_4kHz = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * 4;
124885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    frame_length_8kHz = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * 8;
125885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    sf_length         = PE_SUBFR_LENGTH_MS * Fs_kHz;
126885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    sf_length_4kHz    = PE_SUBFR_LENGTH_MS * 4;
127885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    sf_length_8kHz    = PE_SUBFR_LENGTH_MS * 8;
128885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    min_lag           = PE_MIN_LAG_MS * Fs_kHz;
129885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    min_lag_4kHz      = PE_MIN_LAG_MS * 4;
130885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    min_lag_8kHz      = PE_MIN_LAG_MS * 8;
131885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    max_lag           = PE_MAX_LAG_MS * Fs_kHz - 1;
132885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    max_lag_4kHz      = PE_MAX_LAG_MS * 4;
133885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    max_lag_8kHz      = PE_MAX_LAG_MS * 8 - 1;
134885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
135885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* Resample from input sampled at Fs_kHz to 8 kHz */
136885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    if( Fs_kHz == 16 ) {
137885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        /* Resample to 16 -> 8 khz */
138885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        opus_int16 frame_16_FIX[ 16 * PE_MAX_FRAME_LENGTH_MS ];
139885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        silk_float2short_array( frame_16_FIX, frame, frame_length );
140885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        silk_memset( filt_state, 0, 2 * sizeof( opus_int32 ) );
141885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        silk_resampler_down2( filt_state, frame_8_FIX, frame_16_FIX, frame_length );
142885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        silk_short2float_array( frame_8kHz, frame_8_FIX, frame_length_8kHz );
143885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    } else if( Fs_kHz == 12 ) {
144885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        /* Resample to 12 -> 8 khz */
145885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        opus_int16 frame_12_FIX[ 12 * PE_MAX_FRAME_LENGTH_MS ];
146885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        silk_float2short_array( frame_12_FIX, frame, frame_length );
147885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        silk_memset( filt_state, 0, 6 * sizeof( opus_int32 ) );
148885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        silk_resampler_down2_3( filt_state, frame_8_FIX, frame_12_FIX, frame_length );
149885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        silk_short2float_array( frame_8kHz, frame_8_FIX, frame_length_8kHz );
150885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    } else {
151885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        silk_assert( Fs_kHz == 8 );
152885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        silk_float2short_array( frame_8_FIX, frame, frame_length_8kHz );
153885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
154885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
155885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* Decimate again to 4 kHz */
156885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_memset( filt_state, 0, 2 * sizeof( opus_int32 ) );
157885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_resampler_down2( filt_state, frame_4_FIX, frame_8_FIX, frame_length_8kHz );
158885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_short2float_array( frame_4kHz, frame_4_FIX, frame_length_4kHz );
159885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
160885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* Low-pass filter */
161885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    for( i = frame_length_4kHz - 1; i > 0; i-- ) {
162885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        frame_4kHz[ i ] += frame_4kHz[ i - 1 ];
163885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
164885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
165885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /******************************************************************************
166885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    * FIRST STAGE, operating in 4 khz
167885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    ******************************************************************************/
168e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org    silk_memset(C, 0, sizeof(silk_float) * nb_subfr * ((PE_MAX_LAG >> 1) + 5));
169885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    target_ptr = &frame_4kHz[ silk_LSHIFT( sf_length_4kHz, 2 ) ];
170885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    for( k = 0; k < nb_subfr >> 1; k++ ) {
171885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        /* Check that we are within range of the array */
172885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        silk_assert( target_ptr >= frame_4kHz );
173885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        silk_assert( target_ptr + sf_length_8kHz <= frame_4kHz + frame_length_4kHz );
174885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
175885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        basis_ptr = target_ptr - min_lag_4kHz;
176885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
177885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        /* Check that we are within range of the array */
178885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        silk_assert( basis_ptr >= frame_4kHz );
179885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        silk_assert( basis_ptr + sf_length_8kHz <= frame_4kHz + frame_length_4kHz );
180885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
1813c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com        celt_pitch_xcorr( target_ptr, target_ptr-max_lag_4kHz, xcorr, sf_length_8kHz, max_lag_4kHz - min_lag_4kHz + 1, arch );
182e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
183885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        /* Calculate first vector products before loop */
184e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org        cross_corr = xcorr[ max_lag_4kHz - min_lag_4kHz ];
185e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org        normalizer = silk_energy_FLP( target_ptr, sf_length_8kHz ) +
186e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org                     silk_energy_FLP( basis_ptr,  sf_length_8kHz ) +
187e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org                     sf_length_8kHz * 4000.0f;
188885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
189e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org        C[ 0 ][ min_lag_4kHz ] += (silk_float)( 2 * cross_corr / normalizer );
190885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
191885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        /* From now on normalizer is computed recursively */
192e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org        for( d = min_lag_4kHz + 1; d <= max_lag_4kHz; d++ ) {
193885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            basis_ptr--;
194885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
195885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            /* Check that we are within range of the array */
196885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            silk_assert( basis_ptr >= frame_4kHz );
197885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            silk_assert( basis_ptr + sf_length_8kHz <= frame_4kHz + frame_length_4kHz );
198885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
199e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org            cross_corr = xcorr[ max_lag_4kHz - d ];
200885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
201885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            /* Add contribution of new sample and remove contribution from oldest sample */
202885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            normalizer +=
203885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                basis_ptr[ 0 ] * (double)basis_ptr[ 0 ] -
204885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                basis_ptr[ sf_length_8kHz ] * (double)basis_ptr[ sf_length_8kHz ];
205e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org            C[ 0 ][ d ] += (silk_float)( 2 * cross_corr / normalizer );
206885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        }
207885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        /* Update target pointer */
208885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        target_ptr += sf_length_8kHz;
209885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
210885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
211885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* Apply short-lag bias */
212885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    for( i = max_lag_4kHz; i >= min_lag_4kHz; i-- ) {
213885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        C[ 0 ][ i ] -= C[ 0 ][ i ] * i / 4096.0f;
214885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
215885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
216885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* Sort */
217885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    length_d_srch = 4 + 2 * complexity;
218885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_assert( 3 * length_d_srch <= PE_D_SRCH_LENGTH );
219885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_insertion_sort_decreasing_FLP( &C[ 0 ][ min_lag_4kHz ], d_srch, max_lag_4kHz - min_lag_4kHz + 1, length_d_srch );
220885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
221885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* Escape if correlation is very low already here */
222885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    Cmax = C[ 0 ][ min_lag_4kHz ];
223e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org    if( Cmax < 0.2f ) {
224885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        silk_memset( pitch_out, 0, nb_subfr * sizeof( opus_int ) );
225885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        *LTPCorr      = 0.0f;
226885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        *lagIndex     = 0;
227885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        *contourIndex = 0;
228885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        return 1;
229885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
230885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
231885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    threshold = search_thres1 * Cmax;
232885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    for( i = 0; i < length_d_srch; i++ ) {
233885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        /* Convert to 8 kHz indices for the sorted correlation that exceeds the threshold */
234885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        if( C[ 0 ][ min_lag_4kHz + i ] > threshold ) {
235885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            d_srch[ i ] = silk_LSHIFT( d_srch[ i ] + min_lag_4kHz, 1 );
236885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        } else {
237885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            length_d_srch = i;
238885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            break;
239885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        }
240885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
241885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_assert( length_d_srch > 0 );
242885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
243885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    for( i = min_lag_8kHz - 5; i < max_lag_8kHz + 5; i++ ) {
244885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        d_comp[ i ] = 0;
245885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
246885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    for( i = 0; i < length_d_srch; i++ ) {
247885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        d_comp[ d_srch[ i ] ] = 1;
248885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
249885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
250885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* Convolution */
251885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    for( i = max_lag_8kHz + 3; i >= min_lag_8kHz; i-- ) {
252885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        d_comp[ i ] += d_comp[ i - 1 ] + d_comp[ i - 2 ];
253885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
254885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
255885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    length_d_srch = 0;
256885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    for( i = min_lag_8kHz; i < max_lag_8kHz + 1; i++ ) {
257885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        if( d_comp[ i + 1 ] > 0 ) {
258885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            d_srch[ length_d_srch ] = i;
259885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            length_d_srch++;
260885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        }
261885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
262885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
263885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* Convolution */
264885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    for( i = max_lag_8kHz + 3; i >= min_lag_8kHz; i-- ) {
265885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        d_comp[ i ] += d_comp[ i - 1 ] + d_comp[ i - 2 ] + d_comp[ i - 3 ];
266885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
267885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
268885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    length_d_comp = 0;
269885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    for( i = min_lag_8kHz; i < max_lag_8kHz + 4; i++ ) {
270885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        if( d_comp[ i ] > 0 ) {
271885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            d_comp[ length_d_comp ] = (opus_int16)( i - 2 );
272885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            length_d_comp++;
273885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        }
274885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
275885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
276885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /**********************************************************************************
277885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    ** SECOND STAGE, operating at 8 kHz, on lag sections with high correlation
278885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    *************************************************************************************/
279885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /*********************************************************************************
280885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    * Find energy of each subframe projected onto its history, for a range of delays
281885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    *********************************************************************************/
282885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_memset( C, 0, PE_MAX_NB_SUBFR*((PE_MAX_LAG >> 1) + 5) * sizeof(silk_float));
283885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
284885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    if( Fs_kHz == 8 ) {
285885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        target_ptr = &frame[ PE_LTP_MEM_LENGTH_MS * 8 ];
286885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    } else {
287885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        target_ptr = &frame_8kHz[ PE_LTP_MEM_LENGTH_MS * 8 ];
288885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
289885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    for( k = 0; k < nb_subfr; k++ ) {
290e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org        energy_tmp = silk_energy_FLP( target_ptr, sf_length_8kHz ) + 1.0;
291885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        for( j = 0; j < length_d_comp; j++ ) {
292885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            d = d_comp[ j ];
293885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            basis_ptr = target_ptr - d;
294885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            cross_corr = silk_inner_product_FLP( basis_ptr, target_ptr, sf_length_8kHz );
295885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            if( cross_corr > 0.0f ) {
296e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org                energy = silk_energy_FLP( basis_ptr, sf_length_8kHz );
297e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org                C[ k ][ d ] = (silk_float)( 2 * cross_corr / ( energy + energy_tmp ) );
298885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            } else {
299885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                C[ k ][ d ] = 0.0f;
300885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            }
301885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        }
302885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        target_ptr += sf_length_8kHz;
303885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
304885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
305885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* search over lag range and lags codebook */
306885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* scale factor for lag codebook, as a function of center lag */
307885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
308885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    CCmax   = 0.0f; /* This value doesn't matter */
309885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    CCmax_b = -1000.0f;
310885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
311885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    CBimax = 0; /* To avoid returning undefined lag values */
312885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    lag = -1;   /* To check if lag with strong enough correlation has been found */
313885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
314885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    if( prevLag > 0 ) {
315885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        if( Fs_kHz == 12 ) {
316885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            prevLag = silk_LSHIFT( prevLag, 1 ) / 3;
317885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        } else if( Fs_kHz == 16 ) {
318885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            prevLag = silk_RSHIFT( prevLag, 1 );
319885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        }
320e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org        prevLag_log2 = silk_log2( (silk_float)prevLag );
321885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    } else {
322885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        prevLag_log2 = 0;
323885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
324885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
325885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* Set up stage 2 codebook based on number of subframes */
326885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    if( nb_subfr == PE_MAX_NB_SUBFR ) {
327885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        cbk_size   = PE_NB_CBKS_STAGE2_EXT;
328885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        Lag_CB_ptr = &silk_CB_lags_stage2[ 0 ][ 0 ];
329885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        if( Fs_kHz == 8 && complexity > SILK_PE_MIN_COMPLEX ) {
330885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            /* If input is 8 khz use a larger codebook here because it is last stage */
331885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            nb_cbk_search = PE_NB_CBKS_STAGE2_EXT;
332885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        } else {
333885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            nb_cbk_search = PE_NB_CBKS_STAGE2;
334885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        }
335885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    } else {
336885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        cbk_size       = PE_NB_CBKS_STAGE2_10MS;
337885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        Lag_CB_ptr     = &silk_CB_lags_stage2_10_ms[ 0 ][ 0 ];
338885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        nb_cbk_search  = PE_NB_CBKS_STAGE2_10MS;
339885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
340885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
341885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    for( k = 0; k < length_d_srch; k++ ) {
342885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        d = d_srch[ k ];
343885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        for( j = 0; j < nb_cbk_search; j++ ) {
344885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            CC[j] = 0.0f;
345885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            for( i = 0; i < nb_subfr; i++ ) {
346885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                /* Try all codebooks */
347885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                CC[ j ] += C[ i ][ d + matrix_ptr( Lag_CB_ptr, i, j, cbk_size )];
348885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            }
349885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        }
350885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        /* Find best codebook */
351885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        CCmax_new  = -1000.0f;
352885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        CBimax_new = 0;
353885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        for( i = 0; i < nb_cbk_search; i++ ) {
354885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            if( CC[ i ] > CCmax_new ) {
355885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                CCmax_new = CC[ i ];
356885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                CBimax_new = i;
357885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            }
358885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        }
359885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
360885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        /* Bias towards shorter lags */
361e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org        lag_log2 = silk_log2( (silk_float)d );
362e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org        CCmax_new_b = CCmax_new - PE_SHORTLAG_BIAS * nb_subfr * lag_log2;
363885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
364885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        /* Bias towards previous lag */
365885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        if( prevLag > 0 ) {
366885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            delta_lag_log2_sqr = lag_log2 - prevLag_log2;
367885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            delta_lag_log2_sqr *= delta_lag_log2_sqr;
368e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org            CCmax_new_b -= PE_PREVLAG_BIAS * nb_subfr * (*LTPCorr) * delta_lag_log2_sqr / ( delta_lag_log2_sqr + 0.5f );
369885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        }
370885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
371e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org        if( CCmax_new_b > CCmax_b &&                /* Find maximum biased correlation                  */
372e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org            CCmax_new > nb_subfr * search_thres2    /* Correlation needs to be high enough to be voiced */
373885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        ) {
374885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            CCmax_b = CCmax_new_b;
375885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            CCmax   = CCmax_new;
376885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            lag     = d;
377885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            CBimax  = CBimax_new;
378885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        }
379885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
380885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
381885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    if( lag == -1 ) {
382885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        /* No suitable candidate found */
383885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        silk_memset( pitch_out, 0, PE_MAX_NB_SUBFR * sizeof(opus_int) );
384885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        *LTPCorr      = 0.0f;
385885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        *lagIndex     = 0;
386885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        *contourIndex = 0;
387885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        return 1;
388885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
389885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
390e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org    /* Output normalized correlation */
391e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org    *LTPCorr = (silk_float)( CCmax / nb_subfr );
392e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org    silk_assert( *LTPCorr >= 0.0f );
393e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
394885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    if( Fs_kHz > 8 ) {
395885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        /* Search in original signal */
396885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
397885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        /* Compensate for decimation */
398885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        silk_assert( lag == silk_SAT16( lag ) );
399885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        if( Fs_kHz == 12 ) {
400885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            lag = silk_RSHIFT_ROUND( silk_SMULBB( lag, 3 ), 1 );
401885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        } else { /* Fs_kHz == 16 */
402885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            lag = silk_LSHIFT( lag, 1 );
403885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        }
404885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
405885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        lag = silk_LIMIT_int( lag, min_lag, max_lag );
406885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        start_lag = silk_max_int( lag - 2, min_lag );
407885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        end_lag   = silk_min_int( lag + 2, max_lag );
408885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        lag_new   = lag;                                    /* to avoid undefined lag */
409885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        CBimax    = 0;                                      /* to avoid undefined lag */
410885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
411885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        CCmax = -1000.0f;
412885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
413885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        /* Calculate the correlations and energies needed in stage 3 */
4143c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com        silk_P_Ana_calc_corr_st3( cross_corr_st3, frame, start_lag, sf_length, nb_subfr, complexity, arch );
415885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        silk_P_Ana_calc_energy_st3( energies_st3, frame, start_lag, sf_length, nb_subfr, complexity );
416885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
417885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        lag_counter = 0;
418885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        silk_assert( lag == silk_SAT16( lag ) );
419885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        contour_bias = PE_FLATCONTOUR_BIAS / lag;
420885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
4216b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org        /* Set up cbk parameters according to complexity setting and frame length */
422885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        if( nb_subfr == PE_MAX_NB_SUBFR ) {
423885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            nb_cbk_search = (opus_int)silk_nb_cbk_searchs_stage3[ complexity ];
424885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            cbk_size      = PE_NB_CBKS_STAGE3_MAX;
425885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            Lag_CB_ptr    = &silk_CB_lags_stage3[ 0 ][ 0 ];
426885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        } else {
427885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            nb_cbk_search = PE_NB_CBKS_STAGE3_10MS;
428885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            cbk_size      = PE_NB_CBKS_STAGE3_10MS;
429885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            Lag_CB_ptr    = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ];
430885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        }
431885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
432e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org        target_ptr = &frame[ PE_LTP_MEM_LENGTH_MS * Fs_kHz ];
433e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org        energy_tmp = silk_energy_FLP( target_ptr, nb_subfr * sf_length ) + 1.0;
434885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        for( d = start_lag; d <= end_lag; d++ ) {
435885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            for( j = 0; j < nb_cbk_search; j++ ) {
436885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                cross_corr = 0.0;
437e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org                energy = energy_tmp;
438885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                for( k = 0; k < nb_subfr; k++ ) {
439885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                    cross_corr += cross_corr_st3[ k ][ j ][ lag_counter ];
440e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org                    energy     +=   energies_st3[ k ][ j ][ lag_counter ];
441885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                }
442885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                if( cross_corr > 0.0 ) {
443e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org                    CCmax_new = (silk_float)( 2 * cross_corr / energy );
444885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                    /* Reduce depending on flatness of contour */
445885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                    CCmax_new *= 1.0f - contour_bias * j;
446885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                } else {
447885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                    CCmax_new = 0.0f;
448885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                }
449885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
450e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org                if( CCmax_new > CCmax && ( d + (opus_int)silk_CB_lags_stage3[ 0 ][ j ] ) <= max_lag ) {
451885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                    CCmax   = CCmax_new;
452885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                    lag_new = d;
453885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                    CBimax  = j;
454885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                }
455885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            }
456885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            lag_counter++;
457885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        }
458885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
459885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        for( k = 0; k < nb_subfr; k++ ) {
460885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            pitch_out[ k ] = lag_new + matrix_ptr( Lag_CB_ptr, k, CBimax, cbk_size );
461885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            pitch_out[ k ] = silk_LIMIT( pitch_out[ k ], min_lag, PE_MAX_LAG_MS * Fs_kHz );
462885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        }
463885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        *lagIndex = (opus_int16)( lag_new - min_lag );
464885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        *contourIndex = (opus_int8)CBimax;
465885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    } else {        /* Fs_kHz == 8 */
466e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org        /* Save Lags */
467885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        for( k = 0; k < nb_subfr; k++ ) {
468885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            pitch_out[ k ] = lag + matrix_ptr( Lag_CB_ptr, k, CBimax, cbk_size );
469e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org            pitch_out[ k ] = silk_LIMIT( pitch_out[ k ], min_lag_8kHz, PE_MAX_LAG_MS * 8 );
470885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        }
471885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        *lagIndex = (opus_int16)( lag - min_lag_8kHz );
472885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        *contourIndex = (opus_int8)CBimax;
473885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
474885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_assert( *lagIndex >= 0 );
475885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* return as voiced */
476885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    return 0;
477885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
478885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
479e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org/***********************************************************************
480e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org * Calculates the correlations used in stage 3 search. In order to cover
481e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org * the whole lag codebook for all the searched offset lags (lag +- 2),
482e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org * the following correlations are needed in each sub frame:
483e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org *
484e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org * sf1: lag range [-8,...,7] total 16 correlations
485e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org * sf2: lag range [-4,...,4] total 9 correlations
486e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org * sf3: lag range [-3,....4] total 8 correltions
487e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org * sf4: lag range [-6,....8] total 15 correlations
488e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org *
489e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org * In total 48 correlations. The direct implementation computed in worst
490e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org * case 4*12*5 = 240 correlations, but more likely around 120.
491e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org ***********************************************************************/
492885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgstatic void silk_P_Ana_calc_corr_st3(
493885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_float cross_corr_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ], /* O 3 DIM correlation array */
494885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const silk_float    frame[],            /* I vector to correlate                                            */
495885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int            start_lag,          /* I start lag                                                      */
496885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int            sf_length,          /* I sub frame length                                               */
497885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int            nb_subfr,           /* I number of subframes                                            */
4983c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com    opus_int            complexity,         /* I Complexity setting                                             */
4993c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com    int                 arch                /* I Run-time architecture                                          */
500885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org)
501885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{
5023c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com    const silk_float *target_ptr;
503885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int   i, j, k, lag_counter, lag_low, lag_high;
504885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int   nb_cbk_search, delta, idx, cbk_size;
505885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_float scratch_mem[ SCRATCH_SIZE ];
506e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org    opus_val32 xcorr[ SCRATCH_SIZE ];
507885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const opus_int8 *Lag_range_ptr, *Lag_CB_ptr;
508885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
509885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_assert( complexity >= SILK_PE_MIN_COMPLEX );
510885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_assert( complexity <= SILK_PE_MAX_COMPLEX );
511885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
512885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    if( nb_subfr == PE_MAX_NB_SUBFR ) {
513885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ];
514885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        Lag_CB_ptr    = &silk_CB_lags_stage3[ 0 ][ 0 ];
515885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        nb_cbk_search = silk_nb_cbk_searchs_stage3[ complexity ];
516885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        cbk_size      = PE_NB_CBKS_STAGE3_MAX;
517885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    } else {
518885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        silk_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1);
519885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        Lag_range_ptr = &silk_Lag_range_stage3_10_ms[ 0 ][ 0 ];
520885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        Lag_CB_ptr    = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ];
521885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        nb_cbk_search = PE_NB_CBKS_STAGE3_10MS;
522885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        cbk_size      = PE_NB_CBKS_STAGE3_10MS;
523885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
524885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
525885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    target_ptr = &frame[ silk_LSHIFT( sf_length, 2 ) ]; /* Pointer to middle of frame */
526885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    for( k = 0; k < nb_subfr; k++ ) {
527885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        lag_counter = 0;
528885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
529885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        /* Calculate the correlations for each subframe */
530885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        lag_low  = matrix_ptr( Lag_range_ptr, k, 0, 2 );
531885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        lag_high = matrix_ptr( Lag_range_ptr, k, 1, 2 );
532e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org        silk_assert(lag_high-lag_low+1 <= SCRATCH_SIZE);
5333c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com        celt_pitch_xcorr( target_ptr, target_ptr - start_lag - lag_high, xcorr, sf_length, lag_high - lag_low + 1, arch );
534885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        for( j = lag_low; j <= lag_high; j++ ) {
535885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            silk_assert( lag_counter < SCRATCH_SIZE );
536e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org            scratch_mem[ lag_counter ] = xcorr[ lag_high - j ];
537885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            lag_counter++;
538885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        }
539885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
540885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        delta = matrix_ptr( Lag_range_ptr, k, 0, 2 );
541885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        for( i = 0; i < nb_cbk_search; i++ ) {
542885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            /* Fill out the 3 dim array that stores the correlations for */
543885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            /* each code_book vector for each start lag */
544885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            idx = matrix_ptr( Lag_CB_ptr, k, i, cbk_size ) - delta;
545885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            for( j = 0; j < PE_NB_STAGE3_LAGS; j++ ) {
546885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                silk_assert( idx + j < SCRATCH_SIZE );
547885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                silk_assert( idx + j < lag_counter );
548885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                cross_corr_st3[ k ][ i ][ j ] = scratch_mem[ idx + j ];
549885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            }
550885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        }
551885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        target_ptr += sf_length;
552885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
553885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
554885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
555e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org/********************************************************************/
556e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org/* Calculate the energies for first two subframes. The energies are */
557e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org/* calculated recursively.                                          */
558e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org/********************************************************************/
559885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgstatic void silk_P_Ana_calc_energy_st3(
560885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_float energies_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ], /* O 3 DIM correlation array */
561885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const silk_float    frame[],            /* I vector to correlate                                            */
562885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int            start_lag,          /* I start lag                                                      */
563885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int            sf_length,          /* I sub frame length                                               */
564885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int            nb_subfr,           /* I number of subframes                                            */
565885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int            complexity          /* I Complexity setting                                             */
566885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org)
567885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{
568885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const silk_float *target_ptr, *basis_ptr;
569885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    double    energy;
570885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int   k, i, j, lag_counter;
571885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int   nb_cbk_search, delta, idx, cbk_size, lag_diff;
572885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_float scratch_mem[ SCRATCH_SIZE ];
573885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const opus_int8 *Lag_range_ptr, *Lag_CB_ptr;
574885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
575885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_assert( complexity >= SILK_PE_MIN_COMPLEX );
576885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_assert( complexity <= SILK_PE_MAX_COMPLEX );
577885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
578885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    if( nb_subfr == PE_MAX_NB_SUBFR ) {
579885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ];
580885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        Lag_CB_ptr    = &silk_CB_lags_stage3[ 0 ][ 0 ];
581885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        nb_cbk_search = silk_nb_cbk_searchs_stage3[ complexity ];
582885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        cbk_size      = PE_NB_CBKS_STAGE3_MAX;
583885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    } else {
584885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        silk_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1);
585885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        Lag_range_ptr = &silk_Lag_range_stage3_10_ms[ 0 ][ 0 ];
586885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        Lag_CB_ptr    = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ];
587885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        nb_cbk_search = PE_NB_CBKS_STAGE3_10MS;
588885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        cbk_size      = PE_NB_CBKS_STAGE3_10MS;
589885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
590885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
591885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    target_ptr = &frame[ silk_LSHIFT( sf_length, 2 ) ];
592885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    for( k = 0; k < nb_subfr; k++ ) {
593885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        lag_counter = 0;
594885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
595885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        /* Calculate the energy for first lag */
596885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        basis_ptr = target_ptr - ( start_lag + matrix_ptr( Lag_range_ptr, k, 0, 2 ) );
597885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        energy = silk_energy_FLP( basis_ptr, sf_length ) + 1e-3;
598885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        silk_assert( energy >= 0.0 );
599885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        scratch_mem[lag_counter] = (silk_float)energy;
600885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        lag_counter++;
601885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
602885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        lag_diff = ( matrix_ptr( Lag_range_ptr, k, 1, 2 ) -  matrix_ptr( Lag_range_ptr, k, 0, 2 ) + 1 );
603885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        for( i = 1; i < lag_diff; i++ ) {
604885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            /* remove part outside new window */
605885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            energy -= basis_ptr[sf_length - i] * (double)basis_ptr[sf_length - i];
606885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            silk_assert( energy >= 0.0 );
607885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
608885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            /* add part that comes into window */
609885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            energy += basis_ptr[ -i ] * (double)basis_ptr[ -i ];
610885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            silk_assert( energy >= 0.0 );
611885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            silk_assert( lag_counter < SCRATCH_SIZE );
612885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            scratch_mem[lag_counter] = (silk_float)energy;
613885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            lag_counter++;
614885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        }
615885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
616885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        delta = matrix_ptr( Lag_range_ptr, k, 0, 2 );
617885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        for( i = 0; i < nb_cbk_search; i++ ) {
618885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            /* Fill out the 3 dim array that stores the correlations for    */
619885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            /* each code_book vector for each start lag                     */
620885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            idx = matrix_ptr( Lag_CB_ptr, k, i, cbk_size ) - delta;
621885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            for( j = 0; j < PE_NB_STAGE3_LAGS; j++ ) {
622885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                silk_assert( idx + j < SCRATCH_SIZE );
623885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                silk_assert( idx + j < lag_counter );
624885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                energies_st3[ k ][ i ][ j ] = scratch_mem[ idx + j ];
625885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                silk_assert( energies_st3[ k ][ i ][ j ] >= 0.0f );
626885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            }
627885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        }
628885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        target_ptr += sf_length;
629885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
630885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
631