#include <ioavr.h>
#include "main.h"
#include "songs.h"

char Melodies = 0;
Note __flash* PlayPointer = EmptySong - 1;
Note __flash* LoopPointer = 0;
unsigned short PeriodCounter;
unsigned short Tempo;
char LastPeriod = 0;

__flash Note EmptySong[] = {
	{0, 0}
};

__flash Note Cat [] = {
	{NOTE_Ds, 16},
	{NOTE_Cs, 16},
	
	{NOTE_Fs/2, 8},
	{NOTE_Fs, 8},
	{NOTE_Fs, 8},
	{NOTE_Ds, 16},
	{NOTE_Cs, 16},
	
	{NOTE_Fs/2, 8},
	{NOTE_Fs, 8},
	{NOTE_Fs, 8},
	{NOTE_Ds, 16},
	{NOTE_Cs, 16},
	
	{NOTE_Fs/2, 8},
	{NOTE_Fs, 8},
	{NOTE_Ds/2, 8},
	{NOTE_Fs, 8},
	
	{NOTE_Cs/2, 8},
	{NOTE_F, 8},
	{NOTE_F, 8},
	{NOTE_Ds, 16},
	{NOTE_Cs, 16},
	
	{NOTE_Cs/2, 8},
	{NOTE_F, 8},
	{NOTE_F, 8},
	{NOTE_Ds, 16},
	{NOTE_Cs, 16},
	
	{NOTE_Cs/2, 8},
	{NOTE_F, 8},
	{NOTE_F, 8},
	{NOTE_Ds, 16},
	{NOTE_Cs, 16},
	
	{NOTE_Cs/2, 8},
	{NOTE_F, 8},
	{NOTE_Ds/2, 8},
	{NOTE_F, 8},
	
	{NOTE_Fs/2, 8},
	{NOTE_Fs, 8},
	{NOTE_Fs, 8},
	{0, 0}
};

__flash Note Gamma [] = {
	{NOTE_C, 4},
	{NOTE_D, 4},
	{NOTE_E, 4},
	{NOTE_F, 4},
	{NOTE_G, 4},
	{NOTE_A, 4},
	{NOTE_H, 4},
	{NOTE_C*2, 4},
	{NOTE_H, 4},
	{NOTE_A, 4},
	{NOTE_G, 4},
	{NOTE_F, 4},
	{NOTE_E, 4},
	{NOTE_D, 4},
	{NOTE_C, 4},
	{SILENCE, 4},
	{0, 0}
};

__flash Note SuperMario[] = {
	// 1
	{NOTE_E *2, 16},
	{NOTE_E *2, 16},
	{SILENCE, 16},
	{NOTE_E *2, 16},
	{SILENCE, 16},
	{NOTE_C *2, 16},
	{NOTE_E *2, 16},
	{SILENCE, 16},
	{NOTE_G *2, 8},
	{SILENCE, 8},
	{NOTE_G, 8},
	{SILENCE, 8},
	// 2
	{NOTE_C *2, 16},
	{SILENCE, 16},
	{SILENCE, 16},
	{NOTE_G, 16},
	{SILENCE, 8},
	{NOTE_E, 16},
	{SILENCE, 16},
	{SILENCE, 16},
	{NOTE_A, 16},
	{SILENCE, 16},
	{NOTE_C *2, 16},
	{SILENCE, 16},
	{NOTE_As, 16},
	{NOTE_A, 16},
	{SILENCE, 16},
	// 3
	{NOTE_G, 8},
	{NOTE_E *2, 8},
	{NOTE_G *2, 8},
	{NOTE_A *2, 16},
	{SILENCE, 16},
	{NOTE_F *2, 16},
	{NOTE_A *2, 16},
	{NOTE_A *2, 16},
	{NOTE_E *2, 16},
	{SILENCE, 16},
	{NOTE_C *2, 16},
	{NOTE_D *2, 16},
	{NOTE_H, 16},
	{SILENCE, 8},
	// 4
	{NOTE_C *2, 16},
	{SILENCE, 8},
	{NOTE_G, 16},
	{SILENCE, 8},
	{NOTE_E, 16},
	{SILENCE, 8},
	{NOTE_A, 16},
	{SILENCE, 16},
	{NOTE_C *2, 16},
	{SILENCE, 16},
	{NOTE_As, 16},
	{NOTE_A, 16},
	{SILENCE, 16},
	// 5 
	{NOTE_G, 8},
	{NOTE_E *2, 8},
	{NOTE_G *2, 8},
	{NOTE_A *2, 16},
	{SILENCE, 16},
	{NOTE_F *2, 16},
	{NOTE_A *2, 16},
	{NOTE_A *2, 16},
	{NOTE_E *2, 16},
	{SILENCE, 16},
	{NOTE_C *2, 16},
	{NOTE_D *2, 16},
	{NOTE_H, 16},
	{SILENCE, 8},
	// 6
	{NOTE_G *2, 16}, 
	{NOTE_Fs *2, 16}, 
	{NOTE_F *2, 16},
	{NOTE_Ds *2, 16}, 
	{SILENCE, 16},
	{NOTE_E *2, 16},
	{SILENCE, 16},
	{NOTE_Gs, 16},
	{NOTE_A, 16},
	{NOTE_C *2, 16},
	{SILENCE, 16},
	{NOTE_A, 16},
	{NOTE_C *2, 16},
	{NOTE_D *2, 16},
	// 7
	{NOTE_G *2, 16}, 
	{NOTE_Fs *2, 16}, 
	{NOTE_F *2, 16},
	{NOTE_Ds *2, 16}, 
	{SILENCE, 16},
	{NOTE_E *2, 16},
	{SILENCE, 16},
	{NOTE_C *3, 16},
	{SILENCE, 16},
	{NOTE_C *3, 16},
	{NOTE_C *3, 16},
	{SILENCE, 16},
	{SILENCE, 8},
	// 8
	{NOTE_G *2, 16}, 
	{NOTE_Fs *2, 16}, 
	{NOTE_F *2, 16},
	{NOTE_Ds *2, 16}, 
	{SILENCE, 16},
	{NOTE_E *2, 16},
	{SILENCE, 16},
	{NOTE_Gs, 16},
	{NOTE_A, 16},
	{NOTE_C *2, 16},
	{SILENCE, 16},
	{NOTE_A, 16},
	{NOTE_C *2, 16},
	{NOTE_D *2, 16},
	// 9
	{SILENCE, 8},
	{NOTE_Ds, 16},
	{SILENCE, 16},
	{SILENCE, 16},
	{NOTE_D, 16},
	{SILENCE, 8},
	{NOTE_C, 16},
	{SILENCE, 16},
	{SILENCE, 8},
	{SILENCE, 4},
	// 10
	{NOTE_G *2, 16}, 
	{NOTE_Fs *2, 16}, 
	{NOTE_F *2, 16},
	{NOTE_Ds *2, 16}, 
	{SILENCE, 16},
	{NOTE_E *2, 16},
	{SILENCE, 16},
	{NOTE_Gs, 16},
	{NOTE_A, 16},
	{NOTE_C *2, 16},
	{SILENCE, 16},
	{NOTE_A, 16},
	{NOTE_C *2, 16},
	{NOTE_D *2, 16},
	// 11
	{NOTE_G *2, 16}, 
	{NOTE_Fs *2, 16}, 
	{NOTE_F *2, 16},
	{NOTE_Ds *2, 16}, 
	{SILENCE, 16},
	{NOTE_E *2, 16},
	{SILENCE, 16},
	{NOTE_C *3, 16},
	{SILENCE, 16},
	{NOTE_C *3, 16},
	{NOTE_C *3, 16},
	{SILENCE, 16},
	{SILENCE, 8},
	// 12
	{NOTE_G *2, 16}, 
	{NOTE_Fs *2, 16}, 
	{NOTE_F *2, 16},
	{NOTE_Ds *2, 16}, 
	{SILENCE, 16},
	{NOTE_E *2, 16},
	{SILENCE, 16},
	{NOTE_Gs, 16},
	{NOTE_A, 16},
	{NOTE_C *2, 16},
	{SILENCE, 16},
	{NOTE_A, 16},
	{NOTE_C *2, 16},
	{NOTE_D *2, 16},
	// 13
	{SILENCE, 8},
	{NOTE_Ds *2, 16},
	{SILENCE, 8},
	{NOTE_Ds *2, 16},
	{SILENCE, 16},
	{SILENCE, 16},
	{NOTE_C *2, 16},
	{SILENCE, 16},
	{SILENCE, 8},
	{SILENCE, 4},
	// 14
	{NOTE_C *2, 16},
	{NOTE_C *2, 16},
	{SILENCE, 16},
	{NOTE_C *2, 16},
	{SILENCE, 16},
	{NOTE_C *2, 16},
	{NOTE_D *2, 16},
	{SILENCE, 16},
	{NOTE_E *2, 16},
	{NOTE_C *2, 16},
	{SILENCE, 16},
	{NOTE_A, 16},
	{NOTE_G, 16},
	{SILENCE, 16},
	{SILENCE, 8},
	// 15
	{NOTE_C *2, 16},
	{NOTE_C *2, 16},
	{SILENCE, 16},
	{NOTE_C *2, 16},
	{SILENCE, 16},
	{NOTE_C *2, 16},
	{NOTE_D *2, 16},
	{SILENCE, 16},
	{NOTE_E *2, 16},
	{SILENCE, 16},
	{SILENCE, 16},
	{SILENCE, 8},
	{SILENCE, 4},
	// 16
	{NOTE_C *2, 16},
	{NOTE_C *2, 16},
	{SILENCE, 16},
	{NOTE_C *2, 16},
	{SILENCE, 16},
	{NOTE_C *2, 16},
	{NOTE_D *2, 16},
	{SILENCE, 16},
	{NOTE_E *2, 16},
	{NOTE_C *2, 16},
	{SILENCE, 16},
	{NOTE_A, 16},
	{NOTE_G, 16},
	{SILENCE, 16},
	{SILENCE, 8},
	// end
	{0, 0}
};

void EnableMelodies(void)
{
	Melodies |= 0x01;
}

void DisableMelodies(void)
{
	Melodies = 0;
	SPEAKER_DISABLE;
	TIMSK &= ~(1 << OCIE0);
}

void PauseMelody(void)
{
	if(Melodies & 0x01)
	{
		TIMSK &= ~(1<<OCIE0);
	}
}

void ResumeMelody(void)
{
	if(Melodies & 0x01)
	{
		TCCR0 = 0;
		TIMSK |= 1<<OCIE0;
		TCNT0 = 0;
		OCR0 = LastPeriod;
		TCCR0 = (1<<CS02) | (1<<CS01) | (1<<WGM01);
	}
}

//обработчик прерывания по переполнению таймера 1
#pragma vector = TIMER0_COMP_vect
__interrupt void Timer0_Comp_handler(void)
{
	if(PeriodCounter == 0)
	{
		PlayPointer++;
		SPEAKER_DISABLE;
		if(PlayPointer->length == 0)
		{
			if(LoopPointer)
			{
				PlayPointer = LoopPointer;
			} else
			{
				PlayPointer = EmptySong - 1;
				PauseMelody();
				return;
			}
		}
		PeriodCounter = PlayPointer->period ? 
			(120 * (unsigned long)PlayPointer->period * 4 / ((unsigned short)PlayPointer->length * Tempo)) : 
			(CPU_SPEED * 600000 * 4 / 256 / ((unsigned short)PlayPointer->length * Tempo));
		LastPeriod = PlayPointer->period ? (CPU_SPEED * 500000 / 256 / PlayPointer->period) : 100;
		OCR0 = LastPeriod;
	}
	PeriodCounter--;
	if(PlayPointer->period)
		SPEAKER_TOGGLE;
}

void Sing(Note __flash* song, unsigned short tempo, char loop)
{
	if(!Melodies)
		return;
	PauseMelody();	
	PlayPointer = song - 1;
	LoopPointer = loop ? song : 0;
	PeriodCounter = 0;
	Tempo = tempo;
	LastPeriod = 2;
	ResumeMelody();
}
