/*
 ** 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"

#define UNUSED(x) (void)(x)

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;
        UNUSED(m);

    /* 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;
}



