diff options
author | Karl Berry <karl@freefriends.org> | 2016-03-07 19:26:54 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2016-03-07 19:26:54 +0000 |
commit | 40d910b7a2d64c93a11bdc1a1de5a9f905e88826 (patch) | |
tree | 8784385541cf0351758ff9c375f489af0408c5bc /Build/source/utils/autosp/autosp-src/autosp.c | |
parent | 28d6c77b1844979930e27317b27d49d1b08a59a2 (diff) |
import new music utility autosp from ctan
git-svn-id: svn://tug.org/texlive/trunk@39962 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/utils/autosp/autosp-src/autosp.c')
-rw-r--r-- | Build/source/utils/autosp/autosp-src/autosp.c | 1953 |
1 files changed, 1953 insertions, 0 deletions
diff --git a/Build/source/utils/autosp/autosp-src/autosp.c b/Build/source/utils/autosp/autosp-src/autosp.c new file mode 100644 index 00000000000..97fc811a8ce --- /dev/null +++ b/Build/source/utils/autosp/autosp-src/autosp.c @@ -0,0 +1,1953 @@ +char version[12] = "2016-01-30"; + +/* Copyright (C) 2014-16 R. D. Tennent School of Computing, + * Queen's University, rdt@cs.queensu.ca + * + * 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. + */ + +/* autosp - preprocessor to generate note-spacing commands for MusiXTeX scores */ + +/* Usage: autosp [-v | --version | -h | --help] + * autosp [-d | --dotted] [-l | --log] infile[.aspc] [outfile[.tex]] + * + * Options + * --dotted (-d) suppresses extra spacing for dotted beam notes. + * --log (-l) generate a log file + * + * + * + * Key functions: + * + * process_command, which processes commands + * \instrumentnumber + * \nbinstrument + * \setstaffs + * \startpiece + * \TransformNotes + * \def\vnotes + * \def\atnextbar + * \anotes etc. + * \bar + * \endpiece etc. + * + * analyze_notes, which determines pointers notes[i] and + * characters terminator[i] for each staff; '$' is used + * as the terminator for the last staff. + * + * generate_notes, which repeatedly uses spacing_note to + * determine spacings[i] of the next spacing note in + * each staff; the current spacing is then the smallest + * of these. If necessary, the current notes command + * is terminated and a new notes command initiated. + * Then one note (or skip) is generated for each staff. + * When necessary, vspacing[i] is set to generate subsequent + * skips. Appoggiaturas and xtuplets are treated separately. + * + * spacing_note (i), which searches for the next spacing note + * in the i'th staff, unless a "virtual note" (skip) is + * needed. + * + * Spacing values are expressed as sums of binary multiples of + * SMALL_NOTE (by default, 1/256th); for example, half-note + * spacing = SP(2) = SMALL_NOTE/2. Special small or large + * values are used for appoggiaturas and bar-rests. + * + */ + +# include "utils.h" + +#ifdef HAVE_CONFIG_H /* for TeXLive */ +#include <config.h> +#endif + +# ifdef KPATHSEA +# include <kpathsea/getopt.h> +# else +# include <getopt.h> +# endif + +# ifdef HAVE_STDBOOL_H +# include <stdbool.h> +# else +# ifndef HAVE__BOOL +# define _Bool signed char +# endif +# define bool _Bool +# define true 1 +# define false 0 +# endif + +# define PRIVATE static + +# define LINE_LEN 1024 +# define SHORT_LEN 256 +# define MAX_STAFFS 9 + +# define SMALL_NOTE 256 +# define SP(note) (SMALL_NOTE/note) +/* note = { 256 | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 } */ +# define MAX_SPACING 2*SP(1) +# define APPOGG_SPACING SP(64)+SP(256) /* not a legitimate spacing */ +# define BARREST_SPACING SP(1)+SP(2)+SP(16) /* not a legitimate spacing */ +# define notespp "\\vnotes2.95\\elemskip" +# define Notespp "\\vnotes3.95\\elemskip" +# define NOtespp "\\vnotes4.95\\elemskip" +# define NOTespp "\\vnotes6.95\\elemskip" +# define NOTEsp "\\vnotes9.52\\elemskip" +# define APPOGG_NOTES "\\vnotes1.45\\elemskip" + +PRIVATE bool debug = false; +PRIVATE char infilename[SHORT_LEN]; +PRIVATE char *infilename_n = infilename; +PRIVATE char outfilename[SHORT_LEN]; +PRIVATE char *outfilename_n = outfilename; +PRIVATE char logfilename[SHORT_LEN]; +PRIVATE char *logfilename_n = logfilename; + +PRIVATE FILE *infile, *outfile, *logfile; + +PRIVATE char line[LINE_LEN]; /* line of input */ + +PRIVATE int ninstr = 1; /* number of instruments */ +PRIVATE int staffs[MAX_STAFFS] = {0,1}; /* number of staffs for ith instrument*/ +PRIVATE int nstaffs = 1; /* number of staffs */ +PRIVATE int nastaffs = 0; /* number of active staffs; + 0 means all are active */ +PRIVATE char terminator[MAX_STAFFS]; /* one of '&' "|', '$' */ +PRIVATE bool active[MAX_STAFFS]; /* is staff i active? */ + +PRIVATE char *notes[MAX_STAFFS]; /* note segment for ith staff */ +PRIVATE char *current[MAX_STAFFS]; + +PRIVATE int spacings[MAX_STAFFS]; /* spacing for ith staff */ +PRIVATE int spacing = MAX_SPACING; /* spacing for current notes */ +PRIVATE int old_spacing = MAX_SPACING; + +PRIVATE int vspacing[MAX_STAFFS]; /* virtual-note (skip) spacing */ +PRIVATE bool nonvirtual_notes; + /* used to preclude output of *only* virtual notes */ + +PRIVATE int cspacing[MAX_STAFFS]; /* nominal collective-note spacing */ +PRIVATE char collective[MAX_STAFFS][SHORT_LEN]; + /* prefixes for collective note sequences */ +PRIVATE bool first_collective[MAX_STAFFS]; + +PRIVATE int restbars = 0; +PRIVATE char deferred_bar[SHORT_LEN]; /* deferred \bar (or \endpiece etc.) */ +PRIVATE bool Changeclefs = false; /* output \Changeclefs after \def\atnextbar */ + +PRIVATE int beaming[MAX_STAFFS]; /* spacing for beamed notes */ +PRIVATE int new_beaming; +PRIVATE int semiauto_beam_notes[MAX_STAFFS]; /* semi-automatic beam notes */ + +/* save-restore state for a staff; used in process_xtuplet */ +PRIVATE int beamingi; +PRIVATE char *currenti; +PRIVATE int cspacingi; +PRIVATE int vspacingi; +PRIVATE char collectivei[SHORT_LEN]; +PRIVATE bool first_collectivei; + +PRIVATE int xtuplet; /* x for xtuplet */ +PRIVATE int xi; /* xi'th staff is the xtuplet staff */ + +PRIVATE bool appoggiatura; +PRIVATE bool fixnotes = false; /* process \Notes etc. like \anotes? */ +PRIVATE bool dottedbeamnotes = false; /* dotted beam notes ignored? */ + +PRIVATE bool bar_rest[MAX_STAFFS]; + +PRIVATE char outstrings[MAX_STAFFS][LINE_LEN]; + /* accumulate commands to be output */ +PRIVATE char *n_outstrings[MAX_STAFFS]; + +PRIVATE void +usage (FILE *f) +{ + fprintf (f, "Usage: autosp [-v | --version | -h | --help]\n"); + fprintf (f, " autosp [-d | --dotted] [-l | --log] infile[.aspc] [outfile[.tex]]\n"); +} + + +PRIVATE +char *ps(int spacing) +/* convert spacing value to note value(s) */ +{ char *s = malloc(SHORT_LEN); + char *s_n = s; + *s = '\0'; + if (spacing == MAX_SPACING) + sprintf(s, "MAX_SPACING"); + else if (spacing == 0) + sprintf(s, "0"); + else + { int n = 1; + while (true) + { if (spacing >= SMALL_NOTE/n) + { s_n = s_n + sprintf (s_n, "SP(%d)", n); + spacing = spacing - SMALL_NOTE/n; + if (spacing > 0) + s_n = s_n + sprintf (s_n, "+"); + else break; + } + n = 2*n; + } + } + return s; +} + +PRIVATE void +note_segment (char *s) +{ char *t; + t = strpbrk (s, "|&$"); + if (t == NULL) t = s + strlen (s); + while (s < t) + { fputc (*s, logfile); s++; } + fputc ('\n', logfile); +} + +PRIVATE void +status (int i) +{ + if (active[i]) + { fprintf (logfile, "notes[%d]=", i); note_segment (notes[i]); + fprintf (logfile, "current[%d]=", i); note_segment (current[i]); + fprintf (logfile, "spacings[%d]=%s\n", i, ps(spacings[i])); + fprintf (logfile, "vspacing[%d]=%s\n", i, ps(vspacing[i])); + fprintf (logfile, "outstrings[%d]=%s\n", i, outstrings[i]); + } +} + +PRIVATE void +status_spacing (void) +{ + fprintf (logfile, "spacing=%s\n", ps(spacing)); + fprintf (logfile, "old_spacing=%s\n", ps(old_spacing)); +} + +PRIVATE void +status_all (void) +{ int i; + for (i=1; i <= nstaffs; i++) + if (active[i]) status (i); + status_spacing (); + fprintf (logfile, "nastaffs=%d\n", nastaffs); +} + +PRIVATE void +status_collective (int i) +{ + if (active[i]) + { fprintf (logfile, "cspacing[%d]=%s\n", i, ps(cspacing[i])); + fprintf (logfile, "collective[%d]=%s\n", i, collective[i]); + fprintf (logfile, "first_collective[%d]=%d\n", i, first_collective[i]); + } +} + +PRIVATE void +status_beam (int i) +{ + if (active[i]) + { fprintf (logfile, "beaming[%d]=%s\n", i, ps(beaming[i])); } +} + + +PRIVATE +void analyze_notes (char **ln) +/* divide material from *ln to \en into notes[i] segments + and initialize terminator[i] etc. */ +{ + int i; char *s; char *t; + int newlines = 0; + s = strpbrk (*ln+1, "|&\\\n"); /* skip initial command */ + while (true) + { /* look for \en */ + t = strstr(s, "\\en"); + if (t != NULL) break; + /* replace EOL by a blank and append another line of input */ + { char new_line[LINE_LEN]; + char *nl; + if (fgets (new_line, LINE_LEN, infile) == NULL) + error ("Unexpected EOF."); + nl = new_line; + while (*nl == ' ') nl++; /* avoid spaces */ + t = strpbrk (s, "\n%"); + if (t == NULL) error ("Missing EOL."); + if (*t == '\n') + { *t = ' '; t++;} + *t = '\0'; + if (append (line, &t, nl, LINE_LEN) >= LINE_LEN) + error ("Line too long."); + newlines++; + } + } + /* t -> "\en" */ + if ( prefix("\\enotes", t) ) *ln = t+7; + else *ln = t+3; + *t = '$'; /* replace '\' by '$' (a distinctive terminating character) */ + for (i=1; i <= nstaffs; i++) + { char *tt; + while (*s == ' ') s++; /* skip spaces */ + if (active[i]) + { notes[i] = s; + current[i] = s; + } + tt = strpbrk (s, "|&$"); + if (tt == NULL) error ("can't parse note-spacing command."); + s = tt; + terminator[i] = *s; + if (*s != '$') s++; + } + lineno = lineno + newlines; + for (i=1; i <= nstaffs; i++) + { + if (active[i]) + { n_outstrings[i] = outstrings[i]; + *n_outstrings[i] = '\0'; + vspacing[i] = 0; + collective[i][0] = '\0'; + cspacing[i] = MAX_SPACING; + first_collective[i] = false; + } + } + spacing = MAX_SPACING; + old_spacing = MAX_SPACING; + xtuplet = 1; + appoggiatura = false; + if (debug) + { fprintf (logfile, "\nAfter analyze_notes:\n"); + status_all (); + } +} + +PRIVATE +void checkc (char *s, char c) +{ if (*s != c) + { + fprintf (stderr, "Error on line %d: Expected %c but found %d:\n%s\n", lineno, c, *s, line); + exit (EXIT_FAILURE); + } +} + +PRIVATE +void checkn (char *s) +{ if (strpbrk (s, "0123456789") != s) + { + fprintf (stderr, "Error on line %d: Expected digit but found %c:\n%s\n", lineno, *s, line); + exit (EXIT_FAILURE); + } +} + +PRIVATE +void output_filtered (int i) +{ /* discard \sk \hsk and \Cpause */ + char *s = notes[i]; + while (s < current[i]) + { char *t = strpbrk (s+1, "\\&|$"); + if (t == NULL || t > current[i]) t = current[i]; + if (!prefix ("\\sk", s) + && !prefix ("\\hsk", s) + && !prefix ("\\Cpause", s) ) + { + while (s < t) + { *n_outstrings[i] = *s; + n_outstrings[i]++; s++; + } + *(n_outstrings[i]) = '\0'; + } + s = t; + } + notes[i] = s; +} + +PRIVATE +void output_notes (int i) +/* append from notes[i] up to current[i] to outstrings[i] */ +{ if (debug) + { fprintf (logfile, "\nEntering output_notes:\n"); + status (i); + } + if (vspacing[i] > 0) + { + if (nonvirtual_notes) + append (outstrings[i], &(n_outstrings[i]), "\\sk", LINE_LEN); + vspacing[i] = vspacing[i] - spacing; + } + else if (collective[i][0]) + { + if (debug) + { fprintf (logfile, "\nBefore outputting collective note:\n"); + status (i); + status_collective (i); + } + if (!first_collective[i]) + append (outstrings[i], &(n_outstrings[i]), collective[i], LINE_LEN); + first_collective[i] = false; + output_filtered (i); + append (outstrings[i], &(n_outstrings[i]), "}", LINE_LEN); + if (*notes[i] == '}') + { collective[i][0] = '\0'; + notes[i]++; + } + if (*notes[i] == '}') /* close of {\tinynotesize..{}}? */ + { append (outstrings[i], &(n_outstrings[i]), "}", LINE_LEN); + notes[i]++; + } + if (debug) + { fprintf (logfile, "\nAfter outputting collective note:\n"); + status (i); + status_collective (i); + } + } + else + output_filtered (i); + if (debug) + { fprintf (logfile, "\nAfter output_notes:\n"); + status (i); + status_spacing (); + } +} + +PRIVATE +void pseudo_output_notes (int i) +{ /* process notes like output_notes but without outputting */ + if (vspacing[i] > 0) + vspacing[i] = vspacing[i] - spacing; + else if (collective[i][0]) + { + first_collective[i] = false; + if (*current[i] == '}') + { collective[i][0] = '\0'; + current[i]++; + } + } +} + +PRIVATE +int collective_note (int i) +{ char *s = current[i]; + int spacing = cspacing[i]; + if (debug) + { fprintf (logfile, "\nEntering collective_note:\n"); + status (i); + status_collective (i); + } + while (true) /* search for alphabetic note (or asterisk) */ + { + if (*s == '.' && new_beaming == 0 && !dottedbeamnotes) + spacing = spacing * 1.50; + else if (isalpha (*s) || *s == '*') + { + s++; + current[i] = s; + if (debug) + { fprintf (logfile, "\nAfter collective_note:\n"); + status (i); + status_collective (i); + } + return spacing; + } + s++; + } +} + +PRIVATE +void beam_initiation (char *s, int i) +{ + if ( prefix ("\\ibbbbbb", s) + || prefix ("\\Ibbbbbb", s) + || prefix ("\\nbbbbbb", s) ) + beaming[i] = SP(256); + else if ( prefix ("\\ibbbbb", s) + || prefix ("\\Ibbbbb", s) + || prefix ("\\nbbbbb", s) ) + beaming[i] = SP(128); + else if ( prefix ("\\ibbbb", s) + || prefix ("\\Ibbbb", s) + || prefix ("\\nbbbb", s) ) + beaming[i] = SP(64); + else if ( prefix ("\\ibbb", s) + || prefix ("\\Ibbb", s) + || prefix ("\\nbbb", s) ) + beaming[i] = SP(32); + else if ( prefix ("\\ibb", s) + || prefix ("\\Ibb", s) + || prefix ("\\nbb", s) ) + beaming[i] = SP(16); + else if ( prefix ("\\ib", s) + || prefix ("\\Ib", s) ) + beaming[i] = SP(8); + if (debug) + { fprintf (logfile, "\nAfter beam_initiation:\n"); + status (i); + status_beam (i); + } +} + +PRIVATE +void beam_termination (char *s, int i) +{ + if (debug) + { fprintf (logfile, "\nEntering beam_termination:\n"); + status (i); + status_beam (i); + } + if ( prefix ("\\tbbbbbb", s) ) + { + new_beaming = SP(128); + if (beaming[i] > SP(256)) + beaming[i] = SP(256); + } + else if ( prefix ("\\tbbbbb", s) ) + { + new_beaming = SP(64); + if (beaming[i] > SP(128)) + beaming[i] = SP(128); + } + else if ( prefix ("\\tbbbb", s) ) + { + new_beaming = SP(32); + if (beaming[i] > SP(64)) + beaming[i] = SP(64); + } + else if ( prefix ("\\tbbb", s) ) + { + new_beaming = SP(16); + if (beaming[i] > SP(32)) + beaming[i] = SP(32); + } + else if ( prefix ("\\tbb", s) ) + { + new_beaming = SP(8); + if (beaming[i] > SP(16)) + beaming[i] = SP(16); + } + else if ( prefix ("\\tb", s) ) + { + new_beaming = 0; + } + if (debug) + { fprintf (logfile, "\nAfter beam_termination:\n"); + status (i); + status_beam (i); + } +} + +PRIVATE +char *skip_balanced_text (char *s) +{ + char *t; + do + { + t = strpbrk (s, "{}"); + if (t == NULL) error ("Expected '}'"); + if (*t == '{') t = skip_balanced_text (t+1); + } + while (*t != '}'); + return t+1; +} + +PRIVATE +char *skip_arg (char *s) +{ + while (*s == ' ') s++; + if (*s == '{') + { s++; + skip_balanced_text (s); + } + else + s++; + return s; +} + +PRIVATE +int spacing_note (int i) +/* Search from current[i] for the next spacing note in the ith staff. + * Returns the spacing value and updates current[i]. + */ +{ + int spacing = MAX_SPACING; + char *s, *t; + bool tinynotesize = false; + bool doubledotted = false; + bool dotted = false; + new_beaming = 0; + if (!active[i]) return spacing; + if (vspacing[i] > 0) + { /* virtual note (i.e., a skip) */ + return vspacing[i]; + } + if (collective[i][0]) + { + nonvirtual_notes = true; + return collective_note (i); + } + if (semiauto_beam_notes[i] > 0) + { if (debug) + fprintf (logfile, "\nsemiauto_beam_notes reduced\n"); + semiauto_beam_notes[i]--; + current[i]++; + if (debug) status (i); + nonvirtual_notes = true; + return beaming[i]; + } + s = strpbrk (current[i], "\\&|$"); + if (*s != '\\') + { return spacing; } + if (debug) + { fprintf (logfile, "\nIn spacing_note:\n"); + status (i); + } + while (true) + { + if ( prefix ("\\wh", s) + || prefix ("\\breve", s) + || prefix ("\\pause", s) + || prefix ("\\wq", s) ) + { spacing = SP(1); break; } + + if ( prefix ("\\ha", s) + || prefix ("\\hl", s) + || prefix ("\\hu", s) + || prefix ("\\hp", s) + || prefix ("\\hpause", s) ) + { spacing = SP(2); break;} + + if ( prefix ("\\qa", s) + || prefix ("\\ql", s) + || prefix ("\\qu", s) + || prefix ("\\qp", s) ) + { spacing = SP(4); break; } + + if ( ( prefix ("\\ca", s) + || prefix ("\\cl", s) + || prefix ("\\cu", s) ) + && !prefix ("\\caesura", s ) ) + { spacing = SP(8); break; } + + if ( prefix ("\\ds", s ) + && !prefix ("\\dsh", s) ) + { spacing = SP(8); break; } + + if ( prefix ("\\cccc", s) ) + { spacing = SP(64); break; } + + if ( prefix ("\\ccc", s) ) + { spacing = SP(32); break; } + + if ( prefix ("\\cc", s) + && !prefix ("\\ccn", s) + && !prefix ("\\cchar", s) ) + { spacing = SP(16); break; } + + if ( prefix ("\\qs", s) + && !prefix ("\\qsk", s) + && !prefix ("\\qspace", s) ) + { spacing = SP(16); break; } + + if ( prefix ("\\hs", s) + && !prefix ("\\hsk", s) + && !prefix ("\\hsp", s) ) + { spacing = SP(32); break;} + + if ( prefix ("\\qqs", s ) + && !prefix ("\\qqsk", s) ) + { spacing = SP(64); break; } + + if ( prefix ("\\qb", s)) /* beam note */ + { spacing = beaming[i]; + if (new_beaming != 0) /* set by preceding \tb... */ + { beaming[i] = new_beaming; + new_beaming = 0; + } + if (debug) + { fprintf (logfile, "\nBeam note:\n"); + status (i); + status_beam (i); + } + break; + } + + if ( prefix ("\\Cpause", s) ) + { /* bar-centered rest */ + bar_rest[i] = true; + spacing = BARREST_SPACING; + break; + } + + if ( prefix("\\tq", s) + && !prefix("\\tqq", s)) + { spacing = beaming[i]; + new_beaming = 0; + if (debug) + { fprintf (logfile, "\nAfter beam completion:\n"); + status (i); + status_beam (i); + } + break; + } + + if (prefix("\\tqqq", s) ) + { if (beaming[i] > SP(32)) + beaming[i] = SP(32); + spacing = beaming[i]; + beaming[i] = SP(16); + new_beaming = 0; + if (debug) + { fprintf (logfile, "\nAfter beam completion:\n"); + status (i); + status_beam (i); + } + break; + } + + if (prefix("\\tqq", s) ) + { if (beaming[i] > SP(16)) + beaming[i] = SP(16); + spacing = beaming[i]; + beaming[i] = SP(8); + new_beaming = 0; + if (debug) + { fprintf (logfile, "\nAfter beam completion:\n"); + status (i); + status_beam (i); + } + break; + } + +/* non-spacing commands: */ + + if ( prefix ("\\ib", s) + || prefix ("\\Ib", s) + || prefix ("\\nb", s) ) + beam_initiation (s, i); + + else if ( prefix("\\tb", s) ) + beam_termination (s, i); + + else if ( prefix("\\ztq", s) ) + /* non-spacing beam termination */ + new_beaming = 0; + + else if ( prefix("\\xtuplet", s)) + { char *t = s+1; + while (!isdigit(*t)) t++; + xi = i; + xtuplet = atoi(t); + } + else + if ( prefix("\\triolet", s) + || prefix("\\uptrio", s) + || prefix("\\downtrio", s) + || prefix("\\uptuplet", s) + || prefix("\\downtuplet", s) ) + { + xi = i; + xtuplet = 3; + } + + else if ( prefix("\\zchar", s) + || prefix("\\lchar", s) + || prefix("\\cchar", s) + || prefix("\\zcn", s) + || prefix("\\lcn", s) + || prefix("\\ccn", s) ) + { /* need to skip two arguments, possibly with embedded commands */ + char *t; + t = strpbrk (s+1, " {"); + if (t == NULL) error ("Argument expected"); + t = skip_arg (t); + t = skip_arg (t); + } + + else if ( prefix("\\tinynotesize", s) ) + { + tinynotesize = true; + appoggiatura = true; + } + + else if (prefix("\\ppt", s) + || prefix("\\pppt", s) ) + doubledotted = true; /* triple-dotted spaced as double-dotted */ + + else if (prefix("\\pt", s)) + dotted = true; + + else if ( prefix ("\\Dqbb", s) ) + { semiauto_beam_notes[i] = 1; + beaming[i] = SP(16); + current[i] = current[i] + 8; + nonvirtual_notes = true; + return beaming[i]; + } + else if ( prefix ("\\Dqb", s) ) + { if (debug) fprintf (logfile, "\nFound \\Dqb\n"); + semiauto_beam_notes[i] = 1; + beaming[i] = SP(8); + current[i] = current[i] + 7; + nonvirtual_notes = true; + if (debug) status (i); + return beaming[i]; + } + else if ( prefix ("\\Tqbb", s) ) + { semiauto_beam_notes[i] = 2; + beaming[i] = SP(16); + current[i] = current[i] + 8; + nonvirtual_notes = true; + return beaming[i]; + } + else if ( prefix ("\\Tqb", s) ) + { semiauto_beam_notes[i] = 2; + beaming[i] = SP(8); + current[i] = current[i] + 7; + nonvirtual_notes = true; + return beaming[i]; + } + else if ( prefix ("\\Qqbb", s) ) + { semiauto_beam_notes[i] = 3; + beaming[i] = SP(16); + current[i] = current[i] + 8; + nonvirtual_notes = true; + return beaming[i]; + } + else if ( prefix ("\\Qqb", s) ) + { semiauto_beam_notes[i] = 3; + beaming[i] = SP(8); + current[i] = current[i] + 7; + nonvirtual_notes = true; + return beaming[i]; + } + + /* Command is non-spacing. */ + /* Skip ahead to the next command. */ + s = strpbrk (s+1, "\\&|$"); + + if ( *s != '\\') + { current[i] = s; + if (debug) + { fprintf (logfile, "\nAfter spacing_note:\n"); + status (i); + } + return spacing; + } + } /* end of while (true) loop */ + + if (spacing < MAX_SPACING) + nonvirtual_notes = true; + if (prefix ("\\whpp", s) + || prefix ("\\hupp", s) + || prefix ("\\hlpp", s) + || prefix ("\\hspp", s) + || prefix ("\\hppp", s) + || prefix ("\\hpausepp", s) + || prefix ("\\qupp", s) + || prefix ("\\qlpp", s) + || prefix ("\\qspp", s) + || prefix ("\\qppp", s) + || prefix ("\\qqspp", s) + || prefix ("\\cupp", s) + || prefix ("\\clpp", s) + || prefix ("\\ccupp", s) + || prefix ("\\cclpp", s) + || prefix ("\\cccupp", s) + || prefix ("\\ccclpp", s) + || prefix ("\\qbpp", s) + || prefix ("\\dspp", s) + || doubledotted ) + { spacing *= 1.75; doubledotted = false;} + else + if (prefix ("\\whp", s) + || prefix ("\\hup", s) + || prefix ("\\hlp", s) + || prefix ("\\hsp", s) + || prefix ("\\hpp", s) + || prefix ("\\hpausep", s) + || prefix ("\\qup", s) + || prefix ("\\qlp", s) + || prefix ("\\qsp", s) + || prefix ("\\qqsp", s) + || prefix ("\\qpp", s) + || prefix ("\\cup", s) + || prefix ("\\clp", s) + || prefix ("\\ccup", s) + || prefix ("\\cclp", s) + || prefix ("\\cccup", s) + || prefix ("\\ccclp", s) + || prefix ("\\qbp", s) + || prefix ("\\dsp", s) + || dotted ) + { spacing *= 1.5; dotted = false; } + + t = strpbrk (s+1, "{\\&|$"); /* collective coding? */ + if (*t == '{') /* {...} */ + { /* Save prefix in collective[i]. + * It will be output for every note in the collective */ + char *ss = s; + char *tt = collective[i]; + while (ss <= t) + { *tt = *ss; tt++, ss++; } + *tt = '\0'; + current[i] = t+1; + if (tinynotesize) spacing = APPOGG_SPACING; + cspacing[i] = spacing; + first_collective[i] = true; + return collective_note (i); + } + if (tinynotesize) spacing = APPOGG_SPACING; + current[i] = strpbrk (s+1, "\\&|$"); + if (debug) + { fprintf (logfile, "\nAfter spacing_note:\n"); + status (i); + } + return spacing; +} + +PRIVATE void +output_rests (void) +{ /* outputs a multi-bar rest and the deferred_bar command */ + int i; + for (i=1; i <= nstaffs; i++) + { if (active[i]) + switch (restbars) + { case 0: return; + case 1: case 7: case 9: + fprintf ( outfile, "\\NOTEs"); + break; + case 2: + fprintf ( outfile, "\\NOTesp"); + break; + case 3: case 5: case 6: case 8: + fprintf ( outfile, "\\NOTes" ); + break; + case 4: + fprintf ( outfile, "\\NOtesp" ); + break; + default: + fprintf ( outfile, "\\NOTEs" ); + } + } + for (i=1; i <= nstaffs; i++) + { + if (active[i]) + switch (restbars) + { case 1: + fprintf ( outfile, "\\sk" ); + break; +/* + case 2: case 4: case 3: case 5: case 6: case 7: case 8: case 9: + fprintf ( outfile, "\\hqsk\\sk" ); + break; +*/ + default: + fprintf ( outfile, "\\sk" ); + } + if (terminator[i] == '&' || terminator[i] == '|') + putc (terminator[i], outfile); + } + fprintf (outfile, "\\en%%\n"); + fprintf (outfile, "\\def\\atnextbar{\\znotes"); + for (i=1; i <= nstaffs; i++) + { + if (active[i]) + { + switch (restbars) + { case 1: + fprintf ( outfile, "\\centerpause" ); + break; + +/* These styles of multi-bar rests now considered obsolete: + + case 2: + fprintf ( outfile, "\\centerbar{\\ccn{9}{\\meterfont2}}\\centerPAuse"); + break; + case 3: + fprintf ( outfile, "\\centerbar{\\ccn{9}{\\meterfont3}}\\centerbar{\\cPAuse\\off{2.0\\elemskip}\\cpause}"); + break; + case 4: + fprintf ( outfile, "\\centerbar{\\ccn{9}{\\meterfont4}}\\centerPAUSe"); + break; + case 5: + fprintf ( outfile, "\\centerbar{\\ccn{9}{\\meterfont5}}\\centerbar{\\cPAUSe\\off{2.0\\elemskip}\\cpause}"); + break; + case 6: + fprintf ( outfile, "\\centerbar{\\ccn{9}{\\meterfont6}}\\centerbar{\\cPAUSe\\off{2.0\\elemskip}\\cPAuse}"); + break; + case 7: + fprintf ( outfile, "\\centerbar{\\ccn{9}{\\meterfont7}}\\centerbar{\\cPAUSe\\off{2.0\\elemskip}\\cPAuse\\off{2.0\\elemskip}\\cpause}"); + break; + case 8: + fprintf ( outfile, "\\centerbar{\\ccn{9}{\\meterfont8}}\\centerbar{\\cPAUSe\\off{2.0\\elemskip}\\cPAUSe}"); + break; + case 9: + fprintf ( outfile, "\\centerbar{\\ccn{9}{\\meterfont9}}\\centerbar{\\cPAUSe\\off{2.0\\elemskip}\\cPAUSe\\off{2.0\\elemskip}\\cpause}"); + break; +*/ + default: + fprintf ( outfile, "\\centerHpause{%d}", restbars ); + } + } + if (terminator[i] != '$') putc (terminator[i], outfile); + } + fprintf (outfile, "\\en}%%\n"); + if (Changeclefs) /* \Changeclefs has to be output after \def\atnextbar... */ + { + fprintf ( outfile, "\\Changeclefs%%\n"); + Changeclefs = false; + } + if (restbars > 1) + fprintf ( outfile, "\\advance\\barno%d%%\n", restbars-1 ); + restbars = 0; + for (i=1; i <= nstaffs; i++) bar_rest[i] = false; + fprintf ( outfile, "%s%%\n", deferred_bar); + deferred_bar[0] = '\0'; +} + +void initialize_notes () +{ int i; + if (debug) + { fprintf (logfile, "\nEntering initialize_notes\n"); + status_all (); + } + if (spacing == SP(1)+SP(2) || spacing == SP(1)+SP(2)+SP(4)) + fprintf (outfile, NOTEsp); + else if (spacing == SP(1)) + fprintf (outfile, "\\NOTEs"); + else if (spacing == SP(2)+SP(4)+SP(8)) + fprintf (outfile, "%s", NOTespp); + else if (spacing == SP(2)+SP(4) ) + fprintf (outfile, "\\NOTesp"); + else if (spacing == SP(2)) + fprintf (outfile, "\\NOTes"); + else if (spacing == SP(4)+SP(8) ) + fprintf (outfile, "\\NOtesp"); + else if (spacing == SP(4)+SP(8)+SP(16) ) + fprintf (outfile, "%s", NOtespp); + else if (spacing == SP(4)) + fprintf (outfile, "\\NOtes"); + else if (spacing == SP(8)+SP(16) ) + fprintf (outfile, "\\Notesp"); + else if (spacing == SP(8)+SP(16)+SP(32)) + fprintf (outfile, "%s", Notespp); + else if (spacing == SP(8)) + fprintf (outfile, "\\Notes"); + else if (spacing == SP(16)+SP(32)+SP(64)) + fprintf (outfile, notespp); + else if (spacing == SP(16)+SP(32) ) + fprintf (outfile, "\\notesp"); + else if (spacing == SP(16) || spacing == SP(32)+SP(64) || spacing == SP(32)+SP(64)+SP(128)) + fprintf (outfile, "\\notes"); + else if (spacing == SP(32) || spacing == SP(64)+SP(128) || spacing == SP(64)+SP(128)+SP(256)) + fprintf (outfile, "\\nnotes"); + else if (spacing == SP(64) ) + fprintf (outfile, "\\nnnotes"); + else if (spacing == APPOGG_SPACING) + fprintf (outfile, "%s", APPOGG_NOTES); + else if (spacing == BARREST_SPACING) + fprintf (outfile, "\\znotes"); + else + { fprintf (stderr, "Error on line %d: spacing %s not recognized.\n", lineno, ps(spacing)); + exit (EXIT_FAILURE); + } + if (debug) fprintf (logfile, "\noutputting \\Notes command for spacing=%s.\n", ps(spacing)); + for (i=1; i <= nstaffs; i++) + { if (active[i]) + { n_outstrings[i] = outstrings[i]; + *n_outstrings[i] = '\0'; + } + } +} + +PRIVATE +void terminate_notes () +{ int i; + if (debug) + { fprintf (logfile, "\nEntering terminate_notes:\n"); + status_all (); + } + for (i=1; i <= nstaffs; i++) + { if (active[i]) + { if (spacing == MAX_SPACING) + { /* output any commands left in notes[i] */ + output_filtered (i); + } + fprintf (outfile, "%s", outstrings[i]); + if (debug) fprintf (logfile, "\noutputting %s from outstrings[%d].\n", outstrings[i], i); + outstrings[i][0] = '\0'; + n_outstrings[i] = outstrings[i]; + if (spacing < MAX_SPACING && spacing > 2 * old_spacing) + { /* add extra space *before* much longer notes */ + fprintf (outfile, "\\hqsk"); + if (debug) fprintf (logfile, "\nExtra half-notehead space before longer notes.\n"); + } + else if (spacing == MAX_SPACING && old_spacing < SP(8)) + { /* add extra space before \en */ + fprintf (outfile, "\\hqsk"); + if (debug) fprintf (logfile, "\nExtra half-notehead space before \\en.\n"); + } + } + if ( (terminator[i] == '&') || (terminator[i] == '|') ) + { + putc (terminator[i], outfile); if (debug) putc (terminator[i], logfile); + } + if (debug) fprintf (logfile, "\n"); + } + fprintf (outfile, "\\en"); + if (debug) + { fprintf (logfile, "\noutputting \\en\n"); + fprintf (logfile, "\nAfter terminate_notes:\n"); + status_all (); + } +} + +PRIVATE +void process_appogg (void) +{ int i; + if (debug) + { fprintf (logfile, "\nEntering process_appogg:\n"); + status_all(); + } + + if (old_spacing < MAX_SPACING) + { + if (debug) fprintf (logfile, "Terminate current notes command:\n"); + for (i=1; i <= nstaffs; i++) + { if (active[i]) + { + fprintf (outfile, "%s", outstrings[i]); + if (debug) fprintf (logfile, "%s", outstrings[i]); + } + if ( (terminator[i] == '&') || (terminator[i] == '|') ) + { + putc (terminator[i], outfile); + if (debug) putc (terminator[i], logfile); + } + } + fprintf (outfile, "\\en"); + if (debug) + { fprintf (logfile, "\\en"); + fprintf (logfile, "\nAfter termination of notes command:\n"); + status_all (); + } + } + + if (debug) fprintf (logfile, "\nCreate a new notes command for the appoggiatura:\n"); + spacing = APPOGG_SPACING; + initialize_notes (); + spacing = MAX_SPACING; + for (i=1; i <= nstaffs; i++) + if (active[i]) + { + if (spacings[i] == APPOGG_SPACING ) + { + output_notes (i); + spacings[i] = spacing_note (i); + } + if (spacings[i] < spacing) + spacing = spacings[i]; + } + appoggiatura = false; + nonvirtual_notes = true; + old_spacing = APPOGG_SPACING; + if (debug) + { fprintf (logfile, "\nAfter process_appogg:\n"); + status_all (); + } + return; +} + +PRIVATE +void save_state (int i) +/* used in process_xtuplet */ +{ + beamingi = beaming[i]; + currenti = current[i]; + cspacingi = cspacing[i]; + vspacingi = vspacing[i]; + first_collectivei = first_collective[i]; + collectivei[0] = '\0'; + append (collectivei, NULL, collective[i], SHORT_LEN); +} + +PRIVATE +void restore_state (int i) +/* used in process_xtuplet */ +{ + beaming[i] = beamingi; + current[i] = currenti; + cspacing[i] = cspacingi; + vspacing[i] = vspacingi; + first_collective[i] = first_collectivei; + collective[i][0] = '\0'; + append (collective[i], NULL, collectivei, SHORT_LEN); +} + + +PRIVATE +void process_xtuplet (void) +{ + int i; + int xspacing = MAX_SPACING; /* xtuplet total spacing */ + int normalized_xspacing; /* (xspacing / xtuplet) * (xtuplet - 1); */ + int xsp; + double multnoteskip; + + if (debug) + { fprintf (logfile, "\nEntering process_xtuplet:\n"); + fprintf (logfile, "xtuplet=%d\n", xtuplet); + fprintf (logfile, "xi=%d\n\n", xi); + status (xi); + } + + if (old_spacing < MAX_SPACING) + { + if (debug) fprintf (logfile, "Terminate current notes command:\n"); + for (i=1; i <= nstaffs; i++) + { if (active[i]) + { + fprintf (outfile, "%s", outstrings[i]); + if (debug) fprintf (logfile, "%s", outstrings[i]); + } + if ( (terminator[i] == '&') || (terminator[i] == '|') ) + putc (terminator[i], outfile); + } + fprintf (outfile, "\\en"); + if (debug) + { fprintf (logfile, "\\en"); + fprintf (logfile, "\nAfter termination of notes command:\n"); + status_all (); + } + } + + if (debug) fprintf (logfile, "\nDetermine xtuplet duration:\n"); + { + save_state (xi); + pseudo_output_notes (xi); + xspacing = spacings[xi]; + do + { + xspacing += spacing_note (xi); + pseudo_output_notes (xi); + if (xspacing >= MAX_SPACING) + error ("Can't determine xtuplet duration."); + } + while (xspacing % xtuplet != 0); + restore_state (xi); + } + if (debug) fprintf (logfile, "\nxspacing=%s\n", ps(xspacing)); + normalized_xspacing = (xspacing / xtuplet) * (xtuplet - 1); + if (debug) + { fprintf (logfile, "normalized_xspacing=%s\n", ps(normalized_xspacing)); + fprintf (logfile, "\nDetermine minimal spacing over all active staffs:\n"); + } + spacing = xspacing / xtuplet; + for (i=1; i <= nstaffs; i++) + if (active[i] && i != xi) + { save_state (i); + pseudo_output_notes (i); + xsp = spacings[i]; + if (spacings[i] < spacing) + spacing = spacings[i]; + while (xsp < normalized_xspacing) + { int spi = spacing_note (i); + pseudo_output_notes (i); + xsp += spi; + if (spi < spacing) + { spacing = spi; + if (debug) fprintf (logfile, "for i=%d spi=%s\n", i, ps(spi)); + } + } + restore_state (i); + } + if (debug) fprintf (logfile, "\nxspacing=%s\n", ps(spacing)); + + if (debug) fprintf (logfile, "\nCreate a new notes command for the xtuplet:\n"); + initialize_notes (); + multnoteskip = (double) (xtuplet - 1) / xtuplet; + n_outstrings[xi] += sprintf (n_outstrings[xi], "\\multnoteskip{%5.3f}", multnoteskip); + if (debug) + { fprintf (logfile, "\noutstrings[%d]=", xi); + note_segment (outstrings[xi]); + } + + if (debug) fprintf (logfile, "\nProcess non-xtuplet staffs:\n"); + for (i=1; i <= nstaffs; i++) + vspacing[i] = 0; + xsp = 0; + while (true) + { + for (i=1; i <= nstaffs; i++) + if (active[i] && i != xi) + output_notes (i); + xsp += spacing; + for (i=1; i <= nstaffs; i++) + { + /* virtual notes needed? */ + if (active[i] && i != xi && spacings[i] != 0 && spacings[i] != spacing && vspacing[i] == 0) + { + vspacing[i] = spacings[i] - spacing; + } + } + if (xsp >= normalized_xspacing) break; + for (i=1; i <= nstaffs; i++) + if (active[i] && i != xi) + spacings[i] = spacing_note(i); + } + if (debug) + { fprintf (logfile, "\nAfter processing non-xtuplet staffs:\n"); + status_all (); + } + if (debug) fprintf (logfile, "\nRe-process xtuplet staff:\n"); + xsp = 0; + while (true) + { output_notes (xi); + xsp += spacing; + if (spacings[xi] != spacing && vspacing[xi] == 0) + vspacing[xi] = spacings[xi] - spacing; + if (xsp >= xspacing) break; + spacings[xi] = spacing_note (xi); + } + + /* Restore normal \noteskip in the xtuplet staff. */ + multnoteskip = (double) (xtuplet) / (xtuplet-1); + n_outstrings[xi] += sprintf (n_outstrings[xi], "\\multnoteskip{%5.3f}", multnoteskip); + xtuplet = 1; + nonvirtual_notes = true; + if (debug) + { fprintf (logfile, "\nAfter process_xtuplet:\n"); + status_all (); + } + return; +} + +PRIVATE +void generate_notes () +/* Repeatedly output one note for each (active) staff + * and, if necessary, set up for subsequent "virtual" notes (skips). + * If spacing has changed, terminate an existing notes command + * and initialize a new one. + */ +{ int i; + while (true) + { old_spacing = spacing; + spacing = MAX_SPACING; + nonvirtual_notes = false; + if (debug) + { fprintf (logfile, "\nIn generate_notes:\n"); + status_all (); + } + for (i=1; i <= nstaffs; i++) + if (active[i]) + { + spacings[i] = spacing_note (i); + if (spacings[i] < spacing) + spacing = spacings[i]; + } + if (appoggiatura) + { + process_appogg (); + } + if (xtuplet > 1) + { + process_xtuplet (); + continue; + } + if (spacing != old_spacing || spacing == MAX_SPACING) + { if (old_spacing < MAX_SPACING) + terminate_notes (); + if (spacing == MAX_SPACING || nonvirtual_notes == false) + { + if (debug) + { fprintf (logfile, "\nAfter generate_notes:\n"); + status_all (); + } + return; + } + if (old_spacing < MAX_SPACING) putc ('\n', outfile); + if ( nastaffs == 1 && spacing != BARREST_SPACING && restbars > 0) + output_rests (); + initialize_notes (); + } + for (i=1; i <= nstaffs; i++) /* append current notes to outstrings */ + if (active[i]) output_notes (i); + for (i=1; i <= nstaffs; i++) + { + /* virtual notes needed? */ + if (active[i] && spacings[i] != MAX_SPACING && spacings[i] != spacing && vspacing[i] == 0 ) + { + vspacing[i] = spacings[i]; + vspacing[i] = vspacing[i] - spacing; + if (debug) + { fprintf (logfile, "\nAfter vspacing initialization:\n"); + status (i); + } + } + } + } +} + + +PRIVATE +void process_command (char **ln) +{ char *s, *t; + if (debug) + { fprintf (logfile, "\nProcessing command:%s\n", *ln); + fflush (logfile); + } + if ( prefix("\\instrumentnumber", *ln) ) + { + s = strpbrk (*ln, "123456789"); + if ( s == NULL ) error ("\\instrumentnumber command unreadable."); + ninstr = atoi (s); + while (*ln <= s) { putc (**ln, outfile); (*ln)++;} + } + + if ( prefix("\\def\\nbinstrument", *ln) ) + { + s = strpbrk (*ln, "123456789"); + if ( s == NULL ) error ("\\def\\nbinstrument command unreadable."); + ninstr = atoi (s); + while (*ln <= s) { putc (**ln, outfile); (*ln)++;} + } + + else if ( prefix("\\setstaffs", *ln) ) + { /* for now, just record in staffs[i] */ + int n, p; + s = strpbrk (*ln, "123456789"); + if ( s == NULL ) error ("\\setstaffs command unreadable."); + n = (int)(*s) - (int)('0'); /* instrument number */ + s = strpbrk (s+1, "123456789"); + if ( s == NULL ) error ("\\setstaffs command unreadable."); + p = (int)(*s) - (int)('0'); /* number of staffs */ + staffs[n] = p; + while (*ln <= s) { putc (**ln, outfile); (*ln)++;} + } + + else if ( prefix("\\startpiece", *ln) ) + { int i, j; + nstaffs = 0; + for (i=1; i <= ninstr; i++) + { for (j=1; j <= staffs[i]; j++) + { nstaffs++; + if (nastaffs == 0) active[nstaffs] = true; + } + } + if (nstaffs == 1) fprintf (outfile, "\\nostartrule\n"); + fprintf (outfile, "\\startpiece"); + t = strpbrk (*ln+1, "\\%\n"); + *ln = t; + } + + else if ( prefix("\\startextract", *ln) ) + { int i, j; + nstaffs = 0; + for (i=1; i <= ninstr; i++) + { for (j=1; j <= staffs[i]; j++) + { nstaffs++; + if (nastaffs == 0) active[nstaffs] = true; + } + } + if (nstaffs == 1) fprintf (outfile, "\\nostartrule\n"); + fprintf (outfile, "\\startextract"); + t = strpbrk (*ln+1, "\\%\n"); + *ln = t; + } + + else if ( prefix("\\TransformNotes", *ln) ) + { /* determine ninstr, nstaffs, nastaffs, staffs[i], and active[i] */ + int i; + s = *ln + 16; /* first parameter */ + ninstr = 0; + nstaffs = 0; + while (true) + { ninstr++; nstaffs++; + staffs[ninstr] = 1; + active[ninstr] = false; + checkc (s, '#'); s++; + checkn (s); s++; + while (*s == '|') + { staffs[ninstr]++; nstaffs++; + s++; + checkc (s, '#'); s++; + checkn (s); s++; + } + if (*s != '&') break; + s++; + } + checkc (s, '}'); s++; + for (i=1; i <= nstaffs; i++) active[i] = false; + nastaffs = 0; + t = strchr (s,'{'); + if (t == NULL) error ("Can't parse \\TransformNotes."); + s = strpbrk (t, "#}"); /* may have \transpose etc. before # */ + while (*s == '#') + { if (sscanf (s, "#%d", &i) != 1) + error ("sscanf for argument number fails"); + active[i-1] = true; /* parameters start at 2 */ + nastaffs++; + s = strpbrk (s+1, "#}"); + } + while (*ln <= s) + { putc (**ln, outfile); (*ln)++;} + } + + else if ( prefix("\\def\\vnotes#1\\elemskip", *ln) ) + { /* determine ninstr, nstaffs, nastaffs, staffs[i], and active[i] */ + int i; + ninstr = 0; + nstaffs = 0; + s = *ln + 22; /* first parameter */ + while (true) + { ninstr++; nstaffs++; + staffs[ninstr] = 1; + active[ninstr] = false; + checkc (s, '#'); s++; + checkn (s); s++; + while (*s == '|') + { staffs[ninstr]++; nstaffs++; + s++; + checkc (s, '#'); s++; + checkn (s); s++; + } + if (*s != '&') break; + s++; + } + for (i=1; i <= nstaffs; i++) active[i] = false; + nastaffs = 0; + t = strstr (s, "@vnotes") + 7; + if (t == NULL) error ("Can't parse \\def\\vnotes."); + s = strpbrk(t, "#}"); /* may have \transpose etc. before # */ + while (*s == '#') + { if (sscanf (s, "#%d", &i) != 1) + error("sscanf for argument number fails"); + active[i-1] = true; /* parameters start at 2 */ + nastaffs++; + s = strpbrk (s+1, "#}"); + } + while (*ln <= s) + { putc (**ln, outfile); (*ln)++;} + } + + else if (prefix("\\def\\atnextbar{\\znotes", *ln) && nastaffs == 1 ) + { /* whole-bar or multi-bar rest? */ + int i; + char *saveln = *ln; /* in case there's no centerpause */ + bool centerpause = false; + analyze_notes(ln); + for (i=1; i <= nstaffs; i++) + { + if (active[i]) + { char *t; + char *s; + t = strpbrk (notes[i], "&|$"); + if (t == NULL) t = notes[i] + strlen (notes[i]); + s = strstr (notes[i], "\\centerpause"); + if (s != NULL && s < t) + { + bar_rest[i] = true; + centerpause = true; + } + break; + } + } + if (centerpause) + { + t = strchr (*ln, '}'); + if (t == NULL) error ("Can't find }."); + *ln = t+1; + t = strpbrk (*ln, "%\\"); + if (t == NULL ) t = *ln + strlen(*ln); + *ln = t; + } + else + { /* treat like other \def commands */ + *ln = saveln; + t = strchr (*ln, '$'); + *t = '\\'; /* restore "\en[otes] */ + t = *ln + strlen(*ln); + while (*ln < t) + { fputc (**ln, outfile); + (*ln)++; + } + } + } + + else if ( prefix("\\def", *ln) ) + { t = *ln + strlen(*ln); + while (*ln < t) + { fputc (**ln, outfile); + (*ln)++; + } + } + + else if ( prefix("\\anotes", *ln) + || (fixnotes && + ( prefix("\\nnnotes", *ln) || + prefix("\\nnotes", *ln) || + prefix("\\notes", *ln) || + prefix("\\Notes", *ln) || + prefix("\\NOtes", *ln) || + prefix("\\NOTes", *ln) || + prefix("\\NOTEs", *ln) ) ) ) + { if (debug) + { fprintf (logfile, "\nProcessing %s", *ln); + fprintf (logfile, "lineno=%d\n", lineno); + fflush (logfile); + } + analyze_notes (ln); + if (debug) + { fprintf (logfile, "\nBefore generate_notes *ln=%s\n", *ln); + fflush (logfile); + } + generate_notes (); + if (debug) + { fprintf (logfile, "\nAfter generate_notes *ln=%s\n", *ln); + fflush (logfile); + } + t = strpbrk (*ln, "%\\\n"); + if (t == NULL) t = *ln + strlen (*ln); + if (*t == '\n') putc ('%', outfile); + *ln = t; + } + + else if ( prefix ("\\bar", *ln) && !prefix ("\\barno", *ln)) + { int i; + bool atnextbar = false; + for (i=1; i <= nstaffs; i++) + if (active[i] && bar_rest[i]) + { atnextbar = true; break; } + if (nastaffs == 1 && atnextbar) + { restbars++; + sprintf (deferred_bar, "\\bar"); + if (debug) fprintf (logfile, "\nrestbars increased to %d\n", restbars); + for (i=1; i<= nstaffs; i++) + bar_rest[i] = false; + *ln = *ln+4; + t = strpbrk (*ln, "\\\n"); + if (t == NULL) t = *ln + strlen (*ln); + if (*t == '\n') putc ('%', outfile); + *ln = t; + } + else + { if (atnextbar) + { fprintf (outfile, "\\def\\atnextbar{\\znotes"); + for (i=1; i <= nstaffs; i++) + { + if (active[i]) + { + if (bar_rest[i]) + fprintf (outfile, "\\centerpause"); + bar_rest[i] = false; + } + if ( (terminator[i] == '&') || (terminator[i] == '|') ) + putc (terminator[i], outfile); + } + fprintf (outfile, "\\en}%%\n"); + } + if (Changeclefs) /* \Changeclefs has to be output after \def\atnextbar... */ + { + fprintf ( outfile, "\\Changeclefs%%\n"); + Changeclefs = false; + } + t = strpbrk (*ln+1, "%\\\n"); + while (*ln < t) + { fputc (**ln, outfile); + (*ln)++; + } + if (*t == '\n') putc ('%', outfile); + *ln = t; + } + if (debug) + { fprintf (logfile, "\nAfter \\bar processing, *ln=%s\n", *ln); + fflush (logfile); + } + } + + else if ( prefix ("\\endpiece", *ln) + || prefix ("\\Endpiece", *ln) + || prefix ("\\endextract", *ln) + || prefix ("\\stoppiece", *ln) + || prefix ("\\raggedstoppiece", *ln) + || prefix ("\\rightrepeat", *ln) + || prefix ("\\leftrepeat", *ln) + || prefix ("\\alaligne", *ln) + || prefix ("\\alapage", *ln) + || prefix ("\\changecontext", *ln) + || prefix ("\\Changecontext", *ln) + || prefix ("\\zalaligne", *ln) + || prefix ("\\zalapage", *ln) ) + { int i; + bool atnextbar = false; + for (i=1; i <= nstaffs; i++) + if (active[i] && bar_rest[i]) + { atnextbar = true; break; } + if (nastaffs == 1 && atnextbar) + { restbars++; + sprintf (deferred_bar, "%s", *ln); + output_rests (); + t = strpbrk (*ln+1, "%\\\n"); + if (*t == '\n') putc ('%', outfile); + *ln = t; + } + else if (atnextbar) + { + fprintf (outfile, "\\def\\atnextbar{\\znotes"); + for (i=1; i <= nstaffs; i++) + { + if (active[i]) + { + if (bar_rest[i]) + fprintf (outfile, "\\centerpause"); + bar_rest[i] = false; + } + if ( terminator[i] != '$') putc (terminator[i], outfile); + } + fprintf (outfile, "\\en}%%\n"); + if (Changeclefs) /* \Changeclefs has to be output after \def\atnextbar... */ + { + fprintf ( outfile, "\\Changeclefs%%\n"); + Changeclefs = false; + } + t = strpbrk (*ln+1, "%\\\n"); + while (*ln < t) + { fputc (**ln, outfile); + (*ln)++; + } + if (*t == '\n') putc ('%', outfile); + *ln = t; + } + else + { if (nastaffs == 1 && restbars > 0) + output_rests (); + t = strpbrk (*ln+1, "%\\\n"); + while (*ln < t) + { fputc (**ln, outfile); + (*ln)++; + } + if (*t == '\n') putc ('%', outfile); + *ln = t; + } + if (debug) + { fprintf (logfile, "\nAfter \\bar processing, *ln=%s\n", *ln); + fflush (logfile); + } + } + + else if ( prefix ("\\znotes", *ln) ) + { + if (nastaffs == 1 && restbars > 0) + output_rests (); + fputs (*ln, outfile); + *ln = *ln + strlen(*ln); + } + + else if ( prefix ("\\Changeclefs", *ln) ) + { /* defer till after \def\atnextbar ... */ + Changeclefs = true; + *ln = *ln + strlen(*ln); + } + + + else /* everything else */ + { + fputs (*ln, outfile); + *ln = *ln + strlen(*ln); + } +} + +PRIVATE +void process_line () +{ + char *ln; + ln = &line[0]; + while ( *ln != '\0') + { + while (*ln == ' ') { ln++; fputc (' ', outfile); } + if (*ln == '%') { + fprintf (outfile, "%s", ln); + return; + } + process_command (&ln); + } +} + +PRIVATE +void process_score () +/* process .tex file */ +{ + int c; int i; + lineno = 0; + for (i=1; i < MAX_STAFFS; i++) + { + staffs[i] = 1; + active[i] = true; + bar_rest[i] = false; + } + spacing = MAX_SPACING; + restbars = 0; + c = getc (infile); + while ( c != EOF ) + { + ungetc (c, infile); + fgets(line, LINE_LEN, infile); + lineno++; + process_line (); + c = getc (infile); + } /* c == EOF */ +} + +int main (int argc, char *argv[]) +{ + int c; + char today[12]; + time_t mytime; +# define NOPTS 5 + struct option longopts[NOPTS] = + { { "help", 0, NULL, 'h'}, + { "version", 0, NULL, 'v'}, + { "dotted", 0, NULL, 'd'}, + { "log", 0, NULL, 'l'}, + { NULL, 0, NULL, 0} + }; + + time (&mytime); + strftime (today, 11, "%Y-%m-%d", localtime (&mytime) ); + fprintf (stdout, "This is autosp, version %s.\n", version); + fprintf (stdout, "Copyright (C) 2014-16 R. D. Tennent\n" ); + fprintf (stdout, "School of Computing, Queen's University, rdt@cs.queensu.ca\n" ); + fprintf (stdout, "License GNU GPL version 2 or later <http://gnu.org/licences/gpl.html>.\n" ); + fprintf (stdout, "There is NO WARRANTY, to the extent permitted by law.\n\n" ); + + c = getopt_long (argc, argv, "hvdl", longopts, NULL); + while (c != -1) + { + switch (c) + { + case 'h': + usage (stdout); + fprintf (stdout, "Please report bugs to rdt@cs.queensu.ca.\n" ); + exit (0); + case 'v': + fprintf (stdout, "This is autosp, version %s.\n", version); + exit (0); + case 'd': + dottedbeamnotes = true; + break; + case 'l': + debug = true; + break; + case '?': + exit (EXIT_FAILURE); + default: + fprintf (stderr, "Function getopt returned character code 0%o.\n", + (unsigned int) c); + exit (EXIT_FAILURE); + } + c = getopt_long (argc, argv, "hvd", longopts, NULL); + } + + infilename[0] = '\0'; + infilename_n = infilename; + if (optind < argc) + { append (infilename, &infilename_n, argv[optind], sizeof (infilename)); + if (!suffix (".tex", infilename) && !suffix (".aspc", infilename)) + append (infilename, &infilename_n, ".aspc", sizeof (infilename)); + } + else + { usage(stderr); + exit (EXIT_FAILURE); + } + infile = fopen (infilename, "r"); + if (infile == NULL && suffix (".tex", infilename) ) + { fprintf (stderr, "Can't open %s\n", infilename); + exit (EXIT_FAILURE); + } + else if (infile == NULL && suffix (".aspc", infilename) ) + { /* try infile.tex */ + infilename_n -= 4; + *infilename_n = '\0'; + append (infilename, &infilename_n, "tex", sizeof (infilename)); + infile = fopen (infilename, "r"); + if (infile == NULL && suffix (".tex", infilename) ) + { fprintf (stderr, "Can't open %s\n", infilename); + exit (EXIT_FAILURE); + } + } + printf ("Reading from %s.", infilename); + if (suffix (".tex", infilename) ) + fixnotes = true; + + optind++; + outfilename[0] = '\0'; + outfilename_n = outfilename; + if (optind < argc) /* user-provided outfilename */ + { + append (outfilename, &outfilename_n, argv[optind], sizeof (outfilename)); + if (!suffix (".tex", outfilename)) + append (outfilename, &outfilename_n, ".tex", sizeof (outfilename)); + } + else if (suffix (".aspc", infilename) ) + { /* output to infile.tex */ + append (outfilename, &outfilename_n, infilename, sizeof (outfilename)); + outfilename_n -= 4; + *outfilename_n = '\0'; + append (outfilename, &outfilename_n, "tex", sizeof (outfilename)); + } + + if (*outfilename == '\0') + { outfile = stdout; + printf (" Writing to stdout."); + } + else + { + if (strcmp (outfilename, infilename) == 0) + { + printf ("\n"); + error ("outfile same as infile."); + } + outfile = fopen (outfilename, "w"); + if (outfile == NULL) + { fprintf (stderr,"Can't open %s\n", outfilename); + exit (EXIT_FAILURE); + } + printf (" Writing to %s.", outfilename); + } + + logfilename[0] = '\0'; + logfilename_n = logfilename; + append (logfilename, &logfilename_n, infilename, sizeof (logfilename)); + if (suffix (".aspc", infilename) ) + logfilename_n -= 4; + else + logfilename_n -= 3; + *logfilename_n = '\0'; + append (logfilename, &logfilename_n, "alog", sizeof (logfilename)); + if (debug) + { logfile = fopen (logfilename, "w"); + if (logfile == NULL) + { fprintf (stderr, "Can't open %s\n", logfilename); + exit (EXIT_FAILURE); + } + printf (" Log file %s.", logfilename); + } + printf ("\n\n"); + + fprintf (outfile, "%% Generated by autosp (%s).\n", version); + process_score (); + + return 0; +} |