
// by Alex Klinkhamer  (:handle grencez)
// Update: 2008.10.22

// I assume you need the boost libraries for this.

#include <conio.h>
#include <windows.h>
#include <stdio.h>
#include <cstdlib>
#include <math.h>
#include "boost/date_time/posix_time/posix_time.hpp"

using namespace std;
using namespace boost::posix_time;

double afreq = 440.0;

int wholen = 2000; // Whole note = 2 seconds.
int notelen = wholen; // Start on a whole note.

ptime rectime;
bool inclock = 0;

void end_program ();

double scalemod (char c)
{
    switch (c)
    {
        case 'a' : return -10;
        case 's' : return -9;
        case 'e' : return -8;
        case 'd' : return -7;
        case 'r' : return -6;
        case 'f' : return -5;
        case 'g' : return -4;
        case 'y' : return -3;
        case 'h' : return -2;
        case 'u' : return -1;
        case 'j' : return 0;
        case 'i' : return 1;
        case 'k' : return 2;
        case 'l' : return 3;
        case 'p' : return 4;
        case ';' : return 5;
        case '[' : return 6;
        case '\'' : return 7;
        case EOF :
        case 'q' : end_program ();
        default : return 0;
    }
}

double get_freq (char c)
{
    return afreq * pow (2.0, scalemod (c) / 12.0);
}

void beepit (char c)
{
    Beep ((int) (get_freq (c) + 0.5), notelen);
}

void interpret (char c)
{
    switch (c)
    {
        case '-' : afreq /= 2; break;
        case '=' : afreq *= 2; break;
        case '1' : notelen = wholen; break;
        case '2' : notelen = wholen / 2; break;
        case '3' : notelen = wholen / 3; break;
        case '4' : notelen = wholen / 4; break;
        case '8' : notelen = wholen / 8; break;
        case '.' : notelen += notelen / 2; break;
        case 'c' : if (!inclock) { 
                       rectime = microsec_clock::local_time ();
                       inclock = 1;
                       printf ("\nbegin time interval... ");
                   } else {
                       int nextlen =
                           (microsec_clock::local_time () - rectime)
                           .total_milliseconds ();

                       wholen = wholen * nextlen / notelen;
                       notelen = nextlen;
                       inclock = 0;
                       printf ("omplete: %i ms\n", notelen);
                   }
                   break;
        default : beepit (c);
    }
}

void dispinfo ()
{
    printf ("BeepBoard keys:\n");
    printf ("  e r  y u i  o\n");
    printf ("as d fg h j kl\n");
    printf ("Shift one octave up: =\n");
    printf ("Shift one octave down: -\n");
    printf ("Change note duration to respective fraction: 1 2 3 4 8\n");
    printf ("Multiply the current note length by 3/2: .\n");
    printf ("Tap twice to set timing interval: c\n");
    printf ("Quit: q\n");
}


void end_program ()
{
    exit (0);
}

int main ()
{
    dispinfo ();
    while (1)
        interpret (getche ());
    end_program ();
    return 0;
}

