/*
    FilterParams.h - Parameters for filter

    Original ZynAddSubFX author Nasca Octavian Paul
    Copyright (C) 2002-2005 Nasca Octavian Paul
    Copyright 2009-2011, Alan Calvert
    Copyright 2018 - 2023, Will Godfrey

    This file is part of yoshimi, which is free software: you can redistribute
    it and/or modify it under the terms of the GNU General Public
    License as published by the Free Software Foundation; either version 2 of
    the License, or (at your option) any later version.

    yoshimi is distributed in the hope that it will be useful, but WITHOUT ANY
    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    FOR A PARTICULAR PURPOSE.   See the GNU General Public License (version 2 or
    later) for more details.

    You should have received a copy of the GNU General Public License along with
    yoshimi; if not, write to the Free Software Foundation, Inc., 51 Franklin
    Street, Fifth Floor, Boston, MA  02110-1301, USA.

    This file is a derivative of a ZynAddSubFX original.

*/

#ifndef FILTER_PARAMS_H
#define FILTER_PARAMS_H

#include "Params/ParamCheck.h"
#include "Misc/NumericFuncs.h"
#include "globals.h"

#include <cmath>

using func::power;
using func::decibel;

class XMLwrapper;
class SynthEngine;

class FilterParams : public ParamBase
{
    public:
        FilterParams(uchar Ptype_, float Pfreq, float Pq_, uchar Pfreqtrackoffset_, SynthEngine&);

        void defaults()  override;

        void add2XML(XMLwrapper& xml);
        void add2XMLsection(XMLwrapper& xml, int n);
        void getfromXML(XMLwrapper& xml);
        void getfromXMLsection(XMLwrapper& xml, int n);


        void getfromFilterParams(FilterParams *pars);

        float getfreq();
        float getq();
        float getfreqtracking(float notefreq);
        float getgain();

        float getcenterfreq();
        float getoctavesfreq();
        float getfreqpos(float freq);
        float getfreqx(float x);

        void formantfilterH(int nvowel, int nfreqs, float *freqs); // used by UI

        float getformantfreq(float freq) // Transforms a parameter to
            { return getfreqx(freq / 127.0f); }  // the real value
        float getformantamp(float amp)
            { return decibel<-80>(1.0f - amp / 127.0f); }
        float getformantq(float q)
            { return power<25>((q - 32.0f) / 64.0f); }

        uchar Pcategory;         // Filter category (Analog/Formant/StVar)
        uchar Ptype;             // Filter type  (for analog lpf,hpf,bpf..)
        float Pfreq;             // Frequency (64-central frequency)
        float Pq;                // Q parameters (resonance or bandwidth)
        uchar Pstages;           // filter stages+1
        float Pfreqtrack;        // how the filter frequency is changing
                                 // according the note frequency
        uchar Pfreqtrackoffset;  // Shift range for freq tracking
        float Pgain;             // filter's output gain

        // Formant filter parameters
        uchar Pnumformants;      // how many formants are used
        uchar Pformantslowness;  // how slow varies the formants
        uchar Pvowelclearness;   // how vowels are kept clean (how much try
                                 // to avoid "mixed" vowels)
        uchar Pcenterfreq;       // the centre frequency of the res. func.
        uchar Poctavesfreq;      // the number of octaves
        struct {
            struct {
                float firstF, freq, amp, q; // frequency,amplitude,Q
            } formants[FF_MAX_FORMANTS];
        } Pvowels[FF_MAX_VOWELS];

        uchar Psequencesize;     // how many vowels are in the sequence
        float Psequencestretch;  // how the sequence is stretched (how the input from filter envelopes/LFOs/etc. is "stretched")
        uchar Psequencereversed; // if the input from filter envelopes/LFOs/etc. is reversed(negated)

        struct {
            uchar nvowel; // the vowel from the position
        } Psequence[FF_MAX_SEQUENCE];

        bool changed;

    private:
        void defaults(int n);

        // stored default parameters
        uchar Dtype;
        float Dfreq;
        float Dq;
        uchar Dfreqtrackoffset;
};

class filterLimit
{
    public:
        float getFilterLimits(CommandBlock *getData);
};

struct FILTminmax{
    float min;
    float max;
    float def;
    bool learn;
    bool integer;
};
namespace FILTDEF{
    const FILTminmax addFreq {0,127,94,true,false};
    const FILTminmax voiceFreq {0,127,50,true,false};
    const FILTminmax subFreq {0,127,80,true,false};
    const FILTminmax padFreq {0,127,94,true,false};

        const FILTminmax dynFreq0 {0,127,45,true,false};
        const FILTminmax dynFreq1 {0,127,72,true,false};
        const FILTminmax dynFreq2 {0,127,64,true,false};
        const FILTminmax dynFreq3 {0,127,50,true,false};
        const FILTminmax dynFreq4 {0,127,64,true,false};

    const FILTminmax qVal {0,127,40,true,false};
        const FILTminmax voiceQval {0,127,60,true,false};

        const FILTminmax dynQval0 {0,127,64,true,false};
        const FILTminmax dynQval1 {0,127,64,true,false};
        const FILTminmax dynQval2 {0,127,64,true,false};
        const FILTminmax dynQval3 {0,127,70,true,false};
        const FILTminmax dynQval4 {0,127,70,true,false};

    const FILTminmax velSense {0,127,64,true,false};
        const FILTminmax voiceVelSense {0,127,0,true,false};
    const FILTminmax velFuncSense {0,127,64,true,true};
    const FILTminmax gain {0,127,64,true,false};
    const FILTminmax freqTrack {0,127,64,true,true};

    const FILTminmax formCount {1,FF_MAX_FORMANTS,3,false,true};
    const FILTminmax formSpeed {0,127,64,true,false};
    const FILTminmax formClear {0,127,64,true,false};
    const FILTminmax formFreq {0,127,-1,true,false}; // pseudo default value
    const FILTminmax formQ {0,127,64,true,false};
    const FILTminmax formAmp {0,127,127,true,false};
    const FILTminmax formStretch {0,127,40,true,false};
    const FILTminmax formCentre {0,127,64,true,true};
    const FILTminmax formOctave {0,127,64,true,true};
    const FILTminmax formVowel {1,FF_MAX_SEQUENCE,1,false,true};
    const FILTminmax sequenceSize{1,FF_MAX_SEQUENCE,3,false,true};

    const FILTminmax stages {0,MAX_FILTER_STAGES-1,0,false,true};
        const FILTminmax dynStages {0,MAX_FILTER_STAGES-1,1,false,true};
    const FILTminmax category {0,2,0,false,true};
    const FILTminmax analogType {0,8,2,false,true};
    const FILTminmax stVarfType {0,3,0,false,true};
}

struct DYNinsert{
    float freq;
    float amp;
    float q;
};

namespace DYNform{
    const DYNinsert Preset3V0F0 {34,127,64};
    const DYNinsert Preset3V0F1 {99,122,64};
    const DYNinsert Preset3V0F2 {108,112,64};
    const DYNinsert Preset3V1F0 {61,127,64};
    const DYNinsert Preset3V1F1 {71,121,64};
    const DYNinsert Preset3V1F2 {99,117,64};

    const DYNinsert Preset4V0F0 {70,127,64};
    const DYNinsert Preset4V0F1 {80,122,64};
    const DYNinsert Preset4V1F0 {20,127,64};
    const DYNinsert Preset4V1F1 {100,121,64};
}

namespace FILTSWITCH{
    const bool trackRange = false;
    const bool sequenceReverse = false;
}
#endif
