/* Low Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode with lower bitrate           */
void SKP_Silk_LBRR_encode_FLP(
    SKP_Silk_encoder_state_FLP      *psEnc,             /* I/O  Encoder state FLP                       */
    SKP_Silk_encoder_control_FLP    *psEncCtrl,         /* I/O  Encoder control FLP                     */
          SKP_uint8                 *pCode,             /* O    Payload                                 */
          SKP_int16                 *pnBytesOut,        /* I/O  Payload bytes; in: max; out: used       */
    const SKP_float                 xfw[]               /* I    Input signal                            */
)
{
    SKP_int32   Gains_Q16[ NB_SUBFR ];
    SKP_int     k, TempGainsIndices[ NB_SUBFR ], frame_terminator;
    SKP_int     nBytes, nFramesInPayloadBuf;
    SKP_float   TempGains[ NB_SUBFR ];
    SKP_int     typeOffset, LTP_scaleIndex, Rate_only_parameters = 0;

    /* Control use of inband LBRR */
    SKP_Silk_LBRR_ctrl_FLP( psEnc, &psEncCtrl->sCmn );

    if( psEnc->sCmn.LBRR_enabled ) {
        /* Save original gains */
        SKP_memcpy( TempGainsIndices, psEncCtrl->sCmn.GainsIndices, NB_SUBFR * sizeof( SKP_int   ) );
        SKP_memcpy( TempGains,        psEncCtrl->Gains,             NB_SUBFR * sizeof( SKP_float ) );

        typeOffset     = psEnc->sCmn.typeOffsetPrev; // Temp save as cannot be overwritten
        LTP_scaleIndex = psEncCtrl->sCmn.LTP_scaleIndex;

        /* Set max rate where quant signal is encoded */
        if( psEnc->sCmn.fs_kHz == 8 ) {
            Rate_only_parameters = 13500;
        } else if( psEnc->sCmn.fs_kHz == 12 ) {
            Rate_only_parameters = 15500;
        } else if( psEnc->sCmn.fs_kHz == 16 ) {
            Rate_only_parameters = 17500;
        } else if( psEnc->sCmn.fs_kHz == 24 ) {
            Rate_only_parameters = 19500;
        } else {
            SKP_assert( 0 );
        }

        if( psEnc->sCmn.Complexity > 0 && psEnc->sCmn.TargetRate_bps > Rate_only_parameters ) {
            if( psEnc->sCmn.nFramesInPayloadBuf == 0 ) {
                /* First frame in packet copy everything */
                SKP_memcpy( &psEnc->sCmn.sNSQ_LBRR, &psEnc->sCmn.sNSQ, sizeof( SKP_Silk_nsq_state ) );
                psEnc->sCmn.LBRRprevLastGainIndex = psEnc->sShape.LastGainIndex;
                /* Increase Gains to get target LBRR rate */
                psEncCtrl->sCmn.GainsIndices[ 0 ] += psEnc->sCmn.LBRR_GainIncreases;
                psEncCtrl->sCmn.GainsIndices[ 0 ]  = SKP_LIMIT_int( psEncCtrl->sCmn.GainsIndices[ 0 ], 0, N_LEVELS_QGAIN - 1 );
            }
            /* Decode to get gains in sync with decoder */
            SKP_Silk_gains_dequant( Gains_Q16, psEncCtrl->sCmn.GainsIndices, 
                &psEnc->sCmn.LBRRprevLastGainIndex, psEnc->sCmn.nFramesInPayloadBuf );

            /* Overwrite unquantized gains with quantized gains and convert back to Q0 from Q16 */
            for( k = 0; k < NB_SUBFR; k++ ) {
                psEncCtrl->Gains[ k ] = Gains_Q16[ k ] / 65536.0f;
            }

            /*****************************************/
            /* Noise shaping quantization            */
            /*****************************************/
            SKP_Silk_NSQ_wrapper_FLP( psEnc, psEncCtrl, xfw, psEnc->sCmn.q_LBRR, 1 );
        } else {
            SKP_memset( psEnc->sCmn.q_LBRR, 0, psEnc->sCmn.frame_length * sizeof( SKP_int8 ) );
            psEncCtrl->sCmn.LTP_scaleIndex = 0;
        }
        /****************************************/
        /* Initialize arithmetic coder          */
        /****************************************/
        if( psEnc->sCmn.nFramesInPayloadBuf == 0 ) {
            SKP_Silk_range_enc_init( &psEnc->sCmn.sRC_LBRR );
            psEnc->sCmn.nBytesInPayloadBuf = 0;
        }

        /****************************************/
        /* Encode Parameters                    */
        /****************************************/
        SKP_Silk_encode_parameters( &psEnc->sCmn, &psEncCtrl->sCmn, &psEnc->sCmn.sRC_LBRR, psEnc->sCmn.q_LBRR );

        if( psEnc->sCmn.sRC_LBRR.error ) {
            /* Encoder returned error: Clear payload buffer */
            nFramesInPayloadBuf = 0;
        } else {
            nFramesInPayloadBuf = psEnc->sCmn.nFramesInPayloadBuf + 1;
        }

        /****************************************/
        /* Finalize payload and copy to output  */
        /****************************************/
        if( nFramesInPayloadBuf * FRAME_LENGTH_MS >= psEnc->sCmn.PacketSize_ms ) {

            /* Check if FEC information should be added */
            frame_terminator = SKP_SILK_LAST_FRAME;

            /* Add the frame termination info to stream */
            SKP_Silk_range_encoder( &psEnc->sCmn.sRC_LBRR, frame_terminator, SKP_Silk_FrameTermination_CDF );

            /* Payload length so far */
            SKP_Silk_range_coder_get_length( &psEnc->sCmn.sRC_LBRR, &nBytes );

            /* Check that there is enough space in external output buffer and move data */
            if( *pnBytesOut >= nBytes ) {
                SKP_Silk_range_enc_wrap_up( &psEnc->sCmn.sRC_LBRR );
                SKP_memcpy( pCode, psEnc->sCmn.sRC_LBRR.buffer, nBytes * sizeof( SKP_uint8 ) );
                
                *pnBytesOut = nBytes;               
            } else {
                /* Not enough space: Payload will be discarded */
                *pnBytesOut = 0;
                SKP_assert( 0 );
            }
        } else {
            /* No payload this time */
            *pnBytesOut = 0;

            /* Encode that more frames follows */
            frame_terminator = SKP_SILK_MORE_FRAMES;
            SKP_Silk_range_encoder( &psEnc->sCmn.sRC_LBRR, frame_terminator, SKP_Silk_FrameTermination_CDF );
        }

        /* Restore original Gains */
        SKP_memcpy( psEncCtrl->sCmn.GainsIndices, TempGainsIndices, NB_SUBFR * sizeof( SKP_int   ) );
        SKP_memcpy( psEncCtrl->Gains,             TempGains,        NB_SUBFR * sizeof( SKP_float ) );
    
        /* Restore LTP scale index and typeoffset */
        psEncCtrl->sCmn.LTP_scaleIndex = LTP_scaleIndex;
        psEnc->sCmn.typeOffsetPrev     = typeOffset;
    }
}
/* Low BitRate Redundancy encoding functionality. Reuse all parameters but encode residual with lower bitrate */
void SKP_Silk_LBRR_encode_FIX(SKP_Silk_encoder_state_FIX * psEnc,	/* I/O  Pointer to Silk encoder state           */
			      SKP_Silk_encoder_control_FIX * psEncCtrl,	/* I/O  Pointer to Silk encoder control struct  */
			      uint8_t * pCode,	/* O    Pointer to payload                      */
			      int16_t * pnBytesOut,	/* I/O  Pointer to number of payload bytes      */
			      int16_t xfw[]	/* I    Input signal                            */
    )
{
	int i, TempGainsIndices[NB_SUBFR], frame_terminator;
	int nBytes, nFramesInPayloadBuf;
	int32_t TempGains_Q16[NB_SUBFR];
	int typeOffset, LTP_scaleIndex, Rate_only_parameters = 0;
    /*******************************************/
	/* Control use of inband LBRR              */
    /*******************************************/
	SKP_Silk_LBRR_ctrl_FIX(psEnc, psEncCtrl);

	if (psEnc->sCmn.LBRR_enabled) {
		/* Save original Gains */
		SKP_memcpy(TempGainsIndices, psEncCtrl->sCmn.GainsIndices,
			   NB_SUBFR * sizeof(int));
		SKP_memcpy(TempGains_Q16, psEncCtrl->Gains_Q16,
			   NB_SUBFR * sizeof(int32_t));

		typeOffset = psEnc->sCmn.typeOffsetPrev;	// Temp save as cannot be overwritten
		LTP_scaleIndex = psEncCtrl->sCmn.LTP_scaleIndex;

		/* Set max rate where quant signal is encoded */
		if (psEnc->sCmn.fs_kHz == 8) {
			Rate_only_parameters = 13500;
		} else if (psEnc->sCmn.fs_kHz == 12) {
			Rate_only_parameters = 15500;
		} else if (psEnc->sCmn.fs_kHz == 16) {
			Rate_only_parameters = 17500;
		} else if (psEnc->sCmn.fs_kHz == 24) {
			Rate_only_parameters = 19500;
		} else {
			assert(0);
		}

		if (psEnc->sCmn.Complexity > 0
		    && psEnc->sCmn.TargetRate_bps > Rate_only_parameters) {
			if (psEnc->sCmn.nFramesInPayloadBuf == 0) {
				/* First frame in packet copy Everything */
				SKP_memcpy(&psEnc->sNSQ_LBRR, &psEnc->sNSQ,
					   sizeof(SKP_Silk_nsq_state));

				psEnc->sCmn.LBRRprevLastGainIndex =
				    psEnc->sShape.LastGainIndex;
				/* Increase Gains to get target LBRR rate */
				psEncCtrl->sCmn.GainsIndices[0] =
				    psEncCtrl->sCmn.GainsIndices[0] +
				    psEnc->sCmn.LBRR_GainIncreases;
				psEncCtrl->sCmn.GainsIndices[0] =
				    SKP_LIMIT(psEncCtrl->sCmn.GainsIndices[0],
					      0, N_LEVELS_QGAIN - 1);
			}
			/* Decode to get Gains in sync with decoder         */
			/* Overwrite unquantized gains with quantized gains */
			SKP_Silk_gains_dequant(psEncCtrl->Gains_Q16,
					       psEncCtrl->sCmn.GainsIndices,
					       &psEnc->sCmn.
					       LBRRprevLastGainIndex,
					       psEnc->sCmn.nFramesInPayloadBuf);
	    /*****************************************/
			/* Noise shaping quantization            */
	    /*****************************************/
			psEnc->NoiseShapingQuantizer(&psEnc->sCmn,
						     &psEncCtrl->sCmn,
						     &psEnc->sNSQ_LBRR, xfw,
						     &psEnc->sCmn.q_LBRR[psEnc->
									 sCmn.
									 nFramesInPayloadBuf
									 *
									 psEnc->
									 sCmn.
									 frame_length],
						     psEncCtrl->sCmn.
						     NLSFInterpCoef_Q2,
						     psEncCtrl->PredCoef_Q12[0],
						     psEncCtrl->LTPCoef_Q14,
						     psEncCtrl->AR2_Q13,
						     psEncCtrl->
						     HarmShapeGain_Q14,
						     psEncCtrl->Tilt_Q14,
						     psEncCtrl->LF_shp_Q14,
						     psEncCtrl->Gains_Q16,
						     psEncCtrl->Lambda_Q10,
						     psEncCtrl->LTP_scale_Q14);
		} else {
			SKP_memset(&psEnc->sCmn.
				   q_LBRR[psEnc->sCmn.nFramesInPayloadBuf *
					  psEnc->sCmn.frame_length], 0,
				   psEnc->sCmn.frame_length * sizeof(int));
			psEncCtrl->sCmn.LTP_scaleIndex = 0;
		}
	/****************************************/
		/* Initialize arithmetic coder          */
	/****************************************/
		if (psEnc->sCmn.nFramesInPayloadBuf == 0) {
			SKP_Silk_range_enc_init(&psEnc->sCmn.sRC_LBRR);
			psEnc->sCmn.nBytesInPayloadBuf = 0;
		}

	/****************************************/
		/* Encode Parameters                    */
	/****************************************/
		if (psEnc->sCmn.bitstream_v == BIT_STREAM_V4) {
			SKP_Silk_encode_parameters_v4(&psEnc->sCmn,
						      &psEncCtrl->sCmn,
						      &psEnc->sCmn.sRC_LBRR);
		} else {
			SKP_Silk_encode_parameters(&psEnc->sCmn,
						   &psEncCtrl->sCmn,
						   &psEnc->sCmn.sRC_LBRR,
						   &psEnc->sCmn.q_LBRR[psEnc->
								       sCmn.
								       nFramesInPayloadBuf
								       *
								       psEnc->
								       sCmn.
								       frame_length]);
		}

		if (psEnc->sCmn.sRC_LBRR.error) {
			/* encoder returned error: clear payload buffer */
			nFramesInPayloadBuf = 0;
		} else {
			nFramesInPayloadBuf =
			    psEnc->sCmn.nFramesInPayloadBuf + 1;
		}

	/****************************************/
		/* finalize payload and copy to output  */
	/****************************************/
		if (SKP_SMULBB(nFramesInPayloadBuf, FRAME_LENGTH_MS) >=
		    psEnc->sCmn.PacketSize_ms) {

			/* Check if FEC information should be added */
			frame_terminator = SKP_SILK_LAST_FRAME;

			/* Add the frame termination info to stream */
			SKP_Silk_range_encoder(&psEnc->sCmn.sRC_LBRR,
					       frame_terminator,
					       SKP_Silk_FrameTermination_CDF);

			if (psEnc->sCmn.bitstream_v == BIT_STREAM_V4) {
		/*********************************************/
				/* Encode quantization indices of excitation */
		/*********************************************/
				for (i = 0; i < nFramesInPayloadBuf; i++) {
					SKP_Silk_encode_pulses(&psEnc->sCmn.
							       sRC_LBRR,
							       psEnc->sCmn.
							       sigtype[i],
							       psEnc->sCmn.
							       QuantOffsetType
							       [i],
							       &psEnc->sCmn.
							       q_LBRR[i *
								      psEnc->
								      sCmn.
								      frame_length],
							       psEnc->sCmn.
							       frame_length);
				}
			}
			/* payload length so far */
			SKP_Silk_range_coder_get_length(&psEnc->sCmn.sRC_LBRR,
							&nBytes);

			/* check that there is enough space in external output buffer, and move data */
			if (*pnBytesOut >= nBytes) {
				SKP_Silk_range_enc_wrap_up(&psEnc->sCmn.
							   sRC_LBRR);
				SKP_memcpy(pCode, psEnc->sCmn.sRC_LBRR.buffer,
					   nBytes * sizeof(uint8_t));

				*pnBytesOut = nBytes;
			} else {
				/* not enough space: payload will be discarded */
				*pnBytesOut = 0;
				assert(0);
			}
		} else {
			/* no payload for you this time */
			*pnBytesOut = 0;

			/* Encode that more frames follows */
			frame_terminator = SKP_SILK_MORE_FRAMES;
			SKP_Silk_range_encoder(&psEnc->sCmn.sRC_LBRR,
					       frame_terminator,
					       SKP_Silk_FrameTermination_CDF);
		}

		/* Restore original Gains */
		SKP_memcpy(psEncCtrl->sCmn.GainsIndices, TempGainsIndices,
			   NB_SUBFR * sizeof(int));
		SKP_memcpy(psEncCtrl->Gains_Q16, TempGains_Q16,
			   NB_SUBFR * sizeof(int32_t));

		/* Restore LTP scale index and typeoffset */
		psEncCtrl->sCmn.LTP_scaleIndex = LTP_scaleIndex;
		psEnc->sCmn.typeOffsetPrev = typeOffset;
	}
}