/*
 * Copyright(C) Paul und Scherer (mct.de/mct.net)
 *
 * This example demonstrates how to...
 *
 *  ... use the timers to generate sound.
 */

#include <stdio.h>
#include <conio.h>
#include <target.h>
#include "delay.h"

/*
 * Beep at hz Hertz (0 =off) at MAT0.2 (=P0.16) using Timer0.
 */
static void
beep(unsigned hz)
{
	if (hz) {
		Intern_t0tcr    = 2;		// stop, reset
		Intern_t0mr2    = _PCLK/2/hz-1;	// set period
		Intern_t0mcr   |= 0x80;		// reset on MR2
		Intern_t0emr   |= 0x300;	// MAT0.2 toggle
		Intern_pinsel1 |= 2;		//        enable
		Intern_t0tcr    = 1;		// go...
	} else	Intern_pinsel1 &= ~2;		// disconnect MAT0.2
}

/*
 * Play melody using beep() and delay()
 * (connect P0.16 via 20kOhm to line in).
 */
int
main(void)
{
	int hld = 1;				// hold (=staccato off)
	int dly = 3;				// tempo
	int oct = 1;				// octave shift

	puts("Playing...\n\n"
	     ". : toggle staccato\n"
	     "+ : faster\n"
	     "- : slower\n"
	     "> : octave up\n"
	     "< : octave down\n"
	);
	while (1) {
		static short const ftbl[] =	// frequency table for notes
		{				//  (rounded to ints)
			  0,			//  - code =@
			220,			// a0       A
			247,			// b0       B
			262,			// c1       C
			294,			// d1       D
			330,			// e1       E
			349,			// f1       F
			392,			// g1       G
			440,			// a1       H
			494,			// b1       I
			523			// c2       J
		};

		/*
		 * melody
		 */
		char *p = "GGGFEGJDEEEECCJCHHHICIJHGGGGEEEEG@@FEGCDEED@C@JCDD@DC@B@CCCCC@@@@@@@"
			  "CCDDEEC@CCDDEEC@EEFFGGG@EEFFGGG@GHGFEECJGHGFE@CCJJGGJJJ@JJGGJJJ@@@@@"
			  "CEFGGGG@CEFGGGG@CEFGGEECCE@EDDD@DEDCC@JEEG@GFFF@FEFG@EECCDDCCCC@@@@@";

		int last;			// last note

		for (last = 0; *p; p++) {
			if (kbhit()) switch (getchar()) {
			case '.': hld = !hld; break;
			case '+': dly--;      break;
			case '-': dly++;      break;
			case '>': oct++;      break;
			case '<': oct--;      break;
			}

			if (dly > 9) dly = 0;
			if (dly < 0) dly = 9;
			if (oct > 3) oct = 0;
			if (oct < 0) oct = 3;

			if (*p != last) beep(ftbl[(last = *p)-'@']<<oct);
			if (!hld) delay(40), beep(0);
			delay((dly+hld+1)*40);
		}
		hld = !hld;			// toggle staccato
		dly--;				// speed up
		oct++;				// shift up
	}
}
