/*****************************************************************************/
/*                                                                           */
/*       RTTTL Ring Tone Player for Microchip PIC16F87x Microcontrollers     */
/*                   Copyright Craig.Peacock@beyondlogic.org                 */
/*                       Version 1.0 17th August 2003                        */
/*                                                                           */
/*****************************************************************************/

#include <pic.h>

#define TONE    RA2

void InitTimer(void);
void delayms(unsigned char cnt);
void PlayNote(unsigned short note, unsigned char octave, unsigned int duration);

unsigned char beep;
unsigned char preloadTMR1L;
unsigned char preloadTMR1H;
unsigned short TMR0Count;
unsigned char beat_speed;

#define Jingle

void main(void)
{
    unsigned int pointer = 0;
    unsigned int octave = 0;
    unsigned int duration = 0;
    unsigned short note = 0;
    unsigned int defaultoctave = 0;
    unsigned int defaultduration = 0;

#ifdef Bolero
   	const unsigned char static Melody[] = {"c6,8c6,16b,16c6,16d6,16c6,16b,16a,8c6,16c6,16a,c6,8c6,16b,16c6,16a,16g,16e,16f,2g,16g,16f,16e,16d,16e,16f,16g,16a,g,g,16g,16a,16b,16a,16g,16f,16e,16d,16e,16d,8c,8c,16c,16d,8e,8f,d,2g"};
    defaultoctave = 5;
    defaultduration = 4;
    beat_speed = 20;
#endif

#ifdef Happy
    /* HappyBirthday */
    const unsigned char static Melody[] = {"8g.,16g,a,g,c6,2b,8g.,16g,a,g,d6,2c6,8g.,16g,g6,e6,c6,b,a,8f6.,16f6,e6,c6,d6,2c6,8g.,16g,a,g,c6,2b,8g.,16g,a,g,d6,2c6,8g.,16g,g6,e6,c6,b,a,8f6.,16f6,e6,c6,d6,2c6"};
    defaultoctave = 5;
    defaultduration = 4;
    beat_speed = 125;
#endif

#ifdef Itchy
    /* Itchy & Scratcy */
    const unsigned char static Melody[] = {"a4,a,e,c,c4,g4,e,c,f4,a,f,c,g4,b,g,d,a4,a,e,c,c4,g4,e,c,f4,a,f,c,g4,b,g,d,a4,a,e,c,c4,g4,e,c,f4,a,f,c,g4,b,g,d,a4,a,e,c,c4,g4,e,c,f4,a,f,c,g4,b,g,d,d4,a,d,f,d4,a,d,f,a4,a,e,c,a4,a,e,c,e4,g#4,e,b,e4,g#4,e,b,d4,a,d,f,d4,a,d,f,a4,a,e,c,a4,a,e,c,e4,g#4,e,b,e4,g#4,e,b"}; 
	defaultoctave = 5;
    defaultduration = 4;
    beat_speed = 120;
#endif

#ifdef Jingle
    /* Jingle Bell */
    const unsigned char static Melody[] = {"8g,8e6,8d6,8c6,2g,8g,8e6,8d6,8c6,2a,8a,8f6,8e6,8d6,8b,8g,8b,8d6,8g.6,16g6,8f6,8d6,2e6,8g,8e6,8d6,8c6,2g,16f#,8g,8e6,8d6,8c6,2a,8a,8f6,8e6,8d6,8g6,16g6,16f#6,16g6,16f#6,16g6,16g#6,8a.6,16g6,8e6,8d6,c6,g6,8e6,8e6,8e.6,16d#6,8e6,8e6,8e.6,16d#6,8e6,8g6,8c.6,16d6,2e6,8f6,8f6,8f.6,16f6,8f6,8e6,8e6,16e6,16e6,8e6,8d6,8d6,8e6,2d6"};
    defaultoctave = 5;
    defaultduration = 4;
    beat_speed = 100;
#endif

    TRISA2 = 0;     /* Make TONE an output */
	ANSEL = 0x00;
    beep = 0;

    InitTimer();
    PEIE = 1;
    GIE = 1;      /* Enable General Purpose Interrupts */

    do {

        octave = defaultoctave; 	/* Set Default Octave */

        if ((Melody[pointer] == '3') && (Melody[pointer+1] == '2')) {
            duration = 32;
            pointer += 2;
        }
        else if ((Melody[pointer] == '1') && (Melody[pointer+1] == '6')) {
            duration = 16;
            pointer += 2;
        }
        else if (Melody[pointer] == '8') {
            duration = 8;
            pointer++;
        }
        else if (Melody[pointer] == '4') {
            duration = 4;
            pointer++;
        }
        else if (Melody[pointer] == '2') {
            duration = 2;
            pointer++;
        }
        else if (Melody[pointer] == '1') {
            duration = 1;
            pointer++;
        } else duration = defaultduration;

        if (Melody[pointer + 1] == '#') {

            /* Process Sharps */

            switch (Melody[pointer]) {
                case 'a' : note = 10726;
                           break;
                case 'c' : note = 9019;
                           break;
                case 'd' : note = 8035;
                           break;
                case 'f' : note = 6757;
                           break;
                case 'g' : note = 6024;
                           break;
            }
            pointer +=2;

        } else {

            switch (Melody[pointer]) {
                case 'a' : note = 11364;
                           break;
                case 'b' : note = 10123;
                           break;
                case 'c' : note = 9555;
                           break;
                case 'd' : note = 8513;
                           break;
                case 'e' : note = 7584;    
                           break;
                case 'f' : note = 7158;
                           break;
                case 'g' : note = 6378;
                           break;
                case 'p' : note = 0;
                           break;
            }
            pointer++;
        }

        if (Melody[pointer] == '.') {
            /* Duration 1.5x */
            duration = duration + 128;
            pointer++;
        }

        if (Melody[pointer] == '4') {
            octave = 4;
            pointer++;
        } else if (Melody[pointer] == '5') {
            octave = 5;
            pointer++;
        } else     if (Melody[pointer] == '6') {
            octave = 6;
            pointer++;
        } else     if (Melody[pointer] == '7') {
            octave = 7;
            pointer++;
        } 

        if (Melody[pointer] == '.') {
            /* Duration 1.5x */
            duration = duration + 128;
            pointer++;
        }

        PlayNote(note, octave, duration);
    
        

     } while (Melody[pointer++] == ',');
    
    /* Wait until last note has played */
    while(TMR0Count) { };
    beep = 0;

    /* Loop */
    while(1) {};
}

void PlayNote(unsigned short note, unsigned char octave, unsigned int duration)
{

    /* Process octave */
    switch (octave) {
        case 4 : /* Do noting */
             break;
        case 5 : /* %2 */
             note = note >> 1; 
             break;
        case 6 : /* %4 */
             note = note >> 2;
             break;
        case 7 : /* %8 */
             note = note >> 4;
             break;
    }

    /* Wait until last note has played */
    while(TMR0Count) { };
    beep = 0;

    /* Process New Note Frequency */
    if (note) {
        note = ~note;
        preloadTMR1L = (note & 0xFF);
        preloadTMR1H = ((note & 0xFF00) >> 8);
    }
    
    /* Process Note Duration */    
    TMR0Count = 255/(duration & 0x7F);

    /* If duration is 1.5x add .5 to duration */
    if (duration & 0x80) TMR0Count = (TMR0Count + (TMR0Count >> 1));    

    if (note) beep = 1;
}

void InitTimer(void)
{
    /* Initialise Timer 0 */
    OPTION = 0b11010111;  /* Set TMR0 to Internal CLk, 1:256 */
    T0IF = 0;             /* Clear TMR0 Flag, ready for use */
    T0IE = 1;             /* Enable Timer Overflow Interrupt */

    /* Initialise Timer 1 */
    T1CON = 0b00000001;   /* Counter Enabled, Using Ext Pin 1:1 Prescaler */
    TMR1IF = 0;           /* Clear Flag */
    TMR1IE = 1;           /* Enable Interrupt */
}

void interrupt interr(void)
{
    if (T0IF) {
        TMR0 = beat_speed;
        if (TMR0Count) TMR0Count--;
        T0IF = 0;
    }
    if (TMR1IF) {
        if (beep) TONE = !TONE;
        else      TONE = 0;
        TMR1H = preloadTMR1H;
        TMR1L = preloadTMR1L;
        TMR1IF = 0; /* Clear Flag */
    }
}
