#include "abc.h" #include struct fract { int num; int denom; }; struct fract barlen, unitlen, count, tuplefactor, breakpoint; int barno; int newspacing, barcheck, repcheck, echeck; int newbreaks, totalnotes, notecount; int expect_repeat; int tuplenotes, barend; int xinhead, xinbody; int inmusic; int startline, blankline; int transpose; int newkey, lines, oldtable[7], newtable[7]; int inchord, ingrace, chordcount; int inlinefield; int cleanup; char tmp[2000]; enum abctype {field, bar, barline}; enum linestattype {fresh, midmusic, endmusicline, postfield}; enum linestattype linestat; struct abctext{ struct abctext* next; char* text; enum abctype type; int notes; }; struct abctext* head; struct abctext* tail; char* checkmalloc(); char* addstring(s) char* s; { char* p; p = checkmalloc(strlen(s)+1); strcpy(p, s); return(p); } int purgespace(p) char* p; { int blank; char *s; blank = 1; s = p; while (*s != '\0') { if (*s != ' ') blank = 0; s = s + 1; }; if (blank) { *p = '\0'; }; return(blank); } struct abctext* newabctext(t) enum abctype t; { struct abctext* p; if (newbreaks) { p = (struct abctext*) checkmalloc(sizeof(struct abctext)); p->text = addstring(tmp); tmp[0] = '\0'; p->next = NULL; p->type = t; if (t != field) { p->notes = notecount; totalnotes = totalnotes + notecount; notecount = 0; } else { p->notes = 0; }; if (head == NULL) { head = p; tail = p; } else { tail->next = p; tail = p; }; } else { printf("%s", tmp); tmp[0] = '\0'; p = NULL; }; inmusic = 1; return(p); } freehead() { struct abctext* p; p = head; if (p != NULL) { printf("%s", p->text); free(p->text); head = p->next; free(p); }; if (head == NULL) { tail = NULL; }; } int abs(n) int n; { int r; if (n > 0) { r = n; } else { r = -n; }; return(r); } int nextnotes() { int n, got; struct abctext* p; p = head; n = 100; got = 0; while ((p != NULL) && (!got)) { if (p->type == bar) { n = p->notes; got = 1; } else { p = p->next; }; }; return(n); } setline(t) enum linestattype t; { if ((t == fresh) && ((linestat == postfield) || (linestat == endmusicline))) { printf("\n"); }; if ((t == fresh) && (linestat == midmusic)) { printf("\\\n"); }; linestat = t; } tryout(last) int last; { int outlines; int charcount, ncount; enum abctype t; if (newbreaks && ((totalnotes > 15) || last)) { outlines = ((totalnotes+15)/30); if (outlines == 0) outlines = 1; charcount = 0; ncount = 0; while (head != NULL) { t = head->type; if (t == field) { setline(fresh); charcount = 0; }; if (t != field) { charcount = charcount + strlen(head->text); if (charcount >= 79) { setline(fresh); charcount = 0; }; }; ncount = ncount + head->notes; freehead(); if (t == field) { setline(postfield); setline(fresh); charcount = 0; } else { setline(midmusic); }; if (((t == barline) || (head == NULL) || ((ncount == totalnotes) && (head->type == field))) && (outlines > 0) && (abs(ncount-totalnotes/outlines) < abs(ncount+nextnotes() - totalnotes/outlines))) { setline(endmusicline); setline(fresh); outlines = outlines - 1; totalnotes = totalnotes - ncount; charcount = 0; ncount = 0; }; }; }; } int getarg(option, argc, argv) char *option; char *argv[]; int argc; { int j, place; place = -1; for (j=0; j [-s] [-n] [-b] [-r] [-e] [-t X] -u\n"); printf(" -s for new spacing\n"); printf(" -n for new linebreaks\n"); printf(" -b to remove bar checking\n"); printf(" -r to remove repeat checking\n"); printf(" -e to remove all error reports\n"); printf(" -t X to transpose X semitones\n"); printf(" -u to update notation ([] for chords and () for slurs)\n"); exit(0); } else { *filename = argv[1]; }; if (getarg("-u", argc, argv) == -1) { cleanup = 0; } else { cleanup = 1; }; if (getarg("-s", argc, argv) == -1) { newspacing = 0; } else { newspacing = 1; }; if (getarg("-e", argc, argv) == -1) { echeck = 1; } else { echeck = 0; }; if (getarg("-n", argc, argv) == -1) { newbreaks = 0; } else { newbreaks = 1; echeck = 0; }; if (getarg("-b", argc, argv) != -1) { barcheck = 0; } else { barcheck = 1; }; if (getarg("-r", argc, argv) != -1) { repcheck = 0; } else { repcheck = 1; }; targ = getarg("-t", argc, argv); if (targ == -1) { transpose = 0; } else { if (targ >= argc) { event_error("No tranpose value supplied"); } else { if (*argv[targ] == '-') { transpose = -readnumf(argv[targ]+1); } else { transpose = readnumf(argv[targ]); }; }; }; /* printf("%% output from abc2abc\n"); */ startline = 1; blankline = 0; xinbody =0; inmusic = 0; inchord = 0; ingrace = 0; head = NULL; tail = NULL; tmp[0] = '\0'; totalnotes = 0; } close_newabc() { if (newbreaks) { tryout(1); if (linestat == midmusic) setline(endmusicline); setline(fresh); }; } event_eof() { close_newabc(); } event_blankline() { close_newabc(); if (newbreaks) printf("\n"); xinbody = 0; xinhead = 0; parseroff(); blankline = 1; } event_text(p) char *p; { sprintf(tmp+strlen(tmp),tmp, "%%%s", p); inmusic = 0; } event_reserved(p) char p; { sprintf(tmp+strlen(tmp),tmp+strlen(tmp), "%c", p); inmusic = 0; } event_tex(s) char *s; { sprintf(tmp+strlen(tmp),tmp+strlen(tmp),"%s", s); inmusic = 0; } event_linebreak() { if (newbreaks) { if (!purgespace(tmp)) { if (inmusic) { newabctext(bar); } else { newabctext(field); }; }; } else { newabctext(bar); printf("\n"); }; } event_startmusicline() { } event_endmusicline(endchar) char endchar; { } event_error(s) char *s; { if (echeck) { printf("\n%%Error : %s\n", s); }; } event_warning(s) char *s; { if (echeck) { printf("\n%%Warning : %s\n", s); }; } event_comment(s) char *s; { if (newbreaks && (!purgespace(tmp))) { if (inmusic) { newabctext(bar); } else { newabctext(field); }; }; sprintf(tmp+strlen(tmp),"%%%s", s); inmusic = 0; } event_specific(p, s) char *p, *s; { sprintf(tmp+strlen(tmp),"%%%s %s", p, s); inmusic = 0; } event_field(k, f) char k; char *f; { sprintf(tmp+strlen(tmp),"%c:%s", k, f); inmusic = 0; } event_words(p) char* p; { event_field('w', p); } event_part(s) char* s; { if (xinbody) { tryout(0); }; sprintf(tmp+strlen(tmp),"P:%s", s); inmusic = 0; } event_voice(n, s) int n; char *s; { sprintf(tmp+strlen(tmp),"V:%d %s", n, s); inmusic = 0; } event_length(n) int n; { sprintf(tmp+strlen(tmp),"L:1/%d", n); unitlen.num = 1; unitlen.denom = n; inmusic = 0; } event_refno(n) int n; { if (xinbody) { close_newabc(); }; sprintf(tmp+strlen(tmp),"X: %d", n); parseron(); xinhead = 1; notecount = 0; unitlen.num = 0; unitlen.denom = 1; barlen.num = 0; barlen.denom = 1; inmusic = 0; } event_tempo(n, a, b, relative) int n, a, b; int relative; { if ((a == 0) && (b == 0)) { sprintf(tmp+strlen(tmp),"Q:%d", n); } else { if (relative) { sprintf(tmp+strlen(tmp),"Q:C%d/%d=%d", a, b, n); } else { sprintf(tmp+strlen(tmp),"Q:%d/%d=%d", a, b, n); }; }; inmusic = 0; } event_timesig(n, m, checkbars) int n, m, checkbars; { if (checkbars == 1) { sprintf(tmp+strlen(tmp),"M:%d/%d", n, m); } else { sprintf(tmp+strlen(tmp), "M:none"); barcheck = 0; }; barlen.num = n; barlen.denom = m; breakpoint.num = n; breakpoint.denom = m; if ((n == 9) || (n == 6)) { breakpoint.num = 3; breakpoint.denom = barlen.denom; }; if (n%2 == 0) { breakpoint.num = barlen.num/2; breakpoint.denom = barlen.denom; }; barend = n/breakpoint.num; inmusic = 0; } setmap(sf, map) int sf; int map[7]; { int j; for (j=0; j<7; j++) { map[j] = 0; }; if (sf >= 1) map['f'-'a'] = 1; if (sf >= 2) map['c'-'a'] = 1; if (sf >= 3) map['g'-'a'] = 1; if (sf >= 4) map['d'-'a'] = 1; if (sf >= 5) map['a'-'a'] = 1; if (sf >= 6) map['e'-'a'] = 1; if (sf >= 7) map['b'-'a'] = 1; if (sf <= -1) map['b'-'a'] = -1; if (sf <= -2) map['e'-'a'] = -1; if (sf <= -3) map['a'-'a'] = -1; if (sf <= -4) map['d'-'a'] = -1; if (sf <= -5) map['g'-'a'] = -1; if (sf <= -6) map['c'-'a'] = -1; if (sf <= -7) map['f'-'a'] = -1; } event_key(sharps, s, minor, modmap, modmul) int sharps; char *s; int minor; char modmap[7]; int modmul[7]; { static char* keys[12] = {"Db", "Ab", "Eb", "Bb", "F", "C", "G", "D", "A", "E", "B", "F#"}; setmap(sharps, oldtable); newkey = (sharps+7*transpose)%12; lines = (sharps+7*transpose)/12; if (newkey > 6) { newkey = newkey - 12; lines = lines + 1; }; if (newkey < -5) { newkey = newkey + 12; lines = lines - 1; }; setmap(newkey, newtable); if ((xinhead) && (!xinbody)) { xinbody = 1; start_tune(); }; if (transpose == 0) { sprintf(tmp+strlen(tmp),"K:%s", s); } else { sprintf(tmp+strlen(tmp),"K:%s", keys[newkey+5]); }; inmusic = 0; } start_tune() { parseron(); count.num =0; count.denom = 1; barno = 0; tuplenotes = 0; expect_repeat = 0; if (barlen.num == 0) { /* generate missing time signature */ event_timesig(4, 4, 1); inmusic = 0; event_linebreak(); }; if (unitlen.num == 0) { if ((float) barlen.num / (float) barlen.denom < 0.75) { unitlen.num = 1; unitlen.denom = 16; } else { unitlen.num = 1; unitlen.denom = 8; }; }; } printlen(a, b) int a, b; { if (a != 1) { sprintf(tmp+strlen(tmp),"%d", a); }; if (b != 1) { sprintf(tmp+strlen(tmp),"/%d", b); }; } event_rest(n,m) int n, m; { notecount = notecount + 1; inmusic = 1; sprintf(tmp+strlen(tmp),"z"); printlen(n, m); if (inchord) { chordcount = chordcount + 1; }; if ((!ingrace) && (!inchord || (chordcount == 1))) { addunits(n, m); }; if (tuplenotes != 0) { event_error("Rest not allowed in tuple"); }; } event_bar(type) int type; { char msg[40]; if (!purgespace(tmp)) { if (inmusic) { newabctext(bar); } else { newabctext(field); }; }; if (type == BAR_REP) tryout(0); notecount = notecount + 1; switch(type) { case SINGLE_BAR: sprintf(tmp+strlen(tmp),"|"); break; case DOUBLE_BAR: sprintf(tmp+strlen(tmp),"||"); break; case THIN_THICK: sprintf(tmp+strlen(tmp),"|]"); break; case THICK_THIN: sprintf(tmp+strlen(tmp),"[|"); break; case BAR_REP: sprintf(tmp+strlen(tmp),"|:"); if ((expect_repeat) && (repcheck)) { event_error("Expecting repeat, found |:"); }; expect_repeat = 1; break; case REP_BAR: sprintf(tmp+strlen(tmp),":|"); if ((!expect_repeat) && (repcheck)) { event_error("No repeat expected, found :|"); }; expect_repeat = 0; break; case BAR1: sprintf(tmp+strlen(tmp),"|1"); if ((!expect_repeat) && (repcheck)) { event_error("found |1 in non-repeat section"); }; break; case REP_BAR2: sprintf(tmp+strlen(tmp),":|2"); if ((!expect_repeat) && (repcheck)) { event_error("No repeat expected, found :|2"); }; expect_repeat = 0; break; case DOUBLE_REP: sprintf(tmp+strlen(tmp),"::"); if ((!expect_repeat) && (repcheck)) { event_error("No repeat expected, found ::"); }; expect_repeat = 1; break; }; if ((count.num*barlen.denom != barlen.num*count.denom) && (count.num != 0) && (barno != 0) && (barcheck)) { sprintf(msg, "Bar %d is %d/%d not %d/%d", barno, count.num, count.denom, barlen.num, barlen.denom ); event_error(msg); }; newabctext(barline); if ((type == DOUBLE_BAR) || (type == THIN_THICK) || (type == THICK_THIN) || (type == REP_BAR) || (type == DOUBLE_REP)) { tryout(0); }; barno = barno + 1; count.num = 0; count.denom = 1; } event_space() { if (!newspacing) { sprintf(tmp+strlen(tmp)," "); }; } event_graceon() { sprintf(tmp+strlen(tmp),"{"); ingrace = 1; } event_graceoff() { sprintf(tmp+strlen(tmp),"}"); ingrace = 0; } event_rep1() { sprintf(tmp+strlen(tmp)," [1"); } event_rep2() { sprintf(tmp+strlen(tmp)," [2"); } event_broken(type, n) int type, n; { int i; if (type == GT) { for (i=0; i"); } else { for (i=0; i= 0) { roots = sharproots; bases = sharpbases; } else { roots = flatroots; bases = flatbases; }; p = s; if ((*p >= 'A') && (*p <= 'G')) { pitch = (offset[(int) *p - ((int) 'A')] + transpose)%12; p = p + 1; if (*p == 'b') { pitch = pitch - 1; p = p + 1; }; if (*p == '#') { pitch = pitch + 1; p = p + 1; }; if (pitch < 0) pitch = pitch + 12; strcpy(newchord, roots[pitch]); strcpy(newchord + strlen(newchord), p); } else { if ((*p >= 'a') && (*p <= 'g')) { pitch = (offset[(int) *p - ((int) 'a')] + transpose)%12; p = p + 1; if (*p == 'b') { pitch = pitch - 1; p = p + 1; }; if (*p == '#') { pitch = pitch + 1; p = p + 1; }; if (pitch < 0) pitch = pitch + 12; strcpy(newchord, bases[pitch]); strcpy(newchord + strlen(newchord), p); } else { strcpy(newchord, p); }; }; }; sprintf(tmp+strlen(tmp),"\"%s\"", newchord); } event_gchord(s) char* s; { splitstring(s, ';', event_handle_gchord); } event_instruction(s) char* s; { sprintf(tmp+strlen(tmp),"!%s!", s); } event_slur(t) int t; { if (cleanup) { if (t) { sprintf(tmp+strlen(tmp),"("); } else { sprintf(tmp+strlen(tmp),")"); }; } else { sprintf(tmp+strlen(tmp),"s"); }; } event_sluron(t) int t; { sprintf(tmp+strlen(tmp),"("); } event_sluroff(t) int t; { sprintf(tmp+strlen(tmp),")"); } event_tie() { sprintf(tmp+strlen(tmp),"-"); } event_lineend(ch, n) char ch; int n; { int i; if (!newbreaks) { for (i = 0; i 0) { accidental = '^'; mult = acc; }; if (acc < 0) { accidental = '_'; mult = -acc; }; }; }; notecount = notecount + 1; for (t=0; t= 1) { sprintf(tmp+strlen(tmp),"%c", note); t = octave; while (t > 1) { sprintf(tmp+strlen(tmp),"'"); t = t - 1; }; } else { sprintf(tmp+strlen(tmp),"%c", (char) ((int)note + 'C' - 'c')); t = octave; while (t < 0) { sprintf(tmp+strlen(tmp),","); t = t + 1; }; }; printlen(n, m); if (inchord) { chordcount = chordcount + 1; }; if ((!ingrace) && (!inchord || (chordcount == 1))) { if (tuplenotes == 0) { addunits(n, m); } else { addunits(n*tuplefactor.num, m*tuplefactor.denom); tuplenotes = tuplenotes - 1; }; }; if (newspacing) { barpoint.num = count.num * breakpoint.denom; barpoint.denom = breakpoint.num * count.denom; reduce(&barpoint.num, &barpoint.denom); if ((barpoint.denom == 1) && (barpoint.num != 0) && (barpoint.num != barend)) { sprintf(tmp+strlen(tmp)," "); }; }; } reduce(a, b) int *a, *b; { int t, n, m; /* find HCF using Euclid's algorithm */ if (*a > *b) { n = *a; m = *b; } else { n = *b; m = *a; }; while (m != 0) { t = n % m; n = m; m = t; }; *a = *a/n; *b = *b/n; } addunits(n, m) int n, m; { count.num = n*count.denom + count.num*(m*unitlen.denom); count.denom = (m*unitlen.denom)*count.denom; reduce(&count.num, &count.denom); }