//--------------------------------------------------------------
//  Weaver 変調器
//      入力信号の帯域：             0.1 kHz ---- 6.9 kHz
//      帯域中央の周波数：           3.5 kHz
//      低域通過フィルタの遮断周波数： 3.4 kHz
//
//  2017/04/10, Copyright (c) 2016 MIKAMI, Naoki
//--------------------------------------------------------------

#ifndef WEAVER_MODULATOR_HPP
#define WEAVER_MODULATOR_HPP

#include "ProcessingBase.hpp"
#include "IIR_Cascade.hpp"
#include "Coefficients.hpp"  // Coeffisients of BPF and LPF

namespace Mikami
{
    class WeaverMod : public ProcessingBase
    {
    public:
        WeaverMod(float fS, float fShift = 0)
            : bpf_(ORDER_BPF_, ckBpf_, g0Bpf_),
              lpfC_(ORDER_, ck_, g0Lpf_), lpfS_(ORDER_, ck_, g0Lpf_),
              FS_(fS), PI2_(3.1415926536f*2), F_B0_(3500),
              phi1_(0), dPhi1_(F_B0_*PI2_/FS_), phi2_(0)
        {   SetFrequency(fShift); }

        virtual float Execute(float xn)
        {
            float un = bpf_.Execute(xn);    // 帯域通過フィルタ（BPF）

            float mpyC = un*cosf(phi1_);
            float mpyS = un*sinf(phi1_);

            // 低域通過フィルタ（LPF）
            float mpyC_Lpf = lpfC_.Execute(mpyC);
            float mpyS_Lpf = lpfS_.Execute(mpyS);

            float mpyC_C = mpyC_Lpf*cosf(phi2_);
            float mpyS_S = mpyS_Lpf*sinf(phi2_);

            float yn = 2.0f*(mpyC_C + mpyS_S);

            phi1_ = phi1_ + dPhi1_;
            if (phi1_ > PI2_) phi1_ = phi1_ - PI2_;
            phi2_ = phi2_ + dPhi2_;
            if (phi2_ > PI2_) phi2_ = phi2_ - PI2_;

            return yn;
        }

        // 周波数のシフト量を設定
        void SetFrequency(float fShift)
        {   dPhi2_ = (fShift + F_B0_)*PI2_/FS_; }

    private:
        // 帯域通過フィルタ
        IIR_Cascade bpf_;
        // Weaver 変調器で使う低域通過フィルタ 
        IIR_Cascade lpfC_, lpfS_;

        const float FS_;
        const float PI2_;
        const float F_B0_;  // 中心周波数

        float phi1_, dPhi1_;
        float phi2_, dPhi2_;

        // disallow copy constructor and assignment operator
        WeaverMod(const WeaverMod& );
        WeaverMod& operator=(const WeaverMod& );
    };
}
#endif  // WEAVER_MODULATOR_HPP
