/********************************************************
                                SV_Frame.c
*********************************************************/

#include <string.h>

#include "SV_common_include.h"

#include "./SV_DCRemover/SV_DCRemover.h"
#include "./SV_EQ_Gain_Delay/SV_EQ_Gain_Delay.h"
#include "./SV_EQ_Gain_Delay/SV_Gain.h"
#include "./SV_EQ_Gain_Delay/SV_OutputEQ.h"
#include "./SV_AEC/SV_AEC.h"
#include "./SV_AGC/SV_AGC.h"
#include "./SV_realFFT/SV_realFFT.h"
#include "./SV_VoiceAndNoiseStatus/SV_VoiceAndNoiseStatus.h"
#include "./SV_MBDRC_2ch/SV_MBDRC_2ch.h"
#include "./SV_RES/SV_RES.h"
#include "./SV_NS/SV_NS.h"
#include "./SV_NS/SV_NS_Acc.h"
#include "./SV_NS/SV_RemoveAccTick.h"
#include "./SV_Mixing/SV_Mixing.h"

#include "./SV_UnbiasedMMSE/SV_UnbiasedMMSE.h"
#include "./SV_InEarNC/SV_InEarNC.h"
#include "./SV_BF/SV_TWS_GEVBF.h"
#include "./SV_DNN/SV_DNNInputSynthesis.h"
#include "./SV_DNN/SV_CRNNS.h"

#ifdef Debug_File_Write_C
#include <stdio.h>
extern FILE *fp_chPwr, *fp_fft;
#endif

#ifdef BSH_DEBUG
#define SVTX_NS_DEBUG
#define DUMP_MODULE_OUTPUT
#endif


#define ENABLE_AEC_OUTER1		0
#define ENABLE_AEC_OUTER2		0
#define ENABLE_AEC_INEAR		0

#define ENABLE_INEARNC			0
#define ENABLE_GEVBF			0
#define ENABLE_GEVBF_UPDATE     0 && ENABLE_GEVBF
#define ENABLE_DNN_INPUT_MIX	0
#define ENABLE_DNN_NS			0

// DC remover (for all channels)
static SV_DCRemover_T SV_DCremover_Rx_struct;
static SV_DCRemover_T SV_DCremover_Outer1_struct;
static SV_DCRemover_T SV_DCremover_Outer2_struct;
static SV_DCRemover_T SV_DCremover_Acc_struct;
static SV_DCRemover_T SV_DCremover_Inner_struct;

// EQ, gain, delay (Rx_buf only)
static SV_EQ_Gain_Delay_T EQ_Gain_Delay_Rx_struct;

// SV_AEC
static SV_AEC_T SV_AEC_outer1_struct;
static SV_AEC_T SV_AEC_outer2_struct;
static SV_AEC_T SV_AEC_inEar_struct;

// SV_AGC
static SV_AGC_T SV_AGC_2chInput_struct;

// Gain (could it be combined with AGC ?)

#ifdef TEST_NS
#define GAIN_ACC ((int)(16.0f*(1<<QGAIN)))
#define GAIN_OUTER1 ((int)(1.5f*(1<<QGAIN)))
#define GAIN_OUTER2 ((int)(1.5f*(1<<QGAIN)))
#define GAIN_INEAR ((int)(1.5f*(1<<QGAIN)))

#define FREQ_GAIN_OUTER1 ((int)(1.5f*(1<<QGAIN)))
#define FREQ_GAIN_OUTER2 ((int)(1.5f*(1<<QGAIN)))
#define FREQ_GAIN_INEAR ((int)(1.5f*(1<<QGAIN)))
#else
#define GAIN_ACC ((int)(16.0f*(1<<QGAIN)))
#define GAIN_OUTER1 ((int)(2.67f*(1<<QGAIN)))
#define GAIN_OUTER2 ((int)(2.67f*(1<<QGAIN)))
#define GAIN_INEAR ((int)(1.9953f*(1<<QGAIN)))
#define GAIN_OUT ((int)(5.0119f*(1<<QGAIN)))

#define FREQ_GAIN_OUTER1 ((int)(1.5f*(1<<QGAIN)))
#define FREQ_GAIN_OUTER2 ((int)(1.5f*(1<<QGAIN)))
#define FREQ_GAIN_INEAR ((int)(1.0f*(1<<QGAIN)))
#endif

static SV_Gain_T SV_Gain_Acc_struct;
static SV_Gain_T SV_Gain_Outer1_struct;
static SV_Gain_T SV_Gain_Outer2_struct;
static SV_Gain_T SV_Gain_InEar_struct;
static SV_Gain_T SV_Gain_Out_struct;

static SV_Gain_T SV_FreqGain_Outer1_struct;
static SV_Gain_T SV_FreqGain_Outer2_struct;
static SV_Gain_T SV_FreqGain_InEar_struct;

// FFT/IFFT
static SV_realFFT_1ch_T SV_realFFT_Exe_Rx_struct;
static SV_realFFT_2ch_T SV_realFFT_Exe_Outer1_Outer2_struct;
static SV_realFFT_2ch_T SV_realFFT_Exe_Inner_Acc_struct;
static SV_realFFT_1ch_T SV_realIFFT_Exe_Out_struct;

#ifdef DUMP_MODULE_OUTPUT
static SV_realFFT_1ch_T SV_realIFFT_Exe_BFOut_struct;
static SV_realFFT_1ch_T SV_realIFFT_Exe_BMOut_struct;
static SV_realFFT_1ch_T SV_realIFFT_Exe_InEarOut_struct;
static SV_realFFT_1ch_T SV_realIFFT_Exe_InEarBFOut_struct;
static SV_realFFT_1ch_T SV_realIFFT_Exe_InEarBMOut_struct;
static SV_realFFT_1ch_T SV_realIFFT_Exe_DNNIn1_struct;
static SV_realFFT_1ch_T SV_realIFFT_Exe_DNNIn2_struct;
static SV_realFFT_1ch_T SV_realIFFT_Exe_DNNOut_struct;
#endif

// MBDRC 2ch
static SV_MBDRC_2ch_T SV_MBDRC_2ch_struct;

// Unbiased MMSE based mask
void *BFOutMMSE;
void *inEarOutMMSE;

// BF
//static SV_BF_T SV_BF_struct;

// NS
static SV_NS_T SV_NS_Outer1_struct;
static SV_NS_T SV_NS_Inner_struct;

// NS_acc
static SV_NS_Acc_T SV_NS_Acc_struct;

// Remove Acc Tick
static SV_RemoveAccTick_T SV_RemoveAccTick_struct;

// Mixing
static SV_Mixing_T SV_Mixing_struct;

// Output EQ
static SV_OutputEQ_T SV_OutputEQ_struct;

// Output AGC
static SV_AGC_T SV_AGC_1chOutput_struct;

// Signal Buffers (time domain)
static int Outer1_buf[FRAMELEN];
static int Outer2_buf[FRAMELEN];
static int Inner_buf[FRAMELEN];
static int Rx_buf[FRAMELEN];
static int Acc_buf[FRAMELEN];

static int Ref_delayed_clp_buf[FRAMELEN];	// reference for RES
static int Ref_aecin_buf[FRAMELEN + Nfilter_AEC];	// reference for Linear EC


// Signal Buffers (freq domain)
static ComplexInt Outer1_sp[HFFTLEN];
static ComplexInt Outer2_sp[HFFTLEN];
static ComplexInt Inner_sp[HFFTLEN];
static ComplexInt Acc_sp[HFFTLEN];
static ComplexInt Rx_sp[HFFTLEN];

static int *TxInSpec[4] = { (int*)Outer1_sp, (int*)Outer2_sp, (int*)Inner_sp, (int*)Acc_sp };
static ComplexInt BFSpec[HFFTLEN];
static ComplexInt BMSpec[HFFTLEN];
static ComplexInt inEarSpec[HFFTLEN];
static ComplexInt inEarBFSpec[HFFTLEN];
static ComplexInt inEarBMSpec[HFFTLEN];
static ComplexInt DNNIn1Spec[HFFTLEN];
static ComplexInt DNNIn2Spec[HFFTLEN];
static ComplexInt DNNOutSpec[HFFTLEN];

char SV_scratchMEM[5600]  = { 0 };
char *scratch_mem_ptr = (char*)SV_scratchMEM;
int SV_scratchBF[20480] = { 2147483647, };
int SV_scratchDNN[20480] = { 0, };

static void SV_24bitTo16bit(int* out, int* in, int n)
{
	do {
		*out++ = *in++ >> 8;
	} while (--n > 0);

	return;
}

static void SV_16bitTo24bit(int* out, int* in, int n)
{
	do {
		*out++ = *in++ << 8;
	} while (--n > 0);

	return;
}

void SV_Frame_Exe(int* Out_buf, const int* p_Outer1, const int* p_Outer2, const int* p_Inner, const int* p_Rx, const int* p_Acc, int n)
{
	int i;
	INT64 Pwr_Rx, Pwr_Mic1, Pwr_Mic2, Pwr_InEar;
	int noiseLevel_MMSE;
	short *BFMask, *inEarMask;
	int *BFSNR;
	int BFSNR_Q;
	memcpy(Outer1_buf, p_Outer1, sizeof(int)*(n));
	memcpy(Outer2_buf, p_Outer2, sizeof(int)*(n));
	memcpy(Inner_buf, p_Inner, sizeof(int)*(n));
	memcpy(Rx_buf, p_Rx, sizeof(int)*(n));
	memcpy(Acc_buf, p_Acc, sizeof(int)*(n));

	SV_scratchDNN[20479] = 1;
	SV_scratchBF[20479] = 2147483647;

	/*----------------------------------------*/
	/* 24bit to 16bit						  */
	/*----------------------------------------*/
#ifndef _PC_SIM
	SV_24bitTo16bit(Outer1_buf, Outer1_buf, n);
	SV_24bitTo16bit(Outer2_buf, Outer2_buf, n);
	SV_24bitTo16bit(Inner_buf, Inner_buf, n);
	SV_24bitTo16bit(Rx_buf, Rx_buf, n);
	SV_24bitTo16bit(Acc_buf, Acc_buf, n);
#endif

	/*----------------------------------------*/
	/* DC remover (for all channels)		  */
	/*----------------------------------------*/    
    SV_DCRemover_Exe(Outer1_buf, Outer1_buf, &SV_DCremover_Outer1_struct, n);
	SV_DCRemover_Exe(Outer2_buf, Outer2_buf, &SV_DCremover_Outer2_struct, n);
	SV_DCRemover_Exe(Inner_buf, Inner_buf, &SV_DCremover_Inner_struct, n);
	SV_DCRemover_Exe(Rx_buf, Rx_buf, &SV_DCremover_Rx_struct, n);
	SV_DCRemover_Exe(Acc_buf, Acc_buf, &SV_DCremover_Acc_struct, n);


	/*----------------------------------------*/
	/* Gain									  */
	/*----------------------------------------*/
	SV_Gain_Exe(Acc_buf, n, &SV_Gain_Acc_struct);
	SV_Gain_Exe(Outer1_buf, n, &SV_Gain_Outer1_struct);
	SV_Gain_Exe(Outer2_buf, n, &SV_Gain_Outer2_struct);
	SV_Gain_Exe(Inner_buf, n, &SV_Gain_InEar_struct);
	//memcpy(Out_buf, Outer1_buf, sizeof(int)*(n));
	
	/*----------------------------------------*/
	/* EQ, gain, rx delay					  */
	/*----------------------------------------*/
	Pwr_Rx = SV_Rx_EQ_Gain_Delay(Ref_delayed_clp_buf, Ref_aecin_buf, Rx_buf, &EQ_Gain_Delay_Rx_struct, n);

    // Channels power
    Pwr_Mic1	= SV_GetPower(Outer1_buf,n);
    Pwr_Mic2	= SV_GetPower(Outer2_buf,n);
	Pwr_InEar	= SV_GetPower(Inner_buf, n);

#ifdef Debug_File_Write_C
	fprintf(fp_chPwr, "%lld %lld %lld\n", Pwr_Rx, Pwr_Mic1, Pwr_Mic2);
#endif

	/*----------------------------------------*/
	/* Time domain VAD (power based)		  */
	/*----------------------------------------*/    
	SV_VAD_TimeDomain_Exe(Pwr_Rx, Pwr_Mic1);

	/*----------------------------------------*/
	/* AEC									  */
	/*----------------------------------------*/
#if ENABLE_AEC_OUTER1 == 1
	SV_AEC_SetPar(Pwr_Mic1, VoiceAndNoiseStatus_Get_frmVAD_Rx_AEC(), &SV_AEC_outer1_struct);
	SV_AEC_Exe(Outer1_buf, Ref_aecin_buf + (Nfilter_AEC - Nfilter_AEC_Outer), n, &SV_AEC_outer1_struct);
#endif

	// SV_AEC (Outer 2)
#if ENABLE_AEC_OUTER2 == 1
	SV_AEC_SetPar(Pwr_Mic2, VoiceAndNoiseStatus_Get_frmVAD_Rx_AEC(), &SV_AEC_outer2_struct);
	SV_AEC_Exe(Outer2_buf, Ref_aecin_buf + (Nfilter_AEC - Nfilter_AEC_Outer), n, &SV_AEC_outer2_struct);
#endif

	// SV_AEC (InEar)
#if ENABLE_AEC_INEAR == 1
	SV_AEC_SetPar(Pwr_InEar, VoiceAndNoiseStatus_Get_frmVAD_Rx_AEC(), &SV_AEC_inEar_struct);
	SV_AEC_Exe(Inner_buf, Ref_aecin_buf + (Nfilter_AEC - Nfilter_AEC_InEar), n, &SV_AEC_inEar_struct);
#endif

#ifdef DUMP_MODULE_OUTPUT
	{
		memcpy(Out_buf + FRAMELEN * 9, Outer1_buf, sizeof(int) * FRAMELEN);
		memcpy(Out_buf + FRAMELEN * 10, Outer2_buf, sizeof(int) * FRAMELEN);
		memcpy(Out_buf + FRAMELEN * 11, Inner_buf, sizeof(int) * FRAMELEN);
	}
#endif
	/*----------------------------------------*/
	/* AGC									  */
	/*----------------------------------------*/
#ifdef TEST_NS
	SV_AGC_2ch_Exe(Outer1_buf, Outer2_buf, n, &SV_AGC_2chInput_struct);
#else
	//SV_AGC_2ch_Exe(Outer1_buf, Outer2_buf, n, &SV_AGC_2chInput_struct);
#endif

	/*----------------------------------------*/
	/* FFT									  */
	/*----------------------------------------*/
	SV_realFFT_1ch_Exe(Rx_sp, Ref_aecin_buf + Nfilter_AEC, n, &SV_realFFT_Exe_Rx_struct);
	SV_realFFT_2ch_Exe(Outer1_sp, Outer2_sp, Outer1_buf, Outer2_buf, n, &SV_realFFT_Exe_Outer1_Outer2_struct);
	SV_realFFT_2ch_Exe(Inner_sp, Acc_sp, Inner_buf, Acc_buf, n, &SV_realFFT_Exe_Inner_Acc_struct);

#ifdef Debug_File_Write_C
	for (i = 0; i < 257; i++)
	{
		fprintf(fp_fft, "%d %d %d %d %d %d %d %d\n", Outer1_sp[i].re, Outer1_sp[i].im, Outer2_sp[i].re, Outer2_sp[i].im,
				Acc_sp[i].re, Acc_sp[i].im, Rx_sp[i].re, Rx_sp[i].im);
	}
#endif

	/*----------------------------------------*/
	/* EQ									  */
	/*----------------------------------------*/
	SV_Tx_EQ(Outer1_sp, Outer1_sp, HFFTLEN);
	SV_Tx_EQ(Outer2_sp, Outer2_sp, HFFTLEN);

	/*----------------------------------------*/
	/* Gain									  */
	/*----------------------------------------*/
	SV_Gain_Exe((int*)Outer1_sp, HFFTLEN << 1, &SV_FreqGain_Outer1_struct);
	SV_Gain_Exe((int*)Outer2_sp, HFFTLEN << 1, &SV_FreqGain_Outer2_struct);
	SV_Gain_Exe((int*)Inner_sp, HFFTLEN << 1, &SV_FreqGain_InEar_struct);
	
	/*----------------------------------------*/
	/* VAD and Noise status					  */
	/*----------------------------------------*/
	VoiceAndNoiseStatus_Exe(Rx_sp, Outer1_sp, Outer2_sp, Acc_sp, HFFTLEN);
	VoiceAndNoiseStatus_Get_frmVAD_Acc_BSH();

/*------------------------------------------ InEar Noise Cancellation ------------------------------------------*/
#if ENABLE_INEARNC == 1
	/*----------------------------------------*/
	/* In-ear mic noise cancellation		  */
	/*----------------------------------------*/
	SV_InEarNC_SetPar(VoiceAndNoiseStatus_Get_frmVAD_Acc_BSH(), VoiceAndNoiseStatus_Get_frmVAD_Rx_AEC(), VoiceAndNoiseStatus_Get_flag_OuterMicLowReliability());
	SV_InEarNC_Exe(inEarSpec, Inner_sp, Outer1_sp);
#else
	for (i = 0; i < HFFTLEN; i++) {
		inEarSpec[i].re = Inner_sp[i].re; inEarSpec[i].im = Inner_sp[i].im;
	}
#endif

	/*----------------------------------------*/
	/* VAD Correction						  */
	/*----------------------------------------*/
	// mask extraction for inEar output
	SV_UnbiasedMMSE_Proc(inEarOutMMSE, (int*)inEarSpec,
		VoiceAndNoiseStatus_Get_frmVAD_Acc_BSH(),
		VoiceAndNoiseStatus_Get_frmVAD_Rx_AEC(),
		((void*)0));
	inEarMask = SV_UnbiasedMMSE_Get_Mask(inEarOutMMSE);
	VoiceAndNoiseStatus_VADCorrection(inEarMask);


/*----------------------------------------- GEV Beamformer -----------------------------------------------------*/
#if ENABLE_GEVBF == 1
	/*----------------------------------------*/
	/* GEV based Beamformer	(Outer) 		  */
	/*----------------------------------------*/
	SV_TWS_GEVBF_Outer_Exe((int*)BFSpec, (int*)BMSpec, TxInSpec);

	/*----------------------------------------*/
	/* GEV based Beamformer	(InEar) 		  */
	/* using Outer BF Result and InEar NC     */
	/*----------------------------------------*/
	SV_TWS_GEVBF_InEar_SetPar(SV_InEarNC_GetWeight(), SV_InEarNC_GetWeightQ(), SV_InEarNC_GetLowerBound());
	SV_TWS_GEVBF_InEar_Exe((int*)inEarBFSpec, (int*)inEarBMSpec, (int*)BFSpec, (int*)BMSpec, (int*)inEarSpec);
#else
	for (i = 0; i < HFFTLEN; i++) {
		BFSpec[i].re = Outer1_sp[i].re; BFSpec[i].im = Outer1_sp[i].im;
		BMSpec[i].re = Outer2_sp[i].re; BMSpec[i].im = Outer2_sp[i].im;
		inEarBFSpec[i].re = inEarSpec[i].re; inEarBFSpec[i].im = inEarSpec[i].im;
		inEarBMSpec[i].re = Outer2_sp[i].re; inEarBMSpec[i].im = Outer2_sp[i].im;
	}
#endif
		
	/*----------------------------------------*/
	/* GEV Beamformer update                  */
	/*----------------------------------------*/
	VoiceAndNoiseStatus_NoiseOnsetCorrection((int*)BFSpec, (int*)inEarBFSpec, inEarMask, SV_UnbiasedMMSE_Get_NoiseLevel(BFOutMMSE)/* flag of previous frame*/);

	// mask extraction for bf output
	SV_UnbaisedMMSE_SetNoiseOnsetFlag(BFOutMMSE, 
		VoiceAndNoiseStatus_Get_NoiseOnset() || VoiceAndNoiseStatus_Get_NoiseOffset());
	SV_UnbiasedMMSE_Proc(BFOutMMSE, (int*)BFSpec, 
		VoiceAndNoiseStatus_Get_frmVAD_Acc_BSH(),
		VoiceAndNoiseStatus_Get_frmVAD_Rx_AEC(), 
		inEarMask);
	BFMask = SV_UnbiasedMMSE_Get_Mask(BFOutMMSE);
	BFSNR = SV_UnbiasedMMSE_Get_SNR(BFOutMMSE);
	BFSNR_Q = SV_UnbiasedMMSE_Get_SNR_Q(BFOutMMSE);

#if ENABLE_GEVBF_UPDATE == 1
	SV_TWS_GEVBF_UpdateWithSNR(TxInSpec,
		BFSNR,
		BFSNR_Q,
		inEarMask, // TODO: kernelÇü¿¡¼­ in-ear °í¿ª ¼ººÐ ºÎÁ· -> °í¿ª¿¡ ´ëÇÑ ¸¶½ºÅ© ÃßÁ¤ X -> À½¼º ¸Ô¸ÔÇÔ
		VoiceAndNoiseStatus_Get_frmVAD_Acc_BSH(),
		VoiceAndNoiseStatus_Get_frmVAD_Rx_AEC() || VoiceAndNoiseStatus_Get_flag_OuterMicLowReliability(),
		VoiceAndNoiseStatus_Get_NoiseOnset(),
		VoiceAndNoiseStatus_Get_NoiseOffset(),
		SV_UnbiasedMMSE_Get_NoiseLevel(BFOutMMSE));
#endif


/*----------------------------------------- CRN based NS -------------------------------------------------------*/
#if ENABLE_DNN_INPUT_MIX == 1
	/*----------------------------------------*/
	/* DNN input preparation (input mixing)   */
	/*----------------------------------------*/
	SV_DNNInputSynthesis_SetPar(VoiceAndNoiseStatus_Get_frmVAD_Acc_BSH(), 
		VoiceAndNoiseStatus_Get_frmVAD_Rx_AEC(),
		VoiceAndNoiseStatus_Get_NoiseOnset(), VoiceAndNoiseStatus_Get_NoiseOffset(),
		SV_UnbiasedMMSE_Get_NoiseLevel(BFOutMMSE),
		SV_TWS_GEVBF_GetInEarGain(),
		SV_UnbiasedMMSE_Get_BandSNR(BFOutMMSE),
		BFMask);
	SV_DNNInputSynthesis_Exe((int*)DNNIn1Spec, (int*)DNNIn2Spec,
		(int*)BFSpec, (int*)BMSpec,
		(int*)inEarBFSpec, (int*)inEarBMSpec,
		(int*)Rx_sp);
#else
	for (i = 0; i < HFFTLEN; i++) {
		DNNIn1Spec[i].re = BFSpec[i].re; DNNIn1Spec[i].im = BFSpec[i].im;
		DNNIn2Spec[i].re = BMSpec[i].re; DNNIn2Spec[i].im = BMSpec[i].im;
	}
#endif

#if ENABLE_DNN_NS == 1
	/*----------------------------------------*/
	/* Compressed CRN						  */
	/*----------------------------------------*/
	SV_CirCRNNS_SetPar(VoiceAndNoiseStatus_Get_frmVAD_Acc_BSH(), VoiceAndNoiseStatus_Get_frmVAD_Rx_AEC());
	SV_CirCRNNS_Exe(DNNOutSpec, DNNIn1Spec, DNNIn2Spec);
#else
	for (i = 0; i < HFFTLEN; i++) {
		DNNOutSpec[i].re = DNNIn1Spec[i].re; DNNOutSpec[i].im = DNNIn1Spec[i].im;
	}
#endif
/*--------------------------------------------------------------------------------------------------------------*/

//    // MBDRC 2ch
//    SV_MBDRC_2ch_Exe(Outer1_sp,Outer2_sp,HFFTLEN,&SV_MBDRC_2ch_struct);

//    // RES
//    SV_RES_SetPar(  VoiceAndNoiseStatus_Get_flagTxsilenceAEC(),
//                              VoiceAndNoiseStatus_Get_flagSingleTalk(),
//                              &SV_BFpostNS_struct
//                              );
//    SV_RES_Exe(Outer1_sp,HFFTLEN,&SV_BFpostNS_struct);

	/*----------------------------------------*/
	/* NS									  */
	/*----------------------------------------*/
#ifdef TEST_NS
    //SV_NS_SetPar(BFpostNS_Get_Npsdgsc(),
    //                       RES_Get_G_H1_res(),
    //                       RES_Get_G_REchoPSDch(),
    //                       &SV_NS_Outer_struct);
	SV_NS_Exe(Outer1_sp, HFFTLEN, &SV_NS_Outer1_struct);
#endif
//    // Inner
//    SV_NS_SetPar(VoiceAndNoiseStatus_Get_flagTxsilence(),
//                           VoiceAndNoiseStatus_Get_noiselevel(),
//                           &SV_NS_Inner_struct);
//    SV_NS_Exe(Inner_sp,HFFTLEN,&SV_NS_Inner_struct);
//    // Acc
//    SV_NS_Acc_SetPar(VoiceAndNoiseStatus_Get_VADACCframe(),
//                               VoiceAndNoiseStatus_Get_frmVAD_Rx_AEC(),
//                               &SV_NS_Acc_struct);
//    SV_NS_Acc_Exe(Acc_sp,HFFTLEN,&SV_NS_Acc_struct);
//
//    // Remove Acc Tick
//    SV_RemoveAccTick_SetPar(VoiceAndNoiseStatus_Get_frmVAD_Rx_AEC(),
//                                       &SV_RemoveAccTick_struct);
//    SV_RemoveAccTick_Exe(Acc_sp,HFFTLEN,&SV_RemoveAccTick_struct);
//
//    // Mixing
//    SV_Mixing_SetPar(VoiceAndNoiseStatus_Get_state_noise(),
//                               &SV_Mixing_struct);
//    SV_Mixing_Exe(Outer1_sp,Outer1_sp,Acc_sp,Inner_sp,HFFTLEN,&SV_Mixing_struct);

    // IFFT
#ifdef TEST_NS
	SV_realIFFT_1ch_Exe(Out_buf, Outer1_sp, HFFTLEN, &SV_realIFFT_Exe_Out_struct);
#else
	//SV_realIFFT_1ch_Exe(Out_buf, DNNOutSpec, HFFTLEN, &SV_realIFFT_Exe_Out_struct);
	SV_realIFFT_1ch_Exe(Out_buf, DNNOutSpec, HFFTLEN, &SV_realIFFT_Exe_Out_struct);
#endif

#ifndef _PC_SIM
	SV_16bitTo24bit(Out_buf, Out_buf, n);
#endif
#ifdef DUMP_MODULE_OUTPUT
	{
		SV_realIFFT_1ch_Exe(Out_buf + FRAMELEN,		BFSpec,		HFFTLEN, &SV_realIFFT_Exe_BFOut_struct);
		SV_realIFFT_1ch_Exe(Out_buf + FRAMELEN * 2,	BMSpec,		HFFTLEN, &SV_realIFFT_Exe_BMOut_struct);
		SV_realIFFT_1ch_Exe(Out_buf + FRAMELEN * 3,	inEarSpec,	HFFTLEN, &SV_realIFFT_Exe_InEarOut_struct);
		SV_realIFFT_1ch_Exe(Out_buf + FRAMELEN * 4,	inEarBFSpec,HFFTLEN, &SV_realIFFT_Exe_InEarBFOut_struct);
		SV_realIFFT_1ch_Exe(Out_buf + FRAMELEN * 5,	DNNIn1Spec, HFFTLEN, &SV_realIFFT_Exe_DNNIn1_struct);
		SV_realIFFT_1ch_Exe(Out_buf + FRAMELEN * 6,	DNNIn2Spec, HFFTLEN, &SV_realIFFT_Exe_DNNIn2_struct);
		SV_realIFFT_1ch_Exe(Out_buf + FRAMELEN * 7,	DNNOutSpec,	HFFTLEN, &SV_realIFFT_Exe_DNNOut_struct);
		SV_realIFFT_1ch_Exe(Out_buf + FRAMELEN * 8, inEarBMSpec, HFFTLEN, &SV_realIFFT_Exe_InEarBMOut_struct);
	}
#endif

    /* End Spectral processing */

//    // Output EQ
//    SV_OutputEQ_Exe(Out_buf,n,&SV_OutputEQ_struct);
//
//    // Output AGC
//    SV_AGC_Exe(Out_buf,n,&SV_Output_AGC_outer1_struct);

	SV_Gain_Exe(Out_buf, n, &SV_Gain_Out_struct);

	if (VoiceAndNoiseStatus_Get_NoiseOnset() == 1) 
		SV_InEarNC_ResetNoiseFrameCnt();

	return;
}


void SV_Frame_Init(int Fs)
{
	int used_memory_size;
	int dummy_size;
	int total_memory_size = 0;
	int bandSize;

    //// DC remover (for all channels)
    SV_DCRemover_Init(Fs, &SV_DCremover_Rx_struct);
    SV_DCRemover_Init(Fs, &SV_DCremover_Outer1_struct);
    SV_DCRemover_Init(Fs, &SV_DCremover_Outer2_struct);
    SV_DCRemover_Init(Fs, &SV_DCremover_Acc_struct);
    SV_DCRemover_Init(Fs, &SV_DCremover_Inner_struct);
	
    // SV_AEC
    SV_AEC_Init(Fs,&SV_AEC_outer1_struct);
    SV_AEC_Init(Fs,&SV_AEC_outer2_struct);
	SV_AEC_Init_for_InEar(Fs, &SV_AEC_inEar_struct);

	// EQ, gain, delay (Rx_buf only)
	SV_EQ_Gain_Delay_Init(&EQ_Gain_Delay_Rx_struct,
		AECStatus_Get_DelayRx(&SV_AEC_inEar_struct),
		AECStatus_Get_Nfilter_AEC(&SV_AEC_inEar_struct),
		AECStatus_Get_ValClipp(&SV_AEC_inEar_struct)
		);

    // SV_AGC (!!! must be combined)
	SV_AGC_Init(Fs, &SV_AGC_2chInput_struct);

    // Gain (could it be combined with AGC ?)
    SV_Gain_Init(Fs, GAIN_ACC, &SV_Gain_Acc_struct);
    SV_Gain_Init(Fs, GAIN_OUTER1, &SV_Gain_Outer1_struct);
    SV_Gain_Init(Fs, GAIN_OUTER2, &SV_Gain_Outer2_struct);
	SV_Gain_Init(Fs, GAIN_INEAR, &SV_Gain_InEar_struct);
	SV_Gain_Init(Fs, GAIN_OUT, &SV_Gain_Out_struct);

	SV_Gain_Init(Fs, FREQ_GAIN_OUTER1, &SV_FreqGain_Outer1_struct);
	SV_Gain_Init(Fs, FREQ_GAIN_OUTER2, &SV_FreqGain_Outer2_struct);
	SV_Gain_Init(Fs, FREQ_GAIN_INEAR, &SV_FreqGain_InEar_struct);

    // FFT
    SV_realFFT_1ch_Init(&SV_realFFT_Exe_Rx_struct);
    SV_realFFT_2ch_Init(&SV_realFFT_Exe_Outer1_Outer2_struct);
    SV_realFFT_2ch_Init(&SV_realFFT_Exe_Inner_Acc_struct);
    SV_realIFFT_1ch_Init(&SV_realIFFT_Exe_Out_struct);
#ifdef DUMP_MODULE_OUTPUT
	SV_realIFFT_1ch_Init(&SV_realIFFT_Exe_BFOut_struct);
	SV_realIFFT_1ch_Init(&SV_realIFFT_Exe_BMOut_struct);
	SV_realIFFT_1ch_Init(&SV_realIFFT_Exe_InEarOut_struct);
	SV_realIFFT_1ch_Init(&SV_realIFFT_Exe_InEarBFOut_struct);
	SV_realIFFT_1ch_Init(&SV_realIFFT_Exe_InEarBMOut_struct);
	SV_realIFFT_1ch_Init(&SV_realIFFT_Exe_DNNIn1_struct);
	SV_realIFFT_1ch_Init(&SV_realIFFT_Exe_DNNIn2_struct);
	SV_realIFFT_1ch_Init(&SV_realIFFT_Exe_DNNOut_struct);
#endif

    //// MBDRC 2ch
    //SV_MBDRC_2ch_Init(Fs,&SV_MBDRC_2ch_struct);

	// Unbiased MMSE based mask estimation
	used_memory_size = SV_UnbiasedMMSE_WB_Band_Delayed_Init(&BFOutMMSE, 3, scratch_mem_ptr + total_memory_size);
	//used_memory_size = SV_UnbiasedMMSE_WB_Band_Init(&NS_vars.BFOutMMSE, scratch_mem_ptr + total_memory_size);
	dummy_size = (16 - used_memory_size % 16) % 16;
	used_memory_size += dummy_size;
	total_memory_size += used_memory_size;
	//SV_UnbiasedMMSE_SetReliableVADMode(NS_vars.BFOutMMSE, 1);
#ifdef SVTX_NS_DEBUG
	printf("MMSE memory: %d\n", used_memory_size);
#endif
	//SV_UnbiasedMMSE_Set_DisablePreventStagnation(NS_vars.BFOutMMSE, 1);

	//used_memory_size = SV_UnbiasedMMSE_WB_Band_Delayed_Init(&NS_vars.inEarOutMMSE, 3, scratch_mem_ptr + total_memory_size);
	used_memory_size = SV_UnbiasedMMSE_WB_Band_Init(&inEarOutMMSE, scratch_mem_ptr + total_memory_size);
	dummy_size = (16 - used_memory_size % 16) % 16;
	used_memory_size += dummy_size;
	total_memory_size += used_memory_size;
	//SV_UnbiasedMMSE_SetReliableVADMode(NS_vars.inEarOutMMSE, 1);
#ifdef SVTX_NS_DEBUG
	printf("MMSE memory: %d\n", used_memory_size);
#endif

#if ENABLE_DNN_INPUT_MIX == 1
	bandSize = SV_UnbiasedMMSE_Get_BandIndex(112) + 1;
	used_memory_size = SV_DNNInputSynthesis_Init((int)1, (int)112, bandSize, scratch_mem_ptr + total_memory_size);
	dummy_size = (16 - used_memory_size % 16) % 16;
	used_memory_size += dummy_size;
	total_memory_size += used_memory_size;
#ifdef SVTX_NS_DEBUG
	printf("Mixer memory: %d\n", used_memory_size);
#endif
#endif

	// VoiceAndNoiseStatus (sets many flags that will be used later in various modules)
	VoiceAndNoiseStatus_Init(Fs);
	
	//SV_AccSensor_Init();

#if ENABLE_INEARNC == 1
	// InEar NC
	SV_InEarNC_Init();
#endif

#if ENABLE_GEVBF == 1
	// GEV BF
	SV_TWS_GEVBF_Init();
#endif

#if ENABLE_DNN_NS == 1
	// DNN NS
	SV_CirCRNNS_Init();
#endif

    //SV_BF_Init(Fs,&SV_BF_struct);

    //// BFpostNS
    //SV_BFpostNS_Init(Fs,&SV_BFpostNS_struct);

    //// RES
    //SV_RES_Init(Fs,&SV_BFpostNS_struct);

    // NS
    SV_NS_Init(Fs,&SV_NS_Outer1_struct);
    //SV_NS_Init(Fs,&SV_NS_Inner_struct);

    //// NS_acc
    //SV_NS_Acc_Init(Fs,&SV_NS_Acc_struct);

    //// Remove Acc Tick
    //SV_RemoveAccTick_Init(Fs,&SV_RemoveAccTick_struct);

    //// Mixing
    //SV_Mixing_Init(Fs,&SV_Mixing_struct);

    //// Output EQ
    //SV_OutputEQ_Init(Fs,&SV_OutputEQ_struct);

    //// Output AGC
    //SV_AGC_Init(Fs,&SV_Output_AGC_outer1_struct);
}

void SV_Frame_Deinit()
{
#if ENABLE_INEARNC == 1
	SV_InEarNC_Deinit();
#endif
#if ENABLE_GEVBF == 1
	SV_TWS_GEVBF_Deinit();
#endif
#if ENABLE_DNN_INPUT_MIX == 1
	SV_DNNInputSynthesis_Deinit();
#endif
#if ENABLE_DNN_NS == 1
	SV_CirCRNNS_Deinit();
#endif
	SV_UnbiasedMMSE_Deinit();
	VoiceAndNoiseStatus_Deinit();
}
