/*
 *  MIDIKey.h
 *  MIDI Keybed Library for the Arduino Leonardo(Atmega32U4) & UNO(Atmega 328) & Mega (Atmega1280, 2560)
 *	Version 1.1
 *  by Kodylab 
 *  http://www.kodylab.com
 *	2012/12/14
 *  License		GPL Forty Seven Effects - 2012
 */

#include "MIDIKey.h"
#include <stdlib.h>
#include "Arduino.h"
#include "VelMap.h"

#define _DEBUG 0

#define MIDI_BUFF_SIZE 30
//#define INIT_TIMER_COUNT 65040	// 250uS for 16Mhz - 16bit Timer - Fast Scan Velocity Curve
#define INIT_TIMER_COUNT 64500
#define MAX_KEY_SIZE 61

// Hardware Digital Pin Number
#define KEYSCAN_ZERO	4			// Check Scan line Loop
#define KEYSCAN_CLK 	13		// Gen. Scan Line Clk.
#define DIGITAL_PDL1  	2
// #define DIGITAL_PDL2	3

#define ANALOG_JOYX		0
#define ANALOG_JOYY		1
#define ANALOG_BTN1		3
#define ANALOG_BTN2		4
#define ANALOG_BTN3		2
#define ANALOG_VOL1		5

MIDIKEY_Class MIDIKey;

//
// Pitch Bend table
//
const unsigned char PITCH_TABLE[256] = 
{
	0,0,0,0,0,0,0,0,0,0,1,1,2,2,3,3,
	4,4,5,6,6,7,7,8,8,9,9,10,11,11,12,12,
	13,13,14,14,15,16,16,17,17,18,18,19,19,20,20,21,
	22,22,23,23,24,24,25,25,26,27,27,28,28,29,29,30,
	30,31,32,32,33,33,34,34,35,35,36,36,37,38,38,39,
	39,40,40,41,41,42,43,44,44,45,46,46,47,48,48,49,
	50,50,51,52,53,53,54,55,55,56,57,57,58,59,59,60,
	60,61,61,62,62,63,63,64,64,64,64,64,64,64,64,64,
	64,64,64,64,64,64,64,64,64,64,64,65,65,66,66,67,
	67,68,68,69,69,70,70,71,72,72,73,74,74,75,76,76,
	77,77,78,79,80,80,81,82,82,83,84,85,86,86,87,87,
	88,88,89,89,90,91,91,92,92,93,93,94,94,95,95,96,
	97,97,98,98,99,99,100,100,101,102,102,103,103,104,104,105,
	105,106,107,107,108,108,109,109,110,110,111,112,112,113,113,114,
	114,115,115,116,116,117,118,118,119,119,120,120,121,121,122,123,
	123,124,124,125,125,126,126,127,127,127,127,127,127,127,127,127
};

//
// Debugging
//
// pulse for debugging or measuring on an oscilloscope.
inline void Pulse(void)
{
#if _DEBUG
	// Test Clock
	static unsigned char tg = 0;
	
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)	
// Arduino Mega
	if(tg)	{
			PORTB &= ~0x80;  // PORTB-7 is Low
			tg = 0;
	} else {
			tg = 1;
			PORTB |= 0x80;  // Port B-7 is High
	}
#elif defined(__AVR_ATmega32U4__)
// Arduino Leonardo
	if(tg)	{
			PORTC &= ~0x80;  // PORTC-7 is Low
			tg = 0;
	} else {
			tg = 1;
			PORTC |= 0x80;  // Port C-7 is High
	}
#else 	
// Ports for "standard" boards (Arduino Uno, Duemilanove, etc.)
	if(tg)	{
			PORTB &= ~0x20;  // PORTB is Low
			tg = 0;
	} else {
			tg = 1;
			PORTB |= 0x20;  // Port B is High
	}
#endif
#endif
}

// Timer 1 Interrupt
ISR(TIMER1_OVF_vect) 
{
	//cli();
		// Debug Pulse
		Pulse();

		// Reset Timer
		TCNT1 = INIT_TIMER_COUNT;
  
  	// Velocity Key Calc Timer
  	MIDIKey.TIMER_COUNTER++;
  	if (MIDIKey.TIMER_COUNTER == 4096) {
  		MIDIKey.TIMER_COUNTER = 0;
  	}
    
    // UI Flag Timer
    MIDIKey.UI_COUNTER++;
    if (MIDIKey.UI_COUNTER == 5) MIDIKey.FLAG_STICK = 1;
    if (MIDIKey.UI_COUNTER == 10) MIDIKey.FLAG_PEDAL = 1;
    if (MIDIKey.UI_COUNTER == 15) MIDIKey.FLAG_STICK = 1;
    if (MIDIKey.UI_COUNTER == 20) MIDIKey.FLAG_BUTTON = 1;
    if (MIDIKey.UI_COUNTER == 25) MIDIKey.FLAG_STICK = 1;
    if (MIDIKey.UI_COUNTER == 35) MIDIKey.FLAG_STICK = 1;
    if (MIDIKey.UI_COUNTER == 40) MIDIKey.UI_COUNTER = 0;
  	//sei();
}

// Default constructor for MIDIKEY_Class. 
MIDIKEY_Class::MIDIKEY_Class()
{ 
	// Initialise callbacks to NULL pointer
	mNoteCallback = NULL;
	mPedalCallback = NULL;
	mButtonCallback = NULL;
	mStickCallback = NULL;
}


// Default destructor for MIDIKEY_Class.
MIDIKEY_Class::~MIDIKEY_Class()
{

}


// Call the begin method in the setup() function of the Arduino.
 
void MIDIKEY_Class::begin(const byte MidiKeyCount, const word Baudrate)
{
	int i;
	
	KEY_NUMBER = 	MidiKeyCount;

#if defined(__AVR_ATmega32U4__)
		Serial1.begin(Baudrate);
#else
		Serial.begin(Baudrate);
#endif

		//
		// Init Value
		//
		for (i = 0; i < 16; i++) {
			KEY_DATA[i] = 0xff;
		}

		for (i = 0; i < KEY_NUMBER; i++) {
			KEY_STATUS[i] = 0;
			KEY_TYPE[i] = 0;
		}

	// UI Data
	FLAG_PEDAL = 0;
	FLAG_BUTTON = 0;
	FLAG_STICK = 0;
	
	TIMER_COUNTER = 0;
	UI_COUNTER = 0;
	

// Port Define
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
// Input/Output Ports initialization
// Port A initialization
PORTA=0x00;
DDRA=0xFF;

// Port B initialization
PORTB=0x00;
DDRB=0x87;

// Port C initialization
PORTC=0x00;
DDRC=0xFF;

// Port D initialization
PORTD=0x00;
DDRD=0xFF;

// Port E initialization
PORTE=0x03;
DDRE=0xC6;

// Port F initialization
PORTF=0x00;
DDRF=0x00;

// Port G initialization
PORTG=0x00;
DDRG=0x1F;

// Port H initialization
PORTH=0x00;
DDRH=0x87;

// Port J initialization
PORTJ=0x00;
DDRJ=0xFF;

// Port K initialization
PORTK=0x00;
DDRK=0xFF;

// Port L initialization
PORTL=0x00;
DDRL=0xFF;

// Timer/Counter 1 initialization
TCCR1A=0x00;
TCCR1B=0x02;
TCNT1H=0x00;
TCNT1L=0x83;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
OCR1CH=0x00;
OCR1CL=0x00;

// Timer/Counter 1 Interrupt(s) initialization
TIMSK1=0x01;

#elif defined(__AVR_ATmega32U4__)
// Port B initialization
PORTB=0x00;
DDRB=0x0F;

// Port C initialization
PORTC=0x00;
DDRC=0x80;

// Port D initialization
PORTD=0x0C;
DDRD=0x28;

// Port E initialization
PORTE=0x04;
DDRE=0x00;

// Port F initialization
PORTF=0x00;
DDRF=0x00;

// Timer/Counter 1 initialization
TCCR1A=0x00;
TCCR1B=0x02;
TCNT1H=0x00;
TCNT1L=0x83;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
OCR1CH=0x00;
OCR1CL=0x00;

// Timer/Counter 1 Interrupt(s) initialization
TIMSK1=0x01;

#else
  	//Fast Analog Settings
  	TCCR2A |= (1<<ADPS2);
  	TCCR2A &= ~((1<<ADPS1) | (1<<ADPS0));

		DDRB = 0x20;						// Port B (Digital Port 8~12) input, 13 Output

		pinMode(KEYSCAN_ZERO, INPUT);      	// sets the digital pin as output
		pinMode(KEYSCAN_CLK, OUTPUT);      	// sets the digital pin as output

		TCCR1A=0x00;
		TCCR1B=0x02;
		TCNT1H=0x00;
		TCNT1L=0x83;

// Timer/Counter 1 Interrupt(s) initialization
		TIMSK1=0x01;
#endif	
  sei();
}

// Send Note Message
void MIDIKEY_Class::SendNoteOn(byte channel, byte note, byte velocity)
{
#if defined(__AVR_ATmega32U4__)
		Serial1.write(0x90 + channel);
		Serial1.write(note); 
		Serial1.write(velocity);
#else
		Serial.write(0x90 + channel);
		Serial.write(note); 
		Serial.write(velocity);
#endif
}

void MIDIKEY_Class::SendNoteOff(byte channel, byte note, byte velocity)
{
#if defined(__AVR_ATmega32U4__)
		Serial1.write(0x80 + channel);
		Serial1.write(note); 
		Serial1.write(velocity);
#else
		Serial.write(0x80 + channel);
		Serial.write(note); 
		Serial.write(velocity);
#endif
}

void MIDIKEY_Class::SendControl(byte channel, byte number, byte value)
{
#if defined(__AVR_ATmega32U4__)
		Serial1.write(0xB0 + channel);
		Serial1.write(number);
		Serial1.write(value);
#else
		Serial.write(0xB0 + channel);
		Serial.write(number);
		Serial.write(value);
#endif
}

void MIDIKEY_Class::SendProgramChange(byte channel, byte number)
{
#if defined(__AVR_ATmega32U4__)
		Serial1.write(0xC0 + channel);
		Serial1.write(number);
#else
		Serial.write(0xC0 + channel);
		Serial.write(number);
#endif
}

void MIDIKEY_Class::SendPitchBend(byte channel, int bend)
{
	unsigned char temp;
		temp = 0;
		if (bend == 127) temp = 127;

#if defined(__AVR_ATmega32U4__)
		Serial1.write(0xE0 + channel);
		Serial1.write(temp);
		Serial1.write(bend);
#else
		Serial.write(0xE0 + channel);
		Serial.write(temp);
		Serial.write(bend);
#endif
}

// Callback Func.
void MIDIKEY_Class::setHandleNote(void (*fptr)(byte number, byte value, byte velocity)) { mNoteCallback = fptr; }
void MIDIKEY_Class::setHandlePedal(void (*fptr)(byte number, byte value)) { mPedalCallback = fptr; }
void MIDIKEY_Class::setHandleButton(void (*fptr)(byte number, byte value)) { mButtonCallback = fptr; }
void MIDIKEY_Class::setHandleStick(void (*fptr)(byte number, byte value)) { mStickCallback = fptr; }

void MIDIKEY_Class::resetHandleNote(void) { mNoteCallback = NULL; }
void MIDIKEY_Class::resetHandlePedal(void) { mPedalCallback = NULL; }
void MIDIKEY_Class::resetHandleButton(void) { mButtonCallback = NULL; }
void MIDIKEY_Class::resetHandleStick(void) { mStickCallback = NULL; }

// Read Pedal
void MIDIKEY_Class::PedalCheck(void)
{
	int p1;
	static byte DIG_PDL1 = 1;	

	if (mPedalCallback == NULL) return;
	
	p1 = digitalRead(DIGITAL_PDL1);
	
	if (DIG_PDL1 != p1) {
		DIG_PDL1 = p1;

		// Send Sustain Message
		if (mPedalCallback != NULL) mPedalCallback(0, !p1);
	}
}

// Read Button
void MIDIKEY_Class::ButtonCheck(void)
{
	int b1, b2, b3;
	static byte ANA_BTN1 = 1, ANA_BTN2 = 1, ANA_BTN3;

	if (mButtonCallback == NULL) return;

	b1 = analogRead(ANALOG_BTN1) / 512;
	b2 = analogRead(ANALOG_BTN2) / 512;
	b3 = analogRead(ANALOG_BTN3) / 512;
	
	if (ANA_BTN1 != b1) {
		ANA_BTN1 = b1;
		if (mButtonCallback != NULL) mButtonCallback(0, ANA_BTN1);
	}
	
	if (ANA_BTN2 != b2) {
		ANA_BTN2 = b2;
		if (mButtonCallback != NULL) mButtonCallback(1, ANA_BTN2);
	}

	if (ANA_BTN3 != b3) {
		ANA_BTN3 = b3;
		if (mButtonCallback != NULL) mButtonCallback(2, ANA_BTN3);
	}
}

// Read Stick
void MIDIKEY_Class::StickCheck(void)
{
	unsigned char jx, jy, jvol;
	static byte ANA_JOYX = 64, ANA_JOYY = 64, ANA_VOL = 64;

	if (mStickCallback == NULL) return;
	
	jx = PITCH_TABLE[analogRead(ANALOG_JOYX) / 4];
	if (ANA_JOYX != jx) {
		ANA_JOYX = jx;
			
		if (mStickCallback != NULL) mStickCallback(0, ANA_JOYX);
	}
	
	jy = PITCH_TABLE[analogRead(ANALOG_JOYY) / 4];
	if (ANA_JOYY != jy) {
		ANA_JOYY = jy;

		if (mStickCallback != NULL) mStickCallback(1, ANA_JOYY);
	}

	jy = PITCH_TABLE[analogRead(ANALOG_VOL1) / 4];
	if (ANA_VOL != jy) {
		ANA_VOL = jy;

		if (mStickCallback != NULL) mStickCallback(2, ANA_VOL);
	}
}

//
// Proc Key Event
//
void MIDIKEY_Class::KeyNote(unsigned char KeyPos, unsigned char Status)
{
	unsigned int TCOUNTER, TCALC, TTIME;
	unsigned char BLKCHK, Vel;
	
	TCOUNTER = TIMER_COUNTER;

    if (TCOUNTER >= KEY_TIME[KeyPos]) {
        TCALC = TCOUNTER - KEY_TIME[KeyPos];
    } else {
        TCALC = (4095 - KEY_TIME[KeyPos]) + TCOUNTER;
    } 
    
    if (TCALC > 255) TCALC = 255;
	
    BLKCHK = KeyPos % 12;
    	         
	switch(BLKCHK) {	// Black Key Check
 		case 1:
   		case 3:
    	case 6:
    	case 8:
    	case 10:
    		Vel = KEY_DYNAMIC[TCALC + 256];
    	break;
    	default:	// White Key
			Vel = KEY_DYNAMIC[TCALC];
    	break;
 	} 


	// For Test
	//Vel = (255 -  TCALC) / 2;
	if (mNoteCallback != NULL) mNoteCallback(KeyPos, Status, Vel);
}

// Calc Key Status
void MIDIKEY_Class::KeyCalc(unsigned char KeyPos, unsigned char KeyType, unsigned char OnOff)
{
	if (KeyPos > (KEY_NUMBER - 1)) return;


	if (!KeyType) { // BR
		if (!OnOff && !KEY_TYPE[KeyPos])	{	// Go Note On
			KEY_TIME[KeyPos] = TIMER_COUNTER;
		} 
		if (OnOff && KEY_TYPE[KeyPos])	{	// Go Note OFF
			KeyNote(KeyPos, 0);
		} 
	} else {	// MK
		if (!OnOff && !KEY_TYPE[KeyPos])	{	// Go Note On
			KeyNote(KeyPos, 1);
		} 
		if (OnOff && KEY_TYPE[KeyPos])	{	// Go Note OFF
			KEY_TIME[KeyPos] = TIMER_COUNTER;
		} 
	}

	// New Status
	KEY_TYPE[KeyPos] = KeyType;	
}

// Check Key Bit Data
void MIDIKEY_Class::KeyBitCheck(unsigned char Data)
{
	int i;
	unsigned char KeyType = 0;	// BR = 0 : MK = 1
	unsigned char KeyPos, OldData, NewData, OldBit, NewBit;
	
	
	KeyType = SCAN_LINE % 2;
	
	OldData = KEY_DATA[SCAN_LINE];
	NewData = Data;
	
	for (i = 0; i < 8; i++) {
		OldBit = OldData & 0x01;
		NewBit = NewData & 0x01;
		if (OldBit != NewBit) {
			KeyPos = ((SCAN_LINE / 2) * 8) + i;
			KeyCalc(KeyPos, KeyType, NewBit);
		}
		
		OldData >>= 1;
		NewData >>= 1;
	}
	
	KEY_DATA[SCAN_LINE] = Data;
}

// Check Key On/Off
void MIDIKEY_Class::KeyScan(void)
{
	unsigned char RDATA;
	
	if (mNoteCallback == NULL) return;
	
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)	
	// Toggle CLK
	//digitalWrite(KEYSCAN_CLK, LOW);
	PORTB &= ~0x80;  // PORTB-7 D13 is Low

	delayMicroseconds(5);
	
	// Check Zero
	if (digitalRead(KEYSCAN_ZERO) == 0) {
		SCAN_LINE = 0;
	}
	
	cli();	// Off Int.
	//         PB 3 bit 765   PH 4321
	RDATA = ((PINB << 1) & 0xe0) + ((PINH >> 2) & 0x1e) + ((PINE >> 3) & 0x01);
	
		//Serial.println(PINB, HEX);


	// Check Key Change & Key Chattering
	if (KEY_DATA[SCAN_LINE] != RDATA) {
		delayMicroseconds(1);	// Key Chattering Check
		RDATA = ((PINB << 1) & 0xe0) + ((PINH >> 2) & 0x1e) + ((PINE >> 3) & 0x01);
		
		
		if (KEY_DATA[SCAN_LINE] != RDATA) {
			KeyBitCheck(RDATA);
		}
	}
	sei();	// On.Int

	SCAN_LINE++;

	// Toggle CLK
  PORTB |= 0x80;  // Port B-7 D13 is High
#elif defined(__AVR_ATmega32U4__)
	// Toggle CLK
	//digitalWrite(KEYSCAN_CLK, LOW);
	PORTC &= ~0x80;  // PORTC-7 D13 is Low

	delayMicroseconds(5);
	
	// Check Zero
	if (digitalRead(KEYSCAN_ZERO) == 0) {
		SCAN_LINE = 0;
	}
	
	cli();	// Off Int.
	RDATA = ((PIND << 1) & 0x80) + ((PINB >> 1) & 0x78) + ((PINE >> 4) & 0x04) + ((PIND >> 6) & 0x02) + ((PINC >> 6) & 0x01);

	// Check Key Change & Key Chattering
	if (KEY_DATA[SCAN_LINE] != RDATA) {
		delayMicroseconds(1);	// Key Chattering Check
		RDATA = ((PIND << 1) & 0x80) + ((PINB >> 1) & 0x78) + ((PINE >> 4) & 0x04) + ((PIND >> 6) & 0x02) + ((PINC >> 6) & 0x01);
		
		if (KEY_DATA[SCAN_LINE] != RDATA) {
			KeyBitCheck(RDATA);
		}
	}
	sei();	// On.Int


	SCAN_LINE++;

	// Toggle CLK
  PORTC |= 0x80;  // Port C-7 D13 is High
#else
	
	// Toggle CLK
	//digitalWrite(KEYSCAN_CLK, LOW);
	PORTB &= ~0x20;  // PORTB is Low

	delayMicroseconds(5);
	
	// Check Zero
	if (digitalRead(KEYSCAN_ZERO) == 0) {
		SCAN_LINE = 0;
	}
	
	cli();	// Off Int.
	RDATA = (PINB << 3) + (PIND >> 5);

	// Check Key Change
	if (KEY_DATA[SCAN_LINE] != RDATA) {
		delayMicroseconds(1);	// Key Chattering Check
		RDATA = (PINB << 3) + (PIND >> 5);
		
		if (KEY_DATA[SCAN_LINE] != RDATA) {
			KeyBitCheck(RDATA);
		}
	}
	sei();	// On.Int


	SCAN_LINE++;

	// Toggle CLK
        PORTB |= 0x20;  // Port B is High
#endif	
}
	

// Loop for Port Check
void MIDIKEY_Class::Scan(void)
{

  // Check Keybed	
  KeyScan();
	
  // Check Pedal
  if (FLAG_PEDAL) {
     PedalCheck();
     FLAG_PEDAL = 0;  
  }
  
  // Checak Buttons
  if (FLAG_BUTTON) {
	   ButtonCheck();
     FLAG_BUTTON = 0;
  }
  
  // Check JoyStick
  if (FLAG_STICK) {
	   StickCheck();
     FLAG_STICK = 0;
  }
		
}
