//-------------------------------------------------------------------
//  FFT で使う場合の窓掛け処理の抽象基底クラス
//      ゼロ詰め（zero-padding）の機能を持つ
//
//  2022/10/17, Copyright (c) 2022 MIKAMI, Naoki
//-------------------------------------------------------------------

#ifndef WINDOW_BASE_HPP
#define WINDOW_BASE_HPP

#include "Array.hpp"

namespace Mikami
{
    class WindowBase
    {
    public:
        // コンストラクタ
        //      nFft    使用する FFT の点数
        //      nData   使用するデータ数，nData <= fFft
        WindowBase(uint16_t nFft, uint16_t nData)
            : PI2L_(6.283185f/nData), NFFT_(nFft), N_(nData),
              y_(nFft), w_(nData) { IsOk(); }

        // 窓掛けを実行
        Array<float>& Execute(const Array<float> &x)
        {
            for (int n=0; n<N_; n++) y_[n] = x[n]*w_[n];
            // ゼロ詰めの処理
            for (int n=N_; n<NFFT_; n++) y_[n] = 0.0f;
            return y_;
        }

    protected:
        const float PI2L_;      // 窓関数のデータを発生する計算で使用
        // 窓関数のデータを設定する
        void Set(int n, float win) { w_[n] = win; }

    private:
        const uint16_t NFFT_;   // この窓掛けを使う FFT の点数
        const uint16_t N_;      // 解析に使うデータ数
        Array<float> y_;        // 窓掛けされたデータ
        Array<float> w_;        // 窓関数のデータ
 
        // コンストラクタの引数をチェックする
        void IsOk() const
        {
            // nFft が２のべき乗であることをチェックする
            // __clz(): リーディング 0 の数を取得する命令に対応
            uint32_t shifted = NFFT_ << (__clz(NFFT_)+1);
            MBED_ASSERT(shifted == 0);
            
            // nData <= nFft であることをチェックする
            MBED_ASSERT(N_ <= NFFT_);
        }

        // 窓関数を生成
        virtual void Generate(uint16_t nData) = 0;

        // コピー･コンストラクタおよび代入演算子の禁止のため
        WindowBase(const WindowBase& );
        WindowBase& operator=(const WindowBase& );
    };
}
#endif  // WINDOW_BASE_HPP
