/* 
 * File:   main.c
 * Author: piet
 * PIC12F1822
 * Created on 10 augustus 2016, 20:30
 * Music: Fred Heatherton -  I've Got a Lovely Bunch of Coconuts
 * 
 My family uses this melody from "I've Got a Lovely Bunch of Coconuts" by Fred Heatherton to sing a new text at family meetings such as weddings.
To support the music and tempo I made a music box with a PIC12F1822 to generate the notes and tempo with PWM.
The output from pin RA5 is tied to a piezo or in my case to a transistor feeding a small speaker.
It sounds a bit crappy but it worked great in the field.
 */

#define _XTAL_FREQ 32000000

#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
#include <GenericTypeDefs.h>

//WORD 1 FCMEN IESO CLKOUTEN BOREN<1:0> CPD CP MCLRE PWRTE WDTE<1:0> FOSC<2:0>
//WORD 2 LVP(1) DEBUG(2) ? BORV STVREN PLLEN ? ? ? Reserved ? ? WRT<1:0>

#pragma config FOSC = INTOSC
#pragma config WDTE = OFF
#pragma config PWRTE = ON
#pragma config MCLRE = OFF
#pragma config CP = OFF
#pragma config CPD = OFF
#pragma config BOREN = ON
#pragma config CLKOUTEN = OFF
#pragma config IESO = ON
#pragma config FCMEN = ON

#pragma config WRT = OFF
#pragma config PLLEN = OFF
#pragma config STVREN = OFF
#pragma config BORV = LO
#pragma config LVP = OFF

#define c 0
#define ci 1
#define d 2
#define dii 3   // can't us di  ;)
#define e 4
#define f 5
#define fi 6
#define g 7
#define gi 8
#define a 9
#define ai 10
#define b 11
#define cc 12
#define cci 13
#define dd 14
#define ddi 15
#define ee 16
#define p 17    // mute or pauze

// The notes have not exactly the right pitch.  digital problem
const unsigned char noten[] = {237, 224, 211, 199, 188, 177, 167, 158, 149, 141, 133, 125, 118, 111, 105, 99, 93, 1};

// song starts with some tics for timing
// notes and timing from original musicsheet in my possesion.
const unsigned char tapping[] = {c, p, c, p, c, p, c, p}; //4
const unsigned char tapping_Time[] = {1, 5, 1, 5, 1, 5, 1, 5}; //4
const unsigned char down_at[] = {cc, cc, b, cc, b, cc, cc, a, b, ai, b, ai, b, dd, cci, dd, cci, dd, cc, b, a, dd, cc, b, a, g}; //26
const unsigned char down_at_Time[] = {2, 2, 2, 4, 2, 6, 4, 2, 4, 2, 4, 2, 12, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 12}; //26
const unsigned char ive_got[] = {e, dii, e, cc, cc, cc, b, a, e, e, e, p, e, e, dii, e, cc, cc, b, a, f, p}; //22
const unsigned char ive_got_Time[] = {6, 4, 2, 2, 2, 2, 4, 2, 4, 2, 12, 6, 4, 2, 4, 2, 4, 2, 4, 2, 18, 6}; //22
const unsigned char big_ones[] = {b, b, b, b, b, ai, b, b, ai, b, p, a, a, a, a, gi, a, a, a, a, b, dd, cc, b, a, g, g}; //27
const unsigned char big_ones_Time[] = {6, 6, 6, 6, 4, 2, 2, 2, 2, 6, 6, 2, 2, 2, 4, 2, 2, 2, 2, 4, 2, 4, 2, 4, 2, 6, 6}; //27
const unsigned char ive_got2[] = {e, dii, e, cc, cc, cc, b, a, e, e, e, p, p, e, e, dii, e, cc, cc, b, a, f, f, p}; //24
const unsigned char ive_got2_Time[] = {6, 4, 2, 2, 2, 2, 4, 2, 4, 2, 6, 6, 6, 4, 2, 4, 2, 4, 2, 4, 2, 12, 6, 6}; //24
const unsigned char there[] = {b, b, ai, b, p, ai, b, ai, b, ai, b, b, a, g, a, b, a, g, f, e, e, d, c, p, g, a}; //26
const unsigned char there_Time[] = {6, 4, 2, 6, 4, 2, 4, 2, 4, 2, 6, 4, 2, 4, 2, 4, 2, 4, 2, 2, 2, 2, 12, 6, 4, 2}; //26
const unsigned char Roll_a_bowl[] = {cc, b, cc, b, cc, cc, a, a, g, cc, p, p, g, a, cc, b, cc, b, cc, cc, a, a, g, b, p, p}; //26
const unsigned char Roll_a_bowl_Time[] = {4, 2, 4, 2, 4, 2, 2, 2, 2, 6, 6, 6, 4, 2, 4, 2, 4, 2, 4, 2, 2, 2, 2, 6, 6, 12}; //26
const unsigned char Roll_a_bowl2[] = {b, ai, b, ai, b, p, b, ai, b, ai, b, b, a, g, a, b, a, g, f, e, e, d, c, c, p}; //24
const unsigned char Roll_a_bowl2_Time[] = {4, 2, 4, 2, 6, 6, 4, 2, 4, 2, 6, 4, 2, 4, 2, 4, 2, 4, 2, 2, 2, 2, 12, 6, 6}; //24
int tempo_temp, tempo = 90;
volatile unsigned char teller = 0;
int i;

// "inline delay argument must be constant" so a workaround
delay_ms(unsigned int milliseconds) {
    while (milliseconds > 0) {
        __delay_ms(1);
        milliseconds--;
    }
}

// Play the music
void play(const char note[], const char time[], char tik) {
    for (teller = 0; teller < tik; teller++) {
        PR2 = noten[note[teller]];
        for (i = 0; i < (time[teller]); i++) {
            delay_ms(tempo);
        }
        // this is a hiccup so you better hear the ritme and it gives me
        // time to poll RA0 and RA1 for changing the tempo
        TRISA5 = 1;
        if (!RA0) {
            tempo--;
            if (tempo < 20)tempo = 21;
            while (WR)continue;
            EEPROM_WRITE(0, tempo);
        }
        if (!RA1) {
            tempo++;
            if (tempo > 160)tempo = 150;
            while (WR)continue;
            EEPROM_WRITE(0, tempo);
        }
        __delay_ms(1);
        TRISA5 = 0;
    }
}

void main() {
    OSCCON = 0b11110000; // SPLLEN IRCF<3:0> ? SCS<1:0>
    PORTA = 0b000000;
    ANSELA = 0; //AN0 - AN7 digital I/O mode
    TRISA = 0b000011;
    nWPUEN = 0; //Weak Pull-up Enable bit. 1 = All weak pull-ups are disabled
    WPUA = 0b000111; //Weak Pull-up Register bits 1 = Pull-up enabled
    CCP1SEL = 1;
    PR2 = 0xff;
    T2CON = 0b0000111;
    CCP1CON = 0b00001111; //1100;
    OPTION_REGbits.PS = 0b101; // OPTION_REG | WPUEN INTEDG TMR0CS TMR0SE PSA PS2 PS1 PS0
    INTCON = 0b10100000;
    TMR0IE = 1;
    TMR0IF = 0;
    INTE = 0;
    TMR2IF = 0;
    TMR2ON = 1;
    teller = 0;
    while (WR)continue;
    tempo_temp = EEPROM_READ(0);    // stored tempo
    if (tempo_temp > 20) {
        tempo = tempo_temp;
    } else {
        tempo = 90;
    }
    while (!RA0 && !RA1) { // reset tempo only at startup
        tempo = 90;
        delay_ms(200);
    }
    while (WR)continue;
    EEPROM_WRITE(0, tempo);

    do {
        play(tapping, tapping_Time, 8);
        play(down_at, down_at_Time, 26);
        play(ive_got, ive_got_Time, 22);
        play(big_ones, big_ones_Time, 27);
        play(ive_got2, ive_got2_Time, 24);
        play(there, there_Time, 26);
        play(Roll_a_bowl, Roll_a_bowl_Time, 26);
        play(Roll_a_bowl2, Roll_a_bowl2_Time, 24);

        TRISA5 = 1;
        for (i = 0; i < 24; i++) delay_ms(tempo);   // short silence
        TRISA5 = 0;
    } while (1);
}

/*
 * Music: Fred Heatherton

 Down at an english fair one evening I was there
When I heard a showman shouting underneath the flair

I've got a lovely bunch of coconuts
There they are all standing in a row
Big ones, small ones, some as big as your head
Give them a twist a flick of the wrist
That's what the showman said
I've got a lovely bunch of coconuts
Every ball you throw will make me rich
There stands my wife, the idol of me life
Singing roll a bowl a ball a penny a pitch
Roll a bowl a ball a penny a pitch
Roll a bowl a ball a penny a pitch
Roll a bowl a ball, roll a bowl a ball
Singing roll a bowl a ball a penny a pitch
I've got a lovely bunch of coconuts (they're lovely)
There they are all standing in a row (one, two, three, four)
Big ones, small ones, some as big as your head (and bigger)
Give them a twist a flick of the wrist
That's what the showman said
I've got a lovely bunch of coconuts
Every ball you throw will make me rich
There stands my wife, the idol of me life
Singing roll a bowl a ball a penny a pitch (all together now)
Roll a bowl a ball a penny a pitch (harmony)
Roll a bowl a ball a penny a pitch
Roll a bowl a ball, roll a bowl a ball
Singing roll a bowl a ball a penny a pitch
 */