/* * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * */ /* back-end for outputting (possibly modified) abc */ #define VERSION "2.13 December 10 2020 abc2abc" /* for Microsoft Visual C++ 6.0 or higher */ #ifdef _MSC_VER #define ANSILIBS #endif #include "abc.h" #include "music_utils.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 */ /* holds a fraction */ struct fract { int num; int denom; }; typedef struct complex_barpoint { struct fract break_here[8]; } complex_barpoint_t; 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; complex_barpoint_t bar_break; /* where to put spaces for complex time */ } voice[MAX_VOICES]; 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 chordfactor; /* factor of the first note in a chord [PHDM] 2013-03-10 */ struct fract breakpoint; /* used to break bar into beamed sets of notes */ complex_barpoint_t master_bar_break; int barno; /* number of bar within tune */ int newspacing; /* was -s option selected ? */ int barcheck; /* 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 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 passthru = 0; /* output original abc file [SS] 2011-06-07 */ long selected_voices = -1; /* all voices are selected [PHDM] 2013-03-08 */ 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 */ int noplus; /* flag for outputting !..! instructions instead of +...+ */ int xmatch = -1; /* selected tune to process [SS] 2017-07-10 */ char* clef = ""; /* [SS] 2020-01-22 */ extern int nokey; /* signals no key signature assumed */ extern int nokeysig; /* signals -nokeys or -nokeysf option */ 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 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); void transpose_note(); 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("%s",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); /* output to stdout is here */ tmp[0] = '\0'; p = NULL; }; inmusic = 1; return(p); } /* nextnotes() function is not used [SDG] 2020-06-03 */ #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; if (*b == 0) { printf("Error in reduce: %d / %d\n", *a, *b); return; } /* 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; }; if (n == 0) { printf("Error reducing %d / %d (n = 0) !!\n", *a, *b); return; } *a = *a/n; *b = *b/n; } /* * addunits must be called for each single note or rest and * at each chord end. When called at chordoff time, make * sure that inchord is still true. [PHDM] 2013-03-10 */ static void addunits(n, m) int n, m; /* add fraction n/m to count */ { if (inchord) { /* [PHDM] 2013-03-10 */ if (!chordcount) /* empty chord */ return; n *= chordfactor.num; m *= chordfactor.denom; } if (tuplenotes) { /* [PHDM] 2013-03-10 */ n *= tuplefactor.num; m *= tuplefactor.denom; tuplenotes = tuplenotes - 1; }; count.num = n*count.denom + count.num*(m*unitlen.denom); count.denom = (m*unitlen.denom)*count.denom; reduce(&count.num, &count.denom); } void parse_voices_selection(voices_string) /* [PHDM] 2013-03-08 */ char *voices_string; { char *s = voices_string; selected_voices = 0; if (voices_string == 0x0) return; /* [SS] 2015-02-22 */ do { int v = readnump(&s); selected_voices |= 1 << v; } while (*s++); } int must_emit_voice(n) /* [PHDM] 2013-03-08 */ int n; { return selected_voices & (1 << n); } 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[,Y,,,]] [-P X[,Y...]] [-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(" -useclef (treble or bass)\n"); /* [SS] 2020-01-22 */ printf(" -d to notate with doubled note lengths\n"); printf(" -v to notate with halved note lengths\n"); printf(" -V X[,Y...] to output only voices X,Y...\n"); printf(" -P X[,Y...] restricts action to voice X,Y..., leaving other voices intact\n"); printf(" -ver prints version number and exits\n"); printf(" -X n renumber the all X: fields as n, n+1, ..\n"); printf(" -xref n output only the tune with X reference number n.\n"); printf(" -OCC old chord convention (eg. +CE+)\n"); /*printf(" -noplus use !...! instead of +...+ for instructions\n"); [SS] 2012-06-04 */ 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; }; }; /* [SS] 2017-07-10 */ narg = getarg("-xref",argc,argv); if (narg != -1 && 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 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) nokeysig=1; /* [SS] 2016-03-03 */ targ = getarg("-nokeyf",argc,argv); if (targ != -1) {nokeysig=1; useflats=1;} /* [SS] 2016-03-03 */ targ = getarg("-V", argc, argv); if (targ != -1) { parse_voices_selection(argv[targ]); /* [PHDM] 2013-03-08 */ }; targ = getarg("-P", argc, argv); /* [SS] 2011-06-07 */ if (targ != -1) { passthru = 1; parse_voices_selection(argv[targ]); /* [PHDM] 2013-03-08 */ } 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); } targ = getarg("-useclef",argc,argv); /* [SS] 2020-01-22 */ if (targ != -1) { clef = addstring(argv[targ]); printf("clef = %s\n",clef); } if (getarg("-OCC",argc,argv) != -1) oldchordconvention=1; /*if (getarg("-noplus",argc,argv) != -1) noplus = 1; [SS] 2012-06-04*/ /* 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(); } extern int parsing; /* [SS] 2017-07-10 */ void event_blankline() { if(parsing != 1) return; /* [SS] 2017-07-10 */ 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 print_inputline(); /* from parseabc.c */ void event_linebreak() { if (!output_on && passthru) print_inputline(); /* [SS] 2011-06-07*/ if (newbreaks) { if (!purgespace(tmp)) { if (inmusic) { newabctext(bar); } else { newabctext(field); }; }; } else { newabctext(bar); if (output_on) { printf("\n"); /* linefeed to stdout is here */ }; /* 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. */ }; } /* a score linebreak character has been encountered */ void event_score_linebreak(char ch) { emit_char(ch); } 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 && output_on) { /* [SS] 2011-04-14 */ printf("\n%%Error : %s\n", s); }; } void event_warning(s) char *s; { if (echeck && output_on) { /* [SS] 2011-04-14 */ 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(':'); if (k == 'w' && *f == '|') emit_char(' '); /* [SS] 2018-03-08 */ 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); }; } /* [SS] 2014-09-07 */ void appendfield (morewords) char *morewords; { emit_string("+: "); emit_string(morewords); } void event_part(s) char* s; { if (xinbody) { complete_bars(&voice[this_voice]); }; output_on = 1; /* [SS] 2011-04-14 */ emit_string_sprintf("P:%s", s); inmusic = 0; } /* initialize an abc2abc backend voice when we start using it */ static void init_voice(int voice_index, int num) { int i; struct voicetype *v; complex_barpoint_t *parent_breaks; complex_barpoint_t *voice_breaks; v = &voice[voice_index]; v->number = num; v->drumchan = 0; v->barcount = zero_barcount (&v->foundbar); v->bars_complete = 0; v->bars_remaining = bars_per_line; parent_breaks = &master_bar_break; voice_breaks = &v->bar_break; for (i = 0; i < 8; i++) { voice_breaks->break_here[i].num = parent_breaks->break_here[i].num; voice_breaks->break_here[i].denom = parent_breaks->break_here[i].denom; } } 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"); }; init_voice(voice_index, num); }; voice[voice_index].currentline = NULL; return(voice_index); } void event_voice(n, s, vp) int n; char *s; struct voice_params *vp; { char output[300]; /* [SS] 2017-10-09 2017-10-11 2018-12-27*/ if (xinbody) { close_newabc(); /* [SS] 2020-10-06 */ next_voice = setvoice(n); }; if (!must_emit_voice(n)) { /* [PHDM] 2013-03-08 */ if ((inlinefield) && (output_on == 1)) { unemit_inline(); }; /*output_on = 0; [SS] 2011-06-10 */ if (xinbody) output_on = 0; /* [SS] 2011-06-10 */ } else { if (output_on == 0) { output_on = 1; if (inlinefield) { emit_string("["); /* regenerate missing [ */ }; }; }; if (strlen(voicecode[n-1].label) > 0) { emit_string_sprintf("V:%s",voicecode[n-1].label); } 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);} if( vp->gotother ) { sprintf(output, " %s", vp->other); emit_string(output);} /* [SS] 2011-04-18 */ if (strlen(s) != 0) { emit_string(s); }; inmusic = 0; this_voice = n - 1; /* [SS] 2018-12-01 */ } 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_default_length(n) int n; { unitlen.num = 1; unitlen.denom = n; } void event_refno(n) int n; { /* [SS] 2017-07-10 */ if (xmatch == n || xmatch == -1) parseron(); else {parseroff(); return;} 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; } 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; } /* a complex time signature is something like M:(3+4)/8 * this means the time signature is actually 7/8 or 7 eighth notes in a bar, * but you should group the eighth notes as a set of 3, then a set of four. * This function works out where to put spaces between notes for a * complex time signature. */ static void set_complex_barpoint(timesig_details_t *timesig, complex_barpoint_t *complex_barpoint) { int i; struct fract count; count.num = 0; count.denom = 1; for (i = 0; i < timesig->num_values; i++) { int part_num; int part_denom; /* get component of complex timesig as a fraction */ part_num = timesig->complex_values[i]; part_denom = timesig->denom; /* add component of complex timesig to count */ count.num = (count.num * part_denom) + (part_num * count.denom); count.denom = (count.denom * part_denom); reduce(&count.num, &count.denom); /* set next suggested break to be at current count value */ complex_barpoint->break_here[i].num = count.num; complex_barpoint->break_here[i].denom = count.denom; } } /* M: field in the source. Support M:none, M:C and M:C| as well as * normal M:n/m */ void event_timesig (timesig) timesig_details_t *timesig; { emit_string ( "M:"); switch (timesig->type) { default: case TIMESIG_NORMAL: emit_int ( timesig->num); emit_string ( "/"); emit_int ( timesig->denom); break; case TIMESIG_FREE_METER: emit_string ( "none"); barcheck = 0; break; case TIMESIG_COMMON: emit_string ( "C"); break; case TIMESIG_CUT: emit_string ( "C|"); break; case TIMESIG_COMPLEX: { int i; emit_char( '('); for (i = 0; i < timesig->num_values; i++) { if (i > 0) { emit_char( '+'); } emit_int ( timesig->complex_values[i]); } emit_char( ')'); emit_string ( "/"); emit_int ( timesig->denom); if (xinhead) { set_complex_barpoint( &master_timesig, &master_bar_break); } else if (xinbody) { struct voicetype *toabc_voice; voice_context_t *current_voice; current_voice = &voicecode[this_voice]; toabc_voice = &voice[this_voice]; set_complex_barpoint( ¤t_voice->timesig, &toabc_voice->bar_break); } } break; } barlen.num = timesig->num; barlen.denom = timesig->denom; if ((timesig->type == TIMESIG_NORMAL) || (timesig->type == TIMESIG_COMMON) || (timesig->type == TIMESIG_CUT)) { breakpoint.num = timesig->num; breakpoint.denom = timesig->denom; if ((timesig->num == 9) || (timesig->num == 6)) { breakpoint.num = 3; breakpoint.denom = barlen.denom; }; if (timesig->num % 2 == 0) { breakpoint.num = barlen.num / 2; breakpoint.denom = barlen.denom; }; barend = timesig->num / 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; inlinefield = 0; if (barlen.num == 0) { /* generate missing time signature */ event_linebreak(); event_timesig (&master_timesig); inmusic = 0; }; /* missing unitlen handled by event_default_length */ 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]); /* propagate 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]); } /* [SS] 2011-02-15 */ /* Support functions to transpose key signature modifiers (eg. K: DPhr ^F * K: D exp _b_e^f ). * Method: we represent the notes in the key signature (with modifiers) in * a chromatic scale semiseq. semiseq(i) == 1 means the note is in the * key signature, semiseq(i) == 0 means the note is not present in the * key signature. semiseq(0) corresponds to A natural, semiseq(11) * represents G# or Ab. We transpose the notes by shifting (with * rotation) semiseq() left or right. We then read back the notes * of the shifted sequence, ignoring all flats and sharps in the * new key signature corresponding to this transpose. modmap indicates the key modifiers using the convention in event_key. */ char modmap[7]; int modmap_not_empty (char* modmap) { int i; for (i=0;i<7;i++) if (modmap[i] != ' ') {return 1;} return 0; } /* end of [SS] 2011-02-15 */ void event_key(sharps, s, modeindex, modmap, modmul, modmicrotone, gotkey, gotclef, clefname, new_clef, octave, xtranspose, gotoctave, gottranspose, explict) int sharps; char *s; int modeindex; char modmap[7]; int modmul[7]; struct fraction modmicrotone[7]; /* [SS[ 2014-01-06 */ int gotkey, gotclef; char* clefname; cleftype_t *new_clef; /* [JA] 2020-10-19 */ int octave, xtranspose, gotoctave, gottranspose; int explict; { static char* keys[12] = {"Db", "Ab", "Eb", "Bb", "F", "C", "G", "D", "A", "E", "B", "F#"}; char signature[10]; /* [SS] 2016-05-05 */ int i,k,slength; int xmult,xoctave; int mult; char accidental,note,xnote; char trans_string[32]; if (!xinbody && passthru) {print_inputline_nolinefeed(); /* [SS] 2011-06-10 */ if ((xinhead) && (!xinbody)) { xinbody = 1; start_tune(); }; inmusic = 0; return; } 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'; /* [SS] 2016-05-05 begin */ trans_string[0] = 0; if (modmap_not_empty (modmap)) { k=0; trans_string[k++] = ' '; xmult = 1; xoctave = 1; slength = strlen(s); /*printf("length of s = %d\n",slength);*/ for (i = 0; i 'g') { event_error ("expecting A-G or a-g after accidental in key modifier"); break; } transpose_note(*(s+i),xmult, xnote, xoctave, transpose, &accidental, &mult, ¬e, &octave); /*printf("%c%c\n",accidental,note); */ trans_string[k++] = accidental; if (mult == 2) trans_string[k++] = accidental; trans_string[k++] = note; break; } } trans_string[k] =0; } /* [SS] 2016-05-05 end */ }; 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 */ if (explict) emit_string(" exp"); /* 2011-02-21*/ emit_string(trans_string); /* [SS] 2011-02-20 */ } else if (usekey == 0) emit_string("none"); else emit_string(keys[usekey+5]); }; /* [SS] 2020-01-22 only works with transpose */ if (strlen(clef) > 0) { emit_string_sprintf(" clef=%s",clef); } else { if (gotclef) { emit_string(" "); 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; } /* [JM] 2018-02-22 (add code to treat / and // lengths when SHORT_HALFS is defined during compilation */ static void printlen(a, b) int a, b; { if (a != 1) { emit_int(a); }; #ifdef SHORT_HALFS else { if (b == 2) { emit_string("/"); return; } if (b == 4) { emit_string("//"); return; } } #endif 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 (chordcount == 1) { /* [PHDM] 2013-03-10 */ chordfactor.num = n; chordfactor.denom = m; } }; if ((!ingrace) && (!inchord)) { addunits(n, m); }; } void event_mrest(n,m,c) int n, m; char c; /* [SS] 2017-04-19 to distinguish X from Z */ { inmusic = 1; emit_char(c); /* [SS] 2017-04-19 */ 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("|:"); break; case REP_BAR: emit_string_sprintf(":|%s", replist); break; case BAR1: emit_string("|1"); break; case REP_BAR2: emit_string(":|2"); break; case DOUBLE_REP: emit_string("::"); break; }; if ((count.num*barlen.denom != barlen.num*count.denom) && (count.num != 0) && (barno != 0) && (barcheck)) { /* [J-FM] 2012-06-04 start */ switch (type) { case BAR_REP: case REP_BAR: case BAR1: case REP_BAR2: case DOUBLE_REP: break; /* no error if repeat bar */ default: sprintf(msg, "Bar %d is %d/%d not %d/%d", barno, count.num, count.denom, barlen.num, barlen.denom ); event_error(msg); count.num = 0; count.denom = 1; break; } } else { count.num = 0; count.denom = 1; } /* [J-FM] 2012-06-04 end */ newabctext(barline); barno = barno + 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 || noplus) 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; }; }; } } /* decide whether or not to put a space after note. * part of the logic for newspacing option */ static void consider_break_after_note(int previous_tuplenotes) { struct fract barpoint; voice_context_t *current_voice; current_voice = &voicecode[voicenum - 1]; if (previous_tuplenotes == 1) { /* if the note just output was the last one in a tuple, generate space */ emit_string (" "); return; } if (tuplenotes > 0) { /* never break beaming within a tuple */ return; } if (!parserinchord) { if (current_voice->timesig.type == TIMESIG_COMPLEX) { struct voicetype *v; int i; v = &voice[voicenum - 1]; /* try all the pre-calculated breakpoints */ for (i = 0; i < current_voice->timesig.num_values - 1; i++) { if ((v->bar_break.break_here[i].num == count.num) && (v->bar_break.break_here[i].denom == count.denom)) { emit_string (" "); } } } else { 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 (" "); } } } } void event_note1(decorators, clef, xaccidental, xmult, xnote, xoctave, n, m) int decorators[DECSIZE]; cleftype_t *clef; /* [JA] 2020-10-19 */ int xmult; char xaccidental, xnote; int xoctave, n, m; { int t; struct fract barpoint; struct fract newlen; int mult; char accidental, note; int octave; int prev_tuplenotes; mult = 0; /* [SS] 2006-10-27 */ if (transpose == 0 || drumchan) { accidental = xaccidental; mult = xmult; note = xnote; octave = xoctave; } else { int val, newval; int acc = 0; /* [SDG] 2020-06-03 */ char *anoctave = "cdefgab"; octave = xoctave; val = (int) ((long) strchr(anoctave, xnote) - (long) anoctave); newval = val + lines; octave = octave + (newval/7); newval = newval % 7; if (newval < 0) { newval = newval + 7; octave = octave - 1; }; note = *(anoctave+newval); if (xaccidental == ' ') { accidental = ' '; } else { switch (xaccidental) { case '_': acc = -xmult; break; case '^': acc = xmult; break; case '=': acc = 0; break; default: event_error("Internal error"); }; acc = acc - oldtable[(int)anoctave[val] - (int)'a'] + newtable[(int)anoctave[newval] - (int)'a']; mult = 1; accidental = '='; if (acc > 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 (chordcount == 1) { /* [PHDM] 2013-03-10 */ chordfactor.num = n; chordfactor.denom = m; } }; prev_tuplenotes = tuplenotes; if ((!ingrace) && (!inchord)) { addunits(n, m); }; if (newspacing) { consider_break_after_note(prev_tuplenotes); }; } /* these functions are here to satisfy the linker */ void event_microtone(int dir, int a, int b) { } void event_temperament(char *line) { } 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, clef, xaccidental, xmult, xnote, xoctave, n, m) /* this function is called if flag nokey is set */ int decorators[DECSIZE]; cleftype_t *clef; /* [JA] 2020-10-19 */ 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 = '='; /* [SDG] 2020-06-03 */ 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 */ noplus = 1; /* [SS] 2012-06-04 */ /*for (i=0;i