/*
  ZynAddSubFX - a software synthesizer

  PADnoteParameters.h - Parameters for PADnote (PADsynth)
  Copyright (C) 2002-2005 Nasca Octavian Paul
  Author: Nasca Octavian Paul

  This program 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.
*/

#ifndef PAD_NOTE_PARAMETERS_H
#define PAD_NOTE_PARAMETERS_H

#include "../globals.h"

#include "Presets.h"
#include <string>
#include <functional>

namespace zyn {

/**
 * Parameters for PAD synthesis
 *
 * @note unlike most other parameter objects significant portions of this
 * object are `owned' by the non-realtime context. The realtime context only
 * needs the samples generated by the PADsynth algorithm and modulators (ie
 * envelopes/filters/LFOs) for amplitude, frequency, and filters.
 * The ownership will be unclear for the time being, but it should be made more
 * explicit with time.
 */
class PADnoteParameters:public Presets
{
    public:
        PADnoteParameters(const SYNTH_T &synth_, FFTwrapper *fft_,
                          const AbsTime *time_ = nullptr);
        ~PADnoteParameters() override;

        void defaults();
        void add2XML(XMLwrapper& xml) override;
        void getfromXML(XMLwrapper& xml);

        void paste(PADnoteParameters &p);
        void pasteRT(PADnoteParameters &p);

        //returns a value between 0.0f-1.0f that represents the estimation perceived bandwidth
        float getprofile(float *smp, int size);

        //parameters
        //! the mode how bandwidth is created
        //! the harmonic profile is used only on mode 0
        enum class pad_mode
        {
            //! "normal" mode, generate the wave with bandwidth
            bandwidth,
            //! bandwidth = 0, almost like adnote
            discrete,
            //! filtered noise
            continous
        } Pmode;

        //Harmonic profile (the frequency distribution of a single harmonic)
        struct {
            struct { //base function
                unsigned char type;
                unsigned char par1;
            } base;
            unsigned char freqmult; //frequency multiplier of the distribution
            struct { //the modulator of the distribution
                unsigned char par1;
                unsigned char freq;
            } modulator;

            unsigned char width; //the width of the resulting function after the modulation
            struct { //the amplitude multiplier of the harmonic profile
                unsigned char mode;
                unsigned char type;
                unsigned char par1;
                unsigned char par2;
            } amp;
            bool autoscale; //if the scale of the harmonic profile is computed automatically
            unsigned char onehalf; //what part of the base function is used to make the distribution
        } Php;


        unsigned int  Pbandwidth; //the values are from 0 to 1000
        unsigned char Pbwscale; //how the bandwidth is increased according to the harmonic's frequency

        struct { //where are positioned the harmonics (on integer multimplier or different places)
            unsigned char type;
            unsigned char par1, par2, par3; //0..255
        } Phrpos;

        struct { //quality of the samples (how many samples, the length of them,etc.)
            unsigned char samplesize;
            unsigned char basenote, oct, smpoct;
        } Pquality;

        //frequency parameters
        //If the base frequency is fixed to 440 Hz
        unsigned char Pfixedfreq;

        /* Equal temperate (this is used only if the Pfixedfreq is enabled)
           If this parameter is 0, the frequency is fixed (to 440 Hz);
           if this parameter is 64, 1 MIDI halftone -> 1 frequency halftone */
        unsigned char PfixedfreqET;
        unsigned char PBendAdjust;
        unsigned char POffsetHz;
        unsigned short int PDetune; //fine detune
        unsigned short int PCoarseDetune; //coarse detune+octave
        unsigned char      PDetuneType; //detune type

        EnvelopeParams *FreqEnvelope; //Frequency Envelope
        LFOParams      *FreqLfo; //Frequency LFO

        //Amplitude parameters
        unsigned char PStereo;
        /* Panning -  0 - random
                  1 - left
                 64 - center
                127 - right */
        unsigned char PPanning;

        unsigned char PVolume;

        unsigned char PAmpVelocityScaleFunction;

        EnvelopeParams *AmpEnvelope;

        LFOParams *AmpLfo;

        /* Adjustment factor for anti-pop fadein */
        unsigned char Fadein_adjustment;

        unsigned char PPunchStrength, PPunchTime, PPunchStretch,
                      PPunchVelocitySensing;

        //Filter Parameters
        FilterParams *GlobalFilter;

        // filter velocity sensing
        unsigned char PFilterVelocityScale;

        // filter velocity sensing
        unsigned char PFilterVelocityScaleFunction;

        EnvelopeParams *FilterEnvelope;
        LFOParams      *FilterLfo;




        float setPbandwidth(int Pbandwidth); //!< Return the BandWidth in cents
        //! Get the n-th overtone position relatively to N harmonic
        float getNhr(int n) const;

        void applyparameters(void);
        //! Compute the #sample array from the other parameters.
        //! For the function's parameters, see sampleGenerator()
        void applyparameters(std::function<bool()> do_abort,
                             unsigned max_threads = 0);
        void export2wav(std::string basefilename);

        OscilGen  *oscilgen;
        Resonance *resonance;

        struct Sample {
            int    size;
            float  basefreq;
            float *smp;
        };

        //! RT sample data
        Sample sample[PAD_MAX_SAMPLES];

        //! callback type for sampleGenerator
        typedef std::function<void(int,PADnoteParameters::Sample&&)> callback;

        //! PAD synth main function
        //! Generate spectrum and run IFFTs on it
        //! @param cb A callback that will be executed for each sample buffer
        //!           Note that this function can be executed by multiple
        //!           threads at the same time, so make sure you use mutexes
        //!           etc where required
        //! @param do_abort Function that decides whether the calculation should
        //!                 be aborted (probably because of interruptions by the
        //!                 user)
        //! @param max_threads Maximum number of threads for computation, or
        //!                    zero if no maximum shall be set
        int sampleGenerator(PADnoteParameters::callback cb,
                            std::function<bool()> do_abort,
                            unsigned max_threads = 0);

        const AbsTime *time;
        int64_t last_update_timestamp;

        static const rtosc::MergePorts ports;
        static const rtosc::Ports     &non_realtime_ports;
        static const rtosc::Ports     &realtime_ports;

    private:
        void generatespectrum_bandwidthMode(float *spectrum,
                                            int size,
                                            float basefreq,
                                            const float *profile,
                                            int profilesize,
                                            float bwadjust) const;
        void generatespectrum_otherModes(float *spectrum,
                                         int size,
                                         float basefreq) const;
        void deletesamples();
        void deletesample(int n);

    public:
        const SYNTH_T &synth;
};

}

#endif
