/*
 * An interactive utility for computing the number of beats per
 * note for various time signatures and beat resolutions.
 *
 * Written by Bill Fox   cbema!wbf
 *
 * If you don't want the escape sequences, which are used to
 * do ANSI-compatible screen operationms, you'll have to remove the
 * third #define at the top of the program.  That should make it
 * runnable on non-ANSI terminals.
 */

#include <stdio.h>
#define TRUE 1
#define FALSE 0
/* #define VT100 */

struct NOTE
	{
	char name[20];
	int  value;
	};

static struct NOTE note[12] =
    {	{"half", 2},
	{"half triplet", 3},
	{"quarter", 4},
	{"quarter triplet", 6},
	{"eighth", 8},
	{"eighth triplet", 12},
	{"sixteenth", 16},
	{"sixteenth triplet", 24},
	{"thirtysecond", 32},
	{"thirtysecond triplet", 48},
	{"sixtyfourth", 64},
	{"sixtyfourth triplet", 96}	};

main()
{
int choice;
float BPMin;	/* Tempo in beats per minute. */
float BL;	/* Beat length = 60 / BPMin. */
int BPMea;	/* Beats per measure, time signature's numerator. */
int BEAT;	/* Which type of note gets the beat. */
int QL;		/* Quantize level - which type of note is resolution. */
float TPB;	/* Ticks per beat = (float)QL / (float)BEAT. */
int Beat_no;	/* A beat number <= BPMea. */
int Tick_no;	/* Tick number <= QL; Tick_no = ((TPB) x (Beat_no - 1)) + 1 */
float EQ[12];	/* Equivalent ticks = (float)BEAT*TPB/(float)note[i].value. */
int case_two_done = FALSE;
int case_three_done = FALSE;
int requantize = FALSE;
int i;

printf("\v\v\v\vRythm Composer Aid\n\n");
while (1)
    {
    printf("\nWhat do you want to do?\n\n");
    printf("\t1. Calculate time delay from a tempo marking.\n");
    printf("\t2. Calculate tick number for the beats in a measure.\n");
    printf("\t3. Calculate the number of ticks for different note lengths.\n");
    printf("\t4. Exit the program.\n\n");
    fflush(stdin);
    printf("Enter your choice from the menu by number:  ");
    choice = getchar();
    printf("\n");
    switch(choice)
	{
	case '1':	/* Calculate time delay from tempo marking. */
	    while (1)
		{
		printf("Enter 0 to return to the menu.\n");
		printf("Enter the tempo in beats per minute:  ");
		fflush(stdin);
		scanf("%f", &BPMin);
		/* printf("BPMin = %f\n", BPMin); */
		if (BPMin == 0)
		    break;
		else
		    {
		    BL = 60 / BPMin;
		    printf("\nEach beat lasts %.2f ", BL * 1000);
		    printf("milliseconds.\n\n");
		    }
		}
	    break;
	case '2':	/* Calculate tick number for beats. */
	    case_two_done = TRUE;
	    case_three_done = FALSE;
	    printf("Enter the time signature in two parts...\n");
	    printf("What is the number of beats per measure?  ");
	    fflush(stdin);
	    scanf("%d", &BPMea);
	    printf("What type of note gets the beat?\n\n");
	    BEAT = note_value('r');
	    printf("The time signature is %d/%d.\n", BPMea, BEAT);
	    printf("What note is your quantization level?\n\n");
	    QL = note_value('f');
	    /* printf("QL = %d\n", QL); */
	    TPB = (float)QL / (float)BEAT;
	    printf("There are %5.2f ticks per beat.\n\n", TPB);
	    printf("------------\n");
	    printf("|beat|tick#|\n");
	    printf("|----|-----|\n");
	    for (Beat_no = 1; Beat_no <= BPMea; Beat_no++)
		{
		Tick_no = (TPB * (Beat_no - 1)) + 1;
		printf("| %2d | %3d |\n", Beat_no, Tick_no);
		}
	    printf("------------\n");
	    break;
	case '3':	/* Calculate the equivalent ticks. */
	    if (!case_two_done)
		{
		printf("You must do number 2 before this will work");
		if (case_three_done)
		    {
		    printf(" again");
		    }
		printf(".\n");
		break;
		}
	    case_two_done = FALSE;
	    case_three_done = TRUE;
	    printf("--------------------------------\n");
	    printf("| Note Length          | Ticks |\n");
	    printf("|----------------------|-------|\n");
	    for (i = 0; i < 12; i++)
		{
		EQ[i] = (float)BEAT * TPB / (float)note[i].value;
		if (EQ[i] >= 1.00)
		    {
		    printf("| %-20s | %5.2f |", note[i].name, EQ[i]);
		    if (EQ[i] > (float)((int)EQ[i]))
			{
			printf(" *");
			requantize = TRUE;
			}
		    printf("\n");
		    }
		}
	    printf("--------------------------------\n");
	    if (requantize)
		{
		printf("* To acheive this note length, you'll have ");
		printf("to choose another quantization level.");
		}
	    requantize = FALSE;
	    break;
	case '4':	/* Quit the program. */
	    printf("Thank you for using the Rythm Composer Aid ");
	    printf("Program.\n\n");
	    exit(0);
	default:
	    printf("Invalid response.  Please try again.\n");
	    break;
	}
    }
}

int	note_value(menu)
    char	menu;
    {
    int value = -1;
#ifdef VT100
	static char UP[] = { '', '[', '6', 'A' };
	static char OVER[] = { '', '[', '4', '0', 'C' };
#else
	static char UP[] = { 0 };
	static char OVER[] = { '	' };
#endif

    fflush(stdin);
    printf("\t2.  Half note\n");
    printf("\t4.  Quarter note\n");
    printf("\t8.  Eighth note\n");
    printf("\t16. Sixteenth note\n");
    printf("\t32. Thirtysecond note\n");
    if (menu != 'r')
	{
	/* If the menu is not restricted, print the other menu items. */
	printf("\t64. Sixtyfourth note%s\n", UP);
	printf("%s3.  Half triplet note\n", OVER);
	printf("%s6.  Quarter triplet note\n", OVER);
	printf("%s12. Eighth triplet note\n", OVER);
	printf("%s24. Sixteenth triplet note\n", OVER);
	printf("%s48. Thirtysecond triplet note\n", OVER);
	printf("%s96. Sixtyfourth triplet note\n", OVER);
	}
    printf("\nEnter your choice from the menu by number:  ");
    scanf("%d", &value);
    return(value);
}


