
#pragma once

#include "Covox.h"


#define EMU_GLOBAL_VOLUME 49152.0

class CEMU2149 : public CCovox
{
#pragma pack(push)
#pragma pack(1) // envelope period (envT, R13-R14) has invalid word alignment
		struct AYREGS
		{
			WORD fA, fB, fC; //0,1; 2,3; 4,5;
			BYTE noise, mix; //6; 7;
			BYTE vA, vB, vC; //8; 9; 10;
			WORD envT;       //11,12;
			BYTE env;        //13;
			BYTE portA, portB; //14; 15;
		};
#pragma pack(pop)

		static const int pantbl[6];
		static const int voltbl[2][32];
		int m_nClock, m_nRate, m_nBaseIncrement;
		BOOL m_bHQ;
		BYTE m_nSynthReg;

		union
		{
			struct AYREGS r;
			BYTE reg[16]; //содержимое регистров
		};
		double vols[6][32];

		int count[3];
		int volume[3]; //громкость звучания канала
		int freq[3]; //частота ноты канала
		DWORD env[3]; //флаг, что включена огибающая на канале
		DWORD tone_toggle[3];
		DWORD tmask[3]; //флаг звучания ноты
		DWORD nmask[3]; //флаг звучания шума

		int m_nEnvPtr;
		int m_nDEnv;
		BOOL m_bEnvLValue;
		BOOL m_bEnvAttack;
		BOOL m_bEnvHold;
		BOOL m_bEnvAlt;
		int m_nEnvFreq;
		int m_nEnvCount;

		DWORD m_nNoiseSeed;
		int m_nNoiseCount;
		int m_nNoiseFreq;

		int m_nBaseCount;

		/* m_nRate converter*/
		int m_nRealStep;
		int m_nPSGTime;
		int m_nPSGStep;

		/* I/O Ctrl*/
		DWORD m_nAddr;

		double m_fMixL, m_fMixR;
		void calc();
		void set_volumes(double global_vol, const int *voltab, const int *stereo);
		virtual void NextTick();

	public:
		CEMU2149();
		virtual ~CEMU2149();
		virtual void GetSample(double &sampleL, double &sampleR);

		void    PSG_reset();
		void    PSG_init(int c, int r) ;
		void    PSG_set_quality(BOOL q) ;
		void    PSG_setVolumeMode(int type) ;
		void    PSG_writeReg(int reg, BYTE val) ;
		void    PSG_writeIO(DWORD nAddr, BYTE val) ;
		BYTE    PSG_readReg(int reg) ;
		BYTE    PSG_readIO() ;
		void    PSG_calc(SAMPLE_TYPE &L, SAMPLE_TYPE &R) ;

		// Writing register address
		void synth_write_address(WORD word)
		{
			m_nSynthReg = (~word & 0xF);
		}

		// Writing data
		void synth_write_data(BYTE byte)
		{
			PSG_writeReg(m_nSynthReg, ~byte);
		}
};

