/*! @file melody.c

  @brief   store  Never Gonna Give You Up
  @author  Lukas Fürderer
  @version V1.0
  @date    15.11.2020

This file contains the main app function and init.
*/

#include "melody.h"

// freq: wave duration as multiple of 40ns
// duration: total duration as multiple of 40ns
#define TONE(freq, duration) ((((uint32_t)freq & 0xffff) << 16) | (((uint32_t)duration / (uint32_t)freq) & 0xffff))

// duration: pause duration as multiple of 40ns
#define PAUSE(duration) (0x30000 | ((duration >> 10) & 0xffff))

#define TEXT(id) (0x40000 | id)

const uint32_t TACT = 2120 * 1000 * 25; // 2.12 seconds for one tact

const uint32_t GIS2 = 30098;
const uint32_t F = 35793;
const uint32_t DIS = 40177;
const uint32_t CIS = 45097;
const uint32_t C = 47778;
const uint32_t B = 53629;
const uint32_t GIS = 60197;

const uint32_t CALL = 0x10000;
const uint32_t RETURN = 0x20000;

const uint32_t refrain[];
const uint32_t quadrupel[];
const uint32_t strophe1[];
const uint32_t strophe2[];
const uint32_t main_melody[];
const uint32_t *cpu32EntryPoint = main_melody;

const uint32_t CALL_REFRAIN = CALL + 0;
const uint32_t CALL_QUADRUPEL = CALL + 1;
const uint32_t CALL_STROPHE1 = CALL + 2;
const uint32_t CALL_STROPHE2 = CALL + 3;
const uint32_t GOTO_MAIN_MELODY = 4;

const uint32_t *jumplabels[] = {
    refrain,
    quadrupel,
    strophe1,
    strophe2,
    main_melody,
};
const uint32_t **cppu32JumpLabels = jumplabels;

const char *cpcTexts[] = {
    "                    ", // 0
    " We're no strangers ",
    "      to love       ",
    " You know the rules ",
    "    and so do I     ",
    "A full commitment's ", // 5
    "what I'm thinking of",
    "    You wouldn't    ",
    "   get this from    ",
    "   any other guy    ",
    "    I just wanna    ", // 10
    "  tell you how I'm  ",
    "      feeling       ",
    "   Gotta make you   ",
    "     understand     ",
    "    Never gonna     ", // 15
    "    give you up     ",
    "    let you down    ",
    "   run around and   ",
    "     desert you     ",
    "    make you cry    ", // 20
    "    say goodbye     ",
    "     tell a lie     ",
    "    and hurt you    ",
    "    We've known     ",
    "     each other     ", // 25
    "    for so long     ",
    "    Your heart's    ",
    "  been aching but   ",
    "   You're too shy   ",
    "     to say it      ", // 30
    "Inside we both know ",
    "what's been going on",
    "  We know the game  ",
    "     and we're      ",
    "   gonna play it    ", // 35
    "     And if you     ",
    "   ask me how I'm   ",
    "      feeling       ",
    "   Don't tell me    ",
    "     you're too     ", // 40
    "    blind to see    ",
};

const uint32_t quadrupel[] = {
    TEXT(15),
    TONE(GIS, TACT / 16),
    TONE(B,   TACT / 16),
    TONE(CIS, TACT / 16),
    TONE(B,   TACT / 16),
    RETURN,
};

const uint32_t refrain[] = {
    CALL_QUADRUPEL,

    TEXT(16),
    TONE(F,   TACT * 3 / 16),
    TONE(F,   TACT * 3 / 16),
    TONE(DIS, TACT * 3 / 8),
    CALL_QUADRUPEL,

    TEXT(17),
    TONE(DIS, TACT * 3 / 16),
    TONE(DIS, TACT * 3 / 16),
    TONE(CIS, TACT * 3 / 16),
    TONE(C,   TACT / 16),
    TONE(B,   TACT / 8),
    CALL_QUADRUPEL,

    TEXT(18),
    TONE(CIS, TACT / 4),
    TONE(DIS, TACT / 8),
    TONE(C,   TACT * 3 / 16),
    TONE(B,   TACT / 16),
    TONE(GIS, TACT / 4),
    TEXT(19),
    TONE(GIS, TACT / 8),

    TONE(DIS, TACT / 4),
    TONE(CIS, TACT / 2),
    CALL_QUADRUPEL,

    TEXT(20),
    TONE(F,   TACT * 3 / 16),
    TONE(F,   TACT * 3 / 16),
    TONE(DIS, TACT * 3 / 8),
    CALL_QUADRUPEL,

    TEXT(21),
    TONE(GIS2,TACT / 4),
    TONE(C,   TACT / 8),
    TONE(CIS, TACT * 3 / 16),
    TONE(C,   TACT / 16),
    TONE(B,   TACT / 8),
    CALL_QUADRUPEL,

    TEXT(22),
    TONE(CIS, TACT / 4),
    TONE(DIS, TACT / 8),
    TONE(C,   TACT * 3 / 16),
    TONE(B,   TACT / 16),
    TONE(GIS, TACT / 4),
    TEXT(23),
    TONE(GIS, TACT / 8),

    TONE(DIS, TACT / 4),
    TONE(CIS, TACT / 2),

    RETURN,
};

const uint32_t strophe1[] = {
    PAUSE(TACT / 4),
    TEXT(1),
    TONE(B,   TACT / 8),
    TONE(C,   TACT / 8),
    TONE(CIS, TACT / 8),
    TONE(CIS, TACT / 8),
    TEXT(2),
    TONE(DIS, TACT / 8),

    TONE(C,   TACT * 3 / 16), // 1/8 tact before, 1/16 tact after

    TONE(B,   TACT / 16),
    TONE(GIS, TACT * 7 / 8),

    PAUSE(TACT / 8),
    TEXT(3),
    TONE(B,   TACT / 8),
    TONE(B,   TACT / 8),
    TONE(C,   TACT / 8),
    TONE(CIS, TACT / 8),
    TONE(B,   TACT / 8),
    PAUSE(TACT / 8),
    TEXT(4),
    TONE(GIS, TACT / 8),

    TONE(GIS2,TACT / 4),
    TONE(GIS2,TACT / 8),
    TONE(DIS, TACT * 5 / 8),

    PAUSE(TACT / 8),
    TEXT(5),
    TONE(B,   TACT / 8),
    TONE(B,   TACT / 8),
    TONE(C,   TACT / 8),
    TONE(CIS, TACT / 8),
    TONE(B,   TACT / 8),
    TEXT(6),
    TONE(CIS, TACT / 8),
    TONE(DIS, TACT / 8),

    PAUSE(TACT / 8),
    TONE(C,   TACT / 8),
    TONE(B,   TACT / 8),
    TONE(C,   TACT / 16),
    TONE(B,   TACT / 16),
    TONE(GIS, TACT / 2),

    PAUSE(TACT / 8),
    TEXT(7),
    TONE(B,   TACT / 8),
    TONE(B,   TACT / 8),
    TONE(C,   TACT / 8),
    TEXT(8),
    TONE(CIS, TACT / 8),
    TONE(B,   TACT / 8),
    TONE(GIS, TACT / 4),

    TEXT(9),
    TONE(DIS, TACT / 8),
    TONE(DIS, TACT / 8),
    TONE(DIS, TACT / 8),
    TONE(F,   TACT / 8),
    TONE(DIS, TACT / 2),

    TEXT(10),
    TONE(CIS, TACT * 5 / 8),
    TONE(DIS, TACT / 8),
    TONE(F,   TACT / 8),
    TONE(CIS, TACT / 8),

    TEXT(11),
    TONE(DIS, TACT / 8),
    TONE(DIS, TACT / 8),
    TONE(DIS, TACT / 8),
    TONE(F,   TACT / 8),
    TEXT(12),
    TONE(DIS, TACT / 4),
    TONE(GIS, TACT / 4),

    PAUSE(TACT / 4),
    TEXT(13),
    TONE(B,   TACT / 8),
    TONE(C,   TACT / 8),
    TONE(CIS, TACT / 8),
    TONE(B,   TACT / 8),
    PAUSE(TACT / 8),
    TEXT(14),
    TONE(DIS, TACT / 8),

    TONE(F,   TACT / 8),
    TONE(DIS, TACT * 3 / 8),

    RETURN,
};

const uint32_t strophe2[] = {
    PAUSE(TACT / 8),
    TEXT(24),
    TONE(CIS, TACT / 8),
    TONE(CIS, TACT / 8),
    TEXT(25),
    TONE(B,   TACT / 8),
    TONE(CIS, TACT / 8),
    TONE(DIS, TACT * 3 / 8),

    PAUSE(TACT / 8),
    TEXT(26),
    TONE(C,   TACT / 8),
    TONE(B,   TACT / 8),
    TONE(B,   TACT / 8),
    TONE(GIS, TACT / 2),

    PAUSE(TACT / 8),
    TEXT(27),
    TONE(B,   TACT / 8),
    TONE(B,   TACT / 8),
    TEXT(28),
    TONE(C,   TACT / 8),
    TONE(CIS, TACT / 8),
    TONE(B,   TACT / 8),
    TONE(GIS, TACT / 4),

    PAUSE(TACT / 8),
    TEXT(29),
    TONE(GIS2,TACT / 8),
    TONE(GIS2,TACT / 8),
    TONE(DIS, TACT / 4),
    TEXT(30),
    TONE(F,   TACT / 8),
    TONE(DIS, TACT / 8),
    TONE(CIS, TACT / 8),

    PAUSE(TACT / 8),
    TEXT(31),
    TONE(CIS, TACT / 8),
    TONE(CIS, TACT / 8),
    TONE(B,   TACT / 8),
    TONE(CIS, TACT / 8),
    TONE(B,   TACT / 8),
    TEXT(32),
    TONE(CIS, TACT / 8),
    TONE(DIS, TACT / 8),

    PAUSE(TACT / 8),
    TONE(C,   TACT / 8),
    TONE(B,   TACT / 8),
    TONE(B,   TACT / 8),
    TONE(GIS, TACT / 2),

    PAUSE(TACT / 8),
    TEXT(33),
    TONE(B,   TACT / 8),
    TONE(B,   TACT / 8),
    TONE(C,   TACT / 8),
    TONE(CIS, TACT / 8),
    TEXT(34),
    TONE(B,   TACT / 8),
    TONE(GIS, TACT / 4),

    PAUSE(TACT / 4),
    TEXT(35),
    TONE(DIS, TACT / 8),
    TONE(F,   TACT / 8),
    TONE(F,   TACT / 4),
    TONE(DIS, TACT / 4),

    TEXT(36),
    TONE(CIS, TACT * 5 / 8),
    TONE(DIS, TACT / 8),
    TONE(F,   TACT / 8),

    TEXT(37),
    TONE(DIS, TACT / 4), // 1/8 tact before, 1/8 tact after

    TONE(DIS, TACT / 8),
    TONE(DIS, TACT / 8),
    TONE(F,   TACT / 8),
    TEXT(38),
    TONE(DIS, TACT / 4),
    TONE(GIS, TACT / 4),

    PAUSE(TACT / 4),
    TEXT(39),
    TONE(GIS, TACT / 8),
    TONE(B,   TACT / 8),
    TONE(C,   TACT / 8),
    TEXT(40),
    TONE(CIS, TACT / 8),
    TONE(B,   TACT / 8),
    PAUSE(TACT / 8),

    TEXT(41),
    TONE(DIS, TACT / 8),
    TONE(F,   TACT / 8),
    TONE(DIS, TACT / 4),

    RETURN,
};

const uint32_t main_melody[] = {
    CALL_STROPHE1,
    CALL_REFRAIN,
    CALL_STROPHE2,
    CALL_REFRAIN,
    CALL_REFRAIN,
    GOTO_MAIN_MELODY,
};
