/************************************************************************
*									*
*			abc2mtex.c - V1.1 (10/01/94)			*
*									*
*		by    Chris Walshaw (C.Walshaw@gre.ac.uk)		*
*									*
* 	Copyright Chris Walshaw. Permission is granted to use and	*
*	copy provided that this copyright notice remains attached.	*
*	This code may not be sold.					*
*									*
************************************************************************/

#include <stdio.h>

#define NEG_INF	-99999

static	char	*Keys[]={"Ab","Eb","Bb","F","C","G","D","A","E","B","F#","C#"};
static	char	*Notes[]={"G,","A,","B,","C","D","E","F","G","A","B","c","d",
			"e","f","g","a","b","c'","d'"};
int	beam,beam_start,beam_finish,min,max,tmax,transpose=0,offset=0;

int	accidental(c)
char	c;
{
	if (c == '^' || c == '_' || c == '=') return(1);
	else return(0);
}

char	*set_base(meter)
char	*meter;
{
	int	nmrtr,dnmntr;

	     if ((strcmp(meter, "2/4" )) == 0) { min=1; max = 4; }
	else if ((strcmp(meter, "2/4s")) == 0) { min=2; max = 4; }
	else if ((strcmp(meter, "3/2" )) == 0) { min=4; max = 4; }
	else if ((strcmp(meter, "3/2l")) == 0) { min=2; max = 6; }
	else if ((strcmp(meter, "3/4s")) == 0) { min=4; max = 4; }
	else if ((strcmp(meter, "3/4" )) == 0) { min=2; max = 6; }
	else if ((strcmp(meter, "3/4l")) == 0) { min=1; max = 6; }
	else if ((strcmp(meter, "3/8s")) == 0) { min=2; max = 6; }
	else if ((strcmp(meter, "3/8" )) == 0) { min=1; max = 6; }
	else if ((strcmp(meter, "4/4s")) == 0) { min=4; max = 4; }
	else if ((strcmp(meter, "Cs"  )) == 0) { min=4; max = 4; }
	else if ((strcmp(meter, "C|s" )) == 0) { min=4; max = 4; }
	else if ((strcmp(meter, "4/4" )) == 0) { min=2; max = 8; }
	else if ((strcmp(meter, "C"   )) == 0) { min=2; max = 8; }
	else if ((strcmp(meter, "C|"  )) == 0) { min=2; max = 8; }
	else if ((strcmp(meter, "4/4l")) == 0) { min=1; max = 4; }
	else if ((strcmp(meter, "Cl"  )) == 0) { min=1; max = 4; }
	else if ((strcmp(meter, "C|l" )) == 0) { min=1; max = 4; }
	else if ((strcmp(meter, "5/4" )) == 0) { min=1; max = 4; }
	else if ((strcmp(meter, "6/4" )) == 0) { min=2; max = 8; }
	else if ((strcmp(meter, "6/8" )) == 0) { min=2; max = 6; }
	else if ((strcmp(meter, "6/8l")) == 0) { min=1; max = 6; }
	else if ((strcmp(meter, "7/4" )) == 0) { min=2; max = 8; }
	else if ((strcmp(meter, "9/8" )) == 0) { min=2; max = 6; }
	else if ((strcmp(meter, "9/8l")) == 0) { min=1; max = 6; }
	else if ((strcmp(meter,"12/8" )) == 0) { min=2; max = 6; }
	else if ((strcmp(meter,"12/8l")) == 0) { min=1; max = 6; }
	else { (void) printf("meter not recognised\n"); min = 2; max = 8; }
	tmax = max;

	if (meter[0] == 'C')
		if (meter[1] == '|') (void) strcpy(meter,"\\allabreve");
		else		     (void) strcpy(meter,"\\meterC");
	else {
		(void) sscanf(meter,"%d/%d",&nmrtr,&dnmntr);
		(void) sprintf(meter,"\\meterfrac{%d}{%d}",nmrtr,dnmntr);
	}
	return(meter);
}

void	eval_beam(c)
char	c;
{
	char	median;

	     if (c >= 'A' && c <= 'Z') median = 'W';
	else if (c >= 'a' && c <= 'y') median = 'i';
	beam += c - median;
	if (beam_start == NEG_INF) beam_start = beam;
	beam_finish = c - median;
}

int	sharps_flats(s)
char	*s;
{
	     if ((!strcmp(s,"C"   )) || (!strcmp(s,"Am"   )) ||
		 (!strcmp(s,"DDor")) || (!strcmp(s,"GMix" )))
		return( 0+transpose);
	else if ((!strcmp(s,"G"   )) || (!strcmp(s,"Em"   )) ||
		 (!strcmp(s,"ADor")) || (!strcmp(s,"DMix" )))
		return( 1+transpose);
	else if ((!strcmp(s,"F"   )) || (!strcmp(s,"Dm"   )) ||
		 (!strcmp(s,"GDor")) || (!strcmp(s,"CMix" )))
		return(-1+transpose);
	else if ((!strcmp(s,"D"   )) || (!strcmp(s,"Bm"   )) ||
		 (!strcmp(s,"EDor")) || (!strcmp(s,"AMix" )))
		return( 2+transpose);
	else if ((!strcmp(s,"Bb"  )) || (!strcmp(s,"Gm"   )) ||
		 (!strcmp(s,"CDor")) || (!strcmp(s,"FMix" )))
		return(-2+transpose);
	else if ((!strcmp(s,"Eb"  )) || (!strcmp(s,"Cm"   )) ||
		 (!strcmp(s,"FDor")) || (!strcmp(s,"BbMix")))
		return(-2+transpose);
	else if ((!strcmp(s,"A"   )) || (!strcmp(s,"F#m"  )) ||
		 (!strcmp(s,"BDor")) || (!strcmp(s,"EMix" )))
		return( 3+transpose);
	else if (!strcmp(s,"HP"))
		return(0);
	else if (!strcmp(s,"Hp"))
		return(3);
	else {
		(void) printf("Key Signature not recognised - using C\n");
		return(0);
	}
}

void	convert(line)
char	*line;
{
	int	ctr = 0,new_note,mnote,mctr=0;
	char	mline[999];
	while (line[ctr] != '\0') {
		new_note = 1;
		     if (line[ctr] >= 'C' && line[ctr] <= 'G')
			mnote=line[ctr]-'C'+'c'+offset;
		else if (line[ctr] >= 'A' && line[ctr] <= 'B')
			mnote=line[ctr]-'A'+'h'+offset;
		else if (line[ctr] >= 'c' && line[ctr] <= 'g')
			mnote=line[ctr]-'c'+'j'+offset;
		else if (line[ctr] >= 'a' && line[ctr] <= 'b')
			mnote=line[ctr]-'a'+'o'+offset;
		else {
			new_note = 0;
			mline[mctr++] = line[ctr];
		}
		ctr += 1;
		     if (line[ctr] == '\'') { mnote += 7; ctr += 1; }
		else if (line[ctr] ==  ',') { mnote -= 7; ctr += 1; }
		if (new_note) {
			if (mnote < 'a') mnote = 'O'+mnote-'a';
			mline[mctr++] = mnote;
		}
	}
	mline[mctr] = '\0';
	(void) strcpy(line,mline);
}

void	print_transpose(line)
char	*line;
{
	int	ctr = 0, warning = 0,new_note,note;
	while (line[ctr] != '\0') {
		new_note = 1;
		     if (line[ctr] >= 'C' && line[ctr] <= 'G')
			note = line[ctr]-'C'+ 3+offset;
		else if (line[ctr] >= 'A' && line[ctr] <= 'B')
			note = line[ctr]-'A'+ 8+offset;
		else if (line[ctr] >= 'c' && line[ctr] <= 'g')
			note = line[ctr]-'c'+10+offset;
		else if (line[ctr] >= 'a' && line[ctr] <= 'b')
			note = line[ctr]-'a'+15+offset;
		else {
			new_note = 0;
			(void) printf("%c",line[ctr]);
			if (accidental(line[ctr])) warning = 1;
		}
		ctr += 1;
		     if (line[ctr] == '\'') { note += 7; ctr += 1; }
		else if (line[ctr] ==  ',') { note -= 7; ctr += 1; }
		if (new_note) (void) printf("%s",Notes[note]);
	}
	(void) printf("\n");
	if (warning) (void) printf("WARNING: accidentals not transposed\n");
}

void	grace_error(s)
char	*s;
{
	(void) printf("ERROR: %s not allowed in graces notes\n",s);
}

void	abc2tex(title,meter,key,elemskip,t,tex)
int	t;
char	*title,*meter,*key,*elemskip;
FILE	*tex;
{
	int	total,start,note_ctr,ctr,subctr,notes,rewind,rolls,staccato;
	int	new_line = 0,new_bar = 1,plet,x,grace,accent,new_beam,p,p_m;
	int	hp = 0,length,rest;
	char	line[999],pattern[9],u_l;

	offset = 0;

	if (t) {
		(void) printf("  Transpose %s: ",title);
		(void) gets(line);
		(void) sscanf(line,"%d",&transpose);
	}

	if (transpose) {
		(void) printf("  Note offset: ");
		(void) gets(line);
		(void) sscanf(line,"%d",&offset);
		(void) printf("K:%s\n",Keys[sharps_flats(key)+4]);
	}

	(void) fprintf(tex,"\\generalsignature{%d}\\relax\n",sharps_flats(key));
	if (!strcmp(key,"Hp"))
		(void) fprintf(tex,"\\input zHp-begin\n");
	if ((!strcmp(key,"HP"  )) || (!strcmp(key,"Hp"   )))
		hp = 1;

	(void) fprintf(tex,"\\generalmeter{%s}\\relax\n",set_base(meter));

	(void) fprintf(tex,"\\debutmorceau\n");

	if (elemskip[0] != '\0')
		(void) fprintf(tex,"\\normal\\elemskip=%spt\n",elemskip);
	else
		(void) fprintf(tex,"\\normal\n");

	while ((getsIn(line)) != NULL && (strlen(line)) != 0) { /* each line */

	if (line[0] == '\\') {
		if (new_bar) {
			(void) fprintf(tex,"\\notes");
			new_bar = 0;
		}
		(void) fprintf(tex,"%s",line);
		line[0] = '\0';
	} else if ((strncmp(line,"P:",2)) == 0) {
		if (new_line) (void) fprintf(tex,"\\hfil\\zalaligne\n");
		new_line = 0;
		(void) fprintf(tex,"\\notes\\uptext{\\sevenrm %s}\\enotes\\relax\n",&line[2]);
		line[0] = '\0';
	} else if ((strncmp(line,"I:",2)) == 0) {
		line[0] = '\0';		/* Ignore info fields */
	} else if ((strncmp(line,"K:",2)) == 0) {
		(void) fprintf(tex,"\\generalsignature{%d}\\relax\n",
			sharps_flats(&line[2]));
		if (!new_line) (void) fprintf(tex,"\\changesignature\n");
		if (transpose) (void) printf("K:%s\n",
			Keys[sharps_flats(&line[2])+4]);
		line[0] = '\0';
	} else if ((strncmp(line,"M:",2)) == 0) {
		if (new_line) (void) fprintf(tex,"\\hfil\\zalaligne\n");
		new_line = 0;
		if (transpose) (void) printf("%s\n",line);
		if ((strcmp(meter,set_base(&line[2]))) != 0)
			(void) fprintf(tex,"\\notes%s\\enotes\n",&line[2]);
		(void) strcpy(meter,&line[2]);
		line[0] = '\0';
	} else {
		if (new_line) (void) fprintf(tex,"\\hfil\\zalaligne\n");
		new_line = 1;
		if (transpose) print_transpose(line);
		convert(line);
	}

	ctr = 0;

	while (line[ctr] != '\0') { /* until end of line */

	while (line[ctr] == ' ') ctr += 1;

	total = 0;
	notes = 0;
	beam = 0;
	grace = 0;
	rolls = 0;
	staccato = 0;
	new_beam = 1;
	rest = 0;
	beam_start = NEG_INF;
	start = ctr;
	while (line[ctr] != '|' && line[ctr] != ' ' && line[ctr] != ':'
	    && line[ctr] != '-' && line[ctr] != '\\' && total < tmax) {

	if (line[ctr] == '[') {
		(void) fprintf(tex,"\\notes\\Zrepeat{%c}",line[ctr+1]);
		new_bar = 0;
		ctr += 2;
	}

	while (line[ctr] == ' ') ctr += 1;

	if (line[ctr] == '{') {
		grace = 1;
		ctr += 1;
		if (notes) new_beam = 0;
	}

	if (line[ctr] == '}') {
		ctr += 1;
		if (new_beam) goto output;
		grace = 0;
	}

	if (line[ctr] == '(') {
		       if (line[ctr+1] == '3') {
			pattern[notes++] = 'C';
			tmax = 3*max/2;
		} else if (line[ctr+1] == '4') {
			pattern[notes++] = 'D';
			tmax = 4*max/3;
		}
		ctr += 2;
	}

	if (line[ctr] == '~') {
		rolls = 1;
		if (grace) grace_error("rolls");
		ctr += 1;
	}

	if (line[ctr] == '.') {
		staccato = 1;
		if (grace) grace_error("staccato notes");
		ctr += 1;
	}

	if (accidental(line[ctr])) {
		if (grace) grace_error("accidentals");
		pattern[notes++] = 'O';
		ctr += 1;
	}

	if (line[ctr] == 'z') rest = 1;

	note_ctr = ctr;
	if (line[ctr+1] >= '1' && line[ctr+1] <= '8') {
		if (grace) grace_error("note multipliers");
		length = min*(int) atoi(&line[ctr+1]);
		if (length >= 4) {
			if (!notes || (notes == 1 && pattern[0] == 'O')) {
				eval_beam(line[ctr++]);
				pattern[notes++] = 'a'-1+length;
				ctr += 1;
				if (length/min >= 10) ctr += 1;
			} else {
				if (accidental(line[ctr-1])) {
					notes -= 1;
					ctr -= 1;
				}
				if (line[ctr-1] == '~') ctr -= 1;
			}
			goto output;
		}
		eval_beam(line[ctr++]);
		total += length;
		pattern[notes++] = 'a'-1+length;
		ctr += 1;
		if (length/min >= 10) ctr += 1;
	} else {
		eval_beam(line[ctr++]);
		if (grace)
			pattern[notes++] = 'z';
		else {
			pattern[notes++] = 'a'-1+min;
			total += min;
		}
	}

	if (line[ctr+1] == 'z' || rest) goto output;

	}
output:
	if (grace || (beam <= 0 && !hp)) { u_l = 'u'; accent = '<'; p_m = -1;}
			   else { u_l = 'l'; accent = '>'; p_m =  1;}
	if (new_bar)
		if (grace)
			(void) fprintf(tex,"\\grace");
		else {
			(void) fprintf(tex,"\\notes");
			new_bar = 0;
		}
	else
		if (grace) {
			(void) fprintf(tex,"\\enotes\\grace");
			new_bar = 1;
		}
	     if (staccato) (void) fprintf(tex,"\\staccato");
	else if (rolls)    (void) fprintf(tex,"\\rolls");
	pattern[notes] = '\0';
	p = 0;
	if (pattern[p] == 'C' || pattern[p] == 'D') p = 1;
	if (pattern[p] == 'O') {
		(void) fprintf(tex,"\\qsk");
		p += 1;
	}
	(void) fprintf(tex,"\\Z%c",u_l);
	for (subctr = 0; pattern[subctr] != '\0'; ++subctr)
		if (pattern[subctr] != 'O')
			(void) fprintf(tex,"%c",pattern[subctr]);
	for (subctr = start; subctr < ctr; ++subctr)
		if ((line[subctr] >= 'A' && line[subctr] <= 'Z')
		 || (line[subctr] >= 'a' && line[subctr] <= 'y')) {
			(void) fprintf(tex,"{");
			rewind = 1;
			rewind = subctr<rewind?0:rewind;
			if (accidental(line[subctr-rewind])) {
				(void) fprintf(tex,"%c",line[subctr-1]);
				rewind = 2;
			}
			if (line[subctr-rewind] == '.' || line[subctr-rewind] == '~')
				(void) fprintf(tex,"%c",accent);
			(void) fprintf(tex,"%c",line[subctr]);
			if (pattern[++p] == 'O' && (pattern[p-1]-'a'+1)%3) {
				(void) fprintf(tex,"*");
				++p;
			}
			(void) fprintf(tex,"}");
		}
	if (grace) (void) fprintf(tex,"\\egrace");
	if (pattern[0] == 'C' || pattern[0] == 'D') { /* triplet/quadruplet */
			if (pattern[notes-1] == 'a') x = 1;
						else x = 0;
			plet = beam_start+(beam_finish-beam_start)/2;
			if (beam <= 0) (void) fprintf(tex,"{%c}",'i'+plet+8+x);
			else
				if (plet-11-x < -8)
					(void) fprintf(tex,"{%c}",'W'+plet-11-x);
				else
					(void) fprintf(tex,"{%c}",'i'+plet-11-x);
	}
	if (line[start] == 'z') (void) fprintf(tex,"z");
	if (line[ctr] == '-') { /* slur across bar */
		(void) fprintf(tex,"\\Z%ctie{%c}",u_l,line[note_ctr]+p_m);
		++ctr;
	}

	while (line[ctr] == ' ') ctr += 1;

	if (line[ctr] == '|' || line[ctr] == ':')
		if (!new_bar) {
			(void) fprintf(tex,"\\enotes\n");
			new_bar = 1;
		}
	if (line[ctr] == '|') {
		ctr += 1;
		if (line[ctr] == '|') {
			(void) fprintf(tex,"\\doublebarre\n");
			ctr += 1;
		} else if (line[ctr] == ':') {
			(void) fprintf(tex,"\\leftrepeat\n");
			ctr += 1;
		} else (void) fprintf(tex,"\\barre\n");
	} else if (line[ctr] == ':') {
		ctr += 1;
		if (line[ctr] == '|') {
			(void) fprintf(tex,"\\rightrepeat\n");
			ctr += 1;
		} else if (line[ctr] == ':') {
			(void) fprintf(tex,"\\leftrightrepeat\n");
			ctr += 1;
		}
	}
	if (line[ctr] == '\\') {
		new_line = 0;
		ctr += 1;
	}
	if (line[ctr] == '}') ctr += 1;

	while (line[ctr] == ' ') ctr += 1;

	tmax = max;

	} /* until end of line */
	} /* for each line */

	if (!strcmp(key,"Hp"))
		(void) fprintf(tex,"\\input zHp-end\n");
}

