#ifndef _FASTFFT_CLASS_HPP
#define _FASTFFT_CLASS_HPP 1

/*
**
** FastFFTC.hpp
**
** $VER: FastFFTC.hpp 1.0 (24.07.98)
**
** Classe FastFFTC
**
** $Revision: 1.3 $
** $State: Exp $
** $Date: 1998/08/16 19:03:45 $
**
** $Log: FastFFTC.hpp $
** Revision 1.3  1998/08/16 19:03:45  kakace
** Version Beta3+
**
** Revision 1.2  1998/08/02 15:17:11  kakace
** Fonctionnement OK (Layer 1/2 + Stereo/JStereo)
**
** Revision 1.1  1998/07/24 14:26:57  kakace
** Automatic global CheckIn
**
**
*/

#ifndef  _PEGASECOND_HPP
#include "PegaseCond.hpp"
#endif

#ifndef  EXEC_TYPES_H
#include <exec/types.h>
#endif


typedef float T_FFTDATAS;


//----------------------------------------------------------------------------------------------------
//========================================= Classe FastFFTC ==========================================
//----------------------------------------------------------------------------------------------------

const ULONG SINCOSSIZE  =  768;
const ULONG BLKSIZE     = 1024;
const ULONG HBLKSIZE    =  513;


//----------------------------------------------------------------------------------------------------
// Version n'utilisant pas de table pour les valeurs Sin/Cos

class FastFFTC
{
    private:

        // Fonctions nécessaires lorsqu'on n'utilise pas les versions optimisées en ASM.

#if _USE_ASM_FCT_ == 0
        void FastFFT(T_FFTDATAS *pd_FFTIn, UWORD iFFTSize);
        void FixFFT_Stereo(T_FFTDATAS *pd_FFTIn, UWORD iFFTSize);
        void FixFFT_Mono(T_FFTDATAS *pd_FFTIn, UWORD iFFTSize);
#endif

        ULONG   GetShuffleIndex_10(ULONG input);
        ULONG   GetShuffleIndex_8(ULONG input);

    protected:

        typedef T_FFTDATAS  T_HANN[BLKSIZE];
        typedef T_FFTDATAS  T_FFTBUFF[2][BLKSIZE][2];

        // Sélection du type de table Sin/Cos.
        // A partir du 68040, il est plus rapide de dériver les valeurs sin() et cos()
        // depuis les valeurs précédentes, plutôt que d'utiliser une table précalculée
        // (cette table demandant de nombreux accès mémoire). En contrepartie, les
        // calculs doivent être effectués en double précision.

#if _USE_SINCOS_TABLE_ == 1
        typedef float T_SINCOS[SINCOSSIZE];
        T_SINCOS      FFT_dSinCos;
#else
        double        FFT_dSinCos[2][10];
#endif

        T_HANN       *FFT_pdHannWindowShuffled;
        T_FFTBUFF    *FFT_pdWinSmplShuffled;     // (wsamp_r[]/wsamp_i[])
        int           FFT_MemoryError;

    public:

        FastFFTC();
        ~FastFFTC();

        void ComputeFastFFT_Stereo(UWORD iFFTSize);
        void ComputeFastFFT_Mono(UWORD iFFTSize);
        void SetupWinSamples_1024(WORD *pSamples, UWORD wNumChannels);

        T_FFTBUFF       *FFT_pdWindowedSmpl;        // (wsamp_r[]/wsamp_i[])
        T_HANN          *FFT_pdHannWindow;
        REAL             FFT_dMaxErrorLevel;
};

//----------------------------------------------------------------------------------------------------

#if _USE_ASM_FCT_ == 1

extern "C" {
void SetupWinSamples_1024(WORD *pSamples, UWORD wNumChannels, const T_FFTDATAS *pdHANNWindow, T_FFTDATAS *pdWSmpls);
void FastFFT_Stereo_C(T_FFTDATAS *pdFFTIn, double dSinCos[2][10], UWORD iFFTSize);
void FastFFT_Stereo_T(T_FFTDATAS *pdFFTIn, float dSinCos[SINCOSSIZE], UWORD iFFTSize);
void FastFFT_Mono_C(T_FFTDATAS *pdFFTIn, double dSinCos[2][10], UWORD iFFTSize);
void FastFFT_Mono_T(T_FFTDATAS *pdFFTIn, float dSinCos[SINCOSSIZE], UWORD iFFTSize);
}

inline void FastFFTC::SetupWinSamples_1024(WORD *pSamples, UWORD wNumChannels)
{
    ::SetupWinSamples_1024(pSamples, wNumChannels, (const T_FFTDATAS *) FFT_pdHannWindowShuffled, (T_FFTDATAS *) FFT_pdWinSmplShuffled);
}

#endif


inline void FastFFTC::ComputeFastFFT_Stereo(UWORD iFFTSize)
{
    T_FFTDATAS *pd_FFTIn = (T_FFTDATAS *) FFT_pdWinSmplShuffled;

#if _USE_ASM_FCT_ == 0

    FastFFT(pd_FFTIn, iFFTSize);
    FixFFT_Stereo(pd_FFTIn, iFFTSize);

#else

    // Sélection de la fonction à utiliser suivant le type de la table Sin/Cos.

#if _USE_SINCOS_TABLE_ == 1
    ::FastFFT_Stereo_T(pd_FFTIn, FFT_dSinCos, iFFTSize);
#else
    ::FastFFT_Stereo_C(pd_FFTIn, FFT_dSinCos, iFFTSize);
#endif

#endif
}


inline void FastFFTC::ComputeFastFFT_Mono(UWORD iFFTSize)
{
    T_FFTDATAS *pd_FFTIn = (T_FFTDATAS *) FFT_pdWinSmplShuffled;

#if _USE_ASM_FCT_ == 0

    iFFTSize >>= 1;
    FastFFT(pd_FFTIn, iFFTSize);
    FixFFT_Mono(pd_FFTIn, iFFTSize);

#else

    // Sélection de la fonction à utiliser suivant le type de la table Sin/Cos.

#if _USE_SINCOS_TABLE_ == 1
    ::FastFFT_Mono_T(pd_FFTIn, FFT_dSinCos, iFFTSize);
#else
    ::FastFFT_Mono_C(pd_FFTIn, FFT_dSinCos, iFFTSize);
#endif

#endif
}


#endif  // _FASTFFT_CLASS_HPP

