/*
 * Copyright (C) 2025 Linux Studio Plugins Project <https://lsp-plug.in/>
 *           (C) 2025 Vladimir Sadovnikov <sadko4u@gmail.com>
 *
 * This file is part of lsp-plugins-loud-comp
 * Created on: 3 авг. 2021 г.
 *
 * lsp-plugins-loud-comp is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 *
 * lsp-plugins-loud-comp 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with lsp-plugins-loud-comp. If not, see <https://www.gnu.org/licenses/>.
 */

#ifndef PRIVATE_PLUGINS_LOUD_COMP_H_
#define PRIVATE_PLUGINS_LOUD_COMP_H_

#include <lsp-plug.in/plug-fw/plug.h>
#include <lsp-plug.in/plug-fw/core/IDBuffer.h>
#include <lsp-plug.in/dsp-units/ctl/Blink.h>
#include <lsp-plug.in/dsp-units/ctl/Bypass.h>
#include <lsp-plug.in/dsp-units/filters/Equalizer.h>
#include <lsp-plug.in/dsp-units/meters/LoudnessMeter.h>
#include <lsp-plug.in/dsp-units/noise/Generator.h>
#include <lsp-plug.in/dsp-units/util/Delay.h>
#include <lsp-plug.in/dsp-units/util/Oscillator.h>
#include <lsp-plug.in/dsp-units/util/SpectralProcessor.h>

#include <private/meta/loud_comp.h>

namespace lsp
{
    namespace plugins
    {
        /**
         * Loudness Compensator plugin series
         */
        class loud_comp: public plug::Module
        {
            protected:
                typedef struct channel_t
                {
                    float                  *vIn;        // Input buffer
                    float                  *vOut;       // Output buffer
                    float                  *vDry;       // Dry signal
                    float                  *vBuffer;    // Temporary buffer
                    float                   fInLevel;   // Input level
                    float                   fOutLevel;  // Output level
                    bool                    bHClip;     // Hard-clip

                    dspu::Bypass            sBypass;    // Bypass
                    dspu::Delay             sDelay;     // Delay (for bypass)
                    dspu::SpectralProcessor sProc;      // Spectral processor
                    dspu::Equalizer         sEqualizer; // Equalizer
                    dspu::Blink             sClipInd;   // Clip blink

                    plug::IPort            *pIn;        // Input port
                    plug::IPort            *pOut;       // Output port
                    plug::IPort            *pMeterIn;   // Input meter
                    plug::IPort            *pMeterOut;  // Output meter
                    plug::IPort            *pHClipInd;  // Hard clipping indicator
                } channel_t;

                enum generator_t
                {
                    GEN_SINE,
                    GEN_PINK_M23LUFS,
                    GEN_PINK_M20LUFS,
                    GEN_PINK_M18LUFS,
                    GEN_PINK_M16LUFS,
                    GEN_PINK_M14LUFS,
                    GEN_PINK_M12LUFS,
                };

            protected:
                uint32_t                nChannels;      // Number of channels
                uint32_t                nMode;          // Operating mode
                uint32_t                nCurve;         // Currently selected curve
                uint32_t                nRank;          // Current FFT rank
                uint32_t                nFilters;       // Number of filters
                float                   fGain;          // Input gain
                float                   fVolume;        // Volume
                float                   fInLufs;        // Input LUFS
                float                   fOutLufs;       // Output LUFS
                generator_t             enGenerator;    // Generator type
                bool                    bBypass;        // Bypass
                bool                    bRelative;      // Display relative curve instead of absolute
                bool                    bReference;     // Reference generator
                bool                    bHClipOn;       // Enable hard-clipping
                float                   fHClipLvl;      // Hard-clip threshold
                channel_t              *vChannels[2];   // Audio channels
                float                  *vTmpBuf;        // Temporary buffer for processing
                float                  *vFreqApply;     // Frequency response applied to the output signal
                float                  *vFreqMesh;      // List of frequencies for the mesh
                float                  *vAmpMesh;       // List of amplitudes for the mesh
                bool                    bSyncMesh;      // Synchronize mesh response with UI
                bool                    bSmooth;        // Smooth mode of equalizer
                core::IDBuffer         *pIDisplay;      // Inline display buffer

                float                   vOldGains[meta::loud_comp_metadata::FILTER_BANDS];
                float                   vGains[meta::loud_comp_metadata::FILTER_BANDS];
                dspu::Oscillator        sOsc;           // Oscillator for reference sound
                dspu::NoiseGenerator    sNoise;         // Pink noise generator
                dspu::LoudnessMeter     sInMeter;       // Input loudness meter
                dspu::LoudnessMeter     sOutMeter;      // Output loudness meter

                uint8_t                *pData;          // Allocation data

                plug::IPort            *pBypass;        // Bypass
                plug::IPort            *pGain;          // Input gain
                plug::IPort            *pMode;          // Operating mode
                plug::IPort            *pCurve;         // Curve selector
                plug::IPort            *pRank;          // FFT rank selector
                plug::IPort            *pApproximation; // IIR approximation
                plug::IPort            *pVolume;        // Output volume
                plug::IPort            *pMesh;          // Output mesh response
                plug::IPort            *pRelative;      // Relative mesh display
                plug::IPort            *pLufsIn;        // Input LUFS meter
                plug::IPort            *pLufsOut;       // Output LUFS meter
                plug::IPort            *pReference;     // Enable reference sine generator
                plug::IPort            *pGenerator;     // Generator type
                plug::IPort            *pHClipOn;       // Enable Hard clip
                plug::IPort            *pHClipRange;    // Hard clipping range
                plug::IPort            *pHClipReset;    // Hard clipping reset

            protected:
                void                update_fft_curve();
                void                update_iir_curve(uint32_t slope);
                void                process_spectrum(channel_t *c, float *buf);
                void                generate_signal(size_t samples);
                void                process_audio(size_t samples);
                void                generate_frequencies();
                void                do_destroy();
                void                process_iir_equalizer(channel_t *c, size_t samples);

            protected:
                static void         process_callback(void *object, void *subject, float *buf, size_t rank);
                static generator_t  decode_generator(size_t generator);
                static float        get_generator_amplitude(generator_t gen, bool stereo);

            public:
                explicit loud_comp(const meta::plugin_t *metadata, size_t channels);
                virtual ~loud_comp() override;

                virtual void        init(plug::IWrapper *wrapper, plug::IPort **ports) override;
                virtual void        destroy() override;

            public:
                virtual void        ui_activated() override;
                virtual void        update_sample_rate(long sr) override;
                virtual void        update_settings() override;
                virtual void        process(size_t samples) override;
                virtual bool        inline_display(plug::ICanvas *cv, size_t width, size_t height) override;
                virtual void        dump(dspu::IStateDumper *v) const override;
        };

    } /* namespace plugins */
} /* namespace lsp */

#endif /* PRIVATE_PLUGINS_LOUD_COMP_H_ */
