--- abcmidi-20070318.orig/store.c +++ abcmidi-20070318/store.c @@ -65,7 +65,7 @@ #define strchr index #endif -#ifdef ANSILIBS +#if defined(ANSILIBS) || defined(__STDC__) #include #include #include @@ -73,7 +73,7 @@ extern char* strchr(); extern void reduce(); #endif -/*int snprintf(char *str, size_t size, const char *format, ...);*/ +int snprintf(char *str, size_t size, const char *format, ...); #define MAXLINE 500 @@ -1767,7 +1767,7 @@ int i, j; int stackptr; char* stack[10]; - char lastch; + char lastch = 0; stackptr = 0; in = spec; @@ -2103,7 +2103,8 @@ }; } - +/* This function is never actually used */ +#if 0 static void slurtotie() /* converts a pair of identical slurred notes to tied notes */ { @@ -2158,6 +2159,7 @@ }; }; } +#endif void event_sluron(t) /* called when ( is encountered in the abc */ @@ -2295,6 +2297,8 @@ }; } +/* This function is never actually used. */ +#if 0 static void applybroken(place, type, n) int place, type, n; /* adjust lengths of broken notes */ @@ -2424,6 +2428,7 @@ }; }; } +#endif static void brokenadjust() /* adjust lengths of broken notes */ @@ -2433,6 +2438,8 @@ int failed; switch(v->brokenmult) { + default: + event_error("unknown type of broken rhythm"); case 1: num1 = ratio_b; num2 = ratio_a; @@ -3540,7 +3547,7 @@ { int j; int inchord; - int chord_num, chord_denom; + int chord_num = 1, chord_denom = 1; int chord_start,chord_end; int voiceno; @@ -3586,14 +3593,14 @@ j = j + 1; break; case TIE: -/* +#if 0 if (chord_end+1 == j) { /* did a TIE connect with a chord */ /* removefeature(j); - patchup and backtrack/ + patchup and backtrack */ j = patchup_chordtie(chord_start,chord_end); inchord=1; } -*/ +#endif dotie(j, inchord,voiceno); j = j + 1; break; @@ -3632,7 +3639,6 @@ */ { int start, end, p; - int next_num, next_denom; int fact_num, fact_denom; int grace_num, grace_denom; int j; @@ -3690,6 +3696,7 @@ if (hostnotestart == -1) { event_error("No note found to follow grace notes"); } else { + int next_num = 1, next_denom = 1; /* count up grace units */ grace_num = 0; grace_denom = 1; @@ -3934,7 +3941,8 @@ } } - +/* This function is never actually used */ +#if 0 static void delendrep(j) int j; /* remove bogus repeat */ @@ -3953,6 +3961,7 @@ break; }; } +#endif static void placeendrep(j) /* patch up missing repeat */ @@ -4010,7 +4019,7 @@ /* This can be converted to |: if necessary. */ { int j; - int rep_point; /* where to assume a repeat starts */ + int rep_point = 0; /* where to assume a repeat starts */ int expect_repeat; /* = 1 after |: or :: otherwise 0*/ int use_next; /* if 1 set next bar line as ref_point */ int nplays; /* counts PLAY_ON_REP associated with a BAR_REP*/ --- abcmidi-20070318.orig/position.c +++ abcmidi-20070318/position.c @@ -1,495 +1,495 @@ -/* - * yaps - program to convert abc files to PostScript. - * Copyright (C) 1999 James Allwright - * e-mail: J.R.Allwright@westminster.ac.uk - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -/* position.c */ -/* part of YAPS - abc to PostScript converter */ -/* This file contains routines to calculate symbol positions within */ -/* a line of music. */ - -/* for Microsoft Visual C++ 6.0 and higher */ -#ifdef _MSC_VER -#define ANSILIBS -#endif - -#include -#ifdef ANSILIBS -#include -#endif -#include "abc.h" -#include "structs.h" -#include "sizes.h" - -extern struct tune thetune; -extern double scaledwidth; - -static void addfract(f, n, m) -struct fract* f; -int n, m; -/* add n/m to fraction pointed to by f */ -/* like addunits(), but does not use unitlength */ -{ - f->num = n*f->denom + m*f->num; - f->denom = m*f->denom; - reducef(f); -} - -static void mulfract(f, n, m) -struct fract* f; -int n, m; -/* multiply n/m to fraction pointed to by f */ -/* like addunits(), but does not use unitlength */ -{ - f->num = n*f->num; - f->denom = m*f->denom; - reducef(f); -} - -static void advance(struct voice* v, int phase, int* items, double* itemspace, double x) -/* move on one symbol in the specified voice */ -{ - struct feature* p; - struct rest* arest; - struct note* anote; - struct fract tuplefactor, notelen; - int done; - int stepon; - int zerotime, newline; - - switch(phase) { - case 1: - zerotime = 1; - newline=0; - break; - case 2: - zerotime = 0; - newline=0; - break; - case 3: - zerotime = 0; - newline=1; - break; - default: - printf("Internal error: phase = %d\n", phase); - exit(1); - break; - }; - - *itemspace = 0.0; - *items = 0; - p = v->place; - if (p == NULL) { - v->atlineend = 1; - }; - done = 0; - while ((p != NULL) && (done==0)) { - p->x = (float) (x + p->xleft); - stepon = 1; - switch(p->type) { - case MUSICLINE: - v->inmusic = 1; - break; - case PRINTLINE: - v->inmusic = 0; - done = 1; - if (!newline) { - v->atlineend = 1; - stepon = 0; - }; - break; - case CLEF: - case KEY: - case TIME: - if (!v->inmusic) { - break; - }; - case SINGLE_BAR: - case DOUBLE_BAR: - case BAR_REP: - case REP_BAR: - case BAR1: - case REP_BAR2: - case DOUBLE_REP: - case THICK_THIN: - case THIN_THICK: - *itemspace = *itemspace + p->xleft + p->xright; - *items = *items + 1; - if (!newline) { - done = 1; - }; - break; - case REST: - case NOTE: - tuplefactor = v->tuplefactor; - if ((zerotime==1) && (!v->ingrace)) { - done = 1; - stepon = 0; - } else { - if ((!v->inchord)&&(!newline)) { - done = 1; - }; - *itemspace = *itemspace + p->xleft + p->xright; - *items = *items + 1; - if (p->type == REST) { - arest = p->item; - addfract(&v->time, arest->len.num, arest->len.denom); - }; - if ((p->type == NOTE) && (!v->ingrace)) { - anote = p->item; - notelen = anote->len; - - if (anote->tuplenotes >0) { - mulfract(¬elen,tuplefactor.num,tuplefactor.denom); - } - - - addfract(&v->time, notelen.num, notelen.denom); -/* printf("%c %d/%d %d/%d\n",anote->pitch,notelen.num,notelen.denom, - v->time.num,v->time.denom); -*/ - }; - }; - break; - case CHORDON: - if ((zerotime==1)&&(!v->ingrace)) { - done = 1; - stepon = 0; - } else { - v->inchord = 1; - }; - break; - case CHORDOFF: - if (v->inchord == 1) { - v->inchord = 0; - if ((!v->ingrace)&&(!newline)) { - done = 1; - }; - }; - break; - case GRACEON: - v->ingrace = 1; - break; - case GRACEOFF: - v->ingrace = 0; - break; - default: - break; - }; - if (stepon) { - p = p->next; - } else { - done = 1; - }; - }; - v->place = p; - if (p == NULL) { - v->atlineend = 1; - }; -} - -static int gefract(struct fract* a, struct fract* b) -/* compare two fractions a greater than or equal to b */ -/* returns (a >= b) */ -{ - if ((a->num*b->denom) >= (b->num*a->denom)) { - return(1); - } else { - return(0); - }; -} - -static int gtfract(struct fract* a, struct fract* b) -/* compare two fractions a greater than b */ -/* returns (a > b) */ -{ - if ((a->num*b->denom) > (b->num*a->denom)) { - return(1); - } else { - return(0); - }; -} - -static int spacemultiline(struct fract* mastertime, struct tune* t) -/* calculate spacing for one line (but possibly multiple voices) */ -{ - int i; - int items, thisitems, maxitems; - int totalitems; - double thiswidth, maxwidth; - double totalwidth; - double x, gap; - int done; - struct voice* v; - struct fract minlen; - - /* two passes - on the second pass, inter-symbol spacing is */ - /* known so elements can be given their correct x position */ - gap = 0.0; - for (i=0; i<2; i++) { - setfract(mastertime, 0, 1); - v = firstitem(&t->voices); - while (v != NULL) { - v->place = v->lineplace; - v->ingrace = 0; - v->atlineend = 0; - setfract(&v->time, 0, 1); - v = nextitem(&t->voices); - }; - done = 0; - items = 0; - x = 0.0; - totalitems = 0; - totalwidth = 0.0; - /* count up items in a line */ - while (done == 0) { - maxitems = 0; - maxwidth = 0.0; - /* first do zero-time symbols */ - v = firstitem(&t->voices); - while (v != NULL) { - if ((!v->atlineend)&&(gefract(mastertime, &v->time))) { - advance(v, 1, &thisitems, &thiswidth, x); - if (thisitems > maxitems) { - maxitems = thisitems; - }; - if (thiswidth > maxwidth) { - maxwidth = thiswidth; - }; - }; - v = nextitem(&t->voices); - }; - if (maxitems == 0) { - /* now try moving forward in time */ - /* advance all voices at or before mastertime */ - v = firstitem(&t->voices); - while (v != NULL) { - if ((!v->atlineend)&&(gefract(mastertime, &v->time))) { - advance(v, 2, &thisitems, &thiswidth, x); - if (thisitems > maxitems) { - maxitems = thisitems; - }; - if (thiswidth > maxwidth) { - maxwidth = thiswidth; - }; - }; - v = nextitem(&t->voices); - }; - /* calculate new mastertime */ - v = firstitem(&t->voices); - setfract(&minlen, 0, 1); - done = 1; - while (v != NULL) { - if (!v->atlineend) { - done = 0; - if (minlen.num == 0) { - setfract(&minlen, v->time.num, v->time.denom); - } else { - if (gtfract(&minlen, &v->time)) { - setfract(&minlen, v->time.num, v->time.denom); - }; - }; - }; - v = nextitem(&t->voices); - }; - setfract(mastertime, minlen.num, minlen.denom); - }; - totalitems = totalitems + maxitems; - totalwidth = totalwidth + maxwidth; - if (maxitems > 0) { - x = x + maxwidth + gap; - }; - }; - /* now calculate inter-symbol gap */ - if (totalitems > 1) { - gap = (scaledwidth - totalwidth)/(totalitems-1); - } else { - gap = 1.0; - }; - if (gap < 0.0) { - event_error("Overfull music line"); - }; - if (gap > MAXGAP) { - event_error("Underfull music line"); - gap = MAXGAP; - }; - }; - if (totalitems == 0) { - return(1); - } else { - return(0); - }; -} - -void spacevoices(struct tune* t) -{ - struct fract mastertime; - int donelines; - struct voice* v; - int items; - double x1; - - /* initialize voices */ - v = firstitem(&t->voices); - while (v != NULL) { - v->lineplace = v->first; - v->inmusic=0; - v = nextitem(&t->voices); - }; - donelines = 0; - while(donelines == 0) { - donelines = spacemultiline(&mastertime, t); - v = firstitem(&t->voices); - while (v != NULL) { - v->lineplace = v->place; - advance(v, 3, &items, &x1, 0.0); - v->lineplace = v->place; - v = nextitem(&t->voices); - }; - }; -} - -static int spaceline(struct voice* v) -/* allocate spare space across the width of a single stave line */ -/* thereby fixing the x position of all notes and other elements */ -/* returns 0 when the end of the voice is reached, 1 otherwise */ -{ - struct feature* p; - double x, lastx; - int inmusic, items; - double itemspace; - double gap; - - itemspace = 0.0; - items = 0; - inmusic = 0; - p = v->place; - while ((p != NULL) && (p->type != PRINTLINE)) { - switch(p->type) { - case MUSICLINE: - inmusic = 1; - break; - case PRINTLINE: - inmusic = 0; - break; - case CLEF: - case KEY: - case TIME: - if (!inmusic) { - break; - }; - case SINGLE_BAR: - case DOUBLE_BAR: - case BAR_REP: - case REP_BAR: - case BAR1: - case REP_BAR2: - case DOUBLE_REP: - case THICK_THIN: - case THIN_THICK: - case REST: - case NOTE: - itemspace = itemspace + p->xleft + p->xright; - items = items + 1; - break; - default: - break; - }; - p = p->next; - }; - if (items > 1) { - gap = (scaledwidth - itemspace)/((double)(items-1)); - } else { - gap = 1.0; - }; - if (gap < 0.0) { - event_error("Overfull music line"); - }; - if (gap > MAXGAP) { - event_error("Underfull music line"); - gap = MAXGAP; - }; - /* now assign positions */ - x = 0.0; - p = v->place; - inmusic = 0; - while ((p != NULL) && (p->type != PRINTLINE)) { - switch(p->type) { - case MUSICLINE: - inmusic = 1; - break; - case PRINTLINE: - inmusic = 0; - break; - case CHORDNOTE: - p->x = (float) lastx; - break; - case CLEF: - case KEY: - case TIME: - if (!inmusic) { - break; - }; - case SINGLE_BAR: - case DOUBLE_BAR: - case BAR_REP: - case REP_BAR: - case BAR1: - case REP_BAR2: - case DOUBLE_REP: - case THICK_THIN: - case THIN_THICK: - case REST: - case NOTE: - x = x + p->xleft; - p->x = (float) x; - lastx = x; - x = x + p->xright + gap; - break; - default: - break; - }; - p = p->next; - }; - while ((p!=NULL)&&((p->type == PRINTLINE)||(p->type==LINENUM))) { - p = p->next; - }; - v->place = p; - if (p == NULL) { - return(0); - } else { - return(1); - }; -} - -void monospace(struct tune* t) -{ - int doneline; - struct voice* v; - - v = firstitem(&t->voices); - while (v != NULL) { - doneline = 1; - v->place = v->first; - while (doneline == 1) { - doneline = spaceline(v); - }; - v = nextitem(&t->voices); - }; -} +/* + * yaps - program to convert abc files to PostScript. + * Copyright (C) 1999 James Allwright + * e-mail: J.R.Allwright@westminster.ac.uk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* position.c */ +/* part of YAPS - abc to PostScript converter */ +/* This file contains routines to calculate symbol positions within */ +/* a line of music. */ + +/* for Microsoft Visual C++ 6.0 and higher */ +#ifdef _MSC_VER +#define ANSILIBS +#endif + +#include +#if defined(ANSILIBS) || defined(__STDC__) +#include +#endif +#include "abc.h" +#include "structs.h" +#include "sizes.h" + +extern struct tune thetune; +extern double scaledwidth; + +static void addfract(f, n, m) +struct fract* f; +int n, m; +/* add n/m to fraction pointed to by f */ +/* like addunits(), but does not use unitlength */ +{ + f->num = n*f->denom + m*f->num; + f->denom = m*f->denom; + reducef(f); +} + +static void mulfract(f, n, m) +struct fract* f; +int n, m; +/* multiply n/m to fraction pointed to by f */ +/* like addunits(), but does not use unitlength */ +{ + f->num = n*f->num; + f->denom = m*f->denom; + reducef(f); +} + +static void advance(struct voice* v, int phase, int* items, double* itemspace, double x) +/* move on one symbol in the specified voice */ +{ + struct feature* p; + struct rest* arest; + struct note* anote; + struct fract tuplefactor, notelen; + int done; + int stepon; + int zerotime, newline; + + switch(phase) { + case 1: + zerotime = 1; + newline=0; + break; + case 2: + zerotime = 0; + newline=0; + break; + case 3: + zerotime = 0; + newline=1; + break; + default: + printf("Internal error: phase = %d\n", phase); + exit(1); + break; + }; + + *itemspace = 0.0; + *items = 0; + p = v->place; + if (p == NULL) { + v->atlineend = 1; + }; + done = 0; + while ((p != NULL) && (done==0)) { + p->x = (float) (x + p->xleft); + stepon = 1; + switch(p->type) { + case MUSICLINE: + v->inmusic = 1; + break; + case PRINTLINE: + v->inmusic = 0; + done = 1; + if (!newline) { + v->atlineend = 1; + stepon = 0; + }; + break; + case CLEF: + case KEY: + case TIME: + if (!v->inmusic) { + break; + }; + case SINGLE_BAR: + case DOUBLE_BAR: + case BAR_REP: + case REP_BAR: + case BAR1: + case REP_BAR2: + case DOUBLE_REP: + case THICK_THIN: + case THIN_THICK: + *itemspace = *itemspace + p->xleft + p->xright; + *items = *items + 1; + if (!newline) { + done = 1; + }; + break; + case REST: + case NOTE: + tuplefactor = v->tuplefactor; + if ((zerotime==1) && (!v->ingrace)) { + done = 1; + stepon = 0; + } else { + if ((!v->inchord)&&(!newline)) { + done = 1; + }; + *itemspace = *itemspace + p->xleft + p->xright; + *items = *items + 1; + if (p->type == REST) { + arest = p->item; + addfract(&v->time, arest->len.num, arest->len.denom); + }; + if ((p->type == NOTE) && (!v->ingrace)) { + anote = p->item; + notelen = anote->len; + + if (anote->tuplenotes >0) { + mulfract(¬elen,tuplefactor.num,tuplefactor.denom); + } + + + addfract(&v->time, notelen.num, notelen.denom); +/* printf("%c %d/%d %d/%d\n",anote->pitch,notelen.num,notelen.denom, + v->time.num,v->time.denom); +*/ + }; + }; + break; + case CHORDON: + if ((zerotime==1)&&(!v->ingrace)) { + done = 1; + stepon = 0; + } else { + v->inchord = 1; + }; + break; + case CHORDOFF: + if (v->inchord == 1) { + v->inchord = 0; + if ((!v->ingrace)&&(!newline)) { + done = 1; + }; + }; + break; + case GRACEON: + v->ingrace = 1; + break; + case GRACEOFF: + v->ingrace = 0; + break; + default: + break; + }; + if (stepon) { + p = p->next; + } else { + done = 1; + }; + }; + v->place = p; + if (p == NULL) { + v->atlineend = 1; + }; +} + +static int gefract(struct fract* a, struct fract* b) +/* compare two fractions a greater than or equal to b */ +/* returns (a >= b) */ +{ + if ((a->num*b->denom) >= (b->num*a->denom)) { + return(1); + } else { + return(0); + }; +} + +static int gtfract(struct fract* a, struct fract* b) +/* compare two fractions a greater than b */ +/* returns (a > b) */ +{ + if ((a->num*b->denom) > (b->num*a->denom)) { + return(1); + } else { + return(0); + }; +} + +static int spacemultiline(struct fract* mastertime, struct tune* t) +/* calculate spacing for one line (but possibly multiple voices) */ +{ + int i; + int items, thisitems, maxitems; + int totalitems; + double thiswidth, maxwidth; + double totalwidth; + double x, gap; + int done; + struct voice* v; + struct fract minlen; + + /* two passes - on the second pass, inter-symbol spacing is */ + /* known so elements can be given their correct x position */ + gap = 0.0; + for (i=0; i<2; i++) { + setfract(mastertime, 0, 1); + v = firstitem(&t->voices); + while (v != NULL) { + v->place = v->lineplace; + v->ingrace = 0; + v->atlineend = 0; + setfract(&v->time, 0, 1); + v = nextitem(&t->voices); + }; + done = 0; + items = 0; + x = 0.0; + totalitems = 0; + totalwidth = 0.0; + /* count up items in a line */ + while (done == 0) { + maxitems = 0; + maxwidth = 0.0; + /* first do zero-time symbols */ + v = firstitem(&t->voices); + while (v != NULL) { + if ((!v->atlineend)&&(gefract(mastertime, &v->time))) { + advance(v, 1, &thisitems, &thiswidth, x); + if (thisitems > maxitems) { + maxitems = thisitems; + }; + if (thiswidth > maxwidth) { + maxwidth = thiswidth; + }; + }; + v = nextitem(&t->voices); + }; + if (maxitems == 0) { + /* now try moving forward in time */ + /* advance all voices at or before mastertime */ + v = firstitem(&t->voices); + while (v != NULL) { + if ((!v->atlineend)&&(gefract(mastertime, &v->time))) { + advance(v, 2, &thisitems, &thiswidth, x); + if (thisitems > maxitems) { + maxitems = thisitems; + }; + if (thiswidth > maxwidth) { + maxwidth = thiswidth; + }; + }; + v = nextitem(&t->voices); + }; + /* calculate new mastertime */ + v = firstitem(&t->voices); + setfract(&minlen, 0, 1); + done = 1; + while (v != NULL) { + if (!v->atlineend) { + done = 0; + if (minlen.num == 0) { + setfract(&minlen, v->time.num, v->time.denom); + } else { + if (gtfract(&minlen, &v->time)) { + setfract(&minlen, v->time.num, v->time.denom); + }; + }; + }; + v = nextitem(&t->voices); + }; + setfract(mastertime, minlen.num, minlen.denom); + }; + totalitems = totalitems + maxitems; + totalwidth = totalwidth + maxwidth; + if (maxitems > 0) { + x = x + maxwidth + gap; + }; + }; + /* now calculate inter-symbol gap */ + if (totalitems > 1) { + gap = (scaledwidth - totalwidth)/(totalitems-1); + } else { + gap = 1.0; + }; + if (gap < 0.0) { + event_error("Overfull music line"); + }; + if (gap > MAXGAP) { + event_error("Underfull music line"); + gap = MAXGAP; + }; + }; + if (totalitems == 0) { + return(1); + } else { + return(0); + }; +} + +void spacevoices(struct tune* t) +{ + struct fract mastertime; + int donelines; + struct voice* v; + int items; + double x1; + + /* initialize voices */ + v = firstitem(&t->voices); + while (v != NULL) { + v->lineplace = v->first; + v->inmusic=0; + v = nextitem(&t->voices); + }; + donelines = 0; + while(donelines == 0) { + donelines = spacemultiline(&mastertime, t); + v = firstitem(&t->voices); + while (v != NULL) { + v->lineplace = v->place; + advance(v, 3, &items, &x1, 0.0); + v->lineplace = v->place; + v = nextitem(&t->voices); + }; + }; +} + +static int spaceline(struct voice* v) +/* allocate spare space across the width of a single stave line */ +/* thereby fixing the x position of all notes and other elements */ +/* returns 0 when the end of the voice is reached, 1 otherwise */ +{ + struct feature* p; + double x, lastx = 0.0; + int inmusic, items; + double itemspace; + double gap; + + itemspace = 0.0; + items = 0; + inmusic = 0; + p = v->place; + while ((p != NULL) && (p->type != PRINTLINE)) { + switch(p->type) { + case MUSICLINE: + inmusic = 1; + break; + case PRINTLINE: + inmusic = 0; + break; + case CLEF: + case KEY: + case TIME: + if (!inmusic) { + break; + }; + case SINGLE_BAR: + case DOUBLE_BAR: + case BAR_REP: + case REP_BAR: + case BAR1: + case REP_BAR2: + case DOUBLE_REP: + case THICK_THIN: + case THIN_THICK: + case REST: + case NOTE: + itemspace = itemspace + p->xleft + p->xright; + items = items + 1; + break; + default: + break; + }; + p = p->next; + }; + if (items > 1) { + gap = (scaledwidth - itemspace)/((double)(items-1)); + } else { + gap = 1.0; + }; + if (gap < 0.0) { + event_error("Overfull music line"); + }; + if (gap > MAXGAP) { + event_error("Underfull music line"); + gap = MAXGAP; + }; + /* now assign positions */ + x = 0.0; + p = v->place; + inmusic = 0; + while ((p != NULL) && (p->type != PRINTLINE)) { + switch(p->type) { + case MUSICLINE: + inmusic = 1; + break; + case PRINTLINE: + inmusic = 0; + break; + case CHORDNOTE: + p->x = (float) lastx; + break; + case CLEF: + case KEY: + case TIME: + if (!inmusic) { + break; + }; + case SINGLE_BAR: + case DOUBLE_BAR: + case BAR_REP: + case REP_BAR: + case BAR1: + case REP_BAR2: + case DOUBLE_REP: + case THICK_THIN: + case THIN_THICK: + case REST: + case NOTE: + x = x + p->xleft; + p->x = (float) x; + lastx = x; + x = x + p->xright + gap; + break; + default: + break; + }; + p = p->next; + }; + while ((p!=NULL)&&((p->type == PRINTLINE)||(p->type==LINENUM))) { + p = p->next; + }; + v->place = p; + if (p == NULL) { + return(0); + } else { + return(1); + }; +} + +void monospace(struct tune* t) +{ + int doneline; + struct voice* v; + + v = firstitem(&t->voices); + while (v != NULL) { + doneline = 1; + v->place = v->first; + while (doneline == 1) { + doneline = spaceline(v); + }; + v = nextitem(&t->voices); + }; +} --- abcmidi-20070318.orig/midifile.h +++ abcmidi-20070318/midifile.h @@ -34,26 +34,10 @@ long mf_sec2ticks(); void mfwrite(); void mfread(); -static int readtrack(); int mf_write_meta_event(); int mf_write_midi_event(); void mf_write_tempo(); -static void readheader(); void mferror(); -static void badbyte(); -static void metaevent(); -static void sysex(); -static void chanmessage(); -static void msginit(); -static void msgadd(); -static void biggermsg(); -static void mf_write_track_chunk(); -static void mf_write_header_chunk(); -static void WriteVarLen(); -static void write32bit(); -static void write16bit(); -static int msgleng(); -static int eputc(); /* MIDI status commands most significant bit is 1 */ #define note_off 0x80 --- abcmidi-20070318.orig/genmidi.c +++ abcmidi-20070318/genmidi.c @@ -39,15 +39,15 @@ #include "genmidi.h" #include "midifile.h" #include -#ifdef ANSILIBS +#if defined(ANSILIBS) || defined(__STDC__) #include #include +#include #endif /* define USE_INDEX if your C libraries have index() instead of strchr() */ #ifdef USE_INDEX #define strchr index #endif -#include void single_note_tuning_change(int midikey, float midipitch); void addfract(int *xnum, int *xdenom, int a, int b); --- abcmidi-20070318.orig/makefiles/unix.mak +++ abcmidi-20070318/makefiles/unix.mak @@ -111,7 +111,7 @@ matchsup.o : matchsup.c abc.h parseabc.h parser2.h clean : - rm *.o ${binaries} + rm -f *.o ${binaries} install: abc2midi midi2abc abc2abc mftext midicopy yaps abcmatch $(INSTALL) -m 755 ${binaries} ${prefix}/${bindir} --- abcmidi-20070318.orig/parseabc.c +++ abcmidi-20070318/parseabc.c @@ -59,7 +59,7 @@ #define strchr index #endif -#ifdef ANSILIBS +#if defined(ANSILIBS) || defined(__STDC__) #include #include #include --- abcmidi-20070318.orig/matchsup.c +++ abcmidi-20070318/matchsup.c @@ -1,1964 +1,1966 @@ -/* - matchsup.c (abcmatch support functions) - Seymour Shlien - - - - - * originally store.c - * abc2midi - program to convert abc files to MIDI files. - * Copyright (C) 1999 James Allwright - * e-mail: J.R.Allwright@westminster.ac.uk - -store.c was adapted for the purpose of analyzing the contents -of abc tunes. The code is much the same except many functions -related to the generation of midi files has been trimmed off. -In particular: links to the code in genmidi.c and queue.c are gone. -All the gchord stuff is removed. There are options to suppress -all warning and error messages. Certain variables are no longer -extern's (parts, partno, bar_num, global_transpose etc.). -Output file generation stuff is gone. A new variable xrefno is -added to pass the reference number to abcmatch. Event_init has -been moved to the main program abcmatch.c and maxnotes has -been raised to 3000 since there seems to be a problem with -the autoextend procedure. Some DEBUG statements were -added to addfeature - (they can probably be removed). Support -for text features and comments are gone. All the karaoke stuff -is gone. Tempo stuff, slurs, grace notes, decorations, hornpipe -indications are all ignored. Event_note was changed to ignore -trills and rolls. When a [chord] is included, only the highest -note is extracted from the chord. For debugging, a new function -print_feature_list was introduced.etc. - -Essentially for comparing abc files, we want to ignore repeats, -grace notes, staccato indications and midi indications. We are -only interested in comparing the tunes. The main output -which is used is the feature[],pitch,num[],denom[] list which -is used by abcmatch to create a new representation of the abc -file. - -Some abc files with interleaved voices will not be treated -propertly with this program. In general parts, repeats and -voice indications are ignored. - - - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - - -#define XTEN1 1 - -#include "abc.h" -#include "parseabc.h" -#include "parser2.h" -#include -#include - -#ifdef __MWERKS__ -#define __MACINTOSH__ 1 -#endif /* __MWERKS__ */ - -#ifdef __MACINTOSH__ -int setOutFileCreator(char *fileName,unsigned long theType, - unsigned long theCreator); -#endif /* __MACINTOSH__ */ -/* define USE_INDEX if your C libraries have index() instead of strchr() */ -#ifdef USE_INDEX -#define strchr index -#endif - -#ifdef ANSILIBS -#include -#include -#include -#else -extern char* strchr(); -extern void reduce(); -#endif - -#define MAXLINE 500 -#define INITTEXTS 20 -#define INITWORDS 20 -#define MAXCHANS 16 - -/*#define DEBUG*/ - - -/* global variables grouped roughly by function */ - -FILE *fp; - -programname fileprogram = ABCMATCH; - - -/* parsing stage */ -int tuplecount, tfact_num, tfact_denom, tnote_num, tnote_denom; -int specialtuple; -int gracenotes; -int headerpartlabel; -int dotune, pastheader; -int hornpipe, last_num, last_denom; -int timesigset; -int retain_accidentals; -int ratio_a, ratio_b; - -struct voicecontext { - /* maps of accidentals for each stave line */ - char basemap[7], workmap[7]; - int basemul[7], workmul[7]; - int default_length; - int voiceno; - int indexno; - int hasgchords; - int haswords; - int inslur; - int ingrace; - int octaveshift; - /* chord handling */ - int inchord, chordcount; - int chord_num, chord_denom; - /* details of last 2 notes/chords to apply length-modifiers to */ - int laststart, lastend, thisstart, thisend; - /* broken rythm handling */ - int brokentype, brokenmult, brokenpending; - int broken_stack[7]; - struct voicecontext* next; -}; -struct voicecontext global; -struct voicecontext* v; -struct voicecontext* head; -int voicecount; - -/* storage structure for strings */ -int maxtexts = INITTEXTS; -char** atext; -int ntexts = 0; - -int note_unit_length=8; - -/* general purpose storage structure */ -int maxnotes; -int *pitch, *num, *denom; -featuretype *feature; -int *pitchline; -int notes; - -int verbose = 0; -int nowarn=1; -int noerror=1; -int xmatch; -int sf, mi; - -/* Part handling */ -struct vstring part; -int parts, partno, partlabel; -int part_start[26], part_count[26]; - -int voicesused; - -/* Tempo handling (Q: field) */ -int time_num, time_denom; -long tempo; -int tempo_num, tempo_denom; -int relative_tempo, Qtempo; -extern int division; -extern int div_factor; - -/* output file generation */ -int check; -int ntracks; - -/* bar length checking */ -int bar_num, bar_denom; -int barchecking; -int beat; - -/* generating MIDI output */ -int middle_c; -extern int channels[MAXCHANS + 3]; - -int global_transpose; - -int additive; -int gfact_num, gfact_denom; - -/* karaoke handling */ -int karaoke, wcount; -char** words; -int maxwords = INITWORDS; -int xrefno; - -extern int intune; /* signals to parsetune that tune is finished */ - -/* Many of these functions have been retained in order to link with parseabc. -As I have been forced to also modifiy parseabc, now called abcparse, these -functions can also be removed eventually. - */ - -char *featname[] = { -"SINGLE_BAR", "DOUBLE_BAR", "BAR_REP", "REP_BAR", -"PLAY_ON_REP", "REP1", "REP2", "BAR1", -"REP_BAR2", "DOUBLE_REP", "THICK_THIN", "THIN_THICK", -"PART", "TEMPO", "TIME", "KEY", -"REST", "TUPLE", "NOTE", "NONOTE", -"OLDTIE", "TEXT", "SLUR_ON", "SLUR_OFF", -"TIE", "CLOSE_TIE", "TITLE", "CHANNEL", -"TRANSPOSE", "RTRANSPOSE", "GTRANSPOSE", "GRACEON", -"GRACEOFF", "SETGRACE", "SETC", "SETTRIM", "GCHORD", -"GCHORDON", "GCHORDOFF", "VOICE", "CHORDON", -"CHORDOFF", "CHORDOFFEX", "DRUMON", "DRUMOFF", -"DRONEON", "DRONEOFF", "SLUR_TIE", "TNOTE", -"LT", "GT", "DYNAMIC", "LINENUM", -"MUSICLINE", "MUSICSTOP", "WORDLINE", "WORDSTOP", -"INSTRUCTION", "NOBEAM", "CHORDNOTE", "CLEF", -"PRINTLINE", "NEWPAGE", "LEFT_TEXT", "CENTRE_TEXT", -"VSKIP", "COPYRIGHT", "COMPOSER", "ARPEGGIO", -"SPLITVOICE" -}; - - - -void event_info (place) -char * place; -{ -} - -void event_gchord (chord) -char * chord; -{ -} - -void event_slur (t) -int t; -{ -} - - -void event_instruction (s) -char *s; -{ -} - - -void event_reserved (p) -char p; -{ -} - -int bar_num, bar_denom, barno, barsize; -int b_num,b_denom; - -void reduce(a, b) -/* elimate common factors in fraction a/b */ -int *a, *b; -{ - int sign; - int t, n, m; - - if (*a < 0) { - sign = -1; - *a = -*a; - } else { - sign = 1; - }; - /* 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)*sign; - *b = *b/n; -} - -void addunits(a, b) -/* add a/b to the count of units in the bar */ -int a, b; -{ - bar_num = bar_num*(b*b_denom) + (a*b_num)*bar_denom; - bar_denom = bar_denom * (b*b_denom); - reduce(&bar_num, &bar_denom); -} - - -void set_meter(n, m) -/* set up variables associated with meter */ -int n, m; -{ - /* set up barsize */ - barsize = n; - if (barsize % 3 == 0) { - beat = 3; - } else { - if (barsize % 2 == 0) { - beat = 2; - } else { - beat = barsize; - }; - }; - /* correction factor to make sure we count in the right units */ - if (m > 4) { - b_num = m/4; - b_denom = 1; - } else { - b_num = 1; - b_denom = 4/m; - }; -} - -int dummydecorator[DECSIZE]; /* used in event_chord */ - - -static struct voicecontext* newvoice(n) -/* allocate and initialize the data for a new voice */ -int n; -{ - struct voicecontext *s; - int i; - - s = (struct voicecontext*) checkmalloc(sizeof(struct voicecontext)); - voicecount = voicecount + 1; - s->voiceno = n; - s->indexno = voicecount; - s->default_length = global.default_length; - s->hasgchords = 0; - s->haswords = 0; - s->inslur = 0; - s->ingrace = 0; - s->inchord = 0; - s->chordcount = 0; - s->laststart = -1; - s->lastend = -1; - s->thisstart = -1; - s->thisend = -1; - s->brokenpending = -1; - s->next = NULL; - for (i=0; i<7; i++) { - s->basemap[i] = global.basemap[i]; - s->basemul[i] = global.basemul[i]; - s->workmap[i] = global.workmap[i]; - s->workmul[i] = global.workmul[i]; - }; - s->octaveshift = global.octaveshift; - return(s); -} - -static struct voicecontext* getvoicecontext(n) -/* find the data structure for a given voice number */ -int n; -{ - struct voicecontext *p; - struct voicecontext *q; - - p = head; - q = NULL; - while ((p != NULL) && (p->voiceno != n)) { - q = p; - p = p->next; - }; - if (p == NULL) { - p = newvoice(n); - if (q != NULL) { - q->next = p; - }; - }; - if (head == NULL) { - head = p; - }; - return(p); -} - -static void clearvoicecontexts() -/* free up all the memory allocated to voices */ -{ - struct voicecontext *p; - struct voicecontext *q; - - p = head; - while (p != NULL) { - q = p->next; - free(p); - p = q; - }; - head = NULL; -} - - - - -void event_text(s) -/* text found in abc file */ -char *s; -{ -} - - -void event_specific (package, s) -char *package, *s; -{ -} - - -void event_x_reserved(p) -/* reserved character H-Z found in abc file */ -char p; -{ -} - -void event_abbreviation(symbol, string, container) -/* abbreviation encountered - this is handled within the parser */ -char symbol; -char *string; -char container; -{ -} - - -void event_acciaccatura() -{ -/* does nothing here but outputs a / in abc2abc */ -return; -} - -void event_split_voice() -{ -} - - - -void event_tex(s) -/* TeX command found - ignore it */ -char *s; -{ -} - -void event_fatal_error(s) -/* print error message and halt */ -char *s; -{ - event_error(s); - exit(1); -} - -void event_error(s) -/* generic error handler */ -char *s; -{ -if (noerror) return; -#ifdef NOFTELL - extern int nullpass; - - if (nullpass != 1) { - printf("Error in line %d : %s\n", lineno, s); - }; -#else - printf("Error in line %d : %s\n", lineno, s); -#endif -} - -void event_warning(s) -/* generic warning handler - for flagging possible errors */ -char *s; -{ -if (nowarn) return; -#ifdef NOFTELL - extern int nullpass; - - if (nullpass != 1) { - printf("Warning in line %d : %s\n", lineno, s); - }; -#else - printf("Warning in line %d : %s\n", lineno, s); -#endif -} - -static int autoextend(maxnotes) -/* increase the number of abc elements the program can cope with */ -int maxnotes; -{ - int newlimit; - int *ptr; - featuretype *fptr; - int i; - - if (verbose) { - event_warning("Extending note capacity"); - }; - newlimit = maxnotes*2; - fptr = (featuretype*) checkmalloc(newlimit*sizeof(featuretype)); - for(i=0;i= maxnotes) { - maxnotes = autoextend(maxnotes); - }; -} - -void event_linebreak() -/* reached end of line in abc */ -{ - addfeature(LINENUM, lineno, 0, 0); -} - -void event_startmusicline() -/* starting to parse line of abc music */ -{ - addfeature(MUSICLINE, 0, 0, 0); -} - -void event_endmusicline(endchar) -/* finished parsing line of abc music */ -char endchar; -{ - addfeature(MUSICSTOP, 0, 0, 0); -} - -static void textfeature(type, s) -/* called while parsing abc - stores an item which requires an */ -/* associared string */ -int type; -char* s; -{ -} - -void event_comment(s) -/* comment found in abc */ -char *s; -{ -} - - -void event_startinline() -/* start of in-line field in abc music line */ -{ -} - -void event_closeinline() -/* end of in-line field in abc music line */ -{ -} - -void event_field(k, f) -/* Handles R: T: and any other field not handled elsewhere */ -char k; -char *f; -{ - if (dotune) { - switch (k) { - case 'R': - { - char* p; - - p = f; - skipspace(&p); -/******** if ((strncmp(p, "Hornpipe", 8) == 0) || - (strncmp(p, "hornpipe", 8) == 0)) { - hornpipe = 1; - }; -********/ - }; - break; - default: - { - }; - }; - }; -} - -void event_words(p, continuation) -/* handles a w: field in the abc */ -char* p; -int continuation; -{ -} - - -static void checkbreak() -/* check that we are in not in chord, grace notes or tuple */ -/* called at voice change */ -{ - if (tuplecount != 0) { - event_error("Previous voice has an unfinished tuple"); - tuplecount = 0; - }; - if (v->inchord != 0) { - event_error("Previous voice has incomplete chord"); - event_chordoff(1,1); - }; - if (v->ingrace != 0) { - event_error("Previous voice has unfinished grace notes"); - v->ingrace = 0; - }; -} - - -static void read_spec(spec, part) -/* converts a P: field to a list of part labels */ -/* e.g. P:A(AB)3(CD)2 becomes P:AABABABCDCD */ -/* A '+' indicates 'additive' behaviour (a part may include repeats). */ -/* A '-' indicates 'non-additive' behaviour (repeat marks in the music */ -/* are ignored and only repeats implied by the part order statement */ -/* are played). */ -char spec[]; -struct vstring* part; -{ -} - -void event_part(s) -/* handles a P: field in the abc */ -char* s; -{ - char* p; - - if (dotune) { - p = s; - skipspace(&p); - if (pastheader) { - if (((int)*p < 'A') || ((int)*p > 'Z')) { - event_error("Part must be one of A-Z"); - return; - }; - if ((headerpartlabel == 1) && (part.st[0] == *p)) { - /* P: field in header is not a label */ - headerpartlabel = 0; - /* remove speculative part label */ - feature[part_start[(int)*p - (int)'A']] = NONOTE; - } else { - if (part_start[(int)*p - (int)'A'] != -1) { - event_error("Part defined more than once"); - }; - }; - part_start[(int)*p - (int)'A'] = notes; - addfeature(PART, (int)*p, 0, 0); - checkbreak(); - v = getvoicecontext(1); - } else { - parts = 0; - read_spec(p, &part); - if (parts == 1) { - /* might be a label not a specificaton */ - headerpartlabel = 1; - }; - }; - }; -} - -void event_voice(n, s, vp) -/* handles a V: field in the abc */ -int n; -char *s; -struct voice_params *vp; -{ - if (pastheader || XTEN1) { - voicesused = 1; - if (pastheader) checkbreak(); - v = getvoicecontext(n); - addfeature(VOICE, v->indexno, 0, 0); - if (vp->gotoctave) { - event_octave(vp->octave,1); - }; - if (vp->gottranspose) { - addfeature(TRANSPOSE, vp->transpose, 0, 0); - }; - } else { - event_warning("V: in header ignored"); - }; -} - - -void event_length(n) -/* handles an L: field in the abc */ -int n; -{ - note_unit_length = 8; - if (pastheader) { - v->default_length = n; - } else { - global.default_length = n; - }; -} - -static void tempounits(t_num, t_denom) -/* interprets Q: once default length is known */ -int *t_num, *t_denom; -{ -} - -void event_tempo(n, a, b, rel, pre, post) -/* handles a Q: field e.g. Q: a/b = n or Q: Ca/b = n */ -/* strings before and after are ignored */ -int n; -int a, b, rel; -char *pre; -char *post; -{ -} - - -void event_timesig(n, m, dochecking) -/* handles an M: field M:n/m */ -int n, m, dochecking; -{ - if (dotune) { - if (pastheader) { - addfeature(TIME, dochecking, n, m); - } else { - time_num = n; - time_denom = m; - timesigset = 1; - barchecking = dochecking; - }; - }; -} - -void event_octave(num, local) -/* used internally by other routines when octave=N is encountered */ -/* in I: or K: fields */ -int num; -{ - if (dotune) { - if (pastheader || local) { - v->octaveshift = num; - } else { - global.octaveshift = num; - }; - }; -} - -void event_info_key(key, value) -char* key; -char* value; -{ - int num; - - if (strcmp(key, "octave")==0) { - num = readsnumf(value); - event_octave(num,0); - }; -} - -static void stack_broken(v) -struct voicecontext* v; -{ - v->broken_stack[0] = v->laststart; - v->broken_stack[1] = v->lastend; - v->broken_stack[2] = v->thisstart; - v->broken_stack[3] = v->thisend; - v->broken_stack[4] = v->brokentype; - v->broken_stack[5] = v->brokenmult; - v->broken_stack[6] = v->brokenpending; - v->laststart = -1; - v->lastend = -1; - v->thisstart = -1; - v->thisend = -1; - v->brokenpending = -1; -} - -static void restore_broken(v) -struct voicecontext* v; -{ - if (v->brokenpending != -1) { - event_error("Unresolved broken rhythm in grace notes"); - }; - v->laststart = v->broken_stack[0]; - v->lastend = v->broken_stack[1]; - v->thisstart = v->broken_stack[2]; - v->thisend = v->broken_stack[3]; - v->brokentype = v->broken_stack[4]; - v->brokenmult = v->broken_stack[5]; - v->brokenpending = v->broken_stack[6]; -} - -void event_graceon() -/* a { in the abc */ -{ - if (gracenotes) { - event_error("Nested grace notes not allowed"); - } else { - if (v->inchord) { - event_error("Grace notes not allowed in chord"); - } else { - gracenotes = 1; - addfeature(GRACEON, 0, 0, 0); - v->ingrace = 1; - stack_broken(v); - }; - }; -} - -void event_graceoff() -/* a } in the abc */ -{ - if (!gracenotes) { - event_error("} without matching {"); - } else { - gracenotes = 0; - addfeature(GRACEOFF, 0, 0, 0); - v->ingrace = 0; - restore_broken(v); - }; -} - -void event_rep1() -/* [1 in the abc */ -{ - addfeature(PLAY_ON_REP, 0, 0, 1); -/* - if ((notes == 0) || (feature[notes-1] != SINGLE_BAR)) { - event_error("[1 must follow a single bar"); - } else { - feature[notes-1] = BAR1; - }; -*/ -} - -void event_rep2() -/* [2 in the abc */ -{ - addfeature(PLAY_ON_REP, 0, 0, 2); -/* - if ((notes == 0) || (feature[notes-1] != REP_BAR)) { - event_error("[2 must follow a :| "); - } else { - feature[notes-1] = REP_BAR2; - }; -*/ -} - -void event_playonrep(s) -char* s; -/* [X in the abc, where X is a list of numbers */ -{ - int num, converted; - char seps[2]; - - converted = sscanf(s, "%d%1[,-]", &num, seps); - if (converted == 0) { - event_error("corrupted variant ending"); - } else { - if ((converted == 1) && (num != 0)) { - addfeature(PLAY_ON_REP, 0, 0, num); - } else { - textfeature(PLAY_ON_REP, s); - }; - }; -} - -static void slurtotie() -/* converts a pair of identical slurred notes to tied notes */ -{ -} - -void event_sluron(t) -/* called when ( is encountered in the abc */ -int t; -{ - if (t == 1) { - addfeature(SLUR_ON, 0, 0, 0); - v->inslur = 1; - }; -} - -void event_sluroff(t) -/* called when ) is encountered */ -int t; -{ - if (t == 0) { - slurtotie(); - addfeature(SLUR_OFF, 0, 0, 0); - v->inslur = 0; - }; -} - -void event_tie() -/* a tie - has been encountered in the abc */ -{ - addfeature(TIE, 0, 0, 0); -} - -void event_space() -/* space character in the abc is ignored by abc2midi */ -{ - /* ignore */ - /* printf("Space event\n"); */ -} - -void event_lineend(ch, n) -/* called when \ or ! or * or ** is encountered at the end of a line */ -char ch; -int n; -{ - /* ignore */ -} - -void event_broken(type, mult) -/* handles > >> >>> < << <<< in the abc */ -int type, mult; -{ - if (v->inchord) { - event_error("Broken rhythm not allowed in chord"); - } else { - if (v->ingrace) { - event_error("Broken rhythm not allowed in grace notes"); - } else { - v->brokentype = type; - v->brokenmult = mult; - v->brokenpending = 0; - }; - }; -} - -void event_tuple(n, q, r) -/* handles triplets (3 and general tuplets (n:q:r in the abc */ -int n, q, r; -{ - if (tuplecount > 0) { - event_error("nested tuples"); - } else { - if (r == 0) { - specialtuple = 0; - tuplecount = n; - } else { - specialtuple = 1; - tuplecount = r; - }; - if (q != 0) { - tfact_num = q; - tfact_denom = n; - } else { - if ((n < 2) || (n > 9)) { - event_error("Only tuples (2 - (9 allowed"); - tfact_num = 1; - tfact_denom = 1; - tuplecount = 0; - } else { - /* deduce tfact_num using standard abc rules */ - if ((n == 2) || (n == 4) || (n == 8)) tfact_num = 3; - if ((n == 3) || (n == 6)) tfact_num = 2; - if ((n == 5) || (n == 7) || (n == 9)) { - if ((time_num % 3) == 0) { - tfact_num = 3; - } else { - tfact_num = 2; - }; - }; - tfact_denom = n; - }; - }; - tnote_num = 0; - tnote_denom = 0; - }; -} - -void event_chord() -/* a + has been encountered in the abc */ -{ - if (v->inchord) { - event_chordoff(1,1); - } else { - event_chordon(dummydecorator); - }; -} - -static void lenmul(n, a, b) -/* multiply note length by a/b */ -int n, a, b; -{ - if ((feature[n] == NOTE) || (feature[n] == REST) || - (feature[n] == CHORDOFF)) { - num[n] = num[n] * a; - denom[n] = denom[n] * b; - reduce(&num[n], &denom[n]); - }; -} - - -static void brokenadjust() -/* adjust lengths of broken notes */ -{ - int num1, num2, denom12; - int j; - int failed; - - switch(v->brokenmult) { - case 1: - num1 = ratio_b; - num2 = ratio_a; - break; - case 2: - num1 = 7; - num2 = 1; - break; - case 3: - num1 = 15; - num2 = 1; - break; - }; - denom12 = (num1 + num2)/2; - if (v->brokentype == LT) { - j = num1; - num1 = num2; - num2 = j; - }; - failed = 0; - if ((v->laststart == -1) || (v->lastend == -1) || - (v->thisstart == -1) || (v->thisend == -1)) { - failed = 1; - } else { - /* check for same length notes */ - if ((num[v->laststart]*denom[v->thisstart]) != - (num[v->thisstart]*denom[v->laststart])) { - failed = 1; - }; - }; - if (failed) { - event_error("Cannot apply broken rhythm"); - } else { -/* - printf("Adjusting %d to %d and %d to %d\n", - v->laststart, v->lastend, v->thisstart, v->thisend); -*/ - for (j=v->laststart; j<=v->lastend; j++) { - lenmul(j, num1, denom12); - }; - for (j=v->thisstart; j<=v->thisend; j++) { - lenmul(j, num2, denom12); - }; - }; -} - -static void marknotestart() -/* voice data structure keeps a record of last few notes encountered */ -/* in order to process broken rhythm. This is called at the start of */ -/* a note or chord */ -{ - v->laststart = v->thisstart; - v->lastend = v->thisend; - v->thisstart = notes-1; -} - -static void marknoteend() -/* voice data structure keeps a record of last few notes encountered */ -/* in order to process broken rhythm. This is called at the end of */ -/* a note or chord */ -{ - v->thisend = notes-1; - if (v->brokenpending != -1) { - v->brokenpending = v->brokenpending + 1; - if (v->brokenpending == 1) { - brokenadjust(); - v->brokenpending = -1; - }; - }; -} - -static void marknote() -/* when handling a single note, not a chord, marknotestart() and */ -/* marknoteend() can be called together */ -{ - marknotestart(); - marknoteend(); -} - -/* just a stub to ignore 'y' */ -void event_spacing(n, m) -int n,m; -{ -} - -void event_rest(decorators,n,m,type) -/* rest of n/m in the abc */ -int n, m,type; -int decorators[DECSIZE]; -{ - int num, denom; - - num = n; - denom = m; - if (v == NULL) { - event_fatal_error("Internal error : no voice allocated"); - }; - if (v->inchord) v->chordcount = v->chordcount + 1; - if (tuplecount > 0) { - num = num * tfact_num; - denom = denom * tfact_denom; - if (tnote_num == 0) { - tnote_num = num; - tnote_denom = denom; - } else { - if (tnote_num * denom != num * tnote_denom) { - if (!specialtuple) { - event_warning("Different length notes in tuple"); - }; - }; - }; - if ((!gracenotes) && (!v->inchord)) { - tuplecount = tuplecount - 1; - }; - }; - if (v->chordcount == 1) { - v->chord_num = num*4; - v->chord_denom = denom*(v->default_length); - }; - if ((!v->ingrace) && ((!v->inchord)||(v->chordcount==1))) { - addunits(num, denom*(v->default_length)); - }; - last_num = 3; /* hornpiping (>) cannot follow rest */ - addfeature(REST, 0, num*4, denom*(v->default_length)); - if (!v->inchord ) { - marknote(); - }; -} - -void event_mrest(n,m) -/* multiple bar rest of n/m in the abc */ -/* we check for m == 1 in the parser */ -int n, m; -{ - int i; - int decorators[DECSIZE]; - decorators[FERMATA]=0; -/* it is not legal to pass a fermata to a multirest */ - - for (i=0; idefault_length), time_denom,0); - if (i != n-1) { - event_bar(SINGLE_BAR, ""); - }; - }; -} - - - -void event_chordon(int chorddecorators[]) -/* handles a chord start [ in the abc */ -/* the array chorddecorators is needed in toabc.c and yapstree.c */ -/* but is not relevant here. */ - -{ - if (v->inchord) { - event_error("Attempt to nest chords"); - } else { - addfeature(CHORDON, 0, 0, 0); - v->inchord = 1; - v->chordcount = 0; - v->chord_num = 0; - v->chord_denom = 1; - marknotestart(); - }; -} - -void event_chordoff(int chord_n, int chord_m) -/* handles a chord close ] in the abc */ -{ - if (!v->inchord) { - event_error("Chord already finished"); - } else { - - if(chord_m == 1 && chord_n == 1) /* chord length not set outside [] */ - addfeature(CHORDOFF, 0, v->chord_num, v->chord_denom); - else - addfeature(CHORDOFFEX, 0, chord_n*4, chord_m*v->default_length); - - v->inchord = 0; - v->chordcount = 0; - marknoteend(); - if (tuplecount > 0) --tuplecount; - }; -} - - -void event_finger(p) -/* a 1, 2, 3, 4 or 5 has been found in a guitar chord field */ -char *p; -{ - /* does nothing */ -} - -static int pitchof(note, accidental, mult, octave, propogate_accs) -/* finds MIDI pitch value for note */ -/* if propogate_accs is 1, apply any accidental to all instances of */ -/* that note in the bar. If propogate_accs is 0, accidental does not */ -/* apply to other notes */ -char note, accidental; -int mult, octave; -int propogate_accs; -{ - int p; - char acc; - int mul, noteno; - static int scale[7] = {0, 2, 4, 5, 7, 9, 11}; - char *anoctave = "cdefgab"; - - p = (int) ((long) strchr(anoctave, note) - (long) anoctave); - p = scale[p]; - acc = accidental; - mul = mult; - noteno = (int)note - 'a'; - if (acc == ' ') { - acc = v->workmap[noteno]; - mul = v->workmul[noteno]; - } else { - if ((retain_accidentals) && (propogate_accs)) { - v->workmap[noteno] = acc; - v->workmul[noteno] = mul; - }; - }; - if (acc == '^') p = p + mul; - if (acc == '_') p = p - mul; - return p + 12*octave + middle_c; -} - - - -static void hornp(num, denom) -/* If we have used R:hornpipe, this routine modifies the rhythm by */ -/* applying appropriate broken rhythm */ -int num, denom; -{ - if ((hornpipe) && (notes > 0) && (feature[notes-1] != GT)) { - if ((num*last_denom == last_num*denom) && (num == 1) && - (denom*time_num == 32)) { - if (((time_num == 4) && (bar_denom == 8)) || - ((time_num == 2) && (bar_denom == 16))) { - /* addfeature(GT, 1, 0, 0); */ - v->brokentype = GT; - v->brokenmult = 1; - v->brokenpending = 0; - }; - }; - last_num = num; - last_denom = denom; - }; -} - - -void event_note(decorators, accidental, mult, note, xoctave, n, m) -/* handles a note in the abc */ -int decorators[DECSIZE]; -int mult; -char accidental, note; -int xoctave, n, m; -{ - int pitch; - int pitch_noacc; - int num, denom; - int octave; - - if (v == NULL) { - event_fatal_error("Internal error - no voice allocated"); - }; - octave = xoctave + v->octaveshift; - num = n; - denom = m; - if (v->inchord) v->chordcount = v->chordcount + 1; - if (tuplecount > 0) { - num = num * tfact_num; - denom = denom * tfact_denom; - if (tnote_num == 0) { - tnote_num = num; - tnote_denom = denom; - } else { - if (tnote_num * denom != num * tnote_denom) { - if (!specialtuple) { - event_warning("Different length notes in tuple"); - }; - }; - }; - if ((!gracenotes) && - ((!v->inchord) || ((v->inchord) && (v->chordcount == 1)))) { - tuplecount = tuplecount - 1; - }; - }; - if ((!v->ingrace) && (!v->inchord)) { - hornp(num, denom*(v->default_length)); - } else { - last_num = 3; /* hornpiping (>) cannot follow chord or grace notes */ - }; - if ((!v->ingrace) && ((!v->inchord)||(v->chordcount==1))) { - addunits(num, denom*(v->default_length)); - }; - pitch = pitchof(note, accidental, mult, octave, 1); - pitch_noacc = pitchof(note,0,0,octave,0); - if (decorators[FERMATA]) { - num = num*2; - }; - if (v->chordcount == 1) { - v->chord_num = num*4; - v->chord_denom = denom*(v->default_length); - }; - - pitchline[notes] = pitch_noacc; - addfeature(NOTE, pitch, num*4, denom*(v->default_length)); - marknote(); -} - -void event_microtone(int dir, int a, int b) -{ -} - -void event_normal_tone() -{ -} - - - -char *get_accidental(place, accidental) -/* read in accidental - used by event_handle_gchord() */ -char *place; /* place in string being parsed */ -char *accidental; /* pointer to char variable */ -{ - char *p; - - p = place; - *accidental = '='; - if (*p == '#') { - *accidental = '^'; - p = p + 1; - }; - if (*p == 'b') { - *accidental = '_'; - p = p + 1; - }; - return(p); -} - -void event_handle_gchord(s) -/* handler for the guitar chords */ -char* s; -{ -} - -void event_handle_instruction(s) -/* handler for ! ! instructions */ -/* does ppp pp p mp mf f ff fff */ -/* also does !drum! and !nodrum! */ -char* s; -{ -} - -static void setmap(sf, map, mult) -/* work out accidentals to be applied to each note */ -int sf; /* number of sharps in key signature -7 to +7 */ -char map[7]; -int mult[7]; -{ - int j; - - for (j=0; j<7; j++) { - map[j] = '='; - mult[j] = 1; - }; - if (sf >= 1) map['f'-'a'] = '^'; - if (sf >= 2) map['c'-'a'] = '^'; - if (sf >= 3) map['g'-'a'] = '^'; - if (sf >= 4) map['d'-'a'] = '^'; - if (sf >= 5) map['a'-'a'] = '^'; - if (sf >= 6) map['e'-'a'] = '^'; - if (sf >= 7) map['b'-'a'] = '^'; - if (sf <= -1) map['b'-'a'] = '_'; - if (sf <= -2) map['e'-'a'] = '_'; - if (sf <= -3) map['a'-'a'] = '_'; - if (sf <= -4) map['d'-'a'] = '_'; - if (sf <= -5) map['g'-'a'] = '_'; - if (sf <= -6) map['c'-'a'] = '_'; - if (sf <= -7) map['f'-'a'] = '_'; -} - -static void altermap(v, modmap, modmul) -/* apply modifiers to a set of accidentals */ -struct voicecontext* v; -char modmap[7]; -int modmul[7]; -{ - int i; - - for (i=0; i<7; i++) { - if (modmap[i] != ' ') { - v->basemap[i] = modmap[i]; - v->basemul[i] = modmul[i]; - }; - }; -} - -static void copymap(v) -/* sets up working map at the start of each bar */ -struct voicecontext* v; -{ - int j; - - for (j=0; j<7; j++) { - v->workmap[j] = v->basemap[j]; - v->workmul[j] = v->basemul[j]; - }; -} - -/* workaround for problems with PCC compiler */ -/* data may be written to an internal buffer */ - -int myputc(c) -char c; -{ - return (putc(c,fp)); -} - -static void addfract(xnum, xdenom, a, b) -/* add a/b to the count of units in the bar */ -int *xnum; -int *xdenom; -int a, b; -{ - *xnum = (*xnum)*b + a*(*xdenom); - *xdenom = (*xdenom) * b; - reduce(xnum, xdenom); -} - - -static void dotie(j, xinchord,voiceno) -/* called in preprocessing stage to handle ties */ -/* we need the voiceno in case a tie is broken by a */ -/* voice switch. */ -int j, xinchord,voiceno; -{ - int tienote, place; - int tietodo, done; - int lastnote, lasttie; - int inchord; - int tied_num, tied_denom; - int localvoiceno; - int samechord; - - /* find note to be tied */ - samechord = 0; - if (xinchord) samechord = 1; - tienote = j; - localvoiceno = voiceno; - while ((tienote > 0) && (feature[tienote] != NOTE) && - (feature[tienote] != REST)) { - tienote = tienote - 1; - }; - if (feature[tienote] != NOTE) { - event_error("Cannot find note before tie"); - } else { - inchord = xinchord; - /* change NOTE + TIE to TNOTE + REST */ - feature[tienote] = TNOTE; - feature[j] = REST; - num[j] = num[tienote]; - denom[j] = denom[tienote]; - place = j; - tietodo = 1; - lasttie = j; - tied_num = num[tienote]; - tied_denom = denom[tienote]; - lastnote = -1; - done = 0; - while ((place < notes) && (tied_num >=0) && (done == 0)) { - /* printf("%d %s %d %d/%d ",place,featname[feature[place]],pitch[place],num[place],denom[place]); */ - switch (feature[place]) { - case NOTE: - if(localvoiceno != voiceno) break; - lastnote = place; - if ((tied_num == 0) && (tietodo == 0)) { - done = 1; - }; - if ((pitchline[place] == pitchline[tienote]) - && (tietodo == 1) && (samechord == 0)) { - /* tie in note */ - if (tied_num != 0) { - event_error("Time mismatch at tie"); - }; - tietodo = 0; - pitch[place] = pitch[tienote]; /* in case accidentals did not - propagate */ - /* add time to tied time */ - addfract(&tied_num, &tied_denom, num[place], denom[place]); - /* add time to tied note */ - addfract(&num[tienote], &denom[tienote], num[place], denom[place]); - /* change note to a rest */ - feature[place] = REST; - /* get rid of tie */ - if (lasttie != j) { - feature[lasttie] = OLDTIE; - }; - }; - if (inchord == 0) { - /* subtract time from tied time */ - addfract(&tied_num, &tied_denom, -num[place], denom[place]); - }; - break; - case REST: - if(localvoiceno != voiceno) break; - if ((tied_num == 0) && (tietodo == 0)) { - done = 1; - }; - if (inchord == 0) { - /* subtract time from tied time */ - addfract(&tied_num, &tied_denom, -num[place], denom[place]); - }; - break; - case TIE: - if(localvoiceno != voiceno) break; - if (lastnote == -1) { - event_error("Bad tie: possibly two ties in a row"); - } else { - if (pitch[lastnote] == pitch[tienote] && samechord == 0) { - lasttie = place; - tietodo = 1; - if (inchord) samechord = 1; - }; - }; - break; - case CHORDON: - if(localvoiceno != voiceno) break; - inchord = 1; - break; - case CHORDOFF: - case CHORDOFFEX: - samechord = 0; - if(localvoiceno != voiceno) break; - inchord = 0; - /* subtract time from tied time */ - addfract(&tied_num, &tied_denom, -num[place], denom[place]); - break; - case VOICE: - localvoiceno = pitch[place]; - default: - break; - }; - /*printf("tied_num = %d done = %d inchord = %d\n",tied_num, done, inchord); */ - place = place + 1; - }; - if (tietodo == 1) { - event_error("Could not find note to be tied"); - }; - }; -/* printf("dotie finished\n"); */ -} - -static void tiefix() -/* connect up tied notes and cleans up the */ -/* note lengths in the chords (eg [ace]3 ) */ -{ - int j; - int inchord; - int chord_num, chord_denom; - int chord_start,chord_end; - int voiceno; - - j = 0; - inchord = 0; - voiceno = 1; - while (j 0) { - event_playonrep(replist); - }; -/* - if (type == BAR1) { - addfeature(PLAY_ON_REP, 0, 0, 1); - }; - if (type == REP_BAR2) { - addfeature(PLAY_ON_REP, 0, 0, 2); - }; -*/ -} - - - - -void startfile() -/* called at the beginning of an abc tune by event_refno */ -/* This sets up all the default values */ -{ - int j; - - if (verbose) { - printf("scanning tune\n"); - }; - /* set up defaults */ - sf = 0; - mi = 0; - setmap(0, global.basemap, global.basemul); - copymap(&global); - global.octaveshift = 0; - voicecount = 0; - head = NULL; - v = NULL; - time_num = 4; - time_denom = 4; - timesigset = 0; - barchecking = 1; - global.default_length = -1; - event_tempo(120, 1, 4, 0,NULL, NULL); - notes = 0; - ntexts = 0; - gfact_num = 1; - gfact_denom = 3; - global_transpose = 0; - hornpipe = 0; - karaoke = 0; - retain_accidentals = 1; - ratio_a = 2; - ratio_b = 4; - wcount = 0; - parts = -1; - middle_c = 60; - for (j=0; j<26; j++) { - part_start[j] = -1; - }; - headerpartlabel = 0; - additive = 1; - initvstring(&part); - } - - -static void headerprocess() -/* called after the K: field has been reached, signifying the end of */ -/* the header and the start of the tune */ -{ - int t_num, t_denom; - - if (headerpartlabel == 1) { - part_start[(int)part.st[0] - (int)'A'] = notes; - addfeature(PART, part.st[0], 0, 0); - }; - addfeature(DOUBLE_BAR, 0, 0, 0); - pastheader = 1; - - gracenotes = 0; /* not in a grace notes section */ - if (!timesigset) { - event_warning("No M: in header, using default"); - }; - /* calculate time for a default length note */ - if (global.default_length == -1) { - if (((float) time_num)/time_denom < 0.75) { - global.default_length = 16; - } else { - global.default_length = 8; - }; - }; - bar_num = 0; - bar_denom = 1; - set_meter(time_num, time_denom); - if (hornpipe) { - if ((time_denom != 4) || ((time_num != 2) && (time_num != 4))) { - event_error("Hornpipe must be in 2/4 or 4/4 time"); - hornpipe = 0; - }; - }; - - tempounits(&t_num, &t_denom); - /* make tempo in terms of 1/4 notes */ -/* tempo = (long) 60*1000000*t_denom/(Qtempo*4*t_num); */ -/* div_factor = division; */ - voicesused = 0; -} - -void event_key(sharps, s, modeindex, modmap, modmul, gotkey, gotclef, clefname, - octave, transpose, gotoctave, gottranspose) -/* handles a K: field */ -int sharps; /* sharps is number of sharps in key signature */ -int modeindex; /* 0 major, 1,2,3 minor, 4 locrian, etc. */ -char *s; /* original string following K: */ -char modmap[7]; /* array of accidentals to be applied */ -int modmul[7]; /* array giving multiplicity of each accent (1 or 2) */ -int gotkey, gotclef; -int octave, transpose, gotoctave, gottranspose; -char* clefname; -{ - int minor; - if (modeindex >0 && modeindex <4) minor = 1; - if ((dotune) && gotkey) { - if (pastheader) { - setmap(sharps, v->basemap, v->basemul); - altermap(v, modmap, modmul); - copymap(v); - addfeature(KEY, sharps, 0, minor); - if (gottranspose) { - addfeature(TRANSPOSE, transpose, 0, 0); - }; - } else { - if (gottranspose) { - global_transpose = transpose; - }; - setmap(sharps, global.basemap, global.basemul); - altermap(&global, modmap, modmul); - copymap(&global); - sf = sharps; - mi = minor; - headerprocess(); - v = newvoice(1); - head = v; - }; - if (gotoctave) { - event_octave(octave,0); - }; - }; -} - - - -void print_feature_list () -{ -int i,length; -float fract; -printf("feature list \n"); -for (i=0;i -1) { - addfeature(PART, ' ', 0, 0); - }; - if (headerpartlabel == 1) { - event_error("P: field in header should go after K: field"); - }; - - tiefix(); - - - }; - for (i=0; i +#include + +#ifdef __MWERKS__ +#define __MACINTOSH__ 1 +#endif /* __MWERKS__ */ + +#ifdef __MACINTOSH__ +int setOutFileCreator(char *fileName,unsigned long theType, + unsigned long theCreator); +#endif /* __MACINTOSH__ */ +/* define USE_INDEX if your C libraries have index() instead of strchr() */ +#ifdef USE_INDEX +#define strchr index +#endif + +#ifdef ANSILIBS +#include +#include +#include +#else +extern char* strchr(); +extern void reduce(); +#endif + +#define MAXLINE 500 +#define INITTEXTS 20 +#define INITWORDS 20 +#define MAXCHANS 16 + +/*#define DEBUG*/ + + +/* global variables grouped roughly by function */ + +FILE *fp; + +programname fileprogram = ABCMATCH; + + +/* parsing stage */ +int tuplecount, tfact_num, tfact_denom, tnote_num, tnote_denom; +int specialtuple; +int gracenotes; +int headerpartlabel; +int dotune, pastheader; +int hornpipe, last_num, last_denom; +int timesigset; +int retain_accidentals; +int ratio_a, ratio_b; + +struct voicecontext { + /* maps of accidentals for each stave line */ + char basemap[7], workmap[7]; + int basemul[7], workmul[7]; + int default_length; + int voiceno; + int indexno; + int hasgchords; + int haswords; + int inslur; + int ingrace; + int octaveshift; + /* chord handling */ + int inchord, chordcount; + int chord_num, chord_denom; + /* details of last 2 notes/chords to apply length-modifiers to */ + int laststart, lastend, thisstart, thisend; + /* broken rythm handling */ + int brokentype, brokenmult, brokenpending; + int broken_stack[7]; + struct voicecontext* next; +}; +struct voicecontext global; +struct voicecontext* v; +struct voicecontext* head; +int voicecount; + +/* storage structure for strings */ +int maxtexts = INITTEXTS; +char** atext; +int ntexts = 0; + +int note_unit_length=8; + +/* general purpose storage structure */ +int maxnotes; +int *pitch, *num, *denom; +featuretype *feature; +int *pitchline; +int notes; + +int verbose = 0; +int nowarn=1; +int noerror=1; +int xmatch; +int sf, mi; + +/* Part handling */ +struct vstring part; +int parts, partno, partlabel; +int part_start[26], part_count[26]; + +int voicesused; + +/* Tempo handling (Q: field) */ +int time_num, time_denom; +long tempo; +int tempo_num, tempo_denom; +int relative_tempo, Qtempo; +extern int division; +extern int div_factor; + +/* output file generation */ +int check; +int ntracks; + +/* bar length checking */ +int bar_num, bar_denom; +int barchecking; +int beat; + +/* generating MIDI output */ +int middle_c; +extern int channels[MAXCHANS + 3]; + +int global_transpose; + +int additive; +int gfact_num, gfact_denom; + +/* karaoke handling */ +int karaoke, wcount; +char** words; +int maxwords = INITWORDS; +int xrefno; + +extern int intune; /* signals to parsetune that tune is finished */ + +/* Many of these functions have been retained in order to link with parseabc. +As I have been forced to also modifiy parseabc, now called abcparse, these +functions can also be removed eventually. + */ + +char *featname[] = { +"SINGLE_BAR", "DOUBLE_BAR", "BAR_REP", "REP_BAR", +"PLAY_ON_REP", "REP1", "REP2", "BAR1", +"REP_BAR2", "DOUBLE_REP", "THICK_THIN", "THIN_THICK", +"PART", "TEMPO", "TIME", "KEY", +"REST", "TUPLE", "NOTE", "NONOTE", +"OLDTIE", "TEXT", "SLUR_ON", "SLUR_OFF", +"TIE", "CLOSE_TIE", "TITLE", "CHANNEL", +"TRANSPOSE", "RTRANSPOSE", "GTRANSPOSE", "GRACEON", +"GRACEOFF", "SETGRACE", "SETC", "SETTRIM", "GCHORD", +"GCHORDON", "GCHORDOFF", "VOICE", "CHORDON", +"CHORDOFF", "CHORDOFFEX", "DRUMON", "DRUMOFF", +"DRONEON", "DRONEOFF", "SLUR_TIE", "TNOTE", +"LT", "GT", "DYNAMIC", "LINENUM", +"MUSICLINE", "MUSICSTOP", "WORDLINE", "WORDSTOP", +"INSTRUCTION", "NOBEAM", "CHORDNOTE", "CLEF", +"PRINTLINE", "NEWPAGE", "LEFT_TEXT", "CENTRE_TEXT", +"VSKIP", "COPYRIGHT", "COMPOSER", "ARPEGGIO", +"SPLITVOICE" +}; + + + +void event_info (place) +char * place; +{ +} + +void event_gchord (chord) +char * chord; +{ +} + +void event_slur (t) +int t; +{ +} + + +void event_instruction (s) +char *s; +{ +} + + +void event_reserved (p) +char p; +{ +} + +int bar_num, bar_denom, barno, barsize; +int b_num,b_denom; + +void reduce(a, b) +/* elimate common factors in fraction a/b */ +int *a, *b; +{ + int sign; + int t, n, m; + + if (*a < 0) { + sign = -1; + *a = -*a; + } else { + sign = 1; + }; + /* 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)*sign; + *b = *b/n; +} + +void addunits(a, b) +/* add a/b to the count of units in the bar */ +int a, b; +{ + bar_num = bar_num*(b*b_denom) + (a*b_num)*bar_denom; + bar_denom = bar_denom * (b*b_denom); + reduce(&bar_num, &bar_denom); +} + + +void set_meter(n, m) +/* set up variables associated with meter */ +int n, m; +{ + /* set up barsize */ + barsize = n; + if (barsize % 3 == 0) { + beat = 3; + } else { + if (barsize % 2 == 0) { + beat = 2; + } else { + beat = barsize; + }; + }; + /* correction factor to make sure we count in the right units */ + if (m > 4) { + b_num = m/4; + b_denom = 1; + } else { + b_num = 1; + b_denom = 4/m; + }; +} + +int dummydecorator[DECSIZE]; /* used in event_chord */ + + +static struct voicecontext* newvoice(n) +/* allocate and initialize the data for a new voice */ +int n; +{ + struct voicecontext *s; + int i; + + s = (struct voicecontext*) checkmalloc(sizeof(struct voicecontext)); + voicecount = voicecount + 1; + s->voiceno = n; + s->indexno = voicecount; + s->default_length = global.default_length; + s->hasgchords = 0; + s->haswords = 0; + s->inslur = 0; + s->ingrace = 0; + s->inchord = 0; + s->chordcount = 0; + s->laststart = -1; + s->lastend = -1; + s->thisstart = -1; + s->thisend = -1; + s->brokenpending = -1; + s->next = NULL; + for (i=0; i<7; i++) { + s->basemap[i] = global.basemap[i]; + s->basemul[i] = global.basemul[i]; + s->workmap[i] = global.workmap[i]; + s->workmul[i] = global.workmul[i]; + }; + s->octaveshift = global.octaveshift; + return(s); +} + +static struct voicecontext* getvoicecontext(n) +/* find the data structure for a given voice number */ +int n; +{ + struct voicecontext *p; + struct voicecontext *q; + + p = head; + q = NULL; + while ((p != NULL) && (p->voiceno != n)) { + q = p; + p = p->next; + }; + if (p == NULL) { + p = newvoice(n); + if (q != NULL) { + q->next = p; + }; + }; + if (head == NULL) { + head = p; + }; + return(p); +} + +static void clearvoicecontexts() +/* free up all the memory allocated to voices */ +{ + struct voicecontext *p; + struct voicecontext *q; + + p = head; + while (p != NULL) { + q = p->next; + free(p); + p = q; + }; + head = NULL; +} + + + + +void event_text(s) +/* text found in abc file */ +char *s; +{ +} + + +void event_specific (package, s) +char *package, *s; +{ +} + + +void event_x_reserved(p) +/* reserved character H-Z found in abc file */ +char p; +{ +} + +void event_abbreviation(symbol, string, container) +/* abbreviation encountered - this is handled within the parser */ +char symbol; +char *string; +char container; +{ +} + + +void event_acciaccatura() +{ +/* does nothing here but outputs a / in abc2abc */ +return; +} + +void event_split_voice() +{ +} + + + +void event_tex(s) +/* TeX command found - ignore it */ +char *s; +{ +} + +void event_fatal_error(s) +/* print error message and halt */ +char *s; +{ + event_error(s); + exit(1); +} + +void event_error(s) +/* generic error handler */ +char *s; +{ +if (noerror) return; +#ifdef NOFTELL + extern int nullpass; + + if (nullpass != 1) { + printf("Error in line %d : %s\n", lineno, s); + }; +#else + printf("Error in line %d : %s\n", lineno, s); +#endif +} + +void event_warning(s) +/* generic warning handler - for flagging possible errors */ +char *s; +{ +if (nowarn) return; +#ifdef NOFTELL + extern int nullpass; + + if (nullpass != 1) { + printf("Warning in line %d : %s\n", lineno, s); + }; +#else + printf("Warning in line %d : %s\n", lineno, s); +#endif +} + +static int autoextend(maxnotes) +/* increase the number of abc elements the program can cope with */ +int maxnotes; +{ + int newlimit; + int *ptr; + featuretype *fptr; + int i; + + if (verbose) { + event_warning("Extending note capacity"); + }; + newlimit = maxnotes*2; + fptr = (featuretype*) checkmalloc(newlimit*sizeof(featuretype)); + for(i=0;i= maxnotes) { + maxnotes = autoextend(maxnotes); + }; +} + +void event_linebreak() +/* reached end of line in abc */ +{ + addfeature(LINENUM, lineno, 0, 0); +} + +void event_startmusicline() +/* starting to parse line of abc music */ +{ + addfeature(MUSICLINE, 0, 0, 0); +} + +void event_endmusicline(endchar) +/* finished parsing line of abc music */ +char endchar; +{ + addfeature(MUSICSTOP, 0, 0, 0); +} + +static void textfeature(type, s) +/* called while parsing abc - stores an item which requires an */ +/* associared string */ +int type; +char* s; +{ +} + +void event_comment(s) +/* comment found in abc */ +char *s; +{ +} + + +void event_startinline() +/* start of in-line field in abc music line */ +{ +} + +void event_closeinline() +/* end of in-line field in abc music line */ +{ +} + +void event_field(k, f) +/* Handles R: T: and any other field not handled elsewhere */ +char k; +char *f; +{ + if (dotune) { + switch (k) { + case 'R': + { + char* p; + + p = f; + skipspace(&p); +/******** if ((strncmp(p, "Hornpipe", 8) == 0) || + (strncmp(p, "hornpipe", 8) == 0)) { + hornpipe = 1; + }; +********/ + }; + break; + default: + { + }; + }; + }; +} + +void event_words(p, continuation) +/* handles a w: field in the abc */ +char* p; +int continuation; +{ +} + + +static void checkbreak() +/* check that we are in not in chord, grace notes or tuple */ +/* called at voice change */ +{ + if (tuplecount != 0) { + event_error("Previous voice has an unfinished tuple"); + tuplecount = 0; + }; + if (v->inchord != 0) { + event_error("Previous voice has incomplete chord"); + event_chordoff(1,1); + }; + if (v->ingrace != 0) { + event_error("Previous voice has unfinished grace notes"); + v->ingrace = 0; + }; +} + + +static void read_spec(spec, part) +/* converts a P: field to a list of part labels */ +/* e.g. P:A(AB)3(CD)2 becomes P:AABABABCDCD */ +/* A '+' indicates 'additive' behaviour (a part may include repeats). */ +/* A '-' indicates 'non-additive' behaviour (repeat marks in the music */ +/* are ignored and only repeats implied by the part order statement */ +/* are played). */ +char spec[]; +struct vstring* part; +{ +} + +void event_part(s) +/* handles a P: field in the abc */ +char* s; +{ + char* p; + + if (dotune) { + p = s; + skipspace(&p); + if (pastheader) { + if (((int)*p < 'A') || ((int)*p > 'Z')) { + event_error("Part must be one of A-Z"); + return; + }; + if ((headerpartlabel == 1) && (part.st[0] == *p)) { + /* P: field in header is not a label */ + headerpartlabel = 0; + /* remove speculative part label */ + feature[part_start[(int)*p - (int)'A']] = NONOTE; + } else { + if (part_start[(int)*p - (int)'A'] != -1) { + event_error("Part defined more than once"); + }; + }; + part_start[(int)*p - (int)'A'] = notes; + addfeature(PART, (int)*p, 0, 0); + checkbreak(); + v = getvoicecontext(1); + } else { + parts = 0; + read_spec(p, &part); + if (parts == 1) { + /* might be a label not a specificaton */ + headerpartlabel = 1; + }; + }; + }; +} + +void event_voice(n, s, vp) +/* handles a V: field in the abc */ +int n; +char *s; +struct voice_params *vp; +{ + if (pastheader || XTEN1) { + voicesused = 1; + if (pastheader) checkbreak(); + v = getvoicecontext(n); + addfeature(VOICE, v->indexno, 0, 0); + if (vp->gotoctave) { + event_octave(vp->octave,1); + }; + if (vp->gottranspose) { + addfeature(TRANSPOSE, vp->transpose, 0, 0); + }; + } else { + event_warning("V: in header ignored"); + }; +} + + +void event_length(n) +/* handles an L: field in the abc */ +int n; +{ + note_unit_length = 8; + if (pastheader) { + v->default_length = n; + } else { + global.default_length = n; + }; +} + +static void tempounits(t_num, t_denom) +/* interprets Q: once default length is known */ +int *t_num, *t_denom; +{ +} + +void event_tempo(n, a, b, rel, pre, post) +/* handles a Q: field e.g. Q: a/b = n or Q: Ca/b = n */ +/* strings before and after are ignored */ +int n; +int a, b, rel; +char *pre; +char *post; +{ +} + + +void event_timesig(n, m, dochecking) +/* handles an M: field M:n/m */ +int n, m, dochecking; +{ + if (dotune) { + if (pastheader) { + addfeature(TIME, dochecking, n, m); + } else { + time_num = n; + time_denom = m; + timesigset = 1; + barchecking = dochecking; + }; + }; +} + +void event_octave(num, local) +/* used internally by other routines when octave=N is encountered */ +/* in I: or K: fields */ +int num; +{ + if (dotune) { + if (pastheader || local) { + v->octaveshift = num; + } else { + global.octaveshift = num; + }; + }; +} + +void event_info_key(key, value) +char* key; +char* value; +{ + int num; + + if (strcmp(key, "octave")==0) { + num = readsnumf(value); + event_octave(num,0); + }; +} + +static void stack_broken(v) +struct voicecontext* v; +{ + v->broken_stack[0] = v->laststart; + v->broken_stack[1] = v->lastend; + v->broken_stack[2] = v->thisstart; + v->broken_stack[3] = v->thisend; + v->broken_stack[4] = v->brokentype; + v->broken_stack[5] = v->brokenmult; + v->broken_stack[6] = v->brokenpending; + v->laststart = -1; + v->lastend = -1; + v->thisstart = -1; + v->thisend = -1; + v->brokenpending = -1; +} + +static void restore_broken(v) +struct voicecontext* v; +{ + if (v->brokenpending != -1) { + event_error("Unresolved broken rhythm in grace notes"); + }; + v->laststart = v->broken_stack[0]; + v->lastend = v->broken_stack[1]; + v->thisstart = v->broken_stack[2]; + v->thisend = v->broken_stack[3]; + v->brokentype = v->broken_stack[4]; + v->brokenmult = v->broken_stack[5]; + v->brokenpending = v->broken_stack[6]; +} + +void event_graceon() +/* a { in the abc */ +{ + if (gracenotes) { + event_error("Nested grace notes not allowed"); + } else { + if (v->inchord) { + event_error("Grace notes not allowed in chord"); + } else { + gracenotes = 1; + addfeature(GRACEON, 0, 0, 0); + v->ingrace = 1; + stack_broken(v); + }; + }; +} + +void event_graceoff() +/* a } in the abc */ +{ + if (!gracenotes) { + event_error("} without matching {"); + } else { + gracenotes = 0; + addfeature(GRACEOFF, 0, 0, 0); + v->ingrace = 0; + restore_broken(v); + }; +} + +void event_rep1() +/* [1 in the abc */ +{ + addfeature(PLAY_ON_REP, 0, 0, 1); +/* + if ((notes == 0) || (feature[notes-1] != SINGLE_BAR)) { + event_error("[1 must follow a single bar"); + } else { + feature[notes-1] = BAR1; + }; +*/ +} + +void event_rep2() +/* [2 in the abc */ +{ + addfeature(PLAY_ON_REP, 0, 0, 2); +/* + if ((notes == 0) || (feature[notes-1] != REP_BAR)) { + event_error("[2 must follow a :| "); + } else { + feature[notes-1] = REP_BAR2; + }; +*/ +} + +void event_playonrep(s) +char* s; +/* [X in the abc, where X is a list of numbers */ +{ + int num, converted; + char seps[2]; + + converted = sscanf(s, "%d%1[,-]", &num, seps); + if (converted == 0) { + event_error("corrupted variant ending"); + } else { + if ((converted == 1) && (num != 0)) { + addfeature(PLAY_ON_REP, 0, 0, num); + } else { + textfeature(PLAY_ON_REP, s); + }; + }; +} + +static void slurtotie() +/* converts a pair of identical slurred notes to tied notes */ +{ +} + +void event_sluron(t) +/* called when ( is encountered in the abc */ +int t; +{ + if (t == 1) { + addfeature(SLUR_ON, 0, 0, 0); + v->inslur = 1; + }; +} + +void event_sluroff(t) +/* called when ) is encountered */ +int t; +{ + if (t == 0) { + slurtotie(); + addfeature(SLUR_OFF, 0, 0, 0); + v->inslur = 0; + }; +} + +void event_tie() +/* a tie - has been encountered in the abc */ +{ + addfeature(TIE, 0, 0, 0); +} + +void event_space() +/* space character in the abc is ignored by abc2midi */ +{ + /* ignore */ + /* printf("Space event\n"); */ +} + +void event_lineend(ch, n) +/* called when \ or ! or * or ** is encountered at the end of a line */ +char ch; +int n; +{ + /* ignore */ +} + +void event_broken(type, mult) +/* handles > >> >>> < << <<< in the abc */ +int type, mult; +{ + if (v->inchord) { + event_error("Broken rhythm not allowed in chord"); + } else { + if (v->ingrace) { + event_error("Broken rhythm not allowed in grace notes"); + } else { + v->brokentype = type; + v->brokenmult = mult; + v->brokenpending = 0; + }; + }; +} + +void event_tuple(n, q, r) +/* handles triplets (3 and general tuplets (n:q:r in the abc */ +int n, q, r; +{ + if (tuplecount > 0) { + event_error("nested tuples"); + } else { + if (r == 0) { + specialtuple = 0; + tuplecount = n; + } else { + specialtuple = 1; + tuplecount = r; + }; + if (q != 0) { + tfact_num = q; + tfact_denom = n; + } else { + if ((n < 2) || (n > 9)) { + event_error("Only tuples (2 - (9 allowed"); + tfact_num = 1; + tfact_denom = 1; + tuplecount = 0; + } else { + /* deduce tfact_num using standard abc rules */ + if ((n == 2) || (n == 4) || (n == 8)) tfact_num = 3; + if ((n == 3) || (n == 6)) tfact_num = 2; + if ((n == 5) || (n == 7) || (n == 9)) { + if ((time_num % 3) == 0) { + tfact_num = 3; + } else { + tfact_num = 2; + }; + }; + tfact_denom = n; + }; + }; + tnote_num = 0; + tnote_denom = 0; + }; +} + +void event_chord() +/* a + has been encountered in the abc */ +{ + if (v->inchord) { + event_chordoff(1,1); + } else { + event_chordon(dummydecorator); + }; +} + +static void lenmul(n, a, b) +/* multiply note length by a/b */ +int n, a, b; +{ + if ((feature[n] == NOTE) || (feature[n] == REST) || + (feature[n] == CHORDOFF)) { + num[n] = num[n] * a; + denom[n] = denom[n] * b; + reduce(&num[n], &denom[n]); + }; +} + + +static void brokenadjust() +/* adjust lengths of broken notes */ +{ + int num1, num2, denom12; + int j; + int failed; + + switch(v->brokenmult) { + default: + event_error("unsupported type of broken rhythm"); + case 1: + num1 = ratio_b; + num2 = ratio_a; + break; + case 2: + num1 = 7; + num2 = 1; + break; + case 3: + num1 = 15; + num2 = 1; + break; + }; + denom12 = (num1 + num2)/2; + if (v->brokentype == LT) { + j = num1; + num1 = num2; + num2 = j; + }; + failed = 0; + if ((v->laststart == -1) || (v->lastend == -1) || + (v->thisstart == -1) || (v->thisend == -1)) { + failed = 1; + } else { + /* check for same length notes */ + if ((num[v->laststart]*denom[v->thisstart]) != + (num[v->thisstart]*denom[v->laststart])) { + failed = 1; + }; + }; + if (failed) { + event_error("Cannot apply broken rhythm"); + } else { +/* + printf("Adjusting %d to %d and %d to %d\n", + v->laststart, v->lastend, v->thisstart, v->thisend); +*/ + for (j=v->laststart; j<=v->lastend; j++) { + lenmul(j, num1, denom12); + }; + for (j=v->thisstart; j<=v->thisend; j++) { + lenmul(j, num2, denom12); + }; + }; +} + +static void marknotestart() +/* voice data structure keeps a record of last few notes encountered */ +/* in order to process broken rhythm. This is called at the start of */ +/* a note or chord */ +{ + v->laststart = v->thisstart; + v->lastend = v->thisend; + v->thisstart = notes-1; +} + +static void marknoteend() +/* voice data structure keeps a record of last few notes encountered */ +/* in order to process broken rhythm. This is called at the end of */ +/* a note or chord */ +{ + v->thisend = notes-1; + if (v->brokenpending != -1) { + v->brokenpending = v->brokenpending + 1; + if (v->brokenpending == 1) { + brokenadjust(); + v->brokenpending = -1; + }; + }; +} + +static void marknote() +/* when handling a single note, not a chord, marknotestart() and */ +/* marknoteend() can be called together */ +{ + marknotestart(); + marknoteend(); +} + +/* just a stub to ignore 'y' */ +void event_spacing(n, m) +int n,m; +{ +} + +void event_rest(decorators,n,m,type) +/* rest of n/m in the abc */ +int n, m,type; +int decorators[DECSIZE]; +{ + int num, denom; + + num = n; + denom = m; + if (v == NULL) { + event_fatal_error("Internal error : no voice allocated"); + }; + if (v->inchord) v->chordcount = v->chordcount + 1; + if (tuplecount > 0) { + num = num * tfact_num; + denom = denom * tfact_denom; + if (tnote_num == 0) { + tnote_num = num; + tnote_denom = denom; + } else { + if (tnote_num * denom != num * tnote_denom) { + if (!specialtuple) { + event_warning("Different length notes in tuple"); + }; + }; + }; + if ((!gracenotes) && (!v->inchord)) { + tuplecount = tuplecount - 1; + }; + }; + if (v->chordcount == 1) { + v->chord_num = num*4; + v->chord_denom = denom*(v->default_length); + }; + if ((!v->ingrace) && ((!v->inchord)||(v->chordcount==1))) { + addunits(num, denom*(v->default_length)); + }; + last_num = 3; /* hornpiping (>) cannot follow rest */ + addfeature(REST, 0, num*4, denom*(v->default_length)); + if (!v->inchord ) { + marknote(); + }; +} + +void event_mrest(n,m) +/* multiple bar rest of n/m in the abc */ +/* we check for m == 1 in the parser */ +int n, m; +{ + int i; + int decorators[DECSIZE]; + decorators[FERMATA]=0; +/* it is not legal to pass a fermata to a multirest */ + + for (i=0; idefault_length), time_denom,0); + if (i != n-1) { + event_bar(SINGLE_BAR, ""); + }; + }; +} + + + +void event_chordon(int chorddecorators[]) +/* handles a chord start [ in the abc */ +/* the array chorddecorators is needed in toabc.c and yapstree.c */ +/* but is not relevant here. */ + +{ + if (v->inchord) { + event_error("Attempt to nest chords"); + } else { + addfeature(CHORDON, 0, 0, 0); + v->inchord = 1; + v->chordcount = 0; + v->chord_num = 0; + v->chord_denom = 1; + marknotestart(); + }; +} + +void event_chordoff(int chord_n, int chord_m) +/* handles a chord close ] in the abc */ +{ + if (!v->inchord) { + event_error("Chord already finished"); + } else { + + if(chord_m == 1 && chord_n == 1) /* chord length not set outside [] */ + addfeature(CHORDOFF, 0, v->chord_num, v->chord_denom); + else + addfeature(CHORDOFFEX, 0, chord_n*4, chord_m*v->default_length); + + v->inchord = 0; + v->chordcount = 0; + marknoteend(); + if (tuplecount > 0) --tuplecount; + }; +} + + +void event_finger(p) +/* a 1, 2, 3, 4 or 5 has been found in a guitar chord field */ +char *p; +{ + /* does nothing */ +} + +static int pitchof(note, accidental, mult, octave, propogate_accs) +/* finds MIDI pitch value for note */ +/* if propogate_accs is 1, apply any accidental to all instances of */ +/* that note in the bar. If propogate_accs is 0, accidental does not */ +/* apply to other notes */ +char note, accidental; +int mult, octave; +int propogate_accs; +{ + int p; + char acc; + int mul, noteno; + static int scale[7] = {0, 2, 4, 5, 7, 9, 11}; + char *anoctave = "cdefgab"; + + p = (int) ((long) strchr(anoctave, note) - (long) anoctave); + p = scale[p]; + acc = accidental; + mul = mult; + noteno = (int)note - 'a'; + if (acc == ' ') { + acc = v->workmap[noteno]; + mul = v->workmul[noteno]; + } else { + if ((retain_accidentals) && (propogate_accs)) { + v->workmap[noteno] = acc; + v->workmul[noteno] = mul; + }; + }; + if (acc == '^') p = p + mul; + if (acc == '_') p = p - mul; + return p + 12*octave + middle_c; +} + + + +static void hornp(num, denom) +/* If we have used R:hornpipe, this routine modifies the rhythm by */ +/* applying appropriate broken rhythm */ +int num, denom; +{ + if ((hornpipe) && (notes > 0) && (feature[notes-1] != GT)) { + if ((num*last_denom == last_num*denom) && (num == 1) && + (denom*time_num == 32)) { + if (((time_num == 4) && (bar_denom == 8)) || + ((time_num == 2) && (bar_denom == 16))) { + /* addfeature(GT, 1, 0, 0); */ + v->brokentype = GT; + v->brokenmult = 1; + v->brokenpending = 0; + }; + }; + last_num = num; + last_denom = denom; + }; +} + + +void event_note(decorators, accidental, mult, note, xoctave, n, m) +/* handles a note in the abc */ +int decorators[DECSIZE]; +int mult; +char accidental, note; +int xoctave, n, m; +{ + int pitch; + int pitch_noacc; + int num, denom; + int octave; + + if (v == NULL) { + event_fatal_error("Internal error - no voice allocated"); + }; + octave = xoctave + v->octaveshift; + num = n; + denom = m; + if (v->inchord) v->chordcount = v->chordcount + 1; + if (tuplecount > 0) { + num = num * tfact_num; + denom = denom * tfact_denom; + if (tnote_num == 0) { + tnote_num = num; + tnote_denom = denom; + } else { + if (tnote_num * denom != num * tnote_denom) { + if (!specialtuple) { + event_warning("Different length notes in tuple"); + }; + }; + }; + if ((!gracenotes) && + ((!v->inchord) || ((v->inchord) && (v->chordcount == 1)))) { + tuplecount = tuplecount - 1; + }; + }; + if ((!v->ingrace) && (!v->inchord)) { + hornp(num, denom*(v->default_length)); + } else { + last_num = 3; /* hornpiping (>) cannot follow chord or grace notes */ + }; + if ((!v->ingrace) && ((!v->inchord)||(v->chordcount==1))) { + addunits(num, denom*(v->default_length)); + }; + pitch = pitchof(note, accidental, mult, octave, 1); + pitch_noacc = pitchof(note,0,0,octave,0); + if (decorators[FERMATA]) { + num = num*2; + }; + if (v->chordcount == 1) { + v->chord_num = num*4; + v->chord_denom = denom*(v->default_length); + }; + + pitchline[notes] = pitch_noacc; + addfeature(NOTE, pitch, num*4, denom*(v->default_length)); + marknote(); +} + +void event_microtone(int dir, int a, int b) +{ +} + +void event_normal_tone() +{ +} + + + +char *get_accidental(place, accidental) +/* read in accidental - used by event_handle_gchord() */ +char *place; /* place in string being parsed */ +char *accidental; /* pointer to char variable */ +{ + char *p; + + p = place; + *accidental = '='; + if (*p == '#') { + *accidental = '^'; + p = p + 1; + }; + if (*p == 'b') { + *accidental = '_'; + p = p + 1; + }; + return(p); +} + +void event_handle_gchord(s) +/* handler for the guitar chords */ +char* s; +{ +} + +void event_handle_instruction(s) +/* handler for ! ! instructions */ +/* does ppp pp p mp mf f ff fff */ +/* also does !drum! and !nodrum! */ +char* s; +{ +} + +static void setmap(sf, map, mult) +/* work out accidentals to be applied to each note */ +int sf; /* number of sharps in key signature -7 to +7 */ +char map[7]; +int mult[7]; +{ + int j; + + for (j=0; j<7; j++) { + map[j] = '='; + mult[j] = 1; + }; + if (sf >= 1) map['f'-'a'] = '^'; + if (sf >= 2) map['c'-'a'] = '^'; + if (sf >= 3) map['g'-'a'] = '^'; + if (sf >= 4) map['d'-'a'] = '^'; + if (sf >= 5) map['a'-'a'] = '^'; + if (sf >= 6) map['e'-'a'] = '^'; + if (sf >= 7) map['b'-'a'] = '^'; + if (sf <= -1) map['b'-'a'] = '_'; + if (sf <= -2) map['e'-'a'] = '_'; + if (sf <= -3) map['a'-'a'] = '_'; + if (sf <= -4) map['d'-'a'] = '_'; + if (sf <= -5) map['g'-'a'] = '_'; + if (sf <= -6) map['c'-'a'] = '_'; + if (sf <= -7) map['f'-'a'] = '_'; +} + +static void altermap(v, modmap, modmul) +/* apply modifiers to a set of accidentals */ +struct voicecontext* v; +char modmap[7]; +int modmul[7]; +{ + int i; + + for (i=0; i<7; i++) { + if (modmap[i] != ' ') { + v->basemap[i] = modmap[i]; + v->basemul[i] = modmul[i]; + }; + }; +} + +static void copymap(v) +/* sets up working map at the start of each bar */ +struct voicecontext* v; +{ + int j; + + for (j=0; j<7; j++) { + v->workmap[j] = v->basemap[j]; + v->workmul[j] = v->basemul[j]; + }; +} + +/* workaround for problems with PCC compiler */ +/* data may be written to an internal buffer */ + +int myputc(c) +char c; +{ + return (putc(c,fp)); +} + +static void addfract(xnum, xdenom, a, b) +/* add a/b to the count of units in the bar */ +int *xnum; +int *xdenom; +int a, b; +{ + *xnum = (*xnum)*b + a*(*xdenom); + *xdenom = (*xdenom) * b; + reduce(xnum, xdenom); +} + + +static void dotie(j, xinchord,voiceno) +/* called in preprocessing stage to handle ties */ +/* we need the voiceno in case a tie is broken by a */ +/* voice switch. */ +int j, xinchord,voiceno; +{ + int tienote, place; + int tietodo, done; + int lastnote, lasttie; + int inchord; + int tied_num, tied_denom; + int localvoiceno; + int samechord; + + /* find note to be tied */ + samechord = 0; + if (xinchord) samechord = 1; + tienote = j; + localvoiceno = voiceno; + while ((tienote > 0) && (feature[tienote] != NOTE) && + (feature[tienote] != REST)) { + tienote = tienote - 1; + }; + if (feature[tienote] != NOTE) { + event_error("Cannot find note before tie"); + } else { + inchord = xinchord; + /* change NOTE + TIE to TNOTE + REST */ + feature[tienote] = TNOTE; + feature[j] = REST; + num[j] = num[tienote]; + denom[j] = denom[tienote]; + place = j; + tietodo = 1; + lasttie = j; + tied_num = num[tienote]; + tied_denom = denom[tienote]; + lastnote = -1; + done = 0; + while ((place < notes) && (tied_num >=0) && (done == 0)) { + /* printf("%d %s %d %d/%d ",place,featname[feature[place]],pitch[place],num[place],denom[place]); */ + switch (feature[place]) { + case NOTE: + if(localvoiceno != voiceno) break; + lastnote = place; + if ((tied_num == 0) && (tietodo == 0)) { + done = 1; + }; + if ((pitchline[place] == pitchline[tienote]) + && (tietodo == 1) && (samechord == 0)) { + /* tie in note */ + if (tied_num != 0) { + event_error("Time mismatch at tie"); + }; + tietodo = 0; + pitch[place] = pitch[tienote]; /* in case accidentals did not + propagate */ + /* add time to tied time */ + addfract(&tied_num, &tied_denom, num[place], denom[place]); + /* add time to tied note */ + addfract(&num[tienote], &denom[tienote], num[place], denom[place]); + /* change note to a rest */ + feature[place] = REST; + /* get rid of tie */ + if (lasttie != j) { + feature[lasttie] = OLDTIE; + }; + }; + if (inchord == 0) { + /* subtract time from tied time */ + addfract(&tied_num, &tied_denom, -num[place], denom[place]); + }; + break; + case REST: + if(localvoiceno != voiceno) break; + if ((tied_num == 0) && (tietodo == 0)) { + done = 1; + }; + if (inchord == 0) { + /* subtract time from tied time */ + addfract(&tied_num, &tied_denom, -num[place], denom[place]); + }; + break; + case TIE: + if(localvoiceno != voiceno) break; + if (lastnote == -1) { + event_error("Bad tie: possibly two ties in a row"); + } else { + if (pitch[lastnote] == pitch[tienote] && samechord == 0) { + lasttie = place; + tietodo = 1; + if (inchord) samechord = 1; + }; + }; + break; + case CHORDON: + if(localvoiceno != voiceno) break; + inchord = 1; + break; + case CHORDOFF: + case CHORDOFFEX: + samechord = 0; + if(localvoiceno != voiceno) break; + inchord = 0; + /* subtract time from tied time */ + addfract(&tied_num, &tied_denom, -num[place], denom[place]); + break; + case VOICE: + localvoiceno = pitch[place]; + default: + break; + }; + /*printf("tied_num = %d done = %d inchord = %d\n",tied_num, done, inchord); */ + place = place + 1; + }; + if (tietodo == 1) { + event_error("Could not find note to be tied"); + }; + }; +/* printf("dotie finished\n"); */ +} + +static void tiefix() +/* connect up tied notes and cleans up the */ +/* note lengths in the chords (eg [ace]3 ) */ +{ + int j; + int inchord; + int chord_num = 0, chord_denom = 0; + int chord_start,chord_end; + int voiceno; + + j = 0; + inchord = 0; + voiceno = 1; + while (j 0) { + event_playonrep(replist); + }; +/* + if (type == BAR1) { + addfeature(PLAY_ON_REP, 0, 0, 1); + }; + if (type == REP_BAR2) { + addfeature(PLAY_ON_REP, 0, 0, 2); + }; +*/ +} + + + + +void startfile() +/* called at the beginning of an abc tune by event_refno */ +/* This sets up all the default values */ +{ + int j; + + if (verbose) { + printf("scanning tune\n"); + }; + /* set up defaults */ + sf = 0; + mi = 0; + setmap(0, global.basemap, global.basemul); + copymap(&global); + global.octaveshift = 0; + voicecount = 0; + head = NULL; + v = NULL; + time_num = 4; + time_denom = 4; + timesigset = 0; + barchecking = 1; + global.default_length = -1; + event_tempo(120, 1, 4, 0,NULL, NULL); + notes = 0; + ntexts = 0; + gfact_num = 1; + gfact_denom = 3; + global_transpose = 0; + hornpipe = 0; + karaoke = 0; + retain_accidentals = 1; + ratio_a = 2; + ratio_b = 4; + wcount = 0; + parts = -1; + middle_c = 60; + for (j=0; j<26; j++) { + part_start[j] = -1; + }; + headerpartlabel = 0; + additive = 1; + initvstring(&part); + } + + +static void headerprocess() +/* called after the K: field has been reached, signifying the end of */ +/* the header and the start of the tune */ +{ + int t_num, t_denom; + + if (headerpartlabel == 1) { + part_start[(int)part.st[0] - (int)'A'] = notes; + addfeature(PART, part.st[0], 0, 0); + }; + addfeature(DOUBLE_BAR, 0, 0, 0); + pastheader = 1; + + gracenotes = 0; /* not in a grace notes section */ + if (!timesigset) { + event_warning("No M: in header, using default"); + }; + /* calculate time for a default length note */ + if (global.default_length == -1) { + if (((float) time_num)/time_denom < 0.75) { + global.default_length = 16; + } else { + global.default_length = 8; + }; + }; + bar_num = 0; + bar_denom = 1; + set_meter(time_num, time_denom); + if (hornpipe) { + if ((time_denom != 4) || ((time_num != 2) && (time_num != 4))) { + event_error("Hornpipe must be in 2/4 or 4/4 time"); + hornpipe = 0; + }; + }; + + tempounits(&t_num, &t_denom); + /* make tempo in terms of 1/4 notes */ +/* tempo = (long) 60*1000000*t_denom/(Qtempo*4*t_num); */ +/* div_factor = division; */ + voicesused = 0; +} + +void event_key(sharps, s, modeindex, modmap, modmul, gotkey, gotclef, clefname, + octave, transpose, gotoctave, gottranspose) +/* handles a K: field */ +int sharps; /* sharps is number of sharps in key signature */ +int modeindex; /* 0 major, 1,2,3 minor, 4 locrian, etc. */ +char *s; /* original string following K: */ +char modmap[7]; /* array of accidentals to be applied */ +int modmul[7]; /* array giving multiplicity of each accent (1 or 2) */ +int gotkey, gotclef; +int octave, transpose, gotoctave, gottranspose; +char* clefname; +{ + int minor; + if (modeindex >0 && modeindex <4) minor = 1; + if ((dotune) && gotkey) { + if (pastheader) { + setmap(sharps, v->basemap, v->basemul); + altermap(v, modmap, modmul); + copymap(v); + addfeature(KEY, sharps, 0, minor); + if (gottranspose) { + addfeature(TRANSPOSE, transpose, 0, 0); + }; + } else { + if (gottranspose) { + global_transpose = transpose; + }; + setmap(sharps, global.basemap, global.basemul); + altermap(&global, modmap, modmul); + copymap(&global); + sf = sharps; + mi = minor; + headerprocess(); + v = newvoice(1); + head = v; + }; + if (gotoctave) { + event_octave(octave,0); + }; + }; +} + + + +void print_feature_list () +{ +int i,length; +float fract; +printf("feature list \n"); +for (i=0;i -1) { + addfeature(PART, ' ', 0, 0); + }; + if (headerpartlabel == 1) { + event_error("P: field in header should go after K: field"); + }; + + tiefix(); + + + }; + for (i=0; i -#include "abc.h" -#include "parseabc.h" -#include "parser2.h" - -void event_info(s) -char* s; -/* An I: field has been encountered. This routine scans the following */ -/* text to extract items of the form key=value */ -{ - char* key; - char* endkey; - char* value; - char* endvalue; - char* lastendvalue; - char* newword; - char* lastnewword; - char* ptr; - int doval; - - ptr = s; - doval = 0; - while (*ptr != '\0') { - if (doval == 0) { - /* look for key */ - skipspace(&ptr); - key = ptr; - while ((*ptr != '\0') && (*ptr != ' ') && (*ptr != '=')) { - ptr = ptr + 1; - }; - endkey = ptr; - skipspace(&ptr); - if (*ptr == '=') { - doval = 1; - ptr = ptr + 1; - skipspace(&ptr); - value = ptr; - newword = ptr; - endvalue = NULL; - lastendvalue = NULL; - } else { - key = ptr; - }; - } else { - /* look for value */ - skipspace(&ptr); - while ((*ptr != '\0') && (*ptr != ' ') && (*ptr != '=')) { - ptr = ptr + 1; - }; - lastendvalue = endvalue; - endvalue = ptr; - skipspace(&ptr); - lastnewword = newword; - newword = ptr; - if (*ptr == '\0') { - *endkey = '\0'; - *endvalue = '\0'; - event_info_key(key, value); - } else { - if (*ptr == '=') { - *endkey = '\0'; - if (lastendvalue == NULL) { - event_error("missing key or value in I: field"); - } else { - *lastendvalue = '\0'; - event_info_key(key, value); - }; - key = lastnewword; - endkey = endvalue; - doval = 1; - ptr = ptr + 1; - skipspace(&ptr); - value = ptr; - endvalue = NULL; - lastendvalue = NULL; - }; - }; - }; - }; -} - - -static void splitstring(s, sep, handler) -/* breaks up string into fields with sep as the field separator */ -/* and calls handler() for each sub-string */ -char* s; -char sep; -void (*handler)(); -{ - char* out; - char* p; - int fieldcoming; - - p = s; - fieldcoming = 1; - while (fieldcoming) { - out = p; - while ((*p != '\0') && (*p != sep)) p = p + 1; - if (*p == sep) { - *p = '\0'; - p = p + 1; - } else { - fieldcoming = 0; - }; - (*handler)(out); - }; -} - -void event_gchord(s) -/* handles guitar chords " ... " */ -char* s; -{ - splitstring(s, ';', event_handle_gchord); -} - -void event_instruction(s) -/* handles a ! ... ! event in the abc */ -char* s; -{ - splitstring(s, ';', event_handle_instruction); -} - -void event_slur(t) -int t; -/* handles old 's' notation for slur on/slur off */ -{ - if (t) { - event_sluron(1); - } else { - event_sluroff(0); - }; -} - -void event_reserved(char s) -/* handles H - Z encountered in abc */ -{ - char *expansion; - - expansion = lookup_abbreviation(s); - if (expansion != NULL) { - event_handle_instruction(expansion); - } else { - event_x_reserved(s); - }; -} +/* parser2.c - further parsing */ +/* part of abc2midi and yaps */ +/* implements event_info, event_instruction, event_gchord and event_slur */ +/* also implements event_reserved */ +/* parser2 requires parseabc, but parseabc does not need parser2 */ + +#include +#include "abc.h" +#include "parseabc.h" +#include "parser2.h" + +void event_info(s) +char* s; +/* An I: field has been encountered. This routine scans the following */ +/* text to extract items of the form key=value */ +{ + char* key = NULL; + char* endkey = NULL; + char* value = NULL; + char* endvalue = NULL; + char* lastendvalue; + char* newword = NULL; + char* lastnewword; + char* ptr; + int doval; + + ptr = s; + doval = 0; + while (*ptr != '\0') { + if (doval == 0) { + /* look for key */ + skipspace(&ptr); + key = ptr; + while ((*ptr != '\0') && (*ptr != ' ') && (*ptr != '=')) { + ptr = ptr + 1; + }; + endkey = ptr; + skipspace(&ptr); + if (*ptr == '=') { + doval = 1; + ptr = ptr + 1; + skipspace(&ptr); + value = ptr; + newword = ptr; + endvalue = NULL; + lastendvalue = NULL; + } else { + key = ptr; + }; + } else { + /* look for value */ + skipspace(&ptr); + while ((*ptr != '\0') && (*ptr != ' ') && (*ptr != '=')) { + ptr = ptr + 1; + }; + lastendvalue = endvalue; + endvalue = ptr; + skipspace(&ptr); + lastnewword = newword; + newword = ptr; + if (*ptr == '\0') { + *endkey = '\0'; + *endvalue = '\0'; + event_info_key(key, value); + } else { + if (*ptr == '=') { + *endkey = '\0'; + if (lastendvalue == NULL) { + event_error("missing key or value in I: field"); + } else { + *lastendvalue = '\0'; + event_info_key(key, value); + }; + key = lastnewword; + endkey = endvalue; + doval = 1; + ptr = ptr + 1; + skipspace(&ptr); + value = ptr; + endvalue = NULL; + lastendvalue = NULL; + }; + }; + }; + }; +} + + +static void splitstring(s, sep, handler) +/* breaks up string into fields with sep as the field separator */ +/* and calls handler() for each sub-string */ +char* s; +char sep; +void (*handler)(); +{ + char* out; + char* p; + int fieldcoming; + + p = s; + fieldcoming = 1; + while (fieldcoming) { + out = p; + while ((*p != '\0') && (*p != sep)) p = p + 1; + if (*p == sep) { + *p = '\0'; + p = p + 1; + } else { + fieldcoming = 0; + }; + (*handler)(out); + }; +} + +void event_gchord(s) +/* handles guitar chords " ... " */ +char* s; +{ + splitstring(s, ';', event_handle_gchord); +} + +void event_instruction(s) +/* handles a ! ... ! event in the abc */ +char* s; +{ + splitstring(s, ';', event_handle_instruction); +} + +void event_slur(t) +int t; +/* handles old 's' notation for slur on/slur off */ +{ + if (t) { + event_sluron(1); + } else { + event_sluroff(0); + }; +} + +void event_reserved(char s) +/* handles H - Z encountered in abc */ +{ + char *expansion; + + expansion = lookup_abbreviation(s); + if (expansion != NULL) { + event_handle_instruction(expansion); + } else { + event_x_reserved(s); + }; +} --- abcmidi-20070318.orig/toabc.c +++ abcmidi-20070318/toabc.c @@ -1,2370 +1,2373 @@ -/* - * toabc.c - part of abc2abc - program to manipulate abc files. - * Copyright (C) 1999 James Allwright - * e-mail: J.R.Allwright@westminster.ac.uk - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -/* back-end for outputting (possibly modified) abc */ - -#define VERSION "1.56 December 21 2006" - -/* for Microsoft Visual C++ 6.0 or higher */ -#ifdef _MSC_VER -#define ANSILIBS -#endif - -#include "abc.h" -#include "parseabc.h" -#include - -/* define USE_INDEX if your C libraries have index() instead of strchr() */ -#ifdef USE_INDEX -#define strchr index -#endif - -#ifdef ANSILIBS -#include -#include -#include -#else -extern char* strchr(); -#endif - -#define MAX_VOICES 30 -/* should be plenty! */ - -programname fileprogram = ABC2ABC; -extern int oldchordconvention; /* for handling +..+ chords */ - -struct fract { - int num; - int denom; -}; -struct fract barlen; /* length of a bar as given by the time signature */ -struct fract unitlen; /* unit length as given by the L: field */ -struct fract count; /* length of bar so far */ -struct fract prevcount; /* length of bar before last increment */ -struct fract tuplefactor; /* factor associated with a tuple (N */ -struct fract breakpoint; /* used to break bar into beamed sets of notes */ -int barno; /* number of bar within tune */ -int newspacing; /* was -s option selected ? */ -int barcheck, repcheck; /* indicate -b and -r options selected */ -int echeck; /* was error-checking turned off ? (-e option) */ -int newbreaks; /* was -n option selected ? */ -int nodouble_accidentals; -int totalnotes, notecount; -int bars_per_line; /* number supplied after -n option */ -int barcount; -int expect_repeat; -int tuplenotes, barend; -int xinhead, xinbody; /* are we in head or body of abc tune ? */ -int inmusic; /* are we in a line of notes (in the tune body) ? */ -int startline, blankline; -int transpose; /* number of semitones to transpose by (-t option) */ -struct fract lenfactor; /* fraction to scale note lengths; -v,-d options */ -int newkey; /* key after transposition (expressed as no. of sharps) */ -int lines; /* used by transposition */ -int orig_key_number; /* used for gchord transposition */ -int new_key_number; /* used for gchord transposition */ -int oldtable[7], newtable[7]; /* for handling transposition */ -int inchord; /* are we in a chord [ ] ? */ -int ingrace; /* are we in a grace note set { } ? */ -int chordcount; /* number of notes or rests in current chord */ -int inlinefield; /* boolean - are we in [: ] ? */ -int cleanup; /* boolean to indicate -u option (update notation) */ -char tmp[2000]; /* buffer to hold abc output being assembled */ -int output_on = 1; /* if 0 suppress output */ -int selected_voice = -1; /* no voice was selected */ -int newrefnos; /* boolean for -X option (renumber X: fields) */ -int newref; /* next new number for X: field */ -int useflats=0; /* flag associated with nokey.*/ -int adapt_useflats_to_gchords = 1; /* experimental flag */ -int usekey = 0; -int drumchan=0; /* flag to suppress transposition */ - -extern int nokey; /* signals no key signature assumed */ -extern int voicecodes ; /* from parseabc.c */ -extern char voicecode[16][30]; /*for interpreting V: string */ - -struct voicetype { /* information needed for each voice */ - int number; /* voice number from V: field */ - int barcount; - int foundbar; - struct abctext* currentline; - int bars_remaining; - int bars_complete; - int drumchan; -} voice[MAX_VOICES]; -int voicecount, this_voice, next_voice; -enum abctype {field, bar, barline}; -/* linestat is used by -n for deciding when to generate a newline */ -enum linestattype {fresh, midmusic, endmusicline, postfield}; -enum linestattype linestat; -/* struct abctext is used to store abc lines for re-formatting (-n option) */ -struct lyricwords{ - struct lyricwords* nextverse; - char* words; -}; -struct abctext{ /* linked list used to store output before re-formatting */ - struct abctext* next; - char* text; - enum abctype type; - int notes; - struct lyricwords* lyrics; -}; -struct abctext* head; -struct abctext* tail; - -extern char *mode[]; -extern int modekeyshift[]; -int basemap[7], workmap[7]; /* for -nokey and pitchof() */ -int workmul[7]; -void copymap(); -void printpitch(int); -void setup_sharps_flats (int sf); -int pitchof(char note,int accidental,int mult,int octave); - - -static int purgespace(p) -char* p; -/* if string p is empty or consists of spaces, set p to the empty string */ -/* and return 1, otherwise return 0. Used to test tmp */ -/* part of new linebreak option (-n) */ -{ - int blank; - char *s; - - blank = 1; - s = p; - while (*s != '\0') { - if (*s != ' ') blank = 0; - s = s + 1; - }; - if (blank) { - *p = '\0'; - }; - return(blank); -} - -int zero_barcount(foundbar) -/* initialize bar counter for abctext elements */ -/* part of new linebreak option (-n) */ -int *foundbar; -{ - *foundbar = 0; - return(0); -} - -int new_barcount(type, foundbar, oldcount) -enum abctype type; -int *foundbar; -int oldcount; -/* work out whether we have reached the end of a bar in abctext elements */ -/* and increment barcount if we have */ -/* part of new linebreak option (-n) */ -{ - int new_value; - - new_value = oldcount; - if (type == bar) { - *foundbar = 1; - }; - if ((type == barline) && (*foundbar == 1)) { - new_value = new_value + 1; - *foundbar = 0; - }; - return(new_value); -} - - -static void setline(t) -enum linestattype t; -/* generates newline, or continuation, or nothing at all */ -/* part of new linebreak option (-n) */ -{ - if ((t == fresh) && ((linestat == postfield) || (linestat == endmusicline))) { - printf("\n"); - }; - if ((t == fresh) && (linestat == midmusic)) { - printf("\\\n"); - }; - linestat = t; -} - -static int flush_abctext(bars, termination) -int bars; -enum linestattype termination; -/* outputs up to the specified number of bars of stored music */ -/* and frees up the storage allocated for those bars. */ -/* returns the number of bars actually output */ -/* part of new linebreak option (-n) */ -{ - struct abctext *p, *nextp; - struct lyricwords *q, *r; - struct lyricwords *barlyrics; - int count, donewords, wordline; - int i, foundtext; - int foundbar; - - /* printf("flush_abctext called\n"); */ - /* print music */ - p = head; - count = zero_barcount(&foundbar); - while ((p != NULL) && (count < bars)) { - if (p->type == field) { - setline(fresh); - }; - printf("%s", p->text); - if (p->type == field) { - setline(postfield); - setline(fresh); - } else { - setline(midmusic); - }; - count = new_barcount(p->type, &foundbar, count); - if ((count == bars) && (p->type == barline)) { - setline(endmusicline); - }; - p = p->next; - }; - if (linestat == midmusic) { - setline(termination); - }; - if (bars > 0) { - /* print out any w: lines */ - donewords = 0; - wordline = 0; - while (donewords == 0) { - p = head; - foundtext = 0; - count = zero_barcount(&foundbar); - while ((p != NULL) && (count < bars)) { - barlyrics = p->lyrics; - for (i=0; inextverse; - }; - }; - if (barlyrics != NULL) { - if (foundtext == 0) { - setline(fresh); - printf("w:"); - foundtext = 1; - }; - printf(barlyrics->words); - }; - count = new_barcount(p->type, &foundbar, count); - p = p->next; - }; - if (foundtext == 0) { - donewords = 1; - } else { - setline(postfield); - setline(fresh); - }; - wordline = wordline + 1; - }; - }; - /* move head on and free up space used by stuff printed out */ - count = zero_barcount(&foundbar); - p = head; - foundbar = 0; - while ((p != NULL) && (count < bars)) { - if (p != NULL) { - free(p->text); - q = p->lyrics; - while (q != NULL) { - free(q->words); - r = q->nextverse; - free(q); - q = r; - }; - count = new_barcount(p->type, &foundbar, count); - nextp = p->next; - free(p); - p = nextp; - }; - head = p; - }; - if (head == NULL) { - tail = NULL; - }; - return(count); -} - -void complete_bars(v) -/* mark all bars as completed (i.e. having associated w: fields parsed) */ -/* and out put all music lines which contain the full set of bars */ -/* part of new linebreak option (-n) */ -struct voicetype *v; -{ - int bars_done; - - v->bars_complete = v->bars_complete + v->barcount; - v->barcount = 0; - while (v->bars_complete > v->bars_remaining) { - bars_done = flush_abctext(v->bars_remaining, endmusicline); - setline(fresh); - v->bars_complete = v->bars_complete - bars_done; - v->bars_remaining = v->bars_remaining - bars_done; - if (v->bars_remaining == 0) { - v->bars_remaining = bars_per_line; - }; - }; -} - -void complete_all(v, termination) -struct voicetype *v; -enum linestattype termination; -/* output all remaining music and fields */ -/* part of new linebreak option (-n) */ -{ - int bars_done; - - complete_bars(v); - bars_done = flush_abctext(v->bars_remaining+1, termination); - v->bars_complete = v->bars_complete - bars_done; - v->bars_remaining = v->bars_remaining - bars_done; - if (v->bars_remaining == 0) { - v->bars_remaining = bars_per_line; - }; - head = NULL; - tail = NULL; - voice[this_voice].currentline = NULL; -} - -static struct abctext* newabctext(t) -enum abctype t; -/* called at newlines and barlines */ -/* adds current output text to linked list structure */ -/* part of new linebreak option (-n) */ -{ - struct abctext* p; - - if (output_on == 0) { - p = NULL; - return(p); - }; - if (newbreaks) { -/* - if ((t == field) && (!xinbody || (this_voice != next_voice))) { -*/ - if (t == field) { - complete_all(&voice[this_voice], midmusic); - this_voice = next_voice; - }; - p = (struct abctext*) checkmalloc(sizeof(struct abctext)); - p->text = addstring(tmp); - tmp[0] = '\0'; - p->next = NULL; - p->type = t; - p->lyrics = NULL; - if (t == bar) { - p->notes = notecount; - totalnotes = totalnotes + notecount; - notecount = 0; - } else { - p->notes = 0; - }; - if (xinbody) { - voice[this_voice].barcount = new_barcount(t, - &voice[this_voice].foundbar, - voice[this_voice].barcount); - }; - if (head == NULL) { - head = p; - tail = p; - } else { - tail->next = p; - tail = p; - }; - if ((t != field) && (voice[this_voice].currentline == NULL)) { - voice[this_voice].currentline = p; - }; - } else { - printf("%s", tmp); - tmp[0] = '\0'; - p = NULL; - }; - inmusic = 1; - return(p); -} - -static int nextnotes() -/* return the number of notes in the next bar */ -/* part of new linebreak option (-n) */ -{ - 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); -} - -static void 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; -} - - -static void addunits(n, m) -int n, m; -/* add fraction n/m to count */ -{ - prevcount = count; /* in case of chord extension eg [CE]3/2 */ - count.num = n*count.denom + count.num*(m*unitlen.denom); - count.denom = (m*unitlen.denom)*count.denom; - reduce(&count.num, &count.denom); -} - -static void repudiate_lastaddunits() -{ - count = prevcount; -} - -void event_init(argc, argv, filename) -int argc; -char* argv[]; -char** filename; -/* routine called on program start-up */ -{ - int targ, narg; - - if ((getarg("-h", argc, argv) != -1) || (argc < 2)) { - printf("abc2abc version %s\n",VERSION); - printf("Usage: abc2abc [-s] [-n X] [-b] [-r] [-e] [-t X]\n"); - printf(" [-u] [-d] [-v] [-V X] [-ver] [-X n]\n"); - printf(" -s for new spacing\n"); - printf(" -n X to re-format the abc with a new linebreak every X bars\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(" -nda No double accidentals in guitar chords\n"); - printf(" -nokeys No key signature. Use sharps\n"); - printf(" -nokeyf No key signature. Use flats\n"); - printf(" -u to update notation ([] for chords and () for slurs)\n"); - printf(" -usekey n Use key signature sf (sharps/flats)\n"); - printf(" -d to notate with doubled note lengths\n"); - printf(" -v to notate with halved note lengths\n"); - printf(" -V X to output only voice X\n"); - printf(" -ver prints version number and exits\n"); - printf(" -X n renumber the all X: fields as n, n+1, ..\n"); - printf(" -OCC old chord convention (eg. +CE+)\n"); - - exit(0); - } else { - *filename = argv[1]; - }; - nodouble_accidentals = 0; /* use correct guitar chords */ - if (getarg("-ver",argc,argv) != -1) { - printf("%s\n",VERSION); - exit(0); - } - if (getarg("-u", argc, argv) == -1) { - cleanup = 0; - } else { - cleanup = 1; - oldchordconvention = 1; - }; - if (getarg("-s", argc, argv) == -1) { - newspacing = 0; - } else { - newspacing = 1; - }; - narg = getarg("-X", argc, argv); - if (narg == -1) { - newrefnos = 0; - } else { - newrefnos = 1; - if (narg < argc) { - newref = readnumf(argv[narg]); - } else { - newref = 1; - }; - }; - if (getarg("-e", argc, argv) == -1) { - echeck = 1; - } else { - echeck = 0; - }; - narg = getarg("-n", argc, argv); - if (narg == -1) { - newbreaks = 0; - } else { - newbreaks = 1; - if (narg >= argc) { - event_error("No value for bars per line after -n"); - bars_per_line = 4; - } else { - bars_per_line = readnumf(argv[narg]); - if (bars_per_line < 1) { - bars_per_line = 4; - }; - }; - }; - if (getarg("-b", argc, argv) != -1) { - barcheck = 0; - } else { - barcheck = 1; - }; - if (getarg("-r", argc, argv) != -1) { - repcheck = 0; - } else { - repcheck = 1; - }; - if (getarg("-v", argc, argv) != -1) { - lenfactor.num = 1; - lenfactor.denom = 2; - } else { - if (getarg("-d", argc, argv) != -1) { - lenfactor.num = 2; - lenfactor.denom = 1; - } else { - lenfactor.num = 1; - lenfactor.denom = 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]); - }; - }; - }; - targ = getarg("-nda",argc,argv); - if (targ != -1) nodouble_accidentals = 1; - - targ = getarg("-nokeys",argc,argv); - if (targ != -1) nokey=1; - - targ = getarg("-nokeyf",argc,argv); - if (targ != -1) {nokey=1; useflats=1;} - - targ = getarg("-V", argc, argv); - if (targ != -1) { - selected_voice = readnumf(argv[targ]); - }; - - targ = getarg("-usekey",argc,argv); - if (targ != -1) { - usekey = readsnumf(argv[targ]); - nokey = 1; - if (usekey < 0) useflats=1; - if (usekey <-5) usekey = -5; - if (usekey >5) usekey = 5; - setup_sharps_flats (usekey); - } - if (getarg("-OCC",argc,argv) != -1) oldchordconvention=1; - - /* 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; -} - -void emit_string(s) -char *s; -/* output string */ -{ - if (output_on) { - strcpy(tmp+strlen(tmp), s); - }; -} - -void emit_char(ch) -char ch; -/* output single character */ -{ - char *place; - - if (output_on) { - place = tmp+strlen(tmp); - *place = ch; - *(place+1) = '\0'; - }; -} - -void emit_int(n) -int n; -/* output integer */ -{ - if (output_on) { - sprintf(tmp+strlen(tmp), "%d", n); - }; -} - -void emit_string_sprintf(s1, s2) -char *s1; -char *s2; -/* output string containing string expression %s */ -{ - if (output_on) { - sprintf(tmp+strlen(tmp), s1, s2); - }; -} - -void emit_int_sprintf(s, n) -char *s; -int n; -/* output string containing int expression %d */ -{ - if (output_on) { - sprintf(tmp+strlen(tmp), s, n); - }; -} - -void unemit_inline() -/* remove previously output start of inline field */ -/* needed for -V voice selection option */ -{ - int len; - - len = strlen(tmp); - if ((len > 0) && (tmp[len-1] == '[')) { - tmp[len-1] = '\0'; /* delete last character */ - } else { - event_error("Internal error - Could not delete ["); - }; -} - -static void close_newabc() -/* output all remaining abc_text elements */ -/* part of new linebreak option (-n) */ -{ - if (newbreaks) { - complete_all(&voice[this_voice], endmusicline); - if (linestat == midmusic) setline(endmusicline); - setline(fresh); - }; -} - -void event_eof() -{ - close_newabc(); -} - -void event_blankline() -{ - output_on = 1; - close_newabc(); -/* if (newbreaks) [SS] 2006-09-23 */ printf("\n"); - xinbody = 0; - xinhead = 0; - parseroff(); - blankline = 1; -} - -void event_text(p) -char *p; -{ - emit_string_sprintf("%%%s", p); - inmusic = 0; -} - -void event_reserved(p) -char p; -{ - emit_char(p); - inmusic = 0; -} - -void event_tex(s) -char *s; -{ - emit_string(s); - inmusic = 0; -} - -void event_linebreak() -{ - if (newbreaks) { - if (!purgespace(tmp)) { - if (inmusic) { - newabctext(bar); - } else { - newabctext(field); - }; - }; - } else { - newabctext(bar); - if (output_on) { - printf("\n"); - }; - /* don't output new line if voice is already suppressed - otherwise we will get lots of blank lines where we - are suppressing output. [SS] feb-10-2002. - */ - }; -} - -void event_startmusicline() -/* encountered the start of a line of notes */ -{ - voice[this_voice].currentline = NULL; - complete_bars(&voice[this_voice]); -} - -void event_endmusicline(endchar) -char endchar; -/* encountered the end of a line of notes */ -{ -} - -void event_error(s) -char *s; -{ - if (echeck) { - printf("\n%%Error : %s\n", s); - }; -} - -void event_warning(s) -char *s; -{ - if (echeck) { - printf("\n%%Warning : %s\n", s); - }; -} - -void event_comment(s) -char *s; -{ - if (newbreaks && (!purgespace(tmp))) { - if (inmusic) { - newabctext(bar); - } else { - newabctext(field); - }; - }; - emit_string_sprintf("%%%s", s); - inmusic = 0; -} - -void event_specific(package, s) -char *package, *s; -{ - char command[40]; - int ch; - char *p; - emit_string("%%"); - emit_string(package); - emit_string(s); - inmusic = 0; -/* detect drum channel by searching for %%MIDI channel 10 */ - if (strcmp(package,"MIDI") != 0) return; - p = s; - skipspace(&p); - readstr(command, &p, 40); - if (strcmp(command, "channel") != 0) return; - skipspace(&p); - ch = readnump(&p); - if(ch == 10) { - voice[next_voice].drumchan = 1; - drumchan = 1; - } -/* printf("event_specific: next_voice = %d\n",next_voice); */ -} - -void event_info(f) -/* handles info field I: */ -char *f; -{ - emit_string_sprintf("I:%s", f); - inmusic = 0; -} - - -void event_field(k, f) -char k; -char *f; -{ - emit_char(k); - emit_char(':'); - emit_string(f); - inmusic = 0; -} - -struct abctext* getbar(place) -struct abctext *place; -/* find first element in list which is a bar of music */ -{ - struct abctext *newplace; - - newplace = place; - while ((newplace != NULL) && - ((newplace->type != bar) || - (newplace->notes == 0))) { - newplace = newplace->next; - }; - return(newplace); -} - -struct abctext* getnextbar(place) -struct abctext *place; -/* find next element in list which is a bar of music */ -{ - struct abctext *newplace; - - newplace = place; - if (newplace != NULL) { - newplace = getbar(newplace->next); - }; - return(newplace); -}; - -void append_lyrics(place, newwords) -struct abctext *place; -char *newwords; -/* add lyrics to end of lyric list associated with bar */ -{ - struct lyricwords* new_words; - struct lyricwords *new_place; - - if (place == NULL) { - return; - }; - /* printf("append_lyrics has %s at %s\n", newwords, place->text); */ - new_words = (struct lyricwords*)checkmalloc(sizeof(struct lyricwords)); - /* add words to bar */ - new_words->nextverse = NULL; - new_words->words = addstring(newwords); - if (place->lyrics == NULL) { - place->lyrics = new_words; - } else { - new_place = place->lyrics; - /* find end of list */ - while (new_place->nextverse != NULL) { - new_place = new_place->nextverse; - }; - new_place->nextverse = new_words; - }; -} - -struct abctext* apply_bar(syll, place, notesleft, barwords) -/* advance to next bar (on finding '|' in a w: field) */ -char* syll; -struct abctext *place; -int *notesleft; -struct vstring *barwords; -{ - struct abctext* new_place; - - if (place == NULL) { - return(NULL); - }; - new_place = place; - addtext(syll, barwords); - append_lyrics(place, barwords->st); - /* go on to next bar */ - clearvstring(barwords); - new_place = getnextbar(place); - if (new_place != NULL) { - *notesleft = new_place->notes; - }; - return(new_place); -} - -struct abctext* apply_syllable(syll, place, notesleft, barwords) -/* attach syllable to appropriate place in abctext structure */ -char* syll; -struct abctext *place; -int *notesleft; -struct vstring *barwords; -{ - struct abctext* new_place; - char msg[80]; - - if (place == NULL) { - sprintf(msg, "Cannot find note to match \"%s\"", syll); - event_error(msg); - return(NULL); - }; - new_place = place; - addtext(syll, barwords); - *notesleft = *notesleft - 1; - if (*notesleft == 0) { - append_lyrics(place, barwords->st); - /* go on to next bar */ - clearvstring(barwords); - new_place = getnextbar(place); - if (new_place != NULL) { - *notesleft = new_place->notes; - }; - }; - return(new_place); -} - -void parse_words(p) -char* p; -/* Break up a line of lyrics (w: ) into component syllables */ -{ - struct vstring syll; - struct vstring barwords; - char* q; - unsigned char ch; - int errors; - int found_hyphen; - - struct abctext *place; - int notesleft; - - if (!xinbody) { - event_error("w: field outside tune body"); - return; - }; - place = getbar(voice[this_voice].currentline); - if (place == NULL) { - event_error("No music to match w: line to"); - return; - }; - notesleft = voice[this_voice].currentline->notes; - initvstring(&barwords); - errors = 0; - if (place == NULL) { - event_error("No notes to match words"); - return; - }; - initvstring(&syll); - q = p; - skipspace(&q); - while (*q != '\0') { - found_hyphen = 0; - clearvstring(&syll); - ch = *q; - while(ch=='|') { - addch('|', &syll); - addch(' ', &syll); - place = apply_bar(syll.st, place, ¬esleft, &barwords); - clearvstring(&syll); - q++; - ch = *q; - }; - /* PCC seems to require (ch != ' ') on the next line */ - /* presumably PCC's version of ispunct() thinks ' ' is punctuation */ - while (((ch>127)||isalnum(ch)||ispunct(ch))&&(ch != ' ')&& - (ch != '_')&&(ch != '-')&&(ch != '*')&& (ch != '|')) { - if ((ch == '\\') && (*(q+1)=='-')) { - addch('\\', &syll); - ch = '-'; - q++; - }; - /* syllable[i] = ch; */ - addch(ch, &syll); - q++; - ch = *q; - }; - skipspace(&q); - if (ch == '-') { - found_hyphen = 1; - addch(ch, &syll); - while (isspace(ch)||(ch=='-')) { - q++; - ch = *q; - }; - }; - if (syll.len > 0) { - if (!found_hyphen) { - addch(' ', &syll); - }; - place = apply_syllable(syll.st, place, ¬esleft, &barwords); - } else { - if (ch=='_') { - clearvstring(&syll); - addch('_', &syll); - addch(' ', &syll); - place = apply_syllable(syll.st, place, ¬esleft, &barwords); - q++; - ch = *q; - }; - if (ch=='*') { - clearvstring(&syll); - addch('*', &syll); - addch(' ', &syll); - place = apply_syllable(syll.st, place, ¬esleft, &barwords); - q++; - ch = *q; - }; - }; - }; - if (errors > 0) { - event_error("Lyric line too long for music"); - } else { - clearvstring(&syll); - }; - freevstring(&syll); -} - -void event_words(p, continuation) -char* p; -int continuation; -/* a w: field has been encountered */ -{ - struct vstring afield; - - if (xinbody && newbreaks) { - parse_words(p); - } else { - initvstring(&afield); - addtext(p, &afield); - if (continuation) { - addch(' ', &afield); - addch('\\', &afield); - }; - event_field('w', afield.st); - }; -} - -void event_part(s) -char* s; -{ - if (xinbody) { - complete_bars(&voice[this_voice]); - }; - emit_string_sprintf("P:%s", s); - inmusic = 0; -} - -int setvoice(num) -int num; -/* we need to keep track of current voice for new linebreak handling (-n) */ -/* change voice to num. If voice does not exist, start new one */ -{ - int i, voice_index; - - i = 0; - while ((i < voicecount) && (voice[i].number != num)) { - i = i + 1; - }; - if ((i < voicecount) && (voice[i].number == num)) { - voice_index = i; - drumchan = voice[voice_index].drumchan; -/* printf("voice_index = %d drumchan = %d\n",voice_index,drumchan); */ - } else { - voice_index = voicecount; - if (voicecount < MAX_VOICES) { - voicecount = voicecount + 1; - } else { - event_error("Number of voices exceeds static limit MAX_VOICES"); - }; - voice[voice_index].number = num; - voice[voice_index].barcount = zero_barcount(&voice[voice_index].foundbar); - voice[voice_index].bars_complete = 0; - voice[voice_index].bars_remaining = bars_per_line; - voice[voice_index].drumchan = 0; - }; - voice[voice_index].currentline = NULL; - return(voice_index); -} - -void event_voice(n, s, vp) -int n; -char *s; -struct voice_params *vp; -{ - char output[32]; - if (xinbody) { - next_voice = setvoice(n); - }; - if ((selected_voice != -1) && (n != selected_voice)) { - if ((inlinefield) && (output_on == 1)) { - unemit_inline(); - }; - output_on = 0; - } else { - if (output_on == 0) { - output_on = 1; - if (inlinefield) { - emit_string("["); /* regenerate missing [ */ - }; - }; - }; - if (strlen(s) == 0) { - if(voicecodes >= n) emit_string_sprintf("V:%s",voicecode[n-1]); - else emit_int_sprintf("V:%d", n); - if (vp->gotclef) {sprintf(output," clef=%s", vp->clefname); - emit_string(output);} - if (vp->gotoctave) {sprintf(output," octave=%d", vp->octave); - emit_string(output);} - if (vp->gottranspose) {sprintf(output," transpose=%d", vp->transpose); - emit_string(output);} - if (vp->gotname) {sprintf(output," name=%s", vp->namestring); - emit_string(output);} - if (vp->gotsname) {sprintf(output," sname=%s", vp->snamestring); - emit_string(output);} - if( vp->gotmiddle ) { sprintf(output, " middle=%s", vp->middlestring); - emit_string(output);} - } else { - if(voicecodes >= n) emit_string_sprintf("V:%s",voicecode[n-1]); - emit_int_sprintf("V:%d ", n); - if (vp->gotclef) {sprintf(output," clef=%s", vp->clefname); - emit_string(output);} - if (vp->gotoctave) {sprintf(output," octave=%d", vp->octave); - emit_string(output);} - if (vp->gottranspose) {sprintf(output," transpose=%d", vp->transpose); - emit_string(output);} - if (vp->gotname) {sprintf(output," name=%s", vp->namestring); - emit_string(output);} - if( vp->gotmiddle ) { sprintf(output, " middle=%s", vp->middlestring); - emit_string(output);} - emit_string(s); - }; - inmusic = 0; -} - -void event_length(n) -int n; -{ - struct fract newunit; - - newunit.num = lenfactor.denom; - newunit.denom = lenfactor.num * n; - reduce(&newunit.num, &newunit.denom); - emit_int_sprintf("L:%d/", newunit.num); - emit_int(newunit.denom); - unitlen.num = 1; - unitlen.denom = n; - inmusic = 0; -} - -void event_refno(n) -int n; -{ - if (xinbody) { - close_newabc(); - }; - output_on = 1; - if (newrefnos) { - emit_int_sprintf("X: %d", newref); - newref = newref + 1; - } else { - emit_int_sprintf("X: %d", n); - }; - parseron(); - xinhead = 1; - notecount = 0; - unitlen.num = 0; - unitlen.denom = 1; - barlen.num = 0; - barlen.denom = 1; - inmusic = 0; - barcount = 0; -} - -void event_tempo(n, a, b, relative, pre, post) -int n, a, b; -int relative; -char *pre; -char *post; -{ - struct fract newlen; - - emit_string("Q:"); - if (pre != NULL) { - emit_string_sprintf("\"%s\"", pre); - }; - if (n != 0) { - if ((a == 0) && (b == 0)) { - emit_int(n); - } else { - if (relative) { - newlen.num = a * lenfactor.num; - newlen.denom = b * lenfactor.denom; - reduce(&newlen.num, &newlen.denom); - emit_int_sprintf("C%d/", newlen.num); - emit_int(newlen.denom); - emit_int_sprintf("=%d", n); - } else { - emit_int_sprintf("%d/", a); - emit_int(b); - emit_int_sprintf("=%d", n); - }; - }; - }; - if (post != NULL) { - emit_string_sprintf("\"%s\"", post); - }; - inmusic = 0; -} - -void event_timesig(n, m, checkbars) -int n, m, checkbars; -{ - if (checkbars == 1) { - emit_int_sprintf("M:%d/", n); - emit_int(m); - } else { - emit_string("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; -} - -static void setmap(sf, map) -int sf; -int map[7]; -{ -/* map[0] to map[7] corresponds to keys a to g and indicates - whether they are flattened or sharpened. sf encodes the - key signature by indicating the number of sharps (positive - numbers) or flats (negative numbers) -*/ - 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; -} - -static void start_tune() -{ - parseron(); - count.num =0; - count.denom = 1; - barno = 0; - tuplenotes = 0; - expect_repeat = 0; - inlinefield = 0; - if (barlen.num == 0) { - /* generate missing time signature */ - event_linebreak(); - event_timesig(4, 4, 1); - inmusic = 0; - }; - 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; - }; - }; - voicecount = 0; - this_voice = setvoice(1); - next_voice = this_voice; -} - -void compute_keysignature (int sf,int modeindex, char * keysignature) -{ -char *notes[7] = {"A","B","C","D","E","F","G"}; -int sf2note[12] = {3,0,4,1,5,2,6,3,0,4,1,5}; -char *flatsharp[2] = {"b","#"}; -int index0,index1,index; -int map[7]; - -index0 = sf+5; /* -5 6) index -=7; -strcpy(keysignature,notes[index]); -/* propogate sharp or flat to key signature of mode */ -if (map[index] == -1) strcat(keysignature,flatsharp[0]); -if (map[index] == 1) strcat(keysignature,flatsharp[1]); -/* add mode name */ -strcat(keysignature,mode[modeindex]); -} - - - -void event_key(sharps, s, modeindex, modmap, modmul, gotkey, gotclef, clefname, - octave, xtranspose, gotoctave, gottranspose) -int sharps; -char *s; -int modeindex; -char modmap[7]; -int modmul[7]; -int gotkey, gotclef; -char* clefname; -int octave, xtranspose, gotoctave, gottranspose; -{ - static char* keys[12] = {"Db", "Ab", "Eb", "Bb", "F", "C", - "G", "D", "A", "E", "B", "F#"}; - char signature[10]; - - if (gotkey) { - setmap(sharps, basemap); /* required by copymap and pitchof */ - setmap(sharps, oldtable); - copymap(); - newkey = (sharps+7*transpose)%12; - if (sharps < -5) orig_key_number = (int) keys[sharps+17][0] - (int) 'A'; - else if (sharps > 6) orig_key_number = (int)keys[sharps-7][0] - (int) 'A'; - else orig_key_number = (int) keys[sharps+5][0] - (int) 'A'; - 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); /* used by event_note1 */ - new_key_number = (int) keys[newkey+5][0] - (int) 'A'; - }; - emit_string("K:"); - if (transpose == 0 && !nokey) { - emit_string(s); - } else { - if (gotkey) { - if (!nokey) { - /* emit_string(keys[newkey+5]); */ - compute_keysignature(newkey,modeindex,signature); /* [SS] 2006-07-30*/ - emit_string(signature); /* [SS] 2006-07-30 */ - } - - else if (usekey == 0) emit_string("none"); - else emit_string(keys[usekey+5]); - if (gotclef) { - emit_string(" "); - }; - }; - if (gotclef) { - emit_string_sprintf("clef=%s", clefname); - }; - if (gotoctave) { - emit_int_sprintf(" octave=%d", octave); - }; - if (gottranspose) { - emit_int_sprintf(" transpose=%d", xtranspose); - }; - }; - if ((xinhead) && (!xinbody)) { - xinbody = 1; - start_tune(); - }; - inmusic = 0; -} - -static void printlen(a, b) -int a, b; -{ - if (a != 1) { - emit_int(a); - }; - if (b != 1) { - emit_int_sprintf("/%d", b); - }; -} - -void event_spacing(n, m) -int n, m; -{ - emit_string("y"); - printlen(n, m); -} - - -void event_rest(decorators,n,m,type) -int n, m, type; -int decorators[DECSIZE]; -{ - struct fract newlen; - - inmusic = 1; - if( type == 1) emit_string("x"); - else emit_string("z"); - newlen.num = n * lenfactor.num; - newlen.denom = m * lenfactor.denom; - reduce(&newlen.num, &newlen.denom); - printlen(newlen.num, newlen.denom); - if (inchord) { - chordcount = chordcount + 1; - }; - if ((!ingrace) && (!inchord || (chordcount == 1))) { - if (!tuplenotes) addunits(n, m); - else { - addunits(n*tuplefactor.num, m*tuplefactor.denom); - tuplenotes = tuplenotes - 1; - } - }; -} - -void event_mrest(n,m) -int n, m; -{ - inmusic = 1; - emit_string("Z"); - printlen(n,m); - if (inchord) { - event_error("Multiple bar rest not allowed in chord"); - }; - if (tuplenotes != 0) { - event_error("Multiple bar rest not allowed in tuple"); - }; -} - -void event_bar(type, replist) -int type; -char* replist; -{ - char msg[40]; - - if (!purgespace(tmp)) { - if (inmusic) { - newabctext(bar); - } else { - newabctext(field); - }; - }; - switch(type) { - case SINGLE_BAR: - emit_string_sprintf("|%s", replist); - break; - case DOUBLE_BAR: - emit_string("||"); - break; - case THIN_THICK: - emit_string("|]"); - break; - case THICK_THIN: - emit_string("[|"); - break; - case BAR_REP: - emit_string("|:"); - if ((expect_repeat) && (repcheck)) { - event_error("Expecting repeat, found |:"); - }; - expect_repeat = 1; - break; - case REP_BAR: - emit_string_sprintf(":|%s", replist); - if ((!expect_repeat) && (repcheck)) { - event_warning("No repeat expected, found :|"); - }; - expect_repeat = 0; - break; - case BAR1: - emit_string("|1"); - if ((!expect_repeat) && (repcheck)) { - event_warning("found |1 in non-repeat section"); - }; - break; - case REP_BAR2: - emit_string(":|2"); - if ((!expect_repeat) && (repcheck)) { - event_warning("No repeat expected, found :|2"); - }; - expect_repeat = 0; - break; - case DOUBLE_REP: - emit_string("::"); - 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); - barno = barno + 1; - count.num = 0; - count.denom = 1; - copymap(); -} - -void event_space() -{ - if (!newspacing) { - emit_string(" "); - }; -} - -void event_graceon() -{ - emit_string("{"); - ingrace = 1; -} - -void event_graceoff() -{ - emit_string("}"); - ingrace = 0; -} - -void event_rep1() -{ - emit_string(" [1"); -} - -void event_rep2() -{ - emit_string(" [2"); -} - -void event_playonrep(s) -char*s; -{ - emit_string_sprintf(" [%s", s); -} - -void event_broken(type, n) -int type, n; -{ - int i; - - if (type == GT) { - for (i=0; i'); - }; - } else { - for (i=0; i') || (*s == '@')) { - emit_string_sprintf("\"%s\"", s); - } else { - char* p; - int pitch; - int j; - - if (newkey >= 0) { - roots = sharproots; - bases = sharpbases; - } else { - roots = flatroots; - bases = flatbases; - }; - p = s; - chordstart = 1; - j = 0; - while (*p != '\0') { - if (chordstart) { - if ((*p >= 'A') && (*p <= 'G')) { - key_number = (int) *p - ((int) 'A'); - old_triad_number = key_number - orig_key_number+1; - if (old_triad_number < 1) old_triad_number += 7; - pitch = (offset[key_number] + transpose)%12; - p = p + 1; - if (*p == 'b') { - pitch = pitch - 1; - p = p + 1; - }; - if (*p == '#') { - pitch = pitch + 1; - p = p + 1; - }; - pitch = (pitch + 12)%12; - key_number = (int) roots[pitch][0] - (int) 'A'; - new_triad_number = key_number - new_key_number +1; - if (new_triad_number < 1) new_triad_number += 7; - triad_diff = new_triad_number - old_triad_number; - if (!nodouble_accidentals && (triad_diff == -1 || triad_diff == 6)) { - /* printf("*** %d old chord = %s (%d) new chord = %s (%d)\n", - triad_diff,s,old_triad_number,roots[pitch],new_triad_number); */ - pitch = pitch+1; - pitch = (pitch+12)%12; - strcpy(&newchord[j],roots[pitch]); - j = strlen(newchord); - strcpy(&newchord[j],"b"); - j = j+1; - if (adapt_useflats_to_gchords) useflats=1; - } else - if (!nodouble_accidentals && (triad_diff ==1 || triad_diff == -6)) { - /* printf("*** %d old chord = %s (%d) new chord = %s (%d)\n", - triad_diff,s,old_triad_number,roots[pitch],new_triad_number); */ - - pitch = pitch-1; - pitch = (pitch+12)%12; - strcpy(&newchord[j],roots[pitch]); - j = strlen(newchord); - strcpy(&newchord[j],"#"); - j = j+1; - if (adapt_useflats_to_gchords) useflats=0; - } else -/* no extra flats or sharps needed */ - { - strcpy(&newchord[j], roots[pitch]); - j = strlen(newchord); - } - - chordstart = 0; - } else { - if ((*p >= 'a') && (*p <= 'g')) { - key_number = (int) *p - ((int) 'a'); - old_triad_number = key_number - orig_key_number+1; - if (old_triad_number < 1) old_triad_number += 7; - pitch = (offset[key_number] + transpose)%12; - p = p + 1; - if (*p == 'b') { - pitch = pitch - 1; - p = p + 1; - }; - if (*p == '#') { - pitch = pitch + 1; - p = p + 1; - }; - pitch = (pitch + 12)%12; - key_number = (int) bases[pitch][0] - (int) 'a'; - new_triad_number = key_number - new_key_number +1; - if (new_triad_number < 1) new_triad_number += 7; - triad_diff = new_triad_number - old_triad_number; - if (!nodouble_accidentals && (triad_diff == -1 || triad_diff == 6)) { - /* printf("*** %d old chord = %s (%d) new chord = %s (%d)\n", - triad_diff,s,old_triad_number,bases[pitch],new_triad_number); */ - pitch = pitch+1; - pitch = (pitch+12)%12; - strcpy(&newchord[j],bases[pitch]); - j = strlen(newchord); - strcpy(&newchord[j],"b"); - j = j+1; - } else - if (!nodouble_accidentals && (triad_diff ==1 || triad_diff == -6)) { - /* printf("*** %d old chord = %s (%d) new chord = %s (%d)\n", - triad_diff,s,old_triad_number,bases[pitch],new_triad_number);*/ - pitch = pitch-1; - pitch = (pitch+12)%12; - strcpy(&newchord[j],bases[pitch]); - j = strlen(newchord); - strcpy(&newchord[j],"#"); - j = j+1; - } else - { - strcpy(&newchord[j], bases[pitch]); - j = strlen(newchord); - } - chordstart = 0; - } else { - if (isalpha(*p)) { - chordstart = 0; - }; - newchord[j] = *p; - p = p + 1; - j = j + 1; - newchord[j] = '\0'; - }; - }; - } else { - if ((*p == '/') || (*p == '(') || (*p == ' ')) { - chordstart = 1; - }; - - newchord[j] = *p; - p = p + 1; - j = j + 1; - newchord[j] = '\0'; - }; - if (j >= 49) { - event_error("guitar chord contains too much text"); - while (*p != '\0') { - p = p + 1; - }; - }; - }; - emit_string_sprintf("\"%s\"", newchord); - }; -} - -void event_gchord(s) -char* s; -{ - splitstring(s, ';', event_handle_gchord); -} - -void event_instruction(s) -char* s; -{ - if (oldchordconvention) emit_string_sprintf("!%s!", s); - else emit_string_sprintf("+%s+", s); -} - -void event_slur(t) -int t; -{ - if (cleanup) { - if (t) { - emit_string("("); - } else { - emit_string(")"); - }; - } else { - emit_string("s"); - }; -} - -void event_sluron(t) -int t; -{ - emit_string("("); -} - -void event_sluroff(t) -int t; -{ - emit_string(")"); -} - -void event_tie() -{ - emit_string("-"); -} - -void 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; - }; - }; - }; - if (!ingrace) { - notecount = notecount + 1; - }; - for (t=0; t= 1) { - emit_char(note); - t = octave; - while (t > 1) { - emit_string("'"); - t = t - 1; - }; - } else { - emit_char((char) ((int)note + 'C' - 'c')); - t = octave; - while (t < 0) { - emit_string(","); - t = t + 1; - }; - }; - newlen.num = n * lenfactor.num; - newlen.denom = m * lenfactor.denom; - reduce(&newlen.num, &newlen.denom); - printlen(newlen.num, newlen.denom); - 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)) { - emit_string(" "); - }; - }; -} - -/* these functions are here to satisfy the linker */ -void event_microtone(int dir, int a, int b) -{ -} - -void event_normal_tone() -{ -} - - - -int accidental_to_code (char xaccidental) -{ - switch (xaccidental) { - case ' ': - return 10; - break; - case '_': - return -1; - break; - case '^': - return 1; - break; - case '=': - return 0; - break; - default: - return 10; - } -} - - -void event_note2(decorators, xaccidental, xmult, xnote, xoctave, n, m) -/* this function is called if flag nokey is set */ -int decorators[DECSIZE]; -int xmult; -char xaccidental, xnote; -int xoctave, n, m; -{ - int t; - struct fract barpoint; - struct fract newlen; - - int acc,assumed_acc; - int propogate; - int val; - char *anoctave = "cdefgab"; - int midipitch; - - for (t=0; t=1) {sharpsym[6] = 0; sharpsym[5] = 2;} -if (sf >=2) {sharpsym[1] = 0; sharpsym[0] = 2;} -if (sf >=3) {sharpsym[8] = 0; sharpsym[7] = 2;} -if (sf >=4) {sharpsym[3] = 0; sharpsym[2] = 2;} -if (sf >=5) {sharpsym[10]= 0; sharpsym[9] = 2;} -if (sf <= -1) {flatsym[10] = 0; flatsym[11] = 2;} -if (sf <= -2) {flatsym[3] = 0; flatsym[4] =2;} -if (sf <= -3) {flatsym[8] = 0; flatsym[9] =2;} -if (sf <= -4) {flatsym[1] = 0; flatsym[2] =2;} -if (sf <= -5) {flatsym[6] = 0; flatsym[6] =2;} -} - - - -void printpitch(int pitch) -/* convert midi pitch value to abc note */ -{ -int p; -char keylet,symlet; -int keynum,symcod; -char string[16]; -p = pitch%12; -if (useflats) - {keynum = flatmap[p]; - symcod = flatsym[p]; - } else - {keynum = sharpmap[p]; - symcod = sharpsym[p]; - } - -if (pitch= MIDDLE + 12) { - emit_string("'"); - p = p - 12; - }; -while (p < MIDDLE - 12) { - emit_string(","); - p = p + 12; - }; -} - - -int main(argc,argv) -int argc; -char *argv[]; -{ - char *filename; - - oldchordconvention = 0; /* for handling +..+ chords */ - - /*for (i=0;i + +/* define USE_INDEX if your C libraries have index() instead of strchr() */ +#ifdef USE_INDEX +#define strchr index +#endif + +#if defined(ANSILIBS) || defined(__STDC__) +#include +#include +#include +#else +extern char* strchr(); +#endif + +#define MAX_VOICES 30 +/* should be plenty! */ + +programname fileprogram = ABC2ABC; +extern int oldchordconvention; /* for handling +..+ chords */ + +struct fract { + int num; + int denom; +}; +struct fract barlen; /* length of a bar as given by the time signature */ +struct fract unitlen; /* unit length as given by the L: field */ +struct fract count; /* length of bar so far */ +struct fract prevcount; /* length of bar before last increment */ +struct fract tuplefactor; /* factor associated with a tuple (N */ +struct fract breakpoint; /* used to break bar into beamed sets of notes */ +int barno; /* number of bar within tune */ +int newspacing; /* was -s option selected ? */ +int barcheck, repcheck; /* indicate -b and -r options selected */ +int echeck; /* was error-checking turned off ? (-e option) */ +int newbreaks; /* was -n option selected ? */ +int nodouble_accidentals; +int totalnotes, notecount; +int bars_per_line; /* number supplied after -n option */ +int barcount; +int expect_repeat; +int tuplenotes, barend; +int xinhead, xinbody; /* are we in head or body of abc tune ? */ +int inmusic; /* are we in a line of notes (in the tune body) ? */ +int startline, blankline; +int transpose; /* number of semitones to transpose by (-t option) */ +struct fract lenfactor; /* fraction to scale note lengths; -v,-d options */ +int newkey; /* key after transposition (expressed as no. of sharps) */ +int lines; /* used by transposition */ +int orig_key_number; /* used for gchord transposition */ +int new_key_number; /* used for gchord transposition */ +int oldtable[7], newtable[7]; /* for handling transposition */ +int inchord; /* are we in a chord [ ] ? */ +int ingrace; /* are we in a grace note set { } ? */ +int chordcount; /* number of notes or rests in current chord */ +int inlinefield; /* boolean - are we in [: ] ? */ +int cleanup; /* boolean to indicate -u option (update notation) */ +char tmp[2000]; /* buffer to hold abc output being assembled */ +int output_on = 1; /* if 0 suppress output */ +int selected_voice = -1; /* no voice was selected */ +int newrefnos; /* boolean for -X option (renumber X: fields) */ +int newref; /* next new number for X: field */ +int useflats=0; /* flag associated with nokey.*/ +int adapt_useflats_to_gchords = 1; /* experimental flag */ +int usekey = 0; +int drumchan=0; /* flag to suppress transposition */ + +extern int nokey; /* signals no key signature assumed */ +extern int voicecodes ; /* from parseabc.c */ +extern char voicecode[16][30]; /*for interpreting V: string */ + +struct voicetype { /* information needed for each voice */ + int number; /* voice number from V: field */ + int barcount; + int foundbar; + struct abctext* currentline; + int bars_remaining; + int bars_complete; + int drumchan; +} voice[MAX_VOICES]; +int voicecount, this_voice, next_voice; +enum abctype {field, bar, barline}; +/* linestat is used by -n for deciding when to generate a newline */ +enum linestattype {fresh, midmusic, endmusicline, postfield}; +enum linestattype linestat; +/* struct abctext is used to store abc lines for re-formatting (-n option) */ +struct lyricwords{ + struct lyricwords* nextverse; + char* words; +}; +struct abctext{ /* linked list used to store output before re-formatting */ + struct abctext* next; + char* text; + enum abctype type; + int notes; + struct lyricwords* lyrics; +}; +struct abctext* head; +struct abctext* tail; + +extern char *mode[]; +extern int modekeyshift[]; +int basemap[7], workmap[7]; /* for -nokey and pitchof() */ +int workmul[7]; +void copymap(); +void printpitch(int); +void setup_sharps_flats (int sf); +int pitchof(char note,int accidental,int mult,int octave); + + +static int purgespace(p) +char* p; +/* if string p is empty or consists of spaces, set p to the empty string */ +/* and return 1, otherwise return 0. Used to test tmp */ +/* part of new linebreak option (-n) */ +{ + int blank; + char *s; + + blank = 1; + s = p; + while (*s != '\0') { + if (*s != ' ') blank = 0; + s = s + 1; + }; + if (blank) { + *p = '\0'; + }; + return(blank); +} + +int zero_barcount(foundbar) +/* initialize bar counter for abctext elements */ +/* part of new linebreak option (-n) */ +int *foundbar; +{ + *foundbar = 0; + return(0); +} + +int new_barcount(type, foundbar, oldcount) +enum abctype type; +int *foundbar; +int oldcount; +/* work out whether we have reached the end of a bar in abctext elements */ +/* and increment barcount if we have */ +/* part of new linebreak option (-n) */ +{ + int new_value; + + new_value = oldcount; + if (type == bar) { + *foundbar = 1; + }; + if ((type == barline) && (*foundbar == 1)) { + new_value = new_value + 1; + *foundbar = 0; + }; + return(new_value); +} + + +static void setline(t) +enum linestattype t; +/* generates newline, or continuation, or nothing at all */ +/* part of new linebreak option (-n) */ +{ + if ((t == fresh) && ((linestat == postfield) || (linestat == endmusicline))) { + printf("\n"); + }; + if ((t == fresh) && (linestat == midmusic)) { + printf("\\\n"); + }; + linestat = t; +} + +static int flush_abctext(bars, termination) +int bars; +enum linestattype termination; +/* outputs up to the specified number of bars of stored music */ +/* and frees up the storage allocated for those bars. */ +/* returns the number of bars actually output */ +/* part of new linebreak option (-n) */ +{ + struct abctext *p, *nextp; + struct lyricwords *q, *r; + struct lyricwords *barlyrics; + int count, donewords, wordline; + int i, foundtext; + int foundbar; + + /* printf("flush_abctext called\n"); */ + /* print music */ + p = head; + count = zero_barcount(&foundbar); + while ((p != NULL) && (count < bars)) { + if (p->type == field) { + setline(fresh); + }; + printf("%s", p->text); + if (p->type == field) { + setline(postfield); + setline(fresh); + } else { + setline(midmusic); + }; + count = new_barcount(p->type, &foundbar, count); + if ((count == bars) && (p->type == barline)) { + setline(endmusicline); + }; + p = p->next; + }; + if (linestat == midmusic) { + setline(termination); + }; + if (bars > 0) { + /* print out any w: lines */ + donewords = 0; + wordline = 0; + while (donewords == 0) { + p = head; + foundtext = 0; + count = zero_barcount(&foundbar); + while ((p != NULL) && (count < bars)) { + barlyrics = p->lyrics; + for (i=0; inextverse; + }; + }; + if (barlyrics != NULL) { + if (foundtext == 0) { + setline(fresh); + printf("w:"); + foundtext = 1; + }; + fputs(barlyrics->words, stdout); + }; + count = new_barcount(p->type, &foundbar, count); + p = p->next; + }; + if (foundtext == 0) { + donewords = 1; + } else { + setline(postfield); + setline(fresh); + }; + wordline = wordline + 1; + }; + }; + /* move head on and free up space used by stuff printed out */ + count = zero_barcount(&foundbar); + p = head; + foundbar = 0; + while ((p != NULL) && (count < bars)) { + if (p != NULL) { + free(p->text); + q = p->lyrics; + while (q != NULL) { + free(q->words); + r = q->nextverse; + free(q); + q = r; + }; + count = new_barcount(p->type, &foundbar, count); + nextp = p->next; + free(p); + p = nextp; + }; + head = p; + }; + if (head == NULL) { + tail = NULL; + }; + return(count); +} + +void complete_bars(v) +/* mark all bars as completed (i.e. having associated w: fields parsed) */ +/* and out put all music lines which contain the full set of bars */ +/* part of new linebreak option (-n) */ +struct voicetype *v; +{ + int bars_done; + + v->bars_complete = v->bars_complete + v->barcount; + v->barcount = 0; + while (v->bars_complete > v->bars_remaining) { + bars_done = flush_abctext(v->bars_remaining, endmusicline); + setline(fresh); + v->bars_complete = v->bars_complete - bars_done; + v->bars_remaining = v->bars_remaining - bars_done; + if (v->bars_remaining == 0) { + v->bars_remaining = bars_per_line; + }; + }; +} + +void complete_all(v, termination) +struct voicetype *v; +enum linestattype termination; +/* output all remaining music and fields */ +/* part of new linebreak option (-n) */ +{ + int bars_done; + + complete_bars(v); + bars_done = flush_abctext(v->bars_remaining+1, termination); + v->bars_complete = v->bars_complete - bars_done; + v->bars_remaining = v->bars_remaining - bars_done; + if (v->bars_remaining == 0) { + v->bars_remaining = bars_per_line; + }; + head = NULL; + tail = NULL; + voice[this_voice].currentline = NULL; +} + +static struct abctext* newabctext(t) +enum abctype t; +/* called at newlines and barlines */ +/* adds current output text to linked list structure */ +/* part of new linebreak option (-n) */ +{ + struct abctext* p; + + if (output_on == 0) { + p = NULL; + return(p); + }; + if (newbreaks) { +/* + if ((t == field) && (!xinbody || (this_voice != next_voice))) { +*/ + if (t == field) { + complete_all(&voice[this_voice], midmusic); + this_voice = next_voice; + }; + p = (struct abctext*) checkmalloc(sizeof(struct abctext)); + p->text = addstring(tmp); + tmp[0] = '\0'; + p->next = NULL; + p->type = t; + p->lyrics = NULL; + if (t == bar) { + p->notes = notecount; + totalnotes = totalnotes + notecount; + notecount = 0; + } else { + p->notes = 0; + }; + if (xinbody) { + voice[this_voice].barcount = new_barcount(t, + &voice[this_voice].foundbar, + voice[this_voice].barcount); + }; + if (head == NULL) { + head = p; + tail = p; + } else { + tail->next = p; + tail = p; + }; + if ((t != field) && (voice[this_voice].currentline == NULL)) { + voice[this_voice].currentline = p; + }; + } else { + printf("%s", tmp); + tmp[0] = '\0'; + p = NULL; + }; + inmusic = 1; + return(p); +} + +/* This function is never actually used */ +#if 0 +static int nextnotes() +/* return the number of notes in the next bar */ +/* part of new linebreak option (-n) */ +{ + 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); +} +#endif + +static void 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; +} + + +static void addunits(n, m) +int n, m; +/* add fraction n/m to count */ +{ + prevcount = count; /* in case of chord extension eg [CE]3/2 */ + count.num = n*count.denom + count.num*(m*unitlen.denom); + count.denom = (m*unitlen.denom)*count.denom; + reduce(&count.num, &count.denom); +} + +static void repudiate_lastaddunits() +{ + count = prevcount; +} + +void event_init(argc, argv, filename) +int argc; +char* argv[]; +char** filename; +/* routine called on program start-up */ +{ + int targ, narg; + + if ((getarg("-h", argc, argv) != -1) || (argc < 2)) { + printf("abc2abc version %s\n",VERSION); + printf("Usage: abc2abc [-s] [-n X] [-b] [-r] [-e] [-t X]\n"); + printf(" [-u] [-d] [-v] [-V X] [-ver] [-X n]\n"); + printf(" -s for new spacing\n"); + printf(" -n X to re-format the abc with a new linebreak every X bars\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(" -nda No double accidentals in guitar chords\n"); + printf(" -nokeys No key signature. Use sharps\n"); + printf(" -nokeyf No key signature. Use flats\n"); + printf(" -u to update notation ([] for chords and () for slurs)\n"); + printf(" -usekey n Use key signature sf (sharps/flats)\n"); + printf(" -d to notate with doubled note lengths\n"); + printf(" -v to notate with halved note lengths\n"); + printf(" -V X to output only voice X\n"); + printf(" -ver prints version number and exits\n"); + printf(" -X n renumber the all X: fields as n, n+1, ..\n"); + printf(" -OCC old chord convention (eg. +CE+)\n"); + + exit(0); + } else { + *filename = argv[1]; + }; + nodouble_accidentals = 0; /* use correct guitar chords */ + if (getarg("-ver",argc,argv) != -1) { + printf("%s\n",VERSION); + exit(0); + } + if (getarg("-u", argc, argv) == -1) { + cleanup = 0; + } else { + cleanup = 1; + oldchordconvention = 1; + }; + if (getarg("-s", argc, argv) == -1) { + newspacing = 0; + } else { + newspacing = 1; + }; + narg = getarg("-X", argc, argv); + if (narg == -1) { + newrefnos = 0; + } else { + newrefnos = 1; + if (narg < argc) { + newref = readnumf(argv[narg]); + } else { + newref = 1; + }; + }; + if (getarg("-e", argc, argv) == -1) { + echeck = 1; + } else { + echeck = 0; + }; + narg = getarg("-n", argc, argv); + if (narg == -1) { + newbreaks = 0; + } else { + newbreaks = 1; + if (narg >= argc) { + event_error("No value for bars per line after -n"); + bars_per_line = 4; + } else { + bars_per_line = readnumf(argv[narg]); + if (bars_per_line < 1) { + bars_per_line = 4; + }; + }; + }; + if (getarg("-b", argc, argv) != -1) { + barcheck = 0; + } else { + barcheck = 1; + }; + if (getarg("-r", argc, argv) != -1) { + repcheck = 0; + } else { + repcheck = 1; + }; + if (getarg("-v", argc, argv) != -1) { + lenfactor.num = 1; + lenfactor.denom = 2; + } else { + if (getarg("-d", argc, argv) != -1) { + lenfactor.num = 2; + lenfactor.denom = 1; + } else { + lenfactor.num = 1; + lenfactor.denom = 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]); + }; + }; + }; + targ = getarg("-nda",argc,argv); + if (targ != -1) nodouble_accidentals = 1; + + targ = getarg("-nokeys",argc,argv); + if (targ != -1) nokey=1; + + targ = getarg("-nokeyf",argc,argv); + if (targ != -1) {nokey=1; useflats=1;} + + targ = getarg("-V", argc, argv); + if (targ != -1) { + selected_voice = readnumf(argv[targ]); + }; + + targ = getarg("-usekey",argc,argv); + if (targ != -1) { + usekey = readsnumf(argv[targ]); + nokey = 1; + if (usekey < 0) useflats=1; + if (usekey <-5) usekey = -5; + if (usekey >5) usekey = 5; + setup_sharps_flats (usekey); + } + if (getarg("-OCC",argc,argv) != -1) oldchordconvention=1; + + /* 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; +} + +void emit_string(s) +char *s; +/* output string */ +{ + if (output_on) { + strcpy(tmp+strlen(tmp), s); + }; +} + +void emit_char(ch) +char ch; +/* output single character */ +{ + char *place; + + if (output_on) { + place = tmp+strlen(tmp); + *place = ch; + *(place+1) = '\0'; + }; +} + +void emit_int(n) +int n; +/* output integer */ +{ + if (output_on) { + sprintf(tmp+strlen(tmp), "%d", n); + }; +} + +void emit_string_sprintf(s1, s2) +char *s1; +char *s2; +/* output string containing string expression %s */ +{ + if (output_on) { + sprintf(tmp+strlen(tmp), s1, s2); + }; +} + +void emit_int_sprintf(s, n) +char *s; +int n; +/* output string containing int expression %d */ +{ + if (output_on) { + sprintf(tmp+strlen(tmp), s, n); + }; +} + +void unemit_inline() +/* remove previously output start of inline field */ +/* needed for -V voice selection option */ +{ + int len; + + len = strlen(tmp); + if ((len > 0) && (tmp[len-1] == '[')) { + tmp[len-1] = '\0'; /* delete last character */ + } else { + event_error("Internal error - Could not delete ["); + }; +} + +static void close_newabc() +/* output all remaining abc_text elements */ +/* part of new linebreak option (-n) */ +{ + if (newbreaks) { + complete_all(&voice[this_voice], endmusicline); + if (linestat == midmusic) setline(endmusicline); + setline(fresh); + }; +} + +void event_eof() +{ + close_newabc(); +} + +void event_blankline() +{ + output_on = 1; + close_newabc(); +/* if (newbreaks) [SS] 2006-09-23 */ printf("\n"); + xinbody = 0; + xinhead = 0; + parseroff(); + blankline = 1; +} + +void event_text(p) +char *p; +{ + emit_string_sprintf("%%%s", p); + inmusic = 0; +} + +void event_reserved(p) +char p; +{ + emit_char(p); + inmusic = 0; +} + +void event_tex(s) +char *s; +{ + emit_string(s); + inmusic = 0; +} + +void event_linebreak() +{ + if (newbreaks) { + if (!purgespace(tmp)) { + if (inmusic) { + newabctext(bar); + } else { + newabctext(field); + }; + }; + } else { + newabctext(bar); + if (output_on) { + printf("\n"); + }; + /* don't output new line if voice is already suppressed + otherwise we will get lots of blank lines where we + are suppressing output. [SS] feb-10-2002. + */ + }; +} + +void event_startmusicline() +/* encountered the start of a line of notes */ +{ + voice[this_voice].currentline = NULL; + complete_bars(&voice[this_voice]); +} + +void event_endmusicline(endchar) +char endchar; +/* encountered the end of a line of notes */ +{ +} + +void event_error(s) +char *s; +{ + if (echeck) { + printf("\n%%Error : %s\n", s); + }; +} + +void event_warning(s) +char *s; +{ + if (echeck) { + printf("\n%%Warning : %s\n", s); + }; +} + +void event_comment(s) +char *s; +{ + if (newbreaks && (!purgespace(tmp))) { + if (inmusic) { + newabctext(bar); + } else { + newabctext(field); + }; + }; + emit_string_sprintf("%%%s", s); + inmusic = 0; +} + +void event_specific(package, s) +char *package, *s; +{ + char command[40]; + int ch; + char *p; + emit_string("%%"); + emit_string(package); + emit_string(s); + inmusic = 0; +/* detect drum channel by searching for %%MIDI channel 10 */ + if (strcmp(package,"MIDI") != 0) return; + p = s; + skipspace(&p); + readstr(command, &p, 40); + if (strcmp(command, "channel") != 0) return; + skipspace(&p); + ch = readnump(&p); + if(ch == 10) { + voice[next_voice].drumchan = 1; + drumchan = 1; + } +/* printf("event_specific: next_voice = %d\n",next_voice); */ +} + +void event_info(f) +/* handles info field I: */ +char *f; +{ + emit_string_sprintf("I:%s", f); + inmusic = 0; +} + + +void event_field(k, f) +char k; +char *f; +{ + emit_char(k); + emit_char(':'); + emit_string(f); + inmusic = 0; +} + +struct abctext* getbar(place) +struct abctext *place; +/* find first element in list which is a bar of music */ +{ + struct abctext *newplace; + + newplace = place; + while ((newplace != NULL) && + ((newplace->type != bar) || + (newplace->notes == 0))) { + newplace = newplace->next; + }; + return(newplace); +} + +struct abctext* getnextbar(place) +struct abctext *place; +/* find next element in list which is a bar of music */ +{ + struct abctext *newplace; + + newplace = place; + if (newplace != NULL) { + newplace = getbar(newplace->next); + }; + return(newplace); +}; + +void append_lyrics(place, newwords) +struct abctext *place; +char *newwords; +/* add lyrics to end of lyric list associated with bar */ +{ + struct lyricwords* new_words; + struct lyricwords *new_place; + + if (place == NULL) { + return; + }; + /* printf("append_lyrics has %s at %s\n", newwords, place->text); */ + new_words = (struct lyricwords*)checkmalloc(sizeof(struct lyricwords)); + /* add words to bar */ + new_words->nextverse = NULL; + new_words->words = addstring(newwords); + if (place->lyrics == NULL) { + place->lyrics = new_words; + } else { + new_place = place->lyrics; + /* find end of list */ + while (new_place->nextverse != NULL) { + new_place = new_place->nextverse; + }; + new_place->nextverse = new_words; + }; +} + +struct abctext* apply_bar(syll, place, notesleft, barwords) +/* advance to next bar (on finding '|' in a w: field) */ +char* syll; +struct abctext *place; +int *notesleft; +struct vstring *barwords; +{ + struct abctext* new_place; + + if (place == NULL) { + return(NULL); + }; + new_place = place; + addtext(syll, barwords); + append_lyrics(place, barwords->st); + /* go on to next bar */ + clearvstring(barwords); + new_place = getnextbar(place); + if (new_place != NULL) { + *notesleft = new_place->notes; + }; + return(new_place); +} + +struct abctext* apply_syllable(syll, place, notesleft, barwords) +/* attach syllable to appropriate place in abctext structure */ +char* syll; +struct abctext *place; +int *notesleft; +struct vstring *barwords; +{ + struct abctext* new_place; + char msg[80]; + + if (place == NULL) { + sprintf(msg, "Cannot find note to match \"%s\"", syll); + event_error(msg); + return(NULL); + }; + new_place = place; + addtext(syll, barwords); + *notesleft = *notesleft - 1; + if (*notesleft == 0) { + append_lyrics(place, barwords->st); + /* go on to next bar */ + clearvstring(barwords); + new_place = getnextbar(place); + if (new_place != NULL) { + *notesleft = new_place->notes; + }; + }; + return(new_place); +} + +void parse_words(p) +char* p; +/* Break up a line of lyrics (w: ) into component syllables */ +{ + struct vstring syll; + struct vstring barwords; + char* q; + unsigned char ch; + int errors; + int found_hyphen; + + struct abctext *place; + int notesleft; + + if (!xinbody) { + event_error("w: field outside tune body"); + return; + }; + place = getbar(voice[this_voice].currentline); + if (place == NULL) { + event_error("No music to match w: line to"); + return; + }; + notesleft = voice[this_voice].currentline->notes; + initvstring(&barwords); + errors = 0; + if (place == NULL) { + event_error("No notes to match words"); + return; + }; + initvstring(&syll); + q = p; + skipspace(&q); + while (*q != '\0') { + found_hyphen = 0; + clearvstring(&syll); + ch = *q; + while(ch=='|') { + addch('|', &syll); + addch(' ', &syll); + place = apply_bar(syll.st, place, ¬esleft, &barwords); + clearvstring(&syll); + q++; + ch = *q; + }; + /* PCC seems to require (ch != ' ') on the next line */ + /* presumably PCC's version of ispunct() thinks ' ' is punctuation */ + while (((ch>127)||isalnum(ch)||ispunct(ch))&&(ch != ' ')&& + (ch != '_')&&(ch != '-')&&(ch != '*')&& (ch != '|')) { + if ((ch == '\\') && (*(q+1)=='-')) { + addch('\\', &syll); + ch = '-'; + q++; + }; + /* syllable[i] = ch; */ + addch(ch, &syll); + q++; + ch = *q; + }; + skipspace(&q); + if (ch == '-') { + found_hyphen = 1; + addch(ch, &syll); + while (isspace(ch)||(ch=='-')) { + q++; + ch = *q; + }; + }; + if (syll.len > 0) { + if (!found_hyphen) { + addch(' ', &syll); + }; + place = apply_syllable(syll.st, place, ¬esleft, &barwords); + } else { + if (ch=='_') { + clearvstring(&syll); + addch('_', &syll); + addch(' ', &syll); + place = apply_syllable(syll.st, place, ¬esleft, &barwords); + q++; + ch = *q; + }; + if (ch=='*') { + clearvstring(&syll); + addch('*', &syll); + addch(' ', &syll); + place = apply_syllable(syll.st, place, ¬esleft, &barwords); + q++; + ch = *q; + }; + }; + }; + if (errors > 0) { + event_error("Lyric line too long for music"); + } else { + clearvstring(&syll); + }; + freevstring(&syll); +} + +void event_words(p, continuation) +char* p; +int continuation; +/* a w: field has been encountered */ +{ + struct vstring afield; + + if (xinbody && newbreaks) { + parse_words(p); + } else { + initvstring(&afield); + addtext(p, &afield); + if (continuation) { + addch(' ', &afield); + addch('\\', &afield); + }; + event_field('w', afield.st); + }; +} + +void event_part(s) +char* s; +{ + if (xinbody) { + complete_bars(&voice[this_voice]); + }; + emit_string_sprintf("P:%s", s); + inmusic = 0; +} + +int setvoice(num) +int num; +/* we need to keep track of current voice for new linebreak handling (-n) */ +/* change voice to num. If voice does not exist, start new one */ +{ + int i, voice_index; + + i = 0; + while ((i < voicecount) && (voice[i].number != num)) { + i = i + 1; + }; + if ((i < voicecount) && (voice[i].number == num)) { + voice_index = i; + drumchan = voice[voice_index].drumchan; +/* printf("voice_index = %d drumchan = %d\n",voice_index,drumchan); */ + } else { + voice_index = voicecount; + if (voicecount < MAX_VOICES) { + voicecount = voicecount + 1; + } else { + event_error("Number of voices exceeds static limit MAX_VOICES"); + }; + voice[voice_index].number = num; + voice[voice_index].barcount = zero_barcount(&voice[voice_index].foundbar); + voice[voice_index].bars_complete = 0; + voice[voice_index].bars_remaining = bars_per_line; + voice[voice_index].drumchan = 0; + }; + voice[voice_index].currentline = NULL; + return(voice_index); +} + +void event_voice(n, s, vp) +int n; +char *s; +struct voice_params *vp; +{ + char output[32]; + if (xinbody) { + next_voice = setvoice(n); + }; + if ((selected_voice != -1) && (n != selected_voice)) { + if ((inlinefield) && (output_on == 1)) { + unemit_inline(); + }; + output_on = 0; + } else { + if (output_on == 0) { + output_on = 1; + if (inlinefield) { + emit_string("["); /* regenerate missing [ */ + }; + }; + }; + if (strlen(s) == 0) { + if(voicecodes >= n) emit_string_sprintf("V:%s",voicecode[n-1]); + else emit_int_sprintf("V:%d", n); + if (vp->gotclef) {sprintf(output," clef=%s", vp->clefname); + emit_string(output);} + if (vp->gotoctave) {sprintf(output," octave=%d", vp->octave); + emit_string(output);} + if (vp->gottranspose) {sprintf(output," transpose=%d", vp->transpose); + emit_string(output);} + if (vp->gotname) {sprintf(output," name=%s", vp->namestring); + emit_string(output);} + if (vp->gotsname) {sprintf(output," sname=%s", vp->snamestring); + emit_string(output);} + if( vp->gotmiddle ) { sprintf(output, " middle=%s", vp->middlestring); + emit_string(output);} + } else { + if(voicecodes >= n) emit_string_sprintf("V:%s",voicecode[n-1]); + emit_int_sprintf("V:%d ", n); + if (vp->gotclef) {sprintf(output," clef=%s", vp->clefname); + emit_string(output);} + if (vp->gotoctave) {sprintf(output," octave=%d", vp->octave); + emit_string(output);} + if (vp->gottranspose) {sprintf(output," transpose=%d", vp->transpose); + emit_string(output);} + if (vp->gotname) {sprintf(output," name=%s", vp->namestring); + emit_string(output);} + if( vp->gotmiddle ) { sprintf(output, " middle=%s", vp->middlestring); + emit_string(output);} + emit_string(s); + }; + inmusic = 0; +} + +void event_length(n) +int n; +{ + struct fract newunit; + + newunit.num = lenfactor.denom; + newunit.denom = lenfactor.num * n; + reduce(&newunit.num, &newunit.denom); + emit_int_sprintf("L:%d/", newunit.num); + emit_int(newunit.denom); + unitlen.num = 1; + unitlen.denom = n; + inmusic = 0; +} + +void event_refno(n) +int n; +{ + if (xinbody) { + close_newabc(); + }; + output_on = 1; + if (newrefnos) { + emit_int_sprintf("X: %d", newref); + newref = newref + 1; + } else { + emit_int_sprintf("X: %d", n); + }; + parseron(); + xinhead = 1; + notecount = 0; + unitlen.num = 0; + unitlen.denom = 1; + barlen.num = 0; + barlen.denom = 1; + inmusic = 0; + barcount = 0; +} + +void event_tempo(n, a, b, relative, pre, post) +int n, a, b; +int relative; +char *pre; +char *post; +{ + struct fract newlen; + + emit_string("Q:"); + if (pre != NULL) { + emit_string_sprintf("\"%s\"", pre); + }; + if (n != 0) { + if ((a == 0) && (b == 0)) { + emit_int(n); + } else { + if (relative) { + newlen.num = a * lenfactor.num; + newlen.denom = b * lenfactor.denom; + reduce(&newlen.num, &newlen.denom); + emit_int_sprintf("C%d/", newlen.num); + emit_int(newlen.denom); + emit_int_sprintf("=%d", n); + } else { + emit_int_sprintf("%d/", a); + emit_int(b); + emit_int_sprintf("=%d", n); + }; + }; + }; + if (post != NULL) { + emit_string_sprintf("\"%s\"", post); + }; + inmusic = 0; +} + +void event_timesig(n, m, checkbars) +int n, m, checkbars; +{ + if (checkbars == 1) { + emit_int_sprintf("M:%d/", n); + emit_int(m); + } else { + emit_string("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; +} + +static void setmap(sf, map) +int sf; +int map[7]; +{ +/* map[0] to map[7] corresponds to keys a to g and indicates + whether they are flattened or sharpened. sf encodes the + key signature by indicating the number of sharps (positive + numbers) or flats (negative numbers) +*/ + 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; +} + +static void start_tune() +{ + parseron(); + count.num =0; + count.denom = 1; + barno = 0; + tuplenotes = 0; + expect_repeat = 0; + inlinefield = 0; + if (barlen.num == 0) { + /* generate missing time signature */ + event_linebreak(); + event_timesig(4, 4, 1); + inmusic = 0; + }; + 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; + }; + }; + voicecount = 0; + this_voice = setvoice(1); + next_voice = this_voice; +} + +void compute_keysignature (int sf,int modeindex, char * keysignature) +{ +char *notes[7] = {"A","B","C","D","E","F","G"}; +int sf2note[12] = {3,0,4,1,5,2,6,3,0,4,1,5}; +char *flatsharp[2] = {"b","#"}; +int index0,index1,index; +int map[7]; + +index0 = sf+5; /* -5 6) index -=7; +strcpy(keysignature,notes[index]); +/* propogate sharp or flat to key signature of mode */ +if (map[index] == -1) strcat(keysignature,flatsharp[0]); +if (map[index] == 1) strcat(keysignature,flatsharp[1]); +/* add mode name */ +strcat(keysignature,mode[modeindex]); +} + + + +void event_key(sharps, s, modeindex, modmap, modmul, gotkey, gotclef, clefname, + octave, xtranspose, gotoctave, gottranspose) +int sharps; +char *s; +int modeindex; +char modmap[7]; +int modmul[7]; +int gotkey, gotclef; +char* clefname; +int octave, xtranspose, gotoctave, gottranspose; +{ + static char* keys[12] = {"Db", "Ab", "Eb", "Bb", "F", "C", + "G", "D", "A", "E", "B", "F#"}; + char signature[10]; + + if (gotkey) { + setmap(sharps, basemap); /* required by copymap and pitchof */ + setmap(sharps, oldtable); + copymap(); + newkey = (sharps+7*transpose)%12; + if (sharps < -5) orig_key_number = (int) keys[sharps+17][0] - (int) 'A'; + else if (sharps > 6) orig_key_number = (int)keys[sharps-7][0] - (int) 'A'; + else orig_key_number = (int) keys[sharps+5][0] - (int) 'A'; + 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); /* used by event_note1 */ + new_key_number = (int) keys[newkey+5][0] - (int) 'A'; + }; + emit_string("K:"); + if (transpose == 0 && !nokey) { + emit_string(s); + } else { + if (gotkey) { + if (!nokey) { + /* emit_string(keys[newkey+5]); */ + compute_keysignature(newkey,modeindex,signature); /* [SS] 2006-07-30*/ + emit_string(signature); /* [SS] 2006-07-30 */ + } + + else if (usekey == 0) emit_string("none"); + else emit_string(keys[usekey+5]); + if (gotclef) { + emit_string(" "); + }; + }; + if (gotclef) { + emit_string_sprintf("clef=%s", clefname); + }; + if (gotoctave) { + emit_int_sprintf(" octave=%d", octave); + }; + if (gottranspose) { + emit_int_sprintf(" transpose=%d", xtranspose); + }; + }; + if ((xinhead) && (!xinbody)) { + xinbody = 1; + start_tune(); + }; + inmusic = 0; +} + +static void printlen(a, b) +int a, b; +{ + if (a != 1) { + emit_int(a); + }; + if (b != 1) { + emit_int_sprintf("/%d", b); + }; +} + +void event_spacing(n, m) +int n, m; +{ + emit_string("y"); + printlen(n, m); +} + + +void event_rest(decorators,n,m,type) +int n, m, type; +int decorators[DECSIZE]; +{ + struct fract newlen; + + inmusic = 1; + if( type == 1) emit_string("x"); + else emit_string("z"); + newlen.num = n * lenfactor.num; + newlen.denom = m * lenfactor.denom; + reduce(&newlen.num, &newlen.denom); + printlen(newlen.num, newlen.denom); + if (inchord) { + chordcount = chordcount + 1; + }; + if ((!ingrace) && (!inchord || (chordcount == 1))) { + if (!tuplenotes) addunits(n, m); + else { + addunits(n*tuplefactor.num, m*tuplefactor.denom); + tuplenotes = tuplenotes - 1; + } + }; +} + +void event_mrest(n,m) +int n, m; +{ + inmusic = 1; + emit_string("Z"); + printlen(n,m); + if (inchord) { + event_error("Multiple bar rest not allowed in chord"); + }; + if (tuplenotes != 0) { + event_error("Multiple bar rest not allowed in tuple"); + }; +} + +void event_bar(type, replist) +int type; +char* replist; +{ + char msg[40]; + + if (!purgespace(tmp)) { + if (inmusic) { + newabctext(bar); + } else { + newabctext(field); + }; + }; + switch(type) { + case SINGLE_BAR: + emit_string_sprintf("|%s", replist); + break; + case DOUBLE_BAR: + emit_string("||"); + break; + case THIN_THICK: + emit_string("|]"); + break; + case THICK_THIN: + emit_string("[|"); + break; + case BAR_REP: + emit_string("|:"); + if ((expect_repeat) && (repcheck)) { + event_error("Expecting repeat, found |:"); + }; + expect_repeat = 1; + break; + case REP_BAR: + emit_string_sprintf(":|%s", replist); + if ((!expect_repeat) && (repcheck)) { + event_warning("No repeat expected, found :|"); + }; + expect_repeat = 0; + break; + case BAR1: + emit_string("|1"); + if ((!expect_repeat) && (repcheck)) { + event_warning("found |1 in non-repeat section"); + }; + break; + case REP_BAR2: + emit_string(":|2"); + if ((!expect_repeat) && (repcheck)) { + event_warning("No repeat expected, found :|2"); + }; + expect_repeat = 0; + break; + case DOUBLE_REP: + emit_string("::"); + 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); + barno = barno + 1; + count.num = 0; + count.denom = 1; + copymap(); +} + +void event_space() +{ + if (!newspacing) { + emit_string(" "); + }; +} + +void event_graceon() +{ + emit_string("{"); + ingrace = 1; +} + +void event_graceoff() +{ + emit_string("}"); + ingrace = 0; +} + +void event_rep1() +{ + emit_string(" [1"); +} + +void event_rep2() +{ + emit_string(" [2"); +} + +void event_playonrep(s) +char*s; +{ + emit_string_sprintf(" [%s", s); +} + +void event_broken(type, n) +int type, n; +{ + int i; + + if (type == GT) { + for (i=0; i'); + }; + } else { + for (i=0; i') || (*s == '@')) { + emit_string_sprintf("\"%s\"", s); + } else { + char* p; + int pitch; + int j; + + if (newkey >= 0) { + roots = sharproots; + bases = sharpbases; + } else { + roots = flatroots; + bases = flatbases; + }; + p = s; + chordstart = 1; + j = 0; + while (*p != '\0') { + if (chordstart) { + if ((*p >= 'A') && (*p <= 'G')) { + key_number = (int) *p - ((int) 'A'); + old_triad_number = key_number - orig_key_number+1; + if (old_triad_number < 1) old_triad_number += 7; + pitch = (offset[key_number] + transpose)%12; + p = p + 1; + if (*p == 'b') { + pitch = pitch - 1; + p = p + 1; + }; + if (*p == '#') { + pitch = pitch + 1; + p = p + 1; + }; + pitch = (pitch + 12)%12; + key_number = (int) roots[pitch][0] - (int) 'A'; + new_triad_number = key_number - new_key_number +1; + if (new_triad_number < 1) new_triad_number += 7; + triad_diff = new_triad_number - old_triad_number; + if (!nodouble_accidentals && (triad_diff == -1 || triad_diff == 6)) { + /* printf("*** %d old chord = %s (%d) new chord = %s (%d)\n", + triad_diff,s,old_triad_number,roots[pitch],new_triad_number); */ + pitch = pitch+1; + pitch = (pitch+12)%12; + strcpy(&newchord[j],roots[pitch]); + j = strlen(newchord); + strcpy(&newchord[j],"b"); + j = j+1; + if (adapt_useflats_to_gchords) useflats=1; + } else + if (!nodouble_accidentals && (triad_diff ==1 || triad_diff == -6)) { + /* printf("*** %d old chord = %s (%d) new chord = %s (%d)\n", + triad_diff,s,old_triad_number,roots[pitch],new_triad_number); */ + + pitch = pitch-1; + pitch = (pitch+12)%12; + strcpy(&newchord[j],roots[pitch]); + j = strlen(newchord); + strcpy(&newchord[j],"#"); + j = j+1; + if (adapt_useflats_to_gchords) useflats=0; + } else +/* no extra flats or sharps needed */ + { + strcpy(&newchord[j], roots[pitch]); + j = strlen(newchord); + } + + chordstart = 0; + } else { + if ((*p >= 'a') && (*p <= 'g')) { + key_number = (int) *p - ((int) 'a'); + old_triad_number = key_number - orig_key_number+1; + if (old_triad_number < 1) old_triad_number += 7; + pitch = (offset[key_number] + transpose)%12; + p = p + 1; + if (*p == 'b') { + pitch = pitch - 1; + p = p + 1; + }; + if (*p == '#') { + pitch = pitch + 1; + p = p + 1; + }; + pitch = (pitch + 12)%12; + key_number = (int) bases[pitch][0] - (int) 'a'; + new_triad_number = key_number - new_key_number +1; + if (new_triad_number < 1) new_triad_number += 7; + triad_diff = new_triad_number - old_triad_number; + if (!nodouble_accidentals && (triad_diff == -1 || triad_diff == 6)) { + /* printf("*** %d old chord = %s (%d) new chord = %s (%d)\n", + triad_diff,s,old_triad_number,bases[pitch],new_triad_number); */ + pitch = pitch+1; + pitch = (pitch+12)%12; + strcpy(&newchord[j],bases[pitch]); + j = strlen(newchord); + strcpy(&newchord[j],"b"); + j = j+1; + } else + if (!nodouble_accidentals && (triad_diff ==1 || triad_diff == -6)) { + /* printf("*** %d old chord = %s (%d) new chord = %s (%d)\n", + triad_diff,s,old_triad_number,bases[pitch],new_triad_number);*/ + pitch = pitch-1; + pitch = (pitch+12)%12; + strcpy(&newchord[j],bases[pitch]); + j = strlen(newchord); + strcpy(&newchord[j],"#"); + j = j+1; + } else + { + strcpy(&newchord[j], bases[pitch]); + j = strlen(newchord); + } + chordstart = 0; + } else { + if (isalpha(*p)) { + chordstart = 0; + }; + newchord[j] = *p; + p = p + 1; + j = j + 1; + newchord[j] = '\0'; + }; + }; + } else { + if ((*p == '/') || (*p == '(') || (*p == ' ')) { + chordstart = 1; + }; + + newchord[j] = *p; + p = p + 1; + j = j + 1; + newchord[j] = '\0'; + }; + if (j >= 49) { + event_error("guitar chord contains too much text"); + while (*p != '\0') { + p = p + 1; + }; + }; + }; + emit_string_sprintf("\"%s\"", newchord); + }; +} + +void event_gchord(s) +char* s; +{ + splitstring(s, ';', event_handle_gchord); +} + +void event_instruction(s) +char* s; +{ + if (oldchordconvention) emit_string_sprintf("!%s!", s); + else emit_string_sprintf("+%s+", s); +} + +void event_slur(t) +int t; +{ + if (cleanup) { + if (t) { + emit_string("("); + } else { + emit_string(")"); + }; + } else { + emit_string("s"); + }; +} + +void event_sluron(t) +int t; +{ + emit_string("("); +} + +void event_sluroff(t) +int t; +{ + emit_string(")"); +} + +void event_tie() +{ + emit_string("-"); +} + +void 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; + }; + }; + }; + if (!ingrace) { + notecount = notecount + 1; + }; + for (t=0; t= 1) { + emit_char(note); + t = octave; + while (t > 1) { + emit_string("'"); + t = t - 1; + }; + } else { + emit_char((char) ((int)note + 'C' - 'c')); + t = octave; + while (t < 0) { + emit_string(","); + t = t + 1; + }; + }; + newlen.num = n * lenfactor.num; + newlen.denom = m * lenfactor.denom; + reduce(&newlen.num, &newlen.denom); + printlen(newlen.num, newlen.denom); + 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)) { + emit_string(" "); + }; + }; +} + +/* these functions are here to satisfy the linker */ +void event_microtone(int dir, int a, int b) +{ +} + +void event_normal_tone() +{ +} + + + +int accidental_to_code (char xaccidental) +{ + switch (xaccidental) { + case ' ': + return 10; + break; + case '_': + return -1; + break; + case '^': + return 1; + break; + case '=': + return 0; + break; + default: + return 10; + } +} + + +void event_note2(decorators, xaccidental, xmult, xnote, xoctave, n, m) +/* this function is called if flag nokey is set */ +int decorators[DECSIZE]; +int xmult; +char xaccidental, xnote; +int xoctave, n, m; +{ + int t; + struct fract barpoint; + struct fract newlen; + + int acc,assumed_acc; + int propogate; + int val; + char *anoctave = "cdefgab"; + int midipitch; + + for (t=0; t=1) {sharpsym[6] = 0; sharpsym[5] = 2;} +if (sf >=2) {sharpsym[1] = 0; sharpsym[0] = 2;} +if (sf >=3) {sharpsym[8] = 0; sharpsym[7] = 2;} +if (sf >=4) {sharpsym[3] = 0; sharpsym[2] = 2;} +if (sf >=5) {sharpsym[10]= 0; sharpsym[9] = 2;} +if (sf <= -1) {flatsym[10] = 0; flatsym[11] = 2;} +if (sf <= -2) {flatsym[3] = 0; flatsym[4] =2;} +if (sf <= -3) {flatsym[8] = 0; flatsym[9] =2;} +if (sf <= -4) {flatsym[1] = 0; flatsym[2] =2;} +if (sf <= -5) {flatsym[6] = 0; flatsym[6] =2;} +} + + + +void printpitch(int pitch) +/* convert midi pitch value to abc note */ +{ +int p; +char keylet,symlet = 0; +int keynum,symcod; +char string[16]; +p = pitch%12; +if (useflats) + {keynum = flatmap[p]; + symcod = flatsym[p]; + } else + {keynum = sharpmap[p]; + symcod = sharpsym[p]; + } + +if (pitch= MIDDLE + 12) { + emit_string("'"); + p = p - 12; + }; +while (p < MIDDLE - 12) { + emit_string(","); + p = p + 12; + }; +} + + +int main(argc,argv) +int argc; +char *argv[]; +{ + char *filename; + + oldchordconvention = 0; /* for handling +..+ chords */ + + /*for (i=0;i -#include -#ifdef ANSILIBS -#include -#endif -#include "midifile.h" - -static FILE *F; -int SECONDS; /* global that tells whether to display seconds or ticks */ -int division; /* from the file header */ -long tempo = 500000; /* the default tempo is 120 beats/minute */ - -filegetc() -{ - return(getc(F)); -} - -/* for crack */ -extern int arg_index; - -main(argc,argv) -char **argv; -{ - FILE *efopen(); - char *ch; - char *crack(); - - SECONDS = 0; - - while((ch = crack(argc,argv,"s",0)) != NULL){ - switch(*ch){ - case 's' : SECONDS = 1; break; - } - } - - if ((argc < 2 && !SECONDS) || (argc < 3 && SECONDS)) - F = stdin; - else - F = efopen(argv[arg_index],"rb"); - - initfuncs(); - Mf_getc = filegetc; - midifile(); - fclose(F); - exit(0); -} - -FILE * -efopen(name,mode) -char *name; -char *mode; -{ - FILE *f; - - if ( (f=fopen(name,mode)) == NULL ) { - fprintf(stderr,"Error - Cannot open file %s\n",name); - exit(0); - } - return(f); -} - -void error(s) -char *s; -{ - fprintf(stderr,"Error: %s\n",s); -} - -prtime() -{ - if(SECONDS) - printf("Time=%f ",mf_ticks2sec(Mf_currtime,division,tempo)); - else - printf("Time=%ld ",Mf_currtime); -} - -void txt_header(format,ntrks,ldivision) -{ - division = ldivision; - printf("Header format=%d ntrks=%d division=%d\n",format,ntrks,division); -} - -void txt_trackstart() -{ - printf("Track start\n"); -} - -void txt_trackend() -{ - printf("Track end\n"); -} - -void txt_noteon(chan,pitch,vol) -{ - prtime(); - printf("Note on, chan=%d pitch=%d vol=%d\n",chan+1,pitch,vol); -} - -void txt_noteoff(chan,pitch,vol) -{ - prtime(); - printf("Note off, chan=%d pitch=%d vol=%d\n",chan+1,pitch,vol); -} - -void txt_pressure(chan,pitch,press) -{ - prtime(); - printf("Pressure, chan=%d pitch=%d press=%d\n",chan+1,pitch,press); -} - -void txt_parameter(chan,control,value) -{ - prtime(); - printf("Parameter, chan=%d c1=%d c2=%d\n",chan+1,control,value); -} - -void txt_pitchbend(chan,msb,lsb) -{ - prtime(); - printf("Pitchbend, chan=%d msb=%d lsb=%d\n",chan+1,msb,lsb); -} - -void txt_program(chan,program) -{ - prtime(); - printf("Program, chan=%d program=%d\n",chan+1,program); -} - -void txt_chanpressure(chan,press) -{ - prtime(); - printf("Channel pressure, chan=%d pressure=%d\n",chan+1,press); -} - -void txt_sysex(leng,mess) -char *mess; -{ - prtime(); - printf("Sysex, leng=%d\n",leng); -} - -void txt_metamisc(type,leng,mess) -char *mess; -{ - prtime(); - printf("Meta event, unrecognized, type=0x%02x leng=%d\n",type,leng); -} - -void txt_metaspecial(type,leng,mess) -char *mess; -{ - prtime(); - printf("Meta event, sequencer-specific, type=0x%02x leng=%d\n",type,leng); -} - -void txt_metatext(type,leng,mess) -char *mess; -{ - static char *ttype[] = { - NULL, - "Text Event", /* type=0x01 */ - "Copyright Notice", /* type=0x02 */ - "Sequence/Track Name", - "Instrument Name", /* ... */ - "Lyric", - "Marker", - "Cue Point", /* type=0x07 */ - "Unrecognized" - }; - int unrecognized = (sizeof(ttype)/sizeof(char *)) - 1; - register int n, c; - register char *p = mess; - - if ( type < 1 || type > unrecognized ) - type = unrecognized; - prtime(); - printf("Meta Text, type=0x%02x (%s) leng=%d\n",type,ttype[type],leng); - printf(" Text = <"); - for ( n=0; n\n"); -} - -void txt_metaseq(num) -{ - prtime(); - printf("Meta event, sequence number = %d\n",num); -} - -void txt_metaeot() -{ - prtime(); - printf("Meta event, end of track\n"); -} - -void txt_keysig(sf,mi) -{ - prtime(); - printf("Key signature, sharp/flats=%d minor=%d\n",sf,mi); -} - -void txt_tempo(ltempo) -long ltempo; -{ - tempo = ltempo; - prtime(); - printf("Tempo, microseconds-per-MIDI-quarter-note=%ld\n",tempo); -} - -void txt_timesig(nn,dd,cc,bb) -{ - int denom = 1; - while ( dd-- > 0 ) - denom *= 2; - prtime(); - printf("Time signature=%d/%d MIDI-clocks/click=%d 32nd-notes/24-MIDI-clocks=%d\n", - nn,denom,cc,bb); -} - -void txt_smpte(hr,mn,se,fr,ff) -{ - prtime(); - printf("SMPTE, hour=%d minute=%d second=%d frame=%d fract-frame=%d\n", - hr,mn,se,fr,ff); -} - -void txt_arbitrary(leng,mess) -char *mess; -{ - prtime(); - printf("Arbitrary bytes, leng=%d\n",leng); -} - -initfuncs() -{ - Mf_error = error; - Mf_header = txt_header; - Mf_trackstart = txt_trackstart; - Mf_trackend = txt_trackend; - Mf_noteon = txt_noteon; - Mf_noteoff = txt_noteoff; - Mf_pressure = txt_pressure; - Mf_parameter = txt_parameter; - Mf_pitchbend = txt_pitchbend; - Mf_program = txt_program; - Mf_chanpressure = txt_chanpressure; - Mf_sysex = txt_sysex; - Mf_metamisc = txt_metamisc; - Mf_seqnum = txt_metaseq; - Mf_eot = txt_metaeot; - Mf_timesig = txt_timesig; - Mf_smpte = txt_smpte; - Mf_tempo = txt_tempo; - Mf_keysig = txt_keysig; - Mf_seqspecific = txt_metaspecial; - Mf_text = txt_metatext; - Mf_arbitrary = txt_arbitrary; -} +/* + * mftext + * + * Convert a MIDI file to verbose text. + * + * modified for portability 22/6/98 - error checking on file open failure + * removed. + */ + +#include +#if defined(ANSILIBS) || defined(__STDC__) +#include +#include +#endif +#include "midifile.h" + +static FILE *F; +int SECONDS; /* global that tells whether to display seconds or ticks */ +int division; /* from the file header */ +long tempo = 500000; /* the default tempo is 120 beats/minute */ + +filegetc() +{ + return(getc(F)); +} + +/* for crack */ +extern int arg_index; + +main(argc,argv) +char **argv; +{ + FILE *efopen(); + char *ch; + char *crack(); + + SECONDS = 0; + + while((ch = crack(argc,argv,"s",0)) != NULL){ + switch(*ch){ + case 's' : SECONDS = 1; break; + } + } + + if ((argc < 2 && !SECONDS) || (argc < 3 && SECONDS)) + F = stdin; + else + F = efopen(argv[arg_index],"rb"); + + initfuncs(); + Mf_getc = filegetc; + midifile(); + fclose(F); + exit(0); +} + +FILE * +efopen(name,mode) +char *name; +char *mode; +{ + FILE *f; + + if ( (f=fopen(name,mode)) == NULL ) { + fprintf(stderr,"Error - Cannot open file %s\n",name); + exit(0); + } + return(f); +} + +void error(s) +char *s; +{ + fprintf(stderr,"Error: %s\n",s); +} + +prtime() +{ + if(SECONDS) + printf("Time=%f ",mf_ticks2sec(Mf_currtime,division,tempo)); + else + printf("Time=%ld ",Mf_currtime); +} + +void txt_header(format,ntrks,ldivision) +{ + division = ldivision; + printf("Header format=%d ntrks=%d division=%d\n",format,ntrks,division); +} + +void txt_trackstart() +{ + printf("Track start\n"); +} + +void txt_trackend() +{ + printf("Track end\n"); +} + +void txt_noteon(chan,pitch,vol) +{ + prtime(); + printf("Note on, chan=%d pitch=%d vol=%d\n",chan+1,pitch,vol); +} + +void txt_noteoff(chan,pitch,vol) +{ + prtime(); + printf("Note off, chan=%d pitch=%d vol=%d\n",chan+1,pitch,vol); +} + +void txt_pressure(chan,pitch,press) +{ + prtime(); + printf("Pressure, chan=%d pitch=%d press=%d\n",chan+1,pitch,press); +} + +void txt_parameter(chan,control,value) +{ + prtime(); + printf("Parameter, chan=%d c1=%d c2=%d\n",chan+1,control,value); +} + +void txt_pitchbend(chan,msb,lsb) +{ + prtime(); + printf("Pitchbend, chan=%d msb=%d lsb=%d\n",chan+1,msb,lsb); +} + +void txt_program(chan,program) +{ + prtime(); + printf("Program, chan=%d program=%d\n",chan+1,program); +} + +void txt_chanpressure(chan,press) +{ + prtime(); + printf("Channel pressure, chan=%d pressure=%d\n",chan+1,press); +} + +void txt_sysex(leng,mess) +char *mess; +{ + prtime(); + printf("Sysex, leng=%d\n",leng); +} + +void txt_metamisc(type,leng,mess) +char *mess; +{ + prtime(); + printf("Meta event, unrecognized, type=0x%02x leng=%d\n",type,leng); +} + +void txt_metaspecial(type,leng,mess) +char *mess; +{ + prtime(); + printf("Meta event, sequencer-specific, type=0x%02x leng=%d\n",type,leng); +} + +void txt_metatext(type,leng,mess) +char *mess; +{ + static char *ttype[] = { + NULL, + "Text Event", /* type=0x01 */ + "Copyright Notice", /* type=0x02 */ + "Sequence/Track Name", + "Instrument Name", /* ... */ + "Lyric", + "Marker", + "Cue Point", /* type=0x07 */ + "Unrecognized" + }; + int unrecognized = (sizeof(ttype)/sizeof(char *)) - 1; + register int n, c; + register char *p = mess; + + if ( type < 1 || type > unrecognized ) + type = unrecognized; + prtime(); + printf("Meta Text, type=0x%02x (%s) leng=%d\n",type,ttype[type],leng); + printf(" Text = <"); + for ( n=0; n\n"); +} + +void txt_metaseq(num) +{ + prtime(); + printf("Meta event, sequence number = %d\n",num); +} + +void txt_metaeot() +{ + prtime(); + printf("Meta event, end of track\n"); +} + +void txt_keysig(sf,mi) +{ + prtime(); + printf("Key signature, sharp/flats=%d minor=%d\n",sf,mi); +} + +void txt_tempo(ltempo) +long ltempo; +{ + tempo = ltempo; + prtime(); + printf("Tempo, microseconds-per-MIDI-quarter-note=%ld\n",tempo); +} + +void txt_timesig(nn,dd,cc,bb) +{ + int denom = 1; + while ( dd-- > 0 ) + denom *= 2; + prtime(); + printf("Time signature=%d/%d MIDI-clocks/click=%d 32nd-notes/24-MIDI-clocks=%d\n", + nn,denom,cc,bb); +} + +void txt_smpte(hr,mn,se,fr,ff) +{ + prtime(); + printf("SMPTE, hour=%d minute=%d second=%d frame=%d fract-frame=%d\n", + hr,mn,se,fr,ff); +} + +void txt_arbitrary(leng,mess) +char *mess; +{ + prtime(); + printf("Arbitrary bytes, leng=%d\n",leng); +} + +initfuncs() +{ + Mf_error = error; + Mf_header = txt_header; + Mf_trackstart = txt_trackstart; + Mf_trackend = txt_trackend; + Mf_noteon = txt_noteon; + Mf_noteoff = txt_noteoff; + Mf_pressure = txt_pressure; + Mf_parameter = txt_parameter; + Mf_pitchbend = txt_pitchbend; + Mf_program = txt_program; + Mf_chanpressure = txt_chanpressure; + Mf_sysex = txt_sysex; + Mf_metamisc = txt_metamisc; + Mf_seqnum = txt_metaseq; + Mf_eot = txt_metaeot; + Mf_timesig = txt_timesig; + Mf_smpte = txt_smpte; + Mf_tempo = txt_tempo; + Mf_keysig = txt_keysig; + Mf_seqspecific = txt_metaspecial; + Mf_text = txt_metatext; + Mf_arbitrary = txt_arbitrary; +} --- abcmidi-20070318.orig/doc/abcmatch.1 +++ abcmidi-20070318/doc/abcmatch.1 @@ -0,0 +1,177 @@ +.TH ABCMATCH 1 "24 August 2007" +.SH NAME +abcmatch \- search sequences of notes in an ABC file +.SH SYNOPSIS +\fBabcmatch\fP \fIdata-file\fP [\fInumber\fR] [-a] [-br \fId\fP] [-c] [-con] [-ign] [-length_hist] [-pitch_hist] [-qnt] [-r \fIn\fP] [-v] [-ver] +.SH "DESCRIPTION" +.PP +.B abcmatch +searches an ABC file containing (potentially) many tunes for specific +sequences of notes. For example, if you know a few bars of a tune, you +can use this program to find the tune having this sequence and perhaps +identify the tune. +.PP +At a minimum, abcmatch requires two files. A \fItemplate file\fP called +\fBmatch.abc\fP which contains the bars that you are searching for and +a large file consisting of a hundred or more ABC tunes. +The program automatically loads up the match.abc file and +then scans every tune in the large file. +.PP +Though the program can be run stand-alone, it is really meant to be +run with a GUI such as runabc.tcl (which is not yet part of +Debian). Most of its output is rather cryptic. +.SH "THE MATCHING PROCESS" +.PP +The \fItemplate file\fR must be a well-formed ABC file containing the +basic \fBX:\fP, \fBM:\fP, \fBL:\fP, and \fBK:\fP headers as well as +the bars to be matched. (Normally, this file is created by +runabc.tcl.) It is important to finish each bar in the match file with +a vertical line. +.PP +.B abcmatch +uses the key signature to figure out the relative position of the +notes in the scale, and to determine all the assumed sharps and +flats. Therefore the program can find matching bars in a tune that has +been transposed to another key, as long as the key difference is not +too large. Matches are output in a list format looking like +.P +29 30 4 +.br +30 31 4 + +.PP +Each line indicates a particular match found by the program. The first +number on each line gives the relative position of the tune in the +\fIdata-file\fP, while the next number gives the \fBX:\fP number of +that tune. The last number is the bar number of the matching tune. Bar +numbers are counted sequentially from the start of the tune, and all +\fBV:\fP and \fBP:\fP indications are ignored. That is, the bar number +returned by \fBabcmatch\fP may not match bar numbers printed by one of +the PostScript-producing ABC processors such as \fBabcm2ps\fP or +\fBabcmidi-yaps\fP. +.PP +For the purposes of matching, \fBabcmatch\fP ignores all guitar +chords, lyrics, note decorations (e.g., staccato markings), grace +notes, etc. In chords such as \fB[G2c2]\fP, only the highest note is +considered. Any warnings or error messages from the ABC parser are +suppressed unless the \fB-c\fP option is given. + +.SH OPTIONS +.TP +.B \-a +Report any matching bars. By default, if the template file contains a +sequence of several bars, the program will try to find places in the +data file where the whole sequence matches. With this option, it +returns all places in the data file where \fIany\fP of the bars in the +template file match. +.TP +.BI \-br " d" +`Brief mode' is designed to identify groups of tunes sharing common +bars. In this mode, the program determines the number of all bars in each +tune from the data file which are also present in the template +file. If the number of common bars is greater than or equal to the +value of the \fId\fP parameter, the program reports the tune and the +number of common bars. Currently there is no user control of the +matching criterion; the rhythm must match exactly, and the notes are +transposed to suit the key signature. +.TP +.B \-c +Display error and warning messages from the ABC parser (which are +suppressed by default). +.TP +.B \-con +Do a pitch contour match. In this case, the program uses the key +signature only to indicate accidentals. The pitch contour is computed +from the pitch difference (interval) between adjacent notes. That is, +\fBC2 DE\fP, \fBc2 de\fP, and \fBG2 AB\fP all have the same pitch +contour. +.TP +.B \-ign +Ignore simple bars. +.TP +.B \-length_hist +This does no matching at all but returns a histogram of the +distribution of note lengths in the data file. The output looks like + +.RS +length histogram +.br +12 100 +.br +24 20 +.br +36 6 +.br +48 2 +.br +72 4 +.RE + +.RS +where a quarter note is 24 units, an eight note 12 units, a dotted +half note 72 units etc. +.RE +.TP +.B \-pitch_hist +This does no matching at all but returns a histogram of the +distribution of pitches in the data file. The output looks like + +.RS +pitch histogram +.br +64 2 +.br +66 9 +.br +67 11 +... +.RE + +.RS +where the first number on each line is a MIDI note number and the +second is a count of the number of times that note occurred. +.RE +.TP +.B \-qnt +Do a quantized pitch contour match. This works as described above for +the \fB-con\fP option, but will also quantize the intervals as +follows: Unison and semitone intervals are assigned value 0, major +2nds to major 3rds value 1, and a perfect 4th or greater value +2. Negative numbers are used for descending intervals. +.TP +.BI \-r " n" +Resolution for matching. If the \fIn\fP parameter is zero, a perfect +match must be found, meaning that the lengths of each note in a bar +must match exactly in order to be reported. The larger the value of +\fIn\fP, the looser the match will be. Note lengths are converted into +temporal units where a quarter note is normally assigned a value of 24 +(therefore an eighth note has a value of 12, a sixteenth a value of 6, +a half note a value of 48 etc.) If you specify a temporal resolution +of 12, then the pitch values of the notes only need to match at the +time units that are multiples of an eight note. This means that the +program would match the two bars \fBC2 D2\fP and \fBC C D D\fP, as +well as \fBC2 D2\fP and \fBC/D/C/D/D2\fP. By selecting a suitable +value for \fIn\fP, you can search for matches only at the beginning of +a measure or at the beginning of each beat. +.TP +.B \-v +Run verbosely. +.TP +.B \-ver +Display the program's version number. +.SH LIMITATIONS +.PP +The program has some limitations. For example, the data file must +contain bar lines, and tied notes cannot be longer than the equivalent +of 8 quarter notes. A resolution (\fB-r\fP option) that is too small +may cause some buffers to be exceeded. When there are differences of +key signatures of more than 5 semitones, the program may transpose the +notes in the wrong direction. Also, tunes with more than one key +signature or time signature may not be processed correctly. +.SH "SEE ALSO" +.IR abc2midi "(1), " midi2abc "(1), " mftext "(1)" +.SH AUTHOR +This manual page was written by Anselm Lingnau +for the GNU/Linux system. +.SH VERSION +This manual page describes abcmatch version 1.42 as of 21 December 2006. --- abcmidi-20070318.orig/midi2abc.c +++ abcmidi-20070318/midi2abc.c @@ -1,3507 +1,3506 @@ -/* - * midi2abc - program to convert MIDI files to abc notation. - * Copyright (C) 1998 James Allwright - * e-mail: J.R.Allwright@westminster.ac.uk - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -/* new midi2abc - converts MIDI file to abc format files - * - * - * re-written to use dynamic data structures - * James Allwright - * 5th June 1998 - * - * added output file option -o - * added summary option -sum - * added option -u to enter xunit directly - * fixed computation of xunit using -b option - * added -obpl (one bar per line) option - * add check for carriage return embedded inside midi text line - * Seymour Shlien 04/March/00 - * made to conform as much as possible to the official version. - * check for drum track added - * when midi program channel is command encountered, we ensure that - * we are using the correct channel number for the Voice by sending - * a %%MIDI channel message. - * - * Many more changes (see doc/CHANGES) - * - * Seymour Shlien 2005 - * - * based on public domain 'midifilelib' package. - */ - -#define VERSION "2.90 March 15 2007" -#define SPLITCODE - -/* Microsoft Visual C++ Version 6.0 or higher */ -#ifdef _MSC_VER -#define ANSILIBS -#endif - -#include -#ifdef PCCFIX -#define stdout 1 -#endif - -/* define USE_INDEX if your C libraries have index() instead of strchr() */ -#ifdef USE_INDEX -#define strchr index -#endif - -#ifdef ANSILIBS -#include -#include -#include -#else -extern char* malloc(); -extern char* strchr(); -#endif -#include "midifile.h" -#define BUFFSIZE 200 -/* declare MIDDLE C */ -#define MIDDLE 72 -void initfuncs(); -void setupkey(int); -int testtrack(int trackno, int barbeats, int anacrusis); -int open_note(int chan, int pitch, int vol); -int close_note(int chan, int pitch, int *initvol); - - -/* Global variables and structures */ - -extern long Mf_toberead; - -static FILE *F; -static FILE *outhandle; /* for producing the abc file */ - -int tracknum=0; /* track number */ -int division; /* pulses per quarter note defined in MIDI header */ -long tempo = 500000; /* the default tempo is 120 quarter notes/minute */ -int unitlen; /* abc unit length usually defined in L: field */ -int header_unitlen; /* first unitlen set */ -int unitlen_set =0; /* once unitlen is set don't allow it to change */ -int parts_per_unitlen = 2; /* specifies minimum quantization size */ -long laston = 0; /* length of MIDI track in pulses or ticks */ -char textbuff[BUFFSIZE]; /*buffer for handling text output to abc file*/ -int trans[256], back[256]; /*translation tables for MIDI pitch to abc note*/ -char atog[256]; /* translation tables for MIDI pitch to abc note */ -int symbol[256]; /*translation tables for MIDI pitch to abc note */ -int key[12]; -int sharps; -int trackno, maintrack; -int format; /* MIDI file type */ - -int karaoke, inkaraoke; -int midline; -int tempocount=0; /* number of tempo indications in MIDI file */ -int gotkeysig=0; /*set to 1 if keysignature found in MIDI file */ - -/* global parameters that may be set by command line options */ -int xunit; /* pulses per abc unit length */ -int tsig_set; /* flag - time signature already set by user */ -int ksig_set; /* flag - key signature already set by user */ -int xunit_set;/* flat - xunit already set by user */ -int extracta; /* flag - get anacrusis from strong beat */ -int guessu; /* flag - estimate xunit from note durations */ -int guessa; /* flag - get anacrusis by minimizing tied notes */ -int guessk; /* flag - guess key signature */ -int summary; /* flag - output summary info of MIDI file */ -int keep_short; /*flag - preserve short notes */ -int swallow_rests; /* flag - absorb short rests */ -int midiprint; /* flag - run midigram instead of midi2abc */ -#ifdef SPLITCODE -int usesplits; /* flag - split measure into parts if needed */ -#endif -int restsize; /* smallest rest to absorb */ -int no_triplets; /* flag - suppress triplets or broken rhythm */ -int obpl = 0; /* flag to specify one bar per abc text line */ -int nogr = 0; /* flag to put a space between every note */ -int bars_per_line=4; /* number of bars per output line */ -int bars_per_staff=4; /* number of bars per music staff */ -int asig, bsig; /* time signature asig/bsig */ -int header_asig =0; /* first time signature encountered */ -int header_bsig =0; /* first time signature encountered */ -int header_bb; /* first ticks/quarter note encountered */ -int active_asig,active_bsig; /* last time signature declared */ -int last_asig, last_ksig; /* last time signature printed */ -int barsize; /* barsize in parts_per_unitlen units */ -int Qval; /* tempo - quarter notes per minute */ -int verbosity=0; /* control amount of detail messages in abcfile*/ - -/* global arguments dependent on command line options or computed */ - -int anacrusis=0; -int bars; -int keysig; -int header_keysig= -50; /* header key signature */ -int active_keysig = -50; /* last key signature declared */ -int xchannel; /* channel number to be extracted. -1 means all */ - - -/* structure for storing music notes */ -struct anote { - int pitch; /* MIDI pitch */ - int chan; /* MIDI channel */ - int vel; /* MIDI velocity */ - long time; /* MIDI onset time in pulses */ - long dtnext; /* time increment to next note in pulses */ - long tplay; /* note duration in pulses */ - int xnum; /* number of xunits to next note */ - int playnum; /* note duration in number of xunits */ - int posnum; /* note position in xunits */ - int splitnum; /* voice split number */ - /* int denom; */ -}; - - -/* linked list of notes */ -struct listx { - struct listx* next; - struct anote* note; -}; - -/* linked list of text items (strings) */ -struct tlistx { - struct tlistx* next; - char* text; - long when; /* time in pulses to output */ - int type; /* 0 - comments, other - field commands */ -}; - - -/* a MIDI track */ -struct atrack { - struct listx* head; /* first note */ - struct listx* tail; /* last note */ - struct tlistx* texthead; /* first text string */ - struct tlistx* texttail; /* last text string */ - int notes; /* number of notes in track */ - long tracklen; - long startwait; - int startunits; - int drumtrack; -}; - -/* can cope with up to 64 track MIDI files */ -struct atrack track[64]; -int trackcount = 0; -int maxbarcount = 0; -/* maxbarcount is used to return the numbers of bars created.*/ -/* obpl is a flag for one bar per line. */ - -/* double linked list of notes */ -/* used for temporary list of chords while abc is being generated */ -struct dlistx { - struct dlistx* next; - struct dlistx* last; - struct anote* note; -}; - -int notechan[2048],notechanvol[2048]; /*for linking on and off midi - channel commands */ -int last_tick; /* for getting last pulse number in MIDI file */ - - - -void remove_carriage_returns(); -int validnote(); -void printpitch(struct anote*); -void printfract(int, int); - - - - - -/* Stage 1. Parsing MIDI file */ - -/* Functions called during the reading pass of the MIDI file */ - -/* The following C routines are required by midifilelib. */ -/* They specify the action to be taken when various items */ -/* are encountered in the MIDI. The mfread function scans*/ -/* the MIDI file and calls these functions when needed. */ - - -int filegetc() -{ - return(getc(F)); -} - - -void fatal_error(s) -char* s; -/* fatal error encounterd - abort program */ -{ - fprintf(stderr, "%s\n", s); - exit(1); -} - - -void event_error(s) -char *s; -/* problem encountered but OK to continue */ -{ - char msg[256]; - - sprintf(msg, "Error: Time=%ld Track=%d %s\n", Mf_currtime, trackno, s); - printf(msg); -} - - -int* checkmalloc(bytes) -/* malloc with error checking */ -int bytes; -{ - int *p; - - p = (int*) malloc(bytes); - if (p == NULL) { - fatal_error("Out of memory error - cannot malloc!"); - }; - return (p); -} - - - -char* addstring(s) -/* create space for string and store it in memory */ -char* s; -{ - char* p; - - p = (char*) checkmalloc(strlen(s)+1); - strcpy(p, s); - return(p); -} - -void addtext(s, type) -/* add structure for text */ -/* used when parsing MIDI file */ -char* s; -int type; -{ - struct tlistx* newx; - - newx = (struct tlistx*) checkmalloc(sizeof(struct tlistx)); - newx->next = NULL; - newx->text = addstring(s); - newx->type = type; - newx->when = Mf_currtime; - if (track[trackno].texthead == NULL) { - track[trackno].texthead = newx; - track[trackno].texttail = newx; - } - else { - track[trackno].texttail->next = newx; - track[trackno].texttail = newx; - }; -} - - - -/* The MIDI file has separate commands for starting */ -/* and stopping a note. In order to determine the duration of */ -/* the note it is necessary to find the note_on command associated */ -/* with the note off command. We rely on the note's pitch and channel*/ -/* number to find the right note. While we are parsing the MIDI file */ -/* we maintain a list of all the notes that are currently on */ -/* head and tail of list of notes still playing. */ -/* The following doubly linked list is used for this purpose */ - -struct dlistx* playinghead; -struct dlistx* playingtail; - - -void noteplaying(p) -/* This function adds a new note to the playinghead list. */ -struct anote* p; -{ - struct dlistx* newx; - - newx = (struct dlistx*) checkmalloc(sizeof(struct dlistx)); - newx->note = p; - newx->next = NULL; - newx->last = playingtail; - if (playinghead == NULL) { - playinghead = newx; - }; - if (playingtail == NULL) { - playingtail = newx; - } - else { - playingtail->next = newx; - playingtail = newx; - }; -} - - -void addnote(p, ch, v) -/* add structure for note */ -/* used when parsing MIDI file */ -int p, v; -{ - struct listx* newx; - struct anote* newnote; - - track[trackno].notes = track[trackno].notes + 1; - newx = (struct listx*) checkmalloc(sizeof(struct listx)); - newnote = (struct anote*) checkmalloc(sizeof(struct anote)); - newx->next = NULL; - newx->note = newnote; - if (track[trackno].head == NULL) { - track[trackno].head = newx; - track[trackno].tail = newx; - } - else { - track[trackno].tail->next = newx; - track[trackno].tail = newx; - }; - if (ch == 9) { - track[trackno].drumtrack = 1; - }; - newnote->pitch = p; - newnote->chan = ch; - newnote->vel = v; - newnote->time = Mf_currtime; - laston = Mf_currtime; - newnote->tplay = Mf_currtime; - noteplaying(newnote); -} - - - -void notestop(p, ch) -/* MIDI note stops */ -/* used when parsing MIDI file */ -int p, ch; -{ - struct dlistx* i; - int found; - char msg[80]; - - i = playinghead; - found = 0; - while ((found == 0) && (i != NULL)) { - if ((i->note->pitch == p)&&(i->note->chan==ch)) { - found = 1; - } - else { - i = i->next; - }; - }; - if (found == 0) { - sprintf(msg, "Note terminated when not on - pitch %d", p); - event_error(msg); - return; - }; - /* fill in tplay field */ - i->note->tplay = Mf_currtime - (i->note->tplay); - /* remove note from list */ - if (i->last == NULL) { - playinghead = i->next; - } - else { - (i->last)->next = i->next; - }; - if (i->next == NULL) { - playingtail = i->last; - } - else { - (i->next)->last = i->last; - }; - free(i); -} - - - - -FILE * -efopen(name,mode) -char *name; -char *mode; -{ - FILE *f; - - if ( (f=fopen(name,mode)) == NULL ) { - char msg[256]; - sprintf(msg,"Error - Cannot open file %s",name); - fatal_error(msg); - } - return(f); -} - - -void error(s) -char *s; -{ - fprintf(stderr,"Error: %s\n",s); -} - - - -void txt_header(xformat,ntrks,ldivision) -int xformat, ntrks, ldivision; -{ - division = ldivision; - format = xformat; - if (format != 0) { - /* fprintf(outhandle,"%% format %d file %d tracks\n", format, ntrks);*/ - if(summary>0) printf("This midi file has %d tracks\n\n",ntrks); - } - else { -/* fprintf(outhandle,"%% type 0 midi file\n"); */ - if(summary>0) { - printf("This is a type 0 midi file.\n"); - printf("All the channels are in one track.\n"); - printf("You may need to process the channels separately\n\n"); - } - } - -} - - -void txt_trackstart() -{ - laston = 0L; - track[trackno].notes = 0; - track[trackno].head = NULL; - track[trackno].tail = NULL; - track[trackno].texthead = NULL; - track[trackno].texttail = NULL; - track[trackno].tracklen = Mf_currtime; - track[trackno].drumtrack = 0; -} - -void txt_trackend() -{ - /* check for unfinished notes */ - if (playinghead != NULL) { - printf("Error in MIDI file - notes still on at end of track!\n"); - }; - track[trackno].tracklen = Mf_currtime - track[trackno].tracklen; - trackno = trackno + 1; - trackcount = trackcount + 1; -} - -void txt_noteon(chan,pitch,vol) -int chan, pitch, vol; -{ - if ((xchannel == -1) || (chan == xchannel)) { - if (vol != 0) { - addnote(pitch, chan, vol); - } - else { - notestop(pitch, chan); - }; - }; -} - -void txt_noteoff(chan,pitch,vol) -int chan, pitch, vol; -{ - if ((xchannel == -1) || (chan == xchannel)) { - notestop(pitch, chan); - }; -} - -void txt_pressure(chan,pitch,press) -int chan, pitch, press; -{ -} - -void txt_parameter(chan,control,value) -int chan, control, value; -{ -} - -void txt_pitchbend(chan,msb,lsb) -int chan, msb, lsb; -{ -} - -void txt_program(chan,program) -int chan, program; -{ -/* - sprintf(textbuff, "%%%%MIDI program %d %d", - chan+1, program); -*/ - sprintf(textbuff, "%%%%MIDI program %d", program); - addtext(textbuff,0); -/* abc2midi does not use the same channel number as specified in - the original midi file, so we should not specify that channel - number in the %%MIDI program. If we leave it out the program - will refer to the current channel assigned to this voice. -*/ -} - -void txt_chanpressure(chan,press) -int chan, press; -{ -} - -void txt_sysex(leng,mess) -int leng; -char *mess; -{ -} - -void txt_metamisc(type,leng,mess) -int type, leng; -char *mess; -{ -} - -void txt_metaspecial(type,leng,mess) -int type, leng; -char *mess; -{ -} - -void txt_metatext(type,leng,mess) -int type, leng; -char *mess; -{ - char *ttype[] = { - NULL, - "Text Event", /* type=0x01 */ - "Copyright Notice", /* type=0x02 */ - "Sequence/Track Name", - "Instrument Name", /* ... */ - "Lyric", - "Marker", - "Cue Point", /* type=0x07 */ - "Unrecognized" - }; - int unrecognized = (sizeof(ttype)/sizeof(char *)) - 1; - unsigned char c; - int n; - char *p = mess; - char *buff; - char buffer2[BUFFSIZE]; - - if ((type < 1)||(type > unrecognized)) - type = unrecognized; - buff = textbuff; - for (n=0; n0) return; /* ignore other tempo indications */ - tempo = ltempo; - tempocount++; -} - - -void setup_timesig(nn, denom, bb) -int nn,denom,bb; -{ - asig = nn; - bsig = denom; -/* we must keep unitlen and xunit fixed for the entire tune */ - if (unitlen_set == 0) { - unitlen_set = 1; - if ((asig*4)/bsig >= 3) { - unitlen =8; - } - else { - unitlen = 16; - }; - } -/* set xunit for this unitlen */ - if(!xunit_set) xunit = (division*bb*4)/(8*unitlen); - barsize = parts_per_unitlen*asig*unitlen/bsig; -/* printf("setup_timesig: unitlen=%d xunit=%d barsize=%d\n",unitlen,xunit,barsize); */ - if (header_asig ==0) {header_asig = asig; - header_bsig = bsig; - header_unitlen = unitlen; - header_bb = bb; - } -} - - -void txt_timesig(nn,dd,cc,bb) -int nn, dd, cc, bb; -{ - int denom = 1; - while ( dd-- > 0 ) - denom *= 2; - sprintf(textbuff, - "%% Time signature=%d/%d MIDI-clocks/click=%d 32nd-notes/24-MIDI-clocks=%d", - nn,denom,cc,bb); - if (verbosity) addtext(textbuff,0); - sprintf(textbuff,"%d %d %d\n",nn,denom,bb); - if (!tsig_set) { - addtext(textbuff,2); - setup_timesig(nn, denom,bb); - } - if (summary>0) { - if(tsig_set) printf("Time signature = %d/%d suppressed\n",nn,denom); - else printf("Time signature = %d/%d\n",nn,denom); - } -} - - -void txt_smpte(hr,mn,se,fr,ff) -int hr, mn, se, fr, ff; -{ -} - -void txt_arbitrary(leng,mess) -char *mess; -int leng; -{ -} - - - -/* Dummy functions for handling MIDI messages. - * */ - void no_op0() {} - void no_op1(int dummy1) {} - void no_op2(int dummy1, int dummy2) {} - void no_op3(int dummy1, int dummy2, int dummy3) { } - void no_op4(int dummy1, int dummy2, int dummy3, int dummy4) { } - void no_op5(int dummy1, int dummy2, int dummy3, int dummy4, int dummy5) { } - - - -void print_txt_noteon(chan, pitch, vol) -{ -int start_time; -int initvol; -if (vol > 0) -open_note(chan, pitch, vol); -else { - start_time = close_note(chan, pitch,&initvol); - if (start_time >= 0) - /* printf("%8.4f %8.4f %d %d %d %d\n", - (double) start_time/(double) division, - (double) Mf_currtime/(double) division, - trackno+1, chan +1, pitch,initvol); - */ - printf("%d %ld %d %d %d %d\n", - start_time, Mf_currtime, trackno+1, chan +1, pitch,initvol); - - if(Mf_currtime > last_tick) last_tick = Mf_currtime; - } -} - - - -void print_txt_noteoff(chan, pitch, vol) -{ -int start_time,initvol; - -start_time = close_note(chan, pitch, &initvol); -if (start_time >= 0) -/* - printf("%8.4f %8.4f %d %d %d %d\n", - (double) start_time/(double) division, - (double) Mf_currtime/(double) division, - trackno+1, chan+1, pitch,initvol); -*/ - printf("%d %ld %d %d %d %d\n", - start_time, Mf_currtime, trackno+1, chan +1, pitch,initvol); - if(Mf_currtime > last_tick) last_tick = Mf_currtime; -} - - - -/* In order to associate a channel note off message with its - * corresponding note on message, we maintain the information - * the notechan array. When a midi pitch (0-127) is switched - * on for a particular channel, we record the time that it - * was turned on in the notechan array. As there are 16 channels - * and 128 pitches, we initialize an array 128*16 = 2048 elements - * long. -**/ -void init_notechan() -{ -/* signal that there are no active notes */ - int i; - for (i = 0; i < 2048; i++) notechan[i] = -1; -} - - -/* The next two functions update notechan when a channel note on - or note off is encountered. The second function close_note, - returns the time when the note was turned on. -*/ -int open_note(int chan, int pitch, int vol) -{ - notechan[128 * chan + pitch] = Mf_currtime; - notechanvol[128 * chan + pitch] = vol; - return 0; -} - - -int close_note(int chan, int pitch, int *initvol) -{ - int index, start_tick; - index = 128 * chan + pitch; - if (notechan[index] < 0) - return -1; - start_tick = notechan[index]; - *initvol = notechanvol[index]; - notechan[index] = -1; - return start_tick; -} - - -/* mftext mode */ -int prtime() -{ -/* if(Mf_currtime >= pulses) ignore=0; - if (ignore) return 1; - linecount++; - if(linecount > maxlines) {fclose(F); exit(0);} -*/ - int units; - units = 2; - if(units==1) - /*seconds*/ - printf("%6.2f ",mf_ticks2sec(Mf_currtime,division,tempo)); - else if (units==2) - /*beats*/ - printf("%6.2f ",(float) Mf_currtime/(float) division); - else - /*pulses*/ - printf("%6ld ",Mf_currtime); - return 0; -} - -char * pitch2key(int note) -{ -static char name[5]; -char* s = name; - switch(note % 12) - { - case 0: *s++ = 'c'; break; - case 1: *s++ = 'c'; *s++ = '#'; break; - case 2: *s++ = 'd'; break; - case 3: *s++ = 'd'; *s++ = '#'; break; - case 4: *s++ = 'e'; break; - case 5: *s++ = 'f'; break; - case 6: *s++ = 'f'; *s++ = '#'; break; - case 7: *s++ = 'g'; break; - case 8: *s++ = 'g'; *s++ = '#'; break; - case 9: *s++ = 'a'; break; - case 10: *s++ = 'a'; *s++ = '#'; break; - case 11: *s++ = 'b'; break; - } - sprintf(s, "%d", (note / 12)-1); /* octave (assuming Piano C4 is 60)*/ - return name; -} - -void mftxt_header (int format, int ntrks, int ldivision) -{ - division = ldivision; - printf("Header format=%d ntrks=%d division=%d\n",format,ntrks,division); -} - -void mftxt_trackstart() -{ - int numbytes; - tracknum++; - numbytes = Mf_toberead; - /*if(track != 0 && tracknum != track) {ignore_bytes(numbytes); return;} */ - printf("Track %d contains %d bytes\n",tracknum,numbytes); -} - - -void mftxt_noteon(chan,pitch,vol) -{ - char *key; -/* - if (onlychan >=0 && chan != onlychan) return; -*/ - if (prtime()) return; - key = pitch2key(pitch); - printf("Note on %2d %3s %3d\n",chan+1, key,vol); -} - -void mftxt_noteoff(chan,pitch,vol) -{ - char *key; -/* - if (onlychan >=0 && chan != onlychan) return; -*/ - if (prtime()) return; - key = pitch2key(pitch); - printf("Note off %2d %3s %3d\n",chan+1,key,vol); -} - -void mftxt_pressure(chan,pitch,press) -{ - char *key; - if (prtime()) return; - key = pitch2key(pitch); - printf("Pressure %2d %3s %3d\n",chan+1,key,press); -} - - -void mftxt_pitchbend(chan,msb,lsb) -{ -/* - if (onlychan >=0 && chan != onlychan) return; -*/ - if (prtime()) return; - printf("Pitchbnd %2d msb=%d lsb=%d\n",chan+1,msb,lsb); -} - - - -void mftxt_program(chan,program) -{ -static char *patches[] = { - "Acoustic Grand","Bright Acoustic","Electric Grand","Honky-Tonk", - "Electric Piano 1","Electric Piano 2","Harpsichord","Clav", - "Celesta", "Glockenspiel", "Music Box", "Vibraphone", - "Marimba", "Xylophone", "Tubular Bells", "Dulcimer", - "Drawbar Organ", "Percussive Organ", "Rock Organ", "Church Organ", - "Reed Organ", "Accordian", "Harmonica", "Tango Accordian", - "Acoustic Guitar (nylon)", "Acoustic Guitar (steel)", - "Electric Guitar (jazz)", "Electric Guitar (clean)", - "Electric Guitar (muted)", "Overdriven Guitar", - "Distortion Guitar", "Guitar Harmonics", - "Acoustic Bass", "Electric Bass (finger)", - "Electric Bass (pick)", "Fretless Bass", - "Slap Bass 1", "Slap Bass 2", "Synth Bass 1", "Synth Bass 2", - "Violin", "Viola", "Cello", "Contrabass", - "Tremolo Strings", "Pizzicato Strings", - "Orchestral Strings", "Timpani", - "String Ensemble 1", "String Ensemble 2", - "SynthStrings 1", "SynthStrings 2", - "Choir Aahs", "Voice Oohs", "Synth Voice", "Orchestra Hit", - "Trumpet", "Trombone", "Tuba", "Muted Trumpet", - "French Horn", "Brass Section", "SynthBrass 1", "SynthBrass 2", - "Soprano Sax", "Alto Sax", "Tenor Sax", "Baritone Sax", - "Oboe", "English Horn", "Bassoon", "Clarinet", - "Piccolo", "Flute", "Recorder", "Pan Flute", - "Blown Bottle", "Skakuhachi", "Whistle", "Ocarina", - "Lead 1 (square)", "Lead 2 (sawtooth)", - "Lead 3 (calliope)", "Lead 4 (chiff)", - "Lead 5 (charang)", "Lead 6 (voice)", - "Lead 7 (fifths)", "Lead 8 (bass+lead)", - "Pad 1 (new age)", "Pad 2 (warm)", - "Pad 3 (polysynth)", "Pad 4 (choir)", - "Pad 5 (bowed)", "Pad 6 (metallic)", - "Pad 7 (halo)", "Pad 8 (sweep)", - "FX 1 (rain)", "(soundtrack)", - "FX 3 (crystal)", "FX 4 (atmosphere)", - "FX 5 (brightness)", "FX 6 (goblins)", - "FX 7 (echoes)", "FX 8 (sci-fi)", - "Sitar", "Banjo", "Shamisen", "Koto", - "Kalimba", "Bagpipe", "Fiddle", "Shanai", - "Tinkle Bell", "Agogo", "Steel Drums", "Woodblock", - "Taiko Drum", "Melodic Tom", "Synth Drum", "Reverse Cymbal", - "Guitar Fret Noise", "Breath Noise", "Seashore", "Bird Tweet", - "Telephone ring", "Helicopter", "Applause", "Gunshot"}; -/* - if (onlychan >=0 && chan != onlychan) return; -*/ - if (prtime()) return; - printf("Program %2d %d (%s)\n",chan+1, program,patches[program]); - } - -void mftxt_chanpressure(chan,press) -{ - prtime(); - printf("Chanpres %2d pressure=%d\n",chan+1,press); -} - - -void mftxt_parameter(chan,control,value) -{ - static char *ctype[] = { - "Bank Select", "Modulation Wheel", /*1*/ - "Breath controller", "unknown", /*3*/ - "Foot Pedal", "Portamento Time", /*5*/ - "Data Entry", "Volume", /*7*/ - "Balance", "unknown", /*9*/ - "Pan position", "Expression", /*11*/ - "Effect Control 1", "Effect Control 2", /*13*/ - "unknown", "unknown", /*15*/ - "Slider 1", "Slider 2", /*17*/ - "Slider 3", "Slider 4", /*19*/ - "unknown", "unknown", /*21*/ - "unknown", "unknown", /*23*/ - "unknown", "unknown", /*25*/ - "unknown", "unknown", /*27*/ - "unknown", "unknown", /*29*/ - "unknown", "unknown", /*31*/ - "Bank Select (fine)", "Modulation Wheel (fine)", /*33*/ - "Breath controller (fine)", "unknown", /*35*/ - "Foot Pedal (fine)", "Portamento Time (fine)", /*37*/ - "Data Entry (fine)", "Volume (fine)", /*39*/ - "Balance (fine)", "unknown", /*41*/ - "Pan position (fine)", "Expression (fine)", /*43*/ - "Effect Control 1 (fine)", "Effect Control 2 (fine)", /*45*/ - "unknown", "unknown", /*47*/ - "unknown", "unknown", /*49*/ - "unknown", "unknown", /*51*/ - "unknown", "unknown", /*53*/ - "unknown", "unknown", /*55*/ - "unknown", "unknown", /*57*/ - "unknown", "unknown", /*59*/ -"unknown", "unknown", /*61*/ - "unknown", "unknown", /*63*/ - "Hold Pedal", "Portamento", /*65*/ - "Susteno Pedal", "Soft Pedal", /*67*/ - "Legato Pedal", "Hold 2 Pedal", /*69*/ - "Sound Variation", "Sound Timbre", /*71*/ - "Sound Release Time", "Sound Attack Time", /*73*/ - "Sound Brightness", "Sound Control 6", /*75*/ - "Sound Control 7", "Sound Control 8", /*77*/ - "Sound Control 9", "Sound Control 10", /*79*/ - "GP Button 1", "GP Button 2", /*81*/ - "GP Button 3", "GP Button 4", /*83*/ - "unknown", "unknown", /*85*/ - "unknown", "unknown", /*87*/ - "unknown", "unknown", /*89*/ - "unknown", "Effects Level", /*91*/ - "Tremolo Level", "Chorus Level", /*93*/ - "Celeste Level", "Phaser Level", /*95*/ - "Data button increment", "Data button decrement", /*97*/ - "NRP (fine)", "NRP (coarse)", /*99*/ - "Registered parameter (fine)", "Registered parameter (coarse)", /*101*/ - "unknown", "unknown", /*103*/ - "unknown", "unknown", /*105*/ - "unknown", "unknown", /*107*/ - "unknown", "unknown", /*109*/ - "unknown", "unknown", /*111*/ - "unknown", "unknown", /*113*/ - "unknown", "unknown", /*115*/ - "unknown", "unknown", /*117*/ - "unknown", "unknown", /*119*/ - "All Sound Off", "All Controllers Off", /*121*/ - "Local Keyboard (on/off)","All Notes Off", /*123*/ - "Omni Mode Off", "Omni Mode On", /*125*/ - "Mono Operation", "Poly Operation"}; - -/* if (onlychan >=0 && chan != onlychan) return; */ - if (prtime()) return; - - printf("CntlParm %2d %s = %d\n",chan+1, ctype[control],value); -} - - -void mftxt_metatext(type,leng,mess) -char *mess; -{ - static char *ttype[] = { - NULL, - "Text Event", /* type=0x01 */ - "Copyright Notice", /* type=0x02 */ - "Seqnce/Track Name", - "Instrument Name", /* ... */ - "Lyric", - "Marker", - "Cue Point", /* type=0x07 */ - "Unrecognized" - }; - int unrecognized = (sizeof(ttype)/sizeof(char *)) - 1; - int len; - register int n, c; - register char *p = mess; - - if ( type < 1 || type > unrecognized ) - type = unrecognized; - if (prtime()) return; - printf("Metatext (%s) ",ttype[type]); - len = leng; - if (len > 15) len = 15; - for ( n=0; n */ - printf( (isprint(c)||isspace(c)) ? "%c" : "\\0x%02x" , c); - } - if (leng>15) printf("..."); - printf("\n"); -} - -void mftxt_keysig(sf,mi) -{ - static char *major[] = {"Cb", "Gb", "Db", "Ab", "Eb", "Bb", "F", - "C", "G", "D", "A", "E", "B", "F#", "C#"}; - static char *minor[] = {"Abmin", "Ebmin", "Bbmin", "Fmin", "Cmin", - "Gmin", "Dmin", "Amin", "Emin", "Bmin", "F#min", "C#min", "G#min"}; - int index; - index = sf + 7; - if (prtime()) return; - if (mi) - printf("Metatext key signature %s (%d/%d)\n",minor[index],sf,mi); - else - printf("Metatext key signature %s (%d/%d)\n",major[index],sf,mi); -} - -void mftxt_tempo(ltempo) -long ltempo; -{ - tempo = ltempo; - if (prtime()) return; - printf("Metatext tempo = %6.2f bpm\n",60000000.0/tempo); -} - -void mftxt_timesig(nn,dd,cc,bb) -{ - int denom = 1; - while ( dd-- > 0 ) - denom *= 2; - if (prtime()) return; - printf("Metatext time signature=%d/%d\n",nn,denom); -/* printf("Time signature=%d/%d MIDI-clocks/click=%d \ - 32nd-notes/24-MIDI-clocks=%d\n", nn,denom,cc,bb); */ -} - -void mftxt_smpte(hr,mn,se,fr,ff) -{ - if (prtime()) return; - printf("Metatext SMPTE, %d:%d:%d %d=%d\n", hr,mn,se,fr,ff); -} - -void mftxt_metaeot() -{ - if (prtime()) return; - printf("Meta event, end of track\n"); -} - - -void initfunc_for_midinotes() -{ - Mf_error = error; - Mf_header = txt_header; - Mf_trackstart = txt_trackstart; - Mf_trackend = txt_trackend; - Mf_noteon = print_txt_noteon; - Mf_noteoff = print_txt_noteoff; - Mf_pressure = no_op3; - Mf_parameter = no_op3; - Mf_pitchbend = no_op3; - Mf_program = no_op2; - Mf_chanpressure = no_op3; - Mf_sysex = no_op2; - Mf_metamisc = no_op3; - Mf_seqnum = no_op1; - Mf_eot = no_op0; - Mf_timesig = no_op4; - Mf_smpte = no_op5; - Mf_tempo = no_op1; - Mf_keysig = no_op2; - Mf_seqspecific = no_op3; - Mf_text = no_op3; - Mf_arbitrary = no_op2; -} - - -void initfunc_for_mftext() -{ - Mf_error = error; - Mf_header = mftxt_header; - Mf_trackstart = mftxt_trackstart; - Mf_trackend = txt_trackend; - Mf_noteon = mftxt_noteon; - Mf_noteoff = mftxt_noteoff; - Mf_pressure =mftxt_pressure; - Mf_parameter = mftxt_parameter; - Mf_pitchbend = mftxt_pitchbend; - Mf_program = mftxt_program; - Mf_chanpressure = mftxt_chanpressure; - Mf_sysex = no_op2; - Mf_metamisc = no_op3; - Mf_seqnum = no_op1; - Mf_eot = mftxt_metaeot; - Mf_timesig = mftxt_timesig; - Mf_smpte = mftxt_smpte; - Mf_tempo = mftxt_tempo; - Mf_keysig = mftxt_keysig; - Mf_seqspecific = no_op3; - Mf_text = mftxt_metatext; - Mf_arbitrary = no_op2; -} - - - - -void initfuncs() -{ - Mf_error = error; - Mf_header = txt_header; - Mf_trackstart = txt_trackstart; - Mf_trackend = txt_trackend; - Mf_noteon = txt_noteon; - Mf_noteoff = txt_noteoff; - Mf_pressure = txt_pressure; - Mf_parameter = txt_parameter; - Mf_pitchbend = txt_pitchbend; - Mf_program = txt_program; - Mf_chanpressure = txt_chanpressure; - Mf_sysex = txt_sysex; - Mf_metamisc = txt_metamisc; - Mf_seqnum = txt_metaseq; - Mf_eot = txt_metaeot; - Mf_timesig = txt_timesig; - Mf_smpte = txt_smpte; - Mf_tempo = txt_tempo; - Mf_keysig = txt_keysig; - Mf_seqspecific = txt_metaspecial; - Mf_text = txt_metatext; - Mf_arbitrary = txt_arbitrary; -} - - -/* Stage 2 Quantize MIDI tracks. Get key signature, time signature... */ - - -void postprocess(trackno) -/* This routine calculates the time interval before the next note */ -/* called after the MIDI file has been read in */ -int trackno; -{ - struct listx* i; - - i = track[trackno].head; - if (i != NULL) { - track[trackno].startwait = i->note->time; - } - else { - track[trackno].startwait = 0; - }; - while (i != NULL) { - if (i->next != NULL) { - i->note->dtnext = i->next->note->time - i->note->time; - } - else { - i->note->dtnext = i->note->tplay; - }; - i = i->next; - }; -} - -void scannotes(trackno) -int trackno; -/* diagnostic routine to output notes in a track */ -{ - struct listx* i; - - i = track[trackno].head; - while (i != NULL) { - printf("Pitch %d chan %d vel %d time %ld %ld xnum %d playnum %d\n", - i->note->pitch, i->note->chan, - i->note->vel, i->note->dtnext, i->note->tplay, - i->note->xnum, i->note->playnum); - i = i->next; - }; -} - - -int xnum_to_next_nonchordal_note(fromitem,spare,quantum) -struct listx* fromitem; -int spare,quantum; -{ -struct anote* jnote; -struct listx* nextitem; -int i,xxnum; -jnote = fromitem->note; -if (jnote->xnum > 0) return jnote->xnum; -i = 0; -nextitem = fromitem->next; -while (nextitem != NULL && i < 5) { - jnote = nextitem->note; - xxnum = (2*(jnote->dtnext + spare + (quantum/4)))/quantum; - if (xxnum > 0) return xxnum; - i++; - nextitem = nextitem->next; - } -return 0; -} - -int quantize(trackno, xunit) -/* Work out how long each note is in musical time units. - * The results are placed in note.playnum */ -int trackno, xunit; -{ - struct listx* j; - struct anote* this; - int spare; - int toterror; - int quantum; - int posnum,xxnum; - - /* fix to avoid division by zero errors in strange MIDI */ - if (xunit == 0) { - return(10000); - }; - quantum = (int) (2.*xunit/parts_per_unitlen); /* xunit assume 2 parts_per_unit */ - track[trackno].startunits = (2*(track[trackno].startwait + (quantum/4)))/quantum; - spare = 0; - toterror = 0; - j = track[trackno].head; - posnum = 0; - while (j != NULL) { - this = j->note; - /* this->xnum is the quantized inter onset time */ - /* this->playnum is the quantized note length */ - this->xnum = (2*(this->dtnext + spare + (quantum/4)))/quantum; - this->playnum = (2*(this->tplay + (quantum/4)))/quantum; - if ((this->playnum == 0) && (keep_short)) { - this->playnum = 1; - }; - /* In the event of short rests, the inter onset time - * will be larger than the note length. However, for - * chords the inter onset time can be zero. */ - xxnum = xnum_to_next_nonchordal_note(j,spare,quantum); - if ((swallow_rests>=0) && (xxnum - this->playnum <= restsize) - && xxnum > 0) { - this->playnum = xxnum; - }; - /* this->denom = parts_per_unitlen; this variable is never used ! */ - spare = spare + this->dtnext - (this->xnum*xunit/parts_per_unitlen); - if (spare > 0) { - toterror = toterror + spare; - } - else { - toterror = toterror - spare; - }; - /* gradually forget old errors so that if xunit is slightly off, - errors don't accumulate over several bars */ - spare = (spare * 96)/100; - this->posnum = posnum; - posnum += this->xnum; - j = j->next; - }; - return(toterror); -} - - -void guesslengths(trackno) -/* work out most appropriate value for a unit of musical time */ -int trackno; -{ - int i; - int trial[100]; - float avlen, factor, tryx; - long min; - - min = track[trackno].tracklen; - if (track[trackno].notes == 0) { - return; - }; - avlen = ((float)(min))/((float)(track[trackno].notes)); - tryx = avlen * (float) 0.75; - factor = tryx/100; - for (i=0; i<100; i++) { - trial[i] = quantize(trackno, (int) tryx); - if ((long) trial[i] < min) { - min = (long) trial[i]; - xunit = (int) tryx; - }; - tryx = tryx + factor; - }; -xunit_set = 1; -} - - -int findana(maintrack, barsize) -/* work out anacrusis from MIDI */ -/* look for a strong beat marking the start of a bar */ -int maintrack; -int barsize; -{ - int min, mincount; - int place; - struct listx* p; - - min = 0; - mincount = 0; - place = 0; - p = track[maintrack].head; - while ((p != NULL) && (place < barsize)) { - if ((p->note->vel > min) && (place > 0)) { - min = p->note->vel; - mincount = place; - }; - place = place + (p->note->xnum); - p = p->next; - }; - return(mincount); -} - - - -int guessana(barbeats) -int barbeats; -/* try to guess length of anacrusis */ -{ - int score[64]; - int min, minplace; - int i,j; - - if (barbeats > 64) { - fatal_error("Bar size exceeds static limit of 64 units!"); - }; - for (j=0; jnote->pitch; - max = min; - totalnotes = 0; - for (j=0; jnote->pitch; - if (thispitch > max) { - max = thispitch; - } - else { - if (thispitch < min) { - min = thispitch; - }; - }; - n[thispitch % 12] = n[thispitch % 12] + 1; - p = p->next; - }; - }; - /* count black notes for each key */ - /* assume pitch = 0 is C */ - minkey = 0; - minblacks = totalnotes; - for (j=0; j<12; j++) { - key_score[j] = n[(j+1)%12] + n[(j+3)%12] + n[(j+6)%12] + - n[(j+8)%12] + n[(j+10)%12]; - /* printf("Score for key %d is %d\n", j, key_score[j]); */ - if (key_score[j] < minblacks) { - minkey = j; - minblacks = key_score[j]; - }; - }; - /* do conversion to abc pitches */ - /* Code changed to use absolute rather than */ - /* relative choice of pitch for 'c' */ - /* MIDDLE = (min + (max - min)/2 + 6)/12 * 12; */ - /* Do last note analysis */ - lastpitch = track[maintrack].tail->note->pitch; - if (minkey != (lastpitch%12)) { - fprintf(outhandle,"%% Last note suggests "); - switch((lastpitch+12-minkey)%12) { - case(2): - fprintf(outhandle,"Dorian "); - break; - case(4): - fprintf(outhandle,"Phrygian "); - break; - case(5): - fprintf(outhandle,"Lydian "); - break; - case(7): - fprintf(outhandle,"Mixolydian "); - break; - case(9): - fprintf(outhandle,"minor "); - break; - case(11): - fprintf(outhandle,"Locrian "); - break; - default: - fprintf(outhandle,"unknown "); - break; - }; - fprintf(outhandle,"mode tune\n"); - }; - /* switch to minor mode if it gives same number of accidentals */ - if ((minkey != ((lastpitch+3)%12)) && - (key_score[minkey] == key_score[(lastpitch+3)%12])) { - minkey = (lastpitch+3)%12; - }; - /* switch to major mode if it gives same number of accidentals */ - if ((minkey != (lastpitch%12)) && - (key_score[minkey] == key_score[lastpitch%12])) { - minkey = lastpitch%12; - }; - sharps = keysharps[minkey]; - return(sharps); -} - - - - -/* Stage 3 output MIDI tracks in abc format */ - - -/* head and tail of list of notes in current chord playing */ -/* used while abc is being generated */ -struct dlistx* chordhead; -struct dlistx* chordtail; - - -void printchordlist() -/* diagnostic routine */ -{ - struct dlistx* i; - - i = chordhead; - printf("----CHORD LIST------\n"); - while(i != NULL) { - printf("pitch %d len %d\n", i->note->pitch, i->note->playnum); - if (i->next == i) { - fatal_error("Loopback problem!"); - }; - i = i->next; - }; -} - -void checkchordlist() -/* diagnostic routine */ -/* validates data structure */ -{ - struct dlistx* i; - int n; - - if ((chordhead == NULL) && (chordtail == NULL)) { - return; - }; - if ((chordhead == NULL) && (chordtail != NULL)) { - fatal_error("chordhead == NULL and chordtail != NULL"); - }; - if ((chordhead != NULL) && (chordtail == NULL)) { - fatal_error("chordhead != NULL and chordtail == NULL"); - }; - if (chordhead->last != NULL) { - fatal_error("chordhead->last != NULL"); - }; - if (chordtail->next != NULL) { - fatal_error("chordtail->next != NULL"); - }; - i = chordhead; - n = 0; - while((i != NULL) && (i->next != NULL)) { - if (i->next->last != i) { - char msg[80]; - - sprintf(msg, "chordlist item %d : i->next->last!", n); - fatal_error(msg); - }; - i = i->next; - n = n + 1; - }; - /* checkchordlist(); */ -} - -void addtochord(p) -/* used when printing out abc */ -struct anote* p; -{ - struct dlistx* newx; - struct dlistx* place; - - newx = (struct dlistx*) checkmalloc(sizeof(struct dlistx)); - newx->note = p; - newx->next = NULL; - newx->last = NULL; - - if (chordhead == NULL) { - chordhead = newx; - chordtail = newx; - checkchordlist(); - return; - }; - place = chordhead; - while ((place != NULL) && (place->note->pitch > p->pitch)) { - place = place->next; - }; - if (place == chordhead) { - newx->next = chordhead; - chordhead->last = newx; - chordhead = newx; - checkchordlist(); - return; - }; - if (place == NULL) { - newx->last = chordtail; - chordtail->next = newx; - chordtail = newx; - checkchordlist(); - return; - }; - newx->next = place; - newx->last = place->last; - place->last = newx; - newx->last->next = newx; - checkchordlist(); -} - -struct dlistx* removefromchord(i) -/* used when printing out abc */ -struct dlistx* i; -{ - struct dlistx* newi; - - /* remove note from list */ - if (i->last == NULL) { - chordhead = i->next; - } - else { - (i->last)->next = i->next; - }; - if (i->next == NULL) { - chordtail = i->last; - } - else { - (i->next)->last = i->last; - }; - newi = i->next; - free(i); - checkchordlist(); - return(newi); -} - -int findshortest(gap) -/* find the first note in the chord to terminate */ -int gap; -{ - int min, v; - struct dlistx* p; - - p = chordhead; - min = gap; - while (p != NULL) { - v = p->note->playnum; - if (v < min) { - min = v; - }; - p = p->next; - }; - return(min); -} - -void advancechord(len) -/* adjust note lengths for all notes in the chord */ -int len; -{ - struct dlistx* p; - - p = chordhead; - while (p != NULL) { - if (p->note->playnum <= len) { - if (p->note->playnum < len) { - fatal_error("Error - note too short!"); - }; - /* remove note */ - checkchordlist(); - p = removefromchord(p); - } - else { - /* shorten note */ - p->note->playnum = p->note->playnum - len; - p = p->next; - }; - }; -} - -void freshline() -/* if the current line of abc or text is non-empty, start a new line */ -{ - if (midline == 1) { - fprintf(outhandle,"\n"); - midline = 0; - }; -} - - -void printnote (struct listx *i) -{ - printf("%ld ",i->note->time); - printpitch(i->note); - printfract(i->note->playnum, parts_per_unitlen); - printf(" %d %d %d %d\n",i->note->xnum, i->note->playnum, - i->note->posnum,i->note->splitnum); -} - -void listnotes(int trackno, int start, int end) -/* A diagnostic like scannotes. I usually call it when - I am in the debugger (for example in printtrack). -*/ -{ -struct listx* i; -int k; -i = track[trackno].head; -k = 0; -printf("ticks pitch xnum,playnum,posnum,splitnum\n"); -while (i != NULL && k < end) - { - if (k >= start) - printnote(i); - k++; - i = i->next; - } -} - - - -int testtrack(trackno, barbeats, anacrusis) -/* print out one track as abc */ -int trackno, barbeats, anacrusis; -{ - struct listx* i; - int step, gap; - int barnotes; - int barcount; - int breakcount; - - breakcount = 0; - chordhead = NULL; - chordtail = NULL; - i = track[trackno].head; - gap = 0; - if (anacrusis > 0) { - barnotes = anacrusis; - } - else { - barnotes = barbeats; - }; - barcount = 0; - while((i != NULL)||(gap != 0)) { - if (gap == 0) { - /* add notes to chord */ - addtochord(i->note); - gap = i->note->xnum; - i = i->next; - advancechord(0); /* get rid of any zero length notes */ - } - else { - step = findshortest(gap); - if (step > barnotes) { - step = barnotes; - }; - if (step == 0) { - fatal_error("Advancing by 0 in testtrack!"); - }; - advancechord(step); - gap = gap - step; - barnotes = barnotes - step; - if (barnotes == 0) { - if (chordhead != NULL) { - breakcount = breakcount + 1; - }; - barnotes = barbeats; - barcount = barcount + 1; - if (barcount>0 && barcount%4 ==0) { - /* can't zero barcount because I use it for computing maxbarcount */ - freshline(); - barcount = 0; - }; - }; - }; - }; - return(breakcount); -} - -void printpitch(j) -/* convert numerical value to abc pitch */ -struct anote* j; -{ - int p, po,i; - - p = j->pitch; - if (p == -1) { - fprintf(outhandle,"z"); - } - else { - po = p % 12; - if ((back[trans[p]] != p) || (key[po] == 1)) { - fprintf(outhandle,"%c%c", symbol[po], atog[p]); - for (i=p%12; i<256; i += 12) /* apply accidental to all octaves */ - back[trans[i]] = i; - } - else { - fprintf(outhandle,"%c", atog[p]); - }; - while (p >= MIDDLE + 12) { - fprintf(outhandle,"'"); - p = p - 12; - }; - while (p < MIDDLE - 12) { - fprintf(outhandle,","); - p = p + 12; - }; - }; -} - -static void 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; -} - - - -void printfract(a, b) -/* print fraction */ -/* used when printing abc */ -int a, b; -{ - int c, d; - - c = a; - d = b; - reduce(&c,&d); - /* print out length */ - if (c != 1) { - fprintf(outhandle,"%d", c); - }; - if (d != 1) { - fprintf(outhandle,"/%d", d); - }; -} - -void printchord(len) -/* Print out the current chord. Any notes that haven't */ -/* finished at the end of the chord are tied into the next chord. */ -int len; -{ - struct dlistx* i; - - i = chordhead; - if (i == NULL) { - /* no notes in chord */ -#ifdef SPLITCODE - fprintf(outhandle,"x"); -#else - fprintf(outhandle,"z"); -#endif - printfract(len, parts_per_unitlen); - midline = 1; - } - else { - if (i->next == NULL) { - /* only one note in chord */ - printpitch(i->note); - printfract(len, parts_per_unitlen); - midline = 1; - if (len < i->note->playnum) { - fprintf(outhandle,"-"); - }; - } - else { - fprintf(outhandle,"["); - while (i != NULL) { - printpitch(i->note); - printfract(len, parts_per_unitlen); - if (len < i->note->playnum) { - fprintf(outhandle,"-"); - }; - if (nogr && i->next != NULL) fprintf(outhandle," "); - i = i->next; - }; - fprintf(outhandle,"]"); - midline = 1; - }; - }; -} - -char dospecial(i, barnotes, featurecount) -/* identify and print out triplets and broken rhythm */ -struct listx* i; -int* barnotes; -int* featurecount; -{ - int v1, v2, v3, vt; - int xa, xb; - int pnum; - long total, t1, t2, t3; - - - if ((chordhead != NULL) || (i == NULL) || (i->next == NULL) - /* || (asig%3 == 0) || (asig%2 != 0) 2004/may/09 SS*/) { - return(' '); - }; - t1 = i->note->dtnext; - v1 = i->note->xnum; - pnum = i->note->playnum; - if ((v1 < pnum) || (v1 > 1 + pnum) || (pnum == 0)) { - return(' '); - }; - t2 = i->next->note->dtnext; - v2 = i->next->note->xnum; - pnum = i->next->note->playnum; - if (/*(v2 < pnum) ||*/ (v2 > 1 + pnum) || (pnum == 0) || (v1+v2 > *barnotes)) { - return(' '); - }; - /* look for broken rhythm */ - total = t1 + t2; - if (total == 0L) { - /* shouldn't happen, but avoids possible divide by zero */ - return(' '); - }; - if (((v1+v2)%2 == 0) && ((v1+v2)%3 != 0)) { - vt = (v1+v2)/2; - if (vt == validnote(vt)) { - /* do not try to break a note which cannot be legally expressed */ - switch ((int) ((t1*6+(total/2))/total)) { - case 2: - *featurecount = 2; - i->note->xnum = vt; - i->note->playnum = vt; - i->next->note->xnum = vt; - i->next->note->playnum = vt; - return('<'); - break; - case 4: - *featurecount = 2; - i->note->xnum = vt; - i->note->playnum = vt; - i->next->note->xnum = vt; - i->next->note->playnum = vt; - return('>'); - break; - default: - break; - }; - }; - }; - /* look for triplet */ - if (i->next->next != NULL) { - t3 = i->next->next->note->dtnext; - v3 = i->next->next->note->xnum; - pnum = i->next->next->note->playnum; - if ((v3 < pnum) || (v3 > 1 + pnum) || (pnum == 0) || - (v1+v2+v3 > *barnotes)) { - return(' '); - }; - if ((v1+v2+v3)%2 != 0) { - return(' '); - }; - vt = (v1+v2+v3)/2; - if ((vt%2 == 1) && (vt > 1)) { - /* don't want strange fractions in triplet */ - return(' '); - }; - total = t1+t2+t3; - xa = (int) ((t1*6+(total/2))/total); - xb = (int) (((t1+t2)*6+(total/2))/total); - if ((xa == 2) && (xb == 4) && (vt%3 != 0) ) { - *featurecount = 3; - *barnotes = *barnotes + vt; - i->note->xnum = vt; - i->note->playnum = vt; - i->next->note->xnum = vt; - i->next->note->playnum = vt; - i->next->next->note->xnum = vt; - i->next->next->note->playnum = vt; - }; - }; - return(' '); -} - -int validnote(n) -int n; -/* work out a step which can be expressed as a musical time */ -{ - int v; - - if (n <= 4) { - v = n; - } - else { - v = 4; - while (v*2 <= n) { - v = v*2; - }; - if (v + v/2 <= n) { - v = v + v/2; - }; - }; - return(v); -} - -void handletext(t, textplace, trackno) -/* print out text occuring in the body of the track */ -/* The text is printed out at the appropriate place within the track */ -/* In addition the function handles key signature and time */ -/* signature changes that can occur in the middle of the tune. */ -long t; -struct tlistx** textplace; -int trackno; -{ - char* str; - char ch; - int type,sf,mi,nn,denom,bb; - - while (((*textplace) != NULL) && ((*textplace)->when <= t)) { - str = (*textplace)->text; - ch = *str; - type = (*textplace)->type; - remove_carriage_returns(str); - if (((int)ch == '\\') || ((int)ch == '/')) { - inkaraoke = 1; - }; - if ((inkaraoke == 1) && (karaoke == 1)) { - switch(ch) { - case ' ': - fprintf(outhandle,"%s", str); - midline = 1; - break; - case '\\': - freshline(); - fprintf(outhandle,"w:%s", str + 1); - midline = 1; - break; - case '/': - freshline(); - fprintf(outhandle,"w:%s", str + 1); - midline = 1; - break; - default : - if (midline == 0) { - fprintf(outhandle,"%%%s", str); - } - else { - fprintf(outhandle,"-%s", str); - }; - break; - }; - } - else { - freshline(); - ch=*(str+1); - switch (type) { - case 0: - if (ch != '%') - fprintf(outhandle,"%%%s\n", str); - else - fprintf(outhandle,"%s\n", str); - break; - case 1: /* key signature change */ - sscanf(str,"%d %d",&sf,&mi); - if((trackno != 0 || trackcount==1) && - (active_keysig != sf)) { - setupkey(sf); - active_keysig=sf; - } - break; - case 2: /* time signature change */ - sscanf(str,"%d %d %d",&nn,&denom,&bb); - if ((trackno != 0 || trackcount ==1) && - (active_asig != nn || active_bsig != denom)) - { - setup_timesig(nn,denom,bb); - fprintf(outhandle,"M: %d/%d\n",nn,denom); - fprintf(outhandle,"L: 1/%d\n",unitlen); - active_asig=nn; - active_bsig=denom; - } - break; - default: - break; - } - } - *textplace = (*textplace)->next; - } -} - - -#ifdef SPLITCODE - -/* This function identifies irregular chords, (notes which - do not exactly overlap in time). The notes in the - chords are split into separate lines (split numbers). - The xnum (delay) to next note is updated. -*/ - -int splitstart[10],splitend[10]; /* used in forming chords from notes*/ -int lastposnum[10]; /* posnum of previous note in linked list */ -int endposnum; /* posnum at last note in linked list */ -struct anote* prevnote[10]; /*previous note in linked list */ -struct listx* last_i[10]; /*note after finishing processing bar*/ -int existingsplits[10]; /* existing splits in active bar */ -struct dlistx* splitchordhead[10]; /* chordhead list for splitnum */ -struct dlistx* splitchordtail[10]; /* chordtail list for splitnum */ -int splitgap[10]; /* gap to next note at end of split measure */ - -void label_split(struct anote *note, int activesplit) -{ -/* The function assigns a split number (activesplit), to - a specific note, (*note). We also update splitstart - and splitend which specifies the region in time where - the another note must occur if it forms a proper chord. - After assigning a split number to the note we need to - update note->xnum as this indicates the gap to the - next note in the same split number. The function uses - a greedy algorithm. It assigns a note to the first - splitnumber code which satisfies the above constraint. - If it cannot find a splitnumber, a new one (voice or track) - is created. It would be nice if the voices kept the - high and low notes (in pitch) separate. -*/ - note->splitnum = activesplit; - splitstart[activesplit] = note->posnum; - splitend[activesplit] = splitstart[activesplit] + note->playnum; - if (prevnote[activesplit]) - prevnote[activesplit]->xnum = note->posnum - lastposnum[activesplit]; - lastposnum[activesplit] = note->posnum; - prevnote[activesplit] = note; - /* in case this is the last activesplit note make sure it - xnum points to end of track. Otherwise it will be changed - when the next activesplit note is labeled. - */ - note->xnum = endposnum - note->posnum; - existingsplits[activesplit]++; -} - - -void label_split_voices (int trackno) -{ -/* This function sorts all the notes in the track into - separate split part. A note is placed into a separate - part if it forms a chord in the current part but - does not have the same onset time and same end time. - If this occurs, we search for another part where - this does not happen. If we can't find such a part - a new part (split) is created. - The heuristic used needs to be improved, so - that split number 0 always contains notes and so - that notes in the same pitch range or duration are - given the same split number. -*/ -int activesplit,nsplits; -int done; -struct listx* i; -int k; -int firstposnum; -/* initializations */ -activesplit = 0; -nsplits = 0; -for (k=0;k<10;k++) { - splitstart[k]=splitend[k]=lastposnum[k]=0; - prevnote[k] = NULL; - existingsplits[k] = 0; - splitgap[k]=0; - } -i = track[trackno].head; -if (track[trackno].tail == 0x0) return; -endposnum =track[trackno].tail->note->posnum + - track[trackno].tail->note->playnum; - -if (i != NULL) label_split(i->note, activesplit); -/* now label all the notes in the track */ -while (i != NULL) - { - done =0; - if (nsplits == 0) { /*no splits exist, create split number 0 */ - activesplit = 0; - nsplits++; - i->note->splitnum = activesplit; - splitstart[activesplit] = i->note->posnum; - splitend[activesplit] = splitstart[activesplit] + i->note->playnum; - firstposnum = splitstart[activesplit]; - } else { /* do a compatibility check with the last split number */ - if ( ( i->note->posnum == splitstart[activesplit] - && i->note->playnum == (splitend[activesplit] - splitstart[activesplit])) - || i->note->posnum >= splitend[activesplit]) - { - if (existingsplits[activesplit] == 0) { - last_i[activesplit] = i; - splitgap[activesplit] = i->note->posnum - firstposnum; - } - label_split(i->note, activesplit); - done = 1; - } -/* need to search for any other compatible split numbers */ - if (done == 0) for (activesplit=0;activesplitnote->posnum == splitstart[activesplit] - && i->note->playnum == splitend[activesplit] - splitstart[activesplit]) - || i->note->posnum >= splitend[activesplit]) - { - if (existingsplits[activesplit] == 0) { - last_i[activesplit] = i; - splitgap[activesplit] = i->note->posnum - firstposnum; - } - label_split(i->note,activesplit); - done = 1; - break; - } - } - -/* No compatible split number found. Create new split */ - if (done == 0) { - if(nsplits < 10) {nsplits++; activesplit = nsplits-1;} - if (existingsplits[activesplit] == 0) { - last_i[activesplit] = i; - splitgap[activesplit] = i->note->posnum - firstposnum; - } - label_split(i->note,activesplit); - } - } -/* printf("note %d links to %d %d (%d %d)\n",i->note->pitch,activesplit, -i->note->posnum,splitstart[activesplit],splitend[activesplit]); -*/ - i = i->next; - } /* end while loop */ -} - - -int nextsplitnum(int splitnum) - { - while (splitnum < 9) { - splitnum++; - if (existingsplits[splitnum]) return splitnum; - } - return -1; -} - - -int count_splits() -{ -int i,n; -n = 0; -for (i=0;i<10;i++) - if (existingsplits[i]) n++; -return n; -} - - - - - -void printtrack_with_splits(trackno, anacrusis) -int trackno, anacrusis; -/* This function is an adaption of printtrack so that - notes with separate split numbers are in separated - regions in the measure. (Separated with &'s). - To do this we must make multiple passes through - each bar and maintain separate chordlists (in - event that some chords overlap over more than - one measure). -*/ -{ - struct listx* i; - struct tlistx* textplace; - struct tlistx* textplace0; /* track 0 text storage */ - int step, gap; - int barnotes; - int barcount; - int bars_on_line; - long now; - char broken; - int featurecount; - int last_barsize,barnotes_correction; - int splitnum = 0; - int j; - int nlines; - int done; - - nlines= 0; - label_split_voices (trackno); - - midline = 0; - featurecount = 0; - inkaraoke = 0; - now = 0L; - broken = ' '; - for (j=0;j<10;j++) { - splitchordhead[j] = NULL; - splitchordtail[j] = NULL; - } - i = track[trackno].head; - textplace = track[trackno].texthead; - textplace0 = track[0].texthead; - /*gap = track[trackno].startunits;*/ gap = 0; - if (anacrusis > 0) { - barnotes = anacrusis; - barcount = -1; - } - else { - barnotes = barsize; - barcount = 0; - }; - bars_on_line = 0; - last_barsize = barsize; - active_asig = header_asig; - active_bsig = header_bsig; - setup_timesig(header_asig,header_bsig,header_bb); - active_keysig = header_keysig; - handletext(now, &textplace, trackno); - splitnum = 0; - chordhead = splitchordhead[splitnum]; - chordtail = splitchordtail[splitnum]; - gap = splitgap[splitnum]; - - while((i != NULL)||(gap != 0)) { - if (gap == 0) { - /* do triplet here */ - if (featurecount == 0) { - if (!no_triplets) { - broken = dospecial(i, &barnotes, &featurecount); - }; - }; - -/* ignore any notes that are not in the current splitnum */ - if (i->note->splitnum == splitnum) { - /*printf("\nadding "); - printnote(i); */ - addtochord(i->note); - gap = i->note->xnum; - now = i->note->time; - } - - i = i->next; - advancechord(0); /* get rid of any zero length notes */ - if (trackcount > 1 && trackno !=0) - handletext(now, &textplace0, trackno); - handletext(now, &textplace,trackno); - barnotes_correction = barsize - last_barsize; - barnotes += barnotes_correction; - last_barsize = barsize; - } - else { - step = findshortest(gap); - if (step > barnotes) { - step = barnotes; - }; - step = validnote(step); - if (step == 0) { - fatal_error("Advancing by 0 in printtrack!"); - }; - if (featurecount == 3) - { - fprintf(outhandle," (3"); - }; - printchord(step); if ( featurecount > 0) { featurecount = featurecount - 1; }; - if ((featurecount == 1) && (broken != ' ')) { - fprintf(outhandle,"%c", broken); - }; - advancechord(step); - gap = gap - step; - barnotes = barnotes - step; - -/* at the end of the bar we must decide whether to place - a | or &. If we place a & then we have to return to - the beginning of the bar and process the next split number. -*/ - if (barnotes == 0) { /* end of bar ? */ - nlines++; - if (nlines > 5000) { - printf("\nProbably infinite loop: aborting\n"); - fprintf(outhandle,"\n\nProbably infinite loop: aborting\n"); - return; - } -/* save state for the last splitnum before going to the next */ - last_i[splitnum] = i; - splitchordhead[splitnum] = chordhead; - splitchordtail[splitnum] = chordtail; - splitgap[splitnum] = gap; - -/* look for the next splitnum which contains notes in - the current measure. If not, end the measure. -*/ - done = 0; - while (done != 1) { - splitnum = nextsplitnum(splitnum); - - if (splitnum == -1) { - fprintf(outhandle," | "); - splitnum = nextsplitnum(splitnum); - done = 1; - break; - } - - if (splitgap[splitnum] >= barsize) - { - splitgap[splitnum] -= barsize; - continue; /* look for other splits */ - } - - fprintf(outhandle, " & "); - i = last_i[splitnum]; - done = 1; - } -/* restore state for the next splitnum */ - chordhead = splitchordhead[splitnum]; - chordtail = splitchordtail[splitnum]; - checkchordlist(); - gap = splitgap[splitnum]; - i = last_i[splitnum]; - - /* - printf("returning to %ld ",i->note->time); - printpitch(i->note); - printf("\n"); - */ - - barnotes = barsize; - barcount = barcount + 1; - bars_on_line++; - if (barcount >0 && barcount%bars_per_staff == 0) { - freshline(); - bars_on_line=0; - } - /* can't zero barcount because I use it for computing maxbarcount */ - else if(bars_on_line >= bars_per_line && i != NULL) { - fprintf(outhandle," \\"); - freshline(); - bars_on_line=0;} - } - else if (featurecount == 0) { - /* note grouping algorithm */ - if ((barsize/parts_per_unitlen) % 3 == 0) { - if ( (barnotes/parts_per_unitlen) % 3 == 0 - &&(barnotes%parts_per_unitlen) == 0) { - fprintf(outhandle," "); - }; - } - else { - if (((barsize/parts_per_unitlen) % 2 == 0) - && (barnotes % parts_per_unitlen) == 0 - && ((barnotes/parts_per_unitlen) % 2 == 0)) { - fprintf(outhandle," "); - }; - }; - } - if (nogr) fprintf(outhandle," "); - }; - if (i == NULL) /* end of track before end of measure ? */ - { - last_i[splitnum] = i; - splitchordhead[splitnum] = chordhead; - splitchordtail[splitnum] = chordtail; - splitgap[splitnum] = gap; - splitnum = nextsplitnum(splitnum); - if (splitnum == -1) break; - chordhead = splitchordhead[splitnum]; - chordtail = splitchordtail[splitnum]; - gap = splitgap[splitnum]; - i = last_i[splitnum]; - if (barnotes != barsize) fprintf(outhandle, " & "); - barnotes = barsize; - } - - }; - /* print out all extra text */ - while (textplace != NULL) { - handletext(textplace->when, &textplace, trackno); - }; - freshline(); - if (barcount > maxbarcount) maxbarcount = barcount; -} - - - -void printtrack_split_voice(trackno, anacrusis) -/* print out one track as abc */ -int trackno, anacrusis; -{ - struct listx* i; - struct tlistx* textplace; - struct tlistx* textplace0; /* track 0 text storage */ - int step, gap; - int barnotes; - int barcount; - int bars_on_line; - long now; - char broken; - int featurecount; - int last_barsize,barnotes_correction; - int nlines; - int splitnum; - int lastnote_in_split; - - nlines= 0; - lastnote_in_split = 0; - label_split_voices (trackno); - midline = 0; - featurecount = 0; - inkaraoke = 0; - now = 0L; - broken = ' '; - chordhead = NULL; - chordtail = NULL; - i = track[trackno].head; - textplace = track[trackno].texthead; - textplace0 = track[0].texthead; - gap = track[trackno].startunits; - if (anacrusis > 0) { - barnotes = anacrusis; - barcount = -1; - } - else { - barnotes = barsize; - barcount = 0; - }; - bars_on_line = 0; - last_barsize = barsize; - active_asig = header_asig; - active_bsig = header_bsig; - setup_timesig(header_asig,header_bsig,header_bb); - active_keysig = header_keysig; - handletext(now, &textplace, trackno); - splitnum = 0; - gap = splitgap[splitnum]; - if (count_splits() > 1) fprintf(outhandle,"V: split%d%c\n",trackno+1,'A'+splitnum); - - while((i != NULL)||(gap != 0)) { - if (gap == 0) { - if (i->note->posnum + i->note->xnum == endposnum) lastnote_in_split = 1; - /* do triplet here */ - if (featurecount == 0) { - if (!no_triplets) { - broken = dospecial(i, &barnotes, &featurecount); - }; - }; -/* ignore any notes that are not in the current splitnum */ - if (i->note->splitnum == splitnum) { - /*printf("\nadding "); - printnote(i); */ - addtochord(i->note); - gap = i->note->xnum; - now = i->note->time; - } - i = i->next; - advancechord(0); /* get rid of any zero length notes */ - if (trackcount > 1 && trackno !=0) - handletext(now, &textplace0, trackno); - handletext(now, &textplace,trackno); - barnotes_correction = barsize - last_barsize; - barnotes += barnotes_correction; - last_barsize = barsize; - } - else { - step = findshortest(gap); - if (step > barnotes) { - step = barnotes; - }; - step = validnote(step); - if (step == 0) { - fatal_error("Advancing by 0 in printtrack!"); - }; - if (featurecount == 3) - { - fprintf(outhandle," (3"); - }; - printchord(step); - if ( featurecount > 0) { - featurecount = featurecount - 1; - }; - if ((featurecount == 1) && (broken != ' ')) { - fprintf(outhandle,"%c", broken); - }; - advancechord(step); - gap = gap - step; - barnotes = barnotes - step; - if (barnotes == 0) { - nlines++; - if (nlines > 5000) { - printf("\nProbably infinite loop: aborting\n"); - fprintf(outhandle,"\n\nProbably infinite loop: aborting\n"); - return; - } - fprintf(outhandle,"|"); - barnotes = barsize; - barcount = barcount + 1; - bars_on_line++; - if (barcount >0 && barcount%bars_per_staff == 0) { - freshline(); - bars_on_line=0; - } - /* can't zero barcount because I use it for computing maxbarcount */ - else if(bars_on_line >= bars_per_line && i != NULL) { - if (!lastnote_in_split) fprintf(outhandle," \\"); - freshline(); - bars_on_line=0;} - } - else if (featurecount == 0) { - /* note grouping algorithm */ - if ((barsize/parts_per_unitlen) % 3 == 0) { - if ( (barnotes/parts_per_unitlen) % 3 == 0 - &&(barnotes%parts_per_unitlen) == 0) { - fprintf(outhandle," "); - }; - } - else { - if (((barsize/parts_per_unitlen) % 2 == 0) - && (barnotes % parts_per_unitlen) == 0 - && ((barnotes/parts_per_unitlen) % 2 == 0)) { - fprintf(outhandle," "); - }; - }; - } - if (nogr) fprintf(outhandle," "); - }; - if (i == NULL && gap == 0) - { - i = track[trackno].head; - splitnum = nextsplitnum(splitnum); - lastnote_in_split = 0; - if (splitnum == -1) break; - gap = splitgap[splitnum]; - if(barnotes != barsize) freshline(); - fprintf(outhandle,"V:split%d%c\n",trackno+1,'A'+splitnum); - if (anacrusis > 0) { - barnotes = anacrusis; - barcount = -1; - } - else { - barnotes = barsize; - barcount = 0; - }; - } - }; - /* print out all extra text */ - while (textplace != NULL) { - handletext(textplace->when, &textplace, trackno); - }; - freshline(); - if (barcount > maxbarcount) maxbarcount = barcount; -} - -#endif - -void printtrack(trackno, anacrusis) -/* print out one track as abc */ -int trackno, anacrusis; -{ - struct listx* i; - struct tlistx* textplace; - struct tlistx* textplace0; /* track 0 text storage */ - int step, gap; - int barnotes; - int barcount; - int bars_on_line; - long now; - char broken; - int featurecount; - int last_barsize,barnotes_correction; - - midline = 0; - featurecount = 0; - inkaraoke = 0; - now = 0L; - broken = ' '; - chordhead = NULL; - chordtail = NULL; - i = track[trackno].head; - textplace = track[trackno].texthead; - textplace0 = track[0].texthead; - gap = track[trackno].startunits; - if (anacrusis > 0) { - barnotes = anacrusis; - barcount = -1; - } - else { - barnotes = barsize; - barcount = 0; - }; - bars_on_line = 0; - last_barsize = barsize; - active_asig = header_asig; - active_bsig = header_bsig; - setup_timesig(header_asig,header_bsig,header_bb); - active_keysig = header_keysig; - handletext(now, &textplace, trackno); - - while((i != NULL)||(gap != 0)) { - if (gap == 0) { - /* do triplet here */ - if (featurecount == 0) { - if (!no_triplets) { - broken = dospecial(i, &barnotes, &featurecount); - }; - }; - /* add notes to chord */ - addtochord(i->note); - gap = i->note->xnum; - now = i->note->time; - i = i->next; - advancechord(0); /* get rid of any zero length notes */ - if (trackcount > 1 && trackno !=0) - handletext(now, &textplace0, trackno); - handletext(now, &textplace,trackno); - barnotes_correction = barsize - last_barsize; - barnotes += barnotes_correction; - last_barsize = barsize; - } - else { - step = findshortest(gap); - if (step > barnotes) { - step = barnotes; - }; - step = validnote(step); - if (step == 0) { - fatal_error("Advancing by 0 in printtrack!"); - }; - if (featurecount == 3) - { - fprintf(outhandle," (3"); - }; - printchord(step); - if ( featurecount > 0) { - featurecount = featurecount - 1; - }; - if ((featurecount == 1) && (broken != ' ')) { - fprintf(outhandle,"%c", broken); - }; - advancechord(step); - gap = gap - step; - barnotes = barnotes - step; - if (barnotes == 0) { - fprintf(outhandle,"|"); - barnotes = barsize; - barcount = barcount + 1; - bars_on_line++; - if (barcount >0 && barcount%bars_per_staff == 0) { - freshline(); - bars_on_line=0; - } - /* can't zero barcount because I use it for computing maxbarcount */ - else if(bars_on_line >= bars_per_line && i != NULL) { - fprintf(outhandle," \\"); - freshline(); - bars_on_line=0;} - } - else if (featurecount == 0) { - /* note grouping algorithm */ - if ((barsize/parts_per_unitlen) % 3 == 0) { - if ( (barnotes/parts_per_unitlen) % 3 == 0 - &&(barnotes%parts_per_unitlen) == 0) { - fprintf(outhandle," "); - }; - } - else { - if (((barsize/parts_per_unitlen) % 2 == 0) - && (barnotes % parts_per_unitlen) == 0 - && ((barnotes/parts_per_unitlen) % 2 == 0)) { - fprintf(outhandle," "); - }; - }; - } - if (nogr) fprintf(outhandle," "); - }; - }; - /* print out all extra text */ - while (textplace != NULL) { - handletext(textplace->when, &textplace, trackno); - }; - freshline(); - if (barcount > maxbarcount) maxbarcount = barcount; -} - - - - -void remove_carriage_returns(char *str) -{ -/* a carriage return might be embedded in a midi text meta-event. - do not output this in the abc file or this would make a nonsyntactic - abc file. -*/ -char * loc; -while (loc = (char *) strchr(str,'\r')) *loc = ' '; -while (loc = (char *) strchr(str,'\n')) *loc = ' '; -} - - - -void printQ() -/* print out tempo for abc */ -{ - float Tnote, freq; - Tnote = mf_ticks2sec((long)((xunit*unitlen)/4), division, tempo); - freq = (float) 60.0/Tnote; - fprintf(outhandle,"Q:1/4=%d\n", (int) (freq+0.5)); - if (summary>0) printf("Tempo: %d quarter notes per minute\n", - (int) (freq + 0.5)); -} - - - - -void setupkey(sharps) -int sharps; -/* set up variables related to key signature */ -{ - char sharp[13], flat[13], shsymbol[13], flsymbol[13]; - int j, t, issharp; - int minkey; - - for (j=0; j<12; j++) - key[j] = 0; - minkey = (sharps+12)%12; - if (minkey%2 != 0) { - minkey = (minkey+6)%12; - }; - strcpy(sharp, "ccddeffggaab"); - strcpy(shsymbol, "=^=^==^=^=^="); - if (sharps == 6) { - sharp[6] = 'e'; - shsymbol[6] = '^'; - }; - strcpy(flat, "cddeefggaabb"); - strcpy(flsymbol, "=_=_==_=_=_="); - /* Print out key */ - - if (sharps >= 0) { - if (sharps == 6) { - fprintf(outhandle,"K:F#"); - } - else { - fprintf(outhandle,"K:%c", sharp[minkey] + 'A' - 'a'); - }; - issharp = 1; - } - else { - if (sharps == -1) { - fprintf(outhandle,"K:%c", flat[minkey] + 'A' - 'a'); - } - else { - fprintf(outhandle,"K:%cb", flat[minkey] + 'A' - 'a'); - }; - issharp = 0; - }; - if (sharps >= 0) { - fprintf(outhandle," %% %d sharps\n", sharps); - } - else { - fprintf(outhandle," %% %d flats\n", -sharps); - }; - key[(minkey+1)%12] = 1; - key[(minkey+3)%12] = 1; - key[(minkey+6)%12] = 1; - key[(minkey+8)%12] = 1; - key[(minkey+10)%12] = 1; - for (j=0; j<256; j++) { - t = j%12; - if (issharp) { - atog[j] = sharp[t]; - symbol[j] = shsymbol[t]; - } - else { - atog[j] = flat[t]; - symbol[j] = flsymbol[t]; - }; - trans[j] = 7*(j/12)+((int) atog[j] - 'a'); - if (j < MIDDLE) { - atog[j] = (char) (int) atog[j] + 'A' - 'a'; - }; - if (key[t] == 0) { - back[trans[j]] = j; - }; - }; -} - - - - -/* Functions for supporting the command line user interface to midi2abc. */ - - -int readnum(num) -/* read a number from a string */ -/* used for processing command line */ -char *num; -{ - int t; - char *p; - int neg; - - t = 0; - neg = 1; - p = num; - if (*p == '-') { - p = p + 1; - neg = -1; - }; - while (((int)*p >= '0') && ((int)*p <= '9')) { - t = t * 10 + (int) *p - '0'; - p = p + 1; - }; - return neg*t; -} - - -int readnump(p) -/* read a number from a string (subtly different) */ -/* used for processing command line */ -char **p; -{ - int t; - - t = 0; - while (((int)**p >= '0') && ((int)**p <= '9')) { - t = t * 10 + (int) **p - '0'; - *p = *p + 1; - }; - return t; -} - - -void readsig(a, b, sig) -/* read time signature */ -/* used for processing command line */ -int *a, *b; -char *sig; -{ - char *p; - int t; - - p = sig; - if ((int)*p == 'C') { - *a = 4; - *b = 4; - return; - }; - *a = readnump(&p); - if ((int)*p != '/') { - char msg[80]; - - sprintf(msg, "Expecting / in time signature found %c!", *p); - fatal_error(msg); - }; - p = p + 1; - *b = readnump(&p); - if ((*a == 0) || (*b == 0)) { - char msg[80]; - - sprintf(msg, "%d/%d is not a valid time signature!", *a, *b); - fatal_error(msg); - }; - t = *b; - while (t > 1) { - if (t%2 != 0) { - fatal_error("Bad key signature, divisor must be a power of 2!"); - } - else { - t = t/2; - }; - }; -} - -int is_power_of_two(int numb) -/* checks whether numb is a power of 2 less than 256 */ -{ -int i,k; -k = 1; -for (i= 0;i<8;i++) { - if(numb == k) return(1); - k *= 2; - } -return(0); -} - -int getarg(option, argc, argv) -/* extract arguments from command line */ -char *option; -char *argv[]; -int argc; -{ - int j, place; - - place = -1; - for (j=0; j= 0) bars_per_line=1; - if (!unitlen_set) { - if ((asig*4)/bsig >= 3) { - unitlen =8; - } - else { - unitlen = 16; - }; - } - arg = getarg("-b", argc, argv); - if ((arg != -1) && (arg < argc)) { - bars = readnum(argv[arg]); - } - else { - bars = 0; - }; - arg = getarg("-c", argc, argv); - if ((arg != -1) && (arg < argc)) { - xchannel = readnum(argv[arg]) - 1; - } - else { - xchannel = -1; - }; - arg = getarg("-k", argc, argv); - if ((arg != -1) && (arg < argc)) { - keysig = readnum(argv[arg]); - if (keysig<-6) keysig = 12 - ((-keysig)%12); - if (keysig>6) keysig = keysig%12; - if (keysig>6) keysig = keysig - 12; - ksig_set = 1; - } - else { - keysig = -50; - ksig_set = 0; - }; - - if(guessk) ksig_set=1; - - arg = getarg("-o",argc,argv); - if ((arg != -1) && (arg < argc)) { - outhandle = efopen(argv[arg],"w"); /* open output abc file */ - } - else { - outhandle = stdout; - }; - arg = getarg("-nt", argc, argv); - if (arg == -1) { - no_triplets = 0; - } - else { - no_triplets = 1; - }; - arg = getarg("-nogr",argc,argv); - if (arg != -1) - nogr=1; - else nogr = 0; - - arg = getarg("-f", argc, argv); - if (arg == -1) { - arg = huntfilename(argc, argv); - }; - if ((arg != -1) && (arg < argc)) { - F = efopen(argv[arg],"rb"); -/* fprintf(outhandle,"%% input file %s\n", argv[arg]); */ - } - else { - printf("midi2abc version %s\n usage :\n",VERSION); - printf("midi2abc filename \n"); - printf(" -a \n"); - printf(" -xa Extract anacrusis from file "); - printf("(find first strong note)\n"); - printf(" -ga Guess anacrusis (minimize ties across bars)\n"); - printf(" -gk Guess key signature \n"); - printf(" -gu Guess xunit from note duration statistics\n"); - printf(" -m