#ifndef _YM2612_H_
#define _YM2612_H_

// Change it if you need to do long update
//#define	MAX_UPDATE_LENGHT   4000
#define	MAX_UPDATE_LENGHT   0x100
//#define	MAX_UPDATE_LENGHT   1	// for in_vgm

// Gens always uses 16 bits sound (in 32 bits buffer) and do the convertion later if needed.
#define OUTPUT_BITS         15
// OUTPUT_BITS 15 is MAME's volume level
#define DAC_SHIFT			(OUTPUT_BITS - 9)
// DAC_SHIFT makes sure that FM and DAC volume has the same volume

// VC++ inline
#ifndef INLINE
#define INLINE              __inline
#endif

typedef struct slot__ {
	int *DT;	// paramètre detune
	int MUL;	// paramètre "multiple de fréquence"
	int TL;		// Total Level = volume lorsque l'enveloppe est au plus haut
	int TLL;	// Total Level ajusted
	int SLL;	// Sustin Level (ajusted) = volume où l'enveloppe termine sa première phase de régression
	int KSR_S;	// Key Scale Rate Shift = facteur de prise en compte du KSL dans la variations de l'enveloppe
	int KSR;	// Key Scale Rate = cette valeur est calculée par rapport à la fréquence actuelle, elle va influer
				// sur les différents paramètres de l'enveloppe comme l'attaque, le decay ...  comme dans la réalité !
	int SEG;	// Type enveloppe SSG
	int *AR;	// Attack Rate (table pointeur) = Taux d'attaque (AR[KSR])
	int *DR;	// Decay Rate (table pointeur) = Taux pour la régression (DR[KSR])
	int *SR;	// Sustin Rate (table pointeur) = Taux pour le maintien (SR[KSR])
	int *RR;	// Release Rate (table pointeur) = Taux pour le relâchement (RR[KSR])
	int Fcnt;	// Frequency Count = compteur-fréquence pour déterminer l'amplitude actuelle (SIN[Finc >> 16])
	int Finc;	// frequency step = pas d'incrémentation du compteur-fréquence
				// plus le pas est grand, plus la fréquence est aïgu (ou haute)
	int Ecurp;	// Envelope current phase = cette variable permet de savoir dans quelle phase
				// de l'enveloppe on se trouve, par exemple phase d'attaque ou phase de maintenue ...
				// en fonction de la valeur de cette variable, on va appeler une fonction permettant
				// de mettre à jour l'enveloppe courante.
	int Ecnt;	// Envelope counter = le compteur-enveloppe permet de savoir où l'on se trouve dans l'enveloppe
	int Einc;	// Envelope step courant
	int Ecmp;	// Envelope counter limite pour la prochaine phase
	int EincA;	// Envelope step for Attack = pas d'incrémentation du compteur durant la phase d'attaque
				// cette valeur est égal à AR[KSR]
	int EincD;	// Envelope step for Decay = pas d'incrémentation du compteur durant la phase de regression
				// cette valeur est égal à DR[KSR]
	int EincS;	// Envelope step for Sustain = pas d'incrémentation du compteur durant la phase de maintenue
				// cette valeur est égal à SR[KSR]
	int EincR;	// Envelope step for Release = pas d'incrémentation du compteur durant la phase de relâchement
				// cette valeur est égal à RR[KSR]
	int *OUTp;	// pointeur of SLOT output = pointeur permettant de connecter la sortie de ce slot à l'entrée
				// d'un autre ou carrement à la sortie de la voie
	int INd;	// input data of the slot = données en entrée du slot
	int ChgEnM;	// Change envelop mask.
	int AMS;	// AMS depth level of this SLOT = degré de modulation de l'amplitude par le LFO
	int AMSon;	// AMS enable flag = drapeau d'activation de l'AMS
} slot_;

typedef struct channel__ {
	int S0_OUT[4];			// anciennes sorties slot 0 (pour le feed back)
	int Old_OUTd;			// ancienne sortie de la voie (son brut)
	int OUTd;				// sortie de la voie (son brut)
	int LEFT;				// LEFT enable flag
	int RIGHT;				// RIGHT enable flag
	int ALGO;				// Algorythm = détermine les connections entre les opérateurs
	int FB;					// shift count of self feed back = degré de "Feed-Back" du SLOT 1 (il est son unique entrée)
	int FMS;				// Fréquency Modulation Sensitivity of channel = degré de modulation de la fréquence sur la voie par le LFO
	int AMS;				// Amplitude Modulation Sensitivity of channel = degré de modulation de l'amplitude sur la voie par le LFO
	int FNUM[4];			// hauteur fréquence de la voie (+ 3 pour le mode spécial)
	int FOCT[4];			// octave de la voie (+ 3 pour le mode spécial)
	int KC[4];				// Key Code = valeur fonction de la fréquence (voir KSR pour les slots, KSR = KC >> KSR_S)
	struct slot__ SLOT[4];	// four slot.operators = les 4 slots de la voie
	int FFlag;				// Frequency step recalculation flag
  int Mute;         // Maxim: channel mute flag
} channel_;

typedef struct ym2612__ {
	int Clock;			// Horloge YM2612
	int Rate;			// Sample Rate (11025/22050/44100)
	int TimerBase;		// TimerBase calculation
	int Status;			// YM2612 Status (timer overflow)
	int OPNAadr;		// addresse pour l'écriture dans l'OPN A (propre à l'émulateur)
	int OPNBadr;		// addresse pour l'écriture dans l'OPN B (propre à l'émulateur)
	int LFOcnt;			// LFO counter = compteur-fréquence pour le LFO
	int LFOinc;			// LFO step counter = pas d'incrémentation du compteur-fréquence du LFO
						// plus le pas est grand, plus la fréquence est grande
	int TimerA;			// timerA limit = valeur jusqu'à laquelle le timer A doit compter
	int TimerAL;
	int TimerAcnt;		// timerA counter = valeur courante du Timer A
	int TimerB;			// timerB limit = valeur jusqu'à laquelle le timer B doit compter
	int TimerBL;
	int TimerBcnt;		// timerB counter = valeur courante du Timer B
	int Mode;			// Mode actuel des voie 3 et 6 (normal / spécial)
	int DAC;			// DAC enabled flag
	int DACdata;		// DAC data
	long dac_highpass;
	double Frequence;	// Fréquence de base, se calcul par rapport à l'horlage et au sample rate
	unsigned int Inter_Cnt;			// Interpolation Counter
	unsigned int Inter_Step;		// Interpolation Step
	struct channel__ CHANNEL[6];	// Les 6 voies du YM2612
	int REG[2][0x100];	// Sauvegardes des valeurs de tout les registres, c'est facultatif
						// cela nous rend le débuggage plus facile

	int LFO_ENV_UP[MAX_UPDATE_LENGHT];      // Temporary calculated LFO AMS (adjusted for 11.8 dB) *
	int LFO_FREQ_UP[MAX_UPDATE_LENGHT];      // Temporary calculated LFO FMS *

	int in0, in1, in2, in3;            // current phase calculation *
	int en0, en1, en2, en3;            // current enveloppe calculation *

	int DAC_Mute;
} ym2612_;

/* Gens */

//extern int YM2612_Enable;
//extern int YM2612_Improv;
//extern int DAC_Enable;
//extern int *YM_Buf[2];
//extern int YM_Len;

/* end */

ym2612_ *YM2612_Init(int clock, int rate, int interpolation);
int YM2612_End(ym2612_ *YM2612);
int YM2612_Reset(ym2612_ *YM2612);
int YM2612_Read(ym2612_ *YM2612);
int YM2612_Write(ym2612_ *YM2612, unsigned char adr, unsigned char data);
void YM2612_ClearBuffer(int **buffer, int length);
void YM2612_Update(ym2612_ *YM2612, int **buf, int length);
/*int YM2612_Save(ym2612_ *YM2612, unsigned char SAVE[0x200]);
int YM2612_Restore(ym2612_ *YM2612, unsigned char SAVE[0x200]);*/

/* Maxim: muting (bits 0-5 for channels 0-5) */
int YM2612_GetMute(ym2612_ *YM2612);
void YM2612_SetMute(ym2612_ *YM2612, int val);
void YM2612_SetOptions(int Flags);

/* Gens */

void YM2612_DacAndTimers_Update(ym2612_ *YM2612, int **buffer, int length);
void YM2612_Special_Update(ym2612_ *YM2612);

/* end */

// used for foward...
void Update_Chan_Algo0(ym2612_ *YM2612, channel_ *CH, int **buf, int lenght);
void Update_Chan_Algo1(ym2612_ *YM2612, channel_ *CH, int **buf, int lenght);
void Update_Chan_Algo2(ym2612_ *YM2612, channel_ *CH, int **buf, int lenght);
void Update_Chan_Algo3(ym2612_ *YM2612, channel_ *CH, int **buf, int lenght);
void Update_Chan_Algo4(ym2612_ *YM2612, channel_ *CH, int **buf, int lenght);
void Update_Chan_Algo5(ym2612_ *YM2612, channel_ *CH, int **buf, int lenght);
void Update_Chan_Algo6(ym2612_ *YM2612, channel_ *CH, int **buf, int lenght);
void Update_Chan_Algo7(ym2612_ *YM2612, channel_ *CH, int **buf, int lenght);

void Update_Chan_Algo0_LFO(ym2612_ *YM2612, channel_ *CH, int **buf, int lenght);
void Update_Chan_Algo1_LFO(ym2612_ *YM2612, channel_ *CH, int **buf, int lenght);
void Update_Chan_Algo2_LFO(ym2612_ *YM2612, channel_ *CH, int **buf, int lenght);
void Update_Chan_Algo3_LFO(ym2612_ *YM2612, channel_ *CH, int **buf, int lenght);
void Update_Chan_Algo4_LFO(ym2612_ *YM2612, channel_ *CH, int **buf, int lenght);
void Update_Chan_Algo5_LFO(ym2612_ *YM2612, channel_ *CH, int **buf, int lenght);
void Update_Chan_Algo6_LFO(ym2612_ *YM2612, channel_ *CH, int **buf, int lenght);
void Update_Chan_Algo7_LFO(ym2612_ *YM2612, channel_ *CH, int **buf, int lenght);

void Update_Chan_Algo0_Int(ym2612_ *YM2612, channel_ *CH, int **buf, int lenght);
void Update_Chan_Algo1_Int(ym2612_ *YM2612, channel_ *CH, int **buf, int lenght);
void Update_Chan_Algo2_Int(ym2612_ *YM2612, channel_ *CH, int **buf, int lenght);
void Update_Chan_Algo3_Int(ym2612_ *YM2612, channel_ *CH, int **buf, int lenght);
void Update_Chan_Algo4_Int(ym2612_ *YM2612, channel_ *CH, int **buf, int lenght);
void Update_Chan_Algo5_Int(ym2612_ *YM2612, channel_ *CH, int **buf, int lenght);
void Update_Chan_Algo6_Int(ym2612_ *YM2612, channel_ *CH, int **buf, int lenght);
void Update_Chan_Algo7_Int(ym2612_ *YM2612, channel_ *CH, int **buf, int lenght);

void Update_Chan_Algo0_LFO_Int(ym2612_ *YM2612, channel_ *CH, int **buf, int lenght);
void Update_Chan_Algo1_LFO_Int(ym2612_ *YM2612, channel_ *CH, int **buf, int lenght);
void Update_Chan_Algo2_LFO_Int(ym2612_ *YM2612, channel_ *CH, int **buf, int lenght);
void Update_Chan_Algo3_LFO_Int(ym2612_ *YM2612, channel_ *CH, int **buf, int lenght);
void Update_Chan_Algo4_LFO_Int(ym2612_ *YM2612, channel_ *CH, int **buf, int lenght);
void Update_Chan_Algo5_LFO_Int(ym2612_ *YM2612, channel_ *CH, int **buf, int lenght);
void Update_Chan_Algo6_LFO_Int(ym2612_ *YM2612, channel_ *CH, int **buf, int lenght);
void Update_Chan_Algo7_LFO_Int(ym2612_ *YM2612, channel_ *CH, int **buf, int lenght);

// used for foward...
void Env_Attack_Next(slot_ *SL);
void Env_Decay_Next(slot_ *SL);
void Env_Substain_Next(slot_ *SL);
void Env_Release_Next(slot_ *SL);
void Env_NULL_Next(slot_ *SL);

#endif
