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.h"
33e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#include "stack_alloc.h"
34885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
35885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/* Convert Left/Right stereo signal to adaptive Mid/Side representation */
36885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgvoid silk_stereo_LR_to_MS(
37885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    stereo_enc_state            *state,                         /* I/O  State                                       */
38885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int16                  x1[],                           /* I/O  Left input signal, becomes mid signal       */
39885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int16                  x2[],                           /* I/O  Right input signal, becomes side signal     */
40885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int8                   ix[ 2 ][ 3 ],                   /* O    Quantization indices                        */
41885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int8                   *mid_only_flag,                 /* O    Flag: only mid signal coded                 */
42885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int32                  mid_side_rates_bps[],           /* O    Bitrates for mid and side signals           */
43885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int32                  total_rate_bps,                 /* I    Total bitrate                               */
44885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int                    prev_speech_act_Q8,             /* I    Speech activity level in previous frame     */
45885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int                    toMono,                         /* I    Last frame before a stereo->mono transition */
46885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int                    fs_kHz,                         /* I    Sample rate (kHz)                           */
47885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int                    frame_length                    /* I    Number of samples                           */
48885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org)
49885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{
50885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int   n, is10msFrame, denom_Q16, delta0_Q13, delta1_Q13;
51885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int32 sum, diff, smooth_coef_Q16, pred_Q13[ 2 ], pred0_Q13, pred1_Q13;
52885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int32 LP_ratio_Q14, HP_ratio_Q14, frac_Q16, frac_3_Q16, min_mid_rate_bps, width_Q14, w_Q24, deltaw_Q24;
53e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org    VARDECL( opus_int16, side );
54e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org    VARDECL( opus_int16, LP_mid );
55e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org    VARDECL( opus_int16, HP_mid );
56e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org    VARDECL( opus_int16, LP_side );
57e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org    VARDECL( opus_int16, HP_side );
58885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    opus_int16 *mid = &x1[ -2 ];
59e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org    SAVE_STACK;
60885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
61e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org    ALLOC( side, frame_length + 2, opus_int16 );
62885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* Convert to basic mid/side signals */
63885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    for( n = 0; n < frame_length + 2; n++ ) {
64885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        sum  = x1[ n - 2 ] + (opus_int32)x2[ n - 2 ];
65885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        diff = x1[ n - 2 ] - (opus_int32)x2[ n - 2 ];
66885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        mid[  n ] = (opus_int16)silk_RSHIFT_ROUND( sum, 1 );
67885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        side[ n ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( diff, 1 ) );
68885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
69885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
70885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* Buffering */
71885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_memcpy( mid,  state->sMid,  2 * sizeof( opus_int16 ) );
72885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_memcpy( side, state->sSide, 2 * sizeof( opus_int16 ) );
73885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_memcpy( state->sMid,  &mid[  frame_length ], 2 * sizeof( opus_int16 ) );
74885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_memcpy( state->sSide, &side[ frame_length ], 2 * sizeof( opus_int16 ) );
75885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
76885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* LP and HP filter mid signal */
77e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org    ALLOC( LP_mid, frame_length, opus_int16 );
78e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org    ALLOC( HP_mid, frame_length, opus_int16 );
79885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    for( n = 0; n < frame_length; n++ ) {
80885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        sum = silk_RSHIFT_ROUND( silk_ADD_LSHIFT( mid[ n ] + mid[ n + 2 ], mid[ n + 1 ], 1 ), 2 );
81885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        LP_mid[ n ] = sum;
82885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        HP_mid[ n ] = mid[ n + 1 ] - sum;
83885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
84885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
85885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* LP and HP filter side signal */
86e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org    ALLOC( LP_side, frame_length, opus_int16 );
87e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org    ALLOC( HP_side, frame_length, opus_int16 );
88885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    for( n = 0; n < frame_length; n++ ) {
89885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        sum = silk_RSHIFT_ROUND( silk_ADD_LSHIFT( side[ n ] + side[ n + 2 ], side[ n + 1 ], 1 ), 2 );
90885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        LP_side[ n ] = sum;
91885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        HP_side[ n ] = side[ n + 1 ] - sum;
92885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
93885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
94885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* Find energies and predictors */
95885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    is10msFrame = frame_length == 10 * fs_kHz;
96885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    smooth_coef_Q16 = is10msFrame ?
97885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        SILK_FIX_CONST( STEREO_RATIO_SMOOTH_COEF / 2, 16 ) :
98885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        SILK_FIX_CONST( STEREO_RATIO_SMOOTH_COEF,     16 );
99885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    smooth_coef_Q16 = silk_SMULWB( silk_SMULBB( prev_speech_act_Q8, prev_speech_act_Q8 ), smooth_coef_Q16 );
100885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
101885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    pred_Q13[ 0 ] = silk_stereo_find_predictor( &LP_ratio_Q14, LP_mid, LP_side, &state->mid_side_amp_Q0[ 0 ], frame_length, smooth_coef_Q16 );
102885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    pred_Q13[ 1 ] = silk_stereo_find_predictor( &HP_ratio_Q14, HP_mid, HP_side, &state->mid_side_amp_Q0[ 2 ], frame_length, smooth_coef_Q16 );
103885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* Ratio of the norms of residual and mid signals */
104885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    frac_Q16 = silk_SMLABB( HP_ratio_Q14, LP_ratio_Q14, 3 );
105885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    frac_Q16 = silk_min( frac_Q16, SILK_FIX_CONST( 1, 16 ) );
106885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
107885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* Determine bitrate distribution between mid and side, and possibly reduce stereo width */
108885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    total_rate_bps -= is10msFrame ? 1200 : 600;      /* Subtract approximate bitrate for coding stereo parameters */
109885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    if( total_rate_bps < 1 ) {
110885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        total_rate_bps = 1;
111885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
112885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    min_mid_rate_bps = silk_SMLABB( 2000, fs_kHz, 900 );
113885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    silk_assert( min_mid_rate_bps < 32767 );
114885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* Default bitrate distribution: 8 parts for Mid and (5+3*frac) parts for Side. so: mid_rate = ( 8 / ( 13 + 3 * frac ) ) * total_ rate */
115885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    frac_3_Q16 = silk_MUL( 3, frac_Q16 );
116885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    mid_side_rates_bps[ 0 ] = silk_DIV32_varQ( total_rate_bps, SILK_FIX_CONST( 8 + 5, 16 ) + frac_3_Q16, 16+3 );
117885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* If Mid bitrate below minimum, reduce stereo width */
118885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    if( mid_side_rates_bps[ 0 ] < min_mid_rate_bps ) {
119885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        mid_side_rates_bps[ 0 ] = min_mid_rate_bps;
120885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        mid_side_rates_bps[ 1 ] = total_rate_bps - mid_side_rates_bps[ 0 ];
121885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        /* width = 4 * ( 2 * side_rate - min_rate ) / ( ( 1 + 3 * frac ) * min_rate ) */
122885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        width_Q14 = silk_DIV32_varQ( silk_LSHIFT( mid_side_rates_bps[ 1 ], 1 ) - min_mid_rate_bps,
123885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            silk_SMULWB( SILK_FIX_CONST( 1, 16 ) + frac_3_Q16, min_mid_rate_bps ), 14+2 );
124885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        width_Q14 = silk_LIMIT( width_Q14, 0, SILK_FIX_CONST( 1, 14 ) );
125885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    } else {
126885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        mid_side_rates_bps[ 1 ] = total_rate_bps - mid_side_rates_bps[ 0 ];
127885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        width_Q14 = SILK_FIX_CONST( 1, 14 );
128885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
129885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
130885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* Smoother */
131885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    state->smth_width_Q14 = (opus_int16)silk_SMLAWB( state->smth_width_Q14, width_Q14 - state->smth_width_Q14, smooth_coef_Q16 );
132885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
133885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* At very low bitrates or for inputs that are nearly amplitude panned, switch to panned-mono coding */
134885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    *mid_only_flag = 0;
135885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    if( toMono ) {
136885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        /* Last frame before stereo->mono transition; collapse stereo width */
137885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        width_Q14 = 0;
138885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        pred_Q13[ 0 ] = 0;
139885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        pred_Q13[ 1 ] = 0;
140885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        silk_stereo_quant_pred( pred_Q13, ix );
141885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    } else if( state->width_prev_Q14 == 0 &&
142885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        ( 8 * total_rate_bps < 13 * min_mid_rate_bps || silk_SMULWB( frac_Q16, state->smth_width_Q14 ) < SILK_FIX_CONST( 0.05, 14 ) ) )
143885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    {
144885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        /* Code as panned-mono; previous frame already had zero width */
145885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        /* Scale down and quantize predictors */
146885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        pred_Q13[ 0 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 0 ] ), 14 );
147885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        pred_Q13[ 1 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 1 ] ), 14 );
148885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        silk_stereo_quant_pred( pred_Q13, ix );
149885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        /* Collapse stereo width */
150885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        width_Q14 = 0;
151885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        pred_Q13[ 0 ] = 0;
152885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        pred_Q13[ 1 ] = 0;
153885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        mid_side_rates_bps[ 0 ] = total_rate_bps;
154885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        mid_side_rates_bps[ 1 ] = 0;
155885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        *mid_only_flag = 1;
156885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    } else if( state->width_prev_Q14 != 0 &&
157885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        ( 8 * total_rate_bps < 11 * min_mid_rate_bps || silk_SMULWB( frac_Q16, state->smth_width_Q14 ) < SILK_FIX_CONST( 0.02, 14 ) ) )
158885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    {
159885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        /* Transition to zero-width stereo */
160885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        /* Scale down and quantize predictors */
161885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        pred_Q13[ 0 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 0 ] ), 14 );
162885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        pred_Q13[ 1 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 1 ] ), 14 );
163885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        silk_stereo_quant_pred( pred_Q13, ix );
164885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        /* Collapse stereo width */
165885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        width_Q14 = 0;
166885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        pred_Q13[ 0 ] = 0;
167885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        pred_Q13[ 1 ] = 0;
168885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    } else if( state->smth_width_Q14 > SILK_FIX_CONST( 0.95, 14 ) ) {
169885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        /* Full-width stereo coding */
170885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        silk_stereo_quant_pred( pred_Q13, ix );
171885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        width_Q14 = SILK_FIX_CONST( 1, 14 );
172885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    } else {
173885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        /* Reduced-width stereo coding; scale down and quantize predictors */
174885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        pred_Q13[ 0 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 0 ] ), 14 );
175885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        pred_Q13[ 1 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 1 ] ), 14 );
176885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        silk_stereo_quant_pred( pred_Q13, ix );
177885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        width_Q14 = state->smth_width_Q14;
178885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
179885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
180885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* Make sure to keep on encoding until the tapered output has been transmitted */
181885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    if( *mid_only_flag == 1 ) {
182885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        state->silent_side_len += frame_length - STEREO_INTERP_LEN_MS * fs_kHz;
183885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        if( state->silent_side_len < LA_SHAPE_MS * fs_kHz ) {
184885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            *mid_only_flag = 0;
185885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        } else {
186885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            /* Limit to avoid wrapping around */
187885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            state->silent_side_len = 10000;
188885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        }
189885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    } else {
190885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        state->silent_side_len = 0;
191885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
192885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
193885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    if( *mid_only_flag == 0 && mid_side_rates_bps[ 1 ] < 1 ) {
194885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        mid_side_rates_bps[ 1 ] = 1;
195885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        mid_side_rates_bps[ 0 ] = silk_max_int( 1, total_rate_bps - mid_side_rates_bps[ 1 ]);
196885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
197885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
198885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    /* Interpolate predictors and subtract prediction from side channel */
199885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    pred0_Q13  = -state->pred_prev_Q13[ 0 ];
200885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    pred1_Q13  = -state->pred_prev_Q13[ 1 ];
201885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    w_Q24      =  silk_LSHIFT( state->width_prev_Q14, 10 );
202885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    denom_Q16  = silk_DIV32_16( (opus_int32)1 << 16, STEREO_INTERP_LEN_MS * fs_kHz );
203885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    delta0_Q13 = -silk_RSHIFT_ROUND( silk_SMULBB( pred_Q13[ 0 ] - state->pred_prev_Q13[ 0 ], denom_Q16 ), 16 );
204885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    delta1_Q13 = -silk_RSHIFT_ROUND( silk_SMULBB( pred_Q13[ 1 ] - state->pred_prev_Q13[ 1 ], denom_Q16 ), 16 );
205885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    deltaw_Q24 =  silk_LSHIFT( silk_SMULWB( width_Q14 - state->width_prev_Q14, denom_Q16 ), 10 );
206885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    for( n = 0; n < STEREO_INTERP_LEN_MS * fs_kHz; n++ ) {
207885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        pred0_Q13 += delta0_Q13;
208885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        pred1_Q13 += delta1_Q13;
209885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        w_Q24   += deltaw_Q24;
210885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        sum = silk_LSHIFT( silk_ADD_LSHIFT( mid[ n ] + mid[ n + 2 ], mid[ n + 1 ], 1 ), 9 );    /* Q11 */
211885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        sum = silk_SMLAWB( silk_SMULWB( w_Q24, side[ n + 1 ] ), sum, pred0_Q13 );               /* Q8  */
212885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        sum = silk_SMLAWB( sum, silk_LSHIFT( (opus_int32)mid[ n + 1 ], 11 ), pred1_Q13 );       /* Q8  */
213885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        x2[ n - 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sum, 8 ) );
214885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
215885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
216885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    pred0_Q13 = -pred_Q13[ 0 ];
217885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    pred1_Q13 = -pred_Q13[ 1 ];
218885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    w_Q24     =  silk_LSHIFT( width_Q14, 10 );
219885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    for( n = STEREO_INTERP_LEN_MS * fs_kHz; n < frame_length; n++ ) {
220885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        sum = silk_LSHIFT( silk_ADD_LSHIFT( mid[ n ] + mid[ n + 2 ], mid[ n + 1 ], 1 ), 9 );    /* Q11 */
221885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        sum = silk_SMLAWB( silk_SMULWB( w_Q24, side[ n + 1 ] ), sum, pred0_Q13 );               /* Q8  */
222885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        sum = silk_SMLAWB( sum, silk_LSHIFT( (opus_int32)mid[ n + 1 ], 11 ), pred1_Q13 );       /* Q8  */
223885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        x2[ n - 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sum, 8 ) );
224885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
225885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    state->pred_prev_Q13[ 0 ] = (opus_int16)pred_Q13[ 0 ];
226885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    state->pred_prev_Q13[ 1 ] = (opus_int16)pred_Q13[ 1 ];
227885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    state->width_prev_Q14     = (opus_int16)width_Q14;
228e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org    RESTORE_STACK;
229885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
230