/*
 * Birdianoforte,  Copyright (c) 2011 MickeyDelp.com
 */

sbit KEYBOARD_Pin         at    RA4_bit;
sbit KEYBOARD_Dir         at TRISA4_bit;

sbit OctaveS1_Pin         at    RA5_bit;
sbit OctaveS1_Dir         at TRISA5_bit;
sbit OctaveS2_Pin         at    RB7_bit;
sbit OctaveS2_Dir         at TRISB7_bit;

sbit LEDSA_Pin            at    RC5_bit;
sbit LEDSA_Dir            at TRISC5_bit;
sbit LEDSB_Pin            at    RC4_bit;
sbit LEDSB_Dir            at TRISC4_bit;
sbit LEDSC_Pin            at    RC3_bit;
sbit LEDSC_Dir            at TRISC3_bit;
sbit LEDSD_Pin            at    RC6_bit;
sbit LEDSD_Dir            at TRISC6_bit;

sbit BTN1_Pin             at    RA0_bit;
sbit BTN1_Dir             at TRISA0_bit;
sbit BTN2_Pin             at    RA1_bit;
sbit BTN2_Dir             at TRISA1_bit;

sbit POT_CS_Pin           at    RA2_bit;
sbit POT_CS_Dir           at TRISA2_bit;

sbit SpeakerS_Pin         at    RC0_bit;
sbit SpeakerS_Dir         at TRISC0_bit;

sbit CD4051I_Pin          at    RC1_bit;
sbit CD4051I_Dir          at TRISC1_bit;
sbit CD4051A_Pin          at    RC2_bit;
sbit CD4051A_Dir          at TRISC2_bit;
sbit CD4051B_Pin          at    RB4_bit;
sbit CD4051B_Dir          at TRISB4_bit;
sbit CD4051C_Pin          at    RB5_bit;
sbit CD4051C_Dir          at TRISB5_bit;

#define INPUT 1
#define OUTPUT 0

#define EEbird 0
#define EEoctave 1
#define EErecording 14  // beginning EEPROM location of recording
#define MODEplay 0
#define MODEcalibrate 1
#define KEYNC 0
#define KEYDOWN 1
#define KEYUP 2
#define recordLengthMax 24

//                              1       2       3       4       5       6       7       8       9      10      11      12
const unsigned keys[12] = {0x03FF, 0x03A1, 0x0345, 0x02EC, 0x0297, 0x0242, 0x01EF, 0x019D, 0x014B, 0x00F9, 0x00A6, 0x0052};

const unsigned char LdirA[13] = {INPUT,  INPUT,  INPUT,  OUTPUT, OUTPUT, OUTPUT, OUTPUT, OUTPUT, OUTPUT, INPUT,  INPUT,  INPUT,  INPUT};
const unsigned char LdirB[13] = {INPUT,  OUTPUT, OUTPUT, INPUT,  INPUT,  INPUT,  INPUT,  OUTPUT, OUTPUT, OUTPUT, OUTPUT, INPUT,  INPUT};
const unsigned char LdirC[13] = {INPUT,  INPUT,  INPUT,  INPUT,  INPUT,  OUTPUT, OUTPUT, INPUT,  INPUT,  OUTPUT, OUTPUT, OUTPUT, OUTPUT};
const unsigned char LdirD[13] = {INPUT,  OUTPUT, OUTPUT, OUTPUT, OUTPUT, INPUT,  INPUT,  INPUT,  INPUT,  INPUT,  INPUT,  OUTPUT, OUTPUT};
const unsigned char Lpin0[13] = {0,      2,      4,      1,      4,      1,      3,      1,      2,      3,      2,      3,      4};
const unsigned char Lpin1[13] = {0,      4,      2,      4,      1,      3,      1,      2,      1,      2,      3,      4,      3};

//                               0  1  2  3  4  5  6  7  8  9 10 11 12
const unsigned char BirdA[13] = {1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1};
const unsigned char BirdB[13] = {1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1};
const unsigned char BirdC[13] = {1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0};
const unsigned char BirdI[13] = {0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1};

unsigned char recordBird[recordLengthMax] =    {5,   5,   5,   5,   6};
unsigned char recordPitch[recordLengthMax] =  {12,   6,  12,   1,   6};
unsigned int  recordStart[recordLengthMax] = {200, 300, 500, 600, 800};
unsigned int  recordTime[recordLengthMax] =   {50,  90,  50,  50,  90};
unsigned char recordLength = 5;
unsigned char octave;


void SaveRecording()
{
 unsigned char loc = EErecording;
 unsigned char step;

 if (recordLength == 0)
  return;
 EEPROM_Write(loc++, 123);  // indicates that something is, in fact, saved
 EEPROM_Write(loc++, recordLength);
 for (step = 0; step < recordLength; step++)
 {
  EEPROM_Write(loc++, recordBird[step]);
  EEPROM_Write(loc++, recordPitch[step]);
  EEPROM_Write(loc++, recordStart[step] >> 8);
  EEPROM_Write(loc++, recordStart[step] & 0xff);
  EEPROM_Write(loc++, recordTime[step] >> 8);
  EEPROM_Write(loc++, recordTime[step] & 0xff);
 }
}

void LoadRecording()
{
 unsigned char loc = EErecording;
 unsigned char step;

 if (EEPROM_Read(loc++) != 123)  // indicates that something is, in fact, saved
  return;
 recordLength = EEPROM_Read(loc++);
 if (recordLength > recordLengthMax)
  recordLength = recordLengthMax;
 for (step = 0; step < recordLength; step++)
 {
  recordBird[step] = EEPROM_Read(loc++);
  recordPitch[step] = EEPROM_Read(loc++);
  recordStart[step] = EEPROM_Read(loc++) << 8;
  recordStart[step] |= EEPROM_Read(loc++);
  recordTime[step] = EEPROM_Read(loc++) << 8;
  recordTime[step] |= EEPROM_Read(loc++);
 }
}

void SetOctaveOld(unsigned char octave)
{
 switch (octave)
 {
  case 1:
   OctaveS1_Pin = 0;
   OctaveS2_Pin = 0;
   break;

  case 2:
   OctaveS1_Pin = 0;
   OctaveS2_Pin = 1;
   break;

  case 3:
   OctaveS1_Pin = 1;
   OctaveS2_Pin = 1;
   break;
 }
}

void SetPitchOld(unsigned char pitch)
{
 POT_CS_Pin = 0;
 SPI1_Read(0);
 SPI1_Read((12 - pitch) * 23);
 POT_CS_Pin = 1;
}


const unsigned char PitchA[13] = {0, 210, 168, 126, 84,  42,   0, 210, 168, 126,  84,  42, 0};  // 2 octave range
const unsigned char PitchB[13] = {0, 192, 128,  64,  0, 192, 128,  64,   0, 192, 128,  64, 0};  // 3 octave range

void SetPitch(unsigned char pitch)
{
 switch (octave)
 {
  case 1:
   OctaveS1_Pin = 0;
   if (pitch > 6)
    OctaveS2_Pin = 1;
   else
    OctaveS2_Pin = 0;
   pitch = PitchA[pitch];
   break;

  case 2:
   OctaveS2_Pin = 1;
   if (pitch > 6)
    OctaveS1_Pin = 1;
   else
    OctaveS1_Pin = 0;
   pitch = PitchA[pitch];
   break;

  case 3:
   if (pitch > 8)
   {
    OctaveS1_Pin = 1;
    OctaveS2_Pin = 1;
   }
   else if (pitch > 4)
   {
    OctaveS1_Pin = 0;
    OctaveS2_Pin = 1;
   }
   else
   {
    OctaveS1_Pin = 0;
    OctaveS2_Pin = 0;
   }
   pitch = PitchB[pitch];
   break;
 }
 POT_CS_Pin = 0;
 SPI1_Read(0);
 SPI1_Read(pitch);
 POT_CS_Pin = 1;
}

void PlayBird(unsigned char bird)
{
 if (bird == 0)
  SpeakerS_Pin = 0;
 else
  SpeakerS_Pin = 1;
 CD4051A_Pin = BirdA[bird];
 CD4051B_Pin = BirdB[bird];
 CD4051C_Pin = BirdC[bird];
 CD4051I_Pin = BirdI[bird];
 if (bird == 0)
  return;
 Delay_ms(20);
 CD4051A_Pin = BirdA[0];
 CD4051B_Pin = BirdB[0];
 CD4051C_Pin = BirdC[0];
 CD4051I_Pin = BirdI[0];
}

void LedOn(char num)
{
 LEDSA_Dir = LdirA[num];
 LEDSB_Dir = LdirB[num];
 LEDSC_Dir = LdirC[num];
 LEDSD_Dir = LdirD[num];
 switch (Lpin0[num])
 {
  case 1:
   LEDSA_Pin = 0;
   break;
  case 2:
   LEDSB_Pin = 0;
   break;
  case 3:
   LEDSC_Pin = 0;
   break;
  case 4:
   LEDSD_Pin = 0;
   break;
 }
 switch (Lpin1[num])
 {
  case 1:
   LEDSA_Pin = 1;
   break;
  case 2:
   LEDSB_Pin = 1;
   break;
  case 3:
   LEDSC_Pin = 1;
   break;
  case 4:
   LEDSD_Pin = 1;
   break;
 }
}

unsigned char speed = 0xF0;
volatile unsigned int cnt = 0;

void Interrupt()
{
 cnt++;
 TMR1L = 0x00;          // Preset timer1 value
 TMR1H = speed;         // Preset timer1 value
 PIR1.TMR1IF = 0x00;    // Timer1 interrupt Flag cleared
}

void main()
{
 unsigned char mode = MODEplay;
 unsigned char i1;
 unsigned int  adc;
 unsigned char key = 0;
 unsigned char prevkey = 0;
 unsigned char keyaction = 0;
 unsigned int  blinkRate;
 unsigned char blink = 0;
 unsigned char led;
 unsigned char bird;
 unsigned char recording = 0;
 unsigned char playing = 0;
 unsigned char playIndex;
 
 unsigned int  nextStart;
 unsigned int  nextStop;

 ADCON0 = 0b10000001;   // Right justified
 ANSEL  = 0x08;         // Configure AN3 pin as analog
 ANSELH = 0;            // Configure other AN pins as digital I/O
 OPTION_REG.B7 = 0;     // RABPU - enable individual pull-ups

 INTCON.GIE = 1;        // Enable Global Interrupt
 INTCON.PEIE = 0x01;    // Bit6 Enable Peripheral interrupts
 PIE1.TMR1IE = 0x01;    // Timer1 interrupt enabled
 T1CON.TMR1ON = 0;      // stop the timer
 TMR1L = 0xFF;          // Reset Timer1 lower 8 bits
 TMR1H = 0xF0;          // Reset Timer1 upper 8 bits
 PIR1.TMR1IF = 0x00;    // Timer1 interrupt Flag cleared
 T1CON.TMR1ON = 1;      // start the timer


// KEYBOARD_Dir = INPUT;

 SPI1_Init_Advanced(_SPI_MASTER_OSC_DIV64, _SPI_DATA_SAMPLE_END, _SPI_CLK_IDLE_HIGH, _SPI_LOW_2_HIGH);
 ADC_Init();

 BTN1_Dir = INPUT;
 BTN2_Dir = INPUT;
 WPUA = 0b00000011;

 LEDSA_Dir = INPUT;
 LEDSB_Dir = INPUT;
 LEDSC_Dir = INPUT;
 LEDSD_Dir = INPUT;

 POT_CS_Dir = OUTPUT;
 OctaveS1_Dir = OUTPUT;
 OctaveS2_Dir = OUTPUT;
 CD4051A_Dir = OUTPUT;
 CD4051B_Dir = OUTPUT;
 CD4051C_Dir = OUTPUT;
 CD4051I_Dir = OUTPUT;
 SpeakerS_Dir = OUTPUT;

 PlayBird(0);

 bird = led = EEPROM_Read(EEbird);
 if (bird == 0 || bird > 12)
  bird = led = 1;
 LedOn(led);

 octave = EEPROM_Read(EEoctave);
 if (octave == 0 || octave > 3)
  octave = 2;

 LoadRecording();

 if (BTN2_Pin == 0)
 {
  mode = MODEcalibrate;
  blinkRate = 0x10;
  blink = 1;
  adc = ADC_Get_Sample(3);
  EEPROM_Write(16, adc & 0xff);
  EEPROM_Write(32, adc >> 8);
  while (BTN2_Pin == 0);
 }

 while(1)
 {
  //cnt++;
  //cnt = (TMR1H << 8) | TMR1L;

  adc = ADC_Get_Sample(3) + 8;
  key = 0;
  for (i1 = 0; i1 < 12; i1++)
  {
   if (adc >= keys[i1])
   {
    key = i1 + 1;
    break;
   }
  }
  if (prevkey == key)
   keyaction = KEYNC;
  else
  {
   prevkey = key;
   if (key == 0)
    keyaction = KEYUP;
   else
    keyaction = KEYDOWN;
  }

  switch (mode)
  {
   case MODEcalibrate:
    if (BTN1_Pin == 0)
    {
     if (led == 12)
      led = 1;
     else
      led++;
     LedOn(led);
     Delay_ms(5);
     while (BTN1_Pin == 0);
    }
    if (BTN2_Pin == 0)
    {
     adc -= 8;
     EEPROM_Write(led + 16, adc & 0xff);
     EEPROM_Write(led + 32, adc >> 8);
     Delay_ms(5);
     while (BTN2_Pin == 0);
    }
    break;

   case MODEplay:
    if (keyaction == KEYUP)
    {
      if (BTN1_Pin == 0 || BTN2_Pin == 0)
       break;
      SpeakerS_Pin = 0;
      if (recording == 1 && recordPitch[0] != 0)
      {
       recordTime[recordLength] = cnt - recordStart[recordLength];
       recordLength++;
       if (recordLength == recordLengthMax)
       {
        recording == 0;
        blink = 0;
       }
      }
    }
    else if (keyaction == KEYDOWN)
    {
     if (BTN1_Pin == 0)
     {
      if (bird != key)
      {
       bird = key;
       led = key;
       LedOn(led);
       EEPROM_Write(EEbird, bird);
      }
     }
     else if (BTN2_Pin == 0)
     {
      switch (key)
      {
       case 1:
       case 2:
       case 3:
        octave = key;
        EEPROM_Write(EEoctave, octave);
        break;

       case 4:  // Record
        playing = 0;
        recording = 1;
        speed = 0xF0;
        blinkRate = 0x20;
        blink = 1;
        recordPitch[0] = 0;
        recordLength = 0;
        cnt = 0;
        break;

       case 5:  // Play
        if(recording)
        {
         recording = 0;
         SaveRecording();
        }
        if (recordLength == 0)
        {
         blink = 0;
         break;
        }
        blinkRate = 0x40;
        blink = 1;
        playing = 1;
        playIndex = 0;
        nextStart = recordStart[0];
        nextStop = 0;
        cnt = nextStart - 1;
        break;

       case 6:  // Stop
        SpeakerS_Pin = 0;
        if(recording)
        {
         recording = 0;
         SaveRecording();
        }
        playing = 0;
        blink = 0;
        led = bird;
        LedOn(led);
        break;

       case 7:  // Slow Down
        if (speed != 0)
         speed--;
        if (playing)
        {
         playIndex = 0;
         nextStart = recordStart[0];
         nextStop = 0;
         cnt = nextStart - 1;
        }
        break;

       case 8:  // Speed Up
        if (speed != 0xFF)
         speed++;
        break;
        if (playing)
        {
         playIndex = 0;
         nextStart = recordStart[0];
         nextStop = 0;
         cnt = nextStart - 1;
        }
      }
     }
     else
     {
      if (recording)
      {
       recordPitch[recordLength] = key;
       recordBird[recordLength] = bird;
       recordStart[recordLength] = cnt;
      }
      SetPitch(key);
      PlayBird(bird);
     }
    }
    if (playing)
    {
     if (nextStop)
     {
      if (cnt >= nextStop)
      {
       SpeakerS_Pin = 0;
       playIndex++;
       if (playIndex == recordLength)
       {
        playIndex = 0;
        cnt = 0;
       }
       nextStart = recordStart[playIndex];
       nextStop = 0;
      }
     }
     else if (cnt >= nextStart)
     {
      nextStop = nextStart + recordTime[playIndex];
      SetPitch(recordPitch[playIndex]);
      i1 = recordBird[playIndex] - recordBird[0] + bird;
      if (i1 > 12)
       i1 -= 12;
      PlayBird(i1);
      led = recordPitch[playIndex];
     }
    }
    break;
  }

  if (blink)
  {
   if (cnt & blinkRate)
   {
    LedOn(0);
    blink = 2;
   }
   else if (blink == 2)
   {
    LedOn(led);
    blink = 1;
   }
  }

 Delay_ms(1);
 }
}