/* SKP_Silk_prefilter. Prefilter for finding Quantizer input signal                           */
SKP_INLINE void SKP_Silk_prefilt_FIX(
    SKP_Silk_prefilter_state_FIX *P,                    /* I/O state                          */
    SKP_int32   st_res_Q12[],                           /* I short term residual signal       */
    SKP_int16   xw[],                                   /* O prefiltered signal               */
    SKP_int32   HarmShapeFIRPacked_Q12,                 /* I Harmonic shaping coeficients     */
    SKP_int     Tilt_Q14,                               /* I Tilt shaping coeficient          */
    SKP_int32   LF_shp_Q14,                             /* I Low-frequancy shaping coeficients*/
    SKP_int     lag,                                    /* I Lag for harmonic shaping         */
    SKP_int     length                                  /* I Length of signals                */
)
{
    SKP_int   i, idx, LTP_shp_buf_idx;
    SKP_int32 n_LTP_Q12, n_Tilt_Q10, n_LF_Q10;
    SKP_int32 sLF_MA_shp_Q12, sLF_AR_shp_Q12;
    SKP_int16 *LTP_shp_buf;

    /* To speed up use temp variables instead of using the struct */
    LTP_shp_buf     = P->sLTP_shp;
    LTP_shp_buf_idx = P->sLTP_shp_buf_idx;
    sLF_AR_shp_Q12  = P->sLF_AR_shp_Q12;
    sLF_MA_shp_Q12  = P->sLF_MA_shp_Q12;

    for( i = 0; i < length; i++ ) {
        if( lag > 0 ) {
            /* unrolled loop */
            SKP_assert( HARM_SHAPE_FIR_TAPS == 3 );
            idx = lag + LTP_shp_buf_idx;
            n_LTP_Q12 = SKP_SMULBB(            LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 - 1) & LTP_MASK ], HarmShapeFIRPacked_Q12 );
            n_LTP_Q12 = SKP_SMLABT( n_LTP_Q12, LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2    ) & LTP_MASK ], HarmShapeFIRPacked_Q12 );
            n_LTP_Q12 = SKP_SMLABB( n_LTP_Q12, LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 + 1) & LTP_MASK ], HarmShapeFIRPacked_Q12 );
        } else {
            n_LTP_Q12 = 0;
        }

        n_Tilt_Q10 = SKP_SMULWB( sLF_AR_shp_Q12, Tilt_Q14 );
        n_LF_Q10   = SKP_SMLAWB( SKP_SMULWT( sLF_AR_shp_Q12, LF_shp_Q14 ), sLF_MA_shp_Q12, LF_shp_Q14 );

        sLF_AR_shp_Q12 = SKP_SUB32( st_res_Q12[ i ], SKP_LSHIFT( n_Tilt_Q10, 2 ) );
        sLF_MA_shp_Q12 = SKP_SUB32( sLF_AR_shp_Q12,  SKP_LSHIFT( n_LF_Q10,   2 ) );

        LTP_shp_buf_idx = ( LTP_shp_buf_idx - 1 ) & LTP_MASK;
        LTP_shp_buf[ LTP_shp_buf_idx ] = ( SKP_int16 )SKP_SAT16( SKP_RSHIFT_ROUND( sLF_MA_shp_Q12, 12 ) );

        xw[i] = ( SKP_int16 )SKP_SAT16( SKP_RSHIFT_ROUND( SKP_SUB32( sLF_MA_shp_Q12, n_LTP_Q12 ), 12 ) );
    }

    /* Copy temp variable back to state */
    P->sLF_AR_shp_Q12   = sLF_AR_shp_Q12;
    P->sLF_MA_shp_Q12   = sLF_MA_shp_Q12;
    P->sLTP_shp_buf_idx = LTP_shp_buf_idx;
}
/* Entropy constrained MATRIX-weighted VQ, hard-coded to 5-element vectors, for a single input data vector */
void SKP_Silk_VQ_WMat_EC_FIX(int *ind,	/* O    index of best codebook vector               */
			     int32_t * rate_dist_Q14,	/* O    best weighted quantization error + mu * rate */
			     const int16_t * in_Q14,	/* I    input vector to be quantized                */
			     const int32_t * W_Q18,	/* I    weighting matrix                            */
			     const int16_t * cb_Q14,	/* I    codebook                                    */
			     const int16_t * cl_Q6,	/* I    code length for each codebook vector        */
			     const int mu_Q8,	/* I    tradeoff between weighted error and rate    */
			     int L	/* I    number of vectors in codebook               */
    )
{
	int k;
	const int16_t *cb_row_Q14;
	int32_t sum1_Q14, sum2_Q16, diff_Q14_01, diff_Q14_23, diff_Q14_4;

	/* Loop over codebook */
	*rate_dist_Q14 = int32_t_MAX;
	cb_row_Q14 = cb_Q14;
	for (k = 0; k < L; k++) {
		/* Pack pairs of int16 values per int32 */
		diff_Q14_01 =
		    (uint16_t) (in_Q14[0] -
				cb_row_Q14[0]) | SKP_LSHIFT((int32_t) in_Q14[1]
							    - cb_row_Q14[1],
							    16);
		diff_Q14_23 =
		    (uint16_t) (in_Q14[2] -
				cb_row_Q14[2]) | SKP_LSHIFT((int32_t) in_Q14[3]
							    - cb_row_Q14[3],
							    16);
		diff_Q14_4 = in_Q14[4] - cb_row_Q14[4];

		/* Weighted rate */
		sum1_Q14 = SKP_SMULBB(mu_Q8, cl_Q6[k]);

		assert(sum1_Q14 >= 0);

		/* Add weighted quantization error, assuming W_Q18 is symmetric */
		/* NOTE: the code below loads two int16 values as one int32, and multiplies each using the  */
		/* SMLAWB and SMLAWT instructions. On a big-endian CPU the two int16 variables would be     */
		/* loaded in reverse order and the code will give the wrong result. In that case swapping   */
		/* the SMLAWB and SMLAWT instructions should solve the problem.                             */
		/* first row of W_Q18 */
		sum2_Q16 = SKP_SMULWT(W_Q18[1], diff_Q14_01);
		sum2_Q16 = SKP_SMLAWB(sum2_Q16, W_Q18[2], diff_Q14_23);
		sum2_Q16 = SKP_SMLAWT(sum2_Q16, W_Q18[3], diff_Q14_23);
		sum2_Q16 = SKP_SMLAWB(sum2_Q16, W_Q18[4], diff_Q14_4);
		sum2_Q16 = SKP_LSHIFT(sum2_Q16, 1);
		sum2_Q16 = SKP_SMLAWB(sum2_Q16, W_Q18[0], diff_Q14_01);
		sum1_Q14 = SKP_SMLAWB(sum1_Q14, sum2_Q16, diff_Q14_01);

		/* second row of W_Q18 */
		sum2_Q16 = SKP_SMULWB(W_Q18[7], diff_Q14_23);
		sum2_Q16 = SKP_SMLAWT(sum2_Q16, W_Q18[8], diff_Q14_23);
		sum2_Q16 = SKP_SMLAWB(sum2_Q16, W_Q18[9], diff_Q14_4);
		sum2_Q16 = SKP_LSHIFT(sum2_Q16, 1);
		sum2_Q16 = SKP_SMLAWT(sum2_Q16, W_Q18[6], diff_Q14_01);
		sum1_Q14 = SKP_SMLAWT(sum1_Q14, sum2_Q16, diff_Q14_01);

		/* third row of W_Q18 */
		sum2_Q16 = SKP_SMULWT(W_Q18[13], diff_Q14_23);
		sum2_Q16 = SKP_SMLAWB(sum2_Q16, W_Q18[14], diff_Q14_4);
		sum2_Q16 = SKP_LSHIFT(sum2_Q16, 1);
		sum2_Q16 = SKP_SMLAWB(sum2_Q16, W_Q18[12], diff_Q14_23);
		sum1_Q14 = SKP_SMLAWB(sum1_Q14, sum2_Q16, diff_Q14_23);

		/* fourth row of W_Q18 */
		sum2_Q16 = SKP_SMULWB(W_Q18[19], diff_Q14_4);
		sum2_Q16 = SKP_LSHIFT(sum2_Q16, 1);
		sum2_Q16 = SKP_SMLAWT(sum2_Q16, W_Q18[18], diff_Q14_23);
		sum1_Q14 = SKP_SMLAWT(sum1_Q14, sum2_Q16, diff_Q14_23);

		/* last row of W_Q18 */
		sum2_Q16 = SKP_SMULWB(W_Q18[24], diff_Q14_4);
		sum1_Q14 = SKP_SMLAWB(sum1_Q14, sum2_Q16, diff_Q14_4);

		assert(sum1_Q14 >= 0);

		/* find best */
		if (sum1_Q14 < *rate_dist_Q14) {
			*rate_dist_Q14 = sum1_Q14;
			*ind = k;
		}

		/* Go to next cbk vector */
		cb_row_Q14 += LTP_ORDER;
	}
}