/* AVR Synth Code 
 * Copyright Brian Starkey 2010/2011
 * bs00065[at]surrey[dot]ac[dot]uk
 * NO WARRANTY ACCOMPANIES THIS CODE
 */

#define F_CPU 8000000

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

#include "./lcd_lib/lcd_util.h"

const char poweron[] PROGMEM = "Starting Up...";
const char version[] PROGMEM = "DDS48 05.05.10";

#define LEFT 0
#define RIGHT 1
/* ======== Base Notes, multiply by 2^octave ======== */
/* ========   !These are not pitch perfect!  ======== */
#define C 64
#define Cs 68
#define D 72
#define Ds 76
#define E 82
#define F 86
#define Fs 92
#define G 96
#define Gs 102
#define A 108
#define As 114
#define B 122
/* End Notes */

/* ======== ADC Axes ======== */
#define X_AXIS 4
#define Y_AXIS 3
#define Z_AXIS 1
/* End Axes */

/* ======== Custom Characters ======== */
const char up_down_custom[] PROGMEM = {0x4,0xe,0x1f,0x0,0x0,0x1f,0xe,0x4};
const char up_custom[] PROGMEM = {0x4,0xe,0x1f,0x0,0x0,0x0,0x0,0x0};
const char down_custom[] PROGMEM = {0x0,0x0,0x0,0x0,0x0,0x1f,0xe,0x4};
const char right_custom[] PROGMEM = {0x8,0xc,0xe,0xf,0xe,0xc,0x8,0x0};
const char left_custom[] PROGMEM = {0x2,0x6,0xe,0x1e,0xe,0x6,0x2,0x0};

PGM_P custom_chars[] PROGMEM = {up_down_custom, up_custom, down_custom, right_custom, left_custom};
#define CUSTOM_UP_DOWN 0x00
#define CUSTOM_UP 0x01
#define CUSTOM_DOWN 0x02
#define CUSTOM_RIGHT 0x03
#define CUSTOM_LEFT 0x04
#define NUM_CHARS 5
/* End Custom Chars */

/* ======== Function Protoypes ======== */
void init_pwm(void);
void init_aud(void);
void init_adc(void);
void init_rtc(void);
char stick(char axis, char ad);
void set_tempo(void);
void set_wave(void);
void setup_custom_chars(void);
char * itos(char * s, int i);
void scroll_in(PGM_P what, char from);
/* End functions Prototypes */

/* ======== Waveform Definitions ======== */
const char sine[] PROGMEM = {
	0x80,0x83,0x86,0x89,0x8c,0x8f,0x92,0x95,0x98,0x9c,0x9f,0xa2,0xa5,0xa8,0xab,0xae,
	0xb0,0xb3,0xb6,0xb9,0xbc,0xbf,0xc1,0xc4,0xc7,0xc9,0xcc,0xce,0xd1,0xd3,0xd5,0xd8,
	0xda,0xdc,0xde,0xe0,0xe2,0xe4,0xe6,0xe8,0xea,0xec,0xed,0xef,0xf0,0xf2,0xf3,0xf5,
	0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfc,0xfd,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfd,0xfc,0xfc,0xfb,0xfa,0xf9,0xf8,0xf7,
	0xf6,0xf5,0xf3,0xf2,0xf0,0xef,0xed,0xec,0xea,0xe8,0xe6,0xe4,0xe2,0xe0,0xde,0xdc,
	0xda,0xd8,0xd5,0xd3,0xd1,0xce,0xcc,0xc9,0xc7,0xc4,0xc1,0xbf,0xbc,0xb9,0xb6,0xb3,
	0xb0,0xae,0xab,0xa8,0xa5,0xa2,0x9f,0x9c,0x98,0x95,0x92,0x8f,0x8c,0x89,0x86,0x83,
	0x80,0x7c,0x79,0x76,0x73,0x70,0x6d,0x6a,0x67,0x63,0x60,0x5d,0x5a,0x57,0x54,0x51,
	0x4f,0x4c,0x49,0x46,0x43,0x40,0x3e,0x3b,0x38,0x36,0x33,0x31,0x2e,0x2c,0x2a,0x27,
	0x25,0x23,0x21,0x1f,0x1d,0x1b,0x19,0x17,0x15,0x13,0x12,0x10,0x0f,0x0d,0x0c,0x0a,
	0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x03,0x02,0x01,0x01,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x02,0x03,0x03,0x04,0x05,0x06,0x07,0x08,
	0x09,0x0a,0x0c,0x0d,0x0f,0x10,0x12,0x13,0x15,0x17,0x19,0x1b,0x1d,0x1f,0x21,0x23,
	0x25,0x27,0x2a,0x2c,0x2e,0x31,0x33,0x36,0x38,0x3b,0x3e,0x40,0x43,0x46,0x49,0x4c,
	0x4f,0x51,0x54,0x57,0x5a,0x5d,0x60,0x63,0x67,0x6a,0x6d,0x70,0x73,0x76,0x79,0x7c};
	
const char square[] PROGMEM =  {
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};

const char sawtooth[] PROGMEM = {
	0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
	0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
	0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
	0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
	0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
	0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
	0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
	0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
	0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
	0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
	0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
	0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
	0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
	0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
	0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
	0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff};

const char triangle[] PROGMEM = {
	0x00,0x02,0x04,0x06,0x08,0x0a,0x0c,0x0e,0x10,0x12,0x14,0x16,0x18,0x1a,0x1c,0x1e,
	0x20,0x22,0x24,0x26,0x28,0x2a,0x2c,0x2e,0x30,0x32,0x34,0x36,0x38,0x3a,0x3c,0x3e,
	0x40,0x42,0x44,0x46,0x48,0x4a,0x4c,0x4e,0x50,0x52,0x54,0x56,0x58,0x5a,0x5c,0x5e,
	0x60,0x62,0x64,0x66,0x68,0x6a,0x6c,0x6e,0x70,0x72,0x74,0x76,0x78,0x7a,0x7c,0x7e,
	0x80,0x82,0x84,0x86,0x88,0x8a,0x8c,0x8e,0x90,0x92,0x94,0x96,0x98,0x9a,0x9c,0x9e,
	0xa0,0xa2,0xa4,0xa6,0xa8,0xaa,0xac,0xae,0xb0,0xb2,0xb4,0xb6,0xb8,0xba,0xbc,0xbe,
	0xc0,0xc2,0xc4,0xc6,0xc8,0xca,0xcc,0xce,0xd0,0xd2,0xd4,0xd6,0xd8,0xda,0xdc,0xde,
	0xe0,0xe2,0xe4,0xe6,0xe8,0xea,0xec,0xee,0xf0,0xf2,0xf4,0xf6,0xf8,0xfa,0xfc,0xfe,
	0xff,0xfd,0xfb,0xf9,0xf7,0xf5,0xf3,0xf1,0xef,0xef,0xeb,0xe9,0xe7,0xe5,0xe3,0xe1,
	0xdf,0xdd,0xdb,0xd9,0xd7,0xd5,0xd3,0xd1,0xcf,0xcf,0xcb,0xc9,0xc7,0xc5,0xc3,0xc1,
	0xbf,0xbd,0xbb,0xb9,0xb7,0xb5,0xb3,0xb1,0xaf,0xaf,0xab,0xa9,0xa7,0xa5,0xa3,0xa1,
	0x9f,0x9d,0x9b,0x99,0x97,0x95,0x93,0x91,0x8f,0x8f,0x8b,0x89,0x87,0x85,0x83,0x81,
	0x7f,0x7d,0x7b,0x79,0x77,0x75,0x73,0x71,0x6f,0x6f,0x6b,0x69,0x67,0x65,0x63,0x61,
	0x5f,0x5d,0x5b,0x59,0x57,0x55,0x53,0x51,0x4f,0x4f,0x4b,0x49,0x47,0x45,0x43,0x41,
	0x3f,0x3d,0x3b,0x39,0x37,0x35,0x33,0x31,0x2f,0x2f,0x2b,0x29,0x27,0x25,0x23,0x21,
	0x1f,0x1d,0x1b,0x19,0x17,0x15,0x13,0x11,0x0f,0x0f,0x0b,0x09,0x07,0x05,0x03,0x01};

const PGM_P waveforms[] PROGMEM = {sine, square, sawtooth, triangle};
/* End waveforms */


/* ======== Waveform Names ======== */
const char sin_lbl[] PROGMEM = 		"  Sine  ";
const char square_lbl[] PROGMEM = 	" Square ";
const char saw_lbl[] PROGMEM = 		"Sawtooth";
const char tri_lbl[] PROGMEM = 		"Triangle";
const PGM_P wave_lbls[] PROGMEM = {sin_lbl, square_lbl, saw_lbl, tri_lbl};
/* End Names */

/* ======== Labels ======== */
const char tempo_lbl[] PROGMEM = "Tempo:";
const char bpm_lbl[] PROGMEM = "bpm";
const char wave_lbl[] PROGMEM = "Waveform:";
/* End Labels */

/* ======== Wave struct - not currently used ======== */
struct wave {
	PGM_P values;
	PGM_P name;
};
/* End Wave Struct */

/* ======== Globals ======== */
PGM_P current_wave_table = sine;											// 4 bytes
char current_wave_number = 0;
volatile int phase_accm;									// 2 bytes
uint8_t * phase_accm_high = ((uint8_t*)(&phase_accm))+1;	// 4 bytes
volatile int phase_shift;									// 2 bytes
char overflows;												// 1 byte
volatile int time;											// 2 bytes
char stop_deb_time, play_deb_time, mute_deb_time;
char clear_deb_time, keys_deb_time;							// 5 bytes
volatile char tempo = 120;									// 1 byte
volatile char beat = 1;										// 1 byte
volatile char semiQ = 0;									// 1 byte
volatile char x_axis,y_axis,z_axis;							// 3 bytes
char ctos_buf[4];											// 4 bytes
char tempo_ticks = 100;										// 1 byte
volatile char flags = 0;									// 1 byte
unsigned int leds, buttons, addr;							// 5 bytes
unsigned char octave[12] = {C, Cs, D, Ds, E, F, Fs, G, Gs, A, As, B};
unsigned char current_bar[16] =								//16 bytes
							{C, Cs, D, Ds, E, F, Fs, G, Gs, A, As, B, 0, 0, 0, 0};
/* End Globals */

/* ======== Flags and Macros (used with 'flags') ======== */
#define MUTE_FLAG 1
#define PLAY_FLAG 2
#define START_FLAG 4
#define MUTED (flags & MUTE_FLAG)
#define PLAYING (flags & PLAY_FLAG)
#define AT_START (flags & START_FLAG)
/* End Flags */


int main(void) {
	DDRD = 0x5F; 	/* 0-3 MUXAdd, 4 LEDS, 5 Buttons, 6 OUT */ 
	PORTD |= 0x10;	/* Set LEDs OFF */
	DDRB = 0x38;	/* LCD */
	PORTB = 0;		/* LCD */
	

	_delay_ms(1);
	init_lcd();
	_delay_ms(10);
	print_string_pmem(poweron, 0x01);
	print_string_pmem(version, 0x41);
	_delay_ms(1);
	setup_custom_chars();
	phase_shift = 0;
	init_pwm();
	init_aud();
	init_adc();
	init_rtc();
	sei();
	instruction_cmd(0x01);
	_delay_ms(1);
	
	scroll_in(tempo_lbl, RIGHT);
	for/*ever*/(;;) { 
		set_tempo();
		if (x_axis == 1) {
			scroll_in(wave_lbl, RIGHT);
		}
		else {
			scroll_in(wave_lbl, LEFT);
		};
		set_wave();
		if (x_axis == 1) {
			scroll_in(tempo_lbl, RIGHT);
		}
		else {
			scroll_in(tempo_lbl, LEFT);
		};
	};

	return 0;
}


/* init_adc()
 * Initialise the ADC as required, prescaler etc. Used for thumbsticks
 */
void init_adc(void) {
	ADCSRA |= (1 << ADEN) | (1 << ADSC) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
	ADMUX |= (1 << ADLAR) | (1 << REFS0);
	//| (1 << ADATE) | (1 << ADIE)
}

/* init_pwm()
 * Start Timer0 in WGM, which then generates the required 'amplitude'
 * automatically provided OCR0A is updated appropriately
 */
void init_pwm(void) {
	OCR0A = 128;
	TCCR0A |= (1 << COM0A1) | (1 << WGM01) | (1 << WGM00);
	TCCR0B |= (1 << CS00);
}

/* init_aud()
 * Inititialise Timer1, which is responsible for phase accumulator and
 * other high speed tasks
 */
void init_aud(void) {
	TIMSK1 |= (1 << OCIE1A);
	TCCR1B |= (1 << WGM12) | (1 << CS11);
	OCR1A = 256;
}

/* init_rtc()
 * Initialise Timer2 as an RTC using an external watch crystal.
 * Used for lower speed processing (the bulk of the work)
 */
void init_rtc(void) {
	ASSR |= (1 << AS2);		// External 32768Hz xtal
	TCCR2A |= (1 << WGM21);	// Compare Match Timer Clear Mode
	TIMSK2 |= (1 << OCIE2A); // Compare Interrupt 2A enabled
	OCR2A |= 164; // ~0.005 seconds overflow
	TCCR2B |= (1 << CS20); 	// CK
	beat = 1;
}

/* setup_custom_chars()
 * Load the character data from custom_chars into the LCD's memory
 */
void setup_custom_chars() {
	char i, ii;
	PGM_P p;
	
	for(i = 0; i < NUM_CHARS; i++) {
		instruction_cmd(0x40 | (i << 3));
		memcpy_P(&p, &custom_chars[i], sizeof(PGM_P));
		for (ii = 0; ii < 8; ii++) {
			data_cmd(pgm_read_byte(p+ii));
		}
	}
	
}

/* stick()
 * Get value from thumbsticks
 * 	axis: X_AXIS, Y_AXIS or Z_AXIS
 * 	ad: 0 - return analog value
 * 		1 - return -1, 0 or 1
 */
char stick(char axis, char ad) {
	volatile char adc_res;
	ADMUX = (1 << ADLAR) | (1 << REFS0);
	ADMUX |= axis;
	ADCSRA |= (1 << ADSC);
	do {
		adc_res = ADCSRA & (1 << ADSC);
	} while (adc_res > 0);
	adc_res = ADCH;
	if (ad) {
		if (adc_res < 50) {
			return (-1);
		}
		else if (adc_res > 205) {
			return 1;
		}
		else {
			return 0;
		}
	}
	return adc_res;
 }

/* set_tempo()
 * The tempo set screen. Exits when X_AXIS is moved
 */
void set_tempo(void) {
	char i, oldtempo = 0;
	print_string_pmem(tempo_lbl, 0x01);
	print_string_pmem(bpm_lbl, 0x4D);	
	ctos(ctos_buf, tempo);
	print_string(ctos_buf, 0x4A);

	do{
		instruction_cmd(SET_DDRAM | 0x49);
		y_axis = stick(Y_AXIS, 1);
		if ((tempo > 60) && (tempo < 200)) {
			data_cmd(CUSTOM_UP_DOWN);
			tempo += y_axis;
		}
		else if (tempo == 60) {
			data_cmd(CUSTOM_UP);
			if (y_axis == 1) {
				tempo++;
			}
		}
		else if (tempo == 200) {
			data_cmd(CUSTOM_DOWN);
			if (y_axis == 255) {
				tempo--;
			}
		}
		if (tempo != oldtempo) {
			ctos(ctos_buf, tempo);
			print_string(ctos_buf, 0x4A);
			tempo_ticks = 3000 / tempo;
		}
		oldtempo = tempo;
		for(i = 0; i < 8; i++) {
			_delay_ms(10);
			x_axis = stick(X_AXIS, 1);
			if (x_axis) break;
		}
	} while (x_axis == 0);
}


/* set_wave()
 * The waveform select screen. Exits when X_AXIS is moved
 */
void set_wave(void) {
	char i;
	print_string_pmem(wave_lbl, 0x01);
	PGM_P p;
	memcpy_P(&p, &wave_lbls[current_wave_number], sizeof(PGM_P));
	print_string_pmem(p, 0x48);
	
	do{
		instruction_cmd(SET_DDRAM | 0x47);
		y_axis = stick(Y_AXIS, 1);
		data_cmd(CUSTOM_UP_DOWN);
		current_wave_number += y_axis;
		if (current_wave_number == 255) {
			current_wave_number = 3;	
		}
		if (current_wave_number > 3) {
			current_wave_number = 0;
		}
		memcpy_P(&p, &wave_lbls[current_wave_number], sizeof(PGM_P));
		print_string_pmem(p, 0x48);
		memcpy_P(&p, &waveforms[current_wave_number], sizeof(PGM_P));
		current_wave_table = p;
		for(i = 0; i < 15; i++) {
			_delay_ms(10);
			x_axis = stick(X_AXIS, 1);
			if (x_axis) break;
		}
	} while (x_axis == 0);
}

/* itos()
 * Convert an integer to a string
 * 	s: String buffer
 * 	i: Integer to convert
 * 	returns: s
 */
char * itos(char * s, int i) {
	s[5] = '\0';
	s[0] = (i/10000) | 0x30;
	s[1] = (i/1000)%10 | 0x30;
	s[2] = (i/100)%10 | 0x30;
	s[3] = (i/10)%10 | 0x30;
	s[4] = (i%10) | 0x30;
return s;
}

/* debounce()
 * Decrement the debounce counters (Used in main processing routine)
 */
void debounce(void) {
	if (mute_deb_time > 0) {
		mute_deb_time--;
	}
	if (play_deb_time > 0) {
		play_deb_time--;
	}
	if (stop_deb_time > 0) {
		stop_deb_time--;
	}
	if (keys_deb_time > 0) {
		keys_deb_time--;
	}
	if (clear_deb_time > 0) {
		clear_deb_time--;
	}
}

/* scroll_in()
 * Scroll a string in from the side of the screen.
 * what: The string to scroll (in PROGMEM)
 * from: LEFT or RIGHT
 */
void scroll_in(PGM_P what, char from) {	
				char shift_cmd = (D_SHIFT | D_SHIFT_CD);
				char print_pos = LINE1_START + 16;
				if (from == LEFT) {
					shift_cmd |= (D_SHIFT_LR);
					print_pos = LINE1_START + 24;
				}
				char c;
				instruction_cmd(SET_DDRAM | print_pos);
				for (c = print_pos; c < print_pos + 16; c++) {
					data_cmd(' ');
				}
				instruction_cmd(SET_DDRAM | (print_pos + 0x40));
				for (c = print_pos + 40; c < print_pos + 40 + 16; c++) {
					data_cmd(' ');
				}
				print_string_pmem(what, print_pos+1); /* offscreen */
				for(c = 0; c < 16; c++) 	/* shift */
				{			
					instruction_cmd(shift_cmd);
					_delay_ms(30);
				}
				instruction_cmd(SET_DDRAM | 0x00); 
				for (c = 0x00; c < 0x10; c++) {
					data_cmd(' ');
				}
				instruction_cmd(SET_DDRAM | 0x40); 
				for (c = 0x00; c < 0x10; c++) {
					data_cmd(' ');
				}
				print_string_pmem(what, LINE1_START+1); /* At position 1 */
				instruction_cmd(SET_DDRAM | 0x00);
				data_cmd(CUSTOM_LEFT);
				instruction_cmd(SET_DDRAM | 0x0F);
				data_cmd(CUSTOM_RIGHT);
				instruction_cmd(0x02);
				_delay_ms(5);

}

/* ======== Interrupt Service Rotines ======== */

/* Timer 1 is used for incrementing the phase accumulator, scanning the
 * buttons and lighting the LEDs, basically the high speed stuff
 */ 
ISR(TIMER1_COMPA_vect) {
	int addr_bit = 1 << addr;
	phase_accm+= phase_shift;
	OCR0A = (char)pgm_read_byte(&current_wave_table[*phase_accm_high]);
	PORTD |= 0x10;
	PORTD &= ~0xF;
	PORTD |= addr;

	if (PIND & (1 << 5)) {
		buttons |= (addr_bit);
	}
	else {
		buttons &= ~(addr_bit);
	}
	if ((leds & (addr_bit)) > 0) {
			PORTD &= ~(0x10);
	}
	if (++addr > 15) {
			addr = 0;
	}

}

/* Timer 2 is a RTC - Used for most of the processing */
ISR(TIMER2_COMPA_vect) {  /* We end up here ~every 0.005 seconds */
	int old_phase_shift = phase_shift, one_beat = (tempo_ticks * 4);
	char i;
	sei();
	debounce();
	if (PLAYING) {
		if (time < (16 * tempo_ticks)) {
			time++;
		}
		else {
			time = 1;
		}
		if (time % tempo_ticks == 0) {
			if (semiQ < 15) {
				semiQ++;
				if ((semiQ % 4) == 0) {
					if (beat < 8) {
						beat <<= 1;
					}
				}
			}
			else {
				semiQ = 0;
				beat = 1;
			}
			phase_shift = 64 * (int)current_bar[semiQ];	
			if (phase_shift != old_phase_shift) {
				phase_accm = 0;
			}
		}
	}
	
	for (i = 0; i < 12; i++) {
		if (current_bar[semiQ] == octave[i]) {
			leds |= (1 << (i + 4));
		}
		else {
			leds &= ~(1 << (i + 4));
		}
		if (keys_deb_time == 0) {
			if (buttons & (1 << (i + 4))) {
				if (current_bar[semiQ] == octave[i]) {
					current_bar[semiQ] = 0;
				}
				else {
					current_bar[semiQ] = octave[i];
				}
			if (PLAYING) {
				phase_shift = 64 * (int)current_bar[semiQ];	
				if (phase_shift != old_phase_shift) {
					phase_accm = 0;
				}
			}
			keys_deb_time = tempo_ticks - (time % tempo_ticks);
			}
		}
	}

	if ((buttons & 8) > 0) {
		current_bar[semiQ] = 0;
		clear_deb_time = tempo_ticks - (time % tempo_ticks);
	}
	// Mute removed because the button was repurposed as clear.
	/*if (mute_deb_time == 0) {
		flags ^= MUTE_FLAG;
		mute_deb_time = one_beat;
	}*/
	
	if ((buttons & 2) > 0) {
		if (play_deb_time == 0) {
			if ((PLAYING) || (AT_START)) {
				time = (16 * tempo_ticks) -1;
				semiQ = 15;
				beat = 1;
			}
			flags |= PLAY_FLAG;
			play_deb_time = one_beat;
		}
	}
	
	if ((buttons & 4) > 0) {
		if (stop_deb_time == 0) {
			if (PLAYING) {
				flags &= ~PLAY_FLAG;
				flags &= ~START_FLAG;
				phase_shift = 0;
			}
			else {
				time = (16 * tempo_ticks) -1;
				semiQ = 0;
				beat = 1;
				flags |= (START_FLAG);
			}
			stop_deb_time = one_beat;
		}
	}	
	
	if (MUTED > 0) {
		leds |= 0x0F;	
		phase_shift = 0;
	}
	else {
		leds &= ~0x0F;
	}
	
	if  (((semiQ % 2) == 0) || !(PLAYING)) {
		leds ^= beat;
	}
}

/*
ISR(ADC_vect) {
 
}
*/
