/*
 ** Copyright 2003-2010, VisualOn, Inc.
 **
 ** Licensed under the Apache License, Version 2.0 (the "License");
 ** you may not use this file except in compliance with the License.
 ** You may obtain a copy of the License at
 **
 **     http://www.apache.org/licenses/LICENSE-2.0
 **
 ** Unless required by applicable law or agreed to in writing, software
 ** distributed under the License is distributed on an "AS IS" BASIS,
 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 ** See the License for the specific language governing permissions and
 ** limitations under the License.
 */


/***********************************************************************
*       File: autocorr.c                                               *
*                                                                      *
*       Description:Compute autocorrelations of signal with windowing  *
*                                                                      *
************************************************************************/

#include "typedef.h"
#include "basic_op.h"
#include "oper_32b.h"
#include "acelp.h"
#include "ham_wind.tab"

void Autocorr(
		Word16 x[],                           /* (i)    : Input signal                      */
		Word16 m,                             /* (i)    : LPC order                         */
		Word16 r_h[],                         /* (o) Q15: Autocorrelations  (msb)           */
		Word16 r_l[]                          /* (o)    : Autocorrelations  (lsb)           */
	     )
{
	Word32 i, norm, shift;
	Word16 y[L_WINDOW];
	Word32 L_sum, L_sum1, L_tmp, F_LEN;
	Word16 *p1,*p2,*p3;
	const Word16 *p4;
	/* Windowing of signal */
	p1 = x;
	p4 = vo_window;
	p3 = y;

	for (i = 0; i < L_WINDOW; i+=4)
	{
		*p3++ = vo_mult_r((*p1++), (*p4++));
		*p3++ = vo_mult_r((*p1++), (*p4++));
		*p3++ = vo_mult_r((*p1++), (*p4++));
		*p3++ = vo_mult_r((*p1++), (*p4++));
	}

	/* calculate energy of signal */
	L_sum = vo_L_deposit_h(16);               /* sqrt(256), avoid overflow after rounding */
	for (i = 0; i < L_WINDOW; i++)
	{
		L_tmp = vo_L_mult(y[i], y[i]);
		L_tmp = (L_tmp >> 8);
		L_sum += L_tmp;
	}

	/* scale signal to avoid overflow in autocorrelation */
	norm = norm_l(L_sum);
	shift = 4 - (norm >> 1);
	if(shift > 0)
	{
		p1 = y;
		for (i = 0; i < L_WINDOW; i+=4)
		{
			*p1 = vo_shr_r(*p1, shift);
			p1++;
			*p1 = vo_shr_r(*p1, shift);
			p1++;
			*p1 = vo_shr_r(*p1, shift);
			p1++;
			*p1 = vo_shr_r(*p1, shift);
			p1++;
		}
	}

	/* Compute and normalize r[0] */
	L_sum = 1;
	for (i = 0; i < L_WINDOW; i+=4)
	{
		L_sum += vo_L_mult(y[i], y[i]);
		L_sum += vo_L_mult(y[i+1], y[i+1]);
		L_sum += vo_L_mult(y[i+2], y[i+2]);
		L_sum += vo_L_mult(y[i+3], y[i+3]);
	}

	norm = norm_l(L_sum);
	L_sum = (L_sum << norm);

	r_h[0] = L_sum >> 16;
	r_l[0] = (L_sum & 0xffff)>>1;

	/* Compute r[1] to r[m] */
	for (i = 1; i <= 8; i++)
	{
		L_sum1 = 0;
		L_sum = 0;
		F_LEN = (Word32)(L_WINDOW - 2*i);
		p1 = y;
		p2 = y + (2*i)-1;
		do{
			L_sum1 += *p1 * *p2++;
			L_sum += *p1++ * *p2;
		}while(--F_LEN!=0);

		L_sum1 += *p1 * *p2++;

		L_sum1 = L_sum1<<norm;
		L_sum = L_sum<<norm;

		r_h[(2*i)-1] = L_sum1 >> 15;
		r_l[(2*i)-1] = L_sum1 & 0x00007fff;
		r_h[(2*i)] = L_sum >> 15;
		r_l[(2*i)] = L_sum & 0x00007fff;
	}
	return;
}



