/*
 * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
 * Universitaet Berlin.  See the accompanying file "COPYRIGHT" for
 * details.  THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
 */

#include <stdio.h>
#include <string.h>
#include <assert.h>

#include "gsm610_priv.h"

/*
 *  4.2.4 .. 4.2.7 LPC ANALYSIS SECTION
 */

/* 4.2.4 */


static void Autocorrelation (
	int16_t		* s,		/* [0..159]	IN/OUT  */
 	int32_t	* L_ACF)	/* [0..8]	OUT     */
/*
 *  The goal is to compute the array L_ACF [k].  The signal s [i] must
 *  be scaled in order to avoid an overflow situation.
 */
{
	register int	k, i ;

	int16_t		temp, smax, scalauto ;

#ifdef	USE_FLOAT_MUL
	float		float_s [160] ;
#endif

	/*  Dynamic scaling of the array  s [0..159] */

	/*  Search for the maximum. */
	smax = 0 ;
	for (k = 0 ; k <= 159 ; k++)
	{	temp = GSM_ABS (s [k]) ;
		if (temp > smax) smax = temp ;
		}

	/*  Computation of the scaling factor.
	 */
	if (smax == 0)
		scalauto = 0 ;
	else
	{	assert (smax > 0) ;
		scalauto = 4 - gsm_norm ((int32_t) smax << 16) ;	/* sub (4,..) */
		}

	/*  Scaling of the array s [0...159]
	 */

	if (scalauto > 0)
	{

# ifdef USE_FLOAT_MUL
#	define SCALE(n)	\
	case n: for (k = 0 ; k <= 159 ; k++) \
			float_s [k] = (float)	\
				(s [k] = GSM_MULT_R (s [k], 16384 >> (n-1))) ;\
		break ;
# else
#	define SCALE(n)	\
	case n: for (k = 0 ; k <= 159 ; k++) \
			s [k] = GSM_MULT_R (s [k], 16384 >> (n-1)) ;\
		break ;
# endif /* USE_FLOAT_MUL */

		switch (scalauto) {
		SCALE (1)
		SCALE (2)
		SCALE (3)
		SCALE (4)
		}
# undef	SCALE
	}
# ifdef	USE_FLOAT_MUL
	else for (k = 0 ; k <= 159 ; k++) float_s [k] = (float) s [k] ;
# endif

	/*  Compute the L_ACF [..].
	 */
	{
# ifdef	USE_FLOAT_MUL
		register float	*sp = float_s ;
		register float	sl = *sp ;

#		define STEP(k)	L_ACF [k] += (int32_t) (sl * sp [- (k)]) ;
# else
		int16_t	*sp = s ;
		int16_t	sl = *sp ;

#		define STEP(k)	L_ACF [k] += ((int32_t) sl * sp [- (k)]) ;
# endif

#	define NEXTI	sl = *++sp


	for (k = 9 ; k-- ; L_ACF [k] = 0) ;

	STEP (0) ;
	NEXTI ;
	STEP (0) ; STEP (1) ;
	NEXTI ;
	STEP (0) ; STEP (1) ; STEP (2) ;
	NEXTI ;
	STEP (0) ; STEP (1) ; STEP (2) ; STEP (3) ;
	NEXTI ;
	STEP (0) ; STEP (1) ; STEP (2) ; STEP (3) ; STEP (4) ;
	NEXTI ;
	STEP (0) ; STEP (1) ; STEP (2) ; STEP (3) ; STEP (4) ; STEP (5) ;
	NEXTI ;
	STEP (0) ; STEP (1) ; STEP (2) ; STEP (3) ; STEP (4) ; STEP (5) ; STEP (6) ;
	NEXTI ;
	STEP (0) ; STEP (1) ; STEP (2) ; STEP (3) ; STEP (4) ; STEP (5) ; STEP (6) ; STEP (7) ;

	for (i = 8 ; i <= 159 ; i++)
	{	NEXTI ;

		STEP (0) ;
		STEP (1) ; STEP (2) ; STEP (3) ; STEP (4) ;
		STEP (5) ; STEP (6) ; STEP (7) ; STEP (8) ;
		}

	for (k = 9 ; k-- ; )
		L_ACF [k] = SASL_L (L_ACF [k], 1) ;

	}
	/*   Rescaling of the array s [0..159]
	 */
	if (scalauto > 0)
	{	assert (scalauto <= 4) ;
		for (k = 160 ; k-- ; s++)
			*s = SASL_W (*s, scalauto) ;
		}
}

#if defined (USE_FLOAT_MUL) && defined (FAST)

static void Fast_Autocorrelation (
	int16_t * s,		/* [0..159]	IN/OUT  */
 	int32_t * L_ACF)	/* [0..8]	OUT     */
{
	register int	k, i ;
	float f_L_ACF [9] ;
	float scale ;

	float			s_f [160] ;
	register float *sf = s_f ;

	for (i = 0 ; i < 160 ; ++i) sf [i] = s [i] ;
	for (k = 0 ; k <= 8 ; k++)
	{	register float L_temp2 = 0 ;
		register float *sfl = sf - k ;
		for (i = k ; i < 160 ; ++i) L_temp2 += sf [i] * sfl [i] ;
		f_L_ACF [k] = L_temp2 ;
		}
	scale = MAX_LONGWORD / f_L_ACF [0] ;

	for (k = 0 ; k <= 8 ; k++)
		L_ACF [k] = f_L_ACF [k] * scale ;
}
#endif	/* defined (USE_FLOAT_MUL) && defined (FAST) */

/* 4.2.5 */

static void Reflection_coefficients (
	int32_t	* L_ACF,		/* 0...8	IN	*/
	register int16_t	* r			/* 0...7	OUT 	*/
)
{
	register int	i, m, n ;
	register int16_t	temp ;
	int16_t		ACF [9] ;	/* 0..8 */
	int16_t		P [9] ;	/* 0..8 */
	int16_t		K [9] ; /* 2..8 */

	/*  Schur recursion with 16 bits arithmetic.
	 */

	if (L_ACF [0] == 0)
	{	memset (r, 0, 8 * sizeof (r [0])) ;
		return ;
		}

	assert (L_ACF [0] != 0) ;
	temp = gsm_norm (L_ACF [0]) ;

	assert (temp >= 0 && temp < 32) ;

	/* ? overflow ? */
	for (i = 0 ; i <= 8 ; i++) ACF [i] = SASR_L (SASL_L (L_ACF [i], temp), 16) ;

	/*   Initialize array P [..] and K [..] for the recursion.
	 */

	for (i = 1 ; i <= 7 ; i++) K [i] = ACF [i] ;
	for (i = 0 ; i <= 8 ; i++) P [i] = ACF [i] ;

	/*   Compute reflection coefficients
	 */
	for (n = 1 ; n <= 8 ; n++, r++)
	{	temp = P [1] ;
		temp = GSM_ABS (temp) ;
		if (P [0] < temp)
		{	for (i = n ; i <= 8 ; i++) *r++ = 0 ;
			return ;
			}

		*r = gsm_div (temp, P [0]) ;

		assert (*r >= 0) ;
		if (P [1] > 0) *r = -*r ;		/* r [n] = sub (0, r [n]) */
		assert (*r != MIN_WORD) ;
		if (n == 8) return ;

		/*  Schur recursion
		 */
		temp = GSM_MULT_R (P [1], *r) ;
		P [0] = GSM_ADD (P [0], temp) ;

		for (m = 1 ; m <= 8 - n ; m++)
		{	temp = GSM_MULT_R (K [m], *r) ;
			P [m] = GSM_ADD (P [m + 1], temp) ;

			temp = GSM_MULT_R (P [m + 1], *r) ;
			K [m] = GSM_ADD (K [m], temp) ;
			}
		}
}

/* 4.2.6 */

static void Transformation_to_Log_Area_Ratios (
	register int16_t	* r 			/* 0..7	   IN/OUT */
)
/*
 *  The following scaling for r [..] and LAR [..] has been used:
 *
 *  r [..]   = integer (real_r [..]*32768.) ; -1 <= real_r < 1.
 *  LAR [..] = integer (real_LAR [..] * 16384) ;
 *  with -1.625 <= real_LAR <= 1.625
 */
{
	register int16_t	temp ;
	register int	i ;


	/* Computation of the LAR [0..7] from the r [0..7]
	 */
	for (i = 1 ; i <= 8 ; i++, r++)
	{	temp = *r ;
		temp = GSM_ABS (temp) ;
		assert (temp >= 0) ;

		if (temp < 22118)
		{	temp >>= 1 ;
			}
		else if (temp < 31130)
		{	assert (temp >= 11059) ;
			temp -= 11059 ;
			}
		else
		{	assert (temp >= 26112) ;
			temp -= 26112 ;
			temp <<= 2 ;
			}

		*r = *r < 0 ? -temp : temp ;
		assert (*r != MIN_WORD) ;
	}
}

/* 4.2.7 */

static void Quantization_and_coding (
	register int16_t * LAR		/* [0..7]	IN/OUT	*/
)
{
	register int16_t	temp ;

	/*  This procedure needs four tables ; the following equations
	 *  give the optimum scaling for the constants:
	 *
	 *  A [0..7] = integer (real_A [0..7] * 1024)
	 *  B [0..7] = integer (real_B [0..7] *  512)
	 *  MAC [0..7] = maximum of the LARc [0..7]
	 *  MIC [0..7] = minimum of the LARc [0..7]
	 */

#	undef STEP
#	define	STEP(A, B, MAC, MIC)	\
		temp = GSM_MULT (A, *LAR) ;	\
		temp = GSM_ADD (temp, B) ;	\
		temp = GSM_ADD (temp, 256) ;	\
		temp = SASR_W (temp, 9) ;	\
		*LAR = temp > MAC ? MAC - MIC : (temp < MIC ? 0 : temp - MIC) ; \
		LAR++ ;

	STEP (20480, 0, 31, -32) ;
	STEP (20480, 0, 31, -32) ;
	STEP (20480, 2048, 15, -16) ;
	STEP (20480, -2560, 15, -16) ;

	STEP (13964, 94, 7, -8) ;
	STEP (15360, -1792, 7, -8) ;
	STEP (8534, -341, 3, -4) ;
	STEP (9036, -1144, 3, -4) ;

#	undef	STEP
}

void Gsm_LPC_Analysis (
	struct gsm_state *S,
	int16_t			* s,	/* 0..159 signals	IN/OUT	*/
	int16_t			*LARc)	/* 0..7   LARc's	OUT	*/
{
	int32_t	L_ACF [9] ;

#if defined (USE_FLOAT_MUL) && defined (FAST)
	if (S->fast)
		Fast_Autocorrelation (s, L_ACF) ;
	else
#endif
		Autocorrelation (s,	L_ACF	) ;
	Reflection_coefficients (L_ACF, LARc	) ;
	Transformation_to_Log_Area_Ratios (LARc) ;
	Quantization_and_coding (LARc) ;
}
