/*  This file is part of BKBTL.
    BKBTL 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 (at your option) any later version.
    BKBTL 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
BKBTL. If not, see <http://www.gnu.org/licenses/>. */

// SoundGen.h
//

#pragma once

#define DIRECTSOUND_VERSION 0x1000

#include "BKSound_Defines.h"
#include <Mmsystem.h>
#include <mutex>

// способ синхронизации
// 1 - через семафор (нагрузка на процессор меньше)
// 0 - через переменную-счётчик
#define BKSYNCHRO_SEMAPHORE 1

// сколько будет вообще буферов
constexpr auto BKSOUND_BLOCK_COUNT = 8;
/*
* сколько звуковых фреймов в секунду
* 100 - это количество звуковых фреймов в секунду, которое может нормально обрабатываться waveOut;
* если оставить 50 - буфер получается слишком большой, и латентность заметна;
* если делать больше 100 - буфер получается слишком маленький, и очень много ресурсов уходит на заполнение
* и отправку данных в waveOut.
*/
constexpr auto SOUND_FRAMERATE = 100;

// коэффициент увеличения длины буфера для устройств, работающих со звуком
constexpr auto FRAMESIZE_EXP = 4;

class CBkSound
{
	protected:
		SAMPLE_INT      m_dSampleL{ 0.0 }, m_dSampleR{ 0.0 };
		SAMPLE_INT      m_dFeedbackL{ 0.0 }, m_dFeedbackR{ 0.0 };
		uint32_t        m_nWaveCurrentBlock{ 0 };
		uint32_t        m_nBufCurPos{ 0 };
		uint32_t        m_nBufSizeInBytes{ 0 };         // размер звукового буфера в байтах
		uint32_t        m_nBufSizeInSamples{ 0 };       // размер звукового буфера в сэмплах, общий для всех каналов
		int             m_nSoundSampleRate{ 0 };
		SAMPLE_IO      *m_mBufferIO{ nullptr };         // указатель на текущий заполняемый буфер воспроизведения
		WAVEHDR        *m_pWaveBlocks{ nullptr };
		HWAVEOUT        m_hWaveOut{ nullptr };
		WAVEFORMATEX    m_wfx{};
		bool            m_bSoundGenInitialized{ false };

#if (BKSYNCHRO_SEMAPHORE)
		const HANDLE    m_hSem
		{
			CreateSemaphore(nullptr, BKSOUND_BLOCK_COUNT, BKSOUND_BLOCK_COUNT, nullptr)
		};
#else
		static std::mutex       m_mutCS;
		static volatile int     m_nWaveFreeBlockCount;
#endif
		// захват звука
		std::mutex      m_mutCapture;
		CFile           m_waveFile;
		size_t          m_nWaveLength{ 0 };
		bool            m_bCaptureProcessed{ false };
		bool            m_bCaptureFlag{ false };

	public:
		CBkSound();
		virtual ~CBkSound();
		int             ReInit(const int nSSR);
		void            SoundGen_SetVolume(const uint16_t volume) const;
		uint16_t        SoundGen_GetVolume() const;
		void            SoundGen_ResetSample(const SAMPLE_INT L, const SAMPLE_INT R);
		void            SoundGen_SetSample(const SAMPLE_INT &L, const SAMPLE_INT &R);
		void            SoundGen_MixSample(const sOneSample *pSm);
		void            SoundGen_FeedDAC_Mixer(sOneSample *pSm);
		void            SetCaptureStatus(const bool bCapture, const std::wstring &strUniq);
		bool            IsCapture() const
		{
			return m_bCaptureProcessed;
		}
		int             getBufSizeAZ() const
		{
			return m_nBufSizeInBytes;
		}
		void            SoundGen_FeedDAC_MixerAZ(SAMPLE_IO *pBuf);

	protected:
		void            SoundGen_Initialize(const uint16_t volume);
		void            SoundGen_Finalize();

		void            Init(const uint16_t volume, const int nSSR);
		void            UnInit();

		void            PrepareCapture(const std::wstring &strUniq);
		void            CancelCapture();
		void            WriteToCapture(LPSTR ptr);
		static void CALLBACK WaveCallback(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2);
};
