/*
 ** 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: apisf_2s.c                                               *
*                                                                      *
*       Description: Coding/Decodeing of ISF parameters with predication
*       The ISF vector is quantized using two-stage VQ with split-by-2 *
*       in 1st stage and split-by-5(or 3) in the second stage          *
*                                                                      *
************************************************************************/

#include "typedef.h"
#include "basic_op.h"
#include "cnst.h"
#include "acelp.h"
#include "qpisf_2s.tab"                    /* Codebooks of isfs */

#define MU         10923                   /* Prediction factor   (1.0/3.0) in Q15 */
#define N_SURV_MAX 4                       /* 4 survivors max */
#define ALPHA      29491                   /* 0. 9 in Q15     */
#define ONE_ALPHA (32768-ALPHA)            /* (1.0 - ALPHA) in Q15 */

/* private functions */
static void VQ_stage1(
		Word16 * x,                           /* input : ISF residual vector           */
		Word16 * dico,                        /* input : quantization codebook         */
		Word16 dim,                           /* input : dimention of vector           */
		Word16 dico_size,                     /* input : size of quantization codebook */
		Word16 * index,                       /* output: indices of survivors          */
		Word16 surv                           /* input : number of survivor            */
		);

/**************************************************************************
* Function:   Qpisf_2s_46B()                                              *
*                                                                         *
* Description: Quantization of isf parameters with prediction. (46 bits)  *
*                                                                         *
* The isf vector is quantized using two-stage VQ with split-by-2 in       *
*  1st stage and split-by-5 in the second stage.                          *
***************************************************************************/

void Qpisf_2s_46b(
		Word16 * isf1,                        /* (i) Q15 : ISF in the frequency domain (0..0.5) */
		Word16 * isf_q,                       /* (o) Q15 : quantized ISF               (0..0.5) */
		Word16 * past_isfq,                   /* (io)Q15 : past ISF quantizer                   */
		Word16 * indice,                      /* (o)     : quantization indices                 */
		Word16 nb_surv                        /* (i)     : number of survivor (1, 2, 3 or 4)    */
		)
{
	Word16 tmp_ind[5];
	Word16 surv1[N_SURV_MAX];              /* indices of survivors from 1st stage */
	Word32 i, k, temp, min_err, distance;
	Word16 isf[ORDER];
	Word16 isf_stage2[ORDER];

	for (i = 0; i < ORDER; i++)
	{
		isf[i] = vo_sub(isf1[i], mean_isf[i]);
		isf[i] = vo_sub(isf[i], vo_mult(MU, past_isfq[i]));
	}

	VQ_stage1(&isf[0], dico1_isf, 9, SIZE_BK1, surv1, nb_surv);

	distance = MAX_32;

	for (k = 0; k < nb_surv; k++)
	{
		for (i = 0; i < 9; i++)
		{
			isf_stage2[i] = vo_sub(isf[i], dico1_isf[i + surv1[k] * 9]);
		}
		tmp_ind[0] = Sub_VQ(&isf_stage2[0], dico21_isf, 3, SIZE_BK21, &min_err);
		temp = min_err;
		tmp_ind[1] = Sub_VQ(&isf_stage2[3], dico22_isf, 3, SIZE_BK22, &min_err);
		temp = vo_L_add(temp, min_err);
		tmp_ind[2] = Sub_VQ(&isf_stage2[6], dico23_isf, 3, SIZE_BK23, &min_err);
		temp = vo_L_add(temp, min_err);

		if(temp < distance)
		{
			distance = temp;
			indice[0] = surv1[k];
			for (i = 0; i < 3; i++)
			{
				indice[i + 2] = tmp_ind[i];
			}
		}
	}


	VQ_stage1(&isf[9], dico2_isf, 7, SIZE_BK2, surv1, nb_surv);

	distance = MAX_32;

	for (k = 0; k < nb_surv; k++)
	{
		for (i = 0; i < 7; i++)
		{
			isf_stage2[i] = vo_sub(isf[9 + i], dico2_isf[i + surv1[k] * 7]);
		}

		tmp_ind[0] = Sub_VQ(&isf_stage2[0], dico24_isf, 3, SIZE_BK24, &min_err);
		temp = min_err;
		tmp_ind[1] = Sub_VQ(&isf_stage2[3], dico25_isf, 4, SIZE_BK25, &min_err);
		temp = vo_L_add(temp, min_err);

		if(temp < distance)
		{
			distance = temp;
			indice[1] = surv1[k];
			for (i = 0; i < 2; i++)
			{
				indice[i + 5] = tmp_ind[i];
			}
		}
	}

	Dpisf_2s_46b(indice, isf_q, past_isfq, isf_q, isf_q, 0, 0);

	return;
}

/*****************************************************************************
* Function:   Qpisf_2s_36B()                                                 *
*                                                                            *
* Description: Quantization of isf parameters with prediction. (36 bits)     *
*                                                                            *
* The isf vector is quantized using two-stage VQ with split-by-2 in          *
*  1st stage and split-by-3 in the second stage.                             *
******************************************************************************/

void Qpisf_2s_36b(
		Word16 * isf1,                        /* (i) Q15 : ISF in the frequency domain (0..0.5) */
		Word16 * isf_q,                       /* (o) Q15 : quantized ISF               (0..0.5) */
		Word16 * past_isfq,                   /* (io)Q15 : past ISF quantizer                   */
		Word16 * indice,                      /* (o)     : quantization indices                 */
		Word16 nb_surv                        /* (i)     : number of survivor (1, 2, 3 or 4)    */
		)
{
	Word16 i, k, tmp_ind[5];
	Word16 surv1[N_SURV_MAX];              /* indices of survivors from 1st stage */
	Word32 temp, min_err, distance;
	Word16 isf[ORDER];
	Word16 isf_stage2[ORDER];

	for (i = 0; i < ORDER; i++)
	{
		isf[i] = vo_sub(isf1[i], mean_isf[i]);
		isf[i] = vo_sub(isf[i], vo_mult(MU, past_isfq[i]));
	}

	VQ_stage1(&isf[0], dico1_isf, 9, SIZE_BK1, surv1, nb_surv);

	distance = MAX_32;

	for (k = 0; k < nb_surv; k++)
	{
		for (i = 0; i < 9; i++)
		{
			isf_stage2[i] = vo_sub(isf[i], dico1_isf[i + surv1[k] * 9]);
		}

		tmp_ind[0] = Sub_VQ(&isf_stage2[0], dico21_isf_36b, 5, SIZE_BK21_36b, &min_err);
		temp = min_err;
		tmp_ind[1] = Sub_VQ(&isf_stage2[5], dico22_isf_36b, 4, SIZE_BK22_36b, &min_err);
		temp = vo_L_add(temp, min_err);

		if(temp < distance)
		{
			distance = temp;
			indice[0] = surv1[k];
			for (i = 0; i < 2; i++)
			{
				indice[i + 2] = tmp_ind[i];
			}
		}
	}

	VQ_stage1(&isf[9], dico2_isf, 7, SIZE_BK2, surv1, nb_surv);
	distance = MAX_32;

	for (k = 0; k < nb_surv; k++)
	{
		for (i = 0; i < 7; i++)
		{
			isf_stage2[i] = vo_sub(isf[9 + i], dico2_isf[i + surv1[k] * 7]);
		}

		tmp_ind[0] = Sub_VQ(&isf_stage2[0], dico23_isf_36b, 7, SIZE_BK23_36b, &min_err);
		temp = min_err;

		if(temp < distance)
		{
			distance = temp;
			indice[1] = surv1[k];
			indice[4] = tmp_ind[0];
		}
	}

	Dpisf_2s_36b(indice, isf_q, past_isfq, isf_q, isf_q, 0, 0);

	return;
}

/*********************************************************************
* Function: Dpisf_2s_46b()                                           *
*                                                                    *
* Description: Decoding of ISF parameters                            *
**********************************************************************/

void Dpisf_2s_46b(
		Word16 * indice,                      /* input:  quantization indices                       */
		Word16 * isf_q,                       /* output: quantized ISF in frequency domain (0..0.5) */
		Word16 * past_isfq,                   /* i/0   : past ISF quantizer                    */
		Word16 * isfold,                      /* input : past quantized ISF                    */
		Word16 * isf_buf,                     /* input : isf buffer                                                        */
		Word16 bfi,                           /* input : Bad frame indicator                   */
		Word16 enc_dec
		)
{
	Word16 ref_isf[M], tmp;
	Word32 i, j, L_tmp;

	if (bfi == 0)                          /* Good frame */
	{
		for (i = 0; i < 9; i++)
		{
			isf_q[i] = dico1_isf[indice[0] * 9 + i];
		}
		for (i = 0; i < 7; i++)
		{
			isf_q[i + 9] = dico2_isf[indice[1] * 7 + i];
		}

		for (i = 0; i < 3; i++)
		{
			isf_q[i] = add1(isf_q[i], dico21_isf[indice[2] * 3 + i]);
			isf_q[i + 3] = add1(isf_q[i + 3], dico22_isf[indice[3] * 3 + i]);
			isf_q[i + 6] = add1(isf_q[i + 6], dico23_isf[indice[4] * 3 + i]);
			isf_q[i + 9] = add1(isf_q[i + 9], dico24_isf[indice[5] * 3 + i]);
		}

		for (i = 0; i < 4; i++)
		{
			isf_q[i + 12] = add1(isf_q[i + 12], dico25_isf[indice[6] * 4 + i]);
		}

		for (i = 0; i < ORDER; i++)
		{
			tmp = isf_q[i];
			isf_q[i] = add1(tmp, mean_isf[i]);
			isf_q[i] = add1(isf_q[i], vo_mult(MU, past_isfq[i]));
			past_isfq[i] = tmp;
		}

		if (enc_dec)
		{
			for (i = 0; i < M; i++)
			{
				for (j = (L_MEANBUF - 1); j > 0; j--)
				{
					isf_buf[j * M + i] = isf_buf[(j - 1) * M + i];
				}
				isf_buf[i] = isf_q[i];
			}
		}
	} else
	{                                      /* bad frame */
		for (i = 0; i < M; i++)
		{
			L_tmp = mean_isf[i] << 14;
			for (j = 0; j < L_MEANBUF; j++)
			{
				L_tmp += (isf_buf[j * M + i] << 14);
			}
			ref_isf[i] = vo_round(L_tmp);
		}

		/* use the past ISFs slightly shifted towards their mean */
		for (i = 0; i < ORDER; i++)
		{
			isf_q[i] = add1(vo_mult(ALPHA, isfold[i]), vo_mult(ONE_ALPHA, ref_isf[i]));
		}

		/* estimate past quantized residual to be used in next frame */
		for (i = 0; i < ORDER; i++)
		{
			tmp = add1(ref_isf[i], vo_mult(past_isfq[i], MU));      /* predicted ISF */
			past_isfq[i] = vo_sub(isf_q[i], tmp);
			past_isfq[i] = (past_isfq[i] >> 1);        /* past_isfq[i] *= 0.5 */
		}
	}

	Reorder_isf(isf_q, ISF_GAP, ORDER);
	return;
}

/*********************************************************************
* Function:   Disf_2s_36b()                                          *
*                                                                    *
* Description: Decoding of ISF parameters                            *
*********************************************************************/

void Dpisf_2s_36b(
		Word16 * indice,                      /* input:  quantization indices                       */
		Word16 * isf_q,                       /* output: quantized ISF in frequency domain (0..0.5) */
		Word16 * past_isfq,                   /* i/0   : past ISF quantizer                    */
		Word16 * isfold,                      /* input : past quantized ISF                    */
		Word16 * isf_buf,                     /* input : isf buffer                                                        */
		Word16 bfi,                           /* input : Bad frame indicator                   */
		Word16 enc_dec
		)
{
	Word16 ref_isf[M], tmp;
	Word32 i, j, L_tmp;

	if (bfi == 0)                          /* Good frame */
	{
		for (i = 0; i < 9; i++)
		{
			isf_q[i] = dico1_isf[indice[0] * 9 + i];
		}
		for (i = 0; i < 7; i++)
		{
			isf_q[i + 9] = dico2_isf[indice[1] * 7 + i];
		}

		for (i = 0; i < 5; i++)
		{
			isf_q[i] = add1(isf_q[i], dico21_isf_36b[indice[2] * 5 + i]);
		}
		for (i = 0; i < 4; i++)
		{
			isf_q[i + 5] = add1(isf_q[i + 5], dico22_isf_36b[indice[3] * 4 + i]);
		}
		for (i = 0; i < 7; i++)
		{
			isf_q[i + 9] = add1(isf_q[i + 9], dico23_isf_36b[indice[4] * 7 + i]);
		}

		for (i = 0; i < ORDER; i++)
		{
			tmp = isf_q[i];
			isf_q[i] = add1(tmp, mean_isf[i]);
			isf_q[i] = add1(isf_q[i], vo_mult(MU, past_isfq[i]));
			past_isfq[i] = tmp;
		}


		if (enc_dec)
		{
			for (i = 0; i < M; i++)
			{
				for (j = (L_MEANBUF - 1); j > 0; j--)
				{
					isf_buf[j * M + i] = isf_buf[(j - 1) * M + i];
				}
				isf_buf[i] = isf_q[i];
			}
		}
	} else
	{                                      /* bad frame */
		for (i = 0; i < M; i++)
		{
			L_tmp = (mean_isf[i] << 14);
			for (j = 0; j < L_MEANBUF; j++)
			{
				L_tmp += (isf_buf[j * M + i] << 14);
			}
			ref_isf[i] = vo_round(L_tmp);
		}

		/* use the past ISFs slightly shifted towards their mean */
		for (i = 0; i < ORDER; i++)
		{
			isf_q[i] = add1(vo_mult(ALPHA, isfold[i]), vo_mult(ONE_ALPHA, ref_isf[i]));
		}

		/* estimate past quantized residual to be used in next frame */
		for (i = 0; i < ORDER; i++)
		{
			tmp = add1(ref_isf[i], vo_mult(past_isfq[i], MU));      /* predicted ISF */
			past_isfq[i] = vo_sub(isf_q[i], tmp);
			past_isfq[i] = past_isfq[i] >> 1;         /* past_isfq[i] *= 0.5 */
		}
	}

	Reorder_isf(isf_q, ISF_GAP, ORDER);

	return;
}


/***************************************************************************
* Function:  Reorder_isf()                                                 *
*                                                                          *
* Description: To make sure that the  isfs are properly order and to       *
*              keep a certain minimum distance between consecutive isfs.   *
*--------------------------------------------------------------------------*
*    Argument         description                     in/out               *
*                                                                          *
*     isf[]           vector of isfs                    i/o                *
*     min_dist        minimum required distance         i                  *
*     n               LPC order                         i                  *
****************************************************************************/

void Reorder_isf(
		Word16 * isf,                         /* (i/o) Q15: ISF in the frequency domain (0..0.5) */
		Word16 min_dist,                      /* (i) Q15  : minimum distance to keep             */
		Word16 n                              /* (i)      : number of ISF                        */
		)
{
	Word32 i;
	Word16 isf_min;

	isf_min = min_dist;
	for (i = 0; i < n - 1; i++)
	{
		if(isf[i] < isf_min)
		{
			isf[i] = isf_min;
		}
		isf_min = (isf[i] + min_dist);
	}
	return;
}


Word16 Sub_VQ(                             /* output: return quantization index     */
		Word16 * x,                           /* input : ISF residual vector           */
		Word16 * dico,                        /* input : quantization codebook         */
		Word16 dim,                           /* input : dimention of vector           */
		Word16 dico_size,                     /* input : size of quantization codebook */
		Word32 * distance                     /* output: error of quantization         */
	     )
{
	Word16 temp, *p_dico;
	Word32 i, j, index;
	Word32 dist_min, dist;

	dist_min = MAX_32;
	p_dico = dico;

	index = 0;
	for (i = 0; i < dico_size; i++)
	{
		dist = 0;

		for (j = 0; j < dim; j++)
		{
			temp = x[j] - (*p_dico++);
			dist += (temp * temp)<<1;
		}

		if(dist < dist_min)
		{
			dist_min = dist;
			index = i;
		}
	}

	*distance = dist_min;

	/* Reading the selected vector */
	p_dico = &dico[index * dim];
	for (j = 0; j < dim; j++)
	{
		x[j] = *p_dico++;
	}

	return index;
}


static void VQ_stage1(
		Word16 * x,                           /* input : ISF residual vector           */
		Word16 * dico,                        /* input : quantization codebook         */
		Word16 dim,                           /* input : dimention of vector           */
		Word16 dico_size,                     /* input : size of quantization codebook */
		Word16 * index,                       /* output: indices of survivors          */
		Word16 surv                           /* input : number of survivor            */
		)
{
	Word16 temp, *p_dico;
	Word32 i, j, k, l;
	Word32 dist_min[N_SURV_MAX], dist;

	dist_min[0] = MAX_32;
	dist_min[1] = MAX_32;
	dist_min[2] = MAX_32;
	dist_min[3] = MAX_32;
	index[0] = 0;
	index[1] = 1;
	index[2] = 2;
	index[3] = 3;

	p_dico = dico;

	for (i = 0; i < dico_size; i++)
	{
		dist = 0;
		for (j = 0; j < dim; j++)
		{
			temp = x[j] -  (*p_dico++);
			dist += (temp * temp)<<1;
		}

		for (k = 0; k < surv; k++)
		{
			if(dist < dist_min[k])
			{
				for (l = surv - 1; l > k; l--)
				{
					dist_min[l] = dist_min[l - 1];
					index[l] = index[l - 1];
				}
				dist_min[k] = dist;
				index[k] = i;
				break;
			}
		}
	}
	return;
}




