/**************************************
		SV_FFT.c
***************************************/

#include <string.h>

#include "SV_realFFT.h"

#include "SEC_AudioRD_RealFFT.h"

#define QWIN 15
static const short win[FFTOVERLAP]={          // half of window only
#include"SV_FFT_wincoeffs.dat"
};


static void SV_realFFT_windowing(int* pa, short* wa, int* pb, short* wb, int* in, int n)
{
    do{
        int d=*in++;
        *pa++=(int)((INT64)d*(*wa--))>>QWIN;
        *pb++=(int)((INT64)d*(*wb++))>>QWIN;
    }while(--n>0);
}

static void SV_realIFFT_windowing_add(int* out, int* pa, short* wa, int* pb, short* wb, int n)
{
    do{
        int d=(int)((INT64)(*pa++)*(*wa++))>>QWIN;
        d+=(int)((INT64)(*pb++)*(*wb--))>>QWIN;
        *out++=d;
    }while(--n>0);
}

/* 	 SV_realFFT_1ch_Exe
     C : 1.36MCPS	 */
void SV_realFFT_1ch_Exe(ComplexInt* out, int* in, int n, SV_realFFT_1ch_T* p_struct)
{
    // windowing
	memcpy(p_struct->pa + FFTOVERLAP, in, sizeof(int)*(FFTLEN - 2 * FFTOVERLAP));
	SV_realFFT_windowing(p_struct->pa + (FFTLEN - FFTOVERLAP), win + FFTOVERLAP - 1, p_struct->pb, win, in + (FFTLEN - 2 * FFTOVERLAP), (int)FFTOVERLAP);    // fill last part of "pa" and first part of "pb"

    // FFT
	SEC_AudioRD_RealFFT_Forward_1ch(out, p_struct->pa, (int)FFTLOGLEN);

    // exchange pointers
    {int* p=p_struct->pa;p_struct->pa=p_struct->pb;p_struct->pb=p;}
}

void SV_realFFT_1ch_Init(SV_realFFT_1ch_T* p_struct)
{
    memset(p_struct->winbuf_0,0,sizeof(p_struct->winbuf_0));
    memset(p_struct->winbuf_1,0,sizeof(p_struct->winbuf_1));
    p_struct->pa=p_struct->winbuf_0;
    p_struct->pb=p_struct->winbuf_1;
}

/* SV_realFFT_2ch_Exe
 * C : 2.86 MCPS
 */
void SV_realFFT_2ch_Exe(ComplexInt* out0, ComplexInt* out1, int* in0, int* in1, int n, SV_realFFT_2ch_T* p_struct)
{
    // windowing ch0
	memcpy(p_struct->pa + FFTOVERLAP, in0, sizeof(int)*(FFTLEN - 2 * FFTOVERLAP));
	SV_realFFT_windowing(p_struct->pa + (FFTLEN - FFTOVERLAP), win + FFTOVERLAP - 1, p_struct->pb, win, in0 + (FFTLEN - 2 * FFTOVERLAP), (int)FFTOVERLAP);    // fill last part of "pa" and first part of "pb"

    // windowing ch1
	memcpy(p_struct->pc + FFTOVERLAP, in1, sizeof(int)*(FFTLEN - 2 * FFTOVERLAP));
	SV_realFFT_windowing(p_struct->pc + (FFTLEN - FFTOVERLAP), win + FFTOVERLAP - 1, p_struct->pd, win, in1 + (FFTLEN - 2 * FFTOVERLAP), (int)FFTOVERLAP);    // fill last part of "pa" and first part of "pb"

    // FFT
	SEC_AudioRD_RealFFT_Forward_2ch(out0, out1, p_struct->pa, p_struct->pc, (int)FFTLOGLEN);

    // exchange pointers
    {int* p=p_struct->pa;p_struct->pa=p_struct->pb;p_struct->pb=p;}
    {int* p=p_struct->pc;p_struct->pc=p_struct->pd;p_struct->pd=p;}
}

void SV_realFFT_2ch_Init(SV_realFFT_2ch_T* p_struct)
{
    memset(p_struct->winbuf_ch1_0,0,sizeof(p_struct->winbuf_ch1_0));
    memset(p_struct->winbuf_ch1_1,0,sizeof(p_struct->winbuf_ch1_1));
    memset(p_struct->winbuf_ch2_0,0,sizeof(p_struct->winbuf_ch2_0));
    memset(p_struct->winbuf_ch2_1,0,sizeof(p_struct->winbuf_ch2_1));
    p_struct->pa=p_struct->winbuf_ch1_0;
    p_struct->pb=p_struct->winbuf_ch1_1;
    p_struct->pc=p_struct->winbuf_ch2_0;
    p_struct->pd=p_struct->winbuf_ch2_1;
}

/* SV_realIFFT_1ch_Exe
 * C : 1.47MCPS
 */
void SV_realIFFT_1ch_Exe(int* out, ComplexInt* in, int n, SV_realFFT_1ch_T* p_struct)
{
    // IFFT
	SEC_AudioRD_RealFFT_Inverse_1ch(p_struct->pa, in, (int)FFTLOGLEN);

    // windowing and add
	SV_realIFFT_windowing_add(out, p_struct->pa, win, p_struct->pb + (FFTLEN - FFTOVERLAP), win + FFTOVERLAP - 1, (int)FFTOVERLAP);
    memcpy(out+FFTOVERLAP,p_struct->pa+FFTOVERLAP,sizeof(int)*(FFTLEN-2*FFTOVERLAP));

	// exchange pointers
	{int* p = p_struct->pa; p_struct->pa = p_struct->pb; p_struct->pb = p; }
}

void SV_realIFFT_1ch_Init(SV_realFFT_1ch_T* p_struct)
{
    memset(p_struct->winbuf_0,0,sizeof(p_struct->winbuf_0));
    memset(p_struct->winbuf_1,0,sizeof(p_struct->winbuf_1));
    p_struct->pa=p_struct->winbuf_0;
    p_struct->pb=p_struct->winbuf_1;
}


