#include "commun.h"
//#include "gba.h"
#include "screenmode.h"

ADGlobals ad;

#ifdef SON

extern void initInterrupt(void);
extern void InterruptHandler(void);

//Contrôle le comportement de la musique
//0: en boucle
//1: musique courante sauvée, nouvelle joué une fois, puis musique de base restaurée après
//2: nouvelle musique jouée une fois, arrêt du son après
//Bits supplémentaires:
//0x10: ne pas jouer en plus rapide
int type_transition_musique;

int qualite_son = 0, son_special = 0, last_son_special = 0;
int cur_mixbuf = 0;
signed char SON_ZERO[408];
signed char EWRAM_DATA mixbuf[2][MIXBUF_SIZE];
const unsigned char *audio_dat;
const unsigned char *end = 0;

u16 *videoBuffer = (u16 *) 0x6000000;
u16 *paletteMem = (u16 *) 0x5000000;

signed char *Bruitage[4], *fin_bruitage[4];

/*void JoueSon(int num_voie, const char *nom)      {
    FICHIER *f;

        Bruitage[num_voie] = (signed char *)SymFind(nom,&f);
        fin_bruitage[num_voie] = Bruitage[num_voie] + f->taille;

        if (!Bruitage[num_voie])
           Bruitage[num_voie]=SON_ZERO;
//    else
//        Bruitage[num_voie]+=2000;
}

void JoueMusique(const char *nom, int qualite, int transition)      {
    FICHIER *fichier;
        audio_dat = SymFind(nom,&fichier);
        end = fichier->taille + audio_dat;
        qualite_son=qualite&0xf;
        last_son_special=son_special;
        son_special=qualite>>4;
        type_transition_musique=transition;
        start_ad(audio_dat);
}*/
void JoueSon(int num_voie, int numero)
{
	FICHIER *f;
	char nom[10];

	formatString(nom, "%x.sfx", numero);

	Bruitage[num_voie] = (signed char *) SymFind(nom, &f);
	fin_bruitage[num_voie] = Bruitage[num_voie] + f->taille;

	if (!Bruitage[num_voie])
		Bruitage[num_voie] = SON_ZERO;

	//    else
	//        Bruitage[num_voie]+=2000;
}

void JoueMusique(const char *nom, int qualite, int transition)
{
	FICHIER *fichier;
	audio_dat = SymFind(nom, &fichier);
	end = fichier->taille + audio_dat;
	qualite_son = qualite & 0xf;
	last_son_special = son_special;
	son_special = qualite >> 4;
	type_transition_musique = transition;
	start_ad(audio_dat);
}

static void dsound_switch_buffers(const signed char *src)
{
	REG_DMA1CNT = 0;

	/* no-op to let DMA registers catch up */
	asm volatile(".THUMB\neor r0, r0; eor r0, r0\n.ARM\n":: : "r0");

	REG_DMA1SAD = (u32)src;
	REG_DMA1DAD = (u32)0x040000a0;        /* write to FIFO A address */
	// Only one word
	REG_DMA1CNT = 1 | DMA_DST_FIXED | DMA_SRC_INC | DMA_REPEAT | DMA32 | DMA_SPECIAL | DMA_ENABLE;
}

/* dsound_vblank() *********************
   Call this first in your vblank handler.
*/
void dsound_vblank(void)
{
	dsound_switch_buffers(mixbuf[cur_mixbuf]);

	cur_mixbuf = !cur_mixbuf;
}

extern IWRAM_CODE void decode_ad(
						  unsigned short rapide,
						  signed char *dst,
						  const unsigned char *src,
						  const signed char *son2,
						  const signed char *son3,
						  const signed char *son4,
						  const signed char *son5,
						  unsigned int len);

void RestaureMusique()
{
	son_special = last_son_special;
	if (type_transition_musique == 0)
		start_ad(audio_dat);
	else
		ad.data = NULL;
}

void mixer(int offset, int taille)
{
	int i;
	if (gblSonMusiqueVol == 0 && gblSonBruitagesVol == 0)
		return;

	if (ad.data)
	{
		if ((super_vitesse && !(son_special & 1)) || qualite_son == 1)
		{
			if ((ad.data + (taille >> 1)) > end)
			{        //Morceau terminé?
				RestaureMusique();
				if (!ad.data)
					goto pas_de_son;
			}

			decode_ad(1,
				mixbuf[cur_mixbuf] + offset,
				ad.data,
				Bruitage[0],
				Bruitage[1],
				Bruitage[2],
				Bruitage[3],
				taille);
			ad.data += taille >> 1;
		}
		else
		{
			if ((ad.data + (taille >> 2)) > end)
			{        //Morceau terminé?
				RestaureMusique();
				if (!ad.data)
					goto pas_de_son;
			}

			decode_ad(0,
				mixbuf[cur_mixbuf] + offset,
				ad.data,
				Bruitage[0],
				Bruitage[1],
				Bruitage[2],
				Bruitage[3],
				taille / 2);
			ad.data += taille >> 2;
		}
	}
	else
	{
pas_de_son:
		decode_ad(0,
			mixbuf[cur_mixbuf] + offset,
			SON_ZERO,
			Bruitage[0],
			Bruitage[1],
			Bruitage[2],
			Bruitage[3],
			taille / 2);
	}

	for (i = 0; i < 4; i++)
	{
		if (Bruitage[i] != SON_ZERO)
			Bruitage[i] += taille;
		if (Bruitage[i] + taille > fin_bruitage[i])
			Bruitage[i] = SON_ZERO;
	}
}

void start_ad(const unsigned char *data)
{
	ad.data = data;
	ad.last_sample = 0;
	ad.last_index = 0;
}

static void set_bias(void)
{

	//        asm volatile(".THUMB\nmov r2, #2; lsl r2, #8; swi 0x19\n.ARM\n" ::: "r0", "r1", "r2", "r3");
	SETSNDRES(1);
}

void init_sound(void)
{
	gbaSetTimerControl(0, 0);

	//turn on sound circuit
	SNDSTAT = SNDSTAT_ENABLE;

	//full volume, enable sound 3 to left and right
	DMGSNDCTRL = DMGSNDCTRL_LVOL(7) |
		DMGSNDCTRL_RVOL(7) |
		DMGSNDCTRL_LSQR1 |
		DMGSNDCTRL_RSQR1 |
		DMGSNDCTRL_LSQR2 |
		DMGSNDCTRL_RSQR2 |
		DMGSNDCTRL_LTRI |
		DMGSNDCTRL_RTRI |
		DMGSNDCTRL_LNOISE |
		DMGSNDCTRL_RNOISE;
	DSOUNDCTRL = 0xbb0d;
	TIMER[0].count = 0x10000 - SAMPLE_TIME;
	TIMER[0].control = TIMER_16MHZ | TIMER_ENABLE;

	TRICTRL = TRICTRL_2X32 | TRICTRL_BANK(0) | TRICTRL_ENABLE;
	TRILENVOL = 0;
	TRIFREQ = 1046 | FREQ_RESET | FREQ_HOLD;
	SQR1SWEEP = SQR1SWEEP_OFF;
	set_bias();
	return;
}

int nBlank = 0;

void directSound()
{
	if (nBlank % 3 == 0)

		//Pour le son
		dsound_vblank();

	if (nBlank % 3 == 0)
		mixer(0, 408);
	else if (nBlank % 3 == 1)
		mixer(408, 404);
	else if (nBlank % 3 == 2)
		mixer(408 + 404, 404);

	nBlank++;
}

#endif
