#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#include <avr/eeprom.h>

#define VOL0

#define END  (0xff)
#define WAIT  (0xfe)

#include "len.h"
#include "note.h"
#include "tempo.h"

#define ONLY1 1

#define LSPEED 1

#define PWMLIMIT 192
//#define PWMLIMIT 150

#ifdef LSPEED
  //#define BASE (4096)
  #define BASE (6144)
#else
  #define BASE (4096*2)
#endif

// 8点 WaveTable
// 2/3 倍
signed char table[4][8] = {
	{0,67,80,67,0,-67,-80,-67},
	{0,	33,	47,	33,	0,	-33,	-47,	-33},
	{0, 16,	23,	16,	0,	-16,	-23,	-16},
	{0,	8,	11,	8,	0,	-8,	-11,	-8}
};

// 音階番号->周波数のテーブル
const PROGMEM unsigned int tonetable[] = {
	0, // 休符
	131,139,147,156,165,175,185,196,208,220,233,247, // O3
	262,277,294,311,330,349,370,392,415,440,466,494, // O4          
	523,554,587,622,659,698,740,784,831,880,932,988, // O5
	1047,1109,1175,1245,1319,1397,1480,1568,1661,1760,1865,1976, // O6
	2093,2217,2349,2489,2637,2794,2960,3136,3322,3520,3729,3951  // O7
};

// 音長名
signed char lennum[] = {2, 4, 8, 16};

volatile char vol1= 0;
volatile char vol2= 0;
volatile char vol3= 0;
volatile char vol4= 0;

#ifdef VOL0
#define basevol1 1
#define basevol2 2
#define basevol3 2
#define basevol4 2
#endif
#ifdef VOL1
#define basevol1 0
#define basevol2 2
#define basevol3 3
#define basevol4 3
#endif
#ifdef VOL2
#define basevol1 1
#define basevol2 2
#define basevol3 2
#define basevol4 2
#endif

// 出力周波数
volatile unsigned int freq1=0;
volatile unsigned int freq2=0;
volatile unsigned int freq3=0;
volatile unsigned int freq4=0;
volatile unsigned char tics=0;

volatile unsigned char skipflag=0;
#define SKIPLIMIT 100

// タイマ1 オーバーフロー割り込み
#pragma GCC optimize ("O1")
ISR(SIG_OVERFLOW1) {

	//ISR(SIG_OUTPUT_COMPARE1A) {
	volatile static unsigned char pt1 = 0;
	volatile static unsigned char pt2 = 0;
	volatile static unsigned char pt3 = 0;
	volatile static unsigned char pt4 = 0;
	volatile static signed int cnt1 = 0;
	volatile static signed int cnt2 = 0;
	volatile static signed int cnt3 = 0;
	volatile static signed int cnt4 = 0;
	register int value;
	
	tics++;
	if (skipflag) tics+=9;
	
	cnt1 -= freq1;
	if (cnt1<0) {	cnt1 = cnt1 + BASE;	pt1++;	pt1 &= 0b111;	}

	cnt2 -= freq2;
	if (cnt2<0) {	cnt2 = cnt2 + BASE;	pt2++;	pt2 &= 0b111;	}

	cnt3 -= freq3;
	if (cnt3<0) {	cnt3 = cnt3 + BASE;	pt3++;	pt3 &= 0b111;	}

	cnt4 -= freq4;
	if (cnt4<0) {	cnt4 = cnt4 + BASE;	pt4++;	pt4 &= 0b111;	}
	
	value=0;

	if (freq1) { value += (table[(int)vol1][(int)pt1]); }
	if (freq2) { value += (table[(int)vol2][(int)pt2]); }
	if (freq3) { value += (table[(int)vol3][(int)pt3]); }
	if (freq4) { value += (table[(int)vol4][(int)pt4]); }

	//value = value>>1;
	//OCR1A = value+128;
	
	/*
	正負が逆なので修正
	if (value>=0) {
		if (!(PORTB & _BV(PB2))) DDRB &= ~_BV(PB2);
		PORTB |= _BV(PB2);
		OCR1A = value;
	} else {
		if (PORTB & _BV(PB2)) DDRB &= ~_BV(PB2);
		PORTB &= ~_BV(PB2);
		OCR1A = 255+value;
	}
	*/

	//DDRB のかわりに PORTB を制御: うまくいかない。ノイズが載る
	//volatile static char portb2;
	//PORTB = (PORTB & ~_BV(PB2)) | portb2;
	DDRB |= _BV(PB2);

	value +=0;
		
	if (value>0) {
		if ((PORTB & _BV(PB2))) DDRB &= ~_BV(PB2);
		PORTB &= ~_BV(PB2);
		//portb2 = 0;
		//OCR1A = 256-value;
		OCR1A = PWMLIMIT-value;
	} else {
		if (!(PORTB & _BV(PB2))) DDRB &= ~_BV(PB2);
		PORTB |= _BV(PB2);
		//portb2 = _BV(PB2);
		OCR1A = -value;
	}

	return;
}

/*
ISR(SIG_OUTPUT_COMPARE1A) {
	if (value>=0) {
		PORTB &= ~_BV(PB2);
	} else {
		PORTB |= _BV(PB2);
	}
	return;
}
*/

#pragma GCC optimize ("Os")

// sound main
int main(void) {

	// 楽譜から END を検索
	int i;
	unsigned int start[4*6];
	
#ifndef ONLY1
	unsigned char kyokusuu=1;
	unsigned char kyokuban=0; // 4の倍数
#endif

	start[0]=0;

#ifndef ONLY1
	for (i=0; i<sizeof(gakufu)/sizeof(*gakufu); i++) {
		if (pgm_read_byte(gakufu+i) == END) {
			start[kyokusuu] = i+1;
			kyokusuu++;
		}
	}
	kyokusuu = kyokusuu>>2;
	// 演奏開始する曲の決定
	kyokuban = eeprom_read_byte(0);
	if (kyokuban>=kyokusuu*4) kyokuban=0;
	eeprom_write_byte(0, kyokuban+4);
#else
	unsigned int part=1;
	for (i=0; i<sizeof(gakufu)/sizeof(*gakufu); i++) {
		if (pgm_read_byte(gakufu+i) == END) {
			start[part] = i+1;
			part++;
		}
	}
#endif
	
	cli(); // 全割り込み禁止
	// タイマ初期化(タイマ1 PWM)
	GTCCR |= _BV(TSM);     // タイマ設定開始
	PLLCSR |= _BV(PCKE);   // タイマ1 のベースクロックに PLL 64MHz 使用
	TCCR1  |= _BV(PWM1A);  // タイマ1B の PWM 動作を指示
	TCCR1  |= _BV(COM1A0); // OC1A(PB0,pinx) に **反転** 出力を指示, デューティー比は OCR1A で設定
#ifdef LSPEED
	TCCR1  |= _BV(CS12);   // タイマ1 8分周
#else
	TCCR1  |= _BV(CS11) | _BV(CS10);   // タイマ1 4分周
#endif
	TIMSK  |= _BV(TOIE1);  // タイマ1オーバーフロー割り込み許可
	//TIMSK  |= _BV(OCIE1A);  // タイマ1比較A割り込み許可	

	//OCR1C = 255;           // オーバーフロー割り込みに OCR1C が使われる(PWM時はTCCR1:CTC1によらず)
	OCR1C = PWMLIMIT;           // オーバーフロー割り込みに OCR1C が使われる(PWM時はTCCR1:CTC1によらず)

	GTCCR &= ~_BV(TSM);    // タイマ設定終了

	// GPIO(pin0-2 または pin0-4 に出力を接続)
	DDRB  |= (_BV(PB0) | _BV(PB2)); // PB0(PWM出力 OC1A,pinx)を出力ピンに指示
	PORTB &= ~_BV(PB2);

	//DDRB  |= _BV(PB4);
	//PORTB &= ~_BV(PB4);

	// PB3 プルアップ
	DDRB  &= ~_BV(PB3);
	PORTB |=  _BV(PB3);
	
	sei(); // 全割り込み許可(割り込み開始位置に注意)
	
#define K (50)
	// #define N 140
#ifdef LSPEED
  //#define C (62500/2)
	#define C 41666
#else
	  #define C (62500/1)
#endif
	
	//#define B (C*60/N/K*4)

	// 音長カウンタ
	static int lencnt[4];// = { 0,0,0,0 };
	// 音符名
	static int onpu[4];//  = { 0,0,0,0 };
	// 楽譜ポインタ
	static unsigned int gp[4];// = { 0,0,0,0 };
	// 停止中フラグ
	static char stopflag[4];// = { 0,0,0,0 };

	int B;
	
 restart:

	// 初期化
	for (i=0;i<4;i++) {
		// 音長カウンタ
		lencnt[i]=0;
		// 音符名
		onpu[i]=0;
		// 楽譜ポインタ
		gp[i]=0;
		// 停止中フラグ
		stopflag[i]=0;
	}
	
	// テンポ基準カウント
#ifndef ONLY1
	B = (C/K*4/tempo[kyokuban/4]*60);
#else
	B = (C/K*4/tempo[0]*60);
#endif
	
	while(1) {
		unsigned char tone; // 音階番号
		unsigned char len;  // 音長
							
		// エンベロープ
		// Ch.1
#ifdef VOL0
#if basevol1 == 0
		if      (lencnt[0]<(B-B/8*7)) vol1=basevol1+3;
		else if (lencnt[0]<(B-B/8*6)) vol1=basevol1+2;
		else if (lencnt[0]<(B-B/8*4)) vol1=basevol1+1;
#else
		if (lencnt[0]<(B-B/8*4))      vol1=basevol1+2;
		else if (lencnt[0]<(B-B/8*6)) vol1=basevol1+1;
#endif
		
	// Ch.2
#if basevol2 == 3
		if (lencnt[1]<B-B/8*7)      freq2=0;
#else		
		if (lencnt[1]<B-B/8*7)      vol2=basevol2+1;
#endif
		

		// Ch.3
#if basevol3 == 3
		if (lencnt[2]<B-B/8*7)    freq3=0;
#else
		if (lencnt[2]<B-B/8*7)    vol3=basevol3+1;
#endif

		// Ch.4
#if basevol4 == 3
		if (lencnt[3]<B-B/8*7)      freq4=0;
#else
		if (lencnt[3]<B-B/8*7)      vol4=basevol4+1;
#endif
		
		
#endif
		
		// 割り込み K 回に1回メインループを実行
		if (tics>K) {
			tics=0;

			// SKIP
			{
				static unsigned char skipcnt=0;
				if (!(PINB & _BV(PB3))) { if (skipcnt<0xff) skipcnt++; } else { skipcnt=0; skipflag=0; }
				if (skipcnt>SKIPLIMIT) { skipflag=1; }
			}
			
			// LED
			{
				static unsigned int ledcnt;
				if (ledcnt++ >= B/4) {
					ledcnt=0;
					// if (DDRB & _BV(PB1)) { DDRB &= ~_BV(PB1); } else { DDRB |= _BV(PB1); }

				}
				if (ledcnt<B/16)  { DDRB |= _BV(PB1); } else { DDRB &= ~_BV(PB1); } 
			}

			
			// 再開
			if (stopflag[0] && stopflag[1] && stopflag[2] && stopflag[3]) {
#ifndef ONLY1
				kyokuban+=4;
				if (kyokuban>=kyokusuu*4) kyokuban=0;
#endif
				goto restart;
			}

			// WAIT フラグ
			static char waitflag[4] = {0};
      static char waitend=0;
			
			unsigned char i;
			for (i=0; i<4; i++) {
				// 音長カウンタの減算
				if (lencnt[i]>onpu[i]) {
					// デクリメント
					lencnt[i] -= onpu[i];
				} else {
				reread:
					;
					PGM_P p;
#ifndef ONLY1
					p = (PGM_P) gakufu+start[kyokuban+i]+gp[i];
#else
					p = (PGM_P) gakufu+start[i]+gp[i];
#endif
					
					tone  = pgm_read_byte(p);

					// 楽譜の読み出し
					if (tone==END) { // 楽譜進行停止
						switch (i) {
						case 0:
							freq1=0;
							break;
						case 1:
							freq2=0;
							break;
						case 2:
							freq3=0;
							break;
						case 3:
							freq4=0;
							break;
						}
						stopflag[i]=1;
					} else if (tone==WAIT) {
						// 楽譜中に WAIT マークを発見
						if (waitend) {
							//if (1) {
							waitflag[i]=0;
							gp[i]++;
							goto reread;
						}
						waitflag[i]=1;
					}	else {
						lencnt[i]+=B;
						len   = lennum[tone >> 6];
						onpu[i] = len;
						if (len==2) {
							gp[i]++;
							onpu[i] = pgm_read_byte(p+1);
						}
						gp[i]++;
						unsigned int freq = pgm_read_word(tonetable+(tone & 0b00111111));
					
						switch (i) {
						case 0:
							freq1 = freq;
							vol1 = basevol1;
							break;
						case 1:
							freq2 = freq;
							vol2 = basevol2;
							break;
						case 2:
							freq3 = freq;
							vol3 = basevol3;
							break;
						case 3:
							freq4 = freq;
							vol4 = basevol4;
							break;
						} // switch
					} // if (tone==END) {
				} //if (cnt1>onpu1) {
			} // 
			
			// wait フラグのチェック
			waitend=1;
			for (i=0;i<4;i++) {
				if (!stopflag[i] && !waitflag[i]) waitend=0;
			}

		}	// if (tics>K) 
	}

	return 0;
}

