// BKSoundDevice.h: interface for the CBKSoundDevice class.
//


#pragma once

#include "BKMessageBox.h"       // нужно в дочерних классах
#include "BKSound_Defines.h"
#include "libdspl-2.0.h"        // нужно в дочерних классах


constexpr auto DCOFFSET_BUFFER_MASK = 0xff; // степень двойки минус 1
constexpr auto DCOFFSET_BUFFER_LEN = (DCOFFSET_BUFFER_MASK + 1); // степень двойки

// длина ких фильтра. нечётная. чтоб симметричную характеристику строить
constexpr auto FIR_LENGTH = 127;

class CBKSoundDevice
{
	protected:
		// накопители значения сэмпла, значимо только последнее на момент выборки значение
		double          m_dAccL{ 0.0 }, m_dAccR{ 0.0 };

		// переменные для вычисления смещения DC.
		double          m_dAvgL{ 0.0 }, m_dAvgR{ 0.0 };
		std::vector<double> m_pdDCBufL;
		std::vector<double> m_pdDCBufR;
		int             m_nDCBufPosL{ 0 }, m_nDCBufPosR{ 0 };

		std::vector<double> m_pH;			// коэффициенты КИХ
		int             m_nFirLength{ FIR_LENGTH };  // размер буфера коэффициентов

		std::vector<double> m_pdFBufL;		// буферы для фильтра левый канал
		std::vector<double> m_pdFBufR;		// правый канал
		int             m_nFBufPosL{ 0 };   // позиции в буферах фильтра
		int             m_nFBufPosR{ 0 };

		// эмулятор конденсатора
		struct sRCFparam
		{
			double      ft{0.0};			// аккумулятор временного интервала
			SAMPLE_INT  fmaxvol{0.0};
			SAMPLE_INT  fminvol{0.0};
			SAMPLE_INT  fdeltavol{0.0};
			SAMPLE_INT  fUi_prev{0.0};
			bool        bRCProc{false};		// флаг, обозначает, что идёт в данный момент false - разряд true - заряд
		};

		sRCFparam       m_RCFL, m_RCFR;
		double          m_RCFVal{ 1.0 };

		bool            m_bEnableSound{true};   // флаг разрешения звука
		bool            m_bFilter{ true };      // флаг включения фильтрации звука
		bool            m_bDCOffset{ false };   // включить функцию корректировки смещения
		bool            m_bStereo{ false };

		void            RCFilter(sRCFparam &p, const double fAcc, const double fTime) const;
		inline SAMPLE_INT RCFilterCalc(const sRCFparam &p) const;
		inline void     SetFCFilterValue(const double v)
		{
			m_RCFVal = v;
		}

		double          DCOffset(const double sample, std::span<double> pBuf, int &nBufPos, double &fAvg) const;
		double          FIRFilter(const double sample, std::span<double> pBuf, int &nBufPos) const;

		double          Compressor(const double sample);

		bool            CreateFIRBuffers(int nLen);
	public:
		CBKSoundDevice();
		virtual ~CBKSoundDevice();
		virtual void    ReInit() {}
		virtual void    Reset() {}

		inline void     EnableSound(bool bEnable)
		{
			m_bEnableSound = bEnable;

			if (!bEnable)
			{
				m_dAccL = m_dAccR = 0.0;
			}
		}
		inline bool     IsSoundEnabled() const
		{
			return m_bEnableSound;
		}

		inline void     SetFilter(const bool bEnable)
		{
			m_bFilter = bEnable;
		}
		inline bool     IsFilter() const
		{
			return m_bFilter;
		}
		inline void     SetDCOffsetCorrect(const bool bEnable)
		{
			m_bDCOffset = bEnable;
		}
		inline bool     IsDCOffsetCorrect() const
		{
			return m_bDCOffset;
		}
		inline void     SetStereo(const bool bEnable)
		{
			m_bStereo = bEnable;
		};
		inline bool     IsStereo() const
		{
			return m_bStereo;
		};

		virtual void    SetData(const uint16_t inVal) {}

		virtual void    GetSample(sOneSample *pSm) {}
		void            RCFilterL(const double fTime)
		{
			RCFilter(m_RCFL, m_dAccL, fTime);
		}
		void            RCFilterR(const double fTime)
		{
			RCFilter(m_RCFR, m_dAccR, fTime);
		}
		void            RCFilterLF(const double fTime)
		{
			if (m_bFilter)
			{
				RCFilter(m_RCFL, m_dAccL, fTime);
			}
		}
		void            RCFilterRF(const double fTime)
		{
			if (m_bFilter)
			{
				RCFilter(m_RCFR, m_dAccR, fTime);
			}
		}
};
