/*
 * 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 <assert.h>

#include "gsm610_priv.h"

/*
 *  4.2.11 .. 4.2.12 LONG TERM PREDICTOR (LTP) SECTION
 */


/*
 * This module computes the LTP gain (bc) and the LTP lag (Nc)
 * for the long term analysis filter.   This is done by calculating a
 * maximum of the cross-correlation function between the current
 * sub-segment short term residual signal d [0..39] (output of
 * the short term analysis filter ; for simplification the index
 * of this array begins at 0 and ends at 39 for each sub-segment of the
 * RPE-LTP analysis) and the previous reconstructed short term
 * residual signal dp [-120 .. -1].  A dynamic scaling must be
 * performed to avoid overflow.
 */

 /* The next procedure exists in six versions.  First two integer
  * version (if USE_FLOAT_MUL is not defined) ; then four floating
  * point versions, twice with proper scaling (USE_FLOAT_MUL defined),
  * once without (USE_FLOAT_MUL and FAST defined, and fast run-time
  * option used).  Every pair has first a Cut version (see the -C
  * option to toast or the LTP_CUT option to gsm_option ()), then the
  * uncut one.  (For a detailed explanation of why this is altogether
  * a bad idea, see Henry Spencer and Geoff Collyer, ``#ifdef Considered
  * Harmful''.)
  */

#ifndef	USE_FLOAT_MUL

#ifdef	LTP_CUT

static void Cut_Calculation_of_the_LTP_parameters (

	struct gsm_state * st,

	register int16_t	* d,		/* [0..39]	IN	*/
	register int16_t	* dp,		/* [-120..-1]	IN	*/
	int16_t		* bc_out,	/* 		OUT	*/
	int16_t		* Nc_out	/* 		OUT	*/)
{
	register int	k, lambda ;
	int16_t		Nc, bc ;
	int16_t		wt [40] ;

	int32_t	L_result ;
	int32_t	L_max, L_power ;
	int16_t		R, S, dmax, scal, best_k ;
	int16_t		ltp_cut ;

	register int16_t	temp, wt_k ;

	/*  Search of the optimum scaling of d [0..39]. */
	dmax = 0 ;
	for (k = 0 ; k <= 39 ; k++)
	{	temp = d [k] ;
		temp = GSM_ABS (temp) ;
		if (temp > dmax)
		{	dmax = temp ;
			best_k = k ;
			}
		}
	temp = 0 ;
	if (dmax == 0)
		scal = 0 ;
	else
	{	assert (dmax > 0) ;
		temp = gsm_norm ((int32_t) dmax << 16) ;
		}
	if (temp > 6) scal = 0 ;
	else scal = 6 - temp ;
	assert (scal >= 0) ;

	/* Search for the maximum cross-correlation and coding of the LTP lag
	 */
	L_max = 0 ;
	Nc = 40 ;	/* index for the maximum cross-correlation */
	wt_k = SASR_W (d [best_k], scal) ;

	for (lambda = 40 ; lambda <= 120 ; lambda++)
	{	L_result = (int32_t) wt_k * dp [best_k - lambda] ;
		if (L_result > L_max)
		{	Nc = lambda ;
			L_max = L_result ;
			}
		}
	*Nc_out = Nc ;
	L_max <<= 1 ;

	/*  Rescaling of L_max
	 */
	assert (scal <= 100 && scal >= -100) ;
	L_max = L_max >> (6 - scal) ;	/* sub (6, scal) */

	assert (Nc <= 120 && Nc >= 40) ;

	/*   Compute the power of the reconstructed short term residual
	 *   signal dp [..]
	 */
	L_power = 0 ;
	for (k = 0 ; k <= 39 ; k++)
	{	register int32_t L_temp ;

		L_temp = SASR_W (dp [k - Nc], 3) ;
		L_power += L_temp * L_temp ;
		}
	L_power <<= 1 ;	/* from L_MULT */

	/*  Normalization of L_max and L_power */

	if (L_max <= 0)
	{	*bc_out = 0 ;
		return ;
		}
	if (L_max >= L_power)
	{	*bc_out = 3 ;
		return ;
		}

	temp = gsm_norm (L_power) ;

	R = SASR (L_max << temp, 16) ;
	S = SASR (L_power << temp, 16) ;

	/*  Coding of the LTP gain
	 */

	/*  Table 4.3a must be used to obtain the level DLB [i] for the
	 *  quantization of the LTP gain b to get the coded version bc.
	 */
	for (bc = 0 ; bc <= 2 ; bc++) if (R <= gsm_mult (S, gsm_DLB [bc])) break ;
	*bc_out = bc ;
}

#endif 	/* LTP_CUT */

static void Calculation_of_the_LTP_parameters (
	register int16_t	* d,		/* [0..39]	IN	*/
	register int16_t	* dp,		/* [-120..-1]	IN	*/
	int16_t		* bc_out,	/* 		OUT	*/
	int16_t		* Nc_out	/* 		OUT	*/)
{
	register int	k, lambda ;
	int16_t		Nc, bc ;
	int16_t		wt [40] ;

	int32_t	L_max, L_power ;
	int16_t		R, S, dmax, scal ;
	register int16_t	temp ;

	/*  Search of the optimum scaling of d [0..39].
	 */
	dmax = 0 ;

	for (k = 0 ; k <= 39 ; k++)
	{	temp = d [k] ;
		temp = GSM_ABS (temp) ;
		if (temp > dmax) dmax = temp ;
		}

	temp = 0 ;
	if (dmax == 0)
		scal = 0 ;
	else
	{	assert (dmax > 0) ;
		temp = gsm_norm ((int32_t) dmax << 16) ;
		}

	if (temp > 6) scal = 0 ;
	else scal = 6 - temp ;

	assert (scal >= 0) ;

	/*  Initialization of a working array wt
	 */

	for (k = 0 ; k <= 39 ; k++) wt [k] = SASR_W (d [k], scal) ;

	/* Search for the maximum cross-correlation and coding of the LTP lag */
	L_max = 0 ;
	Nc = 40 ;	/* index for the maximum cross-correlation */

	for (lambda = 40 ; lambda <= 120 ; lambda++)
	{

# undef STEP
#		define STEP(k) 	(int32_t) wt [k] * dp [k - lambda]

		register int32_t L_result ;

		L_result = STEP (0) ; L_result += STEP (1) ;
		L_result += STEP (2) ; L_result += STEP (3) ;
		L_result += STEP (4) ; L_result += STEP (5) ;
		L_result += STEP (6) ; L_result += STEP (7) ;
		L_result += STEP (8) ; L_result += STEP (9) ;
		L_result += STEP (10) ; L_result += STEP (11) ;
		L_result += STEP (12) ; L_result += STEP (13) ;
		L_result += STEP (14) ; L_result += STEP (15) ;
		L_result += STEP (16) ; L_result += STEP (17) ;
		L_result += STEP (18) ; L_result += STEP (19) ;
		L_result += STEP (20) ; L_result += STEP (21) ;
		L_result += STEP (22) ; L_result += STEP (23) ;
		L_result += STEP (24) ; L_result += STEP (25) ;
		L_result += STEP (26) ; L_result += STEP (27) ;
		L_result += STEP (28) ; L_result += STEP (29) ;
		L_result += STEP (30) ; L_result += STEP (31) ;
		L_result += STEP (32) ; L_result += STEP (33) ;
		L_result += STEP (34) ; L_result += STEP (35) ;
		L_result += STEP (36) ; L_result += STEP (37) ;
		L_result += STEP (38) ; L_result += STEP (39) ;

		if (L_result > L_max)
		{	Nc = lambda ;
			L_max = L_result ;
			}
		}

	*Nc_out = Nc ;

	L_max <<= 1 ;

	/*  Rescaling of L_max
	 */
	assert (scal <= 100 && scal >= -100) ;
	L_max = L_max >> (6 - scal) ;	/* sub (6, scal) */

	assert (Nc <= 120 && Nc >= 40) ;

	/*   Compute the power of the reconstructed short term residual
	 *   signal dp [..]
	 */
	L_power = 0 ;
	for (k = 0 ; k <= 39 ; k++)
	{	register int32_t L_temp ;

		L_temp = SASR_W (dp [k - Nc], 3) ;
		L_power += L_temp * L_temp ;
		}
	L_power <<= 1 ;	/* from L_MULT */

	/*  Normalization of L_max and L_power
	 */

	if (L_max <= 0)
	{	*bc_out = 0 ;
		return ;
		}
	if (L_max >= L_power)
	{	*bc_out = 3 ;
		return ;
		}

	temp = gsm_norm (L_power) ;

	R = SASR_L (L_max << temp, 16) ;
	S = SASR_L (L_power << temp, 16) ;

	/*  Coding of the LTP gain
	 */

	/*  Table 4.3a must be used to obtain the level DLB [i] for the
	 *  quantization of the LTP gain b to get the coded version bc.
	 */
	for (bc = 0 ; bc <= 2 ; bc++) if (R <= gsm_mult (S, gsm_DLB [bc])) break ;
	*bc_out = bc ;
}

#else	/* USE_FLOAT_MUL */

#ifdef	LTP_CUT

static void Cut_Calculation_of_the_LTP_parameters (
	struct gsm_state * st,		/*              IN 	*/
	register int16_t	* d,		/* [0..39]	IN	*/
	register int16_t	* dp,		/* [-120..-1]	IN	*/
	int16_t		* bc_out,	/* 		OUT	*/
	int16_t		* Nc_out	/* 		OUT	*/)
{
	register int	k, lambda ;
	int16_t		Nc, bc ;
	int16_t		ltp_cut ;

	float		wt_float [40] ;
	float		dp_float_base [120], * dp_float = dp_float_base + 120 ;

	int32_t	L_max, L_power ;
	int16_t		R, S, dmax, scal ;
	register int16_t	temp ;

	/*  Search of the optimum scaling of d [0..39].
	 */
	dmax = 0 ;

	for (k = 0 ; k <= 39 ; k++)
	{	temp = d [k] ;
		temp = GSM_ABS (temp) ;
		if (temp > dmax) dmax = temp ;
		}

	temp = 0 ;
	if (dmax == 0) scal = 0 ;
	else
	{	assert (dmax > 0) ;
		temp = gsm_norm ((int32_t) dmax << 16) ;
		}

	if (temp > 6) scal = 0 ;
	else scal = 6 - temp ;

	assert (scal >= 0) ;
	ltp_cut = (int32_t) SASR_W (dmax, scal) * st->ltp_cut / 100 ;

	/*  Initialization of a working array wt */

	for (k = 0 ; k < 40 ; k++)
	{	register int16_t w = SASR_W (d [k], scal) ;
		if (w < 0 ? w > -ltp_cut : w < ltp_cut)
			wt_float [k] = 0.0 ;
		else
			wt_float [k] = w ;
		}
	for (k = -120 ; k < 0 ; k++) dp_float [k] = dp [k] ;

	/* Search for the maximum cross-correlation and coding of the LTP lag
	 */
	L_max = 0 ;
	Nc = 40 ;	/* index for the maximum cross-correlation */

	for (lambda = 40 ; lambda <= 120 ; lambda += 9)
	{	/*  Calculate L_result for l = lambda .. lambda + 9. */
		register float *lp = dp_float - lambda ;

		register float W ;
		register float a = lp [-8], b = lp [-7], c = lp [-6],
						d = lp [-5], e = lp [-4], f = lp [-3],
						g = lp [-2], h = lp [-1] ;
		register float E ;
		register float S0 = 0, S1 = 0, S2 = 0, S3 = 0, S4 = 0,
						S5 = 0, S6 = 0, S7 = 0, S8 = 0 ;

#		undef STEP
#		define	STEP(K, a, b, c, d, e, f, g, h) \
			if ((W = wt_float [K]) != 0.0) {	\
			E = W * a ; S8 += E ;		\
			E = W * b ; S7 += E ;		\
			E = W * c ; S6 += E ;		\
			E = W * d ; S5 += E ;		\
			E = W * e ; S4 += E ;		\
			E = W * f ; S3 += E ;		\
			E = W * g ; S2 += E ;		\
			E = W * h ; S1 += E ;		\
			a = lp [K] ;				\
			E = W * a ; S0 += E ; } else (a = lp [K])

#		define	STEP_A(K)	STEP (K, a, b, c, d, e, f, g, h)
#		define	STEP_B(K)	STEP (K, b, c, d, e, f, g, h, a)
#		define	STEP_C(K)	STEP (K, c, d, e, f, g, h, a, b)
#		define	STEP_D(K)	STEP (K, d, e, f, g, h, a, b, c)
#		define	STEP_E(K)	STEP (K, e, f, g, h, a, b, c, d)
#		define	STEP_F(K)	STEP (K, f, g, h, a, b, c, d, e)
#		define	STEP_G(K)	STEP (K, g, h, a, b, c, d, e, f)
#		define	STEP_H(K)	STEP (K, h, a, b, c, d, e, f, g)

		STEP_A (0) ; STEP_B (1) ; STEP_C (2) ; STEP_D (3) ;
		STEP_E (4) ; STEP_F (5) ; STEP_G (6) ; STEP_H (7) ;

		STEP_A (8) ; STEP_B (9) ; STEP_C (10) ; STEP_D (11) ;
		STEP_E (12) ; STEP_F (13) ; STEP_G (14) ; STEP_H (15) ;

		STEP_A (16) ; STEP_B (17) ; STEP_C (18) ; STEP_D (19) ;
		STEP_E (20) ; STEP_F (21) ; STEP_G (22) ; STEP_H (23) ;

		STEP_A (24) ; STEP_B (25) ; STEP_C (26) ; STEP_D (27) ;
		STEP_E (28) ; STEP_F (29) ; STEP_G (30) ; STEP_H (31) ;

		STEP_A (32) ; STEP_B (33) ; STEP_C (34) ; STEP_D (35) ;
		STEP_E (36) ; STEP_F (37) ; STEP_G (38) ; STEP_H (39) ;

#		undef STEP_A
#		undef STEP_B
#		undef STEP_C
#		undef STEP_D
#		undef STEP_E
#		undef STEP_F
#		undef STEP_G
#		undef STEP_H

		if (S0 > L_max) { L_max = S0 ; Nc = lambda ; }
		if (S1 > L_max) { L_max = S1 ; Nc = lambda + 1 ; }
		if (S2 > L_max) { L_max = S2 ; Nc = lambda + 2 ; }
		if (S3 > L_max) { L_max = S3 ; Nc = lambda + 3 ; }
		if (S4 > L_max) { L_max = S4 ; Nc = lambda + 4 ; }
		if (S5 > L_max) { L_max = S5 ; Nc = lambda + 5 ; }
		if (S6 > L_max) { L_max = S6 ; Nc = lambda + 6 ; }
		if (S7 > L_max) { L_max = S7 ; Nc = lambda + 7 ; }
		if (S8 > L_max) { L_max = S8 ; Nc = lambda + 8 ; }

	}
	*Nc_out = Nc ;

	L_max <<= 1 ;

	/*  Rescaling of L_max
	 */
	assert (scal <= 100 && scal >= -100) ;
	L_max = L_max >> (6 - scal) ;	/* sub (6, scal) */

	assert (Nc <= 120 && Nc >= 40) ;

	/*   Compute the power of the reconstructed short term residual
	 *   signal dp [..]
	 */
	L_power = 0 ;
	for (k = 0 ; k <= 39 ; k++)
	{	register int32_t L_temp ;

		L_temp = SASR_W (dp [k - Nc], 3) ;
		L_power += L_temp * L_temp ;
		}
	L_power <<= 1 ;	/* from L_MULT */

	/*  Normalization of L_max and L_power
	 */

	if (L_max <= 0)
	{	*bc_out = 0 ;
		return ;
		}
	if (L_max >= L_power)
	{	*bc_out = 3 ;
		return ;
		}

	temp = gsm_norm (L_power) ;

	R = SASR (L_max << temp, 16) ;
	S = SASR (L_power << temp, 16) ;

	/*  Coding of the LTP gain
	 */

	/*  Table 4.3a must be used to obtain the level DLB [i] for the
	 *  quantization of the LTP gain b to get the coded version bc.
	 */
	for (bc = 0 ; bc <= 2 ; bc++) if (R <= gsm_mult (S, gsm_DLB [bc])) break ;
	*bc_out = bc ;
}

#endif /* LTP_CUT */

static void Calculation_of_the_LTP_parameters (
	register int16_t	* din,		/* [0..39]	IN	*/
	register int16_t	* dp,		/* [-120..-1]	IN	*/
	int16_t		* bc_out,	/* 		OUT	*/
	int16_t		* Nc_out	/* 		OUT	*/)
{
	register int	k, lambda ;
	int16_t	Nc, bc ;

	float	wt_float [40] ;
	float	dp_float_base [120], * dp_float = dp_float_base + 120 ;

	int32_t	L_max, L_power ;
	int16_t		R, S, dmax, scal ;
	register int16_t	temp ;

	/*  Search of the optimum scaling of d [0..39].
	 */
	dmax = 0 ;

	for (k = 0 ; k <= 39 ; k++)
	{	temp = din [k] ;
		temp = GSM_ABS (temp) ;
		if (temp > dmax) dmax = temp ;
		}

	temp = 0 ;
	if (dmax == 0) scal = 0 ;
	else
	{	assert (dmax > 0) ;
		temp = gsm_norm ((int32_t) dmax << 16) ;
		}

	if (temp > 6) scal = 0 ;
	else scal = 6 - temp ;

	assert (scal >= 0) ;

	/*  Initialization of a working array wt */

	for (k = 0 ; k < 40 ; k++)		wt_float [k] = SASR_W (din [k], scal) ;
	for (k = -120 ; k < 0 ; k++)	dp_float [k] = dp [k] ;

	/* Search for the maximum cross-correlation and coding of the LTP lag
	 */
	L_max = 0 ;
	Nc = 40 ;	/* index for the maximum cross-correlation */

	for (lambda = 40 ; lambda <= 120 ; lambda += 9)
	{	/*  Calculate L_result for l = lambda .. lambda + 9. */
		register float *lp = dp_float - lambda ;

		register float W ;
		register float a = lp [-8], b = lp [-7], c = lp [-6],
						d = lp [-5], e = lp [-4], f = lp [-3],
						g = lp [-2], h = lp [-1] ;
		register float E ;
		register float S0 = 0, S1 = 0, S2 = 0, S3 = 0, S4 = 0,
						S5 = 0, S6 = 0, S7 = 0, S8 = 0 ;

#		undef STEP
#		define	STEP(K, a, b, c, d, e, f, g, h) \
			W = wt_float [K] ;		\
			E = W * a ; S8 += E ;		\
			E = W * b ; S7 += E ;		\
			E = W * c ; S6 += E ;		\
			E = W * d ; S5 += E ;		\
			E = W * e ; S4 += E ;		\
			E = W * f ; S3 += E ;		\
			E = W * g ; S2 += E ;		\
			E = W * h ; S1 += E ;		\
			a = lp [K] ;				\
			E = W * a ; S0 += E

#		define	STEP_A(K)	STEP (K, a, b, c, d, e, f, g, h)
#		define	STEP_B(K)	STEP (K, b, c, d, e, f, g, h, a)
#		define	STEP_C(K)	STEP (K, c, d, e, f, g, h, a, b)
#		define	STEP_D(K)	STEP (K, d, e, f, g, h, a, b, c)
#		define	STEP_E(K)	STEP (K, e, f, g, h, a, b, c, d)
#		define	STEP_F(K)	STEP (K, f, g, h, a, b, c, d, e)
#		define	STEP_G(K)	STEP (K, g, h, a, b, c, d, e, f)
#		define	STEP_H(K)	STEP (K, h, a, b, c, d, e, f, g)

		STEP_A (0) ; STEP_B (1) ; STEP_C (2) ; STEP_D (3) ;
		STEP_E (4) ; STEP_F (5) ; STEP_G (6) ; STEP_H (7) ;

		STEP_A (8) ; STEP_B (9) ; STEP_C (10) ; STEP_D (11) ;
		STEP_E (12) ; STEP_F (13) ; STEP_G (14) ; STEP_H (15) ;

		STEP_A (16) ; STEP_B (17) ; STEP_C (18) ; STEP_D (19) ;
		STEP_E (20) ; STEP_F (21) ; STEP_G (22) ; STEP_H (23) ;

		STEP_A (24) ; STEP_B (25) ; STEP_C (26) ; STEP_D (27) ;
		STEP_E (28) ; STEP_F (29) ; STEP_G (30) ; STEP_H (31) ;

		STEP_A (32) ; STEP_B (33) ; STEP_C (34) ; STEP_D (35) ;
		STEP_E (36) ; STEP_F (37) ; STEP_G (38) ; STEP_H (39) ;

#		undef STEP_A
#		undef STEP_B
#		undef STEP_C
#		undef STEP_D
#		undef STEP_E
#		undef STEP_F
#		undef STEP_G
#		undef STEP_H

		if (S0 > L_max) { L_max = S0 ; Nc = lambda ; }
		if (S1 > L_max) { L_max = S1 ; Nc = lambda + 1 ; }
		if (S2 > L_max) { L_max = S2 ; Nc = lambda + 2 ; }
		if (S3 > L_max) { L_max = S3 ; Nc = lambda + 3 ; }
		if (S4 > L_max) { L_max = S4 ; Nc = lambda + 4 ; }
		if (S5 > L_max) { L_max = S5 ; Nc = lambda + 5 ; }
		if (S6 > L_max) { L_max = S6 ; Nc = lambda + 6 ; }
		if (S7 > L_max) { L_max = S7 ; Nc = lambda + 7 ; }
		if (S8 > L_max) { L_max = S8 ; Nc = lambda + 8 ; }
	}
	*Nc_out = Nc ;

	L_max <<= 1 ;

	/*  Rescaling of L_max
	 */
	assert (scal <= 100 && scal >= -100) ;
	L_max = L_max >> (6 - scal) ;	/* sub (6, scal) */

	assert (Nc <= 120 && Nc >= 40) ;

	/*   Compute the power of the reconstructed short term residual
	 *   signal dp [..]
	 */
	L_power = 0 ;
	for (k = 0 ; k <= 39 ; k++)
	{	register int32_t L_temp ;

		L_temp = SASR_W (dp [k - Nc], 3) ;
		L_power += L_temp * L_temp ;
		}
	L_power <<= 1 ;	/* from L_MULT */

	/*  Normalization of L_max and L_power
	 */

	if (L_max <= 0)
	{	*bc_out = 0 ;
		return ;
		}
	if (L_max >= L_power)
	{	*bc_out = 3 ;
		return ;
		}

	temp = gsm_norm (L_power) ;

	R = SASR_L (L_max << temp, 16) ;
	S = SASR_L (L_power << temp, 16) ;

	/*  Coding of the LTP gain
	 */

	/*  Table 4.3a must be used to obtain the level DLB [i] for the
	 *  quantization of the LTP gain b to get the coded version bc.
	 */
	for (bc = 0 ; bc <= 2 ; bc++) if (R <= gsm_mult (S, gsm_DLB [bc])) break ;
	*bc_out = bc ;
}

#ifdef	FAST
#ifdef	LTP_CUT

static void Cut_Fast_Calculation_of_the_LTP_parameters (
	struct gsm_state * st,		/*              IN	*/
	register int16_t	* d,		/* [0..39]	IN	*/
	register int16_t	* dp,		/* [-120..-1]	IN	*/
	int16_t		* bc_out,	/* 		OUT	*/
	int16_t		* Nc_out	/* 		OUT	*/)
{
	register int	k, lambda ;
	register float	wt_float ;
	int16_t	Nc, bc ;
	int16_t	wt_max, best_k, ltp_cut ;

	float		dp_float_base [120], * dp_float = dp_float_base + 120 ;

	register float	L_result, L_max, L_power ;

	wt_max = 0 ;

	for (k = 0 ; k < 40 ; ++k)
	{	if (d [k] > wt_max) wt_max = d [best_k = k] ;
		else if (-d [k] > wt_max) wt_max = -d [best_k = k] ;
		}

	assert (wt_max >= 0) ;
	wt_float = (float) wt_max ;

	for (k = -120 ; k < 0 ; ++k) dp_float [k] = (float) dp [k] ;

	/* Search for the maximum cross-correlation and coding of the LTP lag */
	L_max = 0 ;
	Nc = 40 ;	/* index for the maximum cross-correlation */

	for (lambda = 40 ; lambda <= 120 ; lambda++)
	{	L_result = wt_float * dp_float [best_k - lambda] ;
		if (L_result > L_max)
		{	Nc = lambda ;
			L_max = L_result ;
			}
		}

	*Nc_out = Nc ;
	if (L_max <= 0.)
	{	*bc_out = 0 ;
		return ;
		}

	/*  Compute the power of the reconstructed short term residual
	 *  signal dp [..]
	 */
	dp_float -= Nc ;
	L_power = 0 ;
	for (k = 0 ; k < 40 ; ++k)
	{	register float f = dp_float [k] ;
		L_power += f * f ;
		}

	if (L_max >= L_power)
	{	*bc_out = 3 ;
		return ;
		}

	/*  Coding of the LTP gain
	 *  Table 4.3a must be used to obtain the level DLB [i] for the
	 *  quantization of the LTP gain b to get the coded version bc.
	 */
	lambda = L_max / L_power * 32768.0 ;
	for (bc = 0 ; bc <= 2 ; ++bc) if (lambda <= gsm_DLB [bc]) break ;
	*bc_out = bc ;
}

#endif /* LTP_CUT */

static void Fast_Calculation_of_the_LTP_parameters (
	register int16_t	* din,		/* [0..39]	IN	*/
	register int16_t	* dp,		/* [-120..-1]	IN	*/
	int16_t		* bc_out,	/* 		OUT	*/
	int16_t		* Nc_out	/* 		OUT	*/)
{
	register int	k, lambda ;
	int16_t			Nc, bc ;

	float		wt_float [40] ;
	float		dp_float_base [120], * dp_float = dp_float_base + 120 ;

	register float	L_max, L_power ;

	for (k = 0 ; k < 40 ; ++k) wt_float [k] = (float) din [k] ;
	for (k = -120 ; k < 0 ; ++k) dp_float [k] = (float) dp [k] ;

	/* Search for the maximum cross-correlation and coding of the LTP lag */
	L_max = 0 ;
	Nc = 40 ;	/* index for the maximum cross-correlation */

	for (lambda = 40 ; lambda <= 120 ; lambda += 9)
	{	/*  Calculate L_result for l = lambda .. lambda + 9. */
		register float *lp = dp_float - lambda ;

		register float W ;
		register float a = lp [-8], b = lp [-7], c = lp [-6],
						d = lp [-5], e = lp [-4], f = lp [-3],
						g = lp [-2], h = lp [-1] ;
		register float E ;
		register float S0 = 0, S1 = 0, S2 = 0, S3 = 0, S4 = 0,
						S5 = 0, S6 = 0, S7 = 0, S8 = 0 ;

#		undef STEP
#		define	STEP(K, a, b, c, d, e, f, g, h) \
			W = wt_float [K] ;		\
			E = W * a ; S8 += E ;		\
			E = W * b ; S7 += E ;		\
			E = W * c ; S6 += E ;		\
			E = W * d ; S5 += E ;		\
			E = W * e ; S4 += E ;		\
			E = W * f ; S3 += E ;		\
			E = W * g ; S2 += E ;		\
			E = W * h ; S1 += E ;		\
			a = lp [K] ;				\
			E = W * a ; S0 += E

#		define	STEP_A(K)	STEP (K, a, b, c, d, e, f, g, h)
#		define	STEP_B(K)	STEP (K, b, c, d, e, f, g, h, a)
#		define	STEP_C(K)	STEP (K, c, d, e, f, g, h, a, b)
#		define	STEP_D(K)	STEP (K, d, e, f, g, h, a, b, c)
#		define	STEP_E(K)	STEP (K, e, f, g, h, a, b, c, d)
#		define	STEP_F(K)	STEP (K, f, g, h, a, b, c, d, e)
#		define	STEP_G(K)	STEP (K, g, h, a, b, c, d, e, f)
#		define	STEP_H(K)	STEP (K, h, a, b, c, d, e, f, g)

		STEP_A (0) ; STEP_B (1) ; STEP_C (2) ; STEP_D (3) ;
		STEP_E (4) ; STEP_F (5) ; STEP_G (6) ; STEP_H (7) ;

		STEP_A (8) ; STEP_B (9) ; STEP_C (10) ; STEP_D (11) ;
		STEP_E (12) ; STEP_F (13) ; STEP_G (14) ; STEP_H (15) ;

		STEP_A (16) ; STEP_B (17) ; STEP_C (18) ; STEP_D (19) ;
		STEP_E (20) ; STEP_F (21) ; STEP_G (22) ; STEP_H (23) ;

		STEP_A (24) ; STEP_B (25) ; STEP_C (26) ; STEP_D (27) ;
		STEP_E (28) ; STEP_F (29) ; STEP_G (30) ; STEP_H (31) ;

		STEP_A (32) ; STEP_B (33) ; STEP_C (34) ; STEP_D (35) ;
		STEP_E (36) ; STEP_F (37) ; STEP_G (38) ; STEP_H (39) ;

		if (S0 > L_max) { L_max = S0 ; Nc = lambda ; }
		if (S1 > L_max) { L_max = S1 ; Nc = lambda + 1 ; }
		if (S2 > L_max) { L_max = S2 ; Nc = lambda + 2 ; }
		if (S3 > L_max) { L_max = S3 ; Nc = lambda + 3 ; }
		if (S4 > L_max) { L_max = S4 ; Nc = lambda + 4 ; }
		if (S5 > L_max) { L_max = S5 ; Nc = lambda + 5 ; }
		if (S6 > L_max) { L_max = S6 ; Nc = lambda + 6 ; }
		if (S7 > L_max) { L_max = S7 ; Nc = lambda + 7 ; }
		if (S8 > L_max) { L_max = S8 ; Nc = lambda + 8 ; }
	}
	*Nc_out = Nc ;

	if (L_max <= 0.0)
	{	*bc_out = 0 ;
		return ;
		}

	/*  Compute the power of the reconstructed short term residual
	 *  signal dp [..]
	 */
	dp_float -= Nc ;
	L_power = 0 ;
	for (k = 0 ; k < 40 ; ++k)
	{	register float f = dp_float [k] ;
		L_power += f * f ;
		}

	if (L_max >= L_power)
	{	*bc_out = 3 ;
		return ;
		}

	/*  Coding of the LTP gain
	 *  Table 4.3a must be used to obtain the level DLB [i] for the
	 *  quantization of the LTP gain b to get the coded version bc.
	 */
	lambda = L_max / L_power * 32768.0 ;
	for (bc = 0 ; bc <= 2 ; ++bc) if (lambda <= gsm_DLB [bc]) break ;
	*bc_out = bc ;
}

#endif	/* FAST 	 */
#endif	/* USE_FLOAT_MUL */


/* 4.2.12 */

static void Long_term_analysis_filtering (
	int16_t		bc,	/* 					IN  */
	int16_t		Nc,	/* 					IN  */
	register int16_t	* dp,	/* previous d	[-120..-1]		IN  */
	register int16_t	* d,	/* d		[0..39]			IN  */
	register int16_t	* dpp,	/* estimate	[0..39]			OUT */
	register int16_t	* e	/* long term res. signal [0..39]	OUT */)
/*
 *  In this part, we have to decode the bc parameter to compute
 *  the samples of the estimate dpp [0..39].  The decoding of bc needs the
 *  use of table 4.3b.  The long term residual signal e [0..39]
 *  is then calculated to be fed to the RPE encoding section.
 */
{
	register int k ;

#	undef STEP
#	define STEP(BP)					\
	for (k = 0 ; k <= 39 ; k++)		\
	{	dpp [k] = GSM_MULT_R (BP, dp [k - Nc]) ;	\
		e [k]	= GSM_SUB (d [k], dpp [k]) ;	\
		}

	switch (bc)
	{	case 0:	STEP (3277) ; break ;
		case 1:	STEP (11469) ; break ;
		case 2: STEP (21299) ; break ;
		case 3: STEP (32767) ; break ;
		}
}

void Gsm_Long_Term_Predictor (	/* 4x for 160 samples */

	struct gsm_state	* S,

	int16_t	* d,	/* [0..39]   residual signal	IN	*/
	int16_t	* dp,	/* [-120..-1] d'		IN	*/

	int16_t	* e,	/* [0..39] 			OUT	*/
	int16_t	* dpp,	/* [0..39] 			OUT	*/
	int16_t	* Nc,	/* correlation lag		OUT	*/
	int16_t	* bc	/* gain factor			OUT	*/)
{
	assert (d) ; assert (dp) ; assert (e) ;
	assert (dpp) ; assert (Nc) ; assert (bc) ;

#if defined (FAST) && defined (USE_FLOAT_MUL)
	if (S->fast)
#if defined (LTP_CUT)
		if (S->ltp_cut)
			Cut_Fast_Calculation_of_the_LTP_parameters (S,
				d, dp, bc, Nc) ;
		else
#endif /* LTP_CUT */
			Fast_Calculation_of_the_LTP_parameters (d, dp, bc, Nc) ;
	else
#endif /* FAST & USE_FLOAT_MUL */
#ifdef LTP_CUT
		if (S->ltp_cut)
			Cut_Calculation_of_the_LTP_parameters (S, d, dp, bc, Nc) ;
		else
#endif
			Calculation_of_the_LTP_parameters (d, dp, bc, Nc) ;

	Long_term_analysis_filtering (*bc, *Nc, dp, d, dpp, e) ;
}

/* 4.3.2 */
void Gsm_Long_Term_Synthesis_Filtering (
	struct gsm_state	* S,

	int16_t			Ncr,
	int16_t			bcr,
	register int16_t	* erp,	/* [0..39]		  	 IN */
	register int16_t	* drp	/* [-120..-1] IN, [-120..40] OUT */)
/*
 *  This procedure uses the bcr and Ncr parameter to realize the
 *  long term synthesis filtering.  The decoding of bcr needs
 *  table 4.3b.
 */
{
	register int 		k ;
	int16_t			brp, drpp, Nr ;

	/*  Check the limits of Nr.
	 */
	Nr = Ncr < 40 || Ncr > 120 ? S->nrp : Ncr ;
	S->nrp = Nr ;
	assert (Nr >= 40 && Nr <= 120) ;

	/*  Decoding of the LTP gain bcr
	 */
	brp = gsm_QLB [bcr] ;

	/*  Computation of the reconstructed short term residual
	 *  signal drp [0..39]
	 */
	assert (brp != MIN_WORD) ;

	for (k = 0 ; k <= 39 ; k++)
	{	drpp = GSM_MULT_R (brp, drp [k - Nr]) ;
		drp [k] = GSM_ADD (erp [k], drpp) ;
		}

	/*
	 *  Update of the reconstructed short term residual signal
	 *  drp [-1..-120]
	 */

	for (k = 0 ; k <= 119 ; k++) drp [-120 + k] = drp [-80 + k] ;
}
