/*
 * Copyright (c) 2011-2019 Belledonne Communications SARL.
 *
 * This file is part of bcg729.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
#include <string.h>
#include <stdlib.h>

#include "typedef.h"
#include "codecParameters.h"
#include "basicOperationsMacros.h"
#include "utils.h"

#include "dtx.h"
#include "computeLP.h"
#include "g729FixedPointMath.h"
#include "LP2LSPConversion.h"
#include "LSPQuantization.h"
#include "codebooks.h"
#include "cng.h"
#include "interpolateqLSP.h"
#include "qLSP2LP.h"

#define SID_FRAME 2
#define UNTRANSMITTED_FRAME 0
/*** local functions ***/
static void sumAutocorrelationCoefficients(word32_t autoCorrelationCoefficients[][NB_LSP_COEFF+1], int8_t *autocorrelationCoefficientsScale, uint8_t nbElements,
		word32_t *autoCorrelationCoefficientsResult, int8_t *autocorrelationCoefficientsScaleResults) {
	
	int i,j;
	word64_t autoCorrelationSumBuffer[NB_LSP_COEFF+1]; /* used to temporary store sum on 64 bits */
	word64_t max=0;
	word32_t rescaledAutocorrelationCoefficients[7][NB_LSP_COEFF+1]; /* used to temporary stored rescaled elements */
	int8_t rightShiftToNormalise = 0;

	/* get lowest scale */
	int8_t minScale = autocorrelationCoefficientsScale[0];
	for (i=1; i<nbElements; i++) {
		if (autocorrelationCoefficientsScale[i]<minScale) {
			minScale=autocorrelationCoefficientsScale[i];
		}
	}

	/* rescale the coefficients */
	for (j=0; j<nbElements; j++) {
		int8_t rescaling = autocorrelationCoefficientsScale[j] - minScale;
		for (i=0; i<NB_LSP_COEFF+1; i++) {
			rescaledAutocorrelationCoefficients[j][i] = SHR32(autoCorrelationCoefficients[j][i], rescaling);
		}
	}

	/* sum them on 64 bits and get the maximum value reached */
	for (i=0; i<NB_LSP_COEFF+1; i++) {
		autoCorrelationSumBuffer[i] = rescaledAutocorrelationCoefficients[0][i];
		for (j=1; j<nbElements; j++) {
			autoCorrelationSumBuffer[i] = ADD64(autoCorrelationSumBuffer[i], rescaledAutocorrelationCoefficients[j][i]);
		}
		if (ABS(autoCorrelationSumBuffer[i])>max) max = ABS(autoCorrelationSumBuffer[i]);
	}

	/* normalise result on 32 bits */
	if (max>MAXINT32) {
		do {
			max = SHR(max,1);
			rightShiftToNormalise++;
		} while (max>MAXINT32);
		
		for (i=0; i<NB_LSP_COEFF+1; i++) {
			autoCorrelationCoefficientsResult[i] = (word32_t)SHR64(autoCorrelationSumBuffer[i], rightShiftToNormalise);
		}
	} else {
		for (i=0; i<NB_LSP_COEFF+1; i++) {
			autoCorrelationCoefficientsResult[i] = (word32_t)(autoCorrelationSumBuffer[i]);
		}

	}

	/* adjust output scale according to possible right shift */
	*autocorrelationCoefficientsScaleResults = minScale - rightShiftToNormalise;

	return;
}

/*****************************************************************************/
/* residual Energy quantization according to spec B4.2.1                     */
/*   parameters:                                                             */
/*    -(i) residualEnergy : to be quantized in variable scale                */
/*    -(i) residualEnergyScale : scale of previous parameter                 */
/*    -(o) decodedLogEnergy : decode the quantized energy into a 10Log(E)    */
/*   returns the quantized residual energy parameterR(on 5 bits)             */
/*                                                                           */
/*****************************************************************************/
static uint8_t residualEnergyQuantization(word32_t residualEnergy, int8_t residualEnergyScale, int8_t *decodedLogEnergy) {
	word32_t acc;
	acc = SUB32(g729Log2_Q0Q16(residualEnergy), ADD32(479849, (int32_t)(residualEnergyScale<<16))); /* -479849 is log2(aw/(NCur*80)) acc is log2(E') in Q16 aw = 1 as we use unlagged  autocorrelation coefficients */
	acc = SHR32(acc,1); /* acc = log2(E') in Q15 */
	acc = MULT16_32_Q15(INV_LOG2_10_Q15, acc); /* acc log10(E') in Q15 */

	/* quantization acc contains value to be quantized/10 so all constant / 10 respect what is in the spec */
	if (acc < - 26214) { /* -0.8 in Q15 */
		*decodedLogEnergy = -12;
		return 0; /* first step by 8 */
	} else if (acc < 45875 ) { /* 1,4 in Q15 */
		uint8_t steps;
		acc = (acc+19661); /* up to 14, step by 0.4*/
		if (acc<0) {
			acc= 0;
		} else {
			acc = MULT16_32_Q13(20480, acc); /* step by 0.4, 20480 is 1/0.4 in Q13 -> acc still in Q15 */
		}
		steps = SHR(acc,15);
		*decodedLogEnergy = -2 +4*steps;
		return 1+steps; 
	} else  if (acc<216268) { /* check that log(E') is not > 66dB (216268 is 6.6 in Q15) */
		uint8_t steps;
		acc = (acc-49152); /* -1.5 in Q15 */
		if (acc<0) {
			acc = 0;
		} else {
			acc = MULT16_32_Q12(20480, acc); /* step by 0.2, 20480 is 1/0.2 in Q12 -> acc still in Q15 */
		}
		steps = SHR(acc,15);
		*decodedLogEnergy = 16 +2*steps;
		return 6+steps;
	} else { /* quantized energy support up to 66dB */
		*decodedLogEnergy = 66;
		return 31;
	}
}

/*****************************************************************************/
/* compute LP Coefficients auto correlation as in eq B.13                    */
/*   parameters:                                                             */
/*    -(i) LPCoefficients : in Q12, 10 values, 1 LP Coeff is always 1 and not*/
/*                          stored in this buffer                            */
/*    -(o) LPCautocorrelation : 11 values in Q20                             */
/*                                                                           */
/*****************************************************************************/
static void computeLPCoefficientAutocorrelation(word16_t *LPCoefficients, word32_t *LPCautocorrelation) {
	int j,k;
	/* first compute Ra0 */
	LPCautocorrelation[0] = 4096*4096>>4; /* LPCoefficients are in Q12 -> acc in Q24, init: acc = LP(0)*LP(0) -> 1 in Q20 as LP(0) is not stored because always 1 */
	for (k=0; k<NB_LSP_COEFF; k++) {
		LPCautocorrelation[0] = MAC16_16_Q4(LPCautocorrelation[0], LPCoefficients[k], LPCoefficients[k]); /* LPCoefficients in Q12*Q12 -> Q24 >> Q4: result in Q20 */
	}

	/* and the rest */
	for (j=1; j<NB_LSP_COEFF+1; j++) {
		LPCautocorrelation[j] = SHL(LPCoefficients[j-1],9); /* LPCoeff[0] is not stored always 1, so LPCoeff index is -1 respect LPCautocorrelation, SHL(9) to make *2 and get it in Q20 from Q12 */
		for (k=0; k<10-j; k++) {
			LPCautocorrelation[j] = MAC16_16_Q3(LPCautocorrelation[j], LPCoefficients[k], LPCoefficients[k+j]); /* this k is actually k-1 respect to eq B.13 Q12*Q12 -> Q24 >> 3 : *2 and result in Q20 */
		}

	}
}


/********************************************************************************/
/* compare LPC filters: as in spec B.4.1.3 eq B.12                              */
/*   parameters:                                                                */
/*    -(i) LPCoefficientsAutocorrelation: 11 values in Q20, Ra in spec          */
/*    -(i) autocorrelationCoefficients: 11 values in variable scale, Rt in spec */
/*    -(i) residualEnergy : in the same scale as previous value, Et in spec     */
/*    -(i) threshold : in Q20                                                   */
/*   return 1 if the filter significantly differs (eq B.12 is true)             */
/*                                                                              */
/********************************************************************************/
static uint8_t compareLPCFilters(word32_t *LPCoefficientsAutocorrelation, word32_t *autocorrelationCoefficients, word32_t residualEnergy, word32_t threshold) {
	/* on the left term of the comparison we have Ra in Q20 an Rt in variable scale */
	/* on the right term of the comparison we have Threshold in Q20 an Et in variable scale but same as Rt */
	word64_t acc = 0;
	int i;
	for (i=0; i<NB_LSP_COEFF+1; i++) {
		acc = MAC64(acc, LPCoefficientsAutocorrelation[i], autocorrelationCoefficients[i]);
	}

	if (acc >= MULT32_32(residualEnergy, threshold)) {
		return 1;
	} else {
		return 0;
	}
}
/*****************************************************************************/
/* initBcg729DTXChannel : create context structure and initialise it         */
/*    return value :                                                         */
/*      - the DTX channel context data                                       */
/*                                                                           */
/*****************************************************************************/
bcg729DTXChannelContextStruct *initBcg729DTXChannel() {
	int i;
	/* create the context structure */
	bcg729DTXChannelContextStruct *DTXChannelContext = malloc(sizeof(bcg729DTXChannelContextStruct));
	memset(DTXChannelContext, 0, sizeof(*DTXChannelContext)); /* set autocorrelation buffers to 0 */
	/* avoid arithmetics problem: set past autocorrelation[0] to 1 */
	for (i=0; i<7; i++) {
		DTXChannelContext->autocorrelationCoefficients[i][0] = ONE_IN_Q30;
		DTXChannelContext->autocorrelationCoefficientsScale[i] = 30;
	}

	DTXChannelContext->previousVADflag = 1; /* previous VAD flag must be initialised to VOICE */
	DTXChannelContext->pseudoRandomSeed = CNG_DTX_RANDOM_SEED_INIT;
	return DTXChannelContext;
}

/*******************************************************************************************/
/* updateDTXContext : save autocorrelation value in DTX context as requested in B4.1.1     */
/*   parameters:                                                                           */
/*    -(i/o) DTXChannelContext : the DTX context to be updated                             */
/*    -(i) autocorrelationsCoefficients : 11 values of variable scale, values are copied   */
/*          in DTX context                                                                 */
/*    -(i) autocorrelationCoefficientsScale : the scale of previous buffer(can be <0)      */
/*                                                                                         */
/*******************************************************************************************/
void updateDTXContext(bcg729DTXChannelContextStruct *DTXChannelContext, word32_t *autocorrelationCoefficients, int8_t autocorrelationCoefficientsScale) {
	/* move previous autocorrelation coefficients and store the new one */ 
	/* TODO: optimise it buy using rolling index */
	memcpy(DTXChannelContext->autocorrelationCoefficients[6], DTXChannelContext->autocorrelationCoefficients[5], (NB_LSP_COEFF+1)*sizeof(word32_t));
	DTXChannelContext->autocorrelationCoefficientsScale[6] = DTXChannelContext->autocorrelationCoefficientsScale[5];
	memcpy(DTXChannelContext->autocorrelationCoefficients[5], DTXChannelContext->autocorrelationCoefficients[4], (NB_LSP_COEFF+1)*sizeof(word32_t));
	DTXChannelContext->autocorrelationCoefficientsScale[5] = DTXChannelContext->autocorrelationCoefficientsScale[4];
	memcpy(DTXChannelContext->autocorrelationCoefficients[4], DTXChannelContext->autocorrelationCoefficients[3], (NB_LSP_COEFF+1)*sizeof(word32_t));
	DTXChannelContext->autocorrelationCoefficientsScale[4] = DTXChannelContext->autocorrelationCoefficientsScale[3];
	memcpy(DTXChannelContext->autocorrelationCoefficients[3], DTXChannelContext->autocorrelationCoefficients[2], (NB_LSP_COEFF+1)*sizeof(word32_t));
	DTXChannelContext->autocorrelationCoefficientsScale[3] = DTXChannelContext->autocorrelationCoefficientsScale[2];
	memcpy(DTXChannelContext->autocorrelationCoefficients[2], DTXChannelContext->autocorrelationCoefficients[1], (NB_LSP_COEFF+1)*sizeof(word32_t));
	DTXChannelContext->autocorrelationCoefficientsScale[2] = DTXChannelContext->autocorrelationCoefficientsScale[1];
	memcpy(DTXChannelContext->autocorrelationCoefficients[1], DTXChannelContext->autocorrelationCoefficients[0], (NB_LSP_COEFF+1)*sizeof(word32_t));
	DTXChannelContext->autocorrelationCoefficientsScale[1] = DTXChannelContext->autocorrelationCoefficientsScale[0];
	memcpy(DTXChannelContext->autocorrelationCoefficients[0], autocorrelationCoefficients, (NB_LSP_COEFF+1)*sizeof(word32_t));
	DTXChannelContext->autocorrelationCoefficientsScale[0] = autocorrelationCoefficientsScale;
}

/*******************************************************************************************/
/* encodeSIDFrame: called at eache frame even if VADflag is set to active speech           */
/*   Update the previousVADflag and if curent is set to NOISE, compute the SID params      */
/*  parameters:                                                                            */
/*   -(i/o) DTXChannelContext: current DTX context, is updated by this function            */
/*   -(o)   previousLSPCoefficients : 10 values in Q15, is updated by this function        */
/*   -(i/o) previousqLSPCoefficients : 10 values in Q15, is updated by this function       */
/*   -(i) VADflag : 1 active voice frame, 0 noise frame                                    */
/*   -(i/o) previousqLSF : set of 4 last frames qLSF in Q2.13, is updated                  */
/*   -(i/o) excicationVector : in Q0, accessed in range [-L_PAST_EXCITATION,L_FRAME-1]     */
/*   -(o) qLPCoefficients : 20 values in Q3.12  the quantized LP coefficients              */
/*   -(o) bitStream : SID frame parameters on 2 bytes, may be null if no frame is to be    */
/*        transmitted                                                                      */
/*   -(o) bitStreamLength : length of bitStream buffer to be transmitted (2 for SID, 0 for */
/*        untransmitted frame)                                                             */
/*                                                                                         */
/*******************************************************************************************/
void encodeSIDFrame(bcg729DTXChannelContextStruct *DTXChannelContext, word16_t *previousLSPCoefficients, word16_t *previousqLSPCoefficients,  uint8_t VADflag, word16_t previousqLSF[MA_MAX_K][NB_LSP_COEFF], word16_t *excitationVector, word16_t *qLPCoefficients, uint8_t *bitStream, uint8_t *bitStreamLength) {

	int i;
	word32_t summedAutocorrelationCoefficients[NB_LSP_COEFF+1];
	word16_t LPCoefficients[NB_LSP_COEFF]; /* in Q12 */
	word16_t LSPCoefficients[NB_LSP_COEFF]; /* in Q15 */
	word32_t reflectionCoefficients[NB_LSP_COEFF]; /* product of LP Computation, may be used if we need to generate the RFC3389 payload */
	word32_t residualEnergy; /* in variable scale(summedAutocorrelationCoefficientsScale) computed together with LP coefficients */
	int8_t summedAutocorrelationCoefficientsScale;
	uint8_t frameType;
	word32_t meanEnergy;
	int8_t meanEnergyScale;
	uint8_t quantizedResidualEnergy;
	int8_t decodedLogEnergy;
	uint8_t parameters[3]; /* array of the first 3 output parameters, 4th is in quantizedResidualEnergy */
	word16_t interpolatedqLSP[NB_LSP_COEFF]; /* the interpolated qLSP used for first subframe in Q15 */


	if (VADflag == 1) {/* this is a voice frame, just update the VADflag history and return */
		DTXChannelContext->pseudoRandomSeed = CNG_DTX_RANDOM_SEED_INIT; /* re-init pseudo random seed at each active frame to keep CNG and DTX in sync */
		DTXChannelContext->previousVADflag = 1;
		return;
	}

	/* NOISE frame */
	/* compute the autocorrelation coefficients sum on the current and previous frame */
	sumAutocorrelationCoefficients((DTXChannelContext->autocorrelationCoefficients), DTXChannelContext->autocorrelationCoefficientsScale, 2,
		summedAutocorrelationCoefficients, &summedAutocorrelationCoefficientsScale);

  	/* compute LP filter coefficients */
	autoCorrelation2LP(summedAutocorrelationCoefficients, LPCoefficients, reflectionCoefficients, &residualEnergy); /* output residualEnergy with the same scale of input summedAutocorrelationCoefficients */

	/* determine type of frame SID or untrasmitted */
	if (DTXChannelContext->previousVADflag == 1) { /* if previous frame was active : we must generate a SID frame spec B.10 */
		frameType = SID_FRAME;
		meanEnergy = residualEnergy;
		meanEnergyScale = summedAutocorrelationCoefficientsScale;
		quantizedResidualEnergy = residualEnergyQuantization(meanEnergy, meanEnergyScale, &decodedLogEnergy);
	} else { /* previous frame was already non active, check if we have to generate a new SID frame according to spec 4.1.2-4.1.4 */
		int8_t flag_chang = 0;

		/* update meanEnergy using current and previous frame Energy : meanE = current+previous/2 : rescale both of them dividing by 2 and sum */
		/* eqB14 doesn't divide by KE but it's done in eqB15, do it now */
		if (summedAutocorrelationCoefficientsScale<DTXChannelContext->previousResidualEnergyScale) {
			meanEnergyScale = summedAutocorrelationCoefficientsScale;
			meanEnergy = ADD32(SHR(residualEnergy,1), VSHR32(DTXChannelContext->previousResidualEnergy, DTXChannelContext->previousResidualEnergyScale - summedAutocorrelationCoefficientsScale + 1));

		} else {
			meanEnergyScale = DTXChannelContext->previousResidualEnergyScale;
			meanEnergy = ADD32(VSHR32(residualEnergy,summedAutocorrelationCoefficientsScale - DTXChannelContext->previousResidualEnergyScale + 1), SHR(DTXChannelContext->previousResidualEnergy, 1));
		}
		quantizedResidualEnergy = residualEnergyQuantization(meanEnergy, meanEnergyScale, &decodedLogEnergy);

		/* comparison of LPC filters B4.1.3 : DTXChannelContext->SIDLPCoefficientAutocorrelation contains the last used filter LP coeffecients autocorrelation in Q20 */
		if (compareLPCFilters(DTXChannelContext->SIDLPCoefficientAutocorrelation, summedAutocorrelationCoefficients, residualEnergy, THRESHOLD1_IN_Q20) != 0) {
			flag_chang = 1;
		}

		/* comparison of the energies B4.1.4 */
		if (ABS(DTXChannelContext->previousDecodedLogEnergy - decodedLogEnergy)>2) {
			flag_chang = 1;
		}

		/* check if we have to transmit a SID frame eq B.11 */
		DTXChannelContext->count_fr++;
		if (DTXChannelContext->count_fr<3) { /* min 3 frames between 2 consecutive SID frames */
			frameType = UNTRANSMITTED_FRAME;
		} else {
			if (flag_chang == 1) {
				frameType = SID_FRAME;
			} else {
				frameType = UNTRANSMITTED_FRAME;
			}
			DTXChannelContext->count_fr = 3; /* counter on 8 bits, keep value low, we just need to know if it is > 3 */
		}

	}

	/* generate the SID frame */
	if (frameType == SID_FRAME) {
		word32_t SIDLPCAutocorrelationCoefficients[NB_LSP_COEFF+1];
		int8_t SIDLPCAutocorrelationCoefficientsScale;
		word16_t pastAverageLPCoefficients[NB_LSP_COEFF]; /* in Q12 */
		word32_t pastAverageReflectionCoefficients[NB_LSP_COEFF]; /* produced by LP computation, may be used if we have to generate RFC3389 payload */
		word32_t pastAverageResidualEnergy; /* not used here, by-product of LP coefficients computation */

		/* reset frame count */
		DTXChannelContext->count_fr = 0;

		/*** compute the past average filter on the last 6 past frames ***/
		sumAutocorrelationCoefficients(&(DTXChannelContext->autocorrelationCoefficients[1]), &(DTXChannelContext->autocorrelationCoefficientsScale[1]), 6,
			SIDLPCAutocorrelationCoefficients, &SIDLPCAutocorrelationCoefficientsScale);

	  	/* compute past average LP filter coefficients Ap in B4.2.2 */
		autoCorrelation2LP(SIDLPCAutocorrelationCoefficients, pastAverageLPCoefficients, pastAverageReflectionCoefficients, &pastAverageResidualEnergy); /* output residualEnergy with the same scale of input summedAutocorrelationCoefficients */
	
		/* select coefficients according to eq B.17 we have Ap in SIDLPCoefficients and At in LPCoefficients, store result, in Q12 in SIDLPCoefficients */
		/* check distance beetwen currently used filter and past filter : compute LPCoefficentAutocorrelation for the past average filter */
		computeLPCoefficientAutocorrelation(pastAverageLPCoefficients, DTXChannelContext->SIDLPCoefficientAutocorrelation);

		DTXChannelContext->decodedLogEnergy = decodedLogEnergy; /* store frame mean energy for RFC3389 payload generation */
		
		if (compareLPCFilters(DTXChannelContext->SIDLPCoefficientAutocorrelation, summedAutocorrelationCoefficients, residualEnergy, THRESHOLD3_IN_Q20) == 0) { /* use the past average filter */
			/* generate LSP coefficient using the past LP coefficients */
			if (!LP2LSPConversion(pastAverageLPCoefficients, LSPCoefficients)) {
				/* unable to find the 10 roots repeat previous LSP */
				memcpy(LSPCoefficients, previousqLSPCoefficients, NB_LSP_COEFF*sizeof(word16_t));
			}
			/* LPCoefficientAutocorrelation are already in DTXChannelContext */ 
			/* save the reflection coefficients in the DTX context as they will be requested to generate RFC3389 payload */
			memcpy(DTXChannelContext->reflectionCoefficients, pastAverageReflectionCoefficients, NB_LSP_COEFF*sizeof(word32_t));
		} else { /* use filter computed on current and previous frame */
			/* compute the LPCoefficientAutocorrelation for this filter and store them in DTXChannel */
			computeLPCoefficientAutocorrelation(LPCoefficients, DTXChannelContext->SIDLPCoefficientAutocorrelation);
			/* generate LSP coefficient current LP coefficients */
			if (!LP2LSPConversion(LPCoefficients, LSPCoefficients)) {
				/* unable to find the 10 roots repeat previous LSP */
				memcpy(LSPCoefficients, previousqLSPCoefficients, NB_LSP_COEFF*sizeof(word16_t));
			}
			/* save the reflection coefficients in the DTX context as they will be requested to generate RFC3389 payload */
			memcpy(DTXChannelContext->reflectionCoefficients, reflectionCoefficients, NB_LSP_COEFF*sizeof(word32_t));
		}

		/* update previousLSP coefficient buffer */
		memcpy(previousLSPCoefficients, LSPCoefficients, NB_LSP_COEFF*sizeof(word16_t));
	
		/* LSP quantization */	
		noiseLSPQuantization(previousqLSF, LSPCoefficients, DTXChannelContext->qLSPCoefficients, parameters);

		/* update previousDecodedLogEnergy and SIDGain */
		DTXChannelContext->previousDecodedLogEnergy = decodedLogEnergy;
		DTXChannelContext->currentSIDGain = SIDGainCodebook[quantizedResidualEnergy];
	}

	/* save current Frame Energy */
	DTXChannelContext->previousResidualEnergy = residualEnergy;
	DTXChannelContext->previousResidualEnergyScale = summedAutocorrelationCoefficientsScale;

	/* apply target gain smoothing eq B.19 */
	if(DTXChannelContext->previousVADflag == 1) {
		DTXChannelContext->smoothedSIDGain = DTXChannelContext->currentSIDGain;
	} else {
		DTXChannelContext->smoothedSIDGain = SUB16(DTXChannelContext->smoothedSIDGain, (DTXChannelContext->smoothedSIDGain>>3));
		DTXChannelContext->smoothedSIDGain = ADD16(DTXChannelContext->smoothedSIDGain, (DTXChannelContext->currentSIDGain>>3));
	}

	/* update excitation vector */
	computeComfortNoiseExcitationVector(DTXChannelContext->smoothedSIDGain, &(DTXChannelContext->pseudoRandomSeed), excitationVector);

	/* Interpolate qLSP and update the previousqLSP buffer */
	interpolateqLSP(previousqLSPCoefficients, DTXChannelContext->qLSPCoefficients, interpolatedqLSP); /* in case of untransmitted frame, use qLSP generated for the last transmitted one */
	for (i=0; i<NB_LSP_COEFF; i++) {
		previousqLSPCoefficients[i] = DTXChannelContext->qLSPCoefficients[i];
	}

	/* first subframe */
	qLSP2LP(interpolatedqLSP, qLPCoefficients);
	/* second subframe */
	qLSP2LP(DTXChannelContext->qLSPCoefficients, &(qLPCoefficients[NB_LSP_COEFF]));
	
	/* set parameters into the bitStream if a frame must be transmitted */
	if (frameType == SID_FRAME) {
		*bitStreamLength = 2;
		bitStream[0] = (((parameters[0]&0x01)<<7)  /* L0 1 bit */
			| ((parameters[1]&0x1F)<<2) /* L1 5 bits */
			| ((parameters[2]>>2)%0x03)); /* L2 is 4 bits 2 MSB in this byte */
		bitStream[1] = (((parameters[2]&0x03)<<6) /* 2 LSB of 4 bits L2 */
			| ((quantizedResidualEnergy&0x1F)<<1)); /* Gain 5 bits, last bit is left to 0 */
	} else {
		*bitStreamLength = 0;
	}

	/* update the previousVADflag in context */
	DTXChannelContext->previousVADflag = 0;

}
