#include <stdio.h>
#include <string.h>

static int line=0;


static int get_freq(int note, int octave, int flat, int sharp) {

	if (octave==0) {

	switch(note) {
		case 'A':
			if (sharp) return 143;
			if (flat) return 161;
			return 152;
		case 'B':
			if (flat) return 143;
			return 135;
		case 'C':
			if (sharp) return 241;
			return 255;
		case 'D':
			if (sharp) return 214;
			if (flat) return 241;
			return 227;
		case 'E':
			if (flat) return 214;
			return 202;
		case 'F':
			if (sharp) return 180;
			return 191;
		case 'G':
			if (sharp) return 161;
			if (flat) return 180;
			return 170;
		default: fprintf(stderr,"Unknown note %c Line %d\n",
					note,line);
	}

	} else

	if (octave==1) {

	switch(note) {
		case 'A':
			if (sharp) return 72;
			if (flat) return 81;
			return 76;
		case 'B':
			if (flat) return 72;
			return 68;
		case 'C':
			if (sharp) return 121;
			return 128;
		case 'D':
			if (sharp) return 108;
			if (flat) return 121;
			return 114;
		case 'E':
			if (flat) return 108;
			return 102;
		case 'F':
			if (sharp) return 91;
			return 96;
		case 'G':
			if (sharp) return 81;
			if (flat) return 91;
			return 85;
		default: fprintf(stderr,"Unknown note %c\n",note);
	}
	} else

	if (octave==2) {

	switch(note) {
		case 'A':
			if (sharp) return 36;
			if (flat) return 40;
			return 38;
		case 'B':
			if (flat) return 36;
			return 34;
		case 'C':
			if (sharp) return 60;
			return 64;
		case 'D':
			if (sharp) return 54;
			if (flat) return 60;
			return 57;
		case 'E':
			if (flat) return 54;
			return 51;
		case 'F':
			if (sharp) return 45;
			return 48;
		case 'G':
			if (sharp) return 40;
			if (flat) return 45;
			return 43;
		default: fprintf(stderr,"Unknown note %c\n",note);
	}

	} else {
		fprintf(stderr,"Unknown octave %d!\n",octave);
	}

	return 0;
}

static int get_duration(int length) {

	int d=0;

	if (length==2) {
		d=216;
	} else if (length==4) {
		d=108;
	} else if (length==8) {
		d=54;
	} else if (length==16) {
		d=27;
	} else if (length==3) {
		d=162;
	} else {
		fprintf(stderr,"Unknown duration %d Line %d\n",length,line);
	}

	return d;
}

static int get_rest(int length) {

	int rest=0;

	switch(length) {
		case 1:	rest=128; break;
		case 2: rest=64; break;
		case 4: rest=32; break;
		case 8: rest=16; break;
		case 16: rest=8; break;
		default: fprintf(stderr,"Unknown rest length %d Line %d!\n",
				length,line);
	}

	return rest*5;
}

int main(int argc, char **argv) {

	char string[BUFSIZ];
	char *result;
	int basic_line=100;
	int i;
	int length=8,last_length=0,duration;
	int rest_length,sharp,flat;
	int octave=1;
	int freq;
	int note;

	/* Routine from http://eightbitsoundandfury.ld8.org/programming.html */
	printf("40 FOR L = 770 TO 790: READ V: POKE L,V: NEXT L\n");
	printf("41 DATA 173,48,192,136,208,5,206,1,3,240,9\n");
	printf("42 DATA 202,208,245,174,0,3,76,2,3,96\n");
	printf("43 GOTO 100\n");


	/* Improved by Carlsson */
	/* http://atariage.com/forums/topic/246369-music-in-applesoft-basic/ */
	printf("50 DATA 173,48,192,174,0,3,202,240,247,234,234,136,208,248,206,1,3,208,243,96\n");
	printf("51 FOR L=770 TO 789:READ V:POKE L,V:NEXT L\n");
	printf("52 GOTO 100\n");

	/* Lighter/faster by Carlsson */
	printf("60 DATA 173,48,192,174,0,3,202,240,247,234,136,208,249,206,1,3,208,244,96\n");
	printf("61 FOR L=770 TO 788:READ V:POKE L,V:NEXT L\n");
	printf("62 GOTO 100\n");

	/* Darker/lower by Calsson */
	printf("70 DATA 173,48,192,174,0,3,202,240,247,234,234,234,136,208,247,206,1,3,208,242,96\n");
	printf("71 FOR L=770 TO 790:READ V:POKE L,V:NEXT L\n");
	printf("72 GOTO 100\n");

	/* Violin sound: https://gist.github.com/thelbane/9291cc81ed0d8e0266c8 */
	printf("80 DATA 172,1,3,173,0,3,133,250,174,0,3,228,250,208,3,173,48,"
			"192,202,208,246,173,48,192,136,240,7,198,250,208,"
			"233,76,5,3,96\n");
	printf("81 FOR L=770 TO 804:READ V:POKE L,V:NEXT L\n");
	printf("82 GOTO 100\n");

	printf("90 POKE 768,F:POKE 769,D:CALL 770:RETURN\n");

	while(1) {
		result=fgets(string,BUFSIZ,stdin);
		line++;
		if (result==NULL) break;

		if (string[0]=='\'') {
			printf("%s",string);
			continue;
		}

		i=0;
		while(1) {

			if (string[i]=='\n') break;
			if (string[i]=='\0') break;
			if ((string[i]==' ') || (string[i]=='\t')) {
				i++;
				continue;
			}

			if (string[i]=='<') {
				octave--;
			}
			else if (string[i]=='>') {
				octave++;
			}
			else if (string[i]=='L') {
				i++;
				length=string[i]-'0';
				if ((length==1) && (string[i+1]=='6')) {
					length=16;
					i++;
				}
			}
			else if (string[i]=='R') {
				i++;
				rest_length=get_rest(string[i]-'0');
				printf("%d FOR I=1 TO %d: NEXT I\n",
					basic_line,rest_length);
				basic_line++;
			}
			else if ((string[i]>='A') && (string[i]<='G')) {
				sharp=0; flat=0;
				note=string[i];
				if (string[i+1]=='#') {
					sharp=1;
					i++;
				}
				if (string[i+1]=='-') {
					flat=1;
					i++;
				}
				printf("%d ",basic_line);
				if (length!=last_length) {
					duration=get_duration(length);
					printf("D=%d:",duration);
					last_length=length;
				}

				freq=get_freq(note,octave,flat,sharp);

				printf("F=%d:GOSUB 90\n",freq);
				basic_line++;
			}
			else {
				fprintf(stderr,"Unknown char %c\n",string[i]);
			}
			i++;

		}
	}

	return 0;
}
