/*
***********************************************************************
*
* Copyright (C) 1999 Ericsson Radio Systems AB
* 
* The Association of Radio Industries and Businesses (ARIB) has the
* licence to reproduce, distribute and publish the Bit Exact C Code
* programs in this CD-ROM together with the other parts of the RCR
* STD-27 (Personal Digital Cellular Telecommunication System)
* specification.
* 
* Ericsson has declared Option 1 (royalty-free licence) to ARIB for
* its Essential Industrial Property Rights related to the ACELP
* specification and the Bit Exact C Code programs. The royalty-free
* licence is limited to the development and manufacturing of
* products complying with the RCR STD-27H specification (or
* subsequent versions) for sale and use in Japan. Copying of the
* program(s) for any other purpose requires the prior written
* permission from Ericsson.
* 
* The user of the Bit Exact C Code hereby acknowledges the
* following:
* 
* 1.  Ericsson does not provide the user with any warranties,
*     whether express or implied, including but not limited to
*     warranties of merchantability and fitness for a particular
*     purpose relating to the Bit Exact C Code.
* 
* 2.  Ericsson shall have no responsibility whatsoever to indemnify
*     the user against actions or claims for infringement of any
*     intellectual property rights, e.g. patents, copyrights,
*     registered designs or any other rights, by reason of the
*     user's use of the Bit Exact C Code.
* 
***********************************************************************
*/

/*************************************************************************
 *
 *  FILE NAME:   postfilter.c
 *
 * Performs adaptive postfiltering on the synthesis speech
 *
 *  FUNCTIONS INCLUDED:  Init_Post_Filter()  and Post_Filter()
 *
 *************************************************************************/

#include "typedef.h"
#include "basic_op.h"
#include "sig_proc.h"
#include "codec.h"
#include "cnst.h"

/*---------------------------------------------------------------*
 *    Postfilter constant parameters (defined in "cnst.h")       *
 *---------------------------------------------------------------*
 *   L_FRAME     : Frame size.                                   *
 *   L_SUBFR     : Sub-frame size.                               *
 *   M           : LPC order.                                    *
 *   MP1         : LPC order+1                                   *
 *   PIT_MAX     : Maximum pitch lag.                            *
 *   GAMMA3      : Formant postfiltering factor (numerator)      *
 *   GAMMA4      : Formant postfiltering factor (denominator)    *
 *   GAMMAP      : Harmonic postfiltering factor                 *
 *   MU          : Factor for tilt compensation filter           *
 *   AGC_FAC     : Factor for automatic gain control             *
 *---------------------------------------------------------------*/

#define L_H 22  /* size of truncated impulse response of A(z/g1)/A(z/g2) */

/*------------------------------------------------------------*
 *   static vectors                                           *
 *------------------------------------------------------------*/

 /* memory of filter 1/A(z/GAMMA4) */

static Word16 mem_syn_pst[M];

 /* Spectral expansion factors */

static Word16 F_gamma3[M];
static Word16 F_gamma4[M];

/*************************************************************************
 *
 *  FUNCTION:   Init_Post_Filter
 *
 *  PURPOSE: Initializes the postfilter parameters.
 *
 *************************************************************************/

void Init_Post_Filter(void)
{
    Set_zero(mem_syn_pst, M);

    /* Compute LPC spectral expansion factors */

    Weight_Fac(GAMMA3, F_gamma3);
    Weight_Fac(GAMMA4, F_gamma4);

    return;
}


/*************************************************************************
 *  FUNCTION:  Post_Filter()
 *
 *  PURPOSE:  postfiltering of synthesis speech.
 *
 *  DESCRIPTION:
 *      The postfiltering process is described as follows:
 *
 *          - inverse filtering of syn[] through A(z/GAMMA3) to get res2[]
 *          - tilt compensation filtering; 1 - MU*k*z^-1
 *          - synthesis filtering through 1/A(z/GAMMA4)
 *          - adaptive gain control
 *
 *************************************************************************/

void Post_Filter(
    Word16 * syn,  /* in/out: synthesis speech (postfiltered is output)    */
    Word16 * Az_4  /* input : interpolated LPC parameters in all subframes */
)
{
 /*-------------------------------------------------------------------*
  *           Decleration of parameters                               *
  *-------------------------------------------------------------------*/


    Word16 res2[L_SUBFR];       /* inverse filtered synthesis */

    Word16 syn_pst[L_FRAME];    /* post filtered synthesis speech   */

    Word16 Ap3[MP1], Ap4[MP1];  /* bandwidth expanded LP parameters */

    Word16 *Az;                 /* pointer to Az_4:                 */
    /*  LPC parameters in each subframe */
    Word16 i_subfr;             /* index for beginning of subframe  */

    Word16 h[L_H];

    Word16 i;
    Word16 temp1, temp2;
    Word32 L_tmp;

   /*-----------------------------------------------------*
    * Post filtering                                      *
    *-----------------------------------------------------*/

    Az = Az_4;

    for (i_subfr = 0; i_subfr < L_FRAME; i_subfr += L_SUBFR) {
        /* Find weighted filter coefficients Ap3[] and ap[4] */

        Weight_Ai(Az, F_gamma3, Ap3);
        Weight_Ai(Az, F_gamma4, Ap4);

        /* filtering of synthesis speech by A(z/GAMMA3) to find res2[] */

        Residu(Ap3, &syn[i_subfr], res2, L_SUBFR);

        /* tilt compensation filter */

        /* impulse response of A(z/gamma3)/A(z/gamma4) */

        Copy(Ap3, h, M + 1);
        Set_zero(&h[M + 1], L_H - M - 1);
        Syn_filt(Ap4, h, h, L_H, &h[M + 1], 0);

        /* 1st correlation of h[] */

        L_tmp = L_mult(h[0], h[0]);
        for (i = 1; i < L_H; i++)
            L_tmp = L_mac(L_tmp, h[i], h[i]);
        temp1 = extract_h(L_tmp);

        L_tmp = L_mult(h[0], h[1]);
        for (i = 1; i < L_H - 1; i++)
            L_tmp = L_mac(L_tmp, h[i], h[i + 1]);
        temp2 = extract_h(L_tmp);

        if (temp2 <= 0) {
            temp2 = 0;
        } else {
            temp2 = mult(temp2, MU);
            temp2 = div_s(temp2, temp1);
        }

        preemphasis(res2, temp2, L_SUBFR);

        /* filtering through  1/A(z/GAMMA4) */

        Syn_filt(Ap4, res2, &syn_pst[i_subfr], L_SUBFR, mem_syn_pst, 1);

        /* scale output to input */

        agc(&syn[i_subfr], &syn_pst[i_subfr], AGC_FAC, L_SUBFR);

        Az += MP1;
    }
    /* update syn[] buffer */

    Copy(&syn[L_FRAME - M], &syn[-M], M);

    /* overwrite synthesis speech by postfiltered synthesis speech */

    Copy(syn_pst, syn, L_FRAME);

    return;
}
