Introduction
Introduction Statistics Contact Development Disclaimer Help
initial import of V1.3.3 - abc2ps - A powerful sheet setting tool using the sim…
git clone git://vernunftzentrum.de/abc2ps.git
Log
Files
Refs
---
commit 3a06ea49c1f1fb94fb58a82709906dbe620186f3
Author: Christian Kellermann <[email protected]>
Date: Sat, 14 Apr 2018 22:52:22 +0200
initial import of V1.3.3
Diffstat:
Changes | 526 +++++++++++++++++++++++++++++++
License | 339 +++++++++++++++++++++++++++++++
New.Features | 334 +++++++++++++++++++++++++++++++
ReadMe.abc2ps | 778 +++++++++++++++++++++++++++++++
abc2ps.c | 753 +++++++++++++++++++++++++++++++
bach.abc | 28 ++++++++++++++++++++++++++++
blue_boy_bass.abc | 35 +++++++++++++++++++++++++++++++
bran5.abc | 54 +++++++++++++++++++++++++++++++
buffer.h | 202 +++++++++++++++++++++++++++++++
celloprelude.abc | 34 +++++++++++++++++++++++++++++++
desafinado.abc | 21 +++++++++++++++++++++
fbook.fmt | 26 ++++++++++++++++++++++++++
fonts.fmt | 5 +++++
format.h | 489 +++++++++++++++++++++++++++++++
journey.abc | 36 +++++++++++++++++++++++++++++++
landscape.fmt | 11 +++++++++++
layout.txt | 150 +++++++++++++++++++++++++++++++
mtunes1.abc | 55 +++++++++++++++++++++++++++++++
music.h | 4496 +++++++++++++++++++++++++++++++
newfeatures.abc | 121 +++++++++++++++++++++++++++++++
parse.h | 2460 ++++++++++++++++++++++++++++++
pssubs.h | 338 +++++++++++++++++++++++++++++++
sample.abc | 122 +++++++++++++++++++++++++++++++
scotland.abc | 22 ++++++++++++++++++++++
style.h | 87 +++++++++++++++++++++++++++++++
style.pure | 104 +++++++++++++++++++++++++++++++
subs.h | 1372 +++++++++++++++++++++++++++++++
syms.h | 1226 +++++++++++++++++++++++++++++++
trio.abc | 44 +++++++++++++++++++++++++++++++
util.h | 494 +++++++++++++++++++++++++++++++
voices.abc | 151 +++++++++++++++++++++++++++++++
31 files changed, 14913 insertions(+), 0 deletions(-)
---
diff --git a/Changes b/Changes
@@ -0,0 +1,526 @@
+
+17.03.99 Experimentally changed parsing so that the end of the header
+ comes at the first music or V: line.
+
+ Note: according to the abc specs, the header ends with the K: line.
+ However, nobody seems aware of this. For multistave music it is
+ important exactly where the header ends, because info fields
+ in the body of the music (outside the header) only operate on
+ the current voice. Info fields in the header operate on all
+ the voices.
+
+16.03.99 Fixed various reported bugs.
+
+25.01.99 Support fermata over a rest.
+
+----- Version 1.3.3 -----
+
+
+10.12.98 New flag: -I writes the contents and page numbers to file Ind.ps.
+
+
+08.12.98 Fixed bug: transposing was wrong for clef changes.
+
+
+----- Version 1.3.2 -----
+
+10.08.98 Added new codes for accents (cf. sample.abc):
+ k: Accent which looks like >
+ K: Accent which looks like an upside-down V.
+
+
+05.08.98 Added bar numbering and bar labels.
+
+ Bar numbers:
+ to switch on bar numbering, use flag -k
+ where: -k 1 numbers every bar
+ -k 5 numbers every fifth bar, etc.
+ -k 0 numbers the first bar in every staff.
+ or, use the equivalent pseudocomment %%barnumbers <number>.
+ (Note: -k was used because it sounds a bit like "count".)
+
+ The program counts through the bars automatically, trying
+ to do the right thing at first and second endings. Namely:
+ it remembers the bar number at the start of the first ending,
+ then resets to that value at the start of the second ending.
+ So, if there is a tune with 2x8 measures with first and second
+ endings after the first 8 bars, we still end up with 16 bars
+ in total.
+ Within one tune, bar numbers are counted through over parts
+ boundaries. However, if a T: title appears inside a tune,
+ the bar number is reset to 1. You can use an empty T:
+ line to reset the bar number without actually writing a title.
+
+
+ Bar labels:
+ this is intended for large letters A, B, C...
+ to mark specific points in the music. They are coded by
+ using a syntax similar to guitarchords, but placed before
+ a bar line instead of a note or rest, e.g.:
+ | abcd "A"| ABCD |
+ places the letter A over the second bar line.
+ Just in case somebody wants a label on the first bar
+ (which is often not preceded by a bar line), a new
+ symbol [|] was introduced for an "invisible" bar line.
+
+
+ Fonts for bar numbers and bar labels:
+ These can be set in the usual way with the two pseudocomments
+ %%barnumberfont and %%barlabelfont.
+
+ In printed music, the bar numbers are often made more visible
+ by putting a box around them. This is now also possible.
+ In fact, a box can be put around most bits of text by
+ adding the word "box" to the font specification, e.g.:
+
+ %%barnumberfont Times-Italic 11 box
+
+ This can be done for the title, guitarchords, vocals, etc.
+ To switch on the box without changing the font style and/or size,
+ the character * can be used, as in:
+
+ %%titlefont * * box
+
+
+ A reminder: to see all the style specifications use 'abc2ps -H'
+ (for the standard format) or 'abc2ps -PH' (pretty2 format).
+ This gives a list suitable for placing in a .fmt file.
+ To modify settings for a single tune only, place the
+ pseudocomments after the 'T:' lines and before the 'K:' line
+ in the tune header.
+
+
+ Examples: look at celloprelude.abc for examples of bar numbers
+ and bar labels. Try 'abc2ps -maxv 8 -k0 bran5' or
+ 'abc2ps -k0 bach' to see bar numbers at the start of
+ the line, as is often used for scores.
+
+
+
+20.07.98 Fixed bug overwriting when lvoiceid too short.
+
+----- Version 1.3.1 -----
+
+12.07.98 A number of enhancements to format multi-stave music nicely.
+ For examples, see files trio.abc bran5.abc voices.abc bach.abc.
+
+ In detail: indentation of the first staff, labels for voices,
+ braces and brackets to group voices, and some additional
+ parameters in the V: line to control the output.
+
+ As before, the syntax of the V: line is
+
+ V: <label> <par1>=<value1> <par2>=<value2> ...
+
+ where <label> is used to switch to the voice in later V: lines.
+ Each <par>=<value> pair sets one parameter for the current voice.
+ There are now alternate short version of the parameter names.
+
+
+ List of the parameters allowed in a V: line:
+
+ parm short example and description
+ ----------------------------------------
+
+ name nm nm=Violin I"
+ This sets the long version of the voice name, to be
+ written before the staves at the start of a piece.
+ If the string contains \\, this is interpreted
+ as a line break and the pieces are writen above
+ each other.
+
+ sname snm snm="Vl. I"
+ Short version of the name, written before
+ subsequent staves.
+
+ clef cl clef=bass
+ Chooses the clef (treble, alto, or bass).
+ It can also be bass+8 and so on.
+
+ staves stv stv=2
+ This is the number of staves (starting from the
+ current one) to connect by tall vertical bar lines.
+
+ brace brc brace=2
+ This is the number of staves (starting from the
+ current one) to be grouped together with a brace.
+ When this option is used, the name defined in the
+ same V: line is written at the center of the brace.
+
+ bracket brk brk=4
+ The number of staves to be grouped together by
+ a bracket. This option does not change the way
+ in which the names are written.
+
+ space spc spc=40
+ This defines or modifies the vertical space between
+ this staff and the one below it. The space can be
+ given in pt (default) or with a unit in the form
+ 1cm or 0.4in. Furthermore: if a + or - sign
+ comes after the start of the number, the value
+ is an increment to be added to or subtracted
+ from the default setting.
+
+ gchords gch gch=0
+ This controls whether any guitar chords
+ embedded in the current voice are actually written.
+ True/false are specified as for the %% formats.
+
+ stems stm stems=up
+ This is parsed but not yet used in the program.
+
+
+ New format directives:
+
+ %%voicefont font to write voice names with
+
+ %%indent <dim> amount to indent the first staff.
+ Indentation is done at the start of
+ the piece and after a T: field, but not
+ after a P: field.
+
+ Note: the margin still refers to the left edge of the staff.
+ Therefore, parameters %%leftmargin %%staffwidth %%indent
+ should be adjusted to leave room for the voice names.
+
+
+ New command-line flag:
+
+ The -V flag was redefined to select voices for output.
+ The old function ("show version") was integrated into -h.
+ The format is as in this example:
+
+ abc2ps -o input.abc -V 1-2,4
+
+ This will generate output only for the specified voices.
+ Specifically, a single voice can be extracted.
+
+
+ Other changes:
+
+ For a rest which fills out a complete measure, the symbol
+ for a full rest is drawn in the center of the bar, independent
+ of the the time signature.
+
+ Added K for strong emphasis decoration (upside-down V).
+
+
+
+
+31.05.98 L: after header but before first voice now sets default length
+ for first voice, named "1".
+
+12.05.98 Tab interpreted as space in music lines.
+
+01.04.98 Fixed Q:C=xxx for multi-stave version.
+
+19.03.98 Run-time allocation for symbols and voices.
+
+
+----- Version 1.3.0 -----
+
+03.03.98 Multi-stave music added.
+
+ To switch to a different voice, use a line starting with 'V:'.
+ An example for the most general form supported now is:
+ V:2 name="Clarinet 2" short="Cl.2" clef=treble stems=down
+ Note that the "2" is a treated as a string, so any single-word
+ identifier can be used instead. Later in the tune,
+ switch to the voice using only
+ V:2
+ The various settings (key, default length, etc) are
+ maintained for each voice separately.
+
+ Guitar chords, first and second endings, and line breaks are
+ taken from the top voice only. Vocals can be set under each
+ voice separately.
+
+ To format the output, two %% format directives were added
+ which determine the staff spacing: %%systaffsep %%systemsep.
+
+ It turned out that the note spacing should be slightly
+ different for multi-stave music. Namely, it is often a good
+ idea to space the notes somewhat more strictly according
+ to their duration than in single-stave music. There is now
+ a new parameter called "strictness" which the user can use
+ to adjust this. For strictness=1, the spacings for notes
+ with short durations is reasonably strictly proportional to
+ their duration. For strictness=0, they are spaced about
+ equally. Good defaults are strictness=0.5 for single-stave
+ music and strictness=0.8 for multistave music.
+ These parameters can be changed with the -X flag or
+ with %% statements in the abc file or in a .fmt file.
+ When using -X, a flag such as -X 0.6 will change both
+ values. To change them separately, use something like
+ -X 0.3,0.7 on the command line.
+
+ As usual, %% directives can be inspected with abc -H
+ and help about flags is obtained with abc -h.
+
+ Files voices.abc and bach.abc have examples for multistave
+ music.
+
+01.03.98 Changed -d flag to accept incremental changes such as -d-5
+ or -d+5.
+
+28.12.97 Transposing added. Also double sharp and double flat symbols.
+ To transpose: use flag -t in two possible ways.
+ (1) Specify the new root explicitly using the form
+ -t XX where XX is the new root note. For example:
+ -t C or -t Bb or -t C#
+ This shifts either up or down, depending on which shift is
+ smaller. To force up or down direction, use prefixes ^_ eg.
+ -t ^C or -t _C
+ (2) Specify the number of halftones to shift by in the form
+ -t nn where nn is the number of halftones.
+ For negative shift, use either a sticky argument
+ such as -t-2 or prefix with underscore, eg -t _2.
+
+ In any case: the program first decides how many halftones
+ to shift the pitches by. This number is kept fixed throughout
+ the whole tune. In this way, key changes within the tune
+ are treated properly.
+
+ To obain information about the transposing process, set the
+ verbosity to 3 or 4 (ie: -v 3 or -v 4).
+
+
+24.12.97 Shift up guitar chords over n-plet brackets.
+
+15.12.97 Some modifications to extent of 1st and 2nd endings.
+
+29.11.97 Q: field now prints out tempo denotations.
+ General form is Q: w1 w2 w3.. where each word is either
+ a string in double quotes such as "Andante" or "Bossa Nova"
+ or a tempo denotation such as C or C=120 or 120.
+ Strings are printed directly, denotations are translated
+ to the form note=100. Font is in new format field "tempofont".
+
+29.11.97 Guitar chords positioned a bit more nicely (centered,
+ except if especially wide).
+
+29.11.97 Added blank-delimited +8 and -8 as extensions to key specifier.
+ Function: write all notes higher or lower by one octave.
+
+02.11.97 Words for vocals now centered under each note, looks nicer.
+ Changed left/right spacings to get better positioning for
+ single note in a bar.
+
+----- Version 1.2.5 -----
+
+05.10.97 Added page numbers for flag -N.
+
+05.10.97 Support for all modes (Wil Macaulay)
+
+07.08.97 Added "x" for rests which are invisible.
+
+14.07.97 Slurs and ties within chords improved, for example:
+ [(a(b] [c)d)] slurs a to c, b to d
+ [a-b] [ac] ties a to a
+
+14.07.97 Grace notes can be before or after guitar chord:
+ "A"{A}Bc and {A}"A"Bc both work.
+
+06.05.97 Fixed bug which sometimes put stems onto whole notes.
+
+06.03.97 Begintext lines can start with %%, to permit usage
+ in header fields and avoid conflict with other programs.
+
+17.02.97 Made txt array global.. avoid stack problems on Mac.
+ Added extra buffer flush at file end.
+
+15.02.97 C (alto) clef added, invoke with "K: alto"
+
+10.02.97 Now \- in vocals for '-' without breaking the word.
+ Changed to work even if no 'T:' field.
+ Fixed bug: did not print 'O:' if no 'C:'.
+
+09.02.97 Added "%%titlecaps" format statement.
+
+07.02.97 Introduced decoration T for "tr" above a note.
+
+----- Version 1.2.4b -----
+
+06.02.97 New: text, page formats, pseudocomments, bass clef.
+
+02.02.97 In-line escape sequences now also [..]
+
+23.01.97 removed "or:" from subtitles.
+
+
+----- Version 1.2.3-x1 -----
+
+26.11 Added aligned vocals under the staff. Example:
+ BA |: "Gm"G2AB|"C7"cd2e|"F"f2fe|"Dm"dA2d|
+ w: Close your eyes and I'll kiss you, to-mor-row I'll miss you; re-
+ "Bb"d2dc|"Gm"B2GF|"Eb"G4-|G2 z2|
+ w:mem-ber I'll al-ways be true._
+ Syntax:
+ Words are given in line starting as w: under music line.
+ Words are aligned one-by-one with the notes.
+ * skips one note.
+ | tabs forward to next bar line.
+ Hyphenations make two syllables, with "-" between them.
+ Underscore draws horizontal line from last word to note.
+ Blanks can be dropped around special chars (* | - _ ).
+
+19.11 Added bagpipe mode for K:HP.
+ Added landscape orientation for flag -l.
+
+05.11 Put in some first pseudocomments to format output:
+ %%sep - writes a standard separator
+ %%sep topspace botspace len - custom separator
+ %%newpage - force page break
+ %%text This is a line.. - write a line of text
+ %%vskip xx - add vertical space in cm
+
+06.10 Added 32nd and 64th rests, 64th notes.
+ Accidentals and grace notes more spaced when room.
+ Correct treatment of slurs at 1st, 2nd endings.
+
+----- Version 1.2.2 -----
+
+22.09 Words like "aza" now under one beam with rest under it.
+ Output "Origin" field in parens together with composer.
+ Added ties between chords.
+
+20.09 Keysigs such as "3+4/8" "78/8" "7 8/8" allowed.
+ Slopes of beams tuned a bit.
+ Fixed bug in position of tilde over stem.
+ Choose same stem directions on neighbors where reasonable.
+
+15.09 Small random horizontal shift of notes improve readability,
+ see RANFAC. Adjust internote spacing according to jump in pitch.
+
+05.08 Consistent handling for word breaks at end of input line.
+
+
+----- Version 1.2.1 -----
+
+28.07 Added W: for words of song.
+ Include notes, discography, transcription in output for -n.
+ Removed bug: ninf=0 messed up usage "abc2ps -h".
+
+26.07 Fixed: swallowed meter change sometimes.
+
+21.07 Correct handling of last line of file even if not terminated
+ by a newline character.
+ Some fine-tuning for beam position when more than one beam.
+ For staff middle, use stem direction from previous note.
+
+18.07 More tolerant of misuse of guitar chords to write general stuff
+ above staff; now OK if "...." is alone on a line.
+ Minibug in syms.h: 'staff' left junk on PS stack.
+
+17.07 For -c mode: don't complain about underfull; don't stretch
+ last staff much when underfull (new parameter BETA_C).
+
+16.07 Fixed obscure bug.. after overfull, sometimes took duration for
+ chord from wrong note, because heads were sorted by pitch.
+ Also: use shrinkage from previous staff for undefull last staff.
+
+15.07 Move slide further away for notes with accidentals.
+
+09.07 Selectors before first file also valid; apply to first file.
+ Took out atof & atoi calls; main now returns int; changed
+ function names def_HD,def_Hd,def_hd.
+
+
+----- Version 1.2 -----
+
+06.07 New flag -O to set output file.
+
+26.06 Added general n-plet syntax "(p:q:r".
+
+10.06 Slurs fatter in middle.
+ Hold (fermata) added code=H.
+ Changed code for bar to M (em-phasis).
+ Added up and down bow u,v.
+
+09.06 Thick-thin, thin thick bars now [| and |].
+ Ties a-b-c now done correctly.
+ Carryover slurs at start and end of line.
+
+08.06 Flat beams shifted to consistent positions relative to staff.
+
+07.06 Set beta0 to avoid infinite stretching.
+ Redid key changes.. mcl.abc Cm-> C was wrong.
+ Fiddled some with slurs.
+
+05.06 Fixed: accidental was too close on full note.
+
+03.06 fix up n-plet cases: (1) on beam with other notes,
+ (2) draw bracket if not on same beam.
+
+03.06 New flag -E to make EPS files eps001.ps, eps002.ps ...
+
+02.05 Guitar chord can be put anywhere before note.
+ Changed note placement for single note in bar.
+
+30.04 Mutiple decorations permitted on one note.
+ Bar for broad emphasis added, code is R.
+
+29.04 Unions: chord with two identical notes like [CC]
+
+29.04 Slide added, code is J.
+
+26.04 Output buffer takes care of page breaks.
+
+----- Version 1.2x -----
+
+[v1.2-x7]
+
+11.04 Output to <file>.ps possible; set OUTPUTFILE in abc2ps.c
+
+[v1.2-x6]
+
+28.03 Can do normal or pretty output, depending on flag -p.
+ Layout parameters bundled as macros in main.
+
+[v1.2-x5]
+
+21.03 Changed roll symbol some more.
+ Put extra \n at end of Out.ps.
+
+[v1.2-x4]
+
+17.03 Fixed nasty bug for selection by xref; now ok on NeXT.
+ Changed roll symbol.
+
+[v1.2-x3]
+
+14.03 Added roll sign as optional way to draw ~.
+ Changed program to avoid all 'gcc -Wall' warnings.
+
+10.03 Fixed wrong dimension for line in do_index (macro BSIZE)
+
+08.03 Took out '#copies..' in PS file.
+ Added -m flag to set margin.
+
+06.03 Added flag -i and interactive mode.
+ Fixed bug in beams, which wrote funny numbers over some beams.
+ Added "newpage" as option for E: field.
+
+04.03 Added -f flag to permit different selectors for different files.
+
+ Changed meter change within tune: for change at start of line,
+ generally writes the symbol (even if the meter did not change),
+ but not if the meter change was used only to set the default
+ length with 'l' or 's'.
+
+ Removed math calls: cos(phi) and sin(phi) defined explicitly
+ in syms.h, also removed sqrt for beam test in music.h.
+ Advantage: now compiles without -lm flag.
+ (Note: '#include <math.h>' still needed for atof ??)
+
+
+----- Version 1.1 -----
+
+24.02 Changed to multiple input files, added -e flag to identify
+ selectors in argument list.
+
+14.02 Outputs "book" field also for -n flag.
+ Chord font changed to Helvetica 12.
+
+
+
diff --git a/License b/License
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/New.Features b/New.Features
@@ -0,0 +1,334 @@
+
+New features in abc2ps 1.3.1 (M. Methfessel, July 1998)
+=======================================================
+
+The program now supports multi-stave output and has been improved
+in various other ways. Please look at Changes for more information.
+
+
+New features in abc2ps 1.2.4 (M. Methfessel, Feb. 1997)
+=======================================================
+
+
+Please also have a look at file newfeatures.abc, which
+demonstrates many of these points.
+
+
+----- Bass clef -----
+
+The bass clef is selected by appending the word "bass" to the
+key specification. eg. "K:G bass". Notes are then drawn so
+"C" is below the staff and "c" is in the third space from the top,
+which is a downward shift by one line relative to the treble clef.
+
+For in-line clef changes, use an in-line specification such as
+[K:G bass] (was formerly \K:G bass\; this still supported).
+If the key itself does not change, it is enough to write
+[K:bass] and similarily [K:treble].
+
+Added: [K:alto] makes the alto (viola or C) clef.
+
+
+----- Vocals -----
+
+Aligned lyrics under the staff are specified using a line directly
+below the staff, starting with "w:". For example:
+
+ edc2 edc2 |
+ w: Three blind mice, three blind mice
+
+Each blank-delimited word in the "w:" line is associated with
+one note, in sequence. The following special symbols are available
+to modify this behaviour:
+
+ * skips one note
+ - split a word into two syllables, associated with two notes,
+ with '-' drawn between them
+ | tabs forward to the next bar line.
+ ~ is drawn as a space, but contracts words to be written under
+ one note. That is, "hey~ho" gives two words under one note.
+ _ draws a thin "underscore" from the previous note to this one.
+
+For more than one line of lyrics, just use several w: lines.
+To draw a '-' without breaking the word there, escape it as "\-".
+
+Note that \\ in the abc music line now defines a staff break. This is
+useful when typesetting vocals, because it is tedious to split
+the line explicitly when shifting a staff break about when there
+are lines with vocals.
+
+If a word starts with a digit, this is interpreted as numbering of a
+stanza and is pushed forward a bit. In other words, use something like
+ w: 1.~~Three blind mice
+to put a number before "Three".
+
+
+----- Writing text between the music -----
+
+This can be done using pseudocomments in three ways. First:
+
+%%text This is a line of text.
+
+writes one line into the output. Second,
+
+%%center This is another line of text.
+
+again writes one line, but centers it. Finally,
+
+%%begintext
+%%First line of text
+%%Second line
+%%And yet another line.
+%%endtext
+
+will write a block of several lines. To avoid conflict with other
+programs, the text lines themselves are (optionally) prefaced with %%.
+
+Statement "%%begintext" can be given a parameter to determine
+how the output is done, namely:
+
+%%begintext obeylines keeps lines as they are (default)
+%%begintext ragged puts in own linebreaks to fill the line
+%%begintext align puts in own breaks and aligns right margin
+%%begintext skip skips the whole block, no output.
+
+For "ragged" and "align", the program has to estimate the number of
+lines needed in the current font, since the typesetting is done
+using the PostScript "widthshow" operator by the printer.
+The estimate should be reasonably reliable for Times-Roman, but might
+be more dodgy for some other fonts. Also, note that the Ghostview fonts
+can be quite different than the fonts used by the printer.
+Strangely, a 13pt font can be smaller than a 12pt font.
+
+An empty line in a block ends a paragraph (see parskipfac below).
+In any case, \\ can be used in a line of text to add line breaks.
+Thus, two centered lines results from this:
+%%center First line\\second line
+
+As with the other pseudocomments (described below), the text is
+associated with a specific tune if it is within that tune's block.
+In that case, it will only be printed if that tune is selected.
+If the text is outside all tune blocks, it will always be printed.
+The exception is if -E is used to to make a separate EPS file for
+each tune. In this case all text outside the blocks is ignored.
+
+The font for text output is determined as described below.
+
+
+----- Other pseudocomments which do something -----
+
+%%sep - draws a short centered line as a separator
+
+%%sep h1 h2 len - draws a separator of length len with space
+ h1 above, space h2 below.
+
+%%vskip h - adds vertical space of height h
+
+
+%%newpage - writes a page break
+
+
+Dimensions can be given in cm, in, or pt, where pt is the default.
+Examples: "%%sep 1cm 1cm 4cm" or "vskip 1.5cm".
+
+
+----- Output formating -----
+
+The user can now tailor the appearance of the output page.
+This is done by setting formating parameters, for example:
+
+ pageheight 29cm % height of page
+ staffwidth 5in % width of staff
+ leftmargin 1.8cm % left margin
+ titlefont Times-Roman 14 % the font for the title
+ titlespace 1cm % vertical space before the title
+ scale 0.9 % size of musical symbols
+ staffsep 60pt % space between staves
+
+Use abc2ps -H to see the current values of these parameters.
+
+To specify the parameters, there are four levels:
+
+1. By default, a predefined set called "standard" is used.
+ With flag -p, an alternative "pretty" set is taken.
+ With flag -P, a third set "pretty2" is used.
+ Users are encouraged to make their own choices for these styles
+ and change the program accordingly (see routines
+ set_standard_format, set_pretty_format, set_pretty2_format
+ in file format.h).
+
+2. Commands to set the parameters can be grouped into a file
+ with extension "fmt", which can then be selected by flag -F.
+ For example: there should be a file landscape.fmt in the
+ distribution. This changes the page orientation to landscape
+ and sets the page height and width accordingly, and also changes
+ the title style a bit. To output file scotland.abc in landscape,
+ the command is
+ abc2ps scotland.abc -F landscape -o
+
+3. An abc file can contain pseudocomments (%%..) such as:
+ %%staffwidth 16cm
+ %%titlespace 1.4cm
+ Depending on the position, the changes to the style parameters
+ are either global for the rest of the file, or local to a single
+ tune. The change is global if the line is outside any tune block
+ (where a tune block starts with "X:" and ends with a blank line).
+ If the pseudocomment is within such a block, the parameter change
+ is only applied for this tune.
+ Note that the program cannot determine if a tune is selected
+ before it knows the title, so such a local pseudocomment should
+ come after the "T:" line.
+
+4. Some of the command-line flags change the style parameters, eg:
+ -s 0.9 (sets symbol scale)
+ -m 2cm (sets left margin) etc.
+ Type "abc2ps -h" for a list of flags.
+
+The priorities are in the sequence given above. That is, the ".fmt"
+file overrides the predefined format, pseudocomments overide that,
+and a command-line flag overrides everything else.
+
+
+Some more details:
+
+1. Format files are searched in the current directory. In abc2ps.c,
+ the line "#define DEFAULT_FDIR .." can be used to set a default
+ directory which is searched whenever a fmt file is not local.
+ Flag -D can also be used to specify this default directory.
+ (The idea is, even if a PC user only has the executable available,
+ he could make something like an alias to get his standard
+ fmt directory into the path.)
+
+2. To see the settings for all the parameters, use flag -H.
+ When used in conjunction with other flags such as -p, -P, or -F,
+ the corresponding parameters are shown. If you redirect the
+ output to a file and edit out the header line, you immediately
+ have a prototype fmt file which specifies all the parameters.
+
+3. Dimensions can be specified either as pt, cm, or in. Default is pt.
+ So, "%%staffwidth 20" will lead to very short lines!
+
+4. Pseudocomments which are not recognized are ignored silently.
+ The idea is that other program can define their own.
+ It also means that when things frustratingly don't seem to work,
+ the reason might be a spelling mistake.
+
+5. Because ISO fonts are needed for special characters and
+ accents, all fonts must be known when the header of the PS file
+ is written. The program tries to be as clever as it can
+ about this, but a font might be undefined if it is invoked
+ for the first time further down in a file. For this reason,
+ a line like this can be put into the fmt file:
+
+ font Palatino-Bold
+
+ or alternatively at the top of the abc file:
+
+ %%font Palatino-Bold
+
+ Either of these will define the corresponding ISO font in the header.
+ To make things even easier, the program always looks for a file
+ "fonts.fmt" and loads it if it exists. So, the often-used fonts
+ can be defined there once and for all.
+
+6. The default page dimensions are set by defines in abc2ps.c
+ and then used in format.h to intialize the predefined formats.
+ Change these if the standard paper will not be Din A4.
+ The relevant lines in abc2ps.c are these:
+
+#define PAGEHEIGHT 29.7 /* basic page dimensions in cm.. */
+#define LEFTMARGIN 1.8 /* .. used in all default formats */
+#define STAFFWIDTH 17.4
+
+7. A line consisting of the word "end" in a fmt file skips the
+ rest of the file.
+
+
+----- List of format parameters -----
+
+Parameters without explanation are deemed obvious.
+
+ pageheight
+ staffwidth
+ topmargin
+ botmargin
+ leftmargin
+ topspace vertical space at the top of a tune.
+ titlespace space before the title.
+
+ Note: Usually, one sees only the sum of these two.
+ However, if text is written preceeding a tune, it
+ will come after "topspace" and before "titlespace".
+
+ subtitlespace space before the subtitle.
+ composerspace space before the composer.
+ musicspace space between the composer and the music.
+ partsspace space ("up") between the "parts" and the music.
+ vocalspace space above a line of vocals.
+ wordsspace space aboove the words at the end of a tune.
+ textspace space above the text such as history (flag -n).
+
+ Note: these spaces count to the top of a line of text.
+ That is, the relevant text size (eg. "12pt") is added.
+
+ staffsep separation between staves. One-half of this
+ distance is added above and below each staff.
+ scale symbol size; eg. 1.0 is used in the "pretty" output.
+ maxshrink how much to compress horizontally when staff breaks
+ are chosen automatically. Between 0 and 1.
+
+ titlefont Font for title, ie: Times-Roman 14
+ subtitlefont
+ composerfont
+ partsfont
+ vocalfont for vocals under a staff (w: field)
+ gchordfont for guitar chords
+ textfont for text under the tune, or between tunes
+ wordsfont for words under the tune (W: field)
+ lineskipfac dimensionless factor for spacing between lines of text:
+ 1.0 gives single-space output, 2.0 double etc.
+ parskipfac similar factor for space after a paragraph of text.
+ barsperstaff same as flag -B
+ landscape (logical) landscape orientation if true
+ titleleft (logical) title flushed left if true.
+ titlecaps (logical) title in capital letters
+ musiconly (logical) no vocals if true (equivalent to flag -M)
+ stretchstaff (logical) stretches underfull staves across page
+ stretchlast (logical) stretches last staff if underfull.
+ writehistory (logical) writes notes, history etc if true;
+ continueall (logical) continue all lines if true (same as -c).
+ breakall (logical) break at all line ends (same as -b).
+ oneperpage (logical) each tune on separate page (same as -1)
+ withxrefs (logical) print out X: xref number in title (same as -x).
+
+Logicals can be specified as follows;
+ One of: 1 yes true gives true
+ One of: 0 no false gives false.
+If nothing is specified, this is equivalent to true.
+
+
+----- Summary of tune layout -----
+
+To summarize: the layout of a tune is done as follows.
+Starting from the current position on the page,
+
+ First write the header:
+ go down by topspace, write text if any is specified;
+ go down by titlespace, write the main title;
+ for each subtitle, go down subtitlespace and write it;
+ go down composerspace, write the composer lines;
+ go down musicspace and go up by partsspace, write the parts.
+
+ Next, starting from musicspace below the composer:
+ For each staff:
+ go down by staffsep/2;
+ write the staff;
+ for vocals, go down by vocalspace and write them;
+ go down another staffsep/2.
+ Note that everything here (including the spaces and fonts)
+ are scaled by "scale".
+
+ Finally:
+ if words are included, go down wordsspace and write them;
+ if history/notes are included, go down textspace and write them.
+ Hereby lineskip and parskip given by "lineskipfac" and "parskipfac".
diff --git a/ReadMe.abc2ps b/ReadMe.abc2ps
@@ -0,0 +1,778 @@
+
+
+Description of abc2ps (version 1.2)
+===================================
+
+Program abc2ps reads an input file containing music in abc format
+and typesets it directly in PostScript. It can also be used to list
+the contents of an abc file.
+
+For a description of the abc syntax, please see the abc userguide
+which is a part of the abc2mtex package written by Chris Walshaw.
+
+
+----- Files -----
+
+ReadMe.abc2ps this file
+License GNU general public license
+Changes history of changes to the program
+New.Features description of new features in 1.2.5
+layout.txt information about the music layout
+abc2ps.c main program
+buffer.h routines to control the output buffer
+format.h routines for output formatting
+syms.h routines to define postscript macros
+subs.h general routines
+util.h more general routines
+pssubs.h routines for postscript output
+parse.h routines to parse input lines
+music.h routines to typeset music
+style.h parameters for music layout
+style.pure alternative style file for "puristic" layout
+sample.abc input for demo and test
+<others>.abc sample input files
+
+
+----- Installation -----
+
+This is a single C program, consisting of file abc2ps.c and some
+include files *.h. It can be compiled in the usual way to make
+the executable abc2ps:
+
+ cc -o abc2ps abc2ps.c
+
+To test the program, unleash it on file sample.abc like this:
+
+ ./abc2ps sample -o
+
+The result can be inspected by using a PostScript previewer such as
+ghostview on the output file Out.ps.
+
+
+Possible problems:
+
+By default, the generated PostScript is level 2 since it uses
+the operator "selectfont". If you want level 1 output instead, set
+macro PS_LEVEL to 1 in abc2ps.c.
+
+Sometimes problems arise with the "stat" function. This used at the
+end of the program to determine the size of the output file.
+The call to 'stat' is in routine get_file_size in file subs.h.
+This file also contains an alternative plodding version of
+get_file_size, which can be used if the 'stat' version causes problems.
+Alternatively, just throw out the call to get_file_size in the bottom
+of abc2ps.c and change the printf statement accordingly... printing
+out the file size is only for user information.
+
+
+----- Program structure -----
+
+The program defines a number of PostScript macros for drawing
+elementary components like note heads, stems, flags, bars,
+rests etc. These definitions are written to the output
+file Out.ps first. The symbols are mostly defined using Bezier
+curves. At some stage, the macros should probably be changed
+to user paths for more efficiency.
+
+The input lines are read and interpreted one at a time.
+The processing of the info fields is straightforward.
+
+The main work is done for lines of music. Such a line is parsed
+into a list of symbols. To position the symbols horizontally along
+the staff, the program uses a method adapted from the "glue" used
+Donald E. Knuth in the TeX program. The algorithm calculates
+three separate sets of spacings:
+
+ "shrink": put the symbols as close together as is acceptable;
+ "space": space the symbols "naturally", whereby the space
+ behind a note reflects its length;
+ "stretch": make a similar but stretched layout which still looks good.
+
+To fill the staff, the spacings are interpolated between the "shrink"
+and "space" cases (if the sum of the natural spacings is larger than
+the staff length) or between the "space" and "stretch" cases (if the
+sum of the natural spacings is too short).
+
+After the positions of all symbols are decided, lines are written to
+Out.ps to invoke the previously defined PostScript macros with
+suitable parameters.
+
+File "layout.txt" gives information on the positioning and how to
+modify the layout.
+
+
+----- Page breaking -----
+
+Page breaking: version 1.2 avoids splitting a tune over pages
+as much as possible. For each tune, the program checks whether
+the remaining space on the page is large enough to fit it in.
+If not, a page break is put in before the tune.
+
+To do this, the Postscript output is accumulated in a buffer first.
+For really large tunes, the buffer might overflow. In that case,
+the output is just written out without attempting to place the
+page breaks cleverly.
+
+
+----- Line breaking -----
+
+The best output is usually obtained if the staff breaks are
+chosen explicitly by suitable line breaks in the input file.
+In this standard usage, the program tries to set the music as well
+as possible for each line separately. The symbols '*' and '**' at
+the end of a line are ignored, as well as the field 'E:' for
+the elementary length.
+
+However, if a line is too long to fit onto one staff, the overhang
+is spilled onto the next staff in this version. This makes it possible
+to get reasonable output even when the input is one long logical line.
+In practice, this is equivalent to automatic line breaking.
+
+To control line breaking, the following flags are available:
+
+ -b break at all line ends, even if they end with the
+ continuation symbol '\'.
+
+ -c consider the input as one long line, ie., implicitly append
+ the continuation symbol '\' to every line of music.
+
+ -B n try to typeset with n bars on each line.
+
+ -a x set the maximal amount of permitted shrinking to x,
+ where x lies between 0 and 1.
+
+If none of these is specified, the standard line-by-line procedure
+is followed, ie:
+
+ abc2ps infile -o
+
+For completely automatic line breaking, use the command
+
+ abc2ps infile -c -o
+
+This should produce reasonable staff breaks in most cases. However,
+repeat bars, 1st and 2nd endings, and slurs might not be positioned
+very nicely.
+
+When doing automatic line breaking with -c, the user can control the
+spacing of the symbols along the staff by specifying the "compression
+parameter" alfa with the -a flag. A value of 0.0 means that no
+shrinking is allowed, and a value of 1.0 allows shrinking until
+the symbols are almost touching. When -c is used, by default alfa
+is set to an intermediate value (displayed with 'abc2ps -c -h').
+When -c is not used, maximal shrinking and stretching are allowed.
+
+Thus, to really squeeze everything as much as possible, that is,
+to get automatic line breaking together with maximal shrinking, use
+
+ abc2ps infile -c -o -a1
+
+For more stretched output, use (for example)
+
+ abc2ps infile -c -o -a 0.2
+
+
+The flag "-B n" formats with n bars on each line. This is useful
+e.g. to try various spacings before deciding on how to set the
+linebreaks explicitly in the file.
+
+There is not complete agreement on what output should be generated
+when a staff is underfull, which happens when maximal stretching
+is not sufficient to fill the staff. The behaviour can be determined
+by the following macros in abc2ps.c:
+
+STRETCH_MODE: allowed values are
+ 0 music for undefull staves is bunched to the left.
+ 1 music for underfull staves is left-bunched for the last staff only.
+ 2 underfull staves are spread over the whole staff.
+
+STRETCH_STAFF: allowed values are
+ 0 when music is bunched to the left, the staff is also shortened.
+ 1 staff lines are always drawn all the way across the page.
+
+
+Abc2ps 1.2 tries to take care of slurs and 1st & 2nd endings at the
+line breaks. But in general, a tune will look a substantially better
+when the breaks are chosen by hand.
+
+
+----- General usage -----
+
+Basically, the usage is:
+
+ abc2ps file1 file2..
+
+where file1, file2.. are the abc input files. This will list
+the file contents. To generate Postscript output, add flag -o:
+
+ abc2ps file1 file2.. -o
+
+Note that most flags (see below) can be used in any sequence.
+Of course, the position does matter for flags e,f,C,S,R,T since
+these determine how the following arguments are interpreted.
+
+Flags can be contracted together if the meaning is clear,
+and a numerical argument for the last flag can be appended.
+That is, '-b -s 0.7 -v 1' can be contracted to '-bs0.7 -v1'.
+
+
+----- Tune selection -----
+
+To select specific tunes from the files, use
+
+ abc2ps file1 file2.. -e selector1 selector2 ...
+
+where each selector is a set of xref numbers or a pattern. Without -o,
+this will list only the selected tunes found in the files. With -o,
+output is generated only for the selected tunes.
+
+Examples:
+
+To list all the tunes in a file, say book1 or book1.abc (whichever exists):
+ abc2ps book1
+
+To list selected tunes:
+
+ abc2ps book1 -e 1-3 5,20- 'House*' Hall
+
+This selects xref numbers 1 to 3, 5, and 20 and above,
+as well as those tunes whose title either starts with "House" or
+contains the string "Hall". A pattern without wildcards such
+as 'Hall' is treated as '*Hall*'
+
+Optionally, the search can be done on other fields using these flags
+in place of -e:
+ flag -R seaches the rhythm field
+ flag -C searches the composer field
+ flag -S searches the source field.
+ flag -T seaches the title field (default)
+
+Thus
+ abc2ps book1 -C "John"
+
+selects all tunes whose composer string contains "John".
+If the -C flag is used, the composer field is also displayed when
+the file are listed. The same goes for the flags -R and -S.
+
+Flag -A selects all tunes, overriding other selectors.
+
+
+----- Selection on multiple input files -----
+
+To filter several files with the same set of selectors, the format is:
+
+ abc2ps file1 file2 -e selectors...
+
+To use a different set of selectors for the separate files,
+use a command such as
+
+ abc2ps file1 -e 1-3 -f file2 file3 -R Jig
+
+This will select tunes 1-3 from file1 and the tunes with 'Jig' in the
+rhythm field from file2 and file3. More precisely, flag -f indicates
+that the following arguments (up to the next -e flag) are file names.
+Each set of selectors is applied to the files preceeding it.
+As before, the flags -C -S -R can be used in place of -e to change
+the searched field.
+
+For convenience, there are two conventions:
+
+ 1. An argument with the extension .abc is always assumed to be a
+ file name, and is treated as if it were preceeded by the flag -f.
+
+ 2. An argument which is obviously a set of xref numbers is assumed
+ to be a selector, and is treated as if it were preceeded by the
+ flag -e.
+
+For example, these three commands all select tunes 1-3 from A.abc
+and tunes 5-7 from B.abc:
+
+ abc2ps A.abc -e 1-3 -f B.abc -e 5-7
+
+ abc2ps A.abc -e 1-3 B.abc -e 5-7
+
+ abc2ps A.abc 1-3 B.abc 5-7
+
+On the other hand, this will NOT work in the expected way:
+
+ abc2ps A 1-3 B 5-7 -o
+
+because the program has no way of knowing that B is an input
+file name and not a pattern selector.
+
+For complicated selections on multiple input files, it might be
+better to run the program interactively (see below).
+
+
+----- Making Postscript output -----
+
+By adding flag '-o', the selected tunes are typeset and written
+to the output file. To typeset all tunes in file "book1.abc":
+
+ abc2ps book1 -o
+
+To typeset selected tunes, use a command such as
+
+ abc2ps book1 -e 1-3 5,20- 'House*' Hall -o
+
+The idea is to vary the numbers and/or patterns until the desired
+titles are listed, then add -o to the argument list to make the
+output file.
+
+By default, all selected tunes are written into the same file,
+with suitable page breaks added. By using the flag -E, EPSF output
+is made. Each tune is then put into a separate file with a correct
+bounding box and no page breaks.
+
+Flag -O determines where the output goes. The argument to -O can be
+either a file name or the '=' sign. The latter case tells abc2ps
+to choose the name by itself.
+
+For the PS and EPS modes, the output file names are:
+
+PS mode:
+ default Out.ps
+ -O NAME NAME.ps
+ -O = Output for "foo.abc" is written to "foo.ps"
+
+EPSF:
+ default Outnnn.eps, where nnn is a running index
+ -O NAME NAMEnnn.eps
+ -O = Outfile name is <tune_title>.eps
+
+Note: an output file is overwritten if it already exists.
+This will happen if two tunes have the same name and flag "-O ="
+is used for EPSF output.
+
+
+----- Modifying the output -----
+
+These flags change the output appearance:
+
+ -x includes the xref numbers in the tune title.
+
+ -1 writes every tune on a separate page.
+
+ -n includes historical notes and other stuff at the bottom
+ of each tune.
+
+ -p generates pretty output, with more whitespace between tunes,
+ larger fonts for titles, and larger music symbols. By default,
+ the layout squeezes the tunes to reduce the number of pages.
+
+ -s xxx scales the music output by factor xxx.
+
+ -w www sets the width of the staff to www points.
+
+ -m mmm sets the left margin to mmm points.
+
+ -g shrink|space|stretch|fill sets the "glue mode".
+ The default mode is fill, which fills the staff.
+ This flag is useful when changing the layout parameters,
+ to see what effect the changes have for each mode separately.
+
+ -B n format with n bars on every staff
+
+ -b forces a staff break at the end of each line, even if
+ the line has the continuation symbol \ at the end.
+
+ -c append the continuation symbol to all music lines,
+ which amounts to automatic line breaking.
+
+ -a x set the maximal allowed shrinkage to x, where x lies
+ between 0.0 and 1.0
+
+
+----- On-line help -----
+
+Flags for on-line help:
+
+ -h quick help, equivalent to "abc2ps" without any arguments.
+ This also shows the default settings for some parameters.
+
+ -v n sets the verbosity for output to the screen to n.
+ Hereby -v0 gives very little, -v1,v2,v3.. show successively
+ more information. Verbosity >= 10 is for debugging.
+
+ -V shows the version number.
+
+
+----- Interactive mode -----
+
+If the command list contains the flag -i, abc2ps runs in
+interactive mode. This makes it possible to build up an output
+file piece by piece. The disadvantage is that you have to start
+over if you make a mistake.
+
+Interactive mode is started with
+
+ abc2ps -i
+
+The program then prompts for input with the line
+
+ select tunes:
+
+The response should be a row of arguments, which are treated
+in exactly the same way as in the non-interactive mode.
+The only difference is that the input is not first run through
+the shell, so that wildcards are not expanded and quotes are
+not removed. Consequently Jig* should be used instead of 'Jig*' etc.
+when specifying strings for selection, and filenames must be written
+out in full.
+
+To exit from interactive mode, enter 'q', 'quit' or an empty input.
+
+For example, a "session" could look like this:
+
+ abc2ps -i start abc2ps interactively
+ book1 list tunes in book1.abc
+ book1 -e 1-10 list tunes with xrefs 1-10 in book1
+ book1 -e 1-10 -o write these to Out.ps
+ book2 list tunes in book2.abc
+ book2 -e House -o write tunes with 'House' in the title
+ quit exit abc2ps
+
+
+To make things easier, there are three special characters:
+ ? shows the last input used;
+ ! at the start of line is substituted by the last files used;
+ * at the start of line is substituted by the last input.
+
+This means that the same effect as above can be obtained in
+shorter form like this:
+
+ abc2ps -i start abc2ps interactively
+ book1 list tunes
+ ! 1-10 equivalent to 'book1 1-10'
+ * -o equivalent to 'book1 1-10 -o'
+ book2 list tunes in book2.abc
+ ! -e House -o equivalent to 'book2 -e House -o'
+ q exit abc2ps
+
+Note that the -e flag is not needed in the line '* 1-10'
+because it is clear that '1-10' is a selector (see above).
+
+
+Another point is that if additional flags are used when starting
+interactively, these function as defaults for the interactive mode.
+For example, by starting the program with
+
+ abc2ps -io
+
+all selected tunes are immediately written to the output file.
+The program usage is then very similar to that of abc2mtex. Of course,
+it is not possible to list the file contents (to help choose among
+the titles) when using the program in this way.
+
+In interactive mode, flags -O -E can be used as before to redirect
+the output. When switching to another output file, the previous
+file is closed. Switching back to the same file later will overwrite
+the file.
+
+
+----- Examples -----
+
+These examples assume that wildcards '*' in the argument list
+are automatically expanded out by the operating system, as
+happens e.g. under the C shell under Unix. If not, the input files
+should be specified explicitly, that is:
+ abc2ps x1.abc x2.abc x3.abc instead of abc2ps x*.abc
+
+To list the contents of file 'mytunes.abc':
+
+ abc mytunes.abc
+
+To typeset all tunes in 'mytunes.abc':
+
+ abc mytunes.abc -o
+
+To typeset all tunes, choosing all line breaks automatically:
+
+ abc mytunes.abc -o -c
+
+To do the same, but squeeze notes together more:
+
+ abc mytunes.abc -o -c -a0.9
+
+To list the contents of all abc files in the current directory:
+
+ abc2ps *.abc
+
+To search all abc files for tunes containing 'House' in the title:
+
+ abc2ps *.abc -e House
+
+To list the contents of all abc files, showing the Rhythm field also:
+
+ abc2ps *.abc -R
+
+To search all abc files for tunes with rhythm 'jig' or 'Jig':
+
+ abc2ps *.abc -R jig Jig
+
+To do the same while avoiding cases like 'slip jig':
+
+ abc2ps *.abc -R 'jig*' 'Jig*'
+
+To output all tunes by composer 'Carolan' in all abc files:
+
+ abc2ps *.abc -C Carolan -o
+
+To output tunes 1 to 10 in A.abc and 11-20 in B.abc:
+
+ abc2ps A -e 1-10 -f B -e 11-20 -o
+or
+ abc2ps A.abc 1-10 B.abc 11-20 -o
+or
+ abc2ps A 1-10 B.abc 11-20 -o
+
+To output all tunes with the string 'House' in the title or with
+xref numbers 10-12, in all abc files whose name starts with X,
+including historical notes and xref numbers in the output,
+forcing a line break at continuation lines, with reduced size
+of the symbols, putting one tune per page:
+
+ abc2ps X*.abc -e House 10,11,12 -onx -s0.9 -b1
+
+
+----- Differences to abc2mtex ------
+
+Essentially, all features described in the abc2mtex userguide
+should work. The are a few exceptions:
+
+ - The slur denotation S was replaced by the syntax (...)
+ (see below)
+
+ - Key signatures HP and Hp probably aren't treated
+ in exactly the right way.
+
+ - There is no automatic beam checking.
+
+ - There is no way to automatically transpose music in this version.
+
+
+----- Some extra features --- -----
+
+For examples, see file sample.abc.
+
+ - Codes for decorations: including the ones defined in the
+ standard abc syntax, the following decorations are interpreted:
+ . dot, staccato
+ J slide
+ M bar (M='em-phasis')
+ H hold sign (fermata)
+ ~ gracing
+ R roll
+ u up-bow
+ v down-bow
+
+
+ - Escape sequences: embedding a string between two backslashes
+ in a music line delimits an escape sequence. In the present version,
+ these are treated as information fields. This makes it easy to
+ change key, meter, or default length within a line (see sample.abc).
+
+
+ - N-tuplets: abc2ps can handle general n-tuplet cases using the syntax
+
+ (p:q:r abcd ..
+
+ This means "put p notes into the time of q for the next r notes."
+ If q is not given, it defaults as described in the abc2mtex
+ user guide. If r is not given, it defaults to p. For example:
+
+ (3::2 = (3:2:2 ; (3 = (3:2:3
+
+ The number written over the n-plet is p. This generalized
+ syntax is compatible with the older usage. Actually, q is not used
+ at all here; it is only relevant for programs which play the music.
+
+
+ - Chords: The program accepts the +...+ notation, but it seems more
+ intuitive to use some kind of brackets to group together the notes
+ which make a chord. This program will accept square brackets:
+
+ [ace][adf]
+
+ in place of the +..+ syntax.
+ The abc notation formally permits notes with different durations
+ on the same stem: [a/bc2] and so on. This program assigns all
+ notes in a chord the duration of the first note in the bracket.
+
+ A chord with two identical notes makes a union (one head
+ with stems going both up and down), eg: [AA].
+
+
+ - Slurs and ties: in place of the syntax "SabcSd" for a slur
+ over notes abcd, this program uses the notation
+
+ (abcd)
+
+ for a slur over the notes abcd. It permits cases such as
+
+ (ab(cd)) and ((ab)cd) and (a(bc)d)
+
+ and similar slurs-below-slurs. To connect three or four notes
+ by ties (e.g., for a note held over several bars) use
+
+ (a(b)c) or by ties a-b-c
+
+ The rule is that any note alone within brackets like (b)
+ terminates a previous slur and at the same time starts a new one.
+
+ Note that the slur syntax (..) does not interfere with the (3abc
+ style for n-tuplets. If a bracket '(' is followed by a digit k,
+ it is interpreted as the start of a k-tuplet, otherwise it is the
+ start of a slur. For example, a slur is put over the last two
+ triplets in this line: (3abc ((3cde) ((3efg).
+
+ An unbalanced parenthesis ')' or '(' indicates the continuation
+ of a slur on a neighboring line. This is needed (for example)
+ in order to make automatic line breaking possible. It will also
+ lead to unexpected strange-looking additional slurs if the input
+ file contains the wrong syntax (3abc) instead of (3abc for triplets.
+
+
+ - Bars: The following symbols denote fat double bars
+ at the start or end of a piece (without repeat dots).
+ Namely: [| for thick-thin, |] for thin-thick.
+
+ For better results when using automatic line breaking, the program
+ will split up some types of bars when these are at the end of a line,
+ for example:
+ :: becomes :| together with |: on the next line
+ |: becomes | together with |: on the next line
+ :|2 becomes :| together with [2 on the next line etc.
+
+
+ - Field E: this field can be used to set some parameters from
+ within the file:
+
+ shrink set glue mode to compress
+ space set to natural glue widths
+ stretch stretched glue mode
+ fill normal mode to fill staffs
+ break ignore continuations
+ xref write xref numbers to output
+ one write one tune per page.
+ newpage start new page for next tune
+ lw ppp set local staff width to ppp points.
+
+ For example, to output a single tune in a narrower format,
+ put 'E:lw 400' into the header of this tune. If this is put
+ after the header but within the tune body, only the music is set
+ with a different width and the title is written as before.
+
+
+----- Customization -----
+
+1. First of all, the horizontal layout of the notes can be changed
+extensively. This is described in 'layout.txt'.
+
+2. Then there are a number of macros in the main program abc2ps.c
+which determine the page layout, ie:
+
+ PAGEHEIGHT height of paper
+ PAGEWIDTH width of paper
+
+The following block determines the layout in the "pretty" mode (-p).
+The numbers are various font sizes, skips between tunes etc.,
+the seperation between staffs, and page margins. A similar
+block (MAINTITLE2 ...) defines the normal, more compact mode.
+
+ MAINTITLE1 18
+ SUBTITLE1 15
+ SUBSUBTITLE1 12
+ ASKIP1 0.6 * CM
+ BSKIP1 0.6 * CM
+ CSKIP1 1.2 * CM
+ DSKIP1 0.5 * CM
+ TOP_SEP1 25
+ BOT_SEP1 25
+ LSCALE1 0.8
+ LMARGIN1 1.5 * CM
+ RMARGIN1 2.0 * CM
+ TMARGIN1 2.0 * CM
+ BMARGIN1 1.0 * CM
+
+For example, the default staff width is calculated from these
+parameters as PAGEWIDTH-LMARGIN-RMARGIN. The flags -w and -m change
+this width and the left margin, respectively.
+
+
+3. The behavior for underfull lines can be chosen (see "Line breaks").
+ Also consider these two parameters:
+
+ ALFA_C default compression when using the -c flag.
+ BETA_X maximal expansion allowed before considering a staff
+ underfull.
+
+Thus, setting BETA_X to 100.0 lets lines be stretched to any
+arbitrary amount quietly.
+
+
+4. Parameters which influence the musical symbols (all dimensions
+are in pt, relative to a fundamental spacing between staff lines of 6pt):
+
+ DECO_IS_ROLL How gracings ~ are interpreted. For 0, draws a trill sign.
+ For 1, draws a roll sign (cap) over the note.
+ LSCALE0 Overall scale factor. The "internal" height for the
+ staff is 24 pt, that is, 6 pt between the lines. This
+ is rather big, so LSCALE0 scales the size down.
+ BASEWIDTH Width of lines within music (bars, stems etc).
+ SLURWIDTH Width of Bezier curves when drawing slurs.
+ STEM_YOFF Offset of stem from note head center, y direction
+ STEM_XOFF Offset of stem from note head center, x direction
+ STEM Standard stem length for single notes.
+ STEM_MIN Minimal stem length when drawing beams.
+ STEM_CH Standard stem length for chords.
+ STEM_CH_MIN Minimal stem length for chords under beams.
+ BEAM_DEPTH Width of the horizontal stroke for beams.
+ BEAM_SHIFT How far the second, third beams are shifted up or down.
+ BEAM_FLATFAC Long beams are drawn with slope reduced by this factor.
+ BEAM_THRESH If the slope of a beam lies below this threshold,
+ it is drawn with slope zero.
+ MAX_SLOPE Upper limit for the slope of a beam.
+ DOTSHIFT Extra shift, to avoid putting the dot into the flag
+ on some notes.
+ GSTEM Grace note stem length.
+ GSTEM_XOFF Offset of grace note stem to head center.
+ GSPACE0 Space between grace note and main note.
+ GSPACE Space between grace notes.
+
+
+
+----- Summary of differences to version 1.1 -----
+
+ - better page breaking
+
+ - automatic line breaking possible
+
+ - EPSF output possible
+
+ - Slurs improved; slurs to previous/next staff allowed.
+
+ - New decorations: fermata, bar, up/down bow, roll sign, slide
+
+ - unions as [aa]
+
+ - thick-thin and thin-thick bars now [| and |]
+
+ - normal or pretty output, depending on flag -p
+
+ - horizontal beams positioned more cleverly
+
+ - n-plets can contain rests, eg. (3zab or (3azb;
+ uses brackets if the notes are not all on one beam.
+
+ - general n-plet syntax (p:q:r added
+
+
+---- Feedback -------
+
+Any suggestions for improvement or bug reports are welcome.
+
+Michael Methfessel ([email protected]), June 1996.
+
+
+
diff --git a/abc2ps.c b/abc2ps.c
@@ -0,0 +1,753 @@
+/*
+ * abc2ps: a program to typeset tunes written in abc format using PostScript
+ * Copyright (C) 1996,1997,1998 Michael Methfessel
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * The author can be contacted as follows:
+ *
+ * Michael Methfessel
+ * [email protected]
+ * Institute for Semiconductor Physics, PO Box 409,
+ * D-15204 Frankfurt (Oder), Germany
+ */
+
+/* Main program abc2ps.c */
+
+#include <stdio.h>
+#include <math.h>
+#include <time.h>
+#include <string.h>
+
+/* -------------- general macros ------------- */
+
+#define VERSION "1.3" /* version */
+#define REVISION "3" /* revison */
+#define VDATE "Mar 17 1999" /* version date */
+#define VERBOSE0 2 /* default verbosity */
+#define DEBUG_LV 0 /* debug output level */
+#define OUTPUTFILE "Out.ps" /* standard output file */
+#define INDEXFILE "Ind.ps" /* output file for index */
+#define PS_LEVEL 2 /* PS laguage level: must be 1 or 2 */
+
+/* default directory to search for format files */
+#define DEFAULT_FDIR ""
+
+
+#define PAGEHEIGHT 29.7 /* basic page dimensions in cm .. */
+#define LEFTMARGIN 1.8 /* .. used in all default formats */
+#define STAFFWIDTH 17.4
+
+
+/* ----- macros controlling music typesetting ----- */
+
+#define BASEWIDTH 0.8 /* width for lines drawn within music */
+#define SLURWIDTH 0.8 /* width for lines for slurs */
+#define STEM_YOFF 1.0 /* offset stem from note center */
+#define STEM_XOFF 3.5
+#define STEM 20 /* standard stem length */
+#define STEM_MIN 16 /* min stem length under beams */
+#define STEM_MIN2 12 /* ... for notes with two beams */
+#define STEM_MIN3 10 /* ... for notes with three beams */
+#define STEM_MIN4 10 /* ... for notes with four beams */
+#define STEM_CH 16 /* standard stem length for chord */
+#define STEM_CH_MIN 12 /* min stem length for chords under beams */
+#define STEM_CH_MIN2 8 /* ... for notes with two beams */
+#define STEM_CH_MIN3 7 /* ... for notes with three beams */
+#define STEM_CH_MIN4 7 /* ... for notes with four beams */
+#define BEAM_DEPTH 2.6 /* width of a beam stroke */
+#define BEAM_OFFSET 0.25 /* pos of flat beam relative to staff line */
+#define BEAM_SHIFT 5.3 /* shift of second and third beams */
+/* To align the 4th beam as the 1st: shift=6-(depth-2*offset)/3 */
+#define BEAM_FLATFAC 0.6 /* factor to decrease slope of long beams */
+#define BEAM_THRESH 0.06 /* flat beam if slope below this threshold */
+#define BEAM_SLOPE 0.5 /* max slope of a beam */
+#define BEAM_STUB 6.0 /* length of stub for flag under beam */
+#define SLUR_SLOPE 1.0 /* max slope of a slur */
+#define DOTSHIFT 5 /* shift dot when up flag on note */
+#define GSTEM 10.0 /* grace note stem length */
+#define GSTEM_XOFF 2.0 /* x offset for grace note stem */
+#define GSPACE0 10.0 /* space from grace note to big note */
+#define GSPACE 7.0 /* space between grace notes */
+#define DECO_IS_ROLL 0 /* ~ makes roll if 1, otherwise twiddle */
+#define WIDTH_MIN 1.0 /* minimal left,right width for xp list */
+#define RANFAC 0.05 /* max random shift = RANFAC * spacing */
+#define RANCUT 1.50 /* cutoff for random shift */
+#define BNUMHT 32.0 /* height for bar numbers */
+
+#define BETA_C 0.1 /* max expansion for flag -c */
+#define ALFA_X 1.0 /* max compression before complaining */
+#define BETA_X 1.2 /* max expansion before complaining */
+
+#define VOCPRE 0.4 /* portion of vocals word before note */
+#define GCHPRE 0.4 /* portion of guitar chord before note */
+
+#define DEFVOICE "1" /* default name for first voice */
+
+
+/* ----- macros for program internals ----- */
+
+#define CM 28.35 /* factor to transform cm to pt */
+#define PT 1.00 /* factor to transform pt to pt */
+#define IN 72.00 /* factor to transform inch to pt */
+
+#define STRL 301 /* string length in info fields */
+#define STRL1 101 /* string length for file names */
+#define MAXSYMST 11 /* max symbols in start piece */
+#define MAXHD 10 /* max heads on one stem */
+#define NTEXT 100 /* max history lines for output */
+#define MAXINF 100 /* max number of input files */
+#define BSIZE 4001 /* buffer size for one input string */
+#define BUFFSZ 40000 /* size of output buffer */
+#define BUFFSZ1 3000 /* buffer reserved for one staff */
+#define BUFFLN 100 /* max number of lines in output buffer */
+#define NWPOOL 4000 /* char pool for vocals */
+#define NWLINE 5 /* max number of vocal lines per staff */
+
+#define BASE 192 /* base for durations */
+#define WHOLE 192 /* whole note */
+#define HALF 96 /* half note */
+#define QUARTER 48 /* quarter note */
+#define EIGHTH 24 /* 1/8 note */
+#define SIXTEENTH 12 /* 1/16 note */
+#define THIRTYSECOND 6 /* 1/32 note */
+#define SIXTYFOURTH 3 /* 1/64 note */
+
+#define COMMENT 1 /* types of lines scanned */
+#define MUSIC 2
+#define E_O_F 4
+#define INFO 5
+#define TITLE 6
+#define METER 7
+#define PARTS 8
+#define KEY 9
+#define XREF 10
+#define DLEN 11
+#define HISTORY 12
+#define BLANK 13
+#define WORDS 14
+#define MWORDS 15
+#define PSCOMMENT 16
+#define TEMPO 17
+#define VOICE 18
+
+#define INVISIBLE 1 /* valid symbol types */
+#define NOTE 2
+#define REST 3
+#define BAR 4
+#define CLEF 5
+#define TIMESIG 6
+#define KEYSIG 7
+#define GCHORD 8
+
+#define SPACE 101 /* additional parsable things */
+#define E_O_L 102
+#define ESCSEQ 103
+#define CONTINUE 104
+#define NEWLINE 105
+#define DUMMY 106
+
+
+#define B_SNGL 1 /* codes for different types of bars */
+#define B_DBL 2 /* || thin double bar */
+#define B_LREP 3 /* |: left repeat bar */
+#define B_RREP 4 /* :| right repeat bar */
+#define B_DREP 5 /* :: double repeat bar */
+#define B_FAT1 6 /* [| thick at section start */
+#define B_FAT2 7 /* |] thick at section end */
+#define B_INVIS 8 /* invisible; for endings without bars */
+
+#define A_SH 1 /* codes for accidentals */
+#define A_NT 2
+#define A_FT 3
+#define A_DS 4
+#define A_DF 5
+
+
+#define D_GRACE 1 /* codes for decoration */
+#define D_STACC 2
+#define D_SLIDE 3
+#define D_EMBAR 4
+#define D_HOLD 5
+#define D_UPBOW 6
+#define D_DOWNBOW 7
+#define D_ROLL 8
+#define D_TRILL 9
+#define D_HAT 10
+#define D_ATT 11
+
+#define H_FULL 1 /* types of heads */
+#define H_EMPTY 2
+#define H_OVAL 3
+
+#define TREBLE 1 /* types of clefs */
+#define BASS 2
+#define ALTO 3
+
+#define G_FILL 1 /* modes for glue */
+#define G_SHRINK 2
+#define G_SPACE 3
+#define G_STRETCH 4
+
+#define S_TITLE 1 /* where to do pattern matching */
+#define S_RHYTHM 2
+#define S_COMPOSER 3
+#define S_SOURCE 4
+
+#define TEXT_H 1 /* type of a text line */
+#define TEXT_W 2
+#define TEXT_Z 3
+#define TEXT_N 4
+#define TEXT_D 5
+
+#define DO_INDEX 1 /* what program does */
+#define DO_OUTPUT 2
+
+#define SWFAC 0.50 /* factor to estimate width of string */
+
+#define DB_SW 0 /* debug switch */
+
+#define MAXFORMATS 10 /* max number of defined page formats */
+#define STRLFMT 81 /* string length in FORMAT struct */
+
+
+#define MAXNTEXT 400 /* for text output */
+#define MAXWLEN 51
+#define ALIGN 1
+#define RAGGED 2
+#define OBEYLINES 3
+#define OBEYCENTER 4
+#define SKIP 5
+
+#define E_CLOSED 1
+#define E_OPEN 2
+
+
+
+/* ----- global variables ------- */
+
+int db=DEBUG_LV; /* debug control */
+
+int maxSyms,maxVc; /* for malloc */
+
+
+#define NCOMP 5 /* max number of composer lines */
+
+struct ISTRUCT { /* information fields */
+ char area [STRL];
+ char book [STRL];
+ char comp [NCOMP][STRL];
+ int ncomp;
+ char disc [STRL];
+ char eskip [STRL];
+ char group [STRL];
+ char hist [STRL];
+ char info [STRL];
+ char key [STRL];
+ char len [STRL];
+ char meter [STRL];
+ char notes [STRL];
+ char orig [STRL];
+ char rhyth [STRL];
+ char src [STRL];
+ char title [STRL];
+ char title2 [STRL];
+ char title3 [STRL];
+ char parts [STRL];
+ char xref [STRL];
+ char trans [STRL];
+ char tempo [STRL];
+} info,default_info;
+
+struct GRACE { /* describes grace notes */
+ int n; /* number of grace notes */
+ int p[30]; /* pitches */
+ int a[30]; /* accidentals */
+};
+
+struct DECO { /* describes decorations */
+ int n; /* number of grace notes */
+ float top; /* max height needed */
+ int t[10]; /* type of deco */
+};
+
+struct SYMBOL { /* struct for a drawable symbol */
+ int type; /* type of symbol */
+ int pits[MAXHD]; /* pitches for notes */
+ int lens[MAXHD]; /* note lengths as multiple of BASE */
+ int accs[MAXHD]; /* code for accidentals */
+ int sl1 [MAXHD]; /* which slur start on this head */
+ int sl2 [MAXHD]; /* which slur ends on this head */
+ int ti1 [MAXHD]; /* flag to start tie here */
+ int ti2 [MAXHD]; /* flag to end tie here */
+ float shhd[MAXHD]; /* horizontal shift for heads */
+ float shac[MAXHD]; /* horizontal shift for accidentals */
+ int npitch; /* number of note heads */
+ int len; /* basic note length */
+ int fullmes; /* flag for full-measure rests */
+ int word_st; /* 1 if word starts here */
+ int word_end; /* 1 if word ends here */
+ int slur_st; /* how many slurs starts here */
+ int slur_end; /* how many slurs ends here */
+ int yadd; /* shift for treble/bass etc clefs */
+ float x,y; /* position */
+ int ymn,ymx,yav; /* min,mav,avg note head height */
+ float ylo,yhi; /* bounds for this object */
+ float xmn,xmx; /* min,max h-pos of a head rel to top */
+ int stem; /* 0,1,-1 for no stem, up, down */
+ int flags; /* number of flags or bars */
+ int dots; /* number of dots */
+ int head; /* type of head */
+ int eoln; /* flag for last symbol in line */
+ struct GRACE gr; /* grace notes */
+ struct DECO dc; /* grace notes */
+ float xs,ys; /* position of stem end */
+ int u,v,w,t,q; /* auxillary information */
+ int invis; /* mark note as invisible */
+ float wl,wr; /* left,right min width */
+ float pl,pr; /* left,right preferred width */
+ float xl,xr; /* left,right expanded width */
+ int p_plet,q_plet,r_plet; /* data for n-plets */
+ float gchy; /* height of guitar chord */
+ char text[41]; /* for guitar chords etc. */
+ char *wordp[NWLINE]; /* pointers to wpool for vocals */
+ int p; /* pointer to entry in posit table */
+ float time; /* time for symbol start */
+} ;
+
+
+char lvoiceid[233]; /* string from last V: line */
+int nvoice,mvoice; /* number of voices defd, nonempty */
+int ivc; /* current voice */
+int ivc0; /* top nonempty voice */
+
+
+struct XPOS { /* struct for a horizontal position */
+ int type; /* type of symbols here */
+ int next,prec; /* pointers for linked list */
+ int eoln; /* flag for line break */
+ int *p; /* pointers to associated syms */
+ float time,dur; /* start time, duration */
+ float wl,wr; /* right and left widths */
+ float space,shrink,stretch; /* glue before this position */
+ float tfac; /* factor to tune spacings */
+ float x; /* final horizontal position */
+};
+
+
+int ixpfree; /* first free element in xp array */
+
+
+struct METERSTR { /* data to specify the meter */
+ int meter1,meter2;
+ int mflag,lflag;
+ int dlen;
+ int insert;
+ char top[31];
+} default_meter;
+
+struct KEYSTR { /* data to specify the key */
+ int ktype;
+ int sf;
+ int add_pitch;
+ int root,root_acc;
+ int add_transp,add_acc[7];
+} default_key;
+
+
+struct VCESPEC { /* struct to characterize a voice */
+ char id[33]; /* identifier string, eg. a number */
+ char name[81]; /* full name of this voice */
+ char sname[81]; /* short name */
+ struct METERSTR meter,meter0,meter1; /* meter */
+ struct KEYSTR key,key0,key1; /* keysig */
+ int stems; /* +1 or -1 to force stem direction */
+ int staves,brace,bracket; /* for deco over several voices */
+ int do_gch; /* 1 to output gchords for this voice */
+ float sep; /* for space to next voice below */
+ int nsym; /* number of symbols */
+ int draw; /* flag if want to draw this voice */
+ int select; /* flag if selected for output */
+ int insert_btype,insert_num; /* to split bars over linebreaks */
+ int insert_bnum; /* same for bar number */
+ float insert_space; /* space to insert after init syms */
+ int end_slur; /* for a-b slurs */
+ char insert_text[81]; /* string over inserted barline */
+};
+
+
+ /* things to alloc: */
+struct SYMBOL *sym; /* symbol list */
+struct SYMBOL **symv; /* symbols for voices */
+struct XPOS *xp; /* shared horizontal positions */
+struct VCESPEC *voice; /* characteristics of a voice */
+struct SYMBOL **sym_st; /* symbols a staff start */
+int *nsym_st;
+
+
+int halftones; /* number of halftones to transpose by */
+
+ /* style parameters: */
+float f0p,f5p,f1p,f0x,f5x,f1x; /* mapping fct */
+float lnnp,bnnp,fnnp,lnnx,bnnx,fnnx; /* note-note spacing */
+float lbnp,bbnp,rbnp,lbnx,bbnx,rbnx; /* bar-note spacing */
+float lnbp,bnbp,rnbp,lnbx,bnbx,rnbx; /* note-bar spacing */
+
+
+char wpool[NWPOOL]; /* pool for vocal strings */
+int nwpool,nwline; /* globals to handle wpool */
+
+struct SYMBOL zsym; /* symbol containing zeros */
+
+struct BEAM { /* packages info about one beam */
+ int i1,i2;
+ float a,b;
+ float x,y,t;
+ int stem;
+};
+
+struct FONTSPEC {
+ char name [STRLFMT];
+ float size;
+ int box;
+};
+
+struct FORMAT { /* struct for page layout */
+ char name [STRLFMT];
+ float pageheight,staffwidth;
+ float topmargin,botmargin,leftmargin;
+ float topspace,wordsspace,titlespace,subtitlespace,partsspace;
+ float composerspace,musicspace,vocalspace,textspace;
+ float scale,maxshrink,lineskipfac,parskipfac,indent;
+ float staffsep,sysstaffsep,systemsep;
+ float strict1,strict2;
+ int landscape,titleleft,continueall,breakall,writehistory;
+ int stretchstaff,stretchlast,withxrefs,barsperstaff;
+ int oneperpage,titlecaps,barnums;
+ struct FONTSPEC titlefont,subtitlefont,vocalfont,textfont,tempofont;
+ struct FONTSPEC composerfont,partsfont,gchordfont,wordsfont,voicefont;
+ struct FONTSPEC barnumfont,barlabelfont,indexfont;
+};
+
+struct FORMAT sfmt; /* format after initialization */
+struct FORMAT dfmt; /* format at start of tune */
+struct FORMAT cfmt; /* current format for output */
+
+char fontnames[50][STRLFMT]; /* list of needed fonts */
+int nfontnames;
+
+char txt[MAXNTEXT][MAXWLEN]; /* for output of text */
+int ntxt;
+
+char vcselstr[101]; /* string for voice selection */
+char mbf[501]; /* mini-buffer for one line */
+char buf[BUFFSZ]; /* output buffer.. should hold one tune */
+int nbuf; /* number of bytes buffered */
+float bposy; /* current position in buffered data */
+int ln_num; /* number of lines in buffer */
+float ln_pos[BUFFLN]; /* vertical positions of buffered lines */
+int ln_buf[BUFFLN]; /* buffer location of buffered lines */
+int use_buffer; /* 1 if lines are being accumulated */
+
+char text [NTEXT][STRL]; /* pool for history, words, etc. lines */
+int text_type[NTEXT]; /* type of each text line */
+int ntext; /* number of text lines */
+char page_init[201]; /* initialization string after page break */
+int do_mode; /* control whether to do index or output */
+char escseq[81]; /* escape sequence string */
+int linenum; /* current line number in input file */
+int tunenum; /* number of current tune */
+int tnum1,tnum2;
+int numtitle; /* how many titles were read */
+int mline; /* number music lines in current tune */
+int nsym; /* number of symbols in line */
+int nsym0; /* nsym at start of parsing a line */
+int pagenum; /* current page in output file */
+int writenum; /* calls to write_buffer for each one tune */
+int xrefnum; /* xref number of current tune */
+int do_meter, do_indent; /* how to start next block */
+
+int index_pagenum; /* for index file */
+float index_posx, index_posy;
+int index_initialized;
+
+char gch[201]; /* guitar chord string */
+int bagpipe; /* switch for HP mode */
+int within_tune, within_block; /* where we are in the file */
+int do_this_tune; /* are we typesetting the current one ? */
+float posx,posy; /* overall scale, position on page */
+int barinit; /* carryover bar number between parts */
+
+char *p, *p0; /* global pointers for parsing music line */
+
+int word,slur; /* variables used for parsing... */
+int last_note,last_real_note;
+int pplet,qplet,rplet;
+int carryover; /* for interpreting > and < chars */
+int ntinext,tinext[MAXHD]; /* for chord ties */
+
+struct { /* where to draw endings */
+ float a,b; /* start and end position */
+ int num; /* number of the ending */
+ int type; /* shape: open or closed at right */
+} ending[20];
+int num_ending; /* number of endings to draw */
+int mes1,mes2; /* to count measures in an ending */
+
+int slur1[20],slur2[20]; /* needed for drawing slurs */
+int overfull; /* flag if staff overfull */
+int do_words; /* flag if staff has words under it */
+
+int vb, verbose; /* verbosity, global and within tune */
+int in_page=0;
+
+ /* switches modified by flags: */
+int gmode; /* switch for glue treatment */
+int include_xrefs; /* to include xref numbers in title */
+int one_per_page; /* new page for each tune ? */
+int pagenumbers; /* write page numbers ? */
+int write_history; /* write history and notes ? */
+int interactive; /* interactive mode ? */
+int help_me; /* need help ? */
+int select_all; /* select all tunes ? */
+int epsf; /* for EPSF postscript output */
+int choose_outname; /* 1 names outfile w. title/fnam */
+int break_continues; /* ignore continuations ? */
+int search_field0; /* default search field */
+int pretty; /* for pretty but sprawling layout */
+int bars_per_line; /* bars for auto linebreaking */
+int continue_lines; /* flag to continue all lines */
+int landscape; /* flag for landscape output */
+int barnums; /* interval for bar numbers */
+int make_index; /* write index file ? */
+float alfa_c; /* max compression allowed */
+float scalefac; /* scale factor for symbol size */
+float lmargin; /* left margin */
+float swidth; /* staff width */
+float staffsep,dstaffsep; /* staff separation */
+float strict1,strict2; /* 1stave, mstave strictness */
+char transpose[21]; /* target key for transposition */
+
+float alfa_last,beta_last; /* for last short short line.. */
+
+char in_file[MAXINF][STRL1]; /* list of input file names */
+int ninf; /* number of input file names */
+FILE *fin; /* for input file */
+
+char outf[STRL1]; /* output file name */
+char outfnam[STRL1]; /* internal file name for open/close */
+char styf[STRL1]; /* layout style file name */
+char styd[STRL1]; /* layout style directory */
+char infostr[STRL1]; /* title string in PS file */
+
+int file_open; /* for output file */
+int file_initialized; /* for output file */
+FILE *fout,*findex; /* for output file */
+int nepsf; /* counter for epsf output files */
+
+char sel_str[MAXINF][STRL1]; /* list of selector strings */
+int s_field[MAXINF]; /* type of selection for each file */
+int psel[MAXINF]; /* pointers from files to selectors */
+
+int temp_switch;
+
+
+#include "style.h" /* globals to define layout style */
+
+/* ----- include subroutine files ----- */
+void identify_note (struct SYMBOL *s, char *q);
+int parse_length ();
+
+#include "syms.h"
+#include "util.h"
+#include "pssubs.h"
+#include "buffer.h"
+#include "format.h"
+#include "subs.h"
+#include "parse.h"
+#include "music.h"
+
+/* ----- start of main ------ */
+int main(argc, argv)
+int argc;
+char *argv[];
+{
+
+ char aaa[501],bbb[501],ccc[501],ext[41];
+ char xref_str[STRL1], pat[30][STRL1];
+ char *urgv[100];
+ int isel,j,npat,search_field,urgc,retcode,rc1;
+
+ /* ----- set default options and parse arguments ----- */
+
+ maxSyms = 800;
+ maxVc = 4;
+
+ init_ops (1);
+ retcode=parse_args (argc, argv);
+ if (retcode) exit (1);
+ if (interactive || (do_mode==DO_OUTPUT))
+ printf ("This is abc2ps, version %s.%s (%s)\n", VERSION, REVISION, VDATE);
+
+ alloc_structs ();
+
+ /* ----- set the page format ----- */
+ nfontnames=0;
+ if (!set_page_format()) exit (3);
+ if (help_me==2) {
+ print_format(cfmt);
+ exit (0);
+ }
+
+ /* ----- help printout ----- */
+ if (argc<=1) help_me=1;
+ if (help_me==1) {
+ write_help ();
+ exit (0);
+ }
+
+ if ((ninf==0) && (!interactive)) rx ("No input file specified", "");
+
+ isel=psel[ninf-1];
+ search_field0=s_field[isel]; /* default for interactive mode */
+ if (epsf) cutext(outf);
+
+ /* ----- initialize ----- */
+ zero_sym();
+ pagenum=0;
+ tunenum=tnum1=tnum2=0;
+ verbose=0;
+ file_open=file_initialized=0;
+ nepsf=0;
+ bposy=0;
+ posx=cfmt.leftmargin;
+ posy=cfmt.pageheight-cfmt.topmargin;
+ writenum=99;
+
+ strcpy(page_init, "");
+ strcpy (bbb,"");
+ for (j=0;j<ninf;j++) {strcat(bbb,in_file[j]); strcat(bbb," ");}
+
+ if ((do_mode == DO_OUTPUT) && make_index) open_index_file (INDEXFILE);
+
+ /* ----- start infinite loop for interactive mode ----- */
+ for (;;) {
+
+ if (interactive) {
+ printf ("\nSelect tunes: ");
+/*| gets (aaa); |*/
+/*| fgets (aaa, sizeof(aaa), stdin); |*/
+ getline(aaa,500,stdin);
+ if (isblank(aaa)) break;
+ sscanf(aaa,"%s",ccc);
+ if (ccc[0]=='?') {
+ printf ("%s\n", bbb);
+ continue;
+ }
+ if (ccc[0]=='*') {
+ strcat (bbb,strchr(aaa,'*')+1);
+ strcpy (aaa,bbb);
+ printf ("%s\n", aaa);
+ }
+ if (ccc[0]=='!') {
+ strcpy (bbb,"");
+ for (j=0;j<ninf;j++) {
+ strcat (bbb,in_file[j]);
+ strcat (bbb," ");
+ }
+ strcat (bbb,strchr(aaa,'!')+1);
+ strcpy (aaa,bbb);
+ printf ("%s\n", aaa);
+ }
+ strcpy(bbb,aaa);
+ urgc=make_arglist (aaa, urgv);
+ if (!strcmp(urgv[1],"q")) break;
+ if (!strcmp(urgv[1],"quit")) break;
+ init_ops(0);
+ retcode=parse_args (urgc, urgv);
+ if (retcode) continue;
+ ops_into_fmt (&cfmt);
+ if (do_mode==DO_OUTPUT) {
+ rc1=set_page_format();
+ if (rc1==0) continue;
+ }
+ if (epsf) cutext(outf);
+ if (help_me==1) {
+ write_help();
+ continue;
+ }
+ if (help_me==2) {
+ print_format(cfmt);
+ continue;
+ }
+
+ }
+
+ /* ----- loop over files in list ---- */
+ if (ninf==0) printf ("++++ No input files\n");
+ for (j=0;j<ninf;j++) {
+ getext (in_file[j],ext);
+ /* skip .ps and .eps files */
+ if ((!strcmp(ext,"ps"))||(!strcmp(ext,"eps"))) continue;
+
+ if ((fin = fopen (in_file[j],"r")) == NULL) {
+ if (!strcmp(ext,"")) strext (in_file[j],in_file[j],"abc",1);
+ if ((fin = fopen (in_file[j],"r")) == NULL) {
+ printf ("++++ Cannot open input file: %s\n", in_file[j]);
+ continue;
+ }
+ }
+ isel=psel[j];
+ search_field=s_field[isel];
+ npat=rehash_selectors (sel_str[isel], xref_str, pat);
+ dfmt=sfmt;
+ strcpy(infostr, in_file[j]);
+
+ if (do_mode==DO_INDEX) {
+ printf ("%s:\n", in_file[j]);
+ do_index (fin,xref_str,npat,pat,select_all,search_field);
+ }
+
+ else {
+ if (!epsf) {
+ strext (outf, outf, "ps", 1);
+ if (choose_outname) strext (outf, in_file[j], "ps", 1);
+ open_output_file(outf,in_file[j]);
+ }
+ printf ("%s: ", in_file[j]);
+ if ((vb>=3) || interactive) printf ("\n");
+ process_file (fin,fout,xref_str,npat,pat,select_all,search_field);
+ printf ("\n");
+ }
+
+ }
+ if (!interactive) break;
+ }
+
+ if ((!interactive) && (do_mode==DO_INDEX))
+ printf ("Selected %d title%s of %d\n", tnum1, tnum1==1?"":"s", tnum2);
+
+ close_output_file ();
+
+ if ((do_mode == DO_OUTPUT) && make_index) close_index_file ();
+
+ exit (0);
+}
+
+
+
+
+
+
diff --git a/bach.abc b/bach.abc
@@ -0,0 +1,28 @@
+%%indent 1.4cm
+%%voicefont Times-Roman 28
+%%titlefont Times-Roman 18
+%%barnumfont Times-Roman 11
+
+X:1
+T: Praeludium II (WT II)
+C: J.S. Bach
+M: C
+L: 1/16
+K:Cm
+V:RH clef=treble staves=2 brace=2 name="2."
+V:LH clef=bass
+[V:RH] zGFG AFEF GEDE FDCD | E2c2F2c2 E2c2D2=B2 |
+[V:LH] c2c'2f2c'2 e2c'2d2=b2 | cgfg bfef gede fdcd |
+%
+[V:RH] CEGc Dc=B=A DGBd EdcB | EAce Fedc FBdf Gfed | ecBc dBAB cBAG Fzz2|
+[V:LH] e2c2f2d2 g2f2g2e2 | a2g2=a2f2 b2a2=b2g2 | c'a'g'a' bg'f'g' a2 z2ze…
+%
+[V:RH] dBAB cAGA BAGF Ezz2 | cAGA BGFG AFEF TA2A2 |
+[V:LH] bg'f'g' af'e'f' g2Z2 z_d'c'b | af'e'f' ge'd'e' fd'c'd' ec'bc' |
+%
+[V:RH] AGFG TA2A2 Adfe dcBA | GBeG FeFd eBAB cAGA |
+[V:LH] dgfg caga B2b2 z2 d2 | e2c2A2B2 E2e2A2e2 |
+%
+[V:RH] BGFG AFEF GEDE C2A2 | B,2G2A,2F2 G,B,EG- GFED | EGcF BEAD [B,8EG] :|
+[V:LH] G2e2F2d2 egfg afef | gede fdcd e2g2a2b2 |c'2a2b2B2 zeBG C4 :|
+
diff --git a/blue_boy_bass.abc b/blue_boy_bass.abc
@@ -0,0 +1,35 @@
+
+
+X: 1
+T: Blue Boy
+C: Barney Kessel
+C: Herzel's Bass Line
+M: 4/4
+L: 1/4
+K: C bass
+ "C"c2 c>c- | c4 | c2 c>c-|c4 | \
+ "F" f2 f>f-| f4 | "C" c2 c>c-| c4 |
+ (3"G"g/^f/g/ -g z "F"(3f/"E"e/"F"f/| -f z "F"f\
+ ^f|1 "C"cef^f|"G"gz z4\
+ :|2"C"cef^f|"G"g^gab|
+"C"c'dec|"Dm"df"Eb0"_ed|"C"cdef|"Gm7"gf"C7"ec|
+"F7"fgag|fg"Fm7"_af|"Em7b5"edc_b,|"A7"a,b,^ce|
+"Dm7"dcb,a,|"G7"g,a,b,d|"C"c>a,-"A7"a,>_b,-| "Bb"_b,>=b,-"B"b,2 |
+"C"c"C#"^c"C"=c^f,|"F"f,"F#"^f,"F"=f,b,|"C"c"C#"^c"C"=c"C#"^c|"C"cdeg|
+"F"f"F#"^f"F"=fa|"Bb"b"Eb"_e"Ab"_a_e|"Db"_d"Gb"_g"F"f"Bb"_b|"Em7b5"e_b"A7"ae|
+"Dm7"defg|"A7"aed_d|"C"c>a,-"A7"a,>d-|"Dm7"dzz2|
+ "C"c2 c>c- | c4 | c2 c>c-|c4 | \
+ "F" f2 f>f-| f4 | "C" c2 c>c-| c4 |
+ (3"G"g/^f/g/ -g z "F"(3f/"E"e/"F"f/| -f z "F"f^f| "C"cef^f|"G"gz z2 |
+ (3"G"g/^f/g/ -g z "F"(3f/"E"e/"F"f/| -f z "F"f^f| "C"cef^f|"G"gz z2 |
+ (3"G"g/^f/g/ -g z "F"(3f/"E"e/"F"f/| -f z "F"f^f| "C"c zz c|z c z THc|]
+
+L:1/4
+ \M:3/4\ (3"G"g^fg -g2 z2 |"F"(3f"E"e"F"f -f2 z2 |\M:2/4\"F"f4\
+ ^f4| \M:4/4\ "C"c2e2f2^f2|"G"g2z2 z4 |
+L:1/4
+ \M:3/4\ (3"G"g^fg -g2 |"F"(3f"E"e"F"f -f2 |\M:2/4\"F"f4\
+ ^f4| \
+M:4/4
+L:1/4
+ "C"c zz c|z c z THc|]
diff --git a/bran5.abc b/bran5.abc
@@ -0,0 +1,54 @@
+%%indent 60pt
+
+%%leftmargin 1.8cm
+%%voicefont Times-Roman 12
+%%titlefont Times-Roman 24
+%%subtitlefont Times-Roman 18
+%%composerfont Times-Roman 12
+%%staffwidth 18.0cm
+%%scale 0.65
+%%musicspace 0.5cm
+%%tempofont Times-Roman
+
+%%topspace 0
+%%titlespace 0.2cm
+%%composerspace 0
+%%musicspace 0
+
+X:1
+T: CONCERTO No. 5
+T: I
+C: Johann Sebastian Bach
+C: BWV 1050
+M: C|
+Q:"Allegro"
+L: 1/8
+K: D
+V:1 clef=treble name="Flauto traverso" sname="Fl."
+V:2 clef=treble name="Violino\\principale" sname="Vl. pr." spc=+5
+V:3 clef=treble name="Violino\\in ripieno" sname="Vl." stv=4 brk=4
+V:4 clef=alto name="Viola\\in ripieno" sname="Vla."
+V:5 clef=bass name="Violoncello" sname="Vc."
+V:6 clef=bass name="Violone" sname="Vne." spc=+5
+V:7 clef=treble name="Cembalo\\concertato" sname="C." brc=2 stv=2 spc=-5
+V:8 clef=bass
+%
+[V:1]
+ z8 | z8 | z8 |
+[V:2]
+ [L:1/16] DDFF AAdd cdcB AGFE| DDFF AAdd e2A2 z2e2|ffee ggff bbaa ccdd|
+[V:3] [L:1/16] DDFF AAdd cdcB AGFE| DDFF AAdd e2A2 z2e2|ffee ggff bbaa ccdd|
+[V:4] f2 zf edec|dAdf cdec|dad'c' d'dgf|
+[V:5] d2 zd abc'a | fefd abc'a| d'c'ba gfed|
+[V:6] d2 zd abc'a | fefd abc'a| d'c'ba gfed|
+[V:7] [D2FAd] x2 x4| x8 | x8|
+[V:8] [d2f2a2] zd abc'a| fefd abc'a| d'c'ba gfed|
+%
+[V:1] z8 | z8 | z8 |
+[V:2] GGFF BBAA CCDD A,A,GG| FEFD EEA,A, DEFG ABcA | ddcc eedd ggff bbaa|
+[V:3] GGFF BBAA CCDD A,A,GG| FEFD EEA,A, DEFG ABcA | ddcc eedd ggff bbaa|
+[V:4] eddd gfeA| AdBc d/e/f/g/ a/b/c'/a/|d'fba cdec|
+[V:5] cdGF EDCc|dBGA B/c/d/e/ f/g/a/f/ | bagf edcA|
+[V:6] cdgf edcA|dBGA B/c/d/e/ f/g/a/f/ | bagf edcA|
+[V:7] x8 | x8 | x8 |
+[V:8] cdgf edcA|dBGA B/c/d/e/ f/g/a/f/ | bagf edcA|
diff --git a/buffer.h b/buffer.h
@@ -0,0 +1,202 @@
+/*
+ * This file is part of abc2ps,
+ * Copyright (C) 1996,1997,1998 Michael Methfessel
+ * See file abc2ps.c for details.
+ */
+
+/* subroutines to handle output buffer */
+
+/* PUTn: add to buffer with n arguments */
+
+#define PUT0(f) {sprintf(mbf,f); a2b(mbf); }
+#define PUT1(f,a) {sprintf(mbf,f,a); a2b(mbf); }
+#define PUT2(f,a,b) {sprintf(mbf,f,a,b); a2b(mbf); }
+#define PUT3(f,a,b,c) {sprintf(mbf,f,a,b,c); a2b(mbf); }
+#define PUT4(f,a,b,c,d) {sprintf(mbf,f,a,b,c,d); a2b(mbf); }
+#define PUT5(f,a,b,c,d,e) {sprintf(mbf,f,a,b,c,d,e); a2b(mbf); }
+
+
+/* ----- a2b: appends string to output buffer ----- */
+void a2b (t)
+char *t;
+{
+ int l,i;
+
+ l=strlen(t);
+ /* printf ("Append %d <%s>\n", l, t); */
+
+ if (nbuf+l>BUFFSZ) {
+ printf("+++ a2b: buffer full, BUFFSZ=%d\n", BUFFSZ);
+ exit (1);
+ }
+
+ for (i=0;i<l;i++) buf[nbuf+i]=t[i];
+ nbuf += l;
+
+}
+
+
+/* ----- bskip(h): translate down by h points in output buffer ---- */
+void bskip(h)
+float h;
+{
+ if (h*h>0.0001) {
+ PUT1("0 %.2f T\n", -h)
+ bposy=bposy-h;
+ }
+}
+
+/* ----- init_pdims: initialize page dimensions ----- */
+void init_pdims ()
+{
+ if (in_page) return;
+ posx=cfmt.leftmargin;
+ posy=cfmt.pageheight-cfmt.topmargin;
+
+}
+
+/* ----- clear_buffer ------- */
+void clear_buffer ()
+{
+ nbuf = 0;
+ bposy = 0.0;
+ ln_num = 0;
+}
+
+/* ----- write_index_entry ------- */
+void write_index_entry ()
+{
+ char s[801];
+ float w,dx1,dx2;
+
+ if (!index_initialized) init_index_file ();
+
+ if (vb>=8) printf("Write index entry: %5d <%s>\n",
+ pagenum, info.title);
+
+ /* spacing determined here */
+ index_posy = index_posy-1.2*cfmt.indexfont.size;
+
+ if (index_posy-cfmt.indexfont.size < cfmt.botmargin) {
+ close_index_page (findex);
+ init_index_page (findex);
+ }
+
+ dx1 = 1.8*cfmt.indexfont.size;
+ dx2 = dx1+cfmt.indexfont.size;
+
+ tex_str (info.title,s,&w);
+ if (strlen(s)==0) strcpy (s, "No title");
+ fprintf (findex, "%.2f %.2f M (%d) lshow\n",
+ index_posx+dx1, index_posy, pagenum);
+
+ fprintf (findex, "%.2f %.2f M (%s) S\n",
+ index_posx+dx2, index_posy, s);
+
+ if (strlen(info.rhyth) || strlen(info.orig)) {
+ fprintf (findex, "( (");
+ if (strlen(info.rhyth)) fprintf (findex, "%s", info.rhyth);
+ if (strlen(info.rhyth) && strlen(info.orig))
+ fprintf (findex, ", ");
+ if (strlen(info.orig)) fprintf (findex, "%s", info.orig);
+ fprintf (findex, ")) S\n");
+ }
+
+
+ if (strlen(info.comp)) fprintf (findex, "( - %s) S\n", info.comp);
+
+ if (cfmt.withxrefs) fprintf (findex, "( [%s]) S\n", info.xref);
+
+}
+
+
+
+
+/* ----- write_buffer: write buffer contents, break at full pages ---- */
+void write_buffer (fp)
+FILE *fp;
+{
+ int i,l,b1,b2,nb;
+ float p1,dp;
+
+ if (nbuf==0) return;
+
+ writenum++;
+
+ if ((writenum==1) && make_index) write_index_entry();
+
+ nb=0;
+ for (l=0;l<ln_num;l++) {
+ b1=0;
+ p1=0;
+ if (l>0) {
+ b1=ln_buf[l-1];
+ p1=ln_pos[l-1];
+ }
+ b2=ln_buf[l];
+ dp=ln_pos[l]-p1;
+ if ((posy+dp<cfmt.botmargin) && (!epsf)) {
+ write_pagebreak (fp);
+ }
+ for (i=b1;i<b2;i++) putc(buf[i],fp);
+ posy=posy+dp;
+ nb=ln_buf[l];
+ }
+
+ if (nb<nbuf) {
+ for (i=nb;i<nbuf;i++) putc(buf[i],fp);
+ }
+
+ clear_buffer();
+ return;
+}
+
+/* ----- buffer_eob: handle completed block in buffer ------- */
+/* if the added stuff does not fit on current page, write it out
+ after page break and change buffer handling mode to pass though */
+void buffer_eob (fp)
+FILE *fp;
+{
+ int do_break;
+
+ if (ln_num>=BUFFLN)
+ rx("max number off buffer lines exceeded"," -- check BUFFLN");
+
+ ln_buf[ln_num]=nbuf;
+ ln_pos[ln_num]=bposy;
+ ln_num++;
+
+ if (!use_buffer) {
+ write_buffer (fp);
+ return;
+ }
+
+ do_break=0;
+ if (posy+bposy<cfmt.botmargin) do_break=1;
+ if (cfmt.oneperpage) do_break=1;
+
+ if (do_break && (!epsf)) {
+ if (tunenum != 1 ) write_pagebreak (fp);
+ write_buffer (fp);
+ use_buffer=0;
+ }
+
+ return;
+}
+
+/* ----- check_buffer: dump buffer if less than nb bytes avilable --- */
+void check_buffer (fp, nb)
+FILE *fp;
+int nb;
+{
+ char mm[81];
+
+ if (nbuf+nb>BUFFSZ) {
+ sprintf (mm, "BUFFSZ exceeded at line %d", ln_num);
+ wng("possibly bad page breaks, ", mm);
+ write_buffer (fp);
+ use_buffer=0;
+ }
+}
+
+
diff --git a/celloprelude.abc b/celloprelude.abc
@@ -0,0 +1,34 @@
+%%barlabelfont Times-Bold 18 box
+%%barnumberfont Times-Roman 12 box
+%%barnumbers 5
+
+X:1
+T: Prelude from the first Cello Suite
+T: (transposed)
+C: J.S. Bach
+M: 4/4
+L: 1/16
+K:D
+"A"[|] (DAf)e fAfA (DAf)e fAfA | (DBg)f gBgB (DBg)f gBgB |
+(Dcg)f gcgc (Dcg)f gcgc | (Ddf)d fdfd (Ddf)d fdfd |
+(DBf)e fdcd Bdcd FA^GF | (^Gde)d eded (^Gde)d eded |
+(cea)^g aede cede AcBA | (B,Fd)c dFdF (B,Fd)c dFdF |
+(B,^GA)B AGFE (dcB)a ^gfed | (cBA)a eace (ABc)e dcBA |
+^d(A=cB) cAdA f(AcB) cAdA | (GBe)f geBA (GBe)f ge^cB |
+^A(cAc) ecec A(cAc) ecec "B"| (dcB)d cdec dcBA GFED |
+CGAG AGAG CGAG AGAG | (DF=c)B cFcF (DFc)B cFcF |
+(DGB)A BGBG (DGB)A BGBG | (D^cg)f gcgc (Dcg)f gcgc |
+(DAf)e fdcB AGFE DCB,A, | ^G,(EBc) dBcd G,(EBc) dBcd |
+=G,(EAB) cABc =G,(EAB) cABc | G,(EAc) (e^g(a2) a)EF=G ABcd "C"|
+%second part
+(ecA)B cdef (gec)d efga | _ba^ga a=gfg gec=B AEFG |
+A,(EAc) efge (fdA)G FDEF | A,DFA defe ^g=fef fe^de |
+e=dcd dB^GF EGBd e^gag | aecB ceAc EA^GF EDCB, "D"|
+A,2 (=gf edcB A)(gfe dcBA | G)(fed cBAG F)(edc BAGF |
+F)(dcB) [cc]e[AA]e [BB]e[cc]e [dd]e[BB]e | [cc]e[AA]e [dd]e[BB]e [cc]e[AA]e [d…
+[cc]e[AA]e [BB]e[cc]e [dd]e[ee]e [ff]e[AA]e | [ee]e[ff]e [gg]e[AA]e [ff]e[gg]e…
+[gg]e[ff]e [gg]e[ee]e [ff]e[ee]e [ff]e[dd]e | [ee]e[dd]e [ee]e[cc]e [dd]e[cc]e…
+ceAB =cA^cA dA^dA eA=fA | ^fAgA ^gAaA ^bA=bA =c'A^c'A |
+d'(fAf) d'fd'f d'(fAf) d'fd'f | d'(eAe) d'ed'e d'(eAe) d'ed'e |
+c'(gAg) c'gc'g c'(gAg) c'gc'g | [D16Afd'] |]
+
diff --git a/desafinado.abc b/desafinado.abc
@@ -0,0 +1,21 @@
+
+X: 1 % ---- desafinado in F
+T: Desafinado
+C: A. Jobim
+C: Chorus by Stan Getz
+M: C|
+L: 1/4
+Q: "Bossa Nova"
+K: F
+z2 A<c-||"FM7"c2z2|C/D/E/F/ (3:2:2ED/ ^C//D//|"G7+11"F3-F/_D/|_D4|"Gm7" z4|"C7…
+"A07"c>_E E/DE/-|"D7b9"_E2zz/D/|"Gm7" cBA2|"A7b9"z/G/B2-B/A//G// |"D7" ^F/A/E/…
+"G7b9"z2z/D/F/G/|_A3-A/G//F//|=B,4| _AG-"Gb7"G_B,|"FM7"A, z z2|z/A,/C/E/ G F/G…
+"G7+11"G>F_D2-|_D z z2|"Gm7"z2 F/^C/D/E/|"C7" F/D/E/F/ G/A/B/=B/|"A07" d c/_E/…
+"Gm7"c/Bc B/A/G/|"Eb9"B A/B/-B A/G//F//|"Dm7"A/GA G/F/E/|"B07"G/FG/-"E7"G>F|"A…
+"G"z{G,D}E/D/ =B,/A,/B,/G,/-|"FM7" G,/A,/C/E/ "E7"GF/E/-|"AM7"E2z z/^C/|"Bbdim…
+"AM7"^G^F/E/ F<G|"Am7"=B/AE/ =C/DE/-|"Bm7"E2z/CE/|"E7"G/E/G E2|"CM7"zz/ G,/ C/…
+"Dm7"G4 |"G7" E/D/^C/D/-D2|"Gm7"z2 (3D/_E/D/ ^C/D/|"A07"B=D"D7b9"^C/D/B|"Gm7"(…
+"FM7"(3C/D/C/ =B,/C/G2-|G>F G/F/z/G/-|"G7+11"G F/_D/-_D2|z2z/AG/|"Gm7"A>G A/GA…
+"A07"d/^c=c/-c>=B|"D7b9"_B2_E D/c/-|"Gm7"c2-c/BA//G//|"Bbm"Mc/B/A/G/ MB/A/G/F/…
+"G7"F4|=B,2F2-|"Bbm7"F3z/F/|"Eb9"cB_A/F/G/F/|"G7"=AF/D/=B,A|"C7"F/D/C/=B,/ _B,…
+"F"G/FF/-F2||"Eb"z2z/_E/E/E/|"F"F4|"Eb"z2z/_E/E/E/|"F"F//C//_E/-E3|"Eb"z2z/_E/…
diff --git a/fbook.fmt b/fbook.fmt
@@ -0,0 +1,26 @@
+
+% Emulates the Jazz Fakebook style.
+% Use caps for title, parts or Q: for tempo.
+
+ scale 0.70
+ topmargin 1.5cm
+ titlefont Helvetica-Bold 13
+ subtitlefont Helvetica-Bold 10
+ titleleft false
+ titlecaps
+ composerfont Helvetica 9
+ composerspace 0.3cm
+ partsfont Times-Bold 10
+ vocalfont Times-Bold 13
+ musicspace 0.7cm
+ gchordfont Times-Roman 12
+ parskipfac 1.0
+ leftmargin 1.3cm
+ staffwidth 18.4cm
+ staffsep 45
+ maxshrink 0.65
+
+ lineskipfac 1.1
+ parskipfac 0
+ textspace 0.2cm
+ textfont Times-Roman 10
diff --git a/fonts.fmt b/fonts.fmt
@@ -0,0 +1,5 @@
+
+font AvantGarde-Demi
+font Palatino-Bold
+font Bookman-Demi
+font Helvetica
diff --git a/format.h b/format.h
@@ -0,0 +1,489 @@
+/*
+ * This file is part of abc2ps,
+ * Copyright (C) 1996,1997,1998 Michael Methfessel
+ * See file abc2ps.c for details.
+ */
+
+/* subroutines connected with page layout */
+
+
+/* ----- fontspec ----- */
+void fontspec (f,name,size,box)
+char name [];
+float size;
+int box;
+struct FONTSPEC *f;
+{
+ strcpy (f->name, name);
+ f->size = size;
+ f->box = box;
+}
+
+/* ----- add_font ----- */
+/* checks font list, adds font if new */
+int add_font (f)
+struct FONTSPEC *f;
+{
+ int i,i0,fnum;
+
+ i0=-1;
+ for (i=0;i<nfontnames;i++) {
+ if (!strcmp(f->name,fontnames[i])) i0=i;
+ }
+
+ if (i0>=0) {
+ fnum=i0;
+ if (vb>=10) printf("Already at %d: font %s\n",fnum,f->name);
+ }
+ else {
+ fnum=nfontnames;
+ strcpy(fontnames[fnum],f->name);
+ if (vb>=10) printf("Add new at %d: font %s\n",fnum,f->name);
+ nfontnames++;
+ }
+ return fnum;
+}
+
+
+/* ----- make_font_list ----- */
+void make_font_list (f)
+struct FORMAT *f;
+{
+ if (vb>=10) printf ("Adding fonts from format..\n");
+ add_font (&f->titlefont);
+ add_font (&f->subtitlefont);
+ add_font (&f->composerfont);
+ add_font (&f->partsfont);
+ add_font (&f->tempofont);
+ add_font (&f->vocalfont);
+ add_font (&f->textfont);
+ add_font (&f->wordsfont);
+ add_font (&f->gchordfont);
+ add_font (&f->voicefont);
+ add_font (&f->barnumfont);
+ add_font (&f->barlabelfont);
+}
+
+
+/* ----- set_standard_format ----- */
+void set_standard_format (f)
+struct FORMAT *f;
+{
+ strcpy (f->name, "standard");
+ f->pageheight = PAGEHEIGHT * CM;
+ f->staffwidth = STAFFWIDTH * CM;
+ f->leftmargin = LEFTMARGIN * CM;
+ f->topmargin = 1.0 * CM;
+ f->botmargin = 1.0 * CM;
+ f->topspace = 0.8 * CM;
+ f->titlespace = 0.2 * CM;
+ f->subtitlespace = 0.1 * CM;
+ f->composerspace = 0.2 * CM;
+ f->musicspace = 0.2 * CM;
+ f->partsspace = 0.3 * CM;
+ f->staffsep = 46.0 * PT;
+ f->sysstaffsep = 40.0 * PT;
+ f->systemsep = 55.0 * PT;
+ f->vocalspace = 23.0 * PT;
+ f->textspace = 0.5 * CM;
+ f->wordsspace = 0.0 * CM;
+ f->scale = 0.70;
+ f->maxshrink = 0.65;
+ f->landscape = 0;
+ f->titleleft = 0;
+ f->stretchstaff = 1;
+ f->stretchlast = 0;
+ f->continueall = 0;
+ f->breakall = 0;
+ f->writehistory = 0;
+ f->withxrefs = 0;
+ f->oneperpage = 0;
+ f->titlecaps = 0;
+ f->barsperstaff = 0;
+ f->barnums = -1;
+ f->lineskipfac = 1.1;
+ f->parskipfac = 0.4;
+ f->strict1 = 0.5;
+ f->strict2 = 0.8;
+ f->indent = 0.0;
+ fontspec (&f->titlefont, "Times-Roman", 15.0, 0);
+ fontspec (&f->subtitlefont, "Times-Roman", 12.0, 0);
+ fontspec (&f->composerfont, "Times-Italic", 11.0, 0);
+ fontspec (&f->partsfont, "Times-Roman", 11.0, 0);
+ fontspec (&f->tempofont, "Times-Bold", 10.0, 0);
+ fontspec (&f->vocalfont, "Times-Bold", 13.0, 0);
+ fontspec (&f->textfont, "Times-Roman", 12.0, 0);
+ fontspec (&f->wordsfont, "Times-Roman", 12.0, 0);
+ fontspec (&f->gchordfont, "Helvetica", 12.0, 0);
+ fontspec (&f->voicefont, "Times-Roman", 12.0, 0);
+ fontspec (&f->barnumfont, "Times-Italic", 12.0, 0);
+ fontspec (&f->barlabelfont, "Times-Bold", 18.0, 0);
+ fontspec (&f->indexfont, "Times-Roman", 11.0, 0);
+ if (vb>=10) printf ("Loading format \"%s\"\n",f->name);
+}
+
+/* ----- set_pretty_format ----- */
+void set_pretty_format (f)
+struct FORMAT *f;
+{
+ set_standard_format (f);
+ strcpy (f->name, "pretty");
+ f->titlespace = 0.4 * CM;
+ f->composerspace = 0.25 * CM;
+ f->musicspace = 0.25 * CM;
+ f->partsspace = 0.3 * CM;
+ f->staffsep = 50.0 * PT;
+ f->sysstaffsep = 45.0 * PT;
+ f->systemsep = 55.0 * PT;
+ f->scale = 0.75;
+ f->maxshrink = 0.55;
+ f->parskipfac = 0.1;
+ fontspec (&f->titlefont, "Times-Roman", 18.0, 0);
+ fontspec (&f->subtitlefont, "Times-Roman", 15.0, 0);
+ fontspec (&f->composerfont, "Times-Italic", 12.0, 0);
+ fontspec (&f->partsfont, "Times-Roman", 12.0, 0);
+ fontspec (&f->tempofont, "Times-Bold", 10.0, 0);
+ fontspec (&f->vocalfont, "Times-Bold", 14.0, 0);
+ fontspec (&f->textfont, "Times-Roman", 10.0, 0);
+ fontspec (&f->wordsfont, "Times-Roman", 10.0, 0);
+ fontspec (&f->gchordfont, "Helvetica", 12.0, 0);
+ fontspec (&f->voicefont, "Times-Roman", 12.0, 0);
+}
+
+/* ----- set_pretty2_format ----- */
+void set_pretty2_format (f)
+struct FORMAT *f;
+{
+ set_standard_format (f);
+ strcpy (f->name, "pretty2");
+ f->titlespace = 0.4 * CM;
+ f->composerspace = 0.3 * CM;
+ f->musicspace = 0.25 * CM;
+ f->partsspace = 0.2 * CM;
+ f->staffsep = 55.0 * PT;
+ f->sysstaffsep = 45.0 * PT;
+ f->systemsep = 55.0 * PT;
+ f->textspace = 0.2 * CM;
+ f->scale = 0.70;
+ f->maxshrink = 0.55;
+ f->titleleft = 1;
+ f->parskipfac = 0.1;
+ fontspec (&f->titlefont, "Helvetica-Bold", 16.0, 0);
+ fontspec (&f->subtitlefont, "Helvetica-Bold", 13.0, 0);
+ fontspec (&f->composerfont, "Helvetica", 10.0, 0);
+ fontspec (&f->partsfont, "Times-Roman", 12.0, 0);
+ fontspec (&f->tempofont, "Times-Bold", 10.0, 0);
+ fontspec (&f->vocalfont, "Times-Bold", 13.0, 0);
+ fontspec (&f->textfont, "Times-Roman", 10.0, 0);
+ fontspec (&f->wordsfont, "Times-Roman", 10.0, 0);
+ fontspec (&f->gchordfont, "Helvetica", 12.0, 0);
+ fontspec (&f->voicefont, "Times-Roman", 12.0, 0);
+ fontspec (&f->barnumfont, "Times-Roman", 11.0, 1);
+ fontspec (&f->barlabelfont, "Times-Bold", 18.0, 1);
+}
+
+
+/* ----- print_font ----- */
+void print_font (str,fs)
+char *str;
+struct FONTSPEC fs;
+{
+ printf (" %-14s %s %.1f", str, fs.name, fs.size);
+ if (fs.box) printf (" box");
+ printf ("\n");
+}
+
+
+/* ----- print_format ----- */
+void print_format (f)
+struct FORMAT f;
+{
+ char yn[2][5]={"no","yes"};
+
+ printf ("\nFormat \"%s\":\n", f.name);
+ printf (" pageheight %.2fcm\n", f.pageheight/CM);
+ printf (" staffwidth %.2fcm\n", f.staffwidth/CM);
+ printf (" topmargin %.2fcm\n", f.topmargin/CM);
+ printf (" botmargin %.2fcm\n", f.botmargin/CM);
+ printf (" leftmargin %.2fcm\n", f.leftmargin/CM);
+ printf (" topspace %.2fcm\n", f.topspace/CM);
+ printf (" titlespace %.2fcm\n", f.titlespace/CM);
+ printf (" subtitlespace %.2fcm\n", f.subtitlespace/CM);
+ printf (" composerspace %.2fcm\n", f.composerspace/CM);
+ printf (" musicspace %.2fcm\n", f.musicspace/CM);
+ printf (" partsspace %.2fcm\n", f.partsspace/CM);
+ printf (" wordsspace %.2fcm\n", f.wordsspace/CM);
+ printf (" textspace %.2fcm\n", f.textspace/CM);
+ printf (" vocalspace %.1fpt\n", f.vocalspace);
+ printf (" staffsep %.1fpt\n", f.staffsep);
+ printf (" sysstaffsep %.1fpt\n", f.sysstaffsep);
+ printf (" systemsep %.1fpt\n", f.systemsep);
+ printf (" scale %.2f\n", f.scale);
+ printf (" maxshrink %.2f\n", f.maxshrink);
+ printf (" strictness1 %.2f\n", f.strict1);
+ printf (" strictness2 %.2f\n", f.strict2);
+ printf (" indent %.1fpt\n", f.indent);
+
+ print_font("titlefont", f.titlefont);
+ print_font("subtitlefont", f.subtitlefont);
+ print_font("composerfont", f.composerfont);
+ print_font("partsfont", f.partsfont);
+ print_font("tempofont", f.tempofont);
+ print_font("vocalfont", f.vocalfont);
+ print_font("gchordfont", f.gchordfont);
+ print_font("textfont", f.textfont);
+ print_font("wordsfont", f.wordsfont);
+ print_font("voicefont", f.voicefont);
+ print_font("barnumberfont",f.barnumfont);
+ print_font("barlabelfont", f.barlabelfont);
+ print_font("indexfont", f.indexfont);
+
+ printf (" lineskipfac %.1f\n", f.lineskipfac);
+ printf (" parskipfac %.1f\n", f.parskipfac);
+ printf (" barsperstaff %d\n", f.barsperstaff);
+ printf (" barnumbers %d\n", f.barnums);
+ printf (" landscape %s\n", yn[f.landscape]);
+ printf (" titleleft %s\n", yn[f.titleleft]);
+ printf (" titlecaps %s\n", yn[f.titlecaps]);
+ printf (" stretchstaff %s\n", yn[f.stretchstaff]);
+ printf (" stretchlast %s\n", yn[f.stretchlast]);
+ printf (" writehistory %s\n", yn[f.writehistory]);
+ printf (" continueall %s\n", yn[f.continueall]);
+ printf (" breakall %s\n", yn[f.breakall]);
+ printf (" oneperpage %s\n", yn[f.oneperpage]);
+ printf (" withxrefs %s\n", yn[f.withxrefs]);
+
+}
+
+
+/* ----- g_unum: read a number with a unit ----- */
+void g_unum (l,s,num)
+char *l,*s;
+float *num;
+{
+ float a,b;
+ char unit[81];
+
+ strcpy(unit,"pt");
+ sscanf(s,"%f%s", &a, unit);
+
+ if (!strcmp(unit,"cm")) b=a*CM;
+ else if (!strcmp(unit,"mm")) b=a*CM*0.1;
+ else if (!strcmp(unit,"in")) b=a*IN;
+ else if (!strcmp(unit,"pt")) b=a*PT;
+ else {
+ printf ("+++ Unknown unit \"%s\" in line: %s\n",unit,l);
+ exit (3);
+ }
+ *num = b;
+}
+
+/* ----- g_logv: read a logical variable ----- */
+void g_logv (l,s,v)
+char *l,*s;
+int *v;
+{
+ int k;
+ char t[31];
+
+ strcpy(t,"1");
+ sscanf (s,"%s", t);
+ if (!strcmp(t,"1") || !strcmp(t,"yes") || !strcmp(t,"true"))
+ k=1;
+ else if (!strcmp(t,"0") || !strcmp(t,"no") || !strcmp(t,"false"))
+ k=0;
+ else {
+ printf ("\n+++ Unknown logical value \"%s\" near \"%s\"\n",t,l);
+ exit (3);
+ }
+ *v = k;
+}
+
+
+/* ----- g_fltv: read a float variable, no units ----- */
+void g_fltv (l,nch,v)
+char *l;
+int nch;
+float *v;
+{
+ float k;
+
+ sscanf (l+nch,"%f", &k);
+ *v = k;
+}
+
+/* ----- g_intv: read an int variable, no units ----- */
+void g_intv (l,nch,v)
+char *l;
+int nch;
+int *v;
+{
+ int k;
+
+ sscanf (l+nch,"%d", &k);
+ *v = k;
+}
+
+
+
+/* ----- g_fspc: read a font specifier ----- */
+void g_fspc (l,nch,fn)
+char *l;
+int nch;
+struct FONTSPEC *fn;
+{
+ char fname[101],ssiz[101],sbox[101];
+ float fsize;
+
+ fsize=fn->size;
+ strcpy(sbox,"SnOt");
+ strcpy(ssiz,"SnOt");
+
+ sscanf (l+nch,"%s %s %s", fname, ssiz, sbox);
+ if (strcmp(fname,"*")) strcpy (fn->name, fname);
+
+ if (strcmp(ssiz,"*")) sscanf(ssiz,"%f",&fsize);
+ fn->size = fsize;
+
+ if (!strcmp(sbox,"box")) fn->box=1;
+ else if (!strcmp(sbox,"SnOt")) ;
+ else wng ("incorrect font spec: ", l+nch);
+
+ if (!file_initialized) add_font (fn);
+}
+
+
+/* ----- interpret_format_line ----- */
+/* read a line with a format directive, set in format struct f */
+int interpret_format_line (l,f)
+char l[];
+struct FORMAT *f;
+{
+ char w[81],fnm[81];
+ int nch,i,fnum;
+ char *s;
+ struct FONTSPEC tempfont;
+
+ strcpy(w,"");
+ sscanf(l,"%s%n", w, &nch);
+ if (!strcmp(w,"")) return 0;
+ if (w[0]=='%') return 0;
+ if (vb>=6) printf ("Interpret format line: %s\n", l);
+ if (!strcmp(w,"end")) return 1;
+ s=l+nch;
+
+ if (!strcmp(w,"pageheight")) g_unum(l,s,&f->pageheight);
+ else if (!strcmp(w,"staffwidth")) g_unum(l,s,&f->staffwidth);
+ else if (!strcmp(w,"topmargin")) g_unum(l,s,&f->topmargin);
+ else if (!strcmp(w,"botmargin")) g_unum(l,s,&f->botmargin);
+ else if (!strcmp(w,"leftmargin")) g_unum(l,s,&f->leftmargin);
+ else if (!strcmp(w,"topspace")) g_unum(l,s,&f->topspace);
+ else if (!strcmp(w,"wordsspace")) g_unum(l,s,&f->wordsspace);
+ else if (!strcmp(w,"titlespace")) g_unum(l,s,&f->titlespace);
+ else if (!strcmp(w,"subtitlespace")) g_unum(l,s,&f->subtitlespace);
+ else if (!strcmp(w,"composerspace")) g_unum(l,s,&f->composerspace);
+ else if (!strcmp(w,"musicspace")) g_unum(l,s,&f->musicspace);
+ else if (!strcmp(w,"partsspace")) g_unum(l,s,&f->partsspace);
+ else if (!strcmp(w,"staffsep")) g_unum(l,s,&f->staffsep);
+ else if (!strcmp(w,"sysstaffsep")) g_unum(l,s,&f->sysstaffsep);
+ else if (!strcmp(w,"systemsep")) g_unum(l,s,&f->systemsep);
+ else if (!strcmp(w,"vocalspace")) g_unum(l,s,&f->vocalspace);
+ else if (!strcmp(w,"textspace")) g_unum(l,s,&f->textspace);
+
+ else if (!strcmp(w,"scale")) g_fltv(l,nch,&f->scale);
+ else if (!strcmp(w,"maxshrink")) g_fltv(l,nch,&f->maxshrink);
+ else if (!strcmp(w,"lineskipfac")) g_fltv(l,nch,&f->lineskipfac);
+ else if (!strcmp(w,"parskipfac")) g_fltv(l,nch,&f->parskipfac);
+ else if (!strcmp(w,"barsperstaff")) g_intv(l,nch,&f->barsperstaff);
+ else if (!strcmp(w,"barnumbers")) g_intv(l,nch,&f->barnums);
+ else if (!strcmp(w,"strictness1")) g_fltv(l,nch,&f->strict1);
+ else if (!strcmp(w,"strictness2")) g_fltv(l,nch,&f->strict2);
+ else if (!strcmp(w,"strictness")) {
+ g_fltv(l,nch,&f->strict1); f->strict2=f->strict1; }
+ else if (!strcmp(w,"indent")) g_unum(l,s,&f->indent);
+
+ else if (!strcmp(w,"titleleft")) g_logv(l,s,&f->titleleft);
+ else if (!strcmp(w,"titlecaps")) g_logv(l,s,&f->titlecaps);
+ else if (!strcmp(w,"landscape")) g_logv(l,s,&f->landscape);
+ else if (!strcmp(w,"stretchstaff")) g_logv(l,s,&f->stretchstaff);
+ else if (!strcmp(w,"stretchlast")) g_logv(l,s,&f->stretchlast);
+ else if (!strcmp(w,"continueall")) g_logv(l,s,&f->continueall);
+ else if (!strcmp(w,"breakall")) g_logv(l,s,&f->breakall);
+ else if (!strcmp(w,"writehistory")) g_logv(l,s,&f->writehistory);
+ else if (!strcmp(w,"withxrefs") ) g_logv(l,s,&f->withxrefs);
+ else if (!strcmp(w,"oneperpage") ) g_logv(l,s,&f->oneperpage);
+
+ else if (!strcmp(w,"titlefont")) g_fspc(l,nch,&f->titlefont);
+ else if (!strcmp(w,"subtitlefont")) g_fspc(l,nch,&f->subtitlefont);
+ else if (!strcmp(w,"vocalfont")) g_fspc(l,nch,&f->vocalfont);
+ else if (!strcmp(w,"partsfont")) g_fspc(l,nch,&f->partsfont);
+ else if (!strcmp(w,"tempofont")) g_fspc(l,nch,&f->tempofont);
+ else if (!strcmp(w,"textfont")) g_fspc(l,nch,&f->textfont);
+ else if (!strcmp(w,"composerfont")) g_fspc(l,nch,&f->composerfont);
+ else if (!strcmp(w,"wordsfont")) g_fspc(l,nch,&f->wordsfont);
+ else if (!strcmp(w,"gchordfont")) g_fspc(l,nch,&f->gchordfont);
+ else if (!strcmp(w,"voicefont")) g_fspc(l,nch,&f->voicefont);
+ else if (!strcmp(w,"barnumberfont")) g_fspc(l,nch,&f->barnumfont);
+ else if (!strcmp(w,"barlabelfont")) g_fspc(l,nch,&f->barlabelfont);
+ else if (!strcmp(w,"indexfont")) g_fspc(l,nch,&f->indexfont);
+
+ else if (!strcmp(w,"font")) {
+ sscanf(l,"%*s %s", fnm);
+ fnum=-1;
+ for (i=0;i<nfontnames;i++) {
+ if (!strcmp(fnm,fontnames[i])) fnum=i;
+ }
+ if (fnum<0) {
+ if (file_initialized) {
+ printf ("+++ Cannot predefine when output file open: %s\n", l);
+ exit (3);
+ }
+ tempfont.size=12.0;
+ g_fspc(l,nch,&tempfont);
+ }
+ }
+
+ else {
+ if (vb>=5) printf ("Ignore format line: %s\n", l);
+ return 2;
+ }
+ return 0;
+}
+
+/* ----- read_fmt_file ----- */
+int read_fmt_file (filename,dirname,f)
+char filename [],dirname[];
+struct FORMAT *f;
+{
+ FILE *fp;
+ char line[BSIZE],fname[201];
+ int i,end;
+
+ strcpy(fname,filename);
+ if ((fp = fopen (fname,"r")) == NULL) {
+ if (strlen(dirname)==0)
+ return 0;
+ else {
+ strcpy(fname,dirname);
+ strcat(fname,"/");
+ strcat(fname,filename);
+ if ((fp = fopen (fname,"r")) == NULL) return 0;
+ }
+ }
+
+ if (vb>=4) printf ("Reading format file %s:\n", fname);
+ printf ("%s .. ", fname);
+ strcpy (line, "");
+ getline(line, BSIZE, fp);
+ for (i=0;i<200;i++) {
+ end=interpret_format_line (line,f);
+ if (end==1) return 1;
+ strcpy (line, "");
+ if (feof(fp)) return 1;
+ if (!getline(line, BSIZE, fp)) return 1 ;
+ }
+ fclose (fp);
+ return 1;
+}
+
+
diff --git a/journey.abc b/journey.abc
@@ -0,0 +1,36 @@
+%%scale 0.70
+%%titlefont Helvetica-Bold 13
+%%composerfont Helvetica 9
+%%composerspace 0.2cm
+%%gchordfont Times-Roman 13
+%%musicspace 1.1cm
+%%leftmargin 1.3cm
+%%staffwidth 18.4cm
+%%staffsep 40
+%%partsfont Times-Bold 10
+%%partsspace 0.35cm
+%musiconly
+
+X: 1
+T: SENTIMENTAL JOURNEY
+C: Words and Music by
+C: Bud Green, Les Brown, and Ben Homer
+M: C
+L: 1/4
+Q: "Easy Swing" 1/4=140
+K: C
+%text Easy Swing
+"C"z/EC/ E>C|E/>C/E/>C/ E<C|z/EC/E>F|"D7"E_E/D/-"G7"D2|
+w: Gon-na take a Sen-ti-men-tal Jour-ney, gon-na set my heart at ease._
+w: Got my bag, I got my re-ser-va-tion, spent each dime I could af-ford.
+"C"z/=EC/ E>C|"F9"_E/>C/E/>C/ E<D|"C"z/=EC/E>F|"G7"E/>_E/ D/C/-"C"C2:|
+w: Gon-na take a Sen-ti-men-tal Jour-ney, to re-new old mem -or-ries._
+w: Like a child in wild an-ti-ci-pa-tion, long to hear that "All_ a-board."
+"FM7"B/c/-c3| B/>c/B/>c/ d<c | "CM7"^F/G/-G3| ^F/>G/F/>G/ A<G|
+w:Se-ven,_ that's the time we leave, at sev-en._ I'll be wait-in' up for
+"D7"^c/d/-d3|^c/>d/c/>d/=c>A|"G7"B/GA/-"Dm7"A>F|"G7"G"C#dim7"E/F/-"G7/D G7"F2|
+w:Hea-ven,_ count-in' ev-'ry mile of rail-road track_ that takes me back._
+"C"z/EC/ E>C|E/>C/E/>C/ E<C|z/EC/E>F|"D7"E_E/D/-"G7"D2|
+w: Nev-er thought my heart could be so yeam-y. Why did I de-cide to roam?_
+"C"z/=EC/ E>C|"F9"_E/>C/E/>C/ E<D|"C"z/=EC/ E<F|"G7"E/>_E/ D/C/-"C"C2 |]
+w:Got-ta take this Sen-ti-men-tal Jour-ney, Sen-ti-men-tal Jour - ney home._
diff --git a/landscape.fmt b/landscape.fmt
@@ -0,0 +1,11 @@
+
+% format for wide output in landscape mode
+
+ pageheight 21cm
+ staffwidth 25cm
+ landscape 1
+
+ titleleft yes
+ titlefont Palatino-Bold 22
+ composerspace 0.6cm
+ staffsep 60
diff --git a/layout.txt b/layout.txt
@@ -0,0 +1,150 @@
+
+
+ How the notes are arranged on the staff in abc2ps
+ =================================================
+
+ This file contains more detailed information on the way in which
+ the layout is calculated in abc2ps, for those who are interested
+ or would like to change the layout.
+
+
+ ----- General points -----
+
+ When typesetting music, an important feature is presumably
+ that notes and rests are arranged in some way which indicates
+ the note durations. The following considerations entered
+ into abc2ps:
+
+ (a) The space assigned a note should be qualitatively proportional
+ to its durations, but this mapping should not be strictly linear.
+ It seems best to "saturate" the mapping so that whole notes
+ are somewhat less than twice as wide as half notes. At the other
+ end, the width allocated to 8th and 16th notes must be
+ more similar than a factor of 1/2 or the layout looks uneven.
+ Thus, for durations approaching zero the note width should go
+ to some constant. A modifiable function nwidth(len) defines
+ the mapping.
+
+ (b) Given a sequence of notes (or rests) within a bar, the space
+ between any two should reflect the duration of the first.
+ If this is done strictly, the distance along the staff becomes
+ the correct "time axis" but the output looks uneven.
+ Therefore there is an "asymmetry" parameter beta to adjust.
+ For beta=0, the internote spacing comes equally from both neighbor
+ notes, and for beta=1 only the first note of each pair is taken
+ into account.
+
+ (c) When notes are grouped under a beam, they are moved slightly
+ closer together.
+
+ (d) The spacing between a note at the start of a measure and the
+ preceding bar line is a separate case. On the one hand, the duration
+ of the note could influence the spacing. On the other hand,
+ music often seems to be written with this spacing some fixed standard
+ distance. The treatment here is to choose a standard space (eg. some
+ fraction of a full measure) and another tuning parameter beta. For beta=0
+ the standard distance is used, and for beta=1 the space is taken from
+ the note duration. Notes at the end of a measure are treated similarily.
+
+ (e) If a measure has only one note in it, one can put the note exactly
+ into the middle and calculate the measure width from the note duration.
+ Alternatively, this case can be treated like case (d) as a bar-note
+ and a note-bar case. A further parameter interpolates between these
+ alternatives.
+
+
+ ----- Puristic layout -----
+
+ To change the layout rules, the parameters in file "style.h" should
+ be modified. As a starting point, it is useful to consider a strict
+ layout defined as follows (see file "style.pure"):
+
+ (a) Make the mapping between note length and the space on the paper linear.
+
+ (b) Make the space between two notes exactly proportional to the length
+ of the first note.
+
+ (c) Do not move notes under beams closer together.
+
+ (d) Put notes at the start of a measure at a fixed distance behind the bar.
+ Put a bar behind a note at a spacing proportional to the note length.
+
+ (e) Treat a measure with a single note in it like case (d).
+
+ For this layout, the position of each note exactly gives the time when
+ the note starts. It looks more or less like what one wants, but it is
+ too strict for good readability. One way to get suitable layout
+ parameters is to start from the settings in "style.pure" and twiddle
+ on the parameters.
+
+
+ ----- Algorithm for filling out the staffs -----
+
+ This is similar to the procedure used by Knuth in TeX
+ as described in the TeXBook, chapter on "Glue".
+ Three different sets of spacings are defined: shrink, space, stretch.
+
+ shrink: the smallest acceptable spacings. These are controlled
+ by function set_sym_widths().
+ space: prefered "natural" spacings at which layout looks best.
+ All parameters in style.h ending in 'p' are relevant.
+ stretch: spacings for an expanded "stretched" layout.
+ All parameters in style.h ending in 'x' are relevant.
+
+ To set a line, the natural spacings are added together. If the sum is
+ larger than the desired staff length, the final spacings are obtained
+ by linear interpolation between the "shrink" and "space" values.
+ If the sum is smaller, the spacings are obtained by interpolating
+ between the "space" and "stretch" values. Compression does not go
+ beyond the "shrink" spacings but expansion is allowed to any width.
+ (Formal note: the definition of shrink and stretch used here is not
+ the same as in TeX; eg. the minimal spacing is here 'shrink'
+ whereas in TeX it is 'space-shrink'.)
+
+
+ ----- How to proceed when changing the layout -----
+
+ When changing the output appearance, the important thing is to modify
+ the three glue modes "shrink", "space", and "stretch" separately.
+ Since a typical music line is a mixture of these modes, it is
+ difficult to see what is happening when changing the parameters
+ in the "fill" mode. In detail:
+
+ (1) Use info field 'E:shrink' or the flag "-g shrink" to force
+ maximally compressed output. In this mode, no extra glue is put
+ between the symbols. The layout should be as compressed as possible
+ while still being acceptable. The spacings are here given by
+ the left and right widths wl,wr which are defined in routine
+ set_sym_widths(). These are presently set so that symbols
+ have a small space around them, taking into account dots, flags,
+ accidentals etc. Slightly more space is left around open notes and
+ fat bars.
+
+ (2) Next, use 'E:space' or "-g space" to force the prefered natural
+ spacing. This layout should be adjusted to get the ouput which looks
+ best. As in case (1), there are left and right widths for each symbol,
+ now called pl and pr, which are also set in set_sym_widths().
+ The important difference is that spacings around notes and rests
+ are influenced by the durations. This is done according
+ to the rules described above, using the parameters ending in 'p'
+ in style.h. The relevant routine is set_sym_poslist().
+
+ (3) Finally, use 'E:stretch' to force stretched output.
+ This output should be something like twice as wide but should still be
+ easily readable. For example, this implies that internote spacings are
+ more even than in the "space" mode. Internally, the stretched spacings
+ are calculated exactly as the prefered spacings, using left and right
+ widths xl and xr, function xwidth(len), and the parameters ending
+ in 'x' in style.h.
+
+ The idea is that after obtaining satisfactory layouts for the shrink,
+ space, and stretch modes separately, the output should look good
+ when the spacings are interpolated to fill out the staff.
+
+ If you change the style file to your tastes, you might as well
+ give the layout a new name, by changing the macro STYLE in style.h.
+ This is so that the command 'abc2ps -V' can show what style is
+ currently being used.
+
+
+ Michael Methfessel, Feb 1996.
diff --git a/mtunes1.abc b/mtunes1.abc
@@ -0,0 +1,55 @@
+
+X:1
+%%indent 1cm
+T: Reel in E-minor
+C: Trad.
+Z: From Fiddle Book by M. Thaut.
+M: C|
+L: 1/8
+K:EDor
+V:1 name="Mandolin" staves=1
+"Em"EB, ((3B,A,B,) (EG) FE | "D"DA, ((3A,G,A,) DE FA | ("Em"GE) ED (EF) GA |
+"Em"B2 eB ("Bm"dB) AF | ((3"Em"EDE) B,E (GE) B,E | ((3"D"DED) A,D (FD) A,D |
+((3"Bm"Bcd) "Em7"eB (dB) AF |1 ("D"DE) FA "Bm"B2 AF :|2 "D"DE FA "Em"B2 z2 ||
+|: "Em"eB ((3BAB) (eg) fe | "D"d2 fa (gf) ed | ((3"Bm"Bcd) "Em"ef (gf) ge |
+("D"fg) ((3agf) "C"gf ed | "Em"eB ((3BAB) ("D"AB) FA | "Em"BE ((3EDE) (Bd) ef|
+"C"g3a "D"f3d |1 ("Em"ef) ed ("Bm"BA) FB :|2 "Em"ef ed B2 z2 |]
+
+X: 2
+T: Carolan's Cup
+C:Trad.
+Z: From Fiddle Book by M. Thaut.
+M: 6/8
+K:D
+ (de) | f3/(g/f/e/) (df)a | ~e2 d/B/ A2 f/e/ | dcB A<FA | Bba bfe |
+ f3/(g/f/e/) (df)a | e(g/f/e/d/) c2 e | (dc)B (AF)A | B3 B2 :|
+|: c | d3/(e/d/c/) d2 f | a3/(b/a/f/) .a2 f | e3/(f/e/d/) (ef)a | (b3 b)(fa) |
+baf/e/ (de)a | ~e2 d/B/ A2 f/e/ | (dc)B (AF)A | B3 B2 :|
+
+X: 3
+T: Anroozha
+C: Persian, arr. Farid Farjad
+S: Anroozha first CD
+M: 2/4
+L: 1/8
+K:Em
+"Em"zAGF | A(G3 |G4) | zGFE | "B7"G(F3|F4) | zFE^D| "Em"F(E3| E4)|
+|:zAGF|"Am"BA2F|AG2E|("B7"F4|F4)|zGFE|"Am"AG2E|"B7"GF2^D|("Em"E4|"(fine)"E4):|
+"Em"z(g/a/) .b/.b/.a/.a/|g(b3|b4)|z(f/g/) .a/.a/.g/.g/|\
+ "Am"f(a3|a4)|"Em7"z(e/f/) .g/.g/.f/.f/|"C"e({e}g3|g4)|
+"B7"z(^d/e/) f.e/.e/|"Em"^d/(d/(e3)|e2)z2|{E}A2 G2|\
+ "Am"F3G/A/|("Em"G4|G2)z2|"C"G2F2|"B7"E3^D/F/|("Em"E4|E2)z2|
+B2A2| "G"G3A/B/|("Am7"A4|A2)z2|A2G2|"D"F3G/A/|\
+ ("C"G4|G3)F/E/|"B7"^D2E2|A2z G/F/|("Em"E4|E2)z2||
+b3b|"G"{b}e'2d'2|"Am"{d'e'}d'c' b<c'|("Em"b4|b2)z2|\
+ zb2g|"G"a2g2|"Am"ag2a|("Em"b4|b2)z2|
+zb2g|"G"a>g f2|"B7"gfe^d|("Em"e4|e2)z2|\
+ B3B|"G"{B}e2d2|"Am"{de}dc B<c|("Em"B4|B2)z2|
+zB2G|"Am7"A2G2|AG2A|("Em"B4|B2)z2|zB2G|\
+ "Am"A>GF2|"B7"GFE^D|("Em"E4|E2)z2|
+"Am"A2((3"Em"GFG)|"B"F3G/A/|("C"G4|G2)z2|"C"G2"B"F2|"Am"E3"B7"^D/F/|\
+ ("Em"E4|E2)z2|"Em"B2"D"A2|"G"GF "C6"GA/B/|("Am"A4|A2)z2|
+"D"A2"C"G2|"B"F3G/A/|("C"G4|G3)F/E/|"Em"^D2E2|"B7"A2zG/F/|("Em"E4|E2)z2|\
+ b3b| ("G"a/c'/b2)(a/b/|"Am"a2)z2|
+a3g|(a/b/a2)(g/a/|"Em"g2)z2|"C"{f}g3f|(g/a/g2)(f/g/|"B7"f3)e|\
+ ^d2e2|"Am"a2zg/f/|("Em"e4|e2)"D.C."z2||
diff --git a/music.h b/music.h
@@ -0,0 +1,4496 @@
+/*
+ * This file is part of abc2ps,
+ * Copyright (C) 1996,1997,1998 Michael Methfessel
+ * See file abc2ps.c for details.
+ */
+
+/* subroutines connected with output of music */
+
+#define XP_START 0
+#define XP_END (maxSyms-1)
+
+/* ----- nwid ----- */
+/* Sets the prefered width for a note depending on the duration.
+ Return value is default space on right and left side.
+ Function is determined by values at 0, 1/2, 1.
+ Return value is 1.0 for quarter note. */
+float nwid (dur)
+float dur;
+{
+ float a,b,x,p,x0,p0;
+
+ a=2*(f1p-2*f5p+f0p);
+ b=f1p-f0p-a;
+ x = dur/(float)BASE;
+ p = a*x*x + b*x + f0p;
+
+ x0 = 0.25;
+ p0 = a*x0*x0 + b*x0 + f0p;
+ p = p/p0;
+ return p;
+}
+
+/* ----- xwid -- --- */
+/* same as nwid but for stretched system */
+float xwid (dur)
+float dur;
+{
+ float a,b,x,p,x0,p0;
+
+ a=2*(f1x-2*f5x+f0x);
+ b=f1x-f0x-a;
+ x = dur/(float)BASE;
+ p = a*x*x + b*x + f0x;
+
+ x0 = 0.25;
+ p0 = a*x0*x0 + b*x0 + f0x;
+ p = p/p0;
+
+ return p;
+}
+
+/* ----- next_note, prec_note ------ */
+int next_note (k,n,symb)
+int k,n;
+struct SYMBOL symb[];
+{
+ int i;
+ for (i=k+1;i<n;i++) {
+ if ((symb[i].type==NOTE)||(symb[i].type==REST)) return i;
+ }
+ return -1;
+}
+
+int prec_note (k,n,symb)
+int k,n;
+struct SYMBOL symb[];
+{
+ int i;
+ for (i=k-1;i>=0;i--) {
+ if ((symb[i].type==NOTE)||(symb[i].type==REST)) return i;
+ }
+ return -1;
+}
+
+
+/* ----- followed_by_note ------ */
+int followed_by_note (k,n,symb)
+int k,n;
+struct SYMBOL symb[];
+{
+ int i;
+
+ for (i=k+1;i<n;i++) {
+ switch (symb[i].type) {
+ case INVISIBLE:
+ break;
+ case NOTE:
+ case REST:
+ return i;
+ break;
+ default:
+ return -1;
+ }
+ }
+ return -1;
+}
+
+/* ----- preceded_by_note ------ */
+int preceded_by_note (k,n,symb)
+int k,n;
+struct SYMBOL symb[];
+{
+ int i;
+
+ for (i=k-1;i>=0;i--) {
+ switch (symb[i].type) {
+ case INVISIBLE:
+ break;
+ case NOTE:
+ case REST:
+ return i;
+ break;
+ default:
+ return -1;
+ }
+ }
+ return -1;
+}
+
+
+void xch (i,j) /* sub to exchange two integers */
+int *i,*j;
+{
+ int k;
+ k=*i;
+ *i=*j;
+ *j=k;
+}
+
+
+
+/* ----- print_linetype ----------- */
+void print_linetype (t)
+int t;
+{
+
+ if (t== COMMENT) printf("COMMENT\n");
+ else if (t== MUSIC) printf("MUSIC\n");
+ else if (t== E_O_F) printf("E_O_F\n");
+ else if (t== INFO) printf("INFO\n");
+ else if (t== TITLE) printf("TITLE\n");
+ else if (t== METER) printf("METER\n");
+ else if (t== PARTS) printf("PARTS\n");
+ else if (t== KEY) printf("KEY\n");
+ else if (t== XREF) printf("XREF\n");
+ else if (t== DLEN) printf("DLEN\n");
+ else if (t== HISTORY) printf("HISTORY\n");
+ else if (t== TEMPO) printf("TEMPO\n");
+ else if (t== BLANK) printf("BLANK\n");
+ else if (t== VOICE) printf("VOICE\n");
+ else if (t== MWORDS) printf("MWORDS\n");
+ else if (t== PSCOMMENT) printf("PSCOMMENT\n");
+ else printf("UNKNOWN LINE TYPE\n");
+}
+
+/* ----- print_syms: show sym properties set by parser ------ */
+void print_syms(num1,num2,symb)
+int num1,num2;
+struct SYMBOL symb[];
+{
+ int i,t,j,y,nsh;
+ char dsym[21] = {' ','~','.','J','M','H','u','v','R','T','K'};
+ char bsym[10] = {'-', '1' ,'2', '3', '4', '5', '6', '7', '8', '9'};
+ char str[21];
+
+ printf ("\n---------- Symbol list ----------\n");
+ printf ("word slur eol num description\n");
+
+ for (i=num1;i<num2;i++) {
+ printf (" %c %c %c %c %c ",
+ bsym[symb[i].word_st], bsym[symb[i].word_end],
+ bsym[symb[i].slur_st], bsym[symb[i].slur_end],
+ bsym[symb[i].eoln] );
+ printf ("%4d ", i);
+ t=symb[i].type;
+ switch (t) {
+
+ case NOTE:
+ case REST:
+ if (t==NOTE) printf ("NOTE ");
+ if (t==REST) printf ("REST ");
+ if (symb[i].npitch>1) printf (" [");
+ for (j=0;j<symb[i].npitch;j++) {
+ printf (" ");
+ if (symb[i].accs[j]==A_SH) printf ("^");
+ if (symb[i].accs[j]==A_NT) printf ("=");
+ if (symb[i].accs[j]==A_FT) printf ("_");
+ if (symb[i].accs[j]==A_DS) printf ("^^");
+ if (symb[i].accs[j]==A_DF) printf ("__");
+ y=3*(symb[i].pits[j]-18)+symb[i].yadd;
+ strcpy (str,"z");
+ if (t==NOTE) symbolic_pitch (symb[i].pits[j],str);
+ printf ("%s(%d)", str, symb[i].lens[j]);
+ }
+ if (symb[i].npitch>1) printf (" ]");
+ if (symb[i].p_plet)
+ printf (" (%d:%d:%d", symb[i].p_plet,symb[i].q_plet,symb[i].r_plet);
+ if (strlen(symb[i].text)>0) printf (" \"%s\"", symb[i].text);
+ if (symb[i].dc.n>0) {
+ printf (" deco ");
+ for (j=0;j<symb[i].dc.n;j++)
+ printf ("%c",dsym[symb[i].dc.t[j]]);
+ }
+ if (symb[i].gr.n>0) {
+ printf (" grace ");
+ for (j=0;j<symb[i].gr.n;j++) {
+ if (j>0) printf ("-");
+ if (symb[i].gr.a[j]==A_SH) printf ("^");
+ if (symb[i].gr.a[j]==A_NT) printf ("=");
+ if (symb[i].gr.a[j]==A_FT) printf ("_");
+ symbolic_pitch (symb[i].gr.p[j],str);
+ printf ("%s",str);
+ }
+ }
+ break;
+
+ case BAR:
+ printf ("BAR ======= ");
+ if (symb[i].u==B_SNGL) printf ("single");
+ if (symb[i].u==B_DBL) printf ("double");
+ if (symb[i].u==B_LREP) printf ("left repeat");
+ if (symb[i].u==B_RREP) printf ("right repeat");
+ if (symb[i].u==B_DREP) printf ("double repeat");
+ if (symb[i].u==B_FAT1) printf ("thick-thin");
+ if (symb[i].u==B_FAT2) printf ("thin-thick");
+ if (symb[i].u==B_INVIS) printf ("invisible");
+ if (symb[i].v) printf (", ending %d", symb[i].v);
+ if (strlen(symb[i].text)>0) printf (", label \"%s\"",symb[i].text);
+ break;
+
+ case CLEF:
+ if (symb[i].u==TREBLE) printf ("CLEF treble");
+ if (symb[i].u==BASS) printf ("CLEF bass");
+ if (symb[i].u==ALTO) printf ("CLEF alto");
+ break;
+
+ case TIMESIG:
+ printf ("TIMESIG ");
+ if (symb[i].w==1) printf ("C");
+ else if (symb[i].w==2) printf ("C|");
+ else printf ("%d/%d", symb[i].u,symb[i].v);
+ break;
+
+ case KEYSIG:
+ printf ("KEYSIG ");
+ if (symb[i].t==A_SH) printf ("sharps ");
+ if (symb[i].t==A_FT) printf ("flats ");
+ printf ("%d to %d", symb[i].u,symb[i].v);
+ if (symb[i].w <= symb[i].v)
+ printf (", neutrals from %d", symb[i].w);
+ break;
+
+ case INVISIBLE:
+ printf ("INVIS ");
+ break;
+
+ default:
+ printf ("UNKNOWN ");
+ break;
+ }
+ printf ("\n");
+
+ }
+ printf ("\n");
+}
+
+/* ----- print_vsyms: print symbols for all voices ----- */
+void print_vsyms ()
+{
+ int i;
+
+ printf("\n");
+ for (i=0;i<nvoice;i++) {
+ if (nvoice>1)
+ printf ("Voice <%s> (%d of %d)", voice[i].id,i,nvoice);
+ print_syms (0,voice[i].nsym,symv[i]);
+ }
+}
+
+
+/* ----- set_head_directions ----------- */
+
+#define ABS(a) ((a)>0) ? (a) : (-a)
+
+/* decide whether to shift heads to other side of stem on chords */
+/* also position accidentals to avoid too much overlap */
+void set_head_directions (s)
+struct SYMBOL *s;
+{
+ int i,n,nx,sig,d,da,shift,nac;
+ int i1,i2,m;
+ float dx,xx,xmn;
+
+ n=s->npitch;
+ sig=-1;
+ if (s->stem>0) sig=1;
+ for (i=0;i<n;i++) {
+ s->shhd[i]=0;
+ s->shac[i]=8;
+ if (s->head==H_OVAL) s->shac[i]+=3;
+ s->xmn=0;
+ s->xmx=0;
+ }
+ if (n<2) return;
+
+ /* sort heads by pitch */
+ for (;;) {
+ nx=0;
+ for (i=1;i<n;i++) {
+ if ( (s->pits[i]-s->pits[i-1])*sig>0 ) {
+ xch (&s->pits[i],&s->pits[i-1]);
+ xch (&s->lens[i],&s->lens[i-1]);
+ xch (&s->accs[i],&s->accs[i-1]);
+ xch (&s->sl1[i],&s->sl1[i-1]);
+ xch (&s->sl2[i],&s->sl2[i-1]);
+ xch (&s->ti1[i],&s->ti1[i-1]);
+ xch (&s->ti2[i],&s->ti2[i-1]);
+ nx++;
+ }
+ }
+ if (!nx) break;
+ }
+
+ shift=0; /* shift heads */
+ for (i=n-2;i>=0;i--) {
+ d=s->pits[i+1]-s->pits[i];
+ if (d<0) d=-d;
+ if ((d>=2) || (d==0))
+ shift=0;
+ else {
+ shift=1-shift;
+ if (shift) {
+ dx=7.8;
+ if (s->head==H_EMPTY) dx=7.8;
+ if (s->head==H_OVAL) dx=10.0;
+ if (s->stem==-1) s->shhd[i]=-dx;
+ else s->shhd[i]=dx;
+ }
+ }
+ if (s->shhd[i] < s->xmn) s->xmn = s->shhd[i];
+ if (s->shhd[i] > s->xmx) s->xmx = s->shhd[i];
+ }
+
+ shift=0; /* shift accidentals */
+ i1=0; i2=n-1;
+ if (sig<0) { i1=n-1; i2=0; }
+ for (i=i1; ; i=i+sig) { /* count down in terms of pitch */
+ xmn=0; /* left-most pos of a close head */
+ nac=99; /* relative pos of next acc above */
+ for (m=0;m<n;m++) {
+ xx=s->shhd[m];
+ d=s->pits[m]-s->pits[i];
+ da=ABS(d);
+ if ((da<=5) && (s->shhd[m]<xmn)) xmn=s->shhd[m];
+ if ((d>0) && (da<nac) && s->accs[m]) nac=da;
+ }
+ s->shac[i]=8.5-xmn+s->shhd[i]; /* aligns accidentals in column */
+ if (s->head==H_EMPTY) s->shac[i] += 1.0;
+ if (s->head==H_OVAL) s->shac[i] += 3.0;
+ if (s->accs[i]) {
+ if (nac>=6) /* no overlap */
+ shift=0;
+ else if (nac>=4) { /* weak overlap */
+ if (shift==0) shift=1;
+ else shift=shift-1;
+ }
+ else { /* strong overlap */
+ if (shift==0) shift=2;
+ else if (shift==1) shift=3;
+ else if (shift==2) shift=1;
+ else if (shift==3) shift=0;
+ }
+
+ while (shift>=4) shift -=4;
+ s->shac[i] += 3*shift;
+ }
+ if (i==i2) break;
+ }
+
+}
+
+
+/* ----- set_minsyms: want at least one symbol in each voice --- */
+void set_minsyms(ivc)
+int ivc;
+{
+ int n2;
+
+ n2=voice[ivc].nsym;
+ printf ("set_minsyms: n2=%d\n",n2);
+ if (n2>0) return;
+
+ symv[ivc][n2]=zsym;
+ symv[ivc][n2].type = INVISIBLE;
+ symv[ivc][n2].u = 3;
+ symv[ivc][n2].v = 3;
+ symv[ivc][n2].w = 3;
+ voice[ivc].nsym++;
+
+}
+
+
+/* ----- set_sym_chars: set symbol characteristics --- */
+void set_sym_chars (n1,n2,symb)
+int n1,n2;
+struct SYMBOL symb[];
+{
+ int i,np,m,ymn,ymx;
+ float yav,yy;
+
+ for (i=n1;i<n2;i++) {
+ if ((symb[i].type==NOTE)||(symb[i].type==REST)) {
+ symb[i].y=3*(symb[i].pits[0]-18)+symb[i].yadd;
+ if (symb[i].type==REST) symb[i].y=12;
+ yav=0;
+ ymn=1000;
+ ymx=-1000;
+ np=symb[i].npitch;
+ for (m=0;m<np;m++) {
+ yy=3*(symb[i].pits[m]-18)+symb[i].yadd;
+ yav=yav+yy/np;
+ if (yy<ymn) ymn=yy;
+ if (yy>ymx) ymx=yy;
+ }
+ symb[i].ymn=ymn;
+ symb[i].ymx=ymx;
+ symb[i].yav=yav;
+ symb[i].ylo=ymn;
+ symb[i].yhi=ymx;
+
+ }
+ }
+}
+
+/* ----- set_beams: decide on beams ---- */
+void set_beams (n1,n2,symb)
+int n1,n2;
+struct SYMBOL symb[];
+{
+ int j,lastnote,start_flag;
+
+ /* separate words at notes without flags */
+ start_flag=0;
+ lastnote=-1;
+ for (j=n1;j<n2;j++) {
+ if (symb[j].type==NOTE) {
+ if (start_flag) {
+ symb[j].word_st=1;
+ start_flag=0;
+ }
+ if (symb[j].flags==0) {
+ if (lastnote>=0) symb[lastnote].word_end=1;
+ symb[j].word_st=1;
+ symb[j].word_end=1;
+ start_flag=1;
+ }
+ lastnote=j;
+ }
+ }
+
+}
+
+/* ----- set_stems: decide on stem directions and lengths ---- */
+void set_stems (n1,n2,symb)
+int n1,n2;
+struct SYMBOL symb[];
+{
+ int beam,j,k,n,stem,laststem;
+ float avg,slen,lasty,dy;
+
+ /* set stem directions; near middle, use previous direction */
+ beam=0;
+ laststem=0;
+ for (j=n1; j<n2; j++) {
+ if (symb[j].type!=NOTE) laststem=0;
+
+ if (symb[j].type==NOTE) {
+
+ symb[j].stem=0;
+ if (symb[j].len<WHOLE) symb[j].stem=1;
+ if (symb[j].yav>=12) symb[j].stem=-symb[j].stem;
+ if ((symb[j].yav>11) && (symb[j].yav<13) && (laststem!=0)) {
+ dy=symb[j].yav-lasty;
+ if ((dy>-7) && (dy<7)) symb[j].stem=laststem;
+ }
+
+ if (symb[j].word_st && (!symb[j].word_end)) { /* start of beam */
+ avg=0;
+ n=0;
+ for (k=j;k<n2;k++) {
+ if (symb[k].type==NOTE) {
+ avg=avg+symb[k].yav;
+ n++;
+ }
+ if (symb[k].word_end) break;
+ }
+ avg=avg/n;
+ stem=1;
+ if (avg>=12) stem=-1;
+ if ((avg>11) && (avg<13) && (laststem!=0)) stem=laststem;
+ beam=1;
+ }
+
+ if (beam) symb[j].stem=stem;
+ if (symb[j].word_end) beam=0;
+ if (bagpipe) symb[j].stem=-1;
+ if (symb[j].len>=WHOLE) symb[j].stem=0;
+ laststem=symb[j].stem;
+ if (symb[j].len>=HALF) laststem=0;
+ lasty=symb[j].yav;
+ }
+ }
+
+ /* shift notes in chords (need stem direction to do this) */
+ for (j=n1;j<n2;j++)
+ if (symb[j].type==NOTE) set_head_directions (&symb[j]);
+
+ /* set height of stem end, without considering beaming for now */
+ for (j=n1; j<n2; j++) if (symb[j].type==NOTE) {
+ slen=STEM;
+ if (symb[j].npitch>1) slen=STEM_CH;
+ if (symb[j].flags==3) slen += 4;
+ if (symb[j].flags==4) slen += 9;
+ if ((symb[j].flags>2) && (symb[j].stem==1)) slen -= 1;
+ if (symb[j].stem==1) {
+ symb[j].y=symb[j].ymn;
+ symb[j].ys=symb[j].ymx+slen;
+ }
+ else if (symb[j].stem==-1) {
+ symb[j].y=symb[j].ymx;
+ symb[j].ys=symb[j].ymn-slen;
+ }
+ else {
+ symb[j].y=symb[j].ymx;
+ symb[j].ys=symb[j].ymx;
+ }
+ }
+}
+
+/* ----- set_sym_times: set time axis; also count through bars ----- */
+int set_sym_times (n1,n2,symb,meter0)
+int n1,n2;
+struct SYMBOL symb[];
+struct METERSTR meter0;
+{
+ int i,pp,qq,rr,meter1,meter2,count,bnum,lastb,bsave;
+ int qtab[] = {0,0,3,2,3,0,2,0,3,0};
+ float time,factor,fullmes;
+
+ meter1=meter0.meter1;
+ meter2=meter0.meter2;
+
+ lastb=bnum=0;
+ bsave=1;
+
+ time=0.0;
+ factor=1.0;
+ for (i=n1;i<n2;i++) {
+ symb[i].time=time;
+
+ /* count through bar numbers, put into symb.t */
+ if (symb[i].type==BAR) {
+ fullmes=(WHOLE*meter1)/meter2;
+ if (bnum==0) {
+ bnum=barinit;
+ if (fullmes<time+0.001) bnum++;
+ symb[i].t=bnum;
+ lastb=i;
+ }
+ else if (time-symb[lastb].time>=fullmes-0.001) {
+ bnum++;
+ while (symb[i+1].type==BAR) {i++; symb[i].time=time; }
+ symb[i].t=bnum;
+ lastb=i;
+ }
+ if (symb[i].v>1) {
+ bnum=bsave;
+ symb[i].t=0;
+ }
+ if (symb[i].v==1) bsave=bnum;
+ }
+
+ if ((symb[i].type==NOTE)||(symb[i].type==REST)) {
+ if (symb[i].p_plet) {
+ pp=symb[i].p_plet;
+ qq=symb[i].q_plet;
+ rr=symb[i].r_plet;
+ if (qq==0) {
+ qq=qtab[pp];
+ if (qq==0) {
+ qq=2;
+ if (meter1%3==0) qq=3;
+ }
+ }
+ factor=((float)qq)/((float)pp);
+ count=rr;
+ }
+ time=time+factor*symb[i].len;
+ if (count>0) count--;
+ if (count==0) factor=1;
+ }
+
+ if (symb[i].type==TIMESIG) { /* maintain meter as we go along */
+ meter1=symb[i].u;
+ meter2=symb[i].v;
+ }
+
+ }
+
+ return bnum;
+
+}
+
+/* ----- set_sym_widths: set widths and prefered space --- */
+/* This routine sets the minimal left and right widths wl,wr
+ so that successive symbols are still separated when
+ no extra glue is put between them. It also sets the prefered
+ spacings pl,pr for good output and xl,xr for expanded layout.
+ All distances in pt relative to the symbol center. */
+
+#define AT_LEAST(a,b) if((a)<(b)) a=b;
+void set_sym_widths (ns1,ns2,symb,ivc)
+int ns1,ns2,ivc;
+struct SYMBOL symb[];
+{
+ int i,n,j0,j,m,n1,n2,bt,k,sl,k1,k2,got_note,ok;
+ float xx,w,swfac,spc,dur,yy;
+ char t[81],tt[81];
+
+ swfac=1.0;
+ if (strstr(cfmt.vocalfont.name,"Times-Roman")) swfac=1.00;
+ if (strstr(cfmt.vocalfont.name,"Times-Bold")) swfac=1.05;
+ if (strstr(cfmt.vocalfont.name,"Helvetica")) swfac=1.10;
+ if (strstr(cfmt.vocalfont.name,"Helvetica-Bold")) swfac=1.15;
+
+ got_note=0;
+ for (i=ns1;i<ns2;i++) {
+ switch (symb[i].type) {
+
+ case INVISIBLE: /* empty space; shrink,space,stretch from u,v,w */
+ symb[i].wl=symb[i].wr=0.5*symb[i].u;
+ symb[i].pl=symb[i].pr=0.5*symb[i].v;
+ symb[i].xl=symb[i].xr=0.5*symb[i].w;
+ break;
+
+ case NOTE:
+ case REST:
+ got_note=1;
+ dur=symb[i].len;
+ symb[i].wl=symb[i].wr=4.5;
+ if (symb[i].head==H_EMPTY) {symb[i].wl=6.0; symb[i].wr=14.0;}
+ if (symb[i].head==H_OVAL) {symb[i].wl=8.0; symb[i].wr=18.0;}
+ symb[i].pl=symb[i].xl=symb[i].wl;
+ symb[i].pr=symb[i].xr=symb[i].wr;
+
+ /* room for shifted heads and accidental signs */
+ for (m=0;m<symb[i].npitch;m++) {
+ xx=symb[i].shhd[m];
+ AT_LEAST (symb[i].wr, xx+6);
+ AT_LEAST (symb[i].wl, -xx+6);
+ if (symb[i].accs[m]) {
+ xx=xx-symb[i].shac[m];
+ AT_LEAST (symb[i].wl, -xx+3);
+ }
+ AT_LEAST (symb[i].xl, -xx+3);
+ symb[i].pl=symb[i].wl;
+ symb[i].xl=symb[i].wl;
+ }
+
+ /* room for slide */
+ for (k=0;k<symb[i].dc.n;k++) {
+ if (symb[i].dc.t[k]==D_SLIDE) symb[i].wl += 10;
+ }
+
+ /* room for grace notes */
+ if (symb[i].gr.n>0) {
+ xx=GSPACE0;
+ if (symb[i].gr.a[0]) xx=xx+3.5;
+ for (j=1;j<symb[i].gr.n;j++) {
+ xx=xx+GSPACE;
+ if (symb[i].gr.a[j]) xx=xx+4;
+ }
+ symb[i].wl = symb[i].wl + xx+1;
+ symb[i].pl = symb[i].pl + xx+1;
+ symb[i].xl = symb[i].xl + xx+1;
+ }
+
+ /* space for flag if stem goes up on standalone note */
+ if (symb[i].word_st && symb[i].word_end)
+ if ((symb[i].stem==1) && symb[i].flags>0)
+ AT_LEAST (symb[i].wr, 12);
+
+ /* leave room for dots */
+ if (symb[i].dots>0) {
+ AT_LEAST (symb[i].wr,12+symb[i].xmx);
+ if (symb[i].dots>=2) symb[i].wr=symb[i].wr+3.5;
+ n=(int) symb[i].y;
+ /* special case: standalone with up-stem and flags */
+ if (symb[i].flags && (symb[i].stem==1) && !(n%6))
+ if ((symb[i].word_st==1) && (symb[i].word_end==1)) {
+ symb[i].wr=symb[i].wr+DOTSHIFT;
+ symb[i].pr=symb[i].pr+DOTSHIFT;
+ symb[i].xr=symb[i].xr+DOTSHIFT;
+ }
+ }
+
+ /* extra space when down stem follows up stem */
+ j0=preceded_by_note(i,ns2,symb);
+ if ((j0>=0) && (symb[j0].stem==1) && (symb[i].stem==-1))
+ AT_LEAST (symb[i].wl, 7);
+
+ /* make sure helper lines don't overlap */
+ if ((j0>=0) && (symb[i].y>27) && (symb[j0].y>27))
+ AT_LEAST (symb[i].wl, 7.5);
+
+ /* leave room guitar chord */
+ if (strlen(symb[i].text)>0) {
+ /* special case: guitar chord under ending 1 or 2 */
+ /* leave some room to the left of the note */
+ if ((i>0) && (symb[i-1].type==BAR)) {
+ bt=symb[i-1].v;
+ if (bt) AT_LEAST (symb[i].wl, 18);
+ }
+ /* rest is same for all guitar chord cases */
+ tex_str(symb[i].text,t,&w);
+ xx=cfmt.gchordfont.size*w;
+ xx=xx*1.05; /* extra space mainly for helvetica font */
+ spc=xx*GCHPRE;
+ k1=prec_note(i,ns2,symb);
+ k2=next_note(i,ns2,symb);
+ if (spc>8.0) spc=8.0;
+ if ((k1>0) && (strlen(symb[k1].text)>0))
+ AT_LEAST (symb[i].wl, spc);
+ if ((k2>0) && (strlen(symb[k2].text)>0))
+ AT_LEAST (symb[i].wr, xx-spc);
+ }
+
+ /* leave room for vocals under note */
+ for (j=0;j<NWLINE;j++) {
+ if (symb[i].wordp[j]) {
+ sl=tex_str(symb[i].wordp[j],t,&w);
+ xx=swfac*cfmt.vocalfont.size*(w+2*cwid(' '));
+ AT_LEAST (symb[i].wl,xx*VOCPRE);
+ AT_LEAST (symb[i].wr,xx*(1.0-VOCPRE));
+ }
+ }
+
+ AT_LEAST (symb[i].pl, symb[i].wl);
+ AT_LEAST (symb[i].xl, symb[i].wl);
+ AT_LEAST (symb[i].pr, symb[i].wr);
+ AT_LEAST (symb[i].xr, symb[i].wr);
+ break;
+
+ case BAR:
+ symb[i].wl=symb[i].wr=0;
+ if (symb[i].u==B_SNGL) symb[i].wl=symb[i].wr=3;
+ else if (symb[i].u==B_DBL) { symb[i].wl=7; symb[i].wr=4; }
+ else if (symb[i].u==B_LREP) { symb[i].wl=3; symb[i].wr=12; }
+ else if (symb[i].u==B_RREP) { symb[i].wl=12; symb[i].wr=3; }
+ else if (symb[i].u==B_DREP) symb[i].wl=symb[i].wr=12;
+ else if (symb[i].u==B_FAT1) { symb[i].wl=3; symb[i].wr=9; }
+ else if (symb[i].u==B_FAT2) { symb[i].wl=9; symb[i].wr=3; }
+
+ if (ivc==ivc0) { /* bar numbers and labels next */
+ ok=0;
+ if ((cfmt.barnums>0) && (symb[i].t%cfmt.barnums==0)) ok=1;
+ if (strlen(symb[i].text)>0) ok=1;
+ if (ok) {
+ if (strlen(symb[i].text)>0) {
+ tex_str(symb[i].text,t,&w);
+ xx=cfmt.barlabelfont.size*w*0.5;
+ }
+ else {
+ sprintf (tt,"%d",symb[i].t);
+ tex_str(tt,t,&w);
+ xx=cfmt.barnumfont.size*w*0.5;
+ }
+ yy=60;
+ if (!got_note) yy=0;
+ if ((i>0) && (symb[i-1].type==NOTE)) {
+ yy=symb[i-1].ymx;
+ if (symb[i-1].stem==1) yy=yy+26;
+ }
+ if ((i>0) && (strlen(symb[i-1].text)>0)) yy=60;
+ AT_LEAST (symb[i].wl, 2);
+ if (yy>BNUMHT-4.0) AT_LEAST (symb[i].wl, xx+1);
+ if (!got_note) AT_LEAST (symb[i].wl, xx+1);
+ yy=0;
+ if (symb[i+1].type==NOTE) yy=symb[i+1].ymx;
+ if (yy>BNUMHT-4.0) AT_LEAST (symb[i].wr, xx+2);
+ if (strlen(symb[i+1].text)>0) AT_LEAST (symb[i].wr, xx+4);
+ }
+ }
+
+ symb[i].pl=symb[i].wl;
+ symb[i].pr=symb[i].wr;
+ symb[i].xl=symb[i].wl;
+ symb[i].xr=symb[i].wr;
+ break;
+
+ case CLEF:
+ symb[i].wl=symb[i].wr=symb[i].xl=13.5;
+ symb[i].pl=symb[i].pr=symb[i].xr=11.5;
+ break;
+
+ case KEYSIG:
+ n1=symb[i].u;
+ n2=symb[i].v;
+ if (n2>=n1) {
+ symb[i].wl=2;
+ symb[i].wr=5*(n2-n1+1)+2;
+ symb[i].pl=symb[i].wl;
+ symb[i].pr=symb[i].wr;
+ symb[i].xl=symb[i].wl;
+ symb[i].xr=symb[i].wr;
+ }
+ else {
+ symb[i].wl=symb[i].pl=symb[i].xl=3;
+ symb[i].wr=symb[i].pr=symb[i].xr=3;
+ }
+ break;
+
+ case TIMESIG:
+ symb[i].wl=8+4*(strlen(symb[i].text)-1);
+ symb[i].wr=symb[i].wl+4;
+ symb[i].pl=symb[i].wl;
+ symb[i].pr=symb[i].wr;
+ symb[i].xl=symb[i].wl;
+ symb[i].xr=symb[i].wr;
+ break;
+
+ default:
+ printf (">>> cannot set width for sym type %d\n", symb[i].type);
+ symb[i].wl=symb[i].wr=symb[i].xl=0;
+ symb[i].pl=symb[i].pr=symb[i].xr=0;
+ break;
+ }
+
+ }
+}
+
+
+
+/* ----- contract_keysigs: delete duplicate keysigs at staff start ---- */
+/* Depending on line breaks, a key and/or meter change can come
+ at the start of a staff. Solution: scan through symbols from start
+ of line as long as sym is a CLEF, KEYSIG, or TIMESIG. Remove all
+ these, but set flags so that set_initsyms will draw the
+ key and meter which result at the end of the scan. */
+int contract_keysigs (ip1)
+int ip1;
+{
+ int i,k,v,t,n3,sf,jp1,m,mtop;
+
+ mtop=10000;
+ for (v=0;v<nvoice;v++) {
+ i=ip1;
+ m=0;
+ for (;;) {
+ m++;
+ k=xp[i].p[v];
+ if (k>=0) {
+ if (symv[v][k].type==CLEF) {
+ voice[v].key.ktype=symv[v][k].u;
+ symv[v][k].type=INVISIBLE;
+ }
+ else if (symv[v][k].type==KEYSIG) {
+ sf=symv[v][k].v;
+ n3=symv[v][k].w;
+ if (n3-1<sf) sf=n3-1;
+ t =symv[v][k].t;
+ if (t==A_FT) sf=-sf;
+ if (t==A_NT) sf=0;
+ voice[v].key.sf=sf;
+ symv[v][k].type=INVISIBLE;
+ }
+ else if (symv[v][k].type==TIMESIG) {
+ voice[v].meter.insert=1;
+ voice[v].meter.meter1=symv[v][k].u;
+ voice[v].meter.meter2=symv[v][k].v;
+ voice[v].meter.mflag =symv[v][k].w;
+ strcpy(voice[v].meter.top,symv[v][k].text);
+ symv[v][k].type=INVISIBLE;
+ }
+ else
+ break;
+ }
+ i=xp[i].next;
+ if (i==XP_END) {
+ i=xp[i].prec;
+ break;
+ }
+ }
+ if (m<mtop && i>=0) {mtop=m; jp1=i; }
+ }
+
+ /* set glue for first symbol */
+ xp[jp1].shrink = xp[jp1].wl+3;
+ xp[jp1].space = xp[jp1].wl+9;
+ xp[jp1].stretch= xp[jp1].wl+16;
+
+ return jp1;
+
+}
+
+/* ----- set_initsyms: set symbols at start of staff ----- */
+int set_initsyms (v,wid0)
+int v;
+float *wid0;
+{
+ int k,t,n;
+ float x;
+
+ k=0;
+
+ /* add clef */
+ sym_st[v][k]=zsym;
+ sym_st[v][k].type = CLEF;
+ sym_st[v][k].u = voice[ivc].key.ktype;
+ sym_st[v][k].v = 0;
+ k++;
+
+ /* add keysig */
+ sym_st[v][k]=zsym;
+ sym_st[v][k].type = KEYSIG;
+ n=voice[ivc].key.sf;
+ t=A_SH;
+ if (n<0) { n=-n; t=A_FT; }
+ sym_st[v][k].u = 1;
+ sym_st[v][k].v = n;
+ sym_st[v][k].w = 100;
+ sym_st[v][k].t = t;
+ k++;
+
+ /* add timesig */
+ if (voice[ivc].meter.insert) {
+ sym_st[v][k]=zsym;
+ sym_st[v][k].type = TIMESIG;
+ sym_st[v][k].u = voice[ivc].meter.meter1;
+ sym_st[v][k].v = voice[ivc].meter.meter2;
+ sym_st[v][k].w = voice[ivc].meter.mflag;
+ strcpy(sym_st[v][k].text,voice[ivc].meter.top);
+ k++;
+ voice[ivc].meter.insert=0;
+ }
+
+ if (voice[ivc].insert_btype) {
+ sym_st[v][k].type = BAR;
+ sym_st[v][k].u=voice[ivc].insert_btype;
+ sym_st[v][k].v=voice[ivc].insert_num;
+ sym_st[v][k].t=voice[ivc].insert_bnum;
+ strcpy(sym_st[v][k].text,voice[ivc].insert_text);
+ voice[ivc].insert_btype=0;
+ voice[ivc].insert_bnum=0;
+ k++;
+ }
+
+ n=k;
+ set_sym_widths (0,n,sym_st[v],ivc);
+
+ x=0;
+ for (k=0;k<n;k++) {
+ x=x+sym_st[v][k].wl;
+ sym_st[v][k].x=x;
+ x=x+sym_st[v][k].wr;
+ }
+
+ *wid0=x+voice[v].insert_space;
+ return n;
+
+}
+
+
+/* ----- print_poslist ----- */
+void print_poslist ()
+{
+ int i,n,typ,vv;
+
+ printf ("\n----------- xpos list -----------\n");
+ printf (" num ptr type time dur width tfac"
+ " shrk spac stre eol vptr\n");
+
+ n=0;
+ i=xp[XP_START].next;
+ for (;;) {
+ typ=xp[i].type;
+ printf ("%3d %3d %d ", n,i,typ);
+ if (typ==NOTE) printf ("NOTE");
+ else if (typ==REST) printf ("REST");
+ else if (typ==KEYSIG) printf ("KEY ");
+ else if (typ==TIMESIG) printf ("TSIG");
+ else if (typ==BAR) printf ("BAR ");
+ else if (typ==CLEF) printf ("CLEF");
+ else if (typ==INVISIBLE) printf ("INVS");
+ else printf ("????");
+ printf (" %7.2f %6.2f %4.1f %4.1f %5.2f %5.1f %5.1f %5.1f",
+ xp[i].time,xp[i].dur,xp[i].wl,xp[i].wr,xp[i].tfac,
+ xp[i].shrink,xp[i].space,xp[i].stretch);
+ if (xp[i].eoln)
+ printf(" %d ",xp[i].eoln);
+ else
+ printf(" - ");
+ for (vv=0;vv<nvoice;vv++) {
+ if (xp[i].p[vv]>=0)
+ printf(" %2d",xp[i].p[vv]);
+ else
+ printf(" -");
+ }
+ printf ("\n");
+ i=xp[i].next;
+ n++;
+ if (i==XP_END) break;
+ }
+
+}
+
+
+
+
+/* ----- insert_poslist: insert new element after element nins ----- */
+int insert_poslist (nins)
+int nins;
+{
+ int new,nxt,vv;
+
+ new=ixpfree;
+ ixpfree++;
+ if (new>=XP_END)
+ rxi("Too many symbols; use -maxs to increase limit, now ",maxSyms);
+
+ nxt=xp[nins].next;
+ xp[new].prec=nins;
+ xp[new].next=nxt;
+ xp[nins].next=new;
+ xp[nxt].prec=new;
+ for (vv=0;vv<nvoice;vv++) xp[new].p[vv]=-1;
+
+ return new;
+
+}
+
+/* ----- set_poslist: make list of horizontal posits to align voices --- */
+void set_poslist ()
+{
+ int i,n,v,vv,typ,nok,nins;
+ float tol=0.01;
+ float d,tim;
+
+ /* initialize xp with data from top nonempty voice, ivc0 */
+ v=ivc0;
+ n=0;
+ xp[0].next=1;
+ for (i=0;i<voice[v].nsym;i++) {
+ n++;
+ xp[n].prec=n-1;
+ xp[n].next=n+1;
+ symv[v][i].p=n;
+ for (vv=0;vv<nvoice;vv++) xp[n].p[vv]=-1;
+ xp[n].p[v]=i;
+ typ=symv[v][i].type;
+ if (typ==REST) typ=NOTE;
+ xp[n].type = typ;
+ xp[n].time = symv[v][i].time;
+ xp[n].dur = xp[n].tfac = 0;
+ xp[n].shrink = xp[n].space = xp[n].stretch =0;
+ xp[n].wl = xp[n].wr = 0;
+ xp[n].eoln=symv[v][i].eoln;
+ }
+ xp[n].next=XP_END;
+ xp[XP_END].prec=n;
+ ixpfree=n+1;
+
+ /* find or insert syms for other voices */
+ for (v=0;v<nvoice;v++) {
+ if (voice[v].draw && v!=ivc0) {
+ n=XP_START;
+ for (i=0;i<voice[v].nsym;i++) {
+ tim=symv[v][i].time;
+ typ=symv[v][i].type;
+ if (typ==REST) typ=NOTE;
+ nok=-1;
+ nins=n;
+ for (;;) {
+ n=xp[n].next;
+ if (n==XP_END) break;
+ d=xp[n].time-tim;
+ if (xp[n].time<tim-tol) nins=n;
+ if (d*d<tol*tol && xp[n].type==typ) {
+ nok=n;
+ break;
+ }
+ if (xp[n].time>tim+tol) break;
+ }
+ if (nok>0)
+ n=nok;
+ else {
+ n=insert_poslist (nins);
+ xp[n].type=typ;
+ xp[n].time=tim;
+ xp[n].dur = xp[n].tfac = 0;
+ xp[n].shrink = xp[n].space = xp[n].stretch =0;
+ xp[n].wl = xp[n].wr = 0;
+ xp[n].eoln=0;
+ }
+ symv[v][i].p=n;
+ xp[n].p[v]=i;
+ }
+ }
+ }
+
+/*| print_poslist (); |*/
+
+}
+
+
+/* ----- set_xpwid: set symbol widths and tfac in xp list ----- */
+void set_xpwid()
+{
+ int i,j,k,i1,i2,k1,k2,v,nsm;
+ float fac,dy,ff,wv,wx;
+
+ /* set all tfacs to 1.0 */
+ i=i1=xp[XP_START].next;
+ for (;;) {
+ xp[i].tfac=1.0;
+ xp[i].wl=xp[i].wr=WIDTH_MIN;
+ i2=i;
+ i=xp[i].next;
+ if (i==XP_END) break;
+ }
+
+ /* loop over voices. first voice last, assumed most important */
+ for (v=nvoice-1;v>=0;v--) {
+ nsm=voice[v].nsym;
+
+ /* first symbol and last symbol */
+ k1=symv[v][0].p;
+ k2=symv[v][nsm-1].p;
+ if (k1==i1 && symv[v][0].wl>xp[k1].wl) xp[k1].wl=symv[v][0].wl;
+ if (k2==i2 && symv[v][nsm-1].wr>xp[k2].wr) xp[k2].wr=symv[v][nsm-1].wr;
+
+ /* loop over symbol nn pairs */
+ for (i=1;i<nsm;i++) {
+ j=i-1;
+ k1=symv[v][j].p;
+ k2=symv[v][i].p;
+ if (xp[k1].next==k2) {
+ if (symv[v][j].wr>xp[k1].wr) xp[k1].wr=symv[v][j].wr;
+ if (symv[v][i].wl>xp[k2].wl) xp[k2].wl=symv[v][i].wl;
+
+ if (symv[v][j].type==NOTE && symv[v][i].type==NOTE) {
+ fac=1.0;
+ /* reduce distance under a beam */
+ if (symv[v][i].word_st==0) fac=fac*fnnp;
+ /* reduce distance for large jumps in pitch */
+ dy=symv[v][i].y-symv[v][j].y;
+ if (dy<0) dy=-dy;
+ ff=1-0.010*dy;
+ if (ff<0.9) ff=0.9;
+ fac=fac*ff;
+ xp[k2].tfac=fac;
+ }
+ }
+ }
+ }
+
+ /* check for all nn pairs in voice, in case some syms very wide */
+ for (v=nvoice-1;v>=0;v--) {
+ nsm=voice[v].nsym;
+ for (i=1;i<nsm;i++) {
+ j=i-1;
+ k1=symv[v][j].p;
+ k2=symv[v][i].p;
+ if (xp[k1].next!=k2) {
+ wv=symv[v][j].wr+symv[v][i].wl;
+ wx=xp[k1].wr+xp[k2].wl;
+ k=k1;
+ for (;;) {
+ k=xp[k].next;
+ if (k==k2) break;
+ wx=wx+xp[k].wl+xp[k].wr;
+ }
+ if(wx<wv) {
+ fac=wv/wx;
+ xp[k1].wr=fac*xp[k1].wr;
+ xp[k2].wl=fac*xp[k2].wl;
+ k=k1;
+ for (;;) {
+ k=xp[k].next;
+ if (k==k2) break;
+ xp[k].wl=fac*xp[k].wl;
+ xp[k].wr=fac*xp[k].wr;
+ }
+
+ }
+ }
+ }
+ }
+
+}
+
+
+/* ----- set_spaces: set the shrink,space,stretch distances ----- */
+void set_spaces ()
+{
+ int i,j,n,nxt,typ,typl,meter1,meter2;
+ float w0,w1,w2;
+ float vbnp,vbnx,vnbp,vnbx;
+
+ /* note lengths for spaces at bars. Use dcefault meter for now */
+ meter1=default_meter.meter1;
+ meter2=default_meter.meter2;
+ vbnp=(rbnp*meter1*BASE)/meter2;
+ vbnx=(rbnx*meter1*BASE)/meter2;
+ vnbp=(rnbp*meter1*BASE)/meter2;
+ vnbx=(rnbx*meter1*BASE)/meter2;
+
+ /* redefine durations as differences in start times */
+ n=0;
+ i=xp[XP_START].next;
+ for (;;) {
+ nxt=xp[i].next;
+ if (nxt!=XP_END) xp[i].dur=xp[nxt].time-xp[i].time;
+ i=nxt;
+ n++;
+ if (i==XP_END) break;
+ }
+
+ i=xp[XP_START].next;
+ j=-1;
+ typl=0;
+ for (;;) {
+ nxt=xp[i].next;
+ typ=xp[i].type;
+
+ /* shrink distance is sum of left and right widths */
+ if (j>=0)
+ xp[i].shrink=xp[j].wr+xp[i].wl;
+ else
+ xp[i].shrink=xp[i].wl;
+ xp[i].space=xp[i].stretch=xp[i].shrink;
+
+ if (xp[i].type==NOTE) {
+
+ if (typl==NOTE) { /* note after another note */
+ w1 = lnnp*nwid(xp[j].dur);
+ w2 = lnnp*nwid(xp[i].dur);
+ xp[i].space = bnnp*w1 + (1-bnnp)*0.5*(w1+w2);
+ w1 = lnnx*xwid(xp[j].dur);
+ w2 = lnnx*xwid(xp[i].dur);
+ xp[i].stretch = bnnx*w1 + (1-bnnx)*0.5*(w1+w2);
+ }
+
+ else { /* note at start of bar */
+ w1 = lbnp*nwid(xp[i].dur);
+ w0 = lbnp*nwid(vbnp);
+ if (w0>w1) w0=w1;
+ xp[i].space = bbnp*w1 + (1-bbnp)*w0 + xp[j].wr;
+ if (xp[i].space<14.0) xp[i].space=14.0;
+ w1 = lbnx*xwid(xp[i].dur);
+ w0 = lbnx*xwid(vbnp);
+ if (w0>w1) w0=w1;
+ xp[i].stretch = bbnx*w1 + (1-bbnx)*w0 + xp[j].wr;
+ if (xp[i].stretch<18.0) xp[i].stretch=18.0;
+ if (xp[i].shrink<12.0) xp[i].shrink=12.0;
+ }
+ }
+
+ else { /* some other symbol after note */
+ if (typl==NOTE) {
+ w1 = lnbp*nwid(xp[j].dur);
+ w0 = lnbp*nwid(vnbp);
+ xp[i].space = bnbp*w1 + (1-bnbp)*w0 + xp[i].wl;
+ if (xp[i].space<13.0) xp[i].space=13.0;
+ w1 = lnbx*xwid(xp[j].dur);
+ w0 = lnbx*xwid(vnbx);
+ xp[i].stretch = bnbx*w1 + (1-bnbx)*w0 + xp[i].wl;
+ if (xp[i].stretch<17.0) xp[i].stretch=17.0;
+ }
+ }
+
+ /* multiply space and stretch by factors tfac */
+ xp[i].space = xp[i].space*xp[i].tfac;
+ xp[i].stretch = xp[i].stretch*xp[i].tfac;
+
+ /* make sure that shrink < space < stretch */
+ if (xp[i].space<xp[i].shrink) xp[i].space=xp[i].shrink;
+ if (xp[i].stretch<xp[i].space) xp[i].stretch=xp[i].space;
+
+ j=i;
+ typl=typ;
+ i=nxt;
+
+ if (i==XP_END) break;
+ }
+
+ if (verbose>=11) print_poslist ();
+
+}
+
+/* ----- check_overflow: returns upper limit which fits on staff ------ */
+int check_overflow (ip1,ip2,width)
+int ip1,ip2;
+float width;
+{
+
+ int i,jp2,lastcut,nbar,need_note;
+ float space,shrink,stretch,alfa,alfa0;
+
+ /* max shrink is alfa0 */
+ alfa0=ALFA_X;
+ if (cfmt.continueall) alfa0=cfmt.maxshrink;
+ if (gmode==G_SHRINK) alfa0=1.0;
+ if (gmode==G_SPACE) alfa0=0.0;
+ if (gmode==G_STRETCH) alfa0=1.0;
+
+ jp2=ip2;
+ space=shrink=stretch=0;
+ lastcut=-1;
+ nbar=0;
+ need_note=1;
+ i=ip1;
+ for (;;) {
+ space=space+xp[i].space;
+ shrink=shrink+xp[i].shrink;
+ stretch=stretch+xp[i].stretch;
+ alfa=0;
+ if (space>shrink) {
+ alfa=(space-width)/(space-shrink);
+ if (xp[i].type!=BAR)
+ alfa=((space+8)-width)/(space-shrink);
+ }
+
+ if (alfa>alfa0) {
+ if (!cfmt.continueall) {
+ if (verbose<=3) printf ("\n");
+ printf ("+++ Overfull after %d bar%s in staff %d\n",
+ nbar, nbar==1 ? "" : "s", mline);
+ }
+ jp2=i;
+ if (i==ip1) jp2=xp[i].next;
+ if (lastcut>=0) jp2=xp[lastcut].next;
+ break;
+ }
+ /* The need_note business is to cut at the first of consecutive bars */
+ if (xp[i].type==NOTE) need_note=0;
+ if (xp[i].type==BAR && need_note==0) {lastcut=i; need_note=1; nbar++; }
+ if (xp[i].type==KEYSIG) lastcut=i;
+ i=xp[i].next;
+ if (i==ip2) break;
+ }
+
+ return jp2;
+
+}
+
+
+/* ----- set_glue --------- */
+float set_glue (ip1,ip2,width)
+int ip1,ip2;
+float width;
+{
+
+ int i,j;
+ float space,shrink,stretch,alfa,beta,glue,w,x,d1,d2,w1;
+ float alfa0,beta0;
+
+ alfa0=ALFA_X; /* max shrink and stretch */
+ if (cfmt.continueall) alfa0=cfmt.maxshrink;
+ if (gmode==G_SHRINK) alfa0=1.0;
+ if (gmode==G_SPACE) alfa0=0.0;
+ if (gmode==G_STRETCH) alfa0=1.0;
+ beta0=BETA_X;
+ if (cfmt.continueall) beta0=BETA_C;
+
+
+ space=shrink=stretch=0;
+ i=ip1;
+ for (;;) {
+ space=space+xp[i].space;
+ shrink=shrink+xp[i].shrink;
+ stretch=stretch+xp[i].stretch;
+ j=i;
+ i=xp[i].next;
+ if (i==ip2) break;
+ }
+
+ /* add extra space if last symbol is not a bar */
+ if (xp[j].type!=BAR) {
+ d1=d2=xp[j].wr+3;
+ if (xp[j].type==NOTE) d2 = lnbp*nwid(xp[j].dur)+xp[j].wr;
+ if (d2<d1) d2=d1;
+ shrink = shrink + d1;
+ space = space + d2;
+ stretch = stretch + d2;
+ }
+
+ /* select alfa and beta */
+ alfa=beta=0;
+ if (space>width) {
+ alfa=99;
+ if (space>shrink) alfa=(space-width)/(space-shrink);
+ }
+ else {
+ beta=99;
+ if (stretch>space) beta=(width-space)/(stretch-space);
+ if (!cfmt.stretchstaff) beta=0;
+ }
+
+ if (gmode==G_SHRINK) { alfa=1; beta=0;} /* force minimal spacing */
+ if (gmode==G_STRETCH) { alfa=0; beta=1;} /* force stretched spacing */
+ if (gmode==G_SPACE) { alfa=beta=0; } /* force natural spacing */
+
+/*| if (alfa>alfa0) { alfa=alfa0; beta=0; } |*/
+
+ if (beta>beta0) {
+ if (!cfmt.continueall) {
+ if (verbose<=3) printf ("\n");
+ printf ("+++ Underfull (%.0fpt of %.0fpt) in staff %d\n",
+ (beta0*stretch+(1-beta0)*space)*cfmt.scale,
+ cfmt.staffwidth,mline);
+ }
+ alfa=0;
+ if (!cfmt.stretchstaff) beta=0;
+ if ((!cfmt.stretchlast) && (ip2==XP_END)) {
+ w1=alfa_last*shrink+beta_last*stretch+(1-alfa_last-beta_last)*space;
+ if (w1<width) {
+ alfa=alfa_last; /* shrink undefull last line same as previous */
+ beta=beta_last;
+ }
+ }
+ }
+
+ w=alfa*shrink+beta*stretch+(1-alfa-beta)*space;
+ if (verbose>=5) {
+ if (alfa>0) printf ("Shrink staff %.0f%%", 100*alfa);
+ else if (beta>0) printf ("Stretch staff %.0f%%", 100*beta);
+ else printf ("No shrink or stretch");
+ printf (" to width %.0f (%.0f,%.0f,%.0f)\n",w,shrink,space,stretch);
+ }
+
+ /* now calculate the x positions */
+ x=0;
+ i=ip1;
+ for (;;) {
+ glue=alfa*xp[i].shrink+beta*xp[i].stretch+(1-alfa-beta)*xp[i].space;
+ x=x+glue;
+ xp[i].x=x;
+ if (verbose>22) printf ("pos[%d]: type=%d pos=%.2f\n", i,xp[i].type,x);
+ i=xp[i].next;
+ if (i==ip2) break;
+ }
+
+ alfa_last=alfa;
+ beta_last=beta;
+ return w;
+
+}
+
+
+/* ----- adjust_group: even out spacings for one group of notes --- */
+/* Here we repeat the whole glue thing, in rudimentary form */
+void adjust_group(i1,i2)
+int i1,i2;
+{
+ int j;
+ float dx,x,spa,shr,str,hp,hx,alfa,beta,dur1;
+
+ dx=sym[i2].x-sym[i1].x;
+ shr=sym[i1].wr+sym[i2].wl;
+ for (j=i1+1;j<i2;j++) shr=shr+sym[j].wl+sym[j].wr;
+ dur1=sym[i1].len;
+ hp=lnnp*nwid(dur1);
+ hx=lnnx*xwid(dur1);
+ spa = (i2-i1)*hp;
+ str = (i2-i1)*hx;
+
+ alfa=beta=0;
+ if (dx>spa)
+ beta=(dx-spa)/(str-spa);
+ else
+ alfa=(dx-spa)/(shr-spa);
+
+ x=sym[i1].x;
+ for (j=i1+1;j<=i2;j++) {
+ x=x+alfa*(sym[j-1].wr+sym[j].wl)+beta*hx+(1-alfa-beta)*hp;
+ sym[j].x=x;
+ }
+
+}
+
+
+/* ----- adjust_spacings: even out triplet spacings etc --- */
+void adjust_spacings (n)
+int n;
+{
+ int i,i1,count,beam,num;
+
+ /* adjust the n-plets */
+ count=0;
+ for (i=1;i<n;i++) {
+ if ((sym[i].type==NOTE)||(sym[i].type==REST)) {
+ if (sym[i].p_plet) {
+ i1=i;
+ count=sym[i].r_plet;
+ }
+ if (count>0 && sym[i].len!=sym[i1].len) count=0;
+ if (count==1) adjust_group (i1,i);
+ if (count>0) count--;
+ }
+ else
+ count=0;
+ }
+
+ /* adjust beamed notes of equal duration */
+ beam=0;
+ for (i=1;i<n;i++) {
+ if ((sym[i].type==NOTE)||(sym[i].type==REST)) {
+ if (sym[i].word_st && (!sym[i].word_end)) {
+ i1=i;
+ beam=1;
+ if (sym[i].p_plet) beam=0; /* don't do nplets here */
+ }
+ if (beam && sym[i].len!=sym[i1].len) beam=0;
+ if (beam && sym[i].word_end) {
+ num=i-i1+1;
+ if (num>2 && num<4) adjust_group (i1,i);
+ }
+ if (sym[i].word_end) beam=0;
+ }
+ else
+ beam=0;
+ }
+
+}
+
+
+/* ----- adjust_rests: position single rests in bar center */
+void adjust_rests (n,v)
+int n,v;
+{
+ int i,ok;
+
+ for (i=2;i<n-1;i++) {
+ if ((sym[i].type==REST) && sym[i].fullmes) {
+
+ ok=1;
+ if ((sym[i-1].type==REST) || (sym[i-1].type==NOTE)) ok=0;
+ if ((sym[i+1].type==REST) || (sym[i+1].type==NOTE)) ok=0;
+
+ if (ok) {
+ sym[i].head = H_OVAL;
+ sym[i].dots = 0;
+ sym[i].x = 0.5*(sym[i-1].x+sym[i+1].x);
+ }
+
+ }
+ }
+
+}
+
+
+
+/* ----- copy_vsyms: copy selected syms for voice to v sym --- */
+int copy_vsyms (v,ip1,ip2,wid0)
+int v,ip1,ip2;
+float wid0;
+{
+ int i,n,m,k;
+ float d1,d2,r,x;
+
+ /* copy staff initialization symbols */
+ n=0;
+ for (i=0;i<nsym_st[v];i++) {
+ sym[n]=sym_st[v][i];
+ n++;
+ }
+
+ /* copy real symbols, shifted by wid0 */
+ i=ip1;
+ m=0;
+ for (;;) {
+ k=xp[i].p[v];
+ if (k >= 0) {
+ sym[n]=symv[v][k];
+ sym[n].x=xp[i].x+wid0;
+ n++;
+ m++;
+ }
+ i=xp[i].next;
+ if (i==ip2) break;
+ }
+
+ /* adjust things for more pretty output.. */
+ adjust_rests (n,v);
+ if (mvoice>1) adjust_spacings (n);
+
+ /* small random shifts make the output more human... */
+ for (i=1;i<n-1;i++) {
+ if ((sym[i].type==NOTE) || (sym[i].type==REST)) {
+ d1=sym[i].x-sym[i-1].x;
+ d2=sym[i+1].x-sym[i].x;
+ r=RANFAC*d1;
+ if (d2<d1) r=RANFAC*d2;
+ if (r>RANCUT) r=RANCUT;
+ x=ranf(-r,r);
+ sym[i].x=sym[i].x+x;
+ }
+ }
+
+ return n;
+
+}
+
+
+/* ----- draw_timesig ------- */
+void draw_timesig (x,s)
+struct SYMBOL s;
+float x;
+{
+ if (s.w==1)
+ PUT1("%.1f csig\n", x)
+ else if (s.w==2)
+ PUT1("%.1f ctsig\n", x)
+ else
+/* PUT3("%.1f (%d) (%d) tsig\n", x, s.u, s.v) */
+ PUT3("%.1f (%s) (%d) tsig\n", x, s.text, s.v)
+}
+
+/* ----- draw_keysig: return sf for this key ----- */
+int draw_keysig (x,s)
+struct SYMBOL s;
+float x;
+{
+ float p;
+ int i,n1,n2,n3,t,yad,sf;
+ int sh_pos[8]={0, 24,15,27,18,9,21,15};
+ int ft_pos[8]={0, 12,21,9,18,6,15,3};
+
+ n1=s.u; /* which symbol to start with */
+ n2=s.v; /* up to which symbol to go */
+ n3=s.w; /* draw neutrals instead starting from this one */
+ t =s.t; /* type of symbol: sharp or flat */
+
+ yad = 0;
+ if (voice[ivc].key.ktype==BASS) yad = -6;
+ if (voice[ivc].key.ktype==ALTO) yad = -3;
+
+ if (n2>7) {
+ printf ("+++ Keysig seems to have %d symbols ???\n", n2);
+ return 0;
+ }
+
+ sf=0;
+ if (t==A_SH) {
+ p=x;
+ for (i=n1;i<=n2;i++) {
+ if (i>=n3)
+ PUT2("%.1f %d nt0 ",p,sh_pos[i]+yad)
+ else {
+ sf++;
+ PUT2("%.1f %d sh0 ",p,sh_pos[i]+yad)
+ }
+ p=p+5;
+ }
+ PUT0("\n")
+ }
+ else if (t==A_FT) {
+ p=x;
+ for (i=n1;i<=n2;i++) {
+ if (i>=n3)
+ PUT2("%.1f %d nt0 ", p, ft_pos[i]+yad)
+ else {
+ sf--;
+ PUT2("%.1f %d ft0 ", p, ft_pos[i]+yad)
+ }
+ p=p+5;
+ }
+ PUT0("\n")
+ }
+ else
+ bug ("wrong type in draw_keysig", 0);
+
+ return sf;
+}
+
+
+/* ----- draw_bar ------- */
+void draw_bar (x,s)
+struct SYMBOL s;
+float x;
+{
+
+ if (s.u==B_SNGL) /* draw the bar */
+ PUT1("%.1f bar\n", x)
+ else if (s.u==B_DBL)
+ PUT1("%.1f dbar\n", x)
+ else if (s.u==B_LREP)
+ PUT2("%.1f fbar1 %.1f rdots\n", x, x+10)
+ else if (s.u==B_RREP) {
+ PUT2("%.1f fbar2 %.1f rdots\n", x, x-10)
+ }
+ else if (s.u==B_DREP) {
+ PUT2("%.1f fbar1 %.1f rdots\n", x-1, x+9)
+ PUT2("%.1f fbar2 %.1f rdots\n", x+1, x-9)
+ }
+ else if (s.u==B_FAT1)
+ PUT1("%.1f fbar1\n", x)
+ else if (s.u==B_FAT2)
+ PUT1("%.1f fbar2\n", x)
+ else if (s.u==B_INVIS)
+ ;
+ else
+ printf (">>> dont know how to draw bar type %d\n", s.u);
+
+ PUT0("\n")
+
+}
+
+
+/* ----- draw_barnums ------- */
+void draw_barnums (fp)
+FILE *fp;
+{
+ int i,last,ok,got_note;
+
+ last=0;
+ got_note=0;
+ for (i=0;i<nsym;i++) {
+ if ((sym[i].type==NOTE)||(sym[i].type==REST)) got_note=1;
+
+ if ((sym[i].type==BAR) && (strlen(sym[i].text)>0)) {
+ if (last != 2) set_font (fp, cfmt.barlabelfont, 0);
+ PUT3 (" %.1f %.1f M (%s) cshow ", sym[i].x, BNUMHT, sym[i].text)
+ last=2;
+ }
+
+ if ((sym[i].type==BAR) && sym[i].t) {
+ ok=0;
+ if ((cfmt.barnums>0) && (sym[i].t%cfmt.barnums==0)) ok=1;
+ if ((cfmt.barnums==0) && (!got_note)) ok=1;
+ if ((cfmt.barnums!=0) && ((strlen(sym[i].text)>0))) ok=0;
+
+ if (ok) {
+ if (last != 1) set_font (fp, cfmt.barnumfont, 0);
+/*| if ((mvoice>1) && (cfmt.barnums==0)) |*/
+ if (cfmt.barnums==0)
+ PUT1 (" 0 38 M (%d) rshow ", sym[i].t)
+ else
+ PUT3 (" %.1f %.1f M (%d) cshow ", sym[i].x, BNUMHT, sym[i].t)
+ last=1;
+ }
+ }
+ }
+ PUT0("\n");
+
+}
+
+
+/* ----- update_endings: remember where to draw endings ------- */
+void update_endings (x,s)
+struct SYMBOL s;
+float x;
+{
+ int i;
+
+ if (num_ending>0) {
+ i=num_ending-1;
+ if (ending[i].num==1)
+ mes1++;
+ else {
+ mes2++;
+ if (mes2==mes1) ending[i].b=x;
+ }
+ }
+
+ if (s.v) {
+ if (num_ending>0)
+ if (ending[num_ending-1].num==1) ending[num_ending-1].b=x-3;
+ ending[num_ending].a=x;
+ ending[num_ending].b=-1;
+ ending[num_ending].num=s.v;
+ if (s.v==1) mes1=0;
+ else mes2=0;
+ num_ending++;
+ }
+
+}
+
+
+
+/* ----- set_ending: determine limits of ending box ------- */
+void set_ending (i)
+int i;
+{
+ int num,j,j0,j1,mes,mesmax;
+ float top;
+
+ num=sym[i].v;
+ mesmax=0;
+ if (num==2) mesmax=mes1;
+
+ mes=0;
+ j0=j1=-1;
+ for (j=i+1;j<nsym;j++) {
+ if (sym[j].type==BAR) {
+ if (sym[j].u!=B_INVIS) mes++;
+ if (mes==1) j1=j;
+ if (sym[j].u==B_RREP || sym[j].u==B_DREP || sym[j].u==B_FAT2 ||
+ sym[j].u==B_LREP || sym[j].u==B_FAT1 || sym[j].v>0) {
+ j0=j;
+ break;
+ }
+ if (mes==mesmax) {
+ j0=j;
+ break;
+ }
+ }
+ }
+ top=-1;
+ if (j0==-1) j0=j1;
+ if (j0>=0) top=sym[j0].x;
+
+ ending[num_ending].num=num;
+ ending[num_ending].a=sym[i].x;
+ ending[num_ending].b=top;
+ if (num==1) ending[num_ending].b=top-3;
+ ending[num_ending].type=E_CLOSED;
+ if (sym[j0].type==BAR && sym[j0].u==B_SNGL) ending[num_ending].type=E_OPEN;
+ num_ending++;
+
+ if (num==1) mes1=mes;
+ if (num==2) mes1=0;
+
+}
+
+
+/* ----- draw_endings ------- */
+void draw_endings ()
+{
+ int i;
+
+ for (i=0;i<num_ending;i++) {
+ if (ending[i].b<0)
+ PUT3("%.1f %.1f (%d) end2\n",
+ ending[i].a, ending[i].a+50, ending[i].num)
+ else {
+ if (ending[i].type==E_CLOSED) {
+ PUT3("%.1f %.1f (%d) end1\n",
+ ending[i].a, ending[i].b, ending[i].num)
+ }
+ else {
+ PUT3("%.1f %.1f (%d) end2\n",
+ ending[i].a, ending[i].b, ending[i].num)
+ }
+ }
+ }
+ num_ending=0;
+
+}
+
+/* ----- draw_rest ----- */
+void draw_rest (x,yy,s,gchy)
+struct SYMBOL s;
+float x,yy;
+float *gchy;
+{
+
+ int y,i,k,deco;
+ float dotx,doty;
+
+ *gchy=38;
+ if (s.invis) return;
+
+ y=(int) s.y;
+ PUT2("%.2f %.0f", x, yy)
+
+ if (s.head==H_OVAL) PUT0(" r1")
+ else if (s.head==H_EMPTY) PUT0(" r2")
+ else {
+ if (s.flags==0) PUT0(" r4")
+ else if (s.flags==1) PUT0(" r8")
+ else if (s.flags==2) PUT0(" r16")
+ else if (s.flags==3) PUT0(" r32")
+ else PUT0(" r64")
+ }
+
+ if (y%6) { dotx=6.5; doty=0; } /* dots */
+ else { dotx=6.5; doty=3; }
+ if (s.head==H_OVAL) { dotx=8; doty=-3; }
+ if (s.head==H_EMPTY) { dotx=8; doty=3; }
+ for (i=0;i<s.dots;i++) {
+ PUT2(" %.1f %.1f dt", dotx, doty)
+ dotx=dotx+3.5;
+ }
+
+
+ for (k=s.dc.n-1;k>=0;k--) {
+ deco=s.dc.t[k];
+ if (deco==D_HOLD) PUT1(" %.1f hld", 27.0)
+ }
+
+ PUT0("\n")
+}
+
+/* ----- draw_gracenotes ----- */
+void draw_gracenotes (x,w,d,s)
+struct SYMBOL *s;
+float x,w,d;
+{
+ int i,n,y,acc,ii,m;
+ float xg[20],yg[20],lg,px[20],py[20],xx,yy;
+ float s1,sx,sy,sxx,sxy,a,b,delta,lmin;
+ float x0,y0,x1,y1,x2,y2,x3,y3,bet1,bet2,dy1,dy2,dx,dd,fac,facx;
+
+ n=s->gr.n;
+ if (n==0) return;
+
+ facx=0.3;
+ fac=d/w-1;
+ if (fac<0) fac=0;
+ fac=1+(fac*facx)/(fac+facx);
+
+ dx=0;
+ for (m=0;m<s->npitch;m++) { /* room for accidentals */
+ dd=-s->shhd[m];
+ if (s->accs[m]) dd=-s->shhd[m]+s->shac[m];
+ if ((s->accs[m]==A_FT)||(s->accs[m]==A_NT)) dd=dd-2;
+ if (dx<dd) dx=dd;
+ }
+
+ xx=x-fac*(dx+GSPACE0);
+ for (i=n-1;i>=0;i--) { /* set note positions */
+ yg[i]=3*(s->gr.p[i]-18)+s->yadd;
+ if (i==n-1) { /* some subtle shifts.. */
+ if(yg[i]>=s->ymx) xx=xx+1; /* gnote above a bit closer */
+ if((yg[i]<s->ymn-7)&&(n==1)) xx=xx-2; /* below with flag further */
+ }
+
+ if (i<n-1) {
+ if (yg[i]>yg[i+1]+8) xx=xx+fac*1.8;
+ }
+
+ xg[i]=xx;
+ xx=xx-fac*GSPACE;
+ if (s->gr.a[i]) xx=xx-3.5;
+ }
+
+ if (n>1) {
+ s1=sx=sy=sxx=sxy=0; /* linear fit through stems */
+ for (i=0;i<n;i++) {
+ px[i]=xg[i]+GSTEM_XOFF;
+ py[i]=yg[i]+GSTEM;
+ s1 += 1; sx += px[i]; sy += py[i];
+ sxx += px[i]*px[i]; sxy += px[i]*py[i];
+ }
+ delta=s1*sxx-sx*sx; /* beam fct: y=ax+b */
+ a=(s1*sxy-sx*sy)/delta;
+ if (a>BEAM_SLOPE) a=BEAM_SLOPE;
+ if (a<-BEAM_SLOPE) a=-BEAM_SLOPE;
+ b=(sy-a*sx)/s1;
+
+ if (bagpipe) { a=0; b=35; }
+
+ lmin=100; /* shift to get min stems */
+ for (i=0;i<n;i++) {
+ px[i]=xg[i]+GSTEM_XOFF;
+ py[i]=a*px[i]+b;
+ lg=py[i]-yg[i];
+ if (lg<lmin) lmin=lg;
+ }
+ if (lmin<10) b=b+10-lmin;
+ }
+
+ for (i=0;i<n;i++) { /* draw grace notes */
+ if (n>1) {
+ px[i]=xg[i]+GSTEM_XOFF;
+ py[i]=a*px[i]+b;
+ lg=py[i]-yg[i];
+ PUT3("%.1f %.1f %.1f gnt ", xg[i],yg[i],lg)
+ }
+ else {
+ lg=GSTEM;
+ PUT3("%.1f %.1f %.1f gn1 ", xg[i],yg[i],lg)
+ }
+
+ acc=s->gr.a[i];
+ if (acc==A_SH) PUT2("%.1f %.1f gsh0 ",xg[i]-4.5,yg[i])
+ if (acc==A_FT) PUT2("%.1f %.1f gft0 ",xg[i]-4.5,yg[i])
+ if (acc==A_NT) PUT2("%.1f %.1f gnt0 ",xg[i]-4.5,yg[i])
+ if (acc==A_DS) PUT2("%.1f %.1f gds0 ",xg[i]-4.5,yg[i])
+ if (acc==A_DF) PUT2("%.1f %.1f gdf0 ",xg[i]-4.5,yg[i])
+
+ y = (int)yg[i]; /* helper lines */
+ if (y<=-6) {
+ if (y%6) PUT2("%.1f %d ghl ",xg[i], y+3)
+ else PUT2("%.1f %d ghl ",xg[i], y)
+ }
+ if (y>=30) {
+ if (y%6) PUT2("%.1f %d ghl ",xg[i], y-3)
+ else PUT2("%.1f %d ghl ",xg[i], y)
+ }
+ }
+
+ if (n>1) /* beam */
+ if (bagpipe)
+ PUT4("%.1f %.1f %.1f %.1f gbm3 ", px[0],py[0],px[n-1],py[n-1])
+ else
+ PUT4("%.1f %.1f %.1f %.1f gbm2 ", px[0],py[0],px[n-1],py[n-1])
+
+
+ bet1=0.2; /* slur */
+ bet2=0.8;
+ yy=1000;
+ for (i=n-1;i>=0;i--) if (yg[i]<=yy) {yy=yg[i]; ii=i;}
+ x0=xg[ii];
+ y0=yg[ii]-5;
+ if (ii>0) { x0=x0-4; y0=y0+1; }
+ x3=x-1;
+ y3=s->ymn-5;
+ dy1=(x3-x0)*0.4;
+ if (dy1>3) dy1=3;
+ dy2=dy1;
+
+ if (yg[ii]>s->ymn+7){
+ x0=xg[ii]-1;
+ y0=yg[ii]-4.5;
+ y3=s->ymn+1.5;
+ x3=x-dx-5.5;
+ dy2=(y0-y3)*0.2;
+ dy1=(y0-y3)*0.8;
+ bet1=0.0;
+ }
+
+ if (y3>y0+4) {
+ y3=y0+4;
+ x0=xg[ii]+2;
+ y0=yg[ii]-4;
+ }
+
+ x1=bet1*x3+(1-bet1)*x0;
+ y1=bet1*y3+(1-bet1)*y0-dy1;
+ x2=bet2*x3+(1-bet2)*x0;
+ y2=bet2*y3+(1-bet2)*y0-dy2;
+
+ PUT4(" %.1f %.1f %.1f %.1f", x1,y1,x2,y2);
+ PUT4(" %.1f %.1f %.1f %.1f gsl\n", x3,y3,x0,y0);
+
+}
+
+/* ----- draw_basic_note: draw m-th head with accidentals and dots -- */
+void draw_basic_note (x,w,d,s,m)
+struct SYMBOL *s;
+float x,w,d;
+int m;
+{
+ int y,i,yy;
+ float dotx,doty,xx,dx,avail,add,fac;
+
+ y=3*(s->pits[m]-18)+s->yadd; /* height on staff */
+
+ xx=x+s->shhd[m]; /* draw head */
+ PUT2("%.1f %d", xx, y)
+ if (s->head==H_OVAL) PUT0(" HD")
+ if (s->head==H_EMPTY) PUT0(" Hd")
+ if (s->head==H_FULL) PUT0(" hd")
+ if (s->shhd[m]) {
+ yy=0;
+ if (y>=30) { yy=y; if (yy%6) yy=yy-3; }
+ if (y<=-6) { yy=y; if (yy%6) yy=yy+3; }
+ if (yy) PUT1(" %d hl", yy)
+ }
+
+ if (s->dots) { /* add dots */
+ if (y%6) { dotx=8; doty=0; }
+ else { dotx=8; doty=3; }
+ if (s->stem==-1)
+ dotx=dotx+s->xmx-s->shhd[m];
+ else
+ dotx=dotx+s->xmx-s->shhd[m];
+ if (s->dots && s->flags && (s->stem==1) && !(y%6))
+ if ((s->word_st==1) && (s->word_end==1) && (s->npitch==1))
+ dotx=dotx+DOTSHIFT;
+ if (s->head==H_EMPTY) dotx=dotx+1;
+ if (s->head==H_OVAL) dotx=dotx+2;
+ for (i=0;i<s->dots;i++) {
+ PUT2(" %.1f %.1f dt", dotx, doty)
+ dotx=dotx+3.5;
+ }
+ }
+
+ if (s->accs[m]) { /* add accidentals */
+ fac=1.0;
+ avail=d-w-3;
+ add=0.3*avail;
+ fac=1+add/s->wl;
+ if (fac<1) fac=1;
+ if (fac>1.2) fac=1.2;
+ dx=fac*s->shac[m];
+ if (s->accs[m]==A_SH) PUT1(" %.1f sh", dx)
+ if (s->accs[m]==A_NT) PUT1(" %.1f nt", dx)
+ if (s->accs[m]==A_FT) PUT1(" %.1f ft", dx)
+ if (s->accs[m]==A_DS) PUT1(" %.1f dsh", dx)
+ if (s->accs[m]==A_DF) PUT1(" %.1f dft", dx)
+ }
+}
+
+
+/* ----- draw_decorations ----- */
+float draw_decorations (x,s,tp)
+struct SYMBOL *s;
+float x;
+float *tp;
+{
+ int y,sig,k,deco,m;
+ float yc,xc,y1,top,top1,dx,dy;
+
+
+ top=-1000;
+ for (k=s->dc.n-1;k>=0;k--) { /* decos close to head */
+ deco=s->dc.t[k];
+
+/* if ((deco==D_STACC)||(deco==D_EMBAR)) { */ /* dot or bar mark */
+ if (deco==D_STACC) { /* dot */
+ sig=1; if (s->stem==1) sig=-1;
+ y=s->y+6*sig;
+ if (y<top+3) y=top+3;
+ if (!(y%6) && (y>=0) && (y<=24)) y+=3*sig;
+ if (top<y) top=y;
+ if (deco==D_STACC) PUT1(" %d stc",y)
+ else PUT1(" %d emb",y)
+ }
+
+ if (deco==D_SLIDE) { /* slide */
+ yc=s->ymn;
+ xc=5;
+ for (m=0;m<s->npitch;m++) {
+ dx=5-s->shhd[m];
+ if (s->head==H_OVAL) dx=dx+2.5;
+ if (s->accs[m]) dx=4-s->shhd[m]+s->shac[m];
+ dy=3*(s->pits[m]-18)+s->yadd-yc;
+ if ((dy<10) && (dx>xc)) xc=dx;
+ }
+ yc=s->ymn;
+ PUT2(" %.1f %.1f sld", yc, xc)
+ }
+ }
+
+ top1=top;
+ for (k=s->dc.n-1;k>=0;k--) { /* decos further away */
+ deco=s->dc.t[k];
+
+ if (deco==D_EMBAR) { /* bar */
+ yc=s->ymx+6;
+ if (s->stem==1) yc=s->ys+4;
+ if (yc<28) yc=28;
+ if (yc<top+3) yc=top+3;
+ if (top<yc+2) top=yc+2;
+ PUT1(" %.2f emb", yc)
+ }
+
+ if ((deco==D_GRACE)||(deco==D_HAT)||(deco==D_ATT)) { /* gracing,hat,att */
+ yc=s->ymx+9;
+ if (s->stem==1) yc=s->ys+5;
+ if (yc<30) yc=30;
+ if (yc<top+4) yc=top+4;
+ if (top<yc+2) top=yc+2;
+ if (deco==D_GRACE) PUT1(" %.2f grm", yc)
+ else if (deco==D_HAT) PUT1(" %.2f hat", yc)
+ else PUT1(" %.2f att", yc)
+ }
+
+ if (deco==D_ROLL) { /* roll sign */
+ y=s->y;
+ if (s->stem==1) {
+ yc=s->y-5;
+ if (yc>-2) yc=-2;
+ PUT1(" %.2f cpd", yc)
+ }
+ else {
+ yc=s->y+5;
+ if (s->dots && (!(y%6))) yc=s->y+6;
+ if (yc<26) yc=26;
+ if (yc<top+1) yc=top+1;
+ if (top<yc+8) top=yc+8;
+ PUT1(" %.2f cpu", yc)
+ }
+ }
+
+ if (deco==D_HOLD) { /* hold sign */
+ yc=27;
+ if (s->stem==1)
+ y1=s->ys+4;
+ else
+ y1=s->ymx+6;
+ if (yc<y1) yc=y1;
+ if (yc<top+4) yc=top+4;
+ if (top<yc+12) top=yc+12;
+ PUT1(" %.1f hld", yc)
+ }
+
+ if (deco==D_TRILL) { /* trill sign */
+ yc=30;
+ if (s->stem==1)
+ y1=s->ys+5;
+ else
+ y1=s->ymx+7;
+ if (yc<y1) yc=y1;
+ if (yc<top+1) yc=top+1;
+ if (top<yc+8) top=yc+8;
+ PUT1(" %.1f trl", yc)
+ }
+
+ if ((deco==D_UPBOW)||(deco==D_DOWNBOW)) { /* bowing signs */
+ yc=21;
+ if (s->stem==1)
+ y1=s->ys+4;
+ else
+ y1=s->ymx+8;
+ if (yc<y1) yc=y1;
+ if (yc<top+4) yc=top+4;
+ if (top<yc+10) top=yc+10;
+ if (deco==D_UPBOW) PUT1(" %.1f upb", yc)
+ if (deco==D_DOWNBOW) PUT1(" %.1f dnb", yc)
+ }
+ }
+ *tp=top;
+ return top1;
+}
+
+
+/* ----- draw_note ----- */
+float draw_note (x,w,d,s,fl,gchy)
+struct SYMBOL *s;
+float x,w,d;
+float *gchy;
+int fl;
+{
+ char c,cc;
+ int y,i,m,k;
+ float yc,slen,slen0,top,top2,xx;
+ slen0=STEM;
+
+ draw_gracenotes (x, w, d, s); /* draw grace notes */
+
+ c = 'd'; cc='u';
+ if (s->stem==1) { c='u'; cc='d'; }
+ slen=s->stem*(s->ys-s->y);
+
+ for (m=0;m<s->npitch;m++) {
+ if (m>0) PUT0(" ")
+ draw_basic_note (x,w,d,s,m); /* draw note heads */
+ xx=3*(s->pits[m]-18)+s->yadd-s->y;
+ xx=xx*xx;
+ if (xx<0.01) { /* add stem */
+ if (s->stem) PUT2(" %.1f s%c",slen,c)
+ if (fl && (s->flags>0)) /* add flags */
+ PUT3(" %.1f f%d%c",slen,s->flags,c)
+ }
+ if ((m>0) && (s->pits[m]==s->pits[m-1])) { /* unions */
+ if (s->stem) PUT2(" %.2f s%c",slen0,cc)
+ if (s->flags>0)
+ PUT3(" %.1f f%d%c",slen0,s->flags,cc)
+ }
+ }
+
+ top=draw_decorations (x,s,&top2); /* add decorations */
+
+ y = s->ymn; /* lower helper lines */
+ if (y<=-6) {
+ for (i=-6;i>=y;i=i-6) PUT1(" %d hl", i)
+ if (s->head==H_OVAL) PUT0("1")
+ }
+ y = s->ymx; /* upper helper lines */
+ if (y>=30) {
+ for (i=30;i<=y;i=i+6) PUT1(" %d hl", i)
+ if (s->head==H_OVAL) PUT0("1")
+ }
+
+ *gchy=38;
+ if (strlen(s->text)>0) { /* position guitar chord */
+ yc=*gchy;
+ if (yc<y+8) yc=y+8;
+ if (yc<s->ys+4) yc=s->ys+4;
+ for (k=0;k<s->dc.n;k++) {
+ if ((s->dc.t[k]==D_GRACE) && (yc<y+12)) yc=y+12;
+ }
+ if (yc<top2) yc=top2;
+ *gchy=yc;
+ }
+
+ PUT0("\n")
+
+ return top;
+
+}
+
+
+/* ----- vsh: up/down shift needed to get k*6 ----- */
+float vsh (x,dir)
+int dir;
+float x;
+{
+ int ix,iy,ir;
+ float x1,xx;
+ x1=x*dir;
+ ix=x1+600.999;
+ ir=ix%6;
+ iy=ix-600;
+ if (ir>0) iy=iy+6-ir;
+ xx=iy*dir;
+ return xx-x;
+}
+
+
+/* ----- rnd3: up/down shift needed to get k*3 ----- */
+float rnd3(x)
+float x;
+{
+ int ix,iy,ir;
+ float xx;
+
+ ix=x+600.999-1.5;
+ ir=ix%3;
+ iy=ix-600;
+ if (ir>0) iy=iy+3-ir;
+ xx=iy;
+ return xx-x;
+}
+
+
+/* ----- rnd6: up/down shift needed to get k*6 ----- */
+float rnd6(x)
+float x;
+{
+ int ix,iy,ir;
+ float xx;
+
+ ix=x+600.999-3.0;
+ ir=ix%6;
+ iy=ix-600;
+ if (ir>0) iy=iy+6-ir;
+ xx=iy;
+ return xx-x;
+}
+
+
+/* ----- b_pos ----- */
+float b_pos (stem,flags,b)
+int stem,flags;
+float b;
+{
+ float bb,d1,d2,add;
+ float top,bot;
+
+ if (stem==1) {
+ top=b;
+ bot=b-(flags-1)*BEAM_SHIFT-BEAM_DEPTH;
+ if (bot>26) return b;
+ }
+ else {
+ bot=b;
+ top=b+(flags-1)*BEAM_SHIFT+BEAM_DEPTH;
+ if (top<-2) return b;
+ }
+
+ d1=rnd6(top-BEAM_OFFSET);
+ d2=rnd6(bot+BEAM_OFFSET);
+ add=d1;
+ if (d1*d1>d2*d2) add=d2;
+ bb=b+add;
+
+/* printf ("stem %d top %.1f, bot%.1f, choices %.1f %.1f => %.1f\n",
+ stem, top,bot, d1,d2, add); */
+/* printf ("b_pos(%d) b=%.1f to %.1f\n", stem,b,bb); */
+
+ return bb;
+}
+
+
+/* ----- calculate_beam ----- */
+int calculate_beam (i0,bm)
+int i0;
+struct BEAM *bm;
+{
+ int j,j1,j2,i,stem,notes,flags;
+ float x,y,ys,a,b,max_stem_err,stem_err,min_stem,slen,yyg,yg,try;
+ float s,sx,sy,sxx,sxy,syy,delta,hh,dev,dev2,a0;
+
+ j1=i0; /* find first and last note in beam */
+ j2=-1;
+ stem=sym[j1].stem;
+ for (j=i0;j<nsym;j++)
+ if (sym[j].word_end) {
+ j2=j;
+ break;
+ }
+ if (j2==-1) {
+ return 0;
+ }
+
+ notes=flags=0; /* set x positions, count notes and flags */
+ for (j=j1;j<=j2;j++) {
+ if(sym[j].type==NOTE) {
+ sym[j].xs=sym[j].x+stem*STEM_XOFF;
+ sym[j].stem=stem;
+ if (sym[j].flags>flags) flags=sym[j].flags;
+ notes++;
+ }
+ }
+
+ s=sx=sy=sxx=sxy=syy=0; /* linear fit through stem ends */
+ for (j=j1;j<=j2;j++) if (sym[j].type==NOTE) {
+ x=sym[j].xs;
+ y=sym[j].ymx+STEM*stem;
+ s += 1; sx += x; sy += y;
+ sxx += x*x; sxy += x*y; syy += y*y;
+ }
+
+ delta=s*sxx-sx*sx; /* beam fct: y=ax+b */
+ a=(s*sxy-sx*sy)/delta;
+ b=(sy-a*sx)/s;
+
+ /* the next few lines modify the slope of the beam */
+ if (notes>=3) {
+ hh=syy-a*sxy-b*sy; /* flatten if notes not in line */
+ dev=0;
+ if (hh>0) {
+ dev2=hh/(notes-2);
+ if (dev2>0.5) a=BEAM_FLATFAC*a;
+ }
+ }
+
+
+ if (a>=0) a=BEAM_SLOPE*a/(BEAM_SLOPE+a); /* max steepness for beam */
+ else a=BEAM_SLOPE*a/(BEAM_SLOPE-a);
+
+
+ /* to decide if to draw flat etc. use normalized slope a0 */
+ a0=a*(sym[j2].xs-sym[j1].xs)/(20*(notes-1));
+
+ if ((a0<BEAM_THRESH) && (a0>-BEAM_THRESH)) a=0; /* flat below threshhold */
+
+ b=(sy-a*sx)/s; /* recalculate b for new slope */
+
+/* if (flags>1) b=b+2*stem;*/ /* leave a bit more room if several beams …
+
+ if (bagpipe) { b=-11; a=0; }
+
+ max_stem_err=0; /* check stem lengths */
+ for (j=j1;j<=j2;j++) if (sym[j].type==NOTE) {
+ if (sym[j].npitch==1) {
+ min_stem=STEM_MIN;
+ if (sym[j].flags==2) min_stem=STEM_MIN2;
+ if (sym[j].flags==3) min_stem=STEM_MIN3;
+ if (sym[j].flags==4) min_stem=STEM_MIN4;
+ }
+ else {
+ min_stem=STEM_CH_MIN;
+ if (sym[j].flags==2) min_stem=STEM_CH_MIN2;
+ if (sym[j].flags==3) min_stem=STEM_CH_MIN3;
+ if (sym[j].flags==4) min_stem=STEM_CH_MIN4;
+ }
+ min_stem=min_stem+BEAM_DEPTH+BEAM_SHIFT*(sym[j].flags-1);
+ ys=a*sym[j].xs+b;
+ if (stem==1) slen=ys-sym[j].ymx;
+ else slen=sym[j].ymn-ys;
+ stem_err=min_stem-slen;
+ if (stem_err>max_stem_err) max_stem_err=stem_err;
+ }
+
+ if (max_stem_err>0) /* shift beam if stems too short */
+ b=b+stem*max_stem_err;
+
+ for (j=j1+1;j<=j2;j++) if (sym[j].type==NOTE) { /* room for gracenotes */
+ for (i=0;i<sym[j].gr.n;i++) {
+ yyg=a*(sym[j].x-GSPACE0)+b;
+ yg=3*(sym[j].gr.p[i]-18)+sym[j].yadd;
+ if (stem==1) {
+ try=(yg+GSTEM)-(yyg-BEAM_DEPTH-2);
+ if (try>0) b=b+try;
+ }
+ else {
+ try=(yg)-(yyg+BEAM_DEPTH+7);
+ if (try<0) b=b+try;
+ }
+ }
+ }
+
+ if ((a<0.01) && (a>-0.01)) /* shift flat beams onto staff lines */
+ b=b_pos (stem,flags,b);
+
+ for (j=j1;j<=j2;j++) if (sym[j].type==NOTE) { /* final stems */
+ sym[j].ys=a*sym[j].xs+b;
+ }
+
+ bm->i1=j1; /* save beam parameters in struct */
+ bm->i2=j2;
+ bm->a=a;
+ bm->b=b;
+ bm->stem=stem;
+ bm->t=stem*BEAM_DEPTH;
+ return 1;
+}
+
+
+/* ----- rest_under_beam ----- */
+float rest_under_beam (x,head,bm)
+float x;
+int head;
+struct BEAM *bm;
+{
+ float y,tspace,bspace;
+ int j1,j2,j,nf,iy;
+
+ tspace=9;
+ bspace=11;
+ if ((head==H_OVAL)||(head==H_EMPTY)) tspace=bspace=4;
+
+ j1=bm->i1;
+ j2=bm->i2;
+ nf=0;
+ for (j=j1;j<=j2;j++)
+ if ((sym[j].type==NOTE)||(sym[j].flags>nf)) nf=sym[j].flags;
+
+ if (bm->stem==1) {
+ y=bm->a*x+bm->b;
+ y=y-BEAM_DEPTH-(nf-1)*BEAM_SHIFT;
+ y=y-tspace;
+ if (y>12) y=12;
+ }
+ else {
+ y=bm->a*x+bm->b;
+ y=y+BEAM_DEPTH+(nf-1)*BEAM_SHIFT;
+ y=y+bspace;
+ if (y<12) y=12;
+ }
+
+ if ((head==H_OVAL)||(head==H_EMPTY)) {
+ iy=(y+3.0)/6.0;
+ y=6*iy;
+ }
+
+ return y;
+}
+
+/* ----- draw_beam_num: draw number on a beam ----- */
+void draw_beam_num (bm,num,xn)
+struct BEAM *bm;
+int num;
+float xn;
+{
+ float yn;
+
+ if (bm->stem==-1)
+ yn=bm->a*xn+bm->b-12;
+ else
+ yn=bm->a*xn+bm->b+4;
+
+ PUT3("%.1f %.1f (%d) bnum\n", xn, yn, num)
+
+}
+
+
+/* ----- draw_beam: draw a single beam ----- */
+void draw_beam (x1,x2,dy,bm)
+float x1,x2,dy;
+struct BEAM *bm;
+{
+ float y1,y2;
+
+ y1=bm->a*x1+bm->b-bm->stem*dy;
+ y2=bm->a*x2+bm->b-bm->stem*dy;
+ PUT5("%.1f %.1f %.1f %.1f %.1f bm\n", x1,y1,x2,y2,bm->t)
+}
+
+/* ----- draw_beams: draw the beams for one word ----- */
+void draw_beams (bm)
+struct BEAM *bm;
+{
+ int j,j1,j2,j3,inbeam,k1,k2,num,p,r;
+ float x1,x2,xn;
+
+ j1=bm->i1;
+ j2=bm->i2;
+
+ /* make first beam over whole word */
+ x1=sym[j1].xs;
+ x2=sym[j2].xs;
+ num=sym[j1].u;
+
+ for (j=j1;j<=j2;j++) { /* numbers for nplets on same beam */
+ if (sym[j].p_plet>0) {
+ p=sym[j].p_plet;
+ r=sym[j].r_plet;
+ j3=j+r-1;
+ if (j3<=j2) {
+ xn=0.5*(sym[j].xs+sym[j3].xs);
+ draw_beam_num (bm,p,xn);
+ sym[j].p_plet=0;
+ }
+ }
+ }
+
+ draw_beam (x1,x2,0.0,bm);
+
+ /* second beams where two or more flags */
+ k1=0;
+ inbeam=0;
+ for (j=j1;j<=j2;j++) {
+ if (sym[j].type!=NOTE) continue;
+ if ((!inbeam) && (sym[j].flags>=2)) {
+ k1=j;
+ inbeam=1;
+ }
+ if (inbeam && ((sym[j].flags<2) || (j==j2))) {
+ if ((sym[j].flags>=2) && (j==j2)) k2=j;
+ x1=sym[k1].xs;
+ x2=sym[k2].xs;
+ inbeam=0;
+ if (k1==k2) {
+ if (k1==j1) draw_beam (x1+BEAM_STUB,x1,BEAM_SHIFT,bm);
+ else draw_beam (x1-BEAM_STUB,x1,BEAM_SHIFT,bm);
+ }
+ else
+ draw_beam (x1,x2,BEAM_SHIFT,bm);
+ inbeam=0;
+ }
+ k2=j;
+ }
+
+ /* third beams where three or more flags */
+ k1=0;
+ inbeam=0;
+ for (j=j1;j<=j2;j++) {
+ if (sym[j].type!=NOTE) continue;
+ if ((!inbeam) && (sym[j].flags>=3)) {
+ k1=j;
+ inbeam=1;
+ }
+ if (inbeam && ((sym[j].flags<3) || (j==j2))) {
+ if ((sym[j].flags>=3) && (j==j2)) k2=j;
+ x1=sym[k1].xs;
+ x2=sym[k2].xs;
+ inbeam=0;
+ if (k1==k2) {
+ if (k1==j1) draw_beam (x1+BEAM_STUB,x1,2*BEAM_SHIFT,bm);
+ else draw_beam (x1-BEAM_STUB,x1,2*BEAM_SHIFT,bm);
+ }
+ else
+ draw_beam (x1,x2,2*BEAM_SHIFT,bm);
+ inbeam=0;
+ }
+ k2=j;
+ }
+
+ /* fourth beams where four or more flags */
+ k1=0;
+ inbeam=0;
+ for (j=j1;j<=j2;j++) {
+ if (sym[j].type!=NOTE) continue;
+ if ((!inbeam) && (sym[j].flags>=4)) {
+ k1=j;
+ inbeam=1;
+ }
+ if (inbeam && ((sym[j].flags<4) || (j==j2))) {
+ if ((sym[j].flags>=4) && (j==j2)) k2=j;
+ x1=sym[k1].xs;
+ x2=sym[k2].xs;
+ inbeam=0;
+ if (k1==k2) {
+ if (k1==j1) draw_beam (x1+BEAM_STUB,x1,3*BEAM_SHIFT,bm);
+ else draw_beam (x1-BEAM_STUB,x1,3*BEAM_SHIFT,bm);
+ }
+ else
+ draw_beam (x1,x2,3*BEAM_SHIFT,bm);
+ inbeam=0;
+ }
+ k2=j;
+ }
+
+}
+
+/* ----- extreme: return min or max, depending on s ----- */
+float extreme (s, a, b)
+float s,a,b;
+{
+
+ if (s>0) {
+ if (a>b) return a;
+ return b;
+ }
+ else {
+ if (a<b) return a;
+ return b;
+ }
+}
+
+/* ----- draw_bracket ----- */
+void draw_bracket (p,j1,j2)
+int p,j1,j2;
+{
+ float x1,x2,y1,y2,xm,ym,s,s0,xx,yy,yx,dy;
+ int j;
+
+ x1=sym[j1].x-4;
+ x2=sym[j2].x+4;
+ y1=sym[j1].ymx+10;
+ y2=sym[j2].ymx+10;
+
+ if (sym[j1].stem==1) { y1=sym[j1].ys+4; x1=x1+3; }
+ if (sym[j2].stem==1) { y2=sym[j2].ys+4; x2=x2+3; }
+
+ if (y1<30) y1=30;
+ if (y2<30) y2=30;
+
+ xm=0.5*(x1+x2);
+ ym=0.5*(y1+y2);
+
+ s=(y2-y1)/(x2-x1);
+ s0=(sym[j2].ymx-sym[j1].ymx)/(x2-x1);
+ if (s0>0) {
+ if (s<0) s=0; if (s>s0) s=s0;
+ }
+ else {
+ if (s>0) s=0; if (s<s0) s=s0;
+ }
+ if (s*s < 0.2*0.2) s=0; /* flat if below limit */
+
+
+ dy=0; /* shift up bracket if needed */
+ for (j=j1;j<=j2;j++) {
+ if ((sym[j].type==NOTE) || (sym[j].type==REST)) {
+ xx=sym[j].x;
+ yy=ym+(xx-xm)*s;
+ yx=sym[j].ymx+10;
+ if (sym[j].stem==1) yx=sym[j].ys+5;
+ if (yx-yy>dy) dy=yx-yy;
+ }
+ }
+ ym=ym+dy;
+ y1=ym+s*(x1-xm);
+ y2=ym+s*(x2-xm);
+
+ /* shift up guitar chords, if needed */
+ for (j=j1;j<=j2;j++) {
+ if ((sym[j].type==NOTE) || (sym[j].type==REST)) {
+ xx=sym[j].x;
+ yy=ym+(xx-xm)*s;
+ if (sym[j].gchy<yy+4) sym[j].gchy=yy+4;
+ }
+ }
+
+ xx=xm-6;
+ yy=ym+s*(xx-xm);
+ PUT4("%.1f %.1f %.1f %.1f hbr ", x1,y1,xx,yy)
+
+ xx=xm+6;
+ yy=ym+s*(xx-xm);
+ PUT4("%.1f %.1f %.1f %.1f hbr ", x2,y2,xx,yy)
+
+ yy=0.5*(y1+y2);
+ PUT3("%.1f %.1f (%d) bnum\n", xm, yy-4, p)
+
+}
+
+/* ----- draw_nplet_brackets ----- */
+void draw_nplet_brackets ()
+{
+ int i,j,k,p,r,c;
+
+ for (i=0;i<nsym;i++) {
+ if ((sym[i].type==NOTE) || (sym[i].type==REST)) {
+ if (sym[i].p_plet>0) {
+ p=sym[i].p_plet;
+ r=sym[i].r_plet;
+ c=r;
+ k=i;
+ for (j=i;j<nsym;j++) {
+ if ((sym[j].type==NOTE) || (sym[j].type==REST)) {
+ c--;
+ k=j;
+ if (c==0) break;
+ }
+ }
+ draw_bracket (p,i,k);
+ }
+ }
+ }
+}
+
+
+/* ----- slur_direction: decide whether slur goes up or down --- */
+float slur_direction (k1,k2)
+int k1,k2;
+{
+ float s;
+ int i,are_stems,are_downstems,are_bars,y_max,notes;
+
+ are_stems=are_downstems=are_bars=0;
+ notes=0;
+ y_max=300;
+ for (i=k1;i<=k2;i++) {
+ if (sym[i].type==BAR) are_bars=1;
+ if (sym[i].type==NOTE) {
+ notes++;
+ if (sym[i].stem != 0 ) are_stems=1;
+ if (sym[i].stem == -1 ) are_downstems=1;
+ if (sym[i].ymn<y_max) y_max=sym[i].ymn;
+ }
+ }
+ s=-1;
+ if (are_downstems) s=1;
+ if (!are_stems) {
+ s=1;
+ if (y_max<12) s=-1;
+ }
+
+ /* next line tries to put long phrasings on top */
+ if (are_bars && (notes>5)) s=1;
+
+ return s;
+}
+
+/* ----- output_slur: output slur -- --- */
+void output_slur (x1,y1,x2,y2,s,height,shift)
+float x1,y1,x2,y2,s,height,shift;
+{
+ float alfa,beta,mx,my,xx1,yy1,xx2,yy2,dx,dy,dz,a,add;
+
+ alfa=0.3;
+ beta=0.45;
+
+ /* for wide flat slurs, make shape more square */
+ dy=y2-y1;
+ if (dy<0) dy=-dy;
+ dx=x2-x1;
+ if (dx<0) dx=-dx;
+ a=dy/dx;
+ if ((a<0.7) && dx>40) {
+ add=0.2*(dx-40)/100;
+ alfa=0.3+add;
+ if (alfa>0.7) alfa=0.7;
+ }
+
+
+ /* alfa, beta, and height determine Bezier control points pp1,pp2
+ *
+ * X====alfa===|===alfa=====X
+ * / | \
+ * pp1 | pp2
+ * / height \
+ * beta | beta
+ * / | \
+ * p1 m p2
+ *
+ */
+
+
+ mx=0.5*(x1+x2);
+ my=0.5*(y1+y2);
+
+ xx1=mx+alfa*(x1-mx);
+ yy1=my+alfa*(y1-my)+height;
+ xx1=x1+beta*(xx1-x1);
+ yy1=y1+beta*(yy1-y1);
+
+ xx2=mx+alfa*(x2-mx);
+ yy2=my+alfa*(y2-my)+height;
+ xx2=x2+beta*(xx2-x2);
+ yy2=y2+beta*(yy2-y2);
+
+ dx=0.03*(x2-x1);
+ if (dx>10.0) dx=10.0;
+ dy=1.0;
+ dz=0.20;
+ if (x2-x1>100) dz=dz+0.001*(x2-x1);
+ if (dz>0.6) dz=0.6;
+
+ PUT4("%.1f %.1f %.1f %.1f ",
+ xx2-dx, yy2+shift+s*dy, xx1+dx, yy1+shift+s*dy)
+ PUT3("%.1f %.1f 0 %.1f ", x1,y1+shift+s*dz,s*dz)
+ PUT4("%.1f %.1f %.1f %.1f ", xx1,yy1+shift,xx2,yy2+shift)
+ PUT4("%.1f %.1f %.1f %.1f SL\n", x2,y2+shift, x1,y1+shift)
+
+
+/*PUT4("%.2f %.2f %.2f %.2f ", xx1,yy1+shift,xx2,yy2+shift)
+ PUT4("%.2f %.2f %.2f %.2f sl\n", x2,y2+shift, x1,y1+shift)*/
+
+ return;
+}
+
+/* ----- draw_slur (not a pretty routine, this) ----- */
+void draw_slur (k1,k2,nn,level)
+int k1,k2,level,nn;
+{
+ float x01,x02,y01,y02;
+ float x1,y1,x2,y2,yy,height,addx,addy;
+ float s,shift,hmin,a;
+ float x,y,z,h,dx,dy;
+ int i;
+
+ s=slur_direction (k1,k2);
+
+ /* fix endpoints */
+ if (sym[k1].type==NOTE) { /* here if k1 points to note */
+ x01=sym[k1].x;
+ yy=sym[k1].ymn; if (s>0) yy=sym[k1].ymx;
+ y01=extreme(s,yy+s*6,sym[k1].ys+s*2);
+ if (sym[k1].word_end) {
+ yy=sym[k1].ymn; if (s>0) yy=sym[k1].ymx;
+ y01=yy+s*6;
+ if ((sym[k1].stem==1)&&(s==1)) x01=x01+4;
+ }
+ if ((s>0) && (y01<sym[k1].dc.top+2.5)) y01=sym[k1].dc.top+2.5;
+ }
+
+ if (sym[k2].type==NOTE) { /* here if k2 points to note */
+ x02=sym[k2].x;
+ yy=sym[k2].ymn; if (s>0) yy=sym[k2].ymx;
+ y02=extreme(s,yy+s*6,sym[k2].ys+s*2);
+ if (sym[k2].word_st) {
+ yy=sym[k2].ymn; if (s>0) yy=sym[k2].ymx;
+ y02=yy+s*6;
+ if ((sym[k2].stem==-1)&&(s==-1)) x02=x02-3;
+ }
+ if ((s>0) && (y02<sym[k2].dc.top+2.5)) y02=sym[k2].dc.top+2.5;
+ }
+
+ if (sym[k1].type!=NOTE) {
+ x01=sym[k1].x+sym[k1].wr;
+ y01=y02+1.2*s;
+ if (nn>1) {
+ if(s==1) { if (y01<28) y01=28; }
+ else { if (y01>-4) y01=-4; }
+ }
+ }
+
+ if (sym[k2].type!=NOTE) {
+ x02=sym[k2].x;
+ y02=y01+1.2*s;
+ if (nn>1) {
+ if (s==1) {if (y02<28) y02=28; }
+ else {if (y02>-4) y02=-4; }
+ }
+ }
+
+ /* shift endpoints */
+ addx=0.04*(x02-x01);
+ if (addx>3.0) addx=3.0;
+ addy=0.02*(x02-x01);
+ if (addy>3.0) addy=3.0;
+ x1 = x01+addx;
+ x2 = x02-addx;
+ y1=y01+s*addy;
+ y2=y02+s*addy;
+
+ a=(y2-y1)/(x2-x1); /* slur steepness */
+ if (a > SLUR_SLOPE) a= SLUR_SLOPE;
+ if (a < -SLUR_SLOPE) a=-SLUR_SLOPE;
+ if (a>0) {
+ if (s == 1) y1=y2-a*(x2-x1);
+ if (s == -1) y2=y1+a*(x2-x1);
+ }
+ else {
+ if (s == -1) y1=y2-a*(x2-x1);
+ if (s == 1) y2=y1+a*(x2-x1);
+ }
+
+ /* for big vertical jump, shift endpoints */
+ y=y2-y1; if (y>8) y=8; if (y<-8) y=-8;
+ z=y; if(z<0) z=-z; dx=0.5*z; dy=0.3*z;
+ if (y>0) {
+ if (s==1) { x2=x2-dx; y2=y2-dy; }
+ if (s==-1) { x1=x1+dx; y1=y1+dy; }
+ }
+ else {
+ if (s==1) { x1=x1+dx; y1=y1-dy; }
+ if (s==-1) { x2=x2-dx; y2=y2+dy; }
+ }
+
+ h=0;
+ for (i=k1+1; i<k2; i++)
+ if (sym[i].type==NOTE) {
+ x = sym[i].x;
+ yy = sym[i].ymn; if (s>0) yy=sym[i].ymx;
+ y = extreme (s, yy+6*s, sym[i].ys+2*s);
+ z = (y2*(x-x1)+y1*(x2-x))/(x2-x1);
+ h = extreme (s, h, y-z);
+ }
+
+ y1=y1+0.4*h;
+ y2=y2+0.4*h;
+ h=0.6*h;
+
+ hmin=s*(0.03*(x2-x1)+8);
+ if (nn>3) hmin=s*(0.12*(x2-x1)+12);
+ height = extreme (s, hmin, 3.0*h);
+ height = extreme (-s, height, s*50);
+
+ y=y2-y1; if (y<0) y=-y;
+ if ((s==1) && (height< 0.8*y)) height=0.8*y;
+ if ((s==-1) && (height>-0.8*y)) height=-0.8*y;
+
+ shift=3*s*level;
+
+ output_slur (x1,y1,x2,y2,s,height,shift);
+
+ return;
+}
+
+
+/* ----- prev_scut, next_scut: find place to terminate/start slur --- */
+int next_scut (i)
+int i;
+{
+ int j,cut,ok;
+
+ cut=nsym-1;
+ for (j=i+1;j<nsym;j++) {
+ ok=0;
+ if (sym[j].type==BAR) {
+ if (sym[j].u==B_RREP) ok=1;
+ if (sym[j].u==B_DREP) ok=1;
+ if (sym[j].u==B_FAT1) ok=1;
+ if (sym[j].u==B_FAT2) ok=1;
+ if (sym[j].v==2) ok=1;
+ }
+ if(ok) {
+ cut=j;
+ break;
+ }
+ }
+ return cut;
+}
+
+int prev_scut(i)
+int i;
+{
+ int j,cut,ok;
+
+ cut=-1;
+ for (j=i;j>=0;j--) {
+ ok=0;
+ if (sym[j].type==BAR) {
+ if (sym[j].u==B_LREP) ok=1;
+ if (sym[j].u==B_DREP) ok=1;
+ if (sym[j].u==B_FAT1) ok=1;
+ if (sym[j].u==B_FAT2) ok=1;
+ if (sym[j].v==2) ok=1;
+ }
+ if(ok) {
+ cut=j;
+ break;
+ }
+ }
+
+ if (cut==-1) { /* return sym before first note */
+ cut=0;
+ for (j=0;j<nsym;j++) {
+ if((sym[j].type==REST) || (sym[j].type==NOTE)) {
+ cut=j-1;
+ break;
+ }
+ }
+ }
+
+ return cut;
+}
+
+
+/* ----- draw_chord_slurs ----- */
+void draw_chord_slurs(k1,k2,nh1,nh2,nslur,mhead1,mhead2,job)
+int k1,k2,nh1,nh2,nslur,mhead1[MAXHD],mhead2[MAXHD],job;
+{
+
+ int i,pbot,ptop,m1,m2,p1,p2,y,cut;
+ float s,x1,y1,x2,y2,height,shift,addx,addy;
+
+ if (nslur==0) return;
+
+ pbot=1000;
+ ptop=-1000;
+ for (i=0;i<sym[k1].npitch;i++) {
+ p1=sym[k1].pits[i];
+ if (p1<pbot) pbot=p1;
+ if (p1>ptop) ptop=p1;
+ }
+
+ for (i=0;i<nslur;i++) {
+ m1=mhead1[i];
+ m2=mhead2[i];
+ p1=sym[k1].pits[m1];
+ p2=sym[k2].pits[m2];
+ s=slur_direction (k1,k2);
+ if (p1==pbot) s=-1;
+ if (p1==ptop) s=1;
+
+ x1=sym[k1].x;
+ x2=sym[k2].x;
+ if (job==2) {
+ cut=next_scut(k1);
+ x2=sym[cut].x;
+ if (cut==k1) x2=x1+30;
+ }
+
+ if (job==1) {
+ cut=prev_scut(k1);
+ x1=sym[cut].x;
+ if (cut==k1) x2=x1-30;
+ }
+
+ addx=0.04*(x2-x1);
+ if (addx>3.0) addx=3.0;
+ addy=0.02*(x2-x1);
+ if (addy>3.0) addy=3.0;
+
+ x1=x1+3+addx;
+ x2=x2-3-addx;
+ if ((s==1) && (sym[k1].stem==1)) x1=x1+1.5;
+ if ((s==-1) && (sym[k2].stem==-1)) x2=x2-1.5;
+
+ y=3*(p1-18)+sym[k1].yadd;
+ y1=y2=y+s*(4+addy);
+ y=3*(p2-18)+sym[k2].yadd;
+ y2=y+s*(4+addy);
+
+ if ((s==1) && !(y%6) && (sym[k1].dots>0)) {
+ y2=y1=y+s*(5.5+addy);
+ x1=x1-2;
+ x2=x2+2;
+ }
+ height=s*(0.04*(x2-x1)+5);
+ shift=0;
+ output_slur (x1,y1,x2,y2,s,height,shift);
+ }
+
+}
+
+
+
+/* ----- draw_slurs: draw slurs/ties between neighboring notes/chords */
+void draw_slurs (k1,k2,job)
+int k1,k2,job;
+{
+ int i,m1,m2;
+ int mhead1[MAXHD],mhead2[MAXHD],nslur,nh1,nh2;
+
+ if (nbuf+100>BUFFSZ)
+ rx ("PS output exceeds reserved space per staff",
+ " -- increase BUFFSZ1");
+
+ nslur=0;
+
+ if (job==2) { /* half slurs from last note in line */
+ nh1=sym[k1].npitch;
+ for (i=1;i<=nh1;i++) {
+ for (m1=0;m1<nh1;m1++) {
+ if (sym[k1].sl1[m1]==i) {
+ nslur=nslur+1;
+ mhead1[nslur-1]=m1;
+ }
+ if (sym[k1].ti1[m1]) {
+ nslur=nslur+1;
+ mhead1[nslur-1]=m1;
+ }
+ }
+ }
+ draw_chord_slurs(k1,k1,nh1,nh1,nslur,mhead1,mhead1,job);
+ return;
+ }
+
+ if (job==1) { /* half slurs to first note in line */
+ nh1=sym[k1].npitch;
+ for (i=1;i<=nh1;i++) {
+ for (m1=0;m1<nh1;m1++) {
+ if (sym[k1].sl2[m1]==i) {
+ nslur=nslur+1;
+ mhead1[nslur-1]=m1;
+ }
+ if (sym[k1].ti2[m1]) {
+ nslur=nslur+1;
+ mhead1[nslur-1]=m1;
+ }
+ }
+ }
+ draw_chord_slurs(k1,k1,nh1,nh1,nslur,mhead1,mhead1,job);
+ return;
+ }
+
+ /* real 2-note case: set up list of slurs/ties to draw */
+ if ((sym[k1].type==NOTE) && (sym[k2].type==NOTE)) {
+ nh1=sym[k1].npitch;
+ nh2=sym[k2].npitch;
+
+ for (m1=0;m1<nh1;m1++) {
+ if (sym[k1].ti1[m1]) {
+ for (m2=0;m2<nh2;m2++) {
+ if (sym[k2].pits[m2]==sym[k1].pits[m1]) {
+ nslur++;
+ mhead1[nslur-1]=m1;
+ mhead2[nslur-1]=m2;
+ break;
+ }
+ }
+ }
+ }
+
+ for (i=1;i<=nh1;i++) {
+ for (m1=0;m1<nh1;m1++) {
+ if (sym[k1].sl1[m1]==i) {
+ nslur++;
+ mhead1[nslur-1]=m1;
+ mhead2[nslur-1]=-1;
+ for (m2=0;m2<nh2;m2++) {
+ if (sym[k2].sl2[m2]==i) mhead2[nslur-1]=m2;
+ }
+ if (mhead2[nslur-1]==-1) nslur--;
+ }
+ }
+ }
+ }
+
+ draw_chord_slurs(k1,k2,nh1,nh2,nslur,mhead1,mhead2,job);
+}
+
+
+
+/* ----- draw_phrasing: draw phrasing slur between two symbols --- */
+void draw_phrasing (k1,k2,level)
+int k1,k2,level;
+{
+ int nn,i;
+
+ if (k1==k2) return;
+ if (nbuf+100>BUFFSZ)
+ rx ("PS output exceeds reserved space per staff",
+ " -- increase BUFFSZ1");
+ nn=0;
+ for (i=k1;i<=k2;i++)
+ if ((sym[i].type==NOTE)||(sym[i].type==REST)) nn++;
+
+ draw_slur (k1,k2,nn,level);
+
+}
+
+/* ----- draw_all_slurs: draw all slurs/ties between neighboring notes */
+void draw_all_slurs ()
+{
+ int i,i1,i2;
+
+ i1=-1;
+ for (i=0;i<nsym;i++) {
+ if (sym[i].type==NOTE) {
+ i1=i;
+ break;
+ }
+ }
+ if (i1<0) return;
+ draw_slurs(i1,i1,1);
+
+ for (;;) {
+ i2=-1;
+ for (i=i1+1;i<nsym;i++) {
+ if (sym[i].type==NOTE) {
+ i2=i;
+ break;
+ }
+ }
+ if (i2<0) break;
+ draw_slurs(i1,i2,0);
+ i1=i2;
+ }
+
+ draw_slurs(i1,i1,2);
+
+}
+
+/* ----- draw_all_phrasings: draw all phrasing slurs for one staff ----- */
+void draw_all_phrasings ()
+{
+ int i,j,k,cut,pass,num;
+
+ for (pass=0;;pass++) {
+ num=0;
+ for (i=0;i<nsym;i++) {
+
+ if (sym[i].slur_st) {
+ k=-1; /* find matching slur end */
+ for (j=i+1;j<nsym;j++) {
+ if (sym[j].slur_st && (!sym[j].slur_end)) break;
+ if (sym[j].slur_end) {
+ k=j;
+ break;
+ }
+ }
+ if (k>=0) {
+ cut=next_scut(i);
+ if (cut<k) {
+ draw_phrasing (i,cut,pass);
+ cut=prev_scut(k);
+ draw_phrasing (cut,k,pass);
+ }
+ else {
+ draw_phrasing (i,k,pass);
+ }
+ num++;
+ sym[i].slur_st--;
+ sym[k].slur_end--;
+ }
+ }
+ }
+ if (num==0) break;
+ }
+
+ /* do unbalanced slurs still left over */
+
+ for (i=0;i<nsym;i++) {
+ if (sym[i].slur_end) {
+ cut=prev_scut(i);
+ draw_phrasing (cut,i,0);
+ }
+ if (sym[i].slur_st) {
+ cut=next_scut(i);
+ draw_phrasing (i,cut,0);
+ }
+ }
+
+}
+
+/* ----- check_bars1 ---------- */
+void check_bars1 (ip1,ip2)
+int ip1,ip2;
+{
+ int v,i,j,k1,k2;
+ float dx;
+
+ /* check for inelegant bar combinations within one line */
+ i=j=ip1;
+ for (;;) {
+ if (xp[i].type==BAR && xp[j].type==BAR && i!=j) {
+ dx=0;
+ for (v=0;v<nvoice;v++) {
+ k1=xp[j].p[v];
+ k2=xp[i].p[v];
+ if (k1>=0 && k2>=0) {
+ if (symv[v][k1].u==B_RREP && symv[v][k2].u==B_LREP) {
+ symv[v][k2].u=B_DREP;
+ symv[v][k1].u=B_INVIS;
+ dx=-4.0;
+ }
+ }
+ }
+ xp[i].x=xp[i].x+dx;
+ }
+ j=i;
+ i=xp[i].next;
+ if (i==ip2) break;
+ }
+
+}
+
+
+/* ----- check_bars2 ---------- */
+void check_bars2 (ip1,ip2)
+int ip1,ip2;
+{
+ int i,ip,v;
+
+ /* check whether to split up last bar over two lines */
+ ip=xp[ip2].prec;
+ for (v=0;v<nvoice;v++) {
+ strcpy(voice[v].insert_text,"");
+ voice[v].insert_bnum = 0;
+ voice[v].insert_space = 0;
+ voice[v].insert_num = 0;
+ voice[v].insert_btype = 0;
+
+ i=xp[ip].p[v];
+ if (i>=0) {
+ if (symv[v][i].type==BAR) {
+ if (symv[v][i].u==B_LREP) {
+ symv[v][i].u=B_SNGL;
+ voice[v].insert_btype=B_LREP;
+ voice[v].insert_num=0;
+ }
+ else if (symv[v][i].u==B_DREP) {
+ symv[v][i].u=B_RREP;
+ voice[v].insert_btype=B_LREP;
+ voice[v].insert_num=0;
+ }
+ else if ((symv[v][i].u==B_RREP) && (symv[v][i].v!=0)) {
+ voice[v].insert_btype=B_INVIS;
+ voice[v].insert_num=symv[v][i].v;
+ symv[v][i].v=0;
+ }
+ else if ((symv[v][i].u==B_SNGL) && (symv[v][i].v!=0)) {
+ voice[v].insert_btype=B_INVIS;
+ voice[v].insert_num=symv[v][i].v;
+ symv[v][i].v=0;
+ }
+
+ /* if number or label on last bar, move to next line */
+ if (symv[v][i].t || (strlen(symv[v][i].text)>0)) {
+ if (symv[v][i+1].type==BAR) {
+ if (symv[v][i+1].t==0) symv[v][i+1].t=symv[v][i].t;
+ if (strlen(symv[v][i+1].text)==0)
+ strcpy(symv[v][i+1].text,symv[v][i].text);
+ }
+ else {
+ if (!voice[v].insert_btype) voice[v].insert_btype=B_INVIS;
+ voice[v].insert_space=symv[v][i].wr;
+ voice[v].insert_bnum=symv[v][i].t;
+ strcpy(voice[v].insert_text,symv[v][i].text);
+ strcpy(symv[v][i].text,"");
+ symv[v][i].t=0;
+ }
+ }
+
+
+ }
+ }
+ }
+
+
+}
+
+
+
+/* ----- draw_vocals ----- */
+void draw_vocals (fp,nwl,botnote,bspace,botpos)
+FILE *fp;
+float botnote,bspace;
+float *botpos;
+int nwl;
+{
+ int i,hyflag,l,j;
+ float x,x0,yword,lastx,spc,vfsize,w,swfac,lskip;
+ char word[81],t[81];
+
+ if (nwl<=0) return;
+ vfsize=cfmt.vocalfont.size;
+ lskip=1.1*vfsize;
+ set_font (fp, cfmt.vocalfont, 0);
+ yword=-cfmt.vocalspace;
+ swfac=1.05;
+ if (strstr(cfmt.vocalfont.name,"Helvetica")) swfac=1.10;
+ if (botnote-cfmt.vocalfont.size<yword)
+ yword=botnote-cfmt.vocalfont.size;
+
+ for (j=0;j<nwl;j++) {
+ hyflag=0;
+ lastx=-10;
+ for (i=0;i<nsym;i++) {
+ if (sym[i].wordp[j]) {
+ strcpy(word,sym[i].wordp[j]);
+ x0=sym[i].x;
+ l=strlen(word);
+
+ if (hyflag) {
+ tex_str (word,t,&w);
+ spc=x0-VOCPRE*vfsize*swfac*w-lastx;
+ x = lastx+0.5*spc-0.5*swfac*vfsize*cwid('-');
+ PUT2("%.1f %.1f whf ",x,yword)
+ hyflag=0;
+ }
+
+ if ((l>1) && (word[l-1]=='^')) {
+ word[l-1]='\0';
+ hyflag=1;
+ }
+
+ if ((l==1) && (word[0]=='_')) {
+ if (lastx<0) lastx=sym[i-1].x+sym[i-1].wr;
+ PUT3("%.1f %.1f %.1f wln ", lastx+3, sym[i].x+1, yword)
+ }
+ else if ((l==1) && (word[0]=='^')) {
+ PUT2("%.1f %.1f whf ", x0, yword)
+ lastx=x0+vfsize*swfac*w;
+ }
+ else {
+ tex_str (word,t,&w);
+ if (isdig(word[0]))
+ x0=x0-3*vfsize*swfac*cwid('1');
+ else
+ x0=x0-VOCPRE*vfsize*swfac*w;
+ if (strcmp(t," ")) PUT3("(%s) %.1f %.1f wd ", t, x0, yword)
+ lastx=x0+vfsize*swfac*w;
+ }
+ }
+ }
+ if (hyflag) PUT2("%.1f %.1f whf ",lastx+5,yword)
+ yword=yword-lskip;
+ }
+ *botpos=yword + lskip - bspace;
+}
+
+/* ----- draw_symbols: draw symbols at proper positions on staff ----- */
+void draw_symbols (fp,bspace,bpos,is_top)
+FILE *fp;
+float bspace,*bpos;
+int is_top;
+{
+ int i,inbeam,j,nwl;
+ float x,y,top,xl,d,w,gchy,botnote,botpos,spc,swfac;
+ struct BEAM bm;
+ char t[81];
+
+ inbeam=do_words=0;
+ botnote=0;
+ nwl=0;
+ for (i=0;i<nsym;i++) { /* draw the symbols */
+
+ for (j=0;j<NWLINE;j++)
+ if (sym[i].wordp[j]) {
+ if (j+1>nwl) nwl=j+1;
+ }
+ if (nbuf+100>BUFFSZ)
+ rx ("PS output exceeds reserved space per staff",
+ " -- increase BUFFSZ1");
+ x=sym[i].x;
+
+ switch (sym[i].type) {
+
+ case NOTE:
+ xl=0; w=sym[i].wl;
+ if (i>0) { xl=sym[i-1].x; w=w+sym[i-1].wr; }
+ d=x-xl;
+
+ if (sym[i].word_st && !sym[i].word_end) {
+ if (calculate_beam (i,&bm)) inbeam=1;
+ }
+ if (inbeam) {
+ top=draw_note(x,w,d,&sym[i],0,&gchy);
+ if (i==bm.i2) {
+ inbeam=0;
+ draw_beams (&bm);
+ }
+ }
+ else {
+ top=draw_note(x,w,d,&sym[i],1,&gchy);
+ }
+ sym[i].gchy=gchy;
+ sym[i].dc.top=top;
+ if (sym[i].ymn-5<botnote) botnote=sym[i].ymn-5;
+ break;
+
+ case REST:
+ y=sym[i].y;
+ if (inbeam) y=rest_under_beam (sym[i].x,sym[i].head,&bm);
+ draw_rest(x,y,sym[i],&gchy);
+ sym[i].gchy=gchy;
+ break;
+
+ case BAR:
+ if (sym[i].v) set_ending(i);
+ draw_bar (x,sym[i]);
+ break;
+
+ case CLEF:
+ if (sym[i].u==TREBLE) {
+ if (sym[i].v) PUT1("%.1f stclef\n", x)
+ else PUT1("%.1f tclef\n", x)
+ }
+ else if (sym[i].u==BASS) {
+ if (sym[i].v) PUT1("%.1f sbclef\n", x)
+ else PUT1("%.1f bclef\n", x)
+ }
+ else if (sym[i].u==ALTO) {
+ if (sym[i].v) PUT1("%.1f scclef\n", x)
+ else PUT1("%.1f cclef\n", x)
+ }
+ else
+ bug("unknown clef type", 0);
+ voice[ivc].key.ktype=sym[i].u;
+ break;
+
+ case TIMESIG:
+ draw_timesig (x,sym[i]);
+ break;
+
+ case KEYSIG:
+ voice[ivc].key.sf=draw_keysig (x,sym[i]);
+ break;
+
+ case INVISIBLE:
+ break;
+
+ default:
+ printf (">>> cannot draw symbol type %d\n", sym[i].type);
+ }
+ }
+
+ draw_nplet_brackets ();
+
+/*| if (voice[ivc].do_gch) draw_barnums (fp); |*/
+
+
+ if (ivc==ivc0) draw_barnums (fp);
+
+
+ /* draw guitar chords */
+ if (voice[ivc].do_gch) {
+ set_font(fp,cfmt.gchordfont,0);
+ swfac=1.0;
+ if (strstr(cfmt.gchordfont.name,"Times-Roman")) swfac=1.00;
+ if (strstr(cfmt.gchordfont.name,"Times-Bold")) swfac=1.05;
+ if (strstr(cfmt.gchordfont.name,"Helvetica")) swfac=1.10;
+ if (strstr(cfmt.gchordfont.name,"Helvetica-Bold")) swfac=1.15;
+
+ for (i=0;i<nsym;i++) {
+ if ((sym[i].type==NOTE)||(sym[i].type==REST)) {
+ if (strlen(sym[i].text)>0) {
+ tex_str (sym[i].text,t,&w);
+ w=cfmt.gchordfont.size*w;
+ spc=w*GCHPRE;
+ if (spc>8.0) spc=8.0;
+ PUT3("%.1f %.1f (%s) gc ", sym[i].x-spc, sym[i].gchy, t)
+ }
+ }
+ }
+ }
+
+
+ draw_all_slurs ();
+ draw_all_phrasings ();
+
+/*| if (is_top) draw_endings (); |*/
+ if (ivc==ivc0) draw_endings ();
+ num_ending=0;
+
+ botpos=-bspace;
+ if (botnote<botpos) botpos=botnote;
+
+ if (nwl>0) draw_vocals (fp,nwl,botnote,bspace,&botpos);
+
+ *bpos=botpos;
+
+}
+
+
+/* ----- draw_sysbars: draw bars extending over staves----- */
+void draw_sysbars (fp,ip1,ip2,wid0,h1,dh)
+FILE *fp;
+int ip1,ip2;
+float wid0,h1,dh;
+{
+ int i,v,ok,u,uu,p;
+ float x;
+
+ PUT2 ("gsave 0 %.2f T 1.0 %.4f scale ",h1,dh/24.0)
+ i=ip1;
+ for (;;) {
+ if (xp[i].type==BAR) {
+ p=xp[i].p[ivc0];
+ u=symv[ivc0][p].u;
+ if (u==B_LREP) u=B_FAT1;
+ if (u==B_RREP) u=B_FAT2;
+ ok=1;
+ for (v=0;v<nvoice;v++) {
+ if (v!=ivc0 && voice[v].draw) {
+ p=xp[i].p[v];
+ if (p<0) ok=0;
+ else {
+ uu=symv[v][p].u;
+ if (uu==B_LREP) uu=B_FAT1;
+ if (uu==B_RREP) uu=B_FAT2;
+ if (uu!=u) ok=0;
+ }
+ }
+ }
+
+ if (ok) {
+ x=xp[i].x+wid0;
+ if (u==B_SNGL)
+ PUT1("%.1f bar ", x)
+ else if (u==B_DBL)
+ PUT1("%.1f dbar ", x)
+ else if (u==B_FAT1)
+ PUT1("%.1f fbar1 ", x)
+ else if (u==B_FAT2)
+ PUT1("%.1f fbar2 ", x)
+ else if (u==B_DREP) {
+ PUT1("%.1f fbar1 ", x-1)
+ PUT1("%.1f fbar2 ", x+1)
+ }
+ }
+ }
+
+ i=xp[i].next;
+ if (i==ip2) break;
+ }
+
+ PUT0 (" 0.0 bar grestore\n")
+
+}
+
+
+/* ----- count_symbols: count number of "real" symbols ---- */
+int count_symbols ()
+{
+ int i,c;
+
+ c=0;
+ for (i=0;i<nsym;i++) {
+ switch (sym[i].type) {
+ case NOTE:
+ case REST:
+ case BAR:
+ c++;
+ }
+ }
+ return c;
+
+}
+
+/* ----- select_piece: choose limits for piece to put on one staff ---- */
+int select_piece (ip1)
+int ip1;
+{
+ int i,num,ltype,count_this;
+
+ /* find next symbol marked as eol */
+ i=ip1;
+ for (;;) {
+ if (xp[i].eoln) break;
+ if (xp[i].next==XP_END) break;
+ i=xp[i].next;
+ }
+ i=xp[i].next;
+ if (cfmt.barsperstaff==0) return i;
+
+ /* find first note or rest */
+ i=ip1;
+ for (;;) {
+ if (xp[i].type==NOTE || xp[i].type==REST)
+ if (xp[i].type==NOTE || xp[i].type==REST) break;
+ i=xp[i].next;
+ if (i==XP_END) return i;
+ }
+ i=xp[i].next;
+ if (i==XP_END) return i;
+
+ /* count bars until number is reached */
+ num=0;
+ ltype=0;
+ for (;;) {
+ count_this=0;
+ if (xp[i].type==BAR) {
+ count_this=1;
+ if (ltype==BAR) count_this=0;
+ }
+ num=num+count_this;
+ ltype=xp[i].type;
+ i=xp[i].next;
+ if (i==XP_END) return i;
+ if (num==cfmt.barsperstaff) return i;
+ }
+ i=xp[i].next;
+
+ return i;
+
+}
+
+/* ----- is_topvc: check for top voice of set staved together --- */
+int is_topvc (jv)
+int jv;
+{
+ int iv,kv,ok;
+
+ ok=0;
+ for (iv=0;iv<jv;iv++) {
+ if (voice[iv].staves >= jv-iv+1) {
+ for (kv=iv;kv<jv;kv++)
+ if (voice[kv].draw) ok=1;
+ }
+ }
+
+ return 1-ok;
+}
+
+
+/* ----- vc_select: set flags for voice selection from -V option --- */
+int vc_select ()
+{
+ char *s;
+ int i,a,b,n;
+
+ if (strlen(vcselstr)==0) return nvoice;
+
+ for (i=0;i<nvoice;i++) voice[i].select=0;
+ s=vcselstr;
+ for (;;) {
+ if (*s==0) break;
+ if (!sscanf(s,"%d%n",&a,&n)) break;
+ s+=n;
+ b=a;
+ if (*s=='-') {
+ s++;
+ if (*s==0) break;
+ if (!sscanf(s,"%d%n",&b,&n)) break;
+ s+=n;
+ }
+ for (i=a-1;i<b;i++)
+ if (i>=0 && i<nvoice) voice[i].select=1;
+
+
+ if (*s==0) {
+ n=0;
+ for (i=0;i<nvoice;i++) if (voice[i].select) n++;
+ if (verbose>=4) {
+ printf ("Selection <%s> selected voices:",vcselstr);
+ for (i=0;i<nvoice;i++) if (voice[i].select) printf(" %d",i+1);
+ printf ("\n");
+ }
+ return n;
+ }
+ if (*s==',') s++;
+ else break;
+ }
+
+ rx ("Bad voice selection: -V ", vcselstr);
+ return 0;
+}
+
+/* ----- voice_label: label voice, or just return length if job==0 -- */
+float voice_label (fp, label, h, xc, dx0, job)
+FILE *fp;
+char *label;
+float xc,dx0,h;
+int job;
+{
+ float w,wid,dy,xcc;
+ char lab[81],t[81];
+ int n,i;
+ char *p,*q,*l[10];
+
+ if (strlen(label)==0) return 0.0;
+
+ strcpy(lab,label);
+ n=0;
+ p=lab;
+ l[0]=p;
+ while (q=strstr(p,"\\\\")) { *q='\0'; p=q+2; n++; l[n]=p; }
+ n++;
+
+ wid=0;
+ for (i=0;i<n;i++) {
+ tex_str(l[i],t,&w);
+ w=cfmt.voicefont.size*w;
+ if (w>wid) wid=w;
+ if (job!=0) {
+ xcc=xc;
+ if (xcc+0.5*w>dx0) xcc=dx0-0.5*w;
+ dy = 8.0 + 0.5*cfmt.voicefont.size*(n-1-2*i) + h;
+ PUT3 (" %.2f %.2f M (%s) cshow\n",xcc,dy,t)
+ }
+ }
+ return wid;
+}
+
+
+
+/* ----- mstave_deco: draw decorations over multiple staves ----- */
+void mstave_deco (fp,ip1,ip2,wid0,hsys,htab)
+FILE *fp;
+int ip1,ip2;
+float hsys,wid0,htab[];
+{
+ int iv,jv,nv;
+ float hbot,htop,ht,x0,y0,wid,wc,wcb,w,wmin;
+ float wmin1=15.0, wmin2=10.0; /* space to staff */
+
+ wmin=wmin2;
+ if (do_indent) wmin=wmin1;
+
+ /* draw bar lines */
+ if (mvoice>1) {
+ for (iv=0;iv<nvoice;iv++) {
+ hbot=10000; htop=-hbot; nv=1;
+ for (jv=iv;jv<iv+voice[iv].staves;jv++) {
+ if (voice[jv].draw) nv++;
+ if (voice[jv].draw && (htab[jv]<hbot)) hbot=htab[jv];
+ if (voice[jv].draw && (htab[jv]>htop)) htop=htab[jv];
+ }
+ if ((hbot<htop-0.001) && (nv>1))
+ draw_sysbars (fp,ip1,ip2,wid0,hsys-htop,htop-hbot+24.0);
+ }
+ PUT1 ("gsave 1.0 %.4f scale 0.0 bar grestore\n", (hsys+24.0)/24.0)
+ }
+
+ /* next part draws voice names (except on braces) */
+ set_font (fp, cfmt.voicefont, 0);
+ nv=0;
+ for (iv=0;iv<nvoice;iv++) if (voice[iv].draw) nv++;
+
+ /* get max label width, then center labels above each other */
+ wid=w=0;
+ for (iv=0;iv<nvoice;iv++) {
+ if (voice[iv].draw) {
+ if (do_indent)
+ w=voice_label (fp, voice[iv].name, 0.0,0.0,0.0, 0);
+ else if (nv>1)
+ w=voice_label (fp, voice[iv].sname, 0.0,0.0,0.0, 0);
+ if (w>wid) wid=w;
+ }
+ }
+ wc=wcb=0.5*wid+wmin;
+ if (wcb<18.0) wcb=18.0; /* label on brace needs a bit more room */
+
+ for (iv=0;iv<nvoice;iv++) {
+ if (voice[iv].draw && (voice[iv].brace==0) ) {
+ y0=hsys-htab[iv];
+ if (do_indent)
+ voice_label (fp, voice[iv].name,y0,-wc,-wmin,1);
+ else if (nv>1)
+ voice_label (fp,voice[iv].sname,y0,-wc,-wmin,1);
+ }
+ }
+
+ /* braces and brackets */
+ for (iv=0;iv<nvoice;iv++) {
+ hbot=10000; htop=-hbot; nv=0;
+ for (jv=iv;jv<iv+voice[iv].brace;jv++) {
+ if (voice[jv].draw) nv++;
+ if (voice[jv].draw && (htab[jv]<hbot)) hbot=htab[jv];
+ if (voice[jv].draw && (htab[jv]>htop)) htop=htab[jv];
+ }
+ if (hbot<htop+0.001) {
+ ht=htop-hbot+24.0;
+ y0=hsys-htop+0.5*ht;
+ x0=-8;
+ ht=ht-2.0;
+ if (voice[iv].brace==1) ht=ht+15.0;
+ if (voice[iv].brace>2) ht=ht-8.0;
+ if ((nv>1)||(voice[iv].brace==1))
+ PUT3 (" %.4f %.1f %.1f brace\n", ht/120.0, x0, y0)
+ if (do_indent)
+ voice_label (fp, voice[iv].name, y0-12.0,-wcb,-wmin,1);
+ else if (nv>1)
+ voice_label (fp, voice[iv].sname,y0-12.0,-wcb,-wmin,1);
+ }
+
+ hbot=10000; htop=-hbot; nv=0;
+ for (jv=iv;jv<iv+voice[iv].bracket;jv++) {
+ if (voice[jv].draw) nv++;
+ if (voice[jv].draw && (htab[jv]<hbot)) hbot=htab[jv];
+ if (voice[jv].draw && (htab[jv]>htop)) htop=htab[jv];
+ }
+ if ((hbot<htop+0.001) && ((nv>1)||(voice[iv].bracket==1)))
+ PUT2 ("\n %.1f -3 %.1f bracket\n", htop-hbot+24.0+6.0, hsys-htop-3.0)
+
+ }
+
+}
+
+
+
+/* ----- output_music: output for parsed symbol list ----- */
+void output_music (fp)
+FILE *fp;
+{
+ int ip1,ip2,mv,is_top,nsel,b,bnum;
+ float realwidth,staffwidth,wid0,widv,lscale,lwidth,bpos;
+ float spa1,spa2,hsys,htab[40],extra,indent,spax;
+
+ /* save current meter and key, to continue after P: or T: field */
+ for (ivc=0;ivc<nvoice;ivc++) {
+ voice[ivc].meter1 = voice[ivc].meter;
+ voice[ivc].key1 = voice[ivc].key;
+ }
+
+ if (!file_initialized && !epsf) {
+ init_ps (fout,infostr,0,0.0,0.0,0.0,0.0);
+ init_page (fout);
+ }
+
+ if (nvoice==0) { init_parse_params(); return; }
+ if (verbose>=10) print_vsyms ();
+
+ alfa_last=0.1; beta_last=0.0;
+ lwidth=cfmt.staffwidth;
+ lscale=cfmt.scale;
+ check_margin (cfmt.leftmargin);
+
+ /* dump buffer if not enough space for a staff line */
+ check_buffer (fp, BUFFSZ1);
+
+ /* initialize meter and key for voices */
+ for (ivc=0;ivc<nvoice;ivc++) {
+ voice[ivc].meter = voice[ivc].meter0;
+ voice[ivc].key = voice[ivc].key0;
+ if (!do_meter) voice[ivc].meter.insert=0;
+ }
+
+ /* setup for horizontal positioning, decide which voices to draw */
+ nsel=vc_select ();
+ for (ivc=0;ivc<nvoice;ivc++)
+ if (!voice[ivc].select) voice[ivc].nsym=0;
+
+ mvoice=0;
+ ivc0=-1;
+ for (ivc=0;ivc<nvoice;ivc++) {
+ voice[ivc].draw=0;
+ if (voice[ivc].nsym>0) {
+ mvoice++;
+ if (ivc0<0) ivc0=ivc;
+ voice[ivc].draw=1;
+ }
+ }
+ if (mvoice==0) { init_parse_params(); return; }
+
+ for (ivc=0;ivc<nvoice;ivc++) {
+ if (voice[ivc].draw) {
+ set_sym_chars (0,voice[ivc].nsym,symv[ivc]);
+ set_beams (0,voice[ivc].nsym,symv[ivc]);
+ set_stems (0,voice[ivc].nsym,symv[ivc]);
+ b=set_sym_times(0,voice[ivc].nsym,symv[ivc],voice[ivc].meter0);
+ set_sym_widths (0,voice[ivc].nsym,symv[ivc],ivc);
+ if (ivc==ivc0) bnum=b;
+ }
+ }
+ barinit=bnum;
+
+ if (mvoice==1)
+ set_style_pars (cfmt.strict1);
+ else
+ set_style_pars (cfmt.strict2);
+
+ set_poslist ();
+ set_xpwid ();
+ set_spaces ();
+
+ /* loop over pieces to output */
+ ip1=xp[XP_START].next;
+ for (;;) {
+ mline++;
+ ip1=contract_keysigs (ip1);
+ wid0=0;
+ for (ivc=0;ivc<nvoice;ivc++) {
+ nsym_st[ivc]=set_initsyms (ivc, &widv);
+ if (widv>wid0) wid0=widv;
+ }
+ indent = (do_indent==1) ? cfmt.indent : 0.0;
+
+ ip2=select_piece (ip1);
+ ip2=check_overflow (ip1,ip2,lwidth/lscale-wid0-indent);
+ if (verbose>5) printf ("output posits %d to %d\n",ip1,ip2-1);
+ realwidth=set_glue (ip1,ip2,lwidth/lscale-wid0-indent);
+ check_bars1 (ip1,ip2);
+ check_bars2 (ip1,ip2);
+
+ spa1=spa2=cfmt.staffsep;
+ if (mvoice>1) {
+ spa1=cfmt.systemsep;
+ spa2=cfmt.sysstaffsep;
+ }
+
+ hsys=0;
+ mv=0;
+ for (ivc=0;ivc<nvoice;ivc++) {
+ if (voice[ivc].draw) {
+ mv++;
+ nsym=copy_vsyms (ivc,ip1,ip2,wid0);
+ PUT2("\n%% --- ln %d vc %d \n", mline,ivc+1)
+ if (mv==1) bskip(lscale*(0.5*spa1+24.0));
+ else bskip(lscale*(0.5*spa2+24.0));
+ PUT3("gsave %.3f %.3f scale %.2f setlinewidth\n",
+ lscale, lscale, BASEWIDTH)
+ if (do_indent) PUT1(" %.2f 0 T ",indent)
+ staffwidth=realwidth+wid0;
+ PUT1("%.2f staff\n", staffwidth)
+ htab[ivc]=hsys;
+ spax=spa2+voice[ivc].sep;
+ if (voice[ivc].sep>1000.0) spax=voice[ivc].sep-2000.0;
+
+ is_top=is_topvc(ivc);
+ draw_symbols (fp,0.5*spa2+spax-spa2,&bpos,is_top);
+
+ if (mv==mvoice) mstave_deco (fp,ip1,ip2,wid0,hsys,htab);
+
+ PUT0("grestore\n")
+ bskip(-lscale*bpos);
+ hsys=hsys+0.5*spa2+24.0-bpos;
+ }
+ }
+
+ extra=-bpos-0.5*spa2;
+ if (mvoice>1) bskip(lscale*(spa1+bpos-0.5*spa1+extra));
+ buffer_eob (fp);
+
+ do_meter=do_indent=0;
+ ip1=ip2;
+ if (ip1==XP_END) break;
+ }
+
+
+ /* set things to continue parsing */
+ for (ivc=0;ivc<nvoice;ivc++) {
+ voice[ivc].nsym=0;
+ voice[ivc].meter0 = voice[ivc].meter = voice[ivc].meter1;
+ voice[ivc].key0 = voice[ivc].key = voice[ivc].key1;
+ }
+ init_parse_params ();
+
+}
+
+/* ----- process_textblock ----- */
+void process_textblock(fpin,fp,job)
+FILE *fp,*fpin;
+int job;
+{
+ char w1[81],ln[BSIZE],ln1[BSIZE];
+ float lwidth,baseskip,parskip;
+ int i,ll,add_final_nl;
+
+ baseskip = cfmt.textfont.size * cfmt.lineskipfac;
+ parskip = cfmt.textfont.size * cfmt.parskipfac;
+ add_final_nl=0;
+ if (job==OBEYLINES) add_final_nl=1;
+ lwidth=cfmt.staffwidth;
+ output_music (fp);
+ buffer_eob (fp);
+ set_font (fp, cfmt.textfont, 0);
+ ntxt=0;
+ for (i=0;i<100;i++) {
+ if (feof(fpin)) rx("EOF reached scanning text block","");
+ strcpy (ln, "");
+ getline(ln, BSIZE, fpin);
+ ll=strlen(ln);
+ linenum++;
+ if ((verbose>=5) || (vb>=10) ) printf ("%3d %s \n", linenum, ln);
+ if ((ln[0]=='%') && (ln[1]=='%')) {
+ strcpy(ln1,ln+2);
+ strcpy(ln,ln1);
+ }
+
+ strcpy(w1,"");
+ sscanf(ln,"%s",w1);
+ if (!strcmp(w1,"endtext")) break;
+
+ if (job!=SKIP) {
+ if (isblank(ln)) {
+ write_text_block (fp,job);
+ ntxt=0;
+ }
+ else {
+ add_to_text_block (ln,add_final_nl);
+ }
+ }
+ }
+ if (job!=SKIP) write_text_block (fp,job);
+}
+
+
+/* ----- process_pscomment ----- */
+void process_pscomment (fpin,fp,line)
+FILE *fp,*fpin;
+char line[];
+{
+ char w[81],fstr[81],unum1[41],unum2[41],unum3[41];
+ float h1,h2,len,lwidth;
+ int i,nch,job;
+
+ lwidth=cfmt.staffwidth;
+ line[0]=' ';
+ line[1]=' ';
+ for (i=0;i<strlen(line);i++) if (line[i]=='%') line[i]='\0';
+ strcpy(w," ");
+ sscanf(line,"%s%n", w, &nch);
+
+ if (!strcmp(w,"begintext")) {
+ if (epsf && !within_block) return;
+ strcpy(fstr,"");
+ sscanf(line, "%*s %s", fstr);
+ if (isblank(fstr)) strcpy(fstr,"obeylines");
+ if (!strcmp(fstr,"obeylines")) job=OBEYLINES;
+ else if (!strcmp(fstr,"align")) job=ALIGN;
+ else if (!strcmp(fstr,"skip")) job=SKIP;
+ else if (!strcmp(fstr,"ragged")) job=RAGGED;
+ else rx("bad argument for begintext: ",fstr);
+ if (within_block && !do_this_tune) job=SKIP;
+ process_textblock (fpin,fp,job);
+ return;
+ }
+
+ if (!strcmp(w,"text") || !strcmp(w,"center")) {
+ if (epsf && !within_block) return;
+ if (within_block && !do_this_tune) return;
+ output_music (fp);
+ set_font (fp, cfmt.textfont, 0);
+ ntxt=0;
+ add_to_text_block (line+nch+1,1);
+ if (!strcmp(w,"text"))
+ write_text_block (fp,OBEYLINES);
+ else
+ write_text_block (fp,OBEYCENTER);
+ buffer_eob (fp);
+ }
+
+ else if (!strcmp(w,"sep")) {
+ if (within_block && !do_this_tune) return;
+ output_music (fp);
+ strcpy(unum1,"");
+ strcpy(unum2,"");
+ strcpy(unum3,"");
+ sscanf(line,"%*s %s %s %s", unum1,unum2,unum3);
+ g_unum(unum1,unum1,&h1);
+ g_unum(unum2,unum2,&h2);
+ g_unum(unum3,unum3,&len);
+ if (h1*h1<0.00001) h1=0.5*CM;
+ if (h2*h2<0.00001) h2=h1;
+ if (len*len<0.0001) len=3.0*CM;
+ bskip (h1);
+ PUT2("%.1f %.1f sep0\n", lwidth/2-len/2, lwidth/2+len/2);
+ bskip (h2);
+ buffer_eob (fp);
+ }
+
+ else if (!strcmp(w,"vskip")) {
+ if (within_block && !do_this_tune) return;
+ output_music (fp);
+ strcpy(unum1,"");
+ sscanf(line,"%*s %s", unum1);
+ g_unum(unum1,unum1,&h1);
+ if (h1*h1<0.00001) h1=0.5*CM;
+ bskip (h1);
+ buffer_eob (fp);
+ }
+
+ else if (!strcmp(w,"newpage")) {
+ if (within_block && !do_this_tune) return;
+ output_music (fp);
+ write_buffer (fp);
+ use_buffer=0;
+ write_pagebreak (fp);
+ }
+
+ else {
+ if (within_block) {
+ interpret_format_line (line,&cfmt);
+ ops_into_fmt (&cfmt);
+
+ }
+ else {
+ interpret_format_line (line,&dfmt);
+ ops_into_fmt (&dfmt);
+ cfmt=dfmt;
+ }
+ }
+
+
+}
+
+/* ----- check_selected ----- */
+void check_selected(fp,xref_str,npat,pat,sel_all,search_field)
+FILE *fp;
+int npat,sel_all,search_field;
+char xref_str[],pat[][STRL1];
+{
+
+ if (!do_this_tune) {
+ if (is_selected(xref_str,npat,pat,sel_all,search_field)) {
+ do_this_tune=1;
+ verbose=vb;
+ clear_buffer ();
+/* set to 0 to permit staff breaks in a tune */
+ use_buffer=1;
+ write_tunetop(fp);
+ }
+ }
+}
+
+
+/* ----- process_header: call at end of header ----- */
+void process_header (fp,xref_str,npat,pat,sel_all,search_field)
+FILE *fp;
+int npat,sel_all,search_field;
+char xref_str[],pat[][STRL1];
+{
+
+ if ((vb>15) || ((verbose>10)&&within_block))
+ printf ("End of header.. process header data\n");
+
+ check_selected(fp,xref_str,npat,pat,sel_all,search_field);
+ if (do_this_tune) {
+ tunenum++;
+ if (verbose>=3)
+ printf ("---- start %d (%s) ----\n", xrefnum, info.title);
+ fflush (stdout);
+ set_keysig (info.key, &default_key, 1);
+ halftones=get_halftones (default_key, transpose);
+ set_transtab (halftones,&default_key);
+ set_meter (info.meter,&default_meter);
+ set_dlen (info.len, &default_meter);
+ check_margin (cfmt.leftmargin);
+ write_heading (fp);
+ nvoice=0;
+ init_parse_params ();
+ default_meter.insert=1;
+ mline=0;
+ do_indent=do_meter=1;
+ barinit=1;
+ writenum=0;
+ }
+ within_tune=1;
+}
+
+/* ----- close_tune ----- */
+void close_tune (fp)
+FILE *fp;
+{
+ char fnm[81],finf[MAXINF];
+ FILE *feps;
+
+ if (do_this_tune) {
+ output_music (fp);
+ put_words (fp);
+ if (cfmt.writehistory) put_history (fp);
+ if (epsf) {
+ close_output_file ();
+ if (choose_outname) {
+ epsf_title (info.title, fnm);
+ strcat (fnm,".eps");
+ }
+ else {
+ nepsf++;
+ sprintf (fnm, "%s%03d.eps", outf, nepsf);
+ }
+ sprintf (finf, "%s (%d)", in_file[0], xrefnum);
+ if ((feps = fopen (fnm,"w")) == NULL)
+ rx ("Cannot open output file ", fnm);
+ init_ps (feps, finf, 1,
+ cfmt.leftmargin-5, posy+bposy-5,
+ cfmt.leftmargin+cfmt.staffwidth+5,
+ cfmt.pageheight-cfmt.topmargin);
+ init_epsf (feps);
+ write_buffer (feps);
+ printf ("\n[%s] %s", fnm, info.title);
+ close_epsf (feps);
+ fclose (feps);
+ in_page=0;
+ init_pdims ();
+ }
+ else {
+ buffer_eob (fp);
+ write_buffer (fp);
+ if ((verbose==0) && (tunenum%10==0)) printf (".");
+ if (verbose==2) printf ("%s - ", info.title);
+ }
+ verbose=0;
+ }
+ info=default_info;
+ within_tune=within_block=do_this_tune=0;
+
+}
+
+
+/* ----- process_line ----- */
+void process_line (fp,type,xref_str,npat,pat,sel_all,search_field)
+FILE *fp;
+int type,npat,sel_all,search_field;
+char xref_str[],pat[][STRL1];
+{
+
+ if ((vb>15) || ((verbose>10)&&within_block)) {
+ printf ("process_line, type %d ", type);
+ print_linetype(type);
+ }
+
+ switch (type) {
+
+ case XREF: /* start of new block */
+ if (!epsf) write_buffer (fp); /* flush stuff left from %% lines */
+ if (within_block) printf ("\n+++ Last tune not closed properly\n");
+ get_default_info ();
+ within_block = 1;
+ within_tune = 0;
+ do_this_tune = 0;
+ numtitle=0;
+ ntext=0;
+ init_pdims();
+ cfmt=dfmt;
+ break;
+
+ case TITLE:
+ if (!within_block) break;
+ if (within_tune) { /* title within tune */
+ if (do_this_tune ) {
+ output_music (fp);
+ write_inside_title (fp);
+ do_meter=do_indent=1;
+ barinit=1;
+ }
+ }
+ else
+ check_selected(fp,xref_str,npat,pat,sel_all,search_field);
+ break;
+
+ case TEMPO:
+ if (!within_block) break;
+ if (within_tune) { /* tempo within tune */
+ if (do_this_tune ) {
+ output_music (fp);
+ write_inside_tempo(fp);
+ }
+ }
+ else
+ check_selected(fp,xref_str,npat,pat,sel_all,search_field);
+ break;
+
+ case KEY:
+ if (!within_block) break;
+ if (within_tune) {
+ if (do_this_tune) handle_inside_field(type);
+ }
+ else { /* end of header.. start now */
+/*| process_header (fp,xref_str,npat,pat,sel_all,search_field); |*/
+ }
+ break;
+
+ case METER:
+ if (!within_block) break;
+ if (do_this_tune && within_tune) handle_inside_field(type);
+ break;
+
+ case DLEN:
+ if (!within_block) break;
+ if (do_this_tune && within_tune) handle_inside_field(type);
+ break;
+
+ case PARTS:
+ if (!within_block) break;
+ if (do_this_tune && within_tune) {
+ output_music (fp);
+ write_parts(fp);
+ }
+ break;
+
+ case VOICE:
+ if (do_this_tune && within_block) {
+ if (!within_tune)
+ printf ("+++ Voice field not allowed in header: V:%s\n", lvoiceid);
+ else
+ ivc=switch_voice (lvoiceid);
+ }
+ break;
+
+ }
+}
+
+/* ----- process_file ----- */
+void process_file (fpin,fpout,xref_str,npat,pat,sel_all,search_field)
+FILE *fpin,*fpout;
+int npat,sel_all,search_field;
+char xref_str[],pat[][STRL1];
+{
+ char line[BSIZE];
+ int type,nsym0;
+
+ within_tune=within_block=do_this_tune=0;
+ linenum=0;
+ numtitle=0;
+ reset_info (&default_info);
+ info=default_info;
+ verbose=0;
+ if (vb>=20) db=3;
+ if (vb>=25) db=5;
+
+ type=read_line (fpin,line);
+
+ for (;;) {
+
+ /* header is completed at first MUSIC or VOICE line */
+ if ((type==MUSIC) || (type==VOICE)) {
+ if (within_block && !within_tune)
+ process_header (fpout,xref_str,npat,pat,sel_all,search_field);
+ }
+
+ /* tune terminates at BLANK or EOF */
+ if ((type==BLANK) || (type==E_O_F)) close_tune (fpout);
+ if (type==E_O_F) break;
+
+ if (type==PSCOMMENT) process_pscomment(fpin,fpout,line);
+ if ((type==MUSIC) && do_this_tune) parse_music_line (line);
+ process_line (fpout,type,xref_str,npat,pat,sel_all,search_field);
+ type=read_line (fpin,line);
+ }
+ if (!epsf) {
+ buffer_eob (fpout);
+ write_buffer (fpout);
+ }
+
+}
+
+
diff --git a/newfeatures.abc b/newfeatures.abc
@@ -0,0 +1,121 @@
+%%textfont Helvetica-Bold 16
+%%center Examples for new features in abc2ps-1.2.5
+%%textfont * 12
+%%center Oct. 5 1997
+%%textfont Times-Roman 12
+
+X:1
+T:Scale with Treble Clef
+M:C
+K:C
+L: 1/4
+ "C,"C,"D,"D,"E,"E,"F,"F, "G,"G,"A,"A,"B,"B,\
+| "C"C"D"D"E"E"F"F "G"G"A"A"B"B| "c"c "d"d"e"e"f"f "g"g"a"a"b"b"c'"c' |
+
+X:2
+T:Scale with Bass and Alto Clef
+M:C
+K:C bass
+L: 1/4
+P:Bass
+ "C,"C,"D,"D,"E,"E,"F,"F, "G,"G,"A,"A,"B,"B,\
+| "C"C"D"D"E"E"F"F "G"G"A"A"B"B| "c"c "d"d"e"e"f"f "g"g"a"a"b"b"c'"c' |
+P:Alto
+K:C alto
+ "C,"C,"D,"D,"E,"E,"F,"F, "G,"G,"A,"A,"B,"B,\
+| "C"C"D"D"E"E"F"F "G"G"A"A"B"B| "c"c "d"d"e"e"f"f "g"g"a"a"b"b"c'"c' |
+
+X:3
+T:Clef Changes Within Tune
+T:In-Line Info Fields by [..]
+%%begintext align
+Here is an example for a block of text which is associated with a specific
+tune. It will only be printed if this tune (number 3) is selected.
+The text should be placed after the "T:" field and before the
+block is terminated by a blank line.
+Text which is outside a block is
+always printed; for example, the title at the top of the page.
+%%endtext
+M:C
+L: 1/8
+K:C
+cdef gabc' [K:bass] | cdef gabc' [K:D treble] | cdef gabc' |
+%%sep
+%%text Note: this line and the separator above are also associated with this t…
+
+
+X:4
+T:Vocals
+T:Note also the trill
+C:Music: Trad.
+C:Text: Anonymous
+M:C
+K:C
+L: 1/4
+e>e ez || edTc2 | ed(c2 | e2 c2- | Hc4) |]
+w: *** 1.~~Three blind mice, three blind mice.__
+w: *** 2.~~See how~they run, see how~they ru-uuu-un._
+
+
+X:6
+T:Invisible Rests Using X
+M:C
+K:C
+L: 1/4
+"F"z4|"F"z4|"F"z4|"F"z4|"Bb"z4|"Bb"z4|"F"z4|"F"z4|"C"z4|"Bb"z4|"F"z4|"F"z4||
+"F"x4|"F"x4|"F"x4|"F"x4|"Bb"x4|"Bb"x4|"F"x4|"F"x4|"C"x4|"Bb"x4|"F"x4|"F"x4||
+
+
+%%leftmargin 3cm
+
+X:5
+T:Scotland The Brave
+T:Demonstrating the Bagpipe Mode and Output Formatting
+%%titleleft
+%%titlefont Helvetica-Bold 18
+%%subtitlefont Helvetica-Bold 12
+%%composerspace 0.4cm
+%%composerfont Helvetica 10
+%%staffwidth 5.5in
+%%scale 0.75
+%%staffsep 55
+C:Trad.
+C:from PS file by Alan S. Watt
+P:March
+L:1/8
+M:4/4
+K:HP
+e|{g}A2 {GdGe}A>B {gcd}c{e}A {gcd}ce| {ag}a2{g}a2 {GdG}ae {gcd}c{e}A|
+ {Gdc}d2 {g}f>d {gcd}ce {gcd}c{e}A|{GdG}B2{gef}e2{A}e>f {g}e/>d/{g}c/>B/|
+{g}A2 {GdGe}A>B {gcd}c{e}A {gcd}ce| {ag}a2{g}a2 {GdG}ae {gcd}c{e}A|
+ {Gdc}d2 {g}f>d {gcd}ce {gcd}c{e}A|{GdG}B2{g}A>B {G}A2 {gcd}ce||
+
+
+
+%%vskip 1cm
+%%textfont Times-Roman 12
+%%begintext
+Summary of changes:
+
+- Bass and alto clefs.
+- Vocals.
+- Double-backslash in music makes staff break.
+- In-line info fields can be coded using [...].
+- Subtitles now printed without "or:".
+- Can be more than one composer field.
+- Predefined formats: standard, pretty, pretty2 (flag -p, -P).
+- Format page layout by .fmt file selected with flag -F.
+- Format page layout by %%-pseudocomments in abc file.
+- Other pseudocomments: %%sep, %%vskip, %%newpage.
+- Text output using %%text, %%center, and %%begintext .. %%endtext.
+- "X" functions like a rest but is invisible on the page.
+- Bagpipe mode for K:HP.
+
+
+%%endtext
+
+
+
+
+
+
diff --git a/parse.h b/parse.h
@@ -0,0 +1,2460 @@
+/*
+ * This file is part of abc2ps,
+ * Copyright (C) 1996,1997,1998 Michael Methfessel
+ * See file abc2ps.c for details.
+ */
+
+/* subroutines connected with parsing the input file */
+
+/* ----- sytax: print message for syntax errror -------- */
+void syntax (msg, q)
+char msg[];
+char *q;
+{
+ int i,n,len,m1,m2,pp,qq,maxcol=65;
+
+ if (verbose<=2) printf ("\n");
+ qq=q-p0+1;
+ if (qq<0) qq=0;
+ printf ("+++ %s in line %d.%d \n", msg, linenum, qq);
+ m1=0;
+ m2=len=strlen(p0);
+ n=q-p0;
+ if (m2>maxcol) {
+ if (n<maxcol)
+ m2=maxcol;
+ else {
+ m1=n-10;
+ m2=m1+maxcol;
+ if (m2>len) m2=len;
+ }
+ }
+
+ printf ("%4d ", linenum);
+ pp=5;
+ if (m1>0) { printf ("..."); pp+=3; }
+ for (i=m1;i<m2;i++) printf ("%c", p0[i]);
+ if (m2<len) printf ("...");
+ printf ("\n");
+
+ if (n>=0 && n<200) {
+ for (i=0;i<n+pp-m1;i++) printf(" ");
+ printf ("^\n");
+ }
+}
+
+/* ----- isnote: checks char for valid note symbol ----- */
+int isnote (c)
+char c;
+{
+ if (c == '\0') return 0;
+ if (strchr("CDEFGABcdefgab^=_",c)) return 1;
+ return 0;
+}
+
+/* ----- zero_sym: init global zero SYMBOL struct ----- */
+void zero_sym ()
+{
+ int j;
+ zsym.type = 0;
+ zsym.npitch = 0;
+ zsym.word_st = 0;
+ zsym.word_end = 0;
+ zsym.slur_st = 0;
+ zsym.slur_end = 0;
+ zsym.len = 0;
+ zsym.fullmes = 0;
+ zsym.yadd = 0;
+ zsym.xs = 0;
+ zsym.ys = 0;
+ zsym.stem = 0;
+ zsym.eoln = 0;
+ zsym.ylo = 12;
+ zsym.yhi = 12;
+ zsym.u = 0;
+ zsym.v = 0;
+ zsym.w = 0;
+ zsym.t = 0;
+ zsym.q = 0;
+ zsym.invis = 0;
+ zsym.wl = 0;
+ zsym.wr = 0;
+ zsym.pr = 0;
+ zsym.pl = 0;
+ zsym.p_plet = 0;
+ zsym.q_plet = 0;
+ zsym.r_plet = 0;
+ zsym.gchy = 0;
+ zsym.gr.n = 0;
+ zsym.dc.n = 0;
+ zsym.dc.top = 0;
+ zsym.p = -1;
+ strcpy (zsym.text, "");
+ for (j=0;j<MAXHD;j++) zsym.sl1[j]=zsym.sl2[j]=0;
+
+ for (j=0;j<NWLINE;j++) zsym.wordp[j] = 0;
+}
+
+/* ----- add_sym: returns index for new symbol at end of list ---- */
+int add_sym (type)
+int type;
+{
+ int k;
+
+ k=voice[ivc].nsym;
+ if (k>=maxSyms) rxi("Too many symbols; increase maxSyms, now ",maxSyms);
+ voice[ivc].nsym++;
+ symv[ivc][k]=zsym;
+ symv[ivc][k].type = type;
+ return k;
+
+}
+
+/* ----- insert_sym: returns index for new symbol inserted at k --- */
+int insert_sym (type,k)
+int type,k;
+{
+ int i,n;
+
+ n=voice[ivc].nsym;
+ if (n>=maxSyms) rxi("insert_sym: maxSyms exceeded: ",maxSyms);
+ for (i=n;i>k;i--) symv[ivc][i]=symv[ivc][i-1];
+ n++;
+ symv[ivc][k]=zsym;
+ symv[ivc][k].type = type;
+ voice[ivc].nsym=n;
+ return k;
+}
+
+/* ----- get_xref: get xref from string ----- */
+int get_xref (str)
+char str[];
+{
+
+ int a,ok;
+ char *q;
+
+ if (strlen(str)==0) {
+ wng ("xref string is empty", "");
+ return 0;
+ }
+ q=str;
+ ok=1;
+ while (*q != '\0') {
+ if (!isdig(*q)) ok=0;
+ q++;
+ }
+ if (!ok) {
+ wng ("xref string has invalid symbols: ", str);
+ return 0;
+ }
+
+ sscanf (str, "%d", &a);
+
+ return a;
+}
+
+/* ----- set_meter: interpret meter string, store in struct ---- */
+void set_meter (str,meter)
+char str[];
+struct METERSTR *meter;
+{
+
+ int m1,m2,m1a,m1b,m1c,d,l;
+ char *q;
+ int meter1,meter2,dlen,mflag,lflag;
+ char meter_top[31];
+
+ l=strlen(str);
+ if (l==0) { wng("Empty meter string", ""); return; }
+ if (str[0]=='C') {
+ if (str[1]=='|') {
+ meter1=4;
+ meter2=4;
+ dlen=EIGHTH;
+ mflag=2;
+ strcpy(meter_top,"C");
+ }
+ else {
+ meter1=4;
+ meter2=4;
+ dlen=EIGHTH;
+ mflag=1;
+ strcpy(meter_top,"C");
+ }
+ }
+ else {
+ m1=m2=m1a=m1b=m1c=0;
+ strcpy (meter_top, str);
+ q=strchr(meter_top,'/');
+ if (!q) {
+ wng("Cannot identify meter, missing /: ", str);
+ m1=m2=1;
+ return;
+ }
+ *q='\0';
+ if (strchr(meter_top,'+')) {
+ sscanf(str,"%d+%d+%d/", &m1a, &m1b, &m1c);
+ m1=m1a+m1b+m1c;
+ }
+ else {
+ sscanf(str,"%d %d %d/", &m1a, &m1b, &m1c);
+ m1=m1a; if (m1b>m1) m1=m1b; if (m1c>m1) m1=m1c;
+ if (m1>30) { /* handle things like 78/8 */
+ m1a=m1/100;
+ m1c=m1-100*m1a;
+ m1b=m1c/10;
+ m1c=m1c-10*m1b;
+ m1=m1a; if (m1b>m1) m1=m1b; if (m1c>m1) m1=m1c;
+ }
+ }
+
+ q++;
+ sscanf (q, "%d", &m2);
+ if (m1*m2 == 0) wng("Cannot identify meter: ", str);
+ d=BASE/m2;
+ if (d*m2 != BASE) wng("Meter not recognized: ", str);
+ meter1=m1;
+ meter2=m2;
+ dlen=EIGHTH;
+ if (4*meter1 < 3*meter2) dlen=SIXTEENTH;
+ mflag=0;
+ }
+
+ if (verbose>=4)
+ printf ("Meter <%s> is %d over %d with default length 1/%d\n",
+ str, meter1, meter2, BASE/dlen);
+
+ /* handle old-style change of default length */
+ lflag=0;
+ if (str[l-1]=='s') { dlen=dlen*2; lflag=1; }
+ if (str[l-1]=='l') { dlen=dlen/2; lflag=-1; }
+
+ /* store parsed data in struct */
+ meter->meter1 = meter1;
+ meter->meter2 = meter2;
+ meter->mflag = mflag;
+ meter->dlen = dlen;
+ meter->lflag = lflag;
+ strcpy(meter->top, meter_top);
+}
+
+
+/* ----- set_dlen: set default length for parsed notes ---- */
+void set_dlen (str,meter)
+char str[];
+struct METERSTR *meter;
+{
+ int l1,l2,d,dlen;
+
+ l1=0;
+ l2=1;
+ sscanf(str,"%d/%d ", &l1, &l2);
+ if (l1 == 0) return; /* empty string.. don't change default length */
+ else {
+ d=BASE/l2;
+ if (d*l2 != BASE) {
+ wng("Length incompatible with BASE, using 1/8: ",str);
+ dlen=BASE/8;
+ }
+ else
+ dlen = d*l1;
+ }
+ if (verbose>=4)
+ printf ("Dlen <%s> sets default note length to %d/%d = 1/%d\n",
+ str, dlen, BASE, BASE/dlen);
+
+ meter->dlen=dlen;
+
+}
+
+/* ----- set_keysig: interpret keysig string, store in struct ---- */
+/* This part was adapted from abc2mtex by Chris Walshaw */
+/* updated 03 Oct 1997 Wil Macaulay - support all modes */
+/* Returns 1 if key was actually specified, because then we want
+ to transpose. Returns zero if this is just a clef change. */
+int set_keysig(s,ks,init)
+char s[];
+struct KEYSTR *ks;
+int init;
+{
+ int c,sf,j,ok;
+ char w[81];
+ int ktype,add_pitch,root,root_acc;
+
+ /* maybe initialize with key C (used for K field in header) */
+ if (init) {
+ ks->sf = 0;
+ ks->ktype = TREBLE;
+ ks->add_pitch = 0;
+ ks->root = 2;
+ ks->root_acc = A_NT;
+ }
+
+ /* check for "treble" "bass" "alto" with no other information */
+ ktype=ks->ktype;
+ add_pitch=0;
+ if (!strcmp(s,"bass")) {ks->ktype=BASS; return 0; }
+ if (!strcmp(s,"treble")) {ks->ktype=TREBLE; return 0; }
+ if (!strcmp(s,"alto")) {ks->ktype=ALTO; return 0; }
+
+ if (!strcmp(s,"bass+8")) {ks->ktype=BASS; ks->add_pitch=8; return 0; }
+ if (!strcmp(s,"treble+8")) {ks->ktype=TREBLE; ks->add_pitch=8; return 0; }
+ if (!strcmp(s,"alto+8")) {ks->ktype=ALTO; ks->add_pitch=8; return 0; }
+
+ if (!strcmp(s,"bass-8")) {ks->ktype=BASS; ks->add_pitch=-8; return 0; }
+ if (!strcmp(s,"treble-8")) {ks->ktype=TREBLE; ks->add_pitch=-8; return 0; }
+ if (!strcmp(s,"alto-8")) {ks->ktype=ALTO; ks->add_pitch=-8; return 0; }
+
+ c=0;
+ bagpipe=0;
+ switch (s[c]) {
+ case 'F':
+ sf = -1; root=5;
+ break;
+ case 'C':
+ sf = 0; root=2;
+ break;
+ case 'G':
+ sf = 1; root=6;
+ break;
+ case 'D':
+ sf = 2; root=3;
+ break;
+ case 'A':
+ sf = 3; root=0;
+ break;
+ case 'E':
+ sf = 4; root=4;
+ break;
+ case 'B':
+ sf = 5; root=1;
+ break;
+ case 'H':
+ bagpipe=1;
+ c++;
+ if (s[c] == 'P') { sf=0; root=2; }
+ else if (s[c] == 'p') { sf=2; root=3; }
+ else wng("unknown bagpipe-like key: ",s);
+ break;
+ default:
+ wng ("Using C because key not recognised: ", s);
+ sf = 0; root=2;
+ }
+ c++;
+
+ root_acc=A_NT;
+ if (s[c] == '#') {
+ sf += 7;
+ c += 1;
+ root_acc=A_SH;
+ } else if (s[c] == 'b') {
+ sf -= 7;
+ c += 1;
+ root_acc=A_FT;
+ }
+
+ /* loop over blank-delimited words: get the next token in lower case */
+ for (;;) {
+ while (s[c] == ' ') c++;
+ if (s[c]=='\0') break;
+
+ j=0;
+ while ((s[c]!=' ') && (s[c]!='\0')) { w[j]=tolower(s[c]); c++; j++; }
+ w[j]='\0';
+
+ /* now identify this word */
+
+ /* first check for mode specifier */
+ if ((strncmp(w,"mix",3)) == 0) {
+ sf -= 1;
+ ok = 1;
+ /* dorian mode on the second note (D in C scale) */
+ } else if ((strncmp(w,"dor",3)) == 0) {
+ sf -= 2;
+ ok = 1;
+ /* phrygian mode on the third note (E in C scale) */
+ } else if ((strncmp(w,"phr",3)) == 0) {
+ sf -= 4;
+ ok = 1;
+ /* lydian mode on the fourth note (F in C scale) */
+ } else if ((strncmp(w,"lyd",3)) == 0) {
+ sf += 1;
+ ok = 1;
+ /* locrian mode on the seventh note (B in C scale) */
+ } else if ((strncmp(w,"loc",3)) == 0) {
+ sf -= 5;
+ ok = 1;
+ /* major and ionian are the same ks */
+ } else if ((strncmp(w,"maj",3)) == 0) {
+ ok = 1;
+ } else if ((strncmp(w,"ion",3)) == 0) {
+ ok = 1;
+ /* aeolian, m, minor are the same ks - sixth note (A in C scale) */
+ } else if ((strncmp(w,"aeo",3)) == 0) {
+ sf -= 3;
+ ok = 1;
+ } else if ((strncmp(w,"min",3)) == 0) {
+ sf -= 3;
+ ok = 1;
+ } else if ((strcmp(w,"m")) == 0) {
+ sf -= 3;
+ ok = 1;
+ }
+
+ /* check for trailing "bass" "treble" "alto" */
+ else if (!strcmp(w,"bass")) {
+ ktype=BASS;
+ }
+ else if (!strcmp(w,"treble")) {
+ ktype=TREBLE;
+ }
+ else if (!strcmp(w,"alto")) {
+ ktype=ALTO;
+ }
+
+ /* check for "+8" or "-8" */
+ else if (!strcmp(w,"+8")) {
+ add_pitch=7;
+ }
+ else if (!strcmp(w,"-8")) {
+ add_pitch=-7;
+ }
+ else wng("Unknown token in key specifier: ",w);
+
+ } /* end of loop over blank-delimted words */
+
+ if (verbose>=4) printf ("Key <%s> gives sharpsflats %d, type %d\n",
+ s, sf, ktype);
+
+ /* copy to struct */
+ ks->sf = sf;
+ ks->ktype = ktype;
+ ks->add_pitch = add_pitch;
+ ks->root = root;
+ ks->root_acc = root_acc;
+
+ return 1;
+
+}
+
+/* ----- get_halftones: figure out how by many halftones to transpose --- */
+/* In the transposing routines: pitches A..G are coded as with 0..7 */
+int get_halftones (key, transpose)
+struct KEYSTR key;
+char transpose[];
+{
+ int pit_old,pit_new,direction,stype,root_new,racc_new,nht;
+ int root_old, racc_old;
+ char *q;
+ /* pit_tab associates true pitches 0-11 with letters A-G */
+ int pit_tab[] = {0,2,3,5,7,8,10};
+
+ if (strlen(transpose)==0) return 0;
+ root_old=key.root;
+ racc_old=key.root_acc;
+
+ /* parse specification for target key */
+ q=transpose;
+ direction=0;
+
+ if (*q=='^') {
+ direction=1; q++;
+ } else if (*q=='_') {
+ direction=-1; q++;
+ }
+ stype=1;
+ if (strchr("ABCDEFG",*q)) {
+ root_new=*q-'A'; q++; stype=2;
+ } else if (strchr("abcdefg",*q)) {
+ root_new=*q-'a'; q++; stype=2;
+ }
+
+ /* first case: offset was given directly as numeric argument */
+ if (stype==1) {
+ sscanf(q,"%d", &nht);
+ if (direction<0) nht=-nht;
+ if (nht==0) {
+ if (direction<0) nht=-12;
+ if (direction>0) nht=+12;
+ }
+ return nht;
+ }
+
+ /* second case: root of target key was specified explicitly */
+ racc_new=0;
+ if (*q=='b') {
+ racc_new=A_FT; q++;
+ } else if (*q=='#') {
+ racc_new=A_SH; q++;
+ } else if (*q!='\0')
+ wng ("expecting accidental in transpose spec: ", transpose);
+
+ /* get pitch as number from 0-11 for root of old key */
+ pit_old=pit_tab[root_old];
+ if (racc_old==A_FT) pit_old--;
+ if (racc_old==A_SH) pit_old++;
+ if (pit_old<0) pit_old+=12;
+ if (pit_old>11) pit_old-=12;
+
+ /* get pitch as number from 0-11 for root of new key */
+ pit_new=pit_tab[root_new];
+ if (racc_new==A_FT) pit_new--;
+ if (racc_new==A_SH) pit_new++;
+ if (pit_new<0) pit_new+=12;
+ if (pit_new>11) pit_new-=12;
+
+ /* number of halftones is difference */
+ nht=pit_new-pit_old;
+ if (direction==0) {
+ if (nht>6) nht-=12;
+ if (nht<-5) nht+=12;
+ }
+ if (direction>0 && nht<=0) nht+=12;
+ if (direction<0 && nht>=0) nht-=12;
+
+ return nht;
+
+}
+
+
+
+/* ----- shift_key: make new key by shifting nht halftones --- */
+void shift_key (sf_old,nht,sfnew,addt)
+int sf_old,nht,*sfnew,*addt;
+{
+ int sf_new,r_old,r_new,add_t, dh,dr;
+ int skey_tab[] = {2,6,3,0,4,1,5,2};
+ int fkey_tab[] = {2,5,1,4,0,3,6,2};
+ char root_tab[]={'A','B','C','D','E','F','G'};
+
+ /* get sf_new by adding 7 for each halftone, then reduce mod 12 */
+ sf_new=sf_old+nht*7;
+ sf_new=(sf_new+240)%12;
+ if (sf_new>=6) sf_new=sf_new-12;
+
+ /* get old and new root in ionian mode, shift is difference */
+ r_old=2;
+ if (sf_old>0) r_old=skey_tab[sf_old];
+ if (sf_old<0) r_old=fkey_tab[-sf_old];
+ r_new=2;
+ if (sf_new>0) r_new=skey_tab[sf_new];
+ if (sf_new<0) r_new=fkey_tab[-sf_new];
+ add_t=r_new-r_old;
+
+ /* fix up add_t to get same "decade" as nht */
+ dh=(nht+120)/12; dh=dh-10;
+ dr=(add_t+70)/7; dr=dr-10;
+ add_t=add_t+7*(dh-dr);
+
+ if (verbose>=8)
+ printf ("shift_key: sf_old=%d new %d root: old %c new %c shift by %d\n"…
+ sf_old, sf_new, root_tab[r_old], root_tab[r_new], add_t);
+
+ *sfnew=sf_new;
+ *addt=add_t;
+
+}
+
+
+/* ----- set_transtab: setup for transposition by nht halftones --- */
+void set_transtab (nht,key)
+int nht;
+struct KEYSTR *key;
+{
+ int a,b,sf_old,sf_new,add_t,i,j,acc_old,acc_new,root_old,root_acc;
+ /* for each note A..G, these tables tell how many sharps (resp. flats)
+ the keysig must have to get the accidental on this note. Phew. */
+ int sh_tab[] = {5,7,2,4,6,1,3};
+ int fl_tab[] = {3,1,6,4,2,7,5};
+ /* tables for pretty printout only */
+ char root_tab[]={'A','B','C','D','E','F','G'};
+ char acc_tab[][3] ={"bb","b "," ","# ","x "};
+ char c1[6],c2[6],c3[6];
+
+ /* nop if no transposition is wanted */
+ if (nht==0) {
+ key->add_transp=0;
+ for (i=0;i<7;i++) key->add_acc[i]=0;
+ return;
+ }
+
+ /* get new sharps_flats and shift of numeric pitch; copy to key */
+ sf_old = key->sf;
+ root_old = key->root;
+ root_acc = key->root_acc;
+ shift_key (sf_old, nht, &sf_new, &add_t);
+ key->sf = sf_new;
+ key->add_transp = add_t;
+
+ /* set up table for conversion of accidentals */
+ for (i=0;i<7;i++) {
+ j=i+add_t;
+ j=(j+70)%7;
+ acc_old=0;
+ if ( sf_old >= sh_tab[i]) acc_old=1;
+ if (-sf_old >= fl_tab[i]) acc_old=-1;
+ acc_new=0;
+ if ( sf_new >= sh_tab[j]) acc_new=1;
+ if (-sf_new >= fl_tab[j]) acc_new=-1;
+ key->add_acc[i]=acc_new-acc_old;
+ }
+
+ /* printout keysig change */
+ if (verbose>=3) {
+ i=root_old;
+ j=i+add_t;
+ j=(j+70)%7;
+ acc_old=0;
+ if ( sf_old >= sh_tab[i]) acc_old=1;
+ if (-sf_old >= fl_tab[i]) acc_old=-1;
+ acc_new=0;
+ if ( sf_new >= sh_tab[j]) acc_new=1;
+ if (-sf_new >= fl_tab[j]) acc_new=-1;
+ strcpy(c3,"s"); if (nht==1 || nht==-1) strcpy(c3,"");
+ strcpy(c1,""); strcpy(c2,"");
+ if (acc_old==-1) strcpy(c1,"b"); if (acc_old==1) strcpy(c1,"#");
+ if (acc_new==-1) strcpy(c2,"b"); if (acc_new==1) strcpy(c2,"#");
+ printf ("Transpose root from %c%s to %c%s (shift by %d halftone%s)\n",
+ root_tab[i],c1,root_tab[j],c2,nht,c3);
+ }
+
+ /* printout full table of transformations */
+ if (verbose>=4) {
+ printf ("old & new keysig conversions\n");
+ for (i=0;i<7;i++) {
+ j=i+add_t;
+ j=(j+70)%7;
+ acc_old=0;
+ if ( sf_old >= sh_tab[i]) acc_old=1;
+ if (-sf_old >= fl_tab[i]) acc_old=-1;
+ acc_new=0;
+ if ( sf_new >= sh_tab[j]) acc_new=1;
+ if (-sf_new >= fl_tab[j]) acc_new=-1;
+ printf("%c%s-> %c%s ", root_tab[i],acc_tab[acc_old+2],
+ root_tab[j],acc_tab[acc_new+2]);
+ for (a=-1;a<=1;a++) {
+ b=a+key->add_acc[i];
+ printf ("%c%s-> %c%s ", root_tab[i],acc_tab[a+2],
+ root_tab[j],acc_tab[b+2]);
+ }
+ printf ("\n");
+ }
+ }
+
+}
+
+/* ----- do_transpose: transpose numeric pitch and accidental --- */
+void do_transpose (key,pitch,acc)
+struct KEYSTR key;
+int *pitch, *acc;
+{
+ int pitch_old,pitch_new,sf_old,sf_new,acc_old,acc_new,i,j;
+
+ pitch_old = *pitch;
+ acc_old = *acc;
+ pitch_new=pitch_old+key.add_transp;
+ i=(pitch_old+70)%7;
+ j=(pitch_new+70)%7;
+
+ if (acc_old) {
+ if (acc_old==A_DF) sf_old=-2;
+ if (acc_old==A_FT) sf_old=-1;
+ if (acc_old==A_NT) sf_old=0 ;
+ if (acc_old==A_SH) sf_old=1;
+ if (acc_old==A_DS) sf_old=2;
+ sf_new=sf_old+key.add_acc[i];
+ if (sf_new==-2) acc_new=A_DF;
+ if (sf_new==-1) acc_new=A_FT;
+ if (sf_new== 0) acc_new=A_NT;
+ if (sf_new== 1) acc_new=A_SH;
+ if (sf_new== 2) acc_new=A_DS;
+ }
+ else {
+ acc_new=0;
+ }
+ *pitch = pitch_new;
+ *acc = acc_new;
+}
+
+
+/* ----- gch_transpose: transpose guitar chord string in gch --- */
+void gch_transpose (key)
+struct KEYSTR key;
+{
+ char *q,*r;
+ char str[201];
+ int root_old,root_new,sf_old,sf_new,ok;
+ char root_tab[]={'A','B','C','D','E','F','G'};
+ char root_tub[]={'a','b','c','d','e','f','g'};
+
+ if (halftones==0) return;
+
+ /* try to avoid some common abuses of gchord string */
+ if (strstr(gch,"capo")) return;
+ if (strstr(gch,"Capo")) return;
+ if (strstr(gch,"Fine")) return;
+ if (strstr(gch,"fine")) return;
+
+ q=gch;
+ r=str;
+
+ for (;;) {
+ while (*q==' ' || *q=='(') { *r=*q; q++; r++; }
+ if (*q=='\0') break;
+ ok=0;
+ if (strchr("ABCDEFG",*q)) {
+ root_old=*q-'A'; q++; ok=1;
+ } else if (strchr("abcdefg",*q)) {
+ root_old=*q-'a'; q++; ok=2;
+ }
+
+ if (ok) {
+ sf_old=0;
+ if (*q=='b') { sf_old=-1; q++; }
+ if (*q=='#') { sf_old= 1; q++; }
+ root_new=root_old+key.add_transp;
+ root_new=(root_new+28)%7;
+ sf_new=sf_old+key.add_acc[root_old];
+ if (ok==1) { *r=root_tab[root_new]; r++; }
+ if (ok==2) { *r=root_tub[root_new]; r++; }
+ if (sf_new==-1) { *r='b'; r++; }
+ if (sf_new== 1) { *r='#'; r++; }
+ }
+
+ while (*q!=' ' && *q!='/' && *q!='\0') {*r=*q; q++; r++; }
+ if (*q=='/') {*r=*q; q++; r++; }
+
+ }
+
+ *r='\0';
+/*| printf("tr_ch: <%s> <%s>\n", gch, str); |*/
+
+ strcpy (gch,str);
+
+}
+
+
+/* ----- init_parse_params: initialize variables for parsing --- */
+void init_parse_params ()
+{
+ int i;
+
+ slur=0;
+ voice[0].end_slur=0;
+ nwpool=nwline=0;
+ ntinext=0;
+
+ /* for continuation after output: reset nsym, switch to first voice */
+ for (i=0;i<nvoice;i++) {
+ voice[i].nsym=0;
+ voice[i].insert_btype=0;
+ voice[i].end_slur=0;
+ }
+
+ ivc=0;
+
+ word=0;
+ carryover=0;
+ last_note=last_real_note=-1;
+ pplet=qplet=rplet=0;
+ num_ending=0;
+ mes1=mes2=0;
+ strcpy (gch, "");
+
+}
+
+/* ----- add_text ---- */
+void add_text (str,type)
+char str[];
+int type;
+{
+ if (do_mode!=DO_OUTPUT) return;
+ if (ntext>=NTEXT) {
+ wng ("No more room for text line <%s>", str);
+ return;
+ }
+ strcpy (text[ntext], str);
+ text_type[ntext]=type;
+ ntext++;
+}
+
+/* ----- reset_info ---- */
+void reset_info (inf)
+struct ISTRUCT *inf;
+{
+
+ /* reset all info fields except info.xref */
+
+ strcpy(inf->parts, "");
+ strcpy(inf->area, "");
+ strcpy(inf->book, "");
+ inf->ncomp=0;
+ strcpy(inf->disc, "");
+ strcpy(inf->group, "");
+ strcpy(inf->hist, "");
+ strcpy(inf->info, "");
+ strcpy(inf->key, "C");
+ strcpy(inf->meter, "4/4");
+ strcpy(inf->notes, "");
+ strcpy(inf->orig, "");
+ strcpy(inf->rhyth, "");
+ strcpy(inf->src, "");
+/* strcpy(inf->title, "(untitled)"); */
+ strcpy(inf->title, "");
+ strcpy(inf->title2, "");
+ strcpy(inf->title3, "");
+ strcpy(inf->trans, "");
+ strcpy(inf->tempo, "");
+}
+
+/* ----- get_default_info: set info to default, except xref field --- */
+void get_default_info ()
+{
+ char savestr[STRL];
+
+ strcpy (savestr, info.xref);
+ info=default_info;
+ strcpy (info.xref, savestr);
+
+}
+
+/* ----- is_info_field: identify any type of info field ---- */
+int is_info_field (str)
+char str[];
+{
+ if (strlen(str)<2) return 0;
+ if (str[1]!=':') return 0;
+ if (str[0]=='|') return 0; /* |: at start of music line */
+ return 1;
+}
+
+/* ----- is_end_line: identify eof ----- */
+int is_end_line (str)
+char str[];
+{
+ if (strlen(str)<3) return 0;
+ if (str[0]=='E' && str[1]=='N' && str[2]=='D') return 1;
+ return 0;
+}
+
+/* ----- is_pseudocomment ----- */
+int is_pseudocomment (str)
+char str[];
+{
+ if (strlen(str)<2) return 0;
+ if ((str[0]=='%')&&(str[1]=='%')) return 1;
+ return 0;
+}
+
+/* ----- is_comment ----- */
+int is_comment (str)
+char str[];
+{
+ if (strlen(str)<1) return 0;
+ if (str[0]=='%') return 1;
+ if (str[0]=='\\') return 1;
+ return 0;
+}
+
+
+/* ----- trim_title: move trailing "The" to front ------------ */
+void trim_title (s,s0)
+char s[],s0[];
+{
+ char *q;
+ char rest[81],str[301];
+ int done;
+
+ strcpy (str, s0);
+ done=0;
+
+ if ((q=strchr(str,','))) {
+ if (*q != '\0') {
+ strip (rest,q+1);
+ if (!strcmp(rest,"The")) {
+ strcpy (s, rest);
+ *q = '\0';
+ strcat (s, " ");
+ strcat (s, str);
+ done=1;
+ }
+ }
+ }
+
+ if (!done) strcpy (s,s0);
+
+}
+
+
+/* ----- find_voice ----- */
+int find_voice (vid,new)
+char vid[];
+int *new;
+{
+ int i;
+
+ for (i=0;i<nvoice;i++)
+ if (!strcmp(vid,voice[i].id)) {
+ *new=0;
+ return i;
+ }
+
+ i=nvoice;
+ if (i>=maxVc)
+ rxi("Too many voices; use -maxv to increase limit, now ",maxVc);
+
+ strcpy(voice[i].id, vid);
+ strcpy(voice[i].name, "");
+ strcpy(voice[i].sname, "");
+ voice[i].stems = 0;
+ voice[i].staves = 0;
+ voice[i].brace = 0;
+ voice[i].bracket = 0;
+ voice[i].do_gch = 1;
+ voice[i].select = 1;
+ voice[i].sep=0.0;
+ voice[i].meter = default_meter;
+ voice[i].key = default_key;
+ voice[i].nsym = 0;
+ nvoice++;
+ if (verbose>5)
+ printf ("Make new voice %d with id \"%s\"\n", i,voice[i].id);
+ *new=1;
+ return i;
+
+}
+
+/* ----- switch_voice: read spec for a voice, return voice number ----- */
+int switch_voice (str)
+char str[];
+{
+ int j,np,new,ap;
+ char *r,*q;
+ char t1[201],t2[201];
+
+ if (!do_this_tune) return 0;
+
+ j=-1;
+
+ /* start loop over vioce options: parse t1=t2 */
+ r=str;
+ np=0;
+ for (;;) {
+ while (*r == ' ') r++;
+ if (*r=='\0') break;
+ strcpy(t1,"");
+ strcpy(t2,"");
+ q=t1;
+ while (*r!=' ' && *r!='\0' && *r!='=') { *q=*r; r++; q++; }
+ *q='\0';
+ if (*r=='=') {
+ r++;
+ q=t2;
+ if (*r=='"') {
+ r++;
+ while (*r!='"' && *r!='\0') { *q=*r; r++; q++; }
+ if (*r=='"') r++;
+ }
+ else {
+ while (*r!=' ' && *r!='\0') { *q=*r; r++; q++; }
+ }
+ *q='\0';
+ }
+ np++;
+
+ /* interpret the parsed option. First case is identifier. */
+ if (np==1) j=find_voice (t1,&new);
+
+ else { /* interpret option */
+ if (j<0) bug("j invalid in switch_voice",1);
+ if (!strcmp(t1,"name") || !strcmp(t1,"nm"))
+ strcpy(voice[j].name, t2);
+
+ else if (!strcmp(t1,"sname") || !strcmp(t1,"snm"))
+ strcpy(voice[j].sname, t2);
+
+ else if (!strcmp(t1,"staves") || !strcmp(t1,"stv"))
+ voice[j].staves = atoi(t2);
+
+ else if (!strcmp(t1,"brace") || !strcmp(t1,"brc"))
+ voice[j].brace = atoi(t2);
+
+ else if (!strcmp(t1,"bracket") || !strcmp(t1,"brk"))
+ voice[j].bracket = atoi(t2);
+
+ else if (!strcmp(t1,"gchords") || !strcmp(t1,"gch"))
+ g_logv (str,t2,&voice[j].do_gch);
+
+ /* for sspace: add 2000 as flag if not incremental */
+ else if (!strcmp(t1,"space") || !strcmp(t1,"spc")) {
+ g_unum (str,t2,&voice[j].sep);
+ if (t2[0]!='+' && t2[0]!='-') voice[j].sep += 2000.0;
+ }
+
+ else if (!strcmp(t1,"clef") || !strcmp(t1,"cl")) {
+ ap=0;
+ if (!strcmp(t2,"treble")) voice[j].key.ktype=TREBLE;
+ else if (!strcmp(t2,"treble+8")) {voice[j].key.ktype=TREBLE; ap=+7;}
+ else if (!strcmp(t2,"treble-8")) {voice[j].key.ktype=TREBLE; ap=-7;}
+ else if (!strcmp(t2,"treble+16")) {voice[j].key.ktype=TREBLE; ap=+14;}
+ else if (!strcmp(t2,"treble-16")) {voice[j].key.ktype=TREBLE; ap=-14;}
+ else if (!strcmp(t2,"bass")) voice[j].key.ktype=BASS;
+ else if (!strcmp(t2,"bass+8")) {voice[j].key.ktype=BASS; ap=+7;}
+ else if (!strcmp(t2,"bass-8")) {voice[j].key.ktype=BASS; ap=-7;}
+ else if (!strcmp(t2,"bass+16")) {voice[j].key.ktype=BASS; ap=+14;}
+ else if (!strcmp(t2,"bass-16")) {voice[j].key.ktype=BASS; ap=-14;}
+ else if (!strcmp(t2,"alto")) voice[j].key.ktype=ALTO;
+ else if (!strcmp(t2,"alto+8")) {voice[j].key.ktype=ALTO; ap=+7;}
+ else if (!strcmp(t2,"alto-8")) {voice[j].key.ktype=ALTO; ap=-7;}
+ else if (!strcmp(t2,"alto+16")) {voice[j].key.ktype=ALTO; ap=+14;}
+ else if (!strcmp(t2,"alto-16")) {voice[j].key.ktype=ALTO; ap=-14;}
+ else wng("Unknown clef in voice spec: ",t2);
+ voice[j].key.add_pitch=ap;
+ }
+ else if (!strcmp(t1,"stems") || !strcmp(t1,"stm")) {
+ if (!strcmp(t2,"up")) voice[j].stems=1;
+ else if (!strcmp(t2,"down")) voice[j].stems=-1;
+ else if (!strcmp(t2,"free")) voice[j].stems=0;
+ else wng("Unknown stem setting in voice spec: ",t2);
+ }
+ else wng("Unknown option in voice spec: ",t1);
+ }
+
+ }
+
+ /* if new voice was initialized, save settings im meter0, key0 */
+ if (new) {
+ voice[j].meter0 = voice[j].meter;
+ voice[j].key0 = voice[j].key;
+ }
+
+ if (verbose>7)
+ printf ("Switch to voice %d <%s> <%s> <%s> clef=%d\n",
+ j,voice[j].id,voice[j].name,voice[j].sname,
+ voice[j].key.ktype);
+
+ nsym0=voice[j].nsym; /* set nsym0 to decide about eoln later.. ugly */
+ return j;
+
+}
+
+
+/* ----- info_field: identify info line, store in proper place ---- */
+/* switch within_block: either goes to default_info or info.
+ Only xref ALWAYS goes to info. */
+int info_field (str)
+char str[];
+{
+ char t[STRL];
+ struct ISTRUCT *inf;
+ int i;
+
+ for (i=0;i<strlen(str);i++) if (str[i]=='%') str[i]='\0';
+
+ if (within_block) {
+ inf=&info;
+ }
+ else {
+ inf=&default_info;
+ }
+
+ if (strlen(str)<2) return 0;
+ if (str[1]!=':') return 0;
+ if (str[0]=='|') return 0; /* |: at start of music line */
+
+ if (str[0]=='X') {
+ strip (info.xref, &str[2]);
+ xrefnum=get_xref(info.xref);
+ return XREF;
+ }
+
+ else if (str[0]=='A') strip (inf->area, &str[2]);
+ else if (str[0]=='B') strip (inf->book, &str[2]);
+ else if (str[0]=='C') {
+ if (inf->ncomp>=NCOMP)
+ wng("Too many composer lines","");
+ else {
+ strip (inf->comp[inf->ncomp],&str[2]);
+ inf->ncomp++;
+ }
+ }
+ else if (str[0]=='D') {
+ strip (inf->disc, &str[2]);
+ add_text (&str[2], TEXT_D);
+ }
+
+ else if (str[0]=='G') strip (inf->group, &str[2]);
+ else if (str[0]=='H') {
+ strip (inf->hist, &str[2]);
+ add_text (&str[2], TEXT_H);
+ return HISTORY;
+ }
+ else if (str[0]=='W') {
+ add_text (&str[2], TEXT_W);
+ return WORDS;
+ }
+ else if (str[0]=='I') strip (inf->info, &str[2]);
+ else if (str[0]=='K') {
+ strip (inf->key, &str[2]);
+ return KEY;
+ }
+ else if (str[0]=='L') {
+ strip (inf->len, &str[2]);
+ return DLEN;
+ }
+ else if (str[0]=='M') {
+ strip (inf->meter, &str[2]);
+ return METER;
+ }
+ else if (str[0]=='N') {
+ strip (inf->notes, &str[2]);
+ add_text (&str[2], TEXT_N);
+ }
+ else if (str[0]=='O') strip (inf->orig, &str[2]);
+ else if (str[0]=='R') strip (inf->rhyth, &str[2]);
+ else if (str[0]=='P') {
+ strip (inf->parts, &str[2]);
+ return PARTS;
+ }
+ else if (str[0]=='S') strip (inf->src, &str[2]);
+ else if (str[0]=='T') {
+ strip (t, &str[2]);
+ numtitle++;
+ if (numtitle>3) numtitle=3;
+ if (numtitle==1) trim_title (inf->title, t);
+ else if (numtitle==2) trim_title (inf->title2, t);
+ else if (numtitle==3) trim_title (inf->title3, t);
+ return TITLE;
+ }
+ else if (str[0]=='V') {
+ strip (lvoiceid, &str[2]);
+ return VOICE;
+ }
+ else if (str[0]=='Z') {
+ strip (inf->trans, &str[2]);
+ add_text (&str[2], TEXT_Z);
+ }
+ else if (str[0]=='Q') {
+ strip (inf->tempo, &str[2]);
+ return TEMPO;
+ }
+
+ else if (str[0]=='E') ;
+
+ else {
+ return 0;
+ }
+
+ return INFO;
+}
+
+/* ----- append_meter: add meter to list of symbols -------- */
+void append_meter (meter)
+struct METERSTR meter;
+{
+ int kk;
+
+ kk=add_sym(TIMESIG);
+ symv[ivc][kk]=zsym;
+ symv[ivc][kk].type = TIMESIG;
+ symv[ivc][kk].u = meter.meter1;
+ symv[ivc][kk].v = meter.meter2;
+ symv[ivc][kk].w = meter.mflag;
+ strcpy(symv[ivc][kk].text,meter.top);
+
+}
+
+/* ----- append_key_change: append change of key to sym list ------ */
+void append_key_change(oldkey,newkey)
+struct KEYSTR oldkey,newkey;
+{
+ int n1,n2,t1,t2,kk;
+
+ n1=oldkey.sf;
+ t1=A_SH;
+ if (n1<0) { n1=-n1; t1=A_FT; }
+ n2=newkey.sf;
+ t2=A_SH;
+
+ if (newkey.ktype != oldkey.ktype) { /* clef change */
+ kk=add_sym(CLEF);
+ symv[ivc][kk].u=newkey.ktype;
+ symv[ivc][kk].v=1;
+ }
+
+ if (n2<0) { n2=-n2; t2=A_FT; }
+ if (t1==t2) { /* here if old and new have same type */
+ if (n2>n1) { /* more new symbols ..*/
+ kk=add_sym(KEYSIG); /* draw all of them */
+ symv[ivc][kk].u=1;
+ symv[ivc][kk].v=n2;
+ symv[ivc][kk].w=100;
+ symv[ivc][kk].t=t1;
+ }
+ else if (n2<n1) { /* less new symbols .. */
+ kk=add_sym(KEYSIG); /* draw all new symbols and neutrals */
+ symv[ivc][kk].u=1;
+ symv[ivc][kk].v=n1;
+ symv[ivc][kk].w=n2+1;
+ symv[ivc][kk].t=t2;
+ }
+ else return;
+ }
+ else { /* here for change s->f or f->s */
+ kk=add_sym(KEYSIG); /* neutralize all old symbols */
+ symv[ivc][kk].u=1;
+ symv[ivc][kk].v=n1;
+ symv[ivc][kk].w=1;
+ symv[ivc][kk].t=t1;
+ kk=add_sym(KEYSIG); /* add all new symbols */
+ symv[ivc][kk].u=1;
+ symv[ivc][kk].v=n2;
+ symv[ivc][kk].w=100;
+ symv[ivc][kk].t=t2;
+ }
+
+}
+
+
+
+/* ----- numeric_pitch ------ */
+/* adapted from abc2mtex by Chris Walshaw */
+int numeric_pitch(note)
+char note;
+{
+
+ if (note=='z')
+ return 14;
+ if (note >= 'C' && note <= 'G')
+ return(note-'C'+16+voice[ivc].key.add_pitch);
+ else if (note >= 'A' && note <= 'B')
+ return(note-'A'+21+voice[ivc].key.add_pitch);
+ else if (note >= 'c' && note <= 'g')
+ return(note-'c'+23+voice[ivc].key.add_pitch);
+ else if (note >= 'a' && note <= 'b')
+ return(note-'a'+28+voice[ivc].key.add_pitch);
+ printf ("numeric_pitch: cannot identify <%c>\n", note);
+ return(0);
+}
+
+/* ----- symbolic_pitch: translate numeric pitch back to symbol ------ */
+int symbolic_pitch(pit,str)
+int pit;
+char str[];
+{
+ int p,r,s;
+ char ltab1[7] = {'C','D','E','F','G','A','B'};
+ char ltab2[7] = {'c','d','e','f','g','a','b'};
+
+ p=pit-16;
+ r=(p+700)%7;
+ s=(p-r)/7;
+
+ if (p<7) {
+ sprintf (str,"%c,,,,,",ltab1[r]);
+ str[1-s]='\0';
+ }
+ else {
+ sprintf (str,"%c'''''",ltab2[r]);
+ str[s]='\0';
+ }
+}
+
+/* ----- handle_inside_field: act on info field inside body of tune --- */
+void handle_inside_field(type)
+int type;
+{
+ struct KEYSTR oldkey;
+ int rc;
+
+ if (type==METER) {
+ if (nvoice==0) ivc=switch_voice (DEFVOICE);
+ set_meter (info.meter,&voice[ivc].meter);
+ append_meter (voice[ivc].meter);
+ }
+
+ else if (type==DLEN) {
+ if (nvoice==0) ivc=switch_voice (DEFVOICE);
+ set_dlen (info.len, &voice[ivc].meter);
+ }
+
+ else if (type==KEY) {
+ if (nvoice==0) ivc=switch_voice (DEFVOICE);
+ oldkey=voice[ivc].key;
+ rc=set_keysig(info.key,&voice[ivc].key,0);
+ if (rc) set_transtab (halftones,&voice[ivc].key);
+ append_key_change(oldkey,voice[ivc].key);
+ }
+
+ else if (type==VOICE) {
+ ivc=switch_voice (lvoiceid);
+ }
+
+}
+
+
+
+/* ----- parse_uint: parse for unsigned integer ----- */
+int parse_uint ()
+{
+ int number,ndig;
+ char num[21];
+
+ if (!isdig(*p)) return 0;
+ ndig=0;
+ while (isdig(*p)) {
+ num[ndig]=*p;
+ ndig++;
+ num[ndig]=0;
+ p++;
+ }
+ sscanf (num, "%d", &number);
+ if (db>3) printf (" parsed unsigned int %d\n", number);
+ return number;
+
+}
+
+/* ----- parse_bar: parse for some kind of bar ---- */
+int parse_bar ()
+{
+ int k;
+
+ parse_gchord ();
+
+ /* special cases: [1 or [2 without a preceeding bar, [| */
+ if (*p=='[') {
+ if ((*(p+1)=='1') || (*(p+1)=='2')) {
+ k=add_sym (BAR);
+ symv[ivc][k].u=B_INVIS;
+ symv[ivc][k].v=1;
+ if (*(p+1)=='2') symv[ivc][k].v=2;
+ p=p+2;
+ return 1;
+ }
+ }
+
+ /* identify valid standard bar types */
+ if (*p == '|') {
+ p++;
+ if (*p == '|') {
+ k=add_sym (BAR);
+ symv[ivc][k].u=B_DBL;
+ p++;
+ }
+ else if (*p == ':') {
+ k=add_sym(BAR);
+ symv[ivc][k].u=B_LREP;
+ p++;
+ }
+ else if (*p==']') { /* code |] for fat end bar */
+ k=add_sym(BAR);
+ symv[ivc][k].u=B_FAT2;
+ p=p+1;
+ }
+ else {
+ k=add_sym(BAR);
+ symv[ivc][k].u=B_SNGL;
+ }
+ }
+ else if (*p == ':') {
+ p++;
+ if (*p == '|') {
+ k=add_sym(BAR);
+ symv[ivc][k].u=B_RREP;
+ p++;
+ }
+ else if (*p == ':') {
+ k=add_sym(BAR);
+ symv[ivc][k].u=B_DREP;
+ p++; }
+ else {
+ syntax ("Syntax error parsing bar", p-1);
+ return 0;
+ }
+ }
+
+ else if ((*p=='[') && (*(p+1)=='|') && (*(p+2)==']')) { /* code [|] invis */
+ k=add_sym(BAR);
+ symv[ivc][k].u=B_INVIS;
+ p=p+3;
+ }
+
+ else if ((*p=='[') && (*(p+1)=='|')) { /* code [| for thick-thin bar */
+ k=add_sym(BAR);
+ symv[ivc][k].u=B_FAT1;
+ p=p+2;
+ }
+
+ else return 0;
+
+ strcpy(symv[ivc][k].text,"");
+ if (strlen(gch)>0) {
+ strcpy (symv[ivc][k].text, gch);
+ strcpy (gch, "");
+ }
+
+ /* see if valid bar is followed by specifier for first or second ending */
+ if (*p=='1') { symv[ivc][k].v=1; p++; }
+ else if (*p=='2') { symv[ivc][k].v=2; p++; }
+ else if ((*p=='[') && (*(p+1)=='1')) { symv[ivc][k].v=1; p=p+2; }
+ else if ((*p=='[') && (*(p+1)=='2')) { symv[ivc][k].v=2; p=p+2; }
+ else if ((*p==' ') && (*(p+1)=='[') && (*(p+2)=='1'))
+ { symv[ivc][k].v=1; p=p+3; }
+ else if ((*p==' ') && (*(p+1)=='[') && (*(p+2)=='2'))
+ { symv[ivc][k].v=2; p=p+3; }
+
+ return 1;
+}
+
+/* ----- parse_space: parse for whitespace ---- */
+int parse_space ()
+{
+ int rc;
+
+ rc=0;
+ while ((*p==' ')||(*p=='\t')) {
+ rc=1;
+ p++;
+ }
+ if (db>3) if (rc) printf (" parsed whitespace\n");
+ return rc;
+}
+
+/* ----- parse_esc: parse for escape sequence ----- */
+int parse_esc ()
+{
+
+ int nseq;
+ char *pp;
+
+ if (*p == '\\') { /* try for \...\ sequence */
+ p++;
+ nseq=0;
+ while ((*p!='\\') && (*p!=0)) {
+ escseq[nseq]=*p;
+ nseq++;
+ p++;
+ }
+ if (*p == '\\') {
+ p++;
+ escseq[nseq]=0;
+ if (db>3) printf (" parsed esc sequence <%s>\n", escseq);
+ return ESCSEQ;
+ }
+ else {
+ if (cfmt.breakall) return DUMMY;
+ if (db>3) printf (" parsed esc to EOL.. continuation\n");
+ }
+ return CONTINUE;
+ }
+
+ /* next, try for [..] sequence */
+ if ((*p=='[') && (*(p+1)>='A') && (*(p+1)<='Z') && (*(p+2)==':')) {
+ pp=p;
+ p++;
+ nseq=0;
+ while ((*p!=']') && (*p!=0)) {
+ escseq[nseq]=*p;
+ nseq++;
+ p++;
+ }
+ if (*p == ']') {
+ p++;
+ escseq[nseq]=0;
+ if (db>3) printf (" parsed esc sequence <%s>\n", escseq);
+ return ESCSEQ;
+ }
+ syntax ("Escape sequence [..] not closed", pp);
+ return ESCSEQ;
+ }
+ return 0;
+}
+
+
+/* ----- parse_nl: parse for newline ----- */
+int parse_nl ()
+{
+
+ if ((*p == '\\')&&(*(p+1)=='\\')) {
+ p+=2;
+ return 1;
+ }
+ else
+ return 0;
+}
+
+/* ----- parse_gchord: parse guitar chord, save in buffer ----- */
+int parse_gchord ()
+{
+ char *q;
+ int n;
+
+ if (*p != '"') return 0;
+
+ q=p;
+ p++;
+ n=strlen(gch);
+ if (n > 0) syntax ("Overwrite unused guitar chord", q);
+
+ while ((*p != '"') && (*p != 0)) {
+ gch[n]=*p;
+ n++;
+ if (n >= 200) {
+ syntax ("String for guitar chord too long", q);
+ return 1;
+ }
+ p++;
+ }
+ if (*p == 0) {
+ syntax ("EOL reached while parsing guitar chord", q);
+ return 1;
+ }
+ p++;
+ gch[n]=0;
+ if (db>3) printf(" parse guitar chord <%s>\n", gch);
+
+/*| gch_transpose (voice[ivc].key); |*/
+
+ return 1;
+}
+
+
+/* ----- parse_deco: parse for decoration on note ----- */
+int parse_deco (dtype)
+int dtype[10];
+{
+ int deco,n;
+
+ n=0;
+
+ for (;;) {
+ deco=0;
+ if (*p == '~') {
+ if (DECO_IS_ROLL) deco=D_ROLL;
+ else deco=D_GRACE;
+ }
+ if (*p == '.') deco=D_STACC;
+ if (*p == 'J') deco=D_SLIDE;
+ if (*p == 'M') deco=D_EMBAR;
+ if (*p == 'H') deco=D_HOLD;
+ if (*p == 'R') deco=D_ROLL;
+ if (*p == 'T') deco=D_TRILL;
+ if (*p == 'u') deco=D_UPBOW;
+ if (*p == 'v') deco=D_DOWNBOW;
+ if (*p == 'K') deco=D_HAT;
+ if (*p == 'k') deco=D_ATT;
+
+ if (deco) {
+ p++;
+ dtype[n]=deco;
+ n++;
+ }
+ else
+ break;
+ }
+
+ return n;
+}
+
+
+/* ----- parse_length: parse length specifer for note or rest --- */
+int parse_length ()
+{
+ int len,fac;
+
+ len=voice[ivc].meter.dlen; /* start with default length */
+
+ if (len<=0) printf ("!!! parse_len: got len=%d\n", len);
+
+
+ if (isdig(*p)) { /* multiply note length */
+ fac=parse_uint ();
+ if (fac==0) fac=1;
+ len *= fac;
+ }
+
+ if (*p=='/') { /* divide note length */
+ while (*p=='/') {
+ p++;
+ if (isdig(*p))
+ fac=parse_uint();
+ else
+ fac=2;
+ if (len%fac) {
+ syntax ("Bad length divisor", p-1);
+ return len;
+ }
+ len=len/fac;
+ }
+ }
+
+ return len;
+
+}
+
+/* ----- parse_grace_sequence --------- */
+int parse_grace_sequence (pgr,agr)
+int pgr[],agr[];
+{
+
+ char *p0;
+ int n,len;
+
+ p0=p;
+ if (*p != '{') return 0;
+ p++;
+
+ n=0;
+ while (*p != '}') {
+ if (*p == '\0') {
+ syntax ("Unbalanced grace note sequence", p0);
+ return 0;
+ }
+ if (!isnote(*p)) {
+ syntax ("Unexpected symbol in grace note sequence", p);
+ p++;
+ }
+ agr[n]=0;
+ if (*p == '=') agr[n]=A_NT;
+ if (*p == '^') {
+ if (*(p+1)=='^') { agr[n]=A_DS; p++; }
+ else agr[n]=A_SH;
+ }
+ if (*p == '_') {
+ if (*(p+1)=='_') { agr[n]=A_DF; p++; }
+ else agr[n]=A_FT;
+ }
+ if (agr[n]) p++;
+
+ pgr[n] = numeric_pitch(*p);
+ p++;
+ while (*p == '\'') { pgr[n] += 7; p++; }
+ while (*p == ',') { pgr[n] -= 7; p++; }
+
+ do_transpose (voice[ivc].key, &pgr[n], &agr[n]);
+
+ len=parse_length (); /* ignore any length specifier */
+ n++;
+ }
+
+ p++;
+ return n;
+}
+
+
+/* ----- idfy_note: set head type, dots, flags for one note --- */
+int idfy_note (s)
+struct SYMBOL *s;
+{
+ int head,base,len,flags,dots;
+
+ if (s->len==0) s->len=s->lens[0];
+ len=s->len;
+
+ base=WHOLE;
+ if (len>=WHOLE) base=WHOLE;
+ else if (len>=HALF) base=HALF;
+ else if (len>=QUARTER) base=QUARTER;
+ else if (len>=EIGHTH) base=EIGHTH;
+ else if (len>=SIXTEENTH) base=SIXTEENTH;
+ else if (len>=THIRTYSECOND) base=THIRTYSECOND;
+ else if (len>=SIXTYFOURTH) base=SIXTYFOURTH;
+ else return 1;
+
+ if (base==WHOLE) head=H_OVAL;
+ else if (base==HALF) head=H_EMPTY;
+ else head=H_FULL;
+
+ if (base==SIXTYFOURTH) flags=4;
+ else if (base==THIRTYSECOND) flags=3;
+ else if (base==SIXTEENTH) flags=2;
+ else if (base==EIGHTH) flags=1;
+ else flags=0;
+
+ dots=0;
+ if (len==base) dots=0;
+ else if (2*len==3*base) dots=1;
+ else if (4*len==7*base) dots=2;
+ else if (8*len==15*base) dots=3;
+ else return 2;
+
+/*| printf ("idfy_note: length %d gives head %d, dots %d, flags %d\n", |*/
+/*| len,head,dots,flags); |*/
+
+ s->head=head;
+ s->dots=dots;
+ s->flags=flags;
+ return 0;
+}
+
+
+
+/* ----- identify_note ----- */
+void identify_note (s,q)
+struct SYMBOL *s;
+char *q;
+{
+ int rc;
+
+ rc = idfy_note (s);
+ if (rc==1) syntax("Cannot identify head for note",q);
+ if (rc==2) syntax("Cannot handle note length for note",q);
+
+ /* set flag if duration equals length of one measure */
+ if (nvoice>0) {
+ if (s->len==(WHOLE*voice[ivc].meter.meter1)/voice[ivc].meter.meter2)
+ s->fullmes=1;
+ }
+}
+
+
+/* ----- double_note: change note length for > or < char --- */
+/* Note: if symv[ivc][i] is a chord, the length shifted to the following
+ note is taken from the first note head. Problem: the crazy syntax
+ permits different lengths within a chord. */
+void double_note (i,num,sign,q)
+int i,num,sign;
+char *q;
+{
+ int m,shift,j,len;
+
+ if ((symv[ivc][i].type!=NOTE) && (symv[ivc][i].type!=REST))
+ bug("sym is not NOTE or REST in double_note", 1);
+
+ shift=0;
+ len=symv[ivc][i].lens[0];
+ for (j=0;j<num;j++) {
+ len=len/2;
+ shift -= sign*len;
+ symv[ivc][i].len += sign*len;
+ for (m=0;m<symv[ivc][i].npitch;m++) symv[ivc][i].lens[m] += sign*len;
+ }
+ identify_note (&symv[ivc][i],q);
+ carryover += shift;
+}
+
+/* ----- parse_basic_note: parse note or rest with pitch and length --*/
+int parse_basic_note (pitch,length,accidental)
+int *pitch,*length,*accidental;
+{
+ int pit,len,acc;
+
+ acc=pit=0; /* look for accidental sign */
+ if (*p == '=') acc=A_NT;
+ if (*p == '^') {
+ if (*(p+1)=='^') { acc=A_DS; p++; }
+ else acc=A_SH;
+ }
+ if (*p == '_') {
+ if (*(p+1)=='_') { acc=A_DF; p++; }
+ else acc=A_FT;
+ }
+
+ if (acc) {
+ p++;
+ if (!strchr("CDEFGABcdefgab",*p)) {
+ syntax("Missing note after accidental", p-1);
+ return 0;
+ }
+ }
+ if (!isnote(*p)) {
+ syntax ("Expecting note", p);
+ p++;
+ return 0;
+ }
+
+ pit= numeric_pitch(*p); /* basic pitch */
+ p++;
+
+ while (*p == '\'') { /* eat up following ' chars */
+ pit += 7;
+ p++;
+ }
+
+ while (*p == ',') { /* eat up following , chars */
+ pit -= 7;
+ p++;
+ }
+
+ len=parse_length();
+
+ do_transpose (voice[ivc].key, &pit, &acc);
+
+ *pitch=pit;
+ *length=len;
+ *accidental=acc;
+
+ if (db>3) printf (" parsed basic note,"
+ "length %d/%d = 1/%d, pitch %d\n",
+ len,BASE,BASE/len,pit);
+
+ return 1;
+
+}
+
+
+/* ----- parse_note: parse for one note or rest with all trimmings --- */
+int parse_note ()
+{
+ int k,deco,i,chord,m,type,rc,sl1,sl2,j;
+ int pitch,length,accidental,invis;
+ int ngr,pgr[30],agr[30],dtype[30];
+ char *q,*q0;
+
+ ngr=parse_grace_sequence(pgr,agr); /* grace notes */
+
+ parse_gchord(); /* permit chord after graces */
+
+ deco=parse_deco(dtype); /* decorations */
+
+ parse_gchord(); /* permit chord after deco */
+
+ chord=0; /* determine if chord */
+ q=p;
+ if ((*p=='+') || (*p=='[')) { chord=1; p++; }
+
+ type=invis=0;
+ if (isnote(*p)) type=NOTE;
+ if (chord && (*p=='(')) type=NOTE;
+ if (chord && (*p==')')) type=NOTE; /* this just for better error msg */
+ if ((*p=='z')||(*p=='Z')) type=REST;
+ if ((*p=='x')||(*p=='X')) {type=REST; invis=1; }
+ if (!type) return 0;
+
+ k=add_sym(type); /* add new symbol to list */
+
+
+ symv[ivc][k].dc.n=deco; /* copy over pre-parsed stuff */
+ for (i=0;i<deco;i++)
+ symv[ivc][k].dc.t[i]=dtype[i];
+ symv[ivc][k].gr.n=ngr;
+ for (i=0;i<ngr;i++) {
+ symv[ivc][k].gr.p[i]=pgr[i];
+ symv[ivc][k].gr.a[i]=agr[i];
+ }
+ if (strlen(gch)>0) {
+ gch_transpose (voice[ivc].key);
+ strcpy (symv[ivc][k].text, gch);
+ strcpy (gch, "");
+ }
+
+ q0=p;
+ if (type==REST) {
+ p++;
+ symv[ivc][k].lens[0] = parse_length();
+ symv[ivc][k].npitch=1;
+ symv[ivc][k].invis=invis;
+ if (db>3) printf (" parsed rest, length %d/%d = 1/%d\n",
+ symv[ivc][k].lens[0],BASE,BASE/symv[ivc][k].lens[0]);
+ }
+ else {
+ m=0; /* get pitch and length */
+ sl1=sl2=0;
+ for (;;) {
+ if (chord && (*p=='(')) {
+ sl1++;
+ symv[ivc][k].sl1[m]=sl1;
+ p++;
+ }
+ deco=parse_deco(dtype); /* for extra decorations within chord */
+ for (i=0;i<deco;i++) symv[ivc][k].dc.t[i+symv[ivc][k].dc.n]=dtype[i];
+ symv[ivc][k].dc.n += deco;
+
+ rc=parse_basic_note (&pitch,&length,&accidental);
+ if (rc==0) { voice[ivc].nsym--; return 0; }
+ symv[ivc][k].pits[m] = pitch;
+ symv[ivc][k].lens[m] = length;
+ symv[ivc][k].accs[m] = accidental;
+ symv[ivc][k].ti1[m] = symv[ivc][k].ti2[m] = 0;
+ for (j=0;j<ntinext;j++)
+ if (tinext[j]==symv[ivc][k].pits[m]) symv[ivc][k].ti2[m]=1;
+
+ if (chord && (*p=='-')) {symv[ivc][k].ti1[m]=1; p++;}
+
+ if (chord && (*p==')')) {
+ sl2++;
+ symv[ivc][k].sl2[m]=sl2;
+ p++;
+ }
+
+ if (chord && (*p=='-')) {symv[ivc][k].ti1[m]=1; p++;}
+
+ m++;
+
+ if (!chord) break;
+ if ((*p=='+')||(*p==']')) {
+ p++;
+ break;
+ }
+ if (*p=='\0') {
+ if (chord) syntax ("Chord not closed", q);
+ return type;
+ }
+ }
+ ntinext=0;
+ for (j=0;j<m;j++)
+ if (symv[ivc][k].ti1[j]) {
+ tinext[ntinext]=symv[ivc][k].pits[j];
+ ntinext++;
+ }
+ symv[ivc][k].npitch=m;
+ }
+
+ for (m=0;m<symv[ivc][k].npitch;m++) { /* add carryover from > or < */
+ if (symv[ivc][k].lens[m]+carryover<=0) {
+ syntax("> leads to zero or negative note length",q0);
+ }
+ else
+ symv[ivc][k].lens[m] += carryover;
+ }
+ carryover=0;
+
+ if (db>3) printf (" parsed note, decos %d, text <%s>\n",
+ symv[ivc][k].dc.n, symv[ivc][k].text);
+
+
+ symv[ivc][k].yadd=0;
+ if (voice[ivc].key.ktype==BASS) symv[ivc][k].yadd=-6;
+ if (voice[ivc].key.ktype==ALTO) symv[ivc][k].yadd=-3;
+ identify_note (&symv[ivc][k],q0);
+ return type;
+}
+
+
+/* ----- parse_sym: parse a symbol and return its type -------- */
+int parse_sym ()
+{
+ int i;
+
+ if (parse_gchord()) return GCHORD;
+ if (parse_bar()) return BAR;
+ if (parse_space()) return SPACE;
+ if (parse_nl()) return NEWLINE;
+ if ((i=parse_esc())) return i;
+ if ((i=parse_note())) return i;
+ if (parse_nl()) return NEWLINE;
+ return 0;
+}
+
+/* ----- add_wd ----- */
+char *add_wd(str)
+char str[];
+{
+ char *rp;
+ int l;
+
+ l=strlen(str);
+ if (l==0) return 0;
+ if (nwpool+l+1>NWPOOL)
+ rx ("Overflow while parsing vocals; increase NWPOOL and recompile.","");
+
+ strcpy(wpool+nwpool, str);
+ rp=wpool+nwpool;
+ nwpool=nwpool+l+1;
+ return rp;
+}
+
+/* ----- parse_vocals: parse words below a line of music ----- */
+/* Use '^' to mark a '-' between syllables - hope nobody needs '^' ! */
+int parse_vocals (line)
+char line[];
+{
+ int isym;
+ char *c,*c1,*w;
+ char word[81];
+
+ if ((line[0]!='w') || (line[1]!=':')) return 0;
+ p0=line;
+
+ isym=nsym0-1;
+ c=line+2;
+ for (;;) {
+ while(*c==' ') c++;
+ if (*c=='\0') break;
+ c1=c;
+ if ((*c=='_') || (*c=='*') || (*c=='|') || (*c=='-')) {
+ word[0]=*c;
+ if (*c=='-') word[0]='^';
+ word[1]='\0';
+ c++;
+ }
+ else {
+ w=word;
+ *w='\0';
+ while ((*c!=' ') && (*c!='\0')) {
+ if ((*c=='_') || (*c=='*') || (*c=='|')) break;
+ if (*c=='-') {
+ if (*(c-1) != '\\') break;
+ w--;
+ *w='-';
+ }
+ *w=*c; w++; c++;
+ }
+ if (*c=='-') { *w='^' ; w++; c++; }
+ *w='\0';
+ }
+
+ /* now word contains a word, possibly with trailing '^',
+ or one of the special characters * | _ - */
+
+ if (!strcmp(word,"|")) { /* skip forward to next bar */
+ isym++;
+ while ((symv[ivc][isym].type!=BAR) && (isym<voice[ivc].nsym)) isym++;
+ if (isym>=voice[ivc].nsym)
+ { syntax("Not enough bar lines for |",c1); break; }
+ }
+
+ else { /* store word in next note */
+ w=word;
+ while (*w!='\0') { /* replace * and ~ by space */
+ if ((*w=='*') || (*w=='~')) *w=' ';
+ w++;
+ }
+ isym++;
+ while ((symv[ivc][isym].type!=NOTE) && (isym<voice[ivc].nsym)) isym++;
+ if (isym>=voice[ivc].nsym)
+ { syntax ("Not enough notes for words",c1); break; }
+ symv[ivc][isym].wordp[nwline]=add_wd(word);
+ }
+
+ if (*c=='\0') break;
+ }
+
+ nwline++;
+ return 1;
+}
+
+
+/* ----- parse_music_line: parse a music line into symbols ----- */
+int parse_music_line (line)
+char line[];
+{
+ int type,num,nbr,n,itype,i,nsym00;
+ char msg[81];
+ char *p1,*pmx;
+
+ if (nvoice==0) ivc=switch_voice (DEFVOICE);
+ if (ivc>=nvoice) bug ("Trying to parse undefined voice",1);
+
+ nwline=0;
+ nsym0=voice[ivc].nsym;
+ nsym00=nsym0;
+
+ nbr=0;
+ p=p0=line;
+ pmx=p+strlen(p);
+
+ while (*p != 0) {
+ if (p>pmx) break; /* emergency exit */
+ type=parse_sym();
+ n=voice[ivc].nsym;
+ i=n-1;
+ if ((db>4) && type)
+ printf (" sym[%d] code (%d,%d)\n",
+ n-1,symv[ivc][n-1].type,symv[ivc][n-1].u);
+
+ if (type==NEWLINE) {
+ if ((n>0) && !cfmt.continueall && !cfmt.barsperstaff) {
+ symv[ivc][i].eoln=1;
+ if (word) {
+ symv[ivc][last_note].word_end=1;
+ word=0;
+ }
+ }
+ }
+
+ if (type==ESCSEQ) {
+ if (db>3)
+ printf ("Handle escape sequence <%s>\n", escseq);
+ itype=info_field (escseq);
+ handle_inside_field (itype);
+ }
+
+ if (type==REST) {
+ if (pplet) { /* n-plet can start on rest */
+ symv[ivc][i].p_plet=pplet;
+ symv[ivc][i].q_plet=qplet;
+ symv[ivc][i].r_plet=rplet;
+ pplet=0;
+ }
+ last_note=i; /* need this so > and < work */
+ p1=p;
+ }
+
+ if (type==NOTE) {
+ if (!word) {
+ symv[ivc][i].word_st=1;
+ word=1;
+ }
+ symv[ivc][i].slur_st+=nbr;
+ nbr=0;
+ if (voice[ivc].end_slur) symv[ivc][i].slur_end++;
+ voice[ivc].end_slur=0;
+
+ if (pplet) { /* start of n-plet */
+ symv[ivc][i].p_plet=pplet;
+ symv[ivc][i].q_plet=qplet;
+ symv[ivc][i].r_plet=rplet;
+ pplet=0;
+ }
+ last_note=last_real_note=i;
+ p1=p;
+ }
+
+ if (word && ((type==BAR)||(type==SPACE))) {
+ if (last_real_note>=0) symv[ivc][last_real_note].word_end=1;
+ word=0;
+ }
+
+ if (!type) {
+
+ if (*p == '-') { /* a-b tie */
+ symv[ivc][last_note].slur_st++;
+ voice[ivc].end_slur=1;
+ p++;
+ }
+
+ else if (*p == '(') {
+ p++;
+ if (isdig(*p)) {
+ pplet=*p-'0'; qplet=0; rplet=pplet;
+ p++;
+ if (*p == ':') {
+ p++;
+ if (isdig(*p)) { qplet=*p-'0'; p++; }
+ if (*p == ':') {
+ p++;
+ if (isdig(*p)) { rplet=*p-'0'; p++; }
+ }
+ }
+ }
+ else {
+ nbr++;
+ }
+ }
+ else if (*p == ')') {
+ if (last_note>0)
+ symv[ivc][last_note].slur_end++;
+ else
+ syntax ("Unexpected symbol",p);
+ p++;
+ }
+ else if (*p == '>') {
+ num=1;
+ p++;
+ while (*p == '>') { num++; p++; }
+ if (last_note<0)
+ syntax ("No note before > sign", p);
+ else
+ double_note (last_note, num, 1, p1);
+ }
+ else if (*p == '<') {
+ num=1;
+ p++;
+ while (*p == '<') { num++; p++; }
+ if (last_note<0)
+ syntax ("No note before < sign", p);
+ else
+ double_note (last_note, num, -1, p1);
+ }
+ else if (*p == '*') /* ignore stars for now */
+ p++;
+ else if (*p == '!') /* ditto for '!' */
+ p++;
+ else {
+ if (*p != '\0')
+ sprintf (msg, "Unexpected symbol \'%c\'", *p);
+ else
+ sprintf (msg, "Unexpected end of line");
+ syntax (msg, p);
+ p++;
+ }
+ }
+ }
+
+ /* maybe set end-of-line marker, if symbols were added */
+ n=voice[ivc].nsym;
+
+ if (n>nsym0) {
+ symv[ivc][n-1].eoln=1;
+ if (type==CONTINUE) symv[ivc][n-1].eoln=0;
+ if (cfmt.barsperstaff) symv[ivc][n-1].eoln=0;
+ if (cfmt.continueall) symv[ivc][n-1].eoln=0;
+ }
+
+
+
+ /* break words at end of line */
+ if (word && (symv[ivc][n-1].eoln==1)) {
+ symv[ivc][last_note].word_end=1;
+ word=0;
+ }
+
+ if (vb>9)
+ printf ("Parsed music symbols %d to %d for voice %d\n",
+ nsym00,voice[ivc].nsym-1,ivc);
+
+ return MUSIC;
+
+}
+
+/* ----- is_selected: check selection for current info fields ---- */
+int is_selected (xref_str,npat,pat,select_all,search_field)
+int npat,select_all,search_field;
+char xref_str[],pat[][STRL1];
+{
+ int i,j,a,b,m;
+
+ /* true if select_all or if no selectors given */
+ if (select_all) return 1;
+ if (isblank(xref_str) && (npat==0)) return 1;
+
+ for (i=0;i<npat;i++) { /*patterns */
+ if (search_field==S_COMPOSER) {
+ for (j=0;j<info.ncomp;j++) {
+ if (!m) m=match(info.comp[j],pat[i]);
+ }
+ }
+ else if (search_field==S_SOURCE)
+ m=match(info.src,pat[i]);
+ else if (search_field==S_RHYTHM)
+ m=match(info.rhyth,pat[i]);
+ else {
+ m=match(info.title,pat[i]);
+ if ((!m) && (numtitle>=2)) m=match(info.title2,pat[i]);
+ if ((!m) && (numtitle>=3)) m=match(info.title3,pat[i]);
+ }
+ if (m) return 1;
+ }
+
+ /* check xref against string of numbers */
+ p=xref_str;
+ while (*p != 0) {
+ parse_space();
+ a=parse_uint();
+ if (!a) return 0; /* can happen if invalid chars in string */
+ parse_space();
+ if (*p == '-') {
+ p++;
+ parse_space();
+ b=parse_uint();
+ if (!b) {
+ if (xrefnum>=a) return 1;
+ }
+ else
+ for (i=a;i<=b;i++) if (xrefnum==i) return 1;
+ }
+ else {
+ if (xrefnum==a) return 1;
+ }
+ if (*p == ',') p++;
+ }
+
+ return 0;
+
+}
+
+/* ----- rehash_selectors: split selectors into patterns and xrefs -- */
+int rehash_selectors (sel_str, xref_str, pat)
+char sel_str[], xref_str[];
+char pat[][STRL1];
+{
+ char *q;
+ char arg[501];
+ int i,npat;
+
+ npat=0;
+ strcpy (xref_str, "");
+ q=sel_str;
+
+ i=0;
+ while (1) {
+ if ((*q==' ') || (*q=='\0')) {
+ arg[i]='\0';
+ i=0;
+ if (!isblank(arg)) {
+ if (arg[0]=='-') /* skip any flags */
+ ;
+ else if (is_xrefstr(arg)) {
+ strcat(xref_str, arg);
+ strcat(xref_str, " ");
+ }
+ else { /* pattern with * or + */
+ if ((strchr(arg,'*')) || (strchr(arg,'+'))) {
+ strcpy(pat[npat],arg);
+ }
+ else { /* simple pattern */
+ strcpy(pat[npat],"*");
+ strcat(pat[npat],arg);
+ strcat(pat[npat],"*");
+ }
+ npat++;
+ }
+ }
+ }
+ else {
+ arg[i]=*q;
+ i++;
+ }
+ if (*q=='\0') break;
+ q++;
+ }
+ return npat;
+}
+
+
+/* ----- decomment_line: cut off after % ----- */
+void decomment_line (ln)
+char ln[];
+{
+ int i;
+
+ for (i=0;i<strlen(ln);i++) if (ln[i]=='%') ln[i]='\0';
+
+}
+
+
+/* ----- get_line: read line, do first operations on it ----- */
+int get_line (fp,ln)
+FILE *fp;
+char ln[];
+{
+ int l;
+
+ strcpy (ln, "");
+ if (feof(fp)) return 0;
+
+ getline(ln, BSIZE, fp);
+/*| fgets(ln, BSIZE, fp); |*/
+ linenum++;
+ l=strlen(ln);
+ if (l>STRL) {
+ if (verbose<=2) printf ("\n");
+ printf ("+++ Line %d too long, truncate from %d to %d chars\n",
+ linenum, l, STRL);
+ l=STRL-1;
+ ln[l]='\0';
+ }
+ if (is_end_line(ln)) return 0;
+ if (ln[l-1]=='\n') ln[l-1]='\0';
+
+ if ((verbose>=7) || (vb>=10) ) printf ("%3d %s \n", linenum, ln);
+
+ return 1;
+
+}
+
+
+/* ----- read_line: returns type of line scanned --- */
+int read_line (fp,line)
+FILE *fp;
+char line[BSIZE];
+{
+ int type,nsym0;
+
+ if (!get_line(fp,line)) return E_O_F;
+
+ if (isblank(line)) return BLANK;
+ if (is_pseudocomment(line)) return PSCOMMENT;
+ if (is_comment(line)) return COMMENT;
+ decomment_line (line);
+
+ if ((type=info_field(line))) {
+ /* skip after history field. Nightmarish syntax, that. */
+ if (type != HISTORY)
+ return type;
+ else {
+ for (;;) {
+ if (! get_line(fp,line)) return E_O_F;
+ if (isblank(line)) return BLANK;
+ if (is_info_field(line)) break;
+ add_text (line, TEXT_H);
+ }
+ type=info_field (line);
+ return type;
+ }
+ }
+
+ if (do_this_tune) {
+ if (parse_vocals(line)) return MWORDS;
+ }
+
+ return MUSIC;
+
+}
+
+/* ----- do_index: print index of abc file ------ */
+void do_index(fp,xref_str,npat,pat,select_all,search_field)
+FILE *fp;
+int npat,select_all,search_field;
+char xref_str[],pat[][STRL1];
+{
+ int type,within_tune;
+ char line[BSIZE];
+
+ linenum=0;
+ verbose=vb;
+ numtitle=0;
+ write_history=0;
+ within_tune=within_block=do_this_tune=0;
+ reset_info (&default_info);
+ info=default_info;
+
+ for (;;) {
+ if (!get_line(fp,line)) break;
+ if (is_comment(line)) continue;
+ decomment_line (line);
+ type=info_field (line);
+
+ switch (type) {
+
+ case XREF:
+ if (within_block)
+ printf ("+++ Tune %d not closed properly \n", xrefnum);
+ numtitle=0;
+ within_tune=0;
+ within_block=1;
+ ntext=0;
+ break;
+
+ case KEY:
+ if (!within_block) break;
+ if (!within_tune) {
+ tnum2++;
+ if (is_selected (xref_str,npat,pat,select_all,search_field)) {
+ printf (" %-4d %-5s %-4s", xrefnum, info.key, info.meter);
+ if (search_field==S_SOURCE) printf (" %-15s", info.src);
+ else if (search_field==S_RHYTHM) printf (" %-8s", info.rhyth);
+ else if (search_field==S_COMPOSER) printf (" %-15s", info.comp[0]);
+ if (numtitle==3)
+ printf (" %s - %s - %s", info.title,info.title2,info.title3);
+ if (numtitle==2) printf (" %s - %s", info.title, info.title2);
+ if (numtitle==1) printf (" %s", info.title);
+
+ printf ("\n");
+ tnum1++;
+ }
+ within_tune=1;
+ }
+ break;
+
+ }
+
+ if (isblank(line)) {
+ if (within_block && !within_tune)
+ printf ("+++ Header not closed in tune %d\n", xrefnum);
+ within_tune=0;
+ within_block=0;
+ info=default_info;
+ }
+ }
+ if (within_block && !within_tune)
+ printf ("+++ Header not closed in for tune %d\n", xrefnum);
+
+}
+
+
+
+
+
diff --git a/pssubs.h b/pssubs.h
@@ -0,0 +1,338 @@
+/*
+ * This file is part of abc2ps,
+ * Copyright (C) 1996,1997,1998 Michael Methfessel
+ * See file abc2ps.c for details.
+ */
+
+/* subroutines for postscript output */
+
+
+/* ----- level1_fix: special defs for level 1 Postscript ------- */
+void level1_fix (fp)
+FILE *fp;
+{
+
+ fprintf (fp,
+ "/selectfont { exch findfont exch dup %% emulate level 2 op\n"
+ " type /arraytype eq {makefont}{scalefont} ifelse setfont\n"
+ "} bind def\n"
+ );
+
+ /* fix to define ISOLatin1Encoding for ps level 1 (david weisman) */
+
+ fprintf (fp,
+ "/ISOLatin1Encoding\n"
+ "[ /.notdef /.notdef /.notdef /.notdef\n"
+ "/.notdef /.notdef /.notdef /.notdef\n"
+ "/.notdef /.notdef /.notdef /.notdef\n"
+ "/.notdef /.notdef /.notdef /.notdef\n"
+ "/.notdef /.notdef /.notdef /.notdef\n"
+ "/.notdef /.notdef /.notdef /.notdef\n"
+ "/.notdef /.notdef /.notdef /.notdef\n"
+ "/.notdef /.notdef /.notdef /.notdef\n"
+ "/space /exclam /quotedbl /numbersign\n"
+ "/dollar /percent /ampersand /quoteright\n"
+ "/parenleft /parenright /asterisk /plus\n"
+ "/comma /hyphen /period /slash\n"
+ "/zero /one /two /three\n"
+ "/four /five /six /seven\n"
+ "/eight /nine /colon /semicolon\n"
+ "/less /equal /greater /question\n"
+ "/at /A/B/C/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z /…
+ "/backslash /bracketright/asciicircum/underscore\n"
+ "/quoteleft /a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z /…
+ "/bar /braceright/asciitilde /.notdef\n"
+ "/.notdef /.notdef /.notdef /.notdef\n"
+ "/.notdef /.notdef /.notdef /.notdef\n"
+ "/.notdef /.notdef /.notdef /.notdef\n"
+ "/.notdef /.notdef /.notdef /.notdef\n"
+ "/dotlessi /grave /acute /circumflex\n"
+ "/tilde /macron /breve /dotaccent\n"
+ "/dieresis /.notdef /ring /cedilla\n"
+ "/.notdef /hungarumlaut/ogonek /caron\n"
+ "/space /exclamdown /cent /sterling\n"
+ "/currency /yen /brokenbar /section\n"
+ "/dieresis /copyright /ordfeminine/guillemotleft\n"
+ "/logicalnot /hyphen /registered /macron\n"
+ "/degree /plusminus /twosuperior/threesuperior\n"
+ "/acute /mu /paragraph /periodcentered\n"
+ "/cedilla /onesuperior/ordmasculine/guillemotright\n"
+ "/onequarter /onehalf /threequarters/questiondown\n"
+ "/Agrave /Aacute /Acircumflex/Atilde\n"
+ "/Adieresis /Aring /AE /Ccedilla\n"
+ "/Egrave /Eacute /Ecircumflex/Edieresis\n"
+ "/Igrave /Iacute /Icircumflex/Idieresis\n"
+ "/Eth /Ntilde /Ograve /Oacute\n"
+ "/Ocircumflex/Otilde /Odieresis /multiply\n"
+ "/Oslash /Ugrave /Uacute /Ucircumflex\n"
+ "/Udieresis /Yacute /Thorn /germandbls\n"
+ "/agrave /aacute /acircumflex/atilde\n"
+ "/adieresis /aring /ae /ccedilla\n"
+ "/egrave /eacute /ecircumflex/edieresis\n"
+ "/igrave /iacute /icircumflex/idieresis\n"
+ "/eth /ntilde /ograve /oacute\n"
+ "/ocircumflex/otilde /odieresis /divide\n"
+ "/oslash /ugrave /uacute /ucircumflex\n"
+ "/udieresis /yacute /thorn /ydieresis\n"
+ "] def\n\n"
+ );
+
+ /* end fix to define ISOLatin1Encoding for ps level 1 */
+
+
+}
+
+/* ----- init_ps ------- */
+void init_ps (fp,str,is_epsf,bx1,by1,bx2,by2)
+FILE *fp;
+char str[];
+int is_epsf;
+float bx1,bx2,by1,by2;
+{
+ time_t ltime;
+ char tstr[41];
+ int i;
+
+ if (is_epsf) {
+ if (vb>=8) printf("Open EPS file with title \"%s\"\n", str);
+ fprintf (fp, "%%!PS-Adobe-3.0 EPSF-3.0\n");
+ fprintf (fp, "%%%%BoundingBox: %.0f %.0f %.0f %.0f\n",
+ bx1,by1,bx2,by2);
+ }
+ else {
+ if (vb>=8) printf("Open PS file with title \"%s\"\n", str);
+ fprintf (fp, "%%!PS-Adobe-3.0\n");
+ }
+
+ /* Title */
+ fprintf (fp, "%%%%Title: %s\n", str);
+
+ /* CreationDate */
+ time(&ltime);
+ strcpy (tstr, ctime(&ltime));
+ tstr[24]='\0';
+ tstr[16]='\0';
+ fprintf (fp, "%%%%Creator: abc2ps %s.%s\n", VERSION, REVISION);
+ fprintf (fp, "%%%%CreationDate: %s %s\n", tstr+4,tstr+20);
+
+ if (PS_LEVEL == 2) fprintf (fp, "%%%%LanguageLevel: 2\n");
+ fprintf (fp, "%%%%EndComments\n\n");
+
+ if (is_epsf)
+ fprintf (fp, "gsave /origstate save def mark\n100 dict begin\n\n");
+
+ fprintf (fp, "%%%%BeginSetup\n");
+ if (PS_LEVEL < 2) level1_fix (fp);
+ if (vb>=7) printf ("\nDefining ISO fonts in file header:\n");
+ for (i=0;i<nfontnames;i++) {
+ define_font (fp,fontnames[i],i);
+ if (vb>=7) printf (" F%d %s\n", i,fontnames[i]);
+ }
+ define_symbols (fp);
+ fprintf (fp, "\n0 setlinecap 0 setlinejoin 0.8 setlinewidth\n");
+ fprintf (fp, "\n/T {translate} bind def\n/M {moveto} bind def\n");
+ fprintf (fp, "%%%%EndSetup\n");
+ file_initialized=1;
+}
+
+/* ----- close_ps ------- */
+void close_ps (fp)
+FILE *fp;
+{
+ if(vb>=8) printf ("closing PS file\n");
+ fprintf (fp,
+ "%%EOF\n\n"
+ );
+}
+
+/* ----- init_page: initialize postscript page ----- */
+void init_page (fp)
+FILE *fp;
+{
+
+ if (vb>=10) printf ("init_page called; in_page=%d\n", in_page);
+ if (in_page) return;
+
+ if (!file_initialized) {
+ if (vb>=10) printf ("file not yet initialized; do it now\n");
+ init_ps (fp,infostr, 0,0.0,0.0,0.0,0.0);
+ }
+ in_page=1;
+ pagenum++;
+
+ if (verbose==0) ;
+ else if (verbose==1) printf ("[%d] ", pagenum);
+ else if (verbose==2) printf ("[%d] ", pagenum);
+ else printf ("[%d]\n", pagenum);
+ fflush (stdout);
+ fprintf (fp,
+ "\n%% --- page %d\n"
+ "%%%%Page: %d %d\n"
+ "%%%%BeginPageSetup\n",
+ pagenum, pagenum, pagenum);
+
+ if (cfmt.landscape) fprintf(fp,"%%%%PageOrientation: Landscape\n");
+ fprintf(fp,"gsave ");
+ if (cfmt.landscape) fprintf(fp,"90 rotate 0 %.1f translate ",
+ -cfmt.pageheight);
+ fprintf (fp,"%.2f %.2f translate\n",
+ cfmt.leftmargin, cfmt.pageheight-cfmt.topmargin);
+ fprintf (fp, "%%%%EndPageSetup\n");
+
+
+ /* write page number */
+ if (pagenumbers) {
+ fprintf (fp, "/Times-Roman 12 selectfont ");
+
+ /* page numbers always at right */
+ fprintf(fp, "%.1f %.1f moveto (%d) /bx false def lshow\n",
+ cfmt.staffwidth, cfmt.topmargin-30.0, pagenum);
+
+ /* page number right/left for odd/even pages */
+/*| if (pagenum%2==0) |*/
+/*| fprintf(fp, "%.1f %.1f moveto (%d) show\n", |*/
+/*| 0.0, cfmt.topmargin-30.0, pagenum); |*/
+/*| else |*/
+/*| fprintf(fp, "%.1f %.1f moveto (%d) lshow\n", |*/
+/*| cfmt.staffwidth, cfmt.topmargin-30.0, pagenum); |*/
+
+ }
+
+}
+
+/* ----- init_index_page ----- */
+void init_index_page (fp)
+FILE *fp;
+{
+ float hsize;
+
+ index_pagenum++;
+
+ fprintf (fp,
+ "\n%% --- page %d\n"
+ "%%%%Page: %d %d\n"
+ "%%%%BeginPageSetup\n",
+ index_pagenum, index_pagenum, index_pagenum);
+
+ if (cfmt.landscape) fprintf(fp,"%%%%PageOrientation: Landscape\n");
+ if (cfmt.landscape) fprintf(fp,"90 rotate 0 %.1f translate ",
+ -cfmt.pageheight);
+ fprintf (findex, "gsave\n");
+ fprintf (fp, "%%%%EndPageSetup\n\n");
+
+ index_posx=cfmt.leftmargin;
+ index_posy=cfmt.pageheight-cfmt.topmargin;
+ /* extra space at top.. */
+
+ index_posy = index_posy - 2*cfmt.indexfont.size;
+
+ /* write heading */
+ if (index_pagenum == 1) {
+ hsize = 1.5*cfmt.indexfont.size;
+ index_posy = index_posy - hsize;
+ fprintf (findex, "%.1f %d F1 \n", hsize,cfmt.indexfont.box);
+ fprintf (findex, "%.2f %.2f M (Contents) S\n", index_posx, index_posy);
+ index_posy = index_posy - cfmt.indexfont.size;
+ }
+
+ fprintf (findex, "%.1f %d F1 \n",
+ cfmt.indexfont.size, cfmt.indexfont.box);
+
+}
+
+
+
+/* ----- init_index_file ------- */
+void init_index_file ()
+{
+ time_t ltime;
+ char tstr[41];
+
+ fprintf (findex, "%%!PS-Adobe-3.0\n");
+ fprintf (findex, "%%%%Title: abc2ps index\n");
+ time(&ltime);
+ strcpy (tstr, ctime(&ltime));
+ tstr[24]='\0';
+ tstr[16]='\0';
+ fprintf (findex, "%%%%Creator: abc2ps %s.%s\n", VERSION, REVISION);
+ fprintf (findex, "%%%%CreationDate: %s %s\n", tstr+4,tstr+20);
+ if (PS_LEVEL == 2) fprintf (findex, "%%%%LanguageLevel: 2\n");
+ fprintf (findex, "%%%%EndComments\n\n");
+
+ fprintf (findex, "%%%%BeginSetup\n");
+ if (PS_LEVEL < 2) level1_fix (findex);
+
+ define_font (findex,cfmt.indexfont.name,1);
+ fprintf (findex, "\n/T {translate} bind def\n/M {moveto} bind def\n");
+ fprintf (findex, "/S {show} bind def\n");
+ def_misc (findex);
+ fprintf (findex, "%%%%EndSetup\n\n");
+
+ index_pagenum=0;
+ init_index_page (findex);
+
+ index_initialized=1;
+
+}
+
+
+/* ----- close_index_page-------- */
+void close_index_page (fp)
+FILE *fp;
+{
+
+ fprintf (fp,
+ "\n%%%%PageTrailer\n"
+ "grestore\n"
+ "showpage\n");
+}
+
+
+/* ----- close_page-------- */
+void close_page (fp)
+FILE *fp;
+{
+ if (vb>=10) printf ("close_page called; in_page=%d\n", in_page);
+
+ if (! in_page) return;
+ in_page=0;
+
+ fprintf (fp,
+ "\n%%%%PageTrailer\n"
+ "grestore\n"
+ "showpage\n");
+}
+
+
+/* ----- init_epsf: initialize epsf file ----- */
+void init_epsf (fp)
+FILE *fp;
+{
+ float px,py;
+ px=cfmt.leftmargin;
+ py=cfmt.pageheight-cfmt.topmargin;
+ fprintf (fp, "%.2f %.2f translate\n", px, py);
+}
+
+/* ----- close_epsf: close epsf file ----- */
+void close_epsf (fp)
+FILE *fp;
+{
+ fprintf (fp,
+ "\nshowpage\nend\n"
+ "cleartomark origstate restore grestore\n\n");
+}
+
+
+/* ----- write_pagebreak ----- */
+void write_pagebreak (fp)
+FILE *fp;
+{
+
+ close_page (fp);
+ init_page (fp);
+ if (strlen(page_init)>0) fprintf(fp,"%s\n", page_init);
+ posy=cfmt.pageheight-cfmt.topmargin;
+
+}
+
diff --git a/sample.abc b/sample.abc
@@ -0,0 +1,122 @@
+% Sample file to test various features of abc2ps
+
+X:1
+T:Scale
+T:Second Title
+T:Third Title
+M:C
+K:C
+L: 1/4
+ "C,"C,"D,"D,"E,"E,"F,"F, "G,"G,"A,"A,"B,"B,\
+| "C"C"D"D"E"E"F"F "G"G"A"A"B"B| "c"c "d"d"e"e"f"f "g"g"a"a"b"b"c'"c' |
+
+X:3
+T:Short and Long Notes, Beams, N-tuplets
+C:Trad
+M:C
+K:C
+L: 1/8
+ c8| d4 e2 fg | C c C/ c/ d/e/ d// C// C/D/E/F/ | d>e d>>e e<fe (3CDE (4fgab |
+
+X:4
+T:Key signature, Accidentals and Decorations
+M:C
+K:A
+L: 1/4
+ ^C=C_C ^G=G_G | .F/.G/.A/ Ma/Mg/Mf/ Jc J^c J[c^f] J[c^g] |\
+ {f}e {C}D {cd}c {E^c}a2 {dedc}d|
+ uc vc'-c'/Mb/Mc'/Ma/ | (b4 | b/).a/.b/.c'/ | ~A ~g \
+ RA Rg MA Mg kA kg | KA Kg vf/-g/ (u.a/.b/) | uR~M.c2 Hg4 ||
+
+X:5
+T:Bars and Rests
+M:6/8
+L: 1/4
+K:D
+[| z4 |] z2 |: z z/z// :| z2> :: z2 z>z | f>z g>z ||
+
+X:6
+T:Chords, Unions, First and Second Endings
+M:9/8
+K:D
+L: 1/4
+|: [D2FA] ~+d2fa+ | [c2e][df][eg]|\
+ [cc] [dd] [F/A][G/B][D/F]>[C/E] [G/e][A/e] [G/e]>.[A/e][B/e]>.[c/e]\
+|1 (3[A//df][A//ef][A//cg] [G3Ce] :|2 (3[A//=df][^A//dg][_A//_c^g] [e3gc] |]
+
+X:7
+T:Slurs and Ties
+T: Title with funny chars like \cC\'e\~n\^o \`A\cc\"a\ss\"o \251
+M:C|
+K:Ebm
+[| (CDEF) ((3efg) ((3gag)| (C2 EF) (ef(ga)) | ((c2 (3(d)ef) e2)\
+ A2-|A4 (c4|(c4)(e4)|a8) |]
+
+X:8
+T:Changing Time or Key Signatures, Guitar Chords
+M: 6/8
+K: G
+ "Em"ABc def |\
+M: 9/8
+"Am7"A,CC DFF GBB |\M:4/4\"G"a,2b,2"D"c2d2 ||\L:1/4\\K:Bb\"Eb"e4|
+K: Gb
+M: 6/8
+| -"Gb"ede edc | def fed |1 "A"efg "D"gfe | e6 \
+:|2 "G"gag "F"f"Em"e"D7"d | "C"c6 |]
+
+X:9
+T:Strange tuplet cases
+M:C
+K:C
+L: 1/8
+ (3cde c(3d/e/f/ |(3zcd (3z/c/d/ (3czc c(4d/e/f/z/ d2-(3def | \
+ (3::2 c4d2 (3::4 cde/f/ (3gfe |
+ (3z2G,2A,2 (3C2E2G2 |e-(5e//f//g//f//g// de- (5e//f//g//f//g// |\
+ (6z/c/e/g/e/c/ (6z/c/e/g/e/c/ | (3d/e/f/g-(3g/f/e/d ||
+
+X:10
+T:Chords with many accidentals
+M: 6/8
+K: G
+[^c^d] [^c^e] [^c^f] [^c^g] [^c^a] [^c^b] |\
+[^C^D] [^C^E] [^C^F] [^C^G] [^C^A] [^C^B] |\
+[^c^d^e] [^c^d^f] [^c^f^g] [^c^f^a] [^c=d=f^g_a_b] |]
+[^c^f^a] [^c^f^b] [^c^f^c'] [^c^f^d'] [^c^f^e'] |\
+[^c^e^f] [^c^f^g] [^c^g^a] [^c^g^b] |\
+ [^c^d^c'] [^c^e^c'] [^A^e^c'] [^G^e^c'] \
+ [^c^d^c'][^c^e^c'][^A^e^c'][^G^e^c'] ||
+
+X:11
+T:Horizontal beams
+M:C
+K:C
+L: 1/8
+ c,d,c, d,e,d, e,f,e, b,cb, | c,/d,/c,/ d,/e,/d,/ e,/f,/e,/ |\
+ c,//d,//c,// d,//e,//d,// e,//f,//e,// |
+ cdc ded efe b,a,b,| c/d/c/ d/e/d/ e/f/e/ | c//d//c// d//e//d// e//f//e// |
+ c'd'c' d'e'd' e'f'e' f'g'f' | c'/d'/c'/ d'/e'/d'/ e'/f'/e'/ |\
+ c'//d'//c'// d'//e'//d'// e'//f'//e'// |
+
+X:12
+T:Gracenotes
+L:1/8
+M:C
+K:D
+FA{c}AF DF{^dc}A f{A}df f{AGA}df |{B}D2 {A}D2 {G}D2 {F}D2 {E}D2 |\
+ {E}c2 {F}c2 {G}c2 {A}c2 {B}c2 |
+ {A}^c2 {gcd}c2 {gAGAG}A2{g}c<{GdG}e {Gdc}d>c {gBd}B<{e}G |\
+ {G}[G4e4] {FGAB}[^c4A4] {ef}[e4c4] {d'c'bagfedcB_AcBFGC}D4|
+
+
+X: 13
+T: Vocals
+M: C|
+K: F
+L: 1/4
+BA |: "Gm"G2AB|"C7"cd2e|"F"f2fe|"Dm"dA2d|
+w: Close your eyes and I'll kiss you, to-mor-row I'll miss you; re-
+"Bb"d2dc|"Gm"B2GF|"Eb"G4-|G2 z2|
+w:mem-ber I'll al-ways be true._
+
+
+
diff --git a/scotland.abc b/scotland.abc
@@ -0,0 +1,22 @@
+
+% Sample file for bagpipe mode (K:Hp)
+% adapted from PS file by Alan S. Watt
+
+
+X:1
+T:Scotland The Brave
+C:Trad.
+P:March
+E:7
+L:1/8
+M:4/4
+K:HP
+e|{g}A2 {GdGe}A>B {gcd}c{e}A {gcd}ce| {ag}a2{g}a2 {GdG}ae {gcd}c{e}A|\
+ {Gdc}d2 {g}f>d {gcd}ce {gcd}c{e}A|{GdG}B2{gef}e2{A}e>f {g}e/>d/{g}c/>B/|
+{g}A2 {GdGe}A>B {gcd}c{e}A {gcd}ce| {ag}a2{g}a2 {GdG}ae {gcd}c{e}A|\
+ {Gdc}d2 {g}f>d {gcd}ce {gcd}c{e}A|{GdG}B2{g}A>B {G}A2 {gcd}ce||
+|| {ag}a2 {g}a2 {GdG}ae {gcd}c{e}A| {ag}a2 {g}a2 {GdG}ae {gcd}ce|\
+ {ag}a2 {g}a>g {a}f2{ag}a>g|{a}fa {f}gf {gef}ed {gcd}cB|
+{g}A2 {GdGe}A>B {gcd}c{e}A {gcd}ce|{ag}a2 {g}a2 {GdG}ae {gcd}c{e}A|\
+ {Gdc}d2 {g}f>d {gcd}ce {gcd}c{e}A|{CdC}B2 {g}A>B {G}A3||
+
diff --git a/style.h b/style.h
@@ -0,0 +1,87 @@
+/*
+ * This file is part of abc2ps,
+ * Copyright (C) 1996,1997,1998 Michael Methfessel
+ * See file abc2ps.c for details.
+ */
+
+/* Global style parameters for the note spacing and Knuthian glue. */
+
+/* Parameters here are used to set spaces around notes.
+ Names ending in p: prefered natural spacings
+ Names ending in x: expanded spacings
+ Units: everything is based on a staff which is 24 points high
+ (ie. 6 pt between two staff lines). */
+
+/* name for this set of parameters */
+#define STYLE "std"
+
+/* ----- set_style_pars: set the parameters which control note spacing ---- */
+void set_style_pars (strictness)
+float strictness;
+{
+ float y;
+
+ f0p=0.10; f0x=0.15;
+ f5p=0.60; f5x=0.7;
+ f1p=1.0; f1x=1.0;
+
+ lnnp=40; lnnx=90;
+ bnnp=1.0; bnnx=1.0;
+ fnnp=1.0; fnnx=1.0;
+
+ lbnp=30; lbnx=50;
+ bbnp=0.2; bbnx=0.2;
+ rbnp=0.12; rbnx=0.10;
+
+ lnbp=30; lnbx=55;
+ bnbp=0.9; bnbx=0.9;
+ rnbp=0.10; rnbx=0.1;
+
+ /* set parameters f0p,f1p according to strictness */
+ /* the y*y makes the scale a bit more intuitive .. */
+ y=1-strictness;
+ f0p=y*y*0.40;
+ f0x=y*y*0.60;
+ if (verbose>3)
+ printf ("Set style parameters, strictness %.2f (f0p=%.3f, f0x=%.3f)\n",
+ strictness,f0p,f0x);
+
+}
+
+
+/* ----- Function of the spacing parameters ----- */
+
+/* Parameters for the length-to-width mapping:
+ f0p, f5p, f1p are the return values for notes of zero duration,
+ half notes, and whole notes. A parabolic interpolation is
+ used for other note durations. The purpose is to allow a non-linear
+ relation between the note duration and the spacing on the paper.
+
+ Parameters for the note-note spacing:
+ (the internote spacing between two notes that follow
+ each other without a bar in between.)
+
+ - lnn is an overall multiplier, i.e. the final note width in points
+ is the return value of function nwid times lnn.
+ - bnn determines how strongly the first note enters into the spacing.
+ For bnn=1, the spacing is calculated using the first note.
+ For bnn=0, the spacing is the average for the two notes.
+ - fnn multiplies the spacing under a beam, to compress the notes a bit
+
+ Parameters for the bar-note spacing:
+ (the spacing between a bar and note at the measure start.)
+
+ - lbn is the overall multiplier for the return values from nwid.
+ - rbn is the note duration which defines the default spacing.
+ - bbn determines how strongly the note duration enters into the spacing.
+ For bbn=1, the spacing is lbn times the return value of nwid.
+ For bbn=0, the spacing is lbn times the width of rbn times timesig.
+
+ Parameters for the note-bar spacing:
+ (the spacing between a note at the measure end and the bar.)
+
+ - lnb is the overall multiplier for the return values from nwid.
+ - rnb is the note duration which defines the default spacing.
+ - bnb determines how strongly the note duration enters into the spacing.
+ For bnb=1, the spacing is lnb times the return value of nwid.
+ For bnb=0, the spacing is lnb times the width of rbn times timesig. */
diff --git a/style.pure b/style.pure
@@ -0,0 +1,104 @@
+/*
+ * This file is part of abc2ps, Copyright (C) 1996 Michael Methfessel
+ * See file abc2ps.c for details.
+ */
+
+/* Global style parameters for the note spacing and Knuthian glue. */
+
+/* Parameters here are used to set spaces around notes.
+ Names ending in p: prefered natural spacings
+ Names ending in x: expanded spacings
+ Units: everything is based on a staff which is 24 points high
+ (ie. 6 pt between two staff lines). */
+
+/* name for this set of parameters */
+#define STYLE "pure"
+
+/* ----- Parameters for the length-to-width mapping ----- */
+/* f0p, f5p, f1p are the return values for notes of zero duration,
+ half notes, and whole notes. A simple parabolic interpolation is
+ used for other note durations. The aim is to permit a non-linear
+ relation between the note duration and the spacing on the paper. */
+
+float f0p=0.0;
+float f5p=0.5;
+float f1p=1.0;
+
+float f0x=0.0;
+float f5x=0.5;
+float f1x=1.0;
+
+
+/* ----- Parameters for the note-note spacing ----- */
+/* That is: the internote spacing between two notes that follow
+ each other without a bar in between.
+
+ -- lnn is an overall multiplier, i.e. the final note width in points
+ is the return value of function nwidth times lnn.
+ -- bnn determines how strongly the first note enters into the spacing.
+ For bnn=1, the spacing is calculated using the first note.
+ For bnn=0, the spacing is the average for the two notes.
+ -- fnn multiplies the spacing under a beam, to compress the notes a bit
+ -- gnn multiplies the spacing a second time within an n-tuplet */
+
+float lnnp=30;
+float bnnp=1.0;
+float fnnp=1.0;
+float gnnp=1.0;
+
+float lnnx=60;
+float bnnx=1.0;
+float fnnx=1.0;
+float gnnx=1.0;
+
+
+/* ---- Parameters for the bar-note spacing ----- */
+/* That is: the spacing between a bar and note at the measure start.
+
+ -- lbn is the overall multiplier for the return values from nwidth.
+ -- vbn is the note duration which defines the default spacing.
+ -- bbn determines how strongly the note duration enters into the spacing.
+ For bbn=1, the spacing is lbn times the return value of nwidth.
+ For bbn=0, the spacing is lbn times the width of rbn times timesig. */
+
+float lbnp=30;
+float bbnp=0.0;
+float rbnp=0.125;
+
+float lbnx=60;
+float bbnx=0.0;
+float rbnx=0.125;
+
+
+/* ---- Parameters for the note-bar spacing ----- */
+/* That is: the spacing between a note at the measure end and the bar.
+
+ -- lnb is the overall multiplier for the return values from nwidth.
+ -- vnb is the note duration which defines the default spacing.
+ -- bnb determines how strongly the note duration enters into the spacing.
+ For bnb=1, the spacing is lnb times the return value of nwidth.
+ For bnb=0, the spacing is lnb times the width of rbn times timesig. */
+
+float lnbp=30;
+float bnbp=1.0;
+float rnbp=0.125;
+
+float lnbx=60;
+float bnbx=1.0;
+float rnbx=0.125;
+
+
+/* ---- Parameters for centered single note in a measure ----- */
+/* That is: the total length = bar-note + note-bar spacings
+
+ -- ln0 is the overall multiplier for the return values from nwidth.
+ -- bn0 interpolates between two limiting cases
+ For bn0=0, this case is treated like bar-note and note-bar cases
+ For bn0=1, the note is centered in the measure. */
+
+float ln0p=30;
+float bn0p=0;
+
+float ln0x=60;
+float bn0x=0;
+
diff --git a/subs.h b/subs.h
@@ -0,0 +1,1372 @@
+/*
+ * This file is part of abc2ps,
+ * Copyright (C) 1996,1997,1998 Michael Methfessel
+ * See file abc2ps.c for details.
+ */
+
+/* miscellaneous subroutines */
+
+/* ----- write_help ----- */
+void write_help ()
+{
+
+ printf ("abc2ps v%s.%s (%s, %s) compiled %s\n",
+ VERSION, REVISION, VDATE, STYLE, __DATE__);
+
+ printf ("Usage: abc2ps files.. [-e nums-or-pats] [other flags]\n"
+ " - show index of abc files or typeset tunes in Postscript.\n"
+ "where: files input files in abc format\n"
+ " nums tune xref numbers, i.e. 1 3 6-7,20-\n"
+ " pats patterns for title search\n"
+ "Tunes are selected if they match a number or a pattern.\n"
+ "Flags: -o write output for selected tunes\n"
+ " -E produce EPSF output, one tune per file\n"
+ " -O aa set outfile name to aaa\n"
+ " -O = make outfile name from infile/title\n"
+ " -i run in interactive mode\n"
+ " -v nn set verbosity level to nn\n"
+ " -h show this command summary\n"
+ " Selection:\n"
+ " -e following arguments are selectors\n"
+ " -f following arguments are file names\n"
+ " -T search Title field (default)\n"
+ " -C search Composer field instead of title\n"
+ " -R search Rhythm field instead of title\n"
+ " -S search Source field instead of title\n"
+ " -V str select voices, eg. -V 1,4-5\n"
+ " Formatting:\n"
+ " -H show the format parameters\n"
+ " -p pretty output (looks better, needs more space)\n"
+ " -P select second predefined pretty output style\n"
+ " -s xx set scale factor for symbol size to xx\n"
+ " -w xx set staff width (cm/in/pt)\n"
+ " -m xx set left margin (cm/in/pt)\n"
+ " -d xx set staff separation (cm/in/pt)\n"
+ " -x include xref numbers in output\n"
+ " -k nn number every nn bars; 0 for first in staff\n"
+ " -n include notes and history in output\n"
+ " -N write page numbers\n"
+ " -I write index to Ind.ps\n"
+ " -1 write one tune per page\n"
+ " -l landscape mode\n"
+ " -g xx set glue mode to shrink|space|stretch|fill\n"
+ " -F foo read format from \"foo.fmt\"\n"
+ " -D bar look for format files in directory \"bar\"\n"
+ " -X x set strictness for note spacing, 0<x<1 \n"
+ " Transposing:\n"
+ " -t n transpose by n halftones (_n for negative number)\n"
+ " -t XX transpose root up/down to note XX (eg. C A# ^Bb _Bb)…
+ " Line breaks:\n"
+ " -a xx set max shrinkage to xx (between 0 and 1)\n"
+ " -b break at all line ends (ignore continuations)\n"
+ " -c continue all line ends (append '\\')\n"
+ " -B bb put line break every bb bars\n"
+ " Alloc options:\n"
+ " -maxs n set maximal number of symbols (default %d)\n"
+ " -maxv n set maximal number of voices (default %d)\n"
+ , maxSyms, maxVc);
+}
+
+
+/* ----- write_version ----- */
+void write_version ()
+{
+
+/* printf ("abc2ps v%s (%s, %s) compiled %s\n",
+ VERSION, VDATE, STYLE, __DATE__); */
+
+ printf ("abc2ps v%s.%s (%s, %s) compiled %s\n",
+ VERSION, REVISION, VDATE, STYLE, __DATE__);
+
+ if (strlen(DEFAULT_FDIR)>0)
+ printf ("Default format directory %s\n", DEFAULT_FDIR);
+
+}
+
+/* ----- is_xrefstr: check if string ok for xref selection ---- */
+int is_xrefstr (str)
+char str[];
+{
+
+ char *c;
+ c=str;
+ while (*c != '\0') {
+ if ((!isdig(*c)) && (*c!='-') && (*c!=',') && (*c!=' ')) return 0;
+ c++;
+ }
+ return 1;
+}
+
+
+/* ----- make_arglist: splits one string into list or arguments ---- */
+int make_arglist (str, av)
+char str[];
+char *av[];
+{
+ char *q;
+ int n;
+
+ q=str;
+ n=1; /* first real arg is 1, as in argv */
+ for (;;) {
+ while (*q==' ') q++;
+ if (*q=='\0') break;
+ av[n]=q;
+ n++;
+ while ((*q!=' ') && (*q!='\0')) q++;
+ if (*q=='\0') break;
+ *q='\0';
+ q++;
+ }
+ return n;
+}
+
+
+/* ----- init_ops ----- */
+void init_ops (job)
+int job;
+{
+
+ one_per_page = -1;
+ landscape = -1;
+ scalefac = -1.0;
+ lmargin = -1.0;
+ swidth = -1.0;
+ write_history = -1;
+ staffsep = -1;
+ dstaffsep = 0;
+ break_continues = -1;
+ continue_lines = -1;
+ include_xrefs = -1;
+ alfa_c = -1.0;
+ strict1 = -1.0;
+ strict2 = -1.0;
+ barnums = -1;
+ make_index = 0;
+
+ select_all = 0;
+ do_mode = DO_INDEX;
+ pagenumbers = 0;
+ strcpy (styf, "");
+ strcpy (transpose, "");
+ strcpy (vcselstr, "");
+
+ if (job) {
+ strcpy (styd, DEFAULT_FDIR);
+ strcpy (outf, OUTPUTFILE);
+ interactive = 0;
+ pretty = 0;
+ epsf = 0;
+ choose_outname = 0;
+ gmode = G_FILL;
+ vb = VERBOSE0;
+ search_field0 = S_TITLE;
+ }
+}
+
+
+/* ----- ops_into_fmt ----- */
+void ops_into_fmt (fmt)
+struct FORMAT *fmt;
+{
+ if (landscape >= 0) fmt->landscape=landscape;
+ if (scalefac >= 0) fmt->scale=scalefac;
+ if (lmargin >= 0) fmt->leftmargin=lmargin;
+ if (swidth >= 0) fmt->staffwidth=swidth;
+ if (continue_lines >= 0) fmt->continueall=continue_lines;
+ if (break_continues >= 0) fmt->breakall=break_continues;
+ if (write_history >= 0) fmt->writehistory=write_history;
+ if (bars_per_line > 0) fmt->barsperstaff=bars_per_line;
+ if (include_xrefs >= 0) fmt->withxrefs=include_xrefs;
+ if (one_per_page >= 0) fmt->oneperpage=one_per_page;
+ if (alfa_c >= 0) fmt->maxshrink=alfa_c;
+ if (staffsep >= 0) fmt->staffsep=staffsep;
+ if (strict1 >= 0) fmt->strict1=strict1;
+ if (strict2 >= 0) fmt->strict2=strict2;
+ if (barnums >= 0) fmt->barnums=barnums;
+ fmt->staffsep = fmt->staffsep + dstaffsep;
+ fmt->sysstaffsep = fmt->sysstaffsep + dstaffsep;
+
+}
+
+
+/* ----- parse_args: parse list of arguments, interpret flags ----- */
+int parse_args (ac, av)
+int ac;
+char *av[];
+{
+ int i,m,k,nsel,sel_arg,j,ok,f_pos,got_value;
+ char c,aaa[201],ext[41];
+
+ help_me=0;
+ ninf=0;
+ nsel=0;
+ sel_arg=0;
+ f_pos=-1;
+ strcpy (sel_str[0], "");
+ s_field[0]=search_field0;
+
+ i=1;
+ while (i<ac) {
+
+ if (av[i][0]=='+') { /* switch off flags with '+' */
+ m=1;
+ k=strlen(av[i]);
+ while (m<k) {
+ c=av[i][m];
+ if (c=='b') break_continues=0;
+ else if (c=='c') continue_lines=0;
+ else if (c=='x') include_xrefs=0;
+ else if (c=='1') one_per_page=0;
+ else if (c=='B') bars_per_line=0;
+ else if (c=='i') interactive=0;
+ else if (c=='n') write_history=0;
+ else if (c=='l') landscape=0;
+ else if (c=='p') pretty=0;
+ else if (c=='E') epsf=0;
+ else if (c=='F') strcpy (styf, "");
+ else if (c=='N') pagenumbers=0;
+ else if (c=='O') { choose_outname=0; strcpy (outf, OUTPUTFILE); }
+ else {
+ printf ("+++ Cannot switch off flag: +%c\n", c);
+ return 1;
+ }
+ m++;
+ }
+ }
+
+ else if (av[i][0]=='-') { /* interpret a flag with '-'*/
+
+ /* identify fullword options first */
+ if (!strcmp(av[i],"-maxv")) {
+ if ((i==ac-1)||(av[i+1][0]=='-')) rx("missing parameter for ",av[i]);
+ sscanf(av[++i],"%d",&maxVc);
+ }
+ else if (!strcmp(av[i],"-maxs")) {
+ if ((i==ac-1)||(av[i+1][0]=='-')) rx("missing parameter for ",av[i]);
+ sscanf(av[++i],"%d",&maxSyms);
+ }
+
+ else {
+ m=1;
+ k=strlen(av[i]);
+ while (m<k) {
+ c=av[i][m];
+ if (c=='h') help_me=1; /* simple flags */
+ else if (c=='H') help_me=2;
+ else if (c=='e') sel_arg=1;
+ else if (c=='f') {
+ nsel++;
+ strcpy (sel_str[nsel], "");
+ if (ninf==0) { /* selector before first file */
+ strcpy(sel_str[nsel],sel_str[nsel-1]);
+ s_field[nsel]=s_field[nsel-1];
+ }
+ s_field[nsel]=search_field0;
+ sel_arg=0;
+ f_pos=i;
+ }
+ else if (c=='b') {break_continues=1; continue_lines=0;}
+ else if (c=='c') {continue_lines=1; break_continues=0;}
+ else if (c=='x') include_xrefs=1;
+ else if (c=='1') one_per_page=1;
+ else if (c=='i') interactive=1;
+ else if (c=='n') write_history=1;
+ else if (c=='l') landscape=1;
+ else if (c=='p') pretty=1;
+ else if (c=='P') pretty=2;
+ else if (c=='E') epsf=1;
+ else if (c=='o') do_mode=DO_OUTPUT;
+ else if (c=='N') pagenumbers=1;
+ else if (c=='I') make_index=1;
+ else if (strchr("TCRS",c)) {
+ if (c=='T') s_field[nsel]=S_TITLE;
+ if (c=='C') s_field[nsel]=S_COMPOSER;
+ if (c=='R') s_field[nsel]=S_RHYTHM;
+ if (c=='S') s_field[nsel]=S_SOURCE;
+ sel_arg=1;
+ }
+
+ else if (strchr("vsdwmgtkDFYBVXaO",c)) { /* flags with parameter.. …
+ strcpy (aaa, &av[i][m+1]);
+ if ((strlen(aaa)>0) && strchr("glO",c)) { /* no sticky arg */
+ printf ("+++ Incorrect usage of flag -%c\n", c);
+ return 1;
+ }
+
+ got_value=1; /* check for value */
+ if (strlen(aaa)==0) {
+ got_value=0;
+ i++;
+ if ((i>=ac) || (av[i][0]=='-'))
+ i--;
+ else {
+ strcpy (aaa,av[i]);
+ got_value=1;
+ }
+ }
+
+ if (got_value && strchr("vskYB",c)) { /* check num args */
+ ok=1;
+ for (j=0;j<strlen(aaa);j++)
+ if (!strchr("0123456789.",aaa[j])) ok=0;
+ if (!ok) {
+ printf ("+++ Invalid parameter <%s> for flag -%c\n",aaa,c);
+ return 1;
+ }
+ }
+
+ /* --- next ops require a value --- */
+
+ if (!got_value) { /* check value was given */
+ printf ("+++ Missing parameter after flag -%c\n", c);
+ return 1;
+ }
+
+ if (c=='k') {
+ sscanf(aaa,"%d",&barnums);
+ break;
+ }
+
+ if (c=='V') { /* -V flag */
+ ok=1;
+ strcpy (vcselstr, aaa);
+ }
+
+ if (c=='X') { /* -X flag */
+ ok=1;
+ if (aaa[0]==',') {
+ sscanf(aaa,",%f",&strict2);
+ if (strict2<-0.001 || strict2>1.001) ok=0;
+ }
+ else if (strchr(aaa,',')) {
+ sscanf (aaa,"%f,%f",&strict1,&strict2);
+ if (strict1<-0.001 || strict1>1.001) ok=0;
+ if (strict2<-0.001 || strict2>1.001) ok=0;
+ }
+ else {
+ sscanf(aaa,"%f",&strict1);
+ if (strict1<-0.001 || strict1>1.001) ok=0;
+ strict2=strict1;
+ }
+ if (!ok) {
+ printf ("+++ Invalid parameter <%s> for flag -%c\n",aaa,c);
+ return 1;
+ }
+ }
+
+ if (c=='O') { /* -O flag */
+ if (!strcmp(aaa,"=")) {
+ choose_outname=1;
+ }
+ else {
+ getext (aaa,ext);
+ if (strcmp(ext,"ps") && strcmp(ext,"eps") && strcmp(ext,"")) {
+ printf ("Wrong extension for output file: %s\n", aaa);
+ return 1;
+ }
+ strext (outf, aaa, "ps", 1);
+ choose_outname=0;
+ }
+ }
+
+ if (c=='a') {
+ sscanf (aaa, "%f", &alfa_c);
+ if ((alfa_c>1.05)||(alfa_c<-0.01)) {
+ printf ("+++ Bad parameter for flag -a: %s\n",aaa);
+ return 1;
+ }
+ }
+
+ if (c=='B') {
+ sscanf(aaa,"%d",&bars_per_line);
+ continue_lines=0;
+ }
+ if (c=='t') strcpy(transpose,aaa);
+ if (c=='v') sscanf(aaa,"%d",&vb);
+ if (c=='s') sscanf(aaa,"%f",&scalefac);
+ if (c=='d') {
+ if (aaa[0]=='+' || aaa[0]=='-') dstaffsep = scan_u(aaa);
+ else staffsep = scan_u(aaa);
+ }
+ if (c=='w') swidth = scan_u(aaa);
+ if (c=='m') lmargin = scan_u(aaa);
+ if (c=='F') strcpy(styf,aaa);
+ if (c=='D') strcpy (styd,aaa);
+ if (c=='g') {
+ if (abbrev(aaa,"shrink", 2)) gmode=G_SHRINK;
+ else if (abbrev(aaa,"stretch",2)) gmode=G_STRETCH;
+ else if (abbrev(aaa,"space", 2)) gmode=G_SPACE;
+ else if (abbrev(aaa,"fill", 2)) gmode=G_FILL;
+ else {
+ printf ("+++ Bad parameter for flag -g: %s\n",aaa);
+ return 1;
+ }
+ }
+ break;
+ }
+ else {
+ printf ("+++ Unknown flag: -%c\n", c);
+ return 1;
+ }
+ m++;
+ }
+ }
+ }
+
+ else {
+ if (strstr(av[i],".fmt")) { /* implict -F */
+ strcpy(styf, av[i]);
+ }
+ else {
+ if (strstr(av[i],".abc") && sel_arg) { /* file if .abc */
+ nsel++;
+ strcpy (sel_str[nsel], "");
+ s_field[nsel]=S_TITLE;
+ if (ninf==0) { /* selector before first file */
+ strcpy(sel_str[nsel],sel_str[nsel-1]);
+ s_field[nsel]=s_field[nsel-1];
+ }
+ sel_arg=0;
+ }
+ if (is_xrefstr(av[i]) && (!sel_arg)) { /* sel if xref numbers */
+ if (i-1 != f_pos) sel_arg=1;
+ }
+
+ if (!sel_arg) { /* this arg is a file name */
+ if (ninf>=MAXINF) {
+ printf ("+++ Too many input files, max is %d\n", MAXINF);
+ return 1;
+ }
+ strcpy (in_file[ninf], av[i]);
+ psel[ninf]=nsel;
+ ninf++;
+ }
+ else { /* this arg is a selector */
+ strcat(sel_str[nsel], av[i]);
+ strcat(sel_str[nsel], " ");
+ }
+ }
+ }
+ i++;
+ }
+
+ return 0;
+}
+
+/* ----- alloc_structs ----- */
+/* Thanks to Henrik Norbeck for this */
+void alloc_structs ()
+{
+ int j;
+
+ sym = (struct SYMBOL *)calloc(maxSyms, sizeof(struct SYMBOL));
+ if (sym==NULL) rx("Out of memory","");
+
+ symv = (struct SYMBOL **)calloc(maxVc, sizeof(struct SYMBOL *));
+ if (symv==NULL) rx("Out of memory","");
+
+ for (j=0;j<maxVc;j++) {
+ symv[j] = (struct SYMBOL *)calloc(maxSyms, sizeof(struct SYMBOL));
+ if (symv[j]==NULL) rx("Out of memory","");
+ }
+
+ xp = (struct XPOS *)calloc(maxSyms+1, sizeof(struct XPOS));
+ if (xp==NULL) rx("Out of memory","");
+
+ for (j=0;j<maxSyms+1;j++) {
+ xp[j].p = (int *)calloc(maxVc, sizeof(int));
+ if (xp[j].p==NULL) rx("Out of memory","");
+ }
+
+ voice=(struct VCESPEC *)calloc(maxVc, sizeof(struct VCESPEC));
+ if (voice==NULL) rx("Out of memory","");
+
+ sym_st = (struct SYMBOL **)calloc(maxVc, sizeof(struct SYMBOL *));
+ if (sym_st==NULL) rx("Out of memory","");
+
+ for (j=0;j<maxVc;j++) {
+ sym_st[j] = (struct SYMBOL *)calloc(MAXSYMST, sizeof(struct SYMBOL));
+ if (sym_st[j]==NULL) rx("Out of memory","");
+ }
+
+ nsym_st = (int *)calloc(maxVc, sizeof(int));
+ if (nsym_st==NULL) rx("Out of memory","");
+
+}
+
+
+/* ----- set_page_format ----- */
+int set_page_format ()
+{
+ int i,j;
+
+ if (pretty==1)
+ set_pretty_format (&cfmt);
+ else if (pretty==2)
+ set_pretty2_format (&cfmt);
+ else
+ set_standard_format (&cfmt);
+
+ i=read_fmt_file ("fonts.fmt", styd, &cfmt);
+ j=0;
+ if (strlen(styf)>0) {
+ strext(styf,styf,"fmt",1);
+ j=read_fmt_file (styf, styd, &cfmt);
+ if (j==0) {
+ printf ("\n+++ Cannot open file: %s\n", styf);
+ return 0;
+ }
+ strcpy(cfmt.name, styf);
+ }
+ if (i || j) printf("\n");
+ ops_into_fmt (&cfmt);
+
+ make_font_list (&cfmt);
+ sfmt=cfmt;
+ dfmt=cfmt;
+ return 1;
+}
+
+
+/* ----- tex_str: change string to take care of some tex-style codes --- */
+/* Puts \ in front of ( and ) in case brackets are not balanced,
+ interprets some TeX-type strings using ISOLatin1 encodings.
+ Returns the length of the string as finally given out on paper.
+ Also returns an estimate of the string width... */
+int tex_str (str,s,wid)
+char *str;
+char s[];
+float *wid;
+{
+ char *c;
+ int base,add,n;
+ char t[21];
+ float w;
+
+ c=str;
+ strcpy(s,"");
+ n=0;
+ w=0;
+ while (*c != '\0') {
+
+ if ((*c=='(') || (*c==')')) /* ( ) becomes \( \) */
+ {sprintf(t, "\\%c", *c); strcat(s,t); w+=cwid('('); n++; }
+
+ else if (*c=='\\') { /* backslash sequences */
+ c++;
+ if (*c=='\0') break;
+ add=0; /* accented vowels */
+ if (*c=='`') add=1;
+ if (*c=='\'') add=2;
+ if (*c=='^') add=3;
+ if (*c=='"') add=4;
+ if (add) {
+ c++;
+ base=0;
+ if (*c=='a') { base=340; if (add==4) add=5; }
+ if (*c=='e') base=350;
+ if (*c=='i') base=354;
+ if (*c=='o') { base=362; if (add==4) add=5; }
+ if (*c=='u') base=371;
+ if (*c=='A') { base=300; if (add==4) add=5; }
+ if (*c=='E') base=310;
+ if (*c=='I') base=314;
+ if (*c=='O') { base=322; if (add==4) add=5; }
+ if (*c=='U') base=331;
+ w+=cwid(*c);
+ if (base)
+ {sprintf(t,"\\%d",base+add-1); strcat(s,t); n+=1; }
+ else
+ {sprintf(t,"%c",*c); strcat(s,t); n+=1; }
+ }
+
+ else if (*c==' ') /* \-space */
+ { strcat(s," "); w+=cwid(' '); n++; }
+
+ else if (*c=='O') /* O-slash */
+ { strcat(s,"\\330"); w+=cwid('O'); n++; }
+
+ else if (*c=='o') /* o-slash */
+ { strcat(s,"\\370"); w+=cwid('O'); n++; }
+
+ else if((*c=='s')&&(*(c+1)=='s')) /* sz */
+ { c++; strcat(s,"\\337"); w+=cwid('s'); n++; }
+ else if((*c=='a')&&(*(c+1)=='a')) /* a-ring */
+ { c++; strcat(s,"\\345"); w+=cwid('a'); n++; }
+ else if((*c=='A')&&(*(c+1)=='A')) /* A-ring */
+ { c++; strcat(s,"\\305"); w+=cwid('A'); n++; }
+ else if((*c=='a')&&(*(c+1)=='e')) /* ae */
+ { c++; strcat(s,"\\346"); w+=1.5*cwid('a'); n++; }
+ else if((*c=='A')&&(*(c+1)=='E')) /* AE */
+ { c++; strcat(s,"\\306"); w+=1.5*cwid('A'); n++; }
+
+
+ else if (*c=='c') { /* c-cedilla */
+ c++;
+ w+=cwid(*c);
+ if (*c=='C') { strcat(s,"\\307"); n++; }
+ else if (*c=='c') { strcat(s,"\\347"); n++; }
+ else {sprintf(t,"%c",*c); strcat(s,t); n++; }
+ }
+
+ else if (*c=='~') { /* n-twiddle */
+ c++;
+ w+=cwid(*c);
+ if (*c=='N') { strcat(s,"\\321"); n++; }
+ else if (*c=='n') { strcat(s,"\\361"); n++; }
+ else { sprintf(t,"%c",*c); strcat(s,t); n++; }
+ }
+
+ else /* \-something-else; pass through */
+ {sprintf(t,"\\%c",*c); strcat(s,t); w+=cwid('A'); n++; }
+ }
+
+ else if (*c=='{')
+ ;
+ else if (*c=='}')
+ ;
+
+ else /* other characters: pass though */
+ {
+ sprintf(t,"%c",*c);
+ strcat(s,t); n++;
+ w+=cwid(*c);
+ }
+
+ c++;
+ }
+ *wid = w;
+
+ return n;
+}
+
+
+/* ----- put_str: output a string in postscript ----- */
+void put_str (str)
+char *str;
+{
+ char s[801];
+ float w;
+
+ tex_str (str,s,&w);
+ PUT1 ("%s", s);
+}
+
+/* ----- set_font ----- */
+void set_font (fp,font,add_bracket)
+FILE *fp;
+struct FONTSPEC font;
+int add_bracket;
+{
+ int i,fnum;
+
+ fnum=-1;
+ for (i=0;i<nfontnames;i++) {
+ if (!strcmp(font.name,fontnames[i])) fnum=i;
+ }
+ if (fnum<0) {
+ printf ("\n+++ Font \"%s\" not predefined; using first in list\n",
+ font.name);
+ fnum=0;
+ }
+ PUT3("%.1f %d F%d ", font.size, font.box, fnum)
+ if (add_bracket) PUT0("(")
+}
+
+/* ----- set_font_str ----- */
+void set_font_str (str,font)
+char str[];
+struct FONTSPEC font;
+{
+ int i,fnum;
+
+ fnum=-1;
+ for (i=0;i<nfontnames;i++) {
+ if (!strcmp(font.name,fontnames[i])) fnum=i;
+ }
+ sprintf (str,"%.1f %d F%d ", font.size, font.box, fnum);
+}
+
+
+/* ----- check_margin: do horizontal shift if needed ---- */
+void check_margin (new_posx)
+float new_posx;
+{
+ float dif;
+
+ dif=new_posx-posx;
+ if (dif*dif<0.001) return;
+
+ PUT1("%.2f 0 T\n", dif)
+ posx=new_posx;
+}
+
+
+/* ----- epsf_title ------ */
+void epsf_title (title,fnm)
+char title[],fnm[];
+{
+ char *p,*q;
+
+ p=title; q=fnm;
+ while (*p != '\0') {
+ if (*p == ' ')
+ *q = '_';
+ else
+ *q = *p;
+ p++; q++;
+ }
+ *q = '\0';
+}
+
+/* ----- close_output_file ------ */
+void close_output_file ()
+{
+ int m;
+
+ if (!file_open) return;
+
+ if (interactive) printf ("(close %s)\n", outfnam);
+
+ close_page(fout);
+ close_ps (fout);
+ fclose (fout);
+ if (tunenum==0)
+ printf ("+++ Warning: no tunes written to output file\n");
+ m=get_file_size (outfnam);
+ printf ("Output written on %s (%d page%s, %d title%s, %d byte%s)\n",
+ outfnam,
+ pagenum, pagenum==1 ? "" : "s",
+ tunenum, tunenum==1 ? "" : "s",
+ m, m==1 ? "" : "s");
+ file_open=0;
+ file_initialized=0;
+
+}
+
+
+/* ----- open_output_file ------ */
+void open_output_file (fnam,tstr)
+char fnam[],tstr[];
+{
+
+ if (!strcmp(fnam,outfnam)) return;
+
+ if (file_open) close_output_file ();
+
+ if (interactive) printf ("(open %s)\n", fnam);
+ strcpy (outfnam, fnam);
+ if ((fout = fopen (outfnam,"w")) == NULL)
+ rx ("Cannot open output file ", outf);
+ pagenum=0;
+ tunenum=tnum1=tnum2=0;
+ file_open=1;
+ file_initialized=0;
+
+}
+
+
+
+/* ----- open_index_file ------- */
+void open_index_file (fnam)
+char fnam[];
+{
+ if (vb>=8) printf("Open index file \"%s\"\n", fnam);
+ if ((findex = fopen (fnam,"w")) == NULL)
+ rx ("Cannot open index file: ", fnam);
+
+ index_initialized=0;
+
+}
+
+/* ----- close_index_file ------- */
+void close_index_file ()
+{
+
+ if (vb>=8) printf("Close index file\n");
+
+ close_index_page (findex);
+
+ fclose (findex);
+
+}
+
+/* ----- add_to_text_block ----- */
+void add_to_text_block (ln,add_final_nl)
+char ln[];
+int add_final_nl;
+{
+ char *c,*a;
+ char word[81];
+ int nt,nl;
+
+ nt=ntxt;
+ c=ln;
+
+ for (;;) {
+ while (*c==' ') c++;
+ if (*c=='\0') break;
+ a=word;
+ while ((*c!=' ')&&(*c!='\0')&&(*c!='\n')) {
+ nl=0;
+ if ((*c=='\\')&&(*(c+1)=='\\')) {
+ nl=1;
+ c+=2;
+ break;
+ }
+ *a=*c;
+ c++;
+ a++;
+
+ }
+ *a='\0';
+ if (strlen(word)>MAXWLEN) {
+ word[MAXWLEN-1]='\0';
+ printf ("+++ Insanely long word truncated to %d chars: %s\n",
+ MAXWLEN-1,word);
+ }
+ if (nt>=MAXNTEXT) {
+ printf ("\n+++ Line %d: %s\n", linenum,ln);
+ rx("Text overflow; increase MAXNTEXT and recompile.","");
+ }
+ if (strlen(word)>0) {
+ strcpy(txt[nt],word);
+ nt++;
+ }
+ if (nl) {
+ strcpy(txt[nt],"$$NL$$");
+ nt++;
+ }
+ }
+ if (add_final_nl) {
+ strcpy(txt[nt],"$$NL$$");
+ nt++;
+ }
+
+ ntxt=nt;
+
+}
+
+
+/* ----- write_text_block ----- */
+void write_text_block (fp,job)
+FILE *fp;
+int job;
+{
+ int i,i1,i2,ntline,nc,mc,nbreak;
+ float textwidth,ftline,ftline0,swfac,baseskip,parskip;
+ float wwidth,wtot,spw;
+ char str[81];
+
+ if (ntxt<=0) return;
+
+ baseskip = cfmt.textfont.size * cfmt.lineskipfac;
+ parskip = cfmt.textfont.size * cfmt.parskipfac;
+ set_font_str (page_init,cfmt.textfont);
+
+ /* estimate text widths.. ok for T-R, wild guess for other fonts */
+ swfac=1.0;
+ if (strstr(cfmt.textfont.name,"Times-Roman")) swfac=1.00;
+ if (strstr(cfmt.textfont.name,"Times-Bold")) swfac=1.05;
+ if (strstr(cfmt.textfont.name,"Helvetica")) swfac=1.10;
+ if (strstr(cfmt.textfont.name,"Helvetica-Bold")) swfac=1.15;
+ if (strstr(cfmt.textfont.name,"Palatino")) swfac=1.10;
+ swfac=1.0;
+ spw=cwid(' ');
+ PUT1("/LF {0 %.1f rmoveto} bind def\n",-baseskip)
+
+ /* output by pieces, separate at newline token */
+ i1=0;
+ while (i1<ntxt) {
+ i2=-1;
+ for (i=i1;i<ntxt;i++) if(!strcmp(txt[i],"$$NL$$")) {i2=i; break; }
+ if (i2==-1) i2=ntxt;
+ bskip(baseskip);
+
+ if (job==OBEYLINES) {
+ PUT0("0 0 M (")
+ for (i=i1;i<i2;i++) {
+ tex_str(txt[i],str,&wwidth);
+ PUT1("%s ",str);
+ }
+ PUT0(") rshow\n")
+ }
+
+ else if (job==OBEYCENTER) {
+ PUT1("%.1f 0 M (",cfmt.staffwidth/2)
+ for (i=i1;i<i2;i++) {
+ tex_str(txt[i],str,&wwidth);
+ PUT1("%s",str)
+ if (i<i2-1) PUT0(" ")
+ }
+ PUT0(") cshow\n")
+ }
+
+ else {
+ PUT0("0 0 M mark\n")
+ nc=0;
+ mc=-1;
+ wtot=-spw;
+ for (i=i2-1;i>=i1;i--) {
+ mc+=tex_str(txt[i],str,&wwidth)+1;
+ wtot+=wwidth+spw;
+ nc+=strlen(str)+2;
+ if (nc>=72) {nc=0; PUT0("\n") }
+ PUT1 ("(%s)",str);
+ }
+ if (job==RAGGED)
+ PUT1(" %.1f P1\n",cfmt.staffwidth)
+ else
+ PUT1(" %.1f P2\n",cfmt.staffwidth)
+ /* first estimate: (total textwidth)/(available width) */
+ textwidth=wtot*swfac*cfmt.textfont.size;
+ if (strstr(cfmt.textfont.name,"Courier"))
+ textwidth=0.60*mc*cfmt.textfont.size;
+ ftline0=textwidth/cfmt.staffwidth;
+ /* revised estimate: assume some chars lost at each line end */
+ nbreak=ftline0;
+ textwidth=textwidth+5*nbreak*cwid('a')*swfac*cfmt.textfont.size;
+ ftline=textwidth/cfmt.staffwidth;
+ ntline=ftline+1.0;
+ if (vb>=10)
+ printf("first estimate %.2f, revised %.2f\n", ftline0,ftline);
+ if (vb>=10)
+ printf("Output %d word%s, about %.2f lines (fac %.2f)\n",
+ i2-i1, i2-i1==1?"":"s", ftline,swfac);
+ bskip((ntline-1)*baseskip);
+ }
+
+ buffer_eob (fp);
+ /* next line to allow pagebreak after each text "line" */
+ /* if (!epsf && !within_tune) write_buffer(fp); */
+ i1=i2+1;
+ }
+ bskip(parskip);
+ buffer_eob (fp);
+ /* next line to allow pagebreak after each paragraph */
+ if (!epsf && !within_tune) write_buffer(fp);
+ strcpy (page_init,"");
+ return;
+}
+
+
+
+/* ----- put_words ------- */
+void put_words (fp)
+FILE *fp;
+{
+ int i,nw,n;
+ char str[81];
+ char *p,*q;
+
+ set_font (fp,cfmt.wordsfont, 0);
+ set_font_str (page_init,cfmt.wordsfont);
+
+ n=0;
+ for (i=0;i<ntext;i++) if (text_type[i]==TEXT_W) n++;
+ if (n==0) return;
+
+ bskip(cfmt.wordsspace);
+ for (i=0;i<ntext;i++) {
+ if (text_type[i]==TEXT_W) {
+ bskip(cfmt.lineskipfac*cfmt.wordsfont.size);
+ p=&text[i][0];
+ q=&str[0];
+ if (isdig(text[i][0])) {
+ while (*p != '\0') {
+ *q=*p;
+ q++;
+ p++;
+ if (*p==' ') break;
+ if (*(p-1)==':') break;
+ if (*(p-1)=='.') break;
+ }
+ if (*p==' ') p++;
+ }
+ *q='\0';
+
+ /* permit page break at empty lines or stanza start */
+ nw=nwords(text[i]);
+ if ((nw==0) || (strlen(str)>0)) buffer_eob(fp);
+
+ if (nw>0) {
+ if (strlen(str)>0) {
+ PUT0("45 0 M (")
+ put_str (str);
+ PUT0(") lshow\n")
+ }
+ if (strlen(p)>0) {
+ PUT0("50 0 M (")
+ put_str (p);
+ PUT0(") rshow\n")
+ }
+ }
+ }
+ }
+
+ buffer_eob (fp);
+ strcpy (page_init,"");
+
+}
+
+/* ----- put_text ------- */
+void put_text (fp, type, str)
+FILE *fp;
+int type;
+char str[];
+{
+ int i,n;
+ float baseskip,parskip;
+
+ n=0;
+ for (i=0;i<ntext;i++) if (text_type[i]==type) n++;
+ if (n==0) return;
+
+ baseskip = cfmt.textfont.size * cfmt.lineskipfac;
+ parskip = cfmt.textfont.size * cfmt.parskipfac;
+ PUT0("0 0 M\n")
+ ntxt=0;
+ add_to_text_block(str,0);
+ for (i=0;i<ntext;i++) {
+ if (text_type[i]==type) add_to_text_block(text[i],1);
+ }
+ write_text_block (fp,RAGGED);
+ buffer_eob (fp);
+
+}
+
+/* ----- put_history ------- */
+void put_history (fp)
+FILE *fp;
+{
+ int i,ok;
+ float baseskip,parskip;
+
+ set_font (fp, cfmt.textfont,0);
+ set_font_str (page_init,cfmt.textfont);
+ baseskip = cfmt.textfont.size * cfmt.lineskipfac;
+ parskip = cfmt.textfont.size * cfmt.parskipfac;
+
+ bskip(cfmt.textspace);
+
+ if (strlen(info.rhyth)>0) {
+ bskip(baseskip);
+ PUT0("0 0 M (Rhythm: ")
+ put_str (info.rhyth);
+ PUT0(") show\n")
+ bskip(parskip);
+ }
+
+ if (strlen(info.book)>0) {
+ bskip(0.5*CM);
+ PUT0("0 0 M (Book: ")
+ put_str (info.book);
+ PUT0(") show\n")
+ bskip(parskip);
+ }
+
+ if (strlen(info.src)>0) {
+ bskip(0.5*CM);
+ PUT0("0 0 M (Source: ")
+ put_str (info.src);
+ PUT0(") show\n")
+ bskip(parskip);
+ }
+
+ put_text (fp, TEXT_D, "Discography: ");
+ put_text (fp, TEXT_N, "Notes: ");
+ put_text (fp, TEXT_Z, "Transcription: ");
+
+ ok=0;
+ for (i=0;i<ntext;i++) {
+ if (text_type[i]==TEXT_H) {
+ bskip(0.5*CM);
+ PUT0("0 0 M (")
+ put_str (text[i]);
+ PUT0(") show\n")
+ ok=1;
+ }
+ }
+ if (ok) bskip(parskip);
+ buffer_eob (fp);
+ strcpy (page_init,"");
+
+}
+
+
+/* ----- write_inside_title ----- */
+void write_inside_title (fp)
+FILE *fp;
+{
+ char t[201];
+
+ if (numtitle==1) strcpy (t,info.title);
+ else if (numtitle==2) strcpy (t,info.title2);
+ else if (numtitle==3) strcpy (t,info.title3);
+ if (vb>15) printf ("write inside title <%s>\n", t);
+ if (strlen(t)==0) return;
+
+ bskip (cfmt.subtitlefont.size+0.2*CM);
+ set_font (fp, cfmt.subtitlefont, 0);
+
+ if (cfmt.titlecaps) cap_str(t);
+ PUT0(" (")
+ put_str (t);
+ if (cfmt.titleleft) PUT0(") 0 0 M rshow\n")
+ else PUT1(") %.1f 0 M cshow\n", cfmt.staffwidth/2)
+ bskip (cfmt.musicspace+0.2*CM);
+
+}
+
+
+/* ----- write_tunetop ----- */
+void write_tunetop(fp)
+FILE *fp;
+{
+
+ PUT2("\n\n%% --- tune %d %s\n", tunenum+1, info.title)
+ if (!epsf) bskip (cfmt.topspace);
+}
+
+
+/* ----- write_tempo ----- */
+void write_tempo(fp,tempo,meter)
+FILE *fp;
+char tempo[];
+struct METERSTR meter;
+{
+ char *r, *q;
+ char text[STRL];
+ int top,bot,value,len,i,err,fac,dig,div,rc;
+ struct SYMBOL s;
+ float stem,dotx,doty,sc,dx;
+
+ if (vb>15) printf ("write tempo <%s>\n", info.tempo);
+ r=tempo;
+ p0=tempo;
+ set_font (fp,cfmt.tempofont,0);
+ PUT0(" 18 0 M\n")
+
+ for (;;) {
+
+ while (*r==' ') r++; /* skip blanks */
+ if (*r=='\0') break;
+
+ if (*r=='"') { /* write string */
+ r++;
+ q=text;
+ while (*r!='"' && *r!='\0') { *q=*r; r++; q++; }
+ if (*r=='"') r++;
+ *q='\0';
+ if (strlen(text)>0) {
+ PUT0("6 0 rmoveto (")
+ put_str (text);
+ PUT0(") rshow 12 0 \n")
+ }
+ }
+
+ else { /* write tempo denotation */
+ q=text;
+ while (*r!=' ' && *r!='\0') { *q=*r; r++; q++; }
+ *q='\0';
+ q=text;
+
+ len=QUARTER;
+ value=0;
+ err=0;
+ if (strchr(q,'=')) {
+ if ((*q=='C') || (*q=='c')) {
+ q++;
+
+ len=meter.dlen;
+ div=0;
+ if (*q=='/') { div=1; q++; }
+ fac=0;
+ while (isdig(*q)) { dig=*q-'0'; fac=10*fac+dig; q++; }
+
+ if (div) {
+ if (fac==0) fac=2;
+ if (len%fac) printf ("Bad length divisor in tempo: %s", text);
+ len=len/fac;
+ }
+ else
+ if (fac>0) len=len*fac;
+ if (*q!='=') err=1;
+ q++;
+ if (!isdig(*q)) err=1;
+ sscanf(q,"%d", &value);
+ }
+ else if (isdig(*q)) {
+ sscanf(q,"%d/%d=%d", &top,&bot,&value);
+ len=(BASE*top)/bot;
+ }
+ else err=1;
+ }
+ else {
+ if (isdig(*q))
+ sscanf(q,"%d", &value);
+ else err=1;
+ }
+
+ s.len=len;
+ rc = idfy_note (&s);
+ if (rc) err=1;
+ if (err) /* draw note=value */
+ printf("\n+++ invalid tempo specifier: %s\n", text);
+ else {
+ sc=0.55*cfmt.tempofont.size/10.0;
+ PUT2("gsave %.2f %.2f scale 15 3 rmoveto currentpoint\n", sc,sc)
+ if (s.head==H_OVAL) PUT0("HD")
+ if (s.head==H_EMPTY) PUT0("Hd")
+ if (s.head==H_FULL) PUT0("hd")
+ dx=4.0;
+ if (s.dots) {
+ dotx=8; doty=0;
+ if (s.flags>0) dotx=dotx+4;
+ if (s.head==H_EMPTY) dotx=dotx+1;
+ if (s.head==H_OVAL) dotx=dotx+2;
+ for (i=0;i<s.dots;i++) {
+ PUT2(" %.1f %.1f dt", dotx, doty)
+ dx=dotx;
+ dotx=dotx+3.5;
+ }
+ }
+ stem=16.0;
+ if (s.flags>1) stem=stem+3*(s.flags-1);
+ if (s.len<WHOLE) PUT1(" %.1f su",stem)
+ if (s.flags>0) PUT2(" %.1f f%du",stem,s.flags)
+ if ((s.flags>0) && (dx<6.0)) dx=6.0;
+ dx=(dx+18)*sc;
+ PUT2(" grestore %.2f 0 rmoveto ( = %d) rshow\n", dx,value)
+ }
+ }
+ }
+}
+
+
+/* ----- write_inside_tempo ----- */
+void write_inside_tempo (fp)
+FILE *fp;
+{
+
+ bskip (cfmt.partsfont.size);
+ write_tempo(fp,info.tempo,default_meter);
+ bskip (0.1*CM);
+}
+
+/* ----- write_heading ----- */
+void write_heading (fp)
+FILE *fp;
+{
+ float lwidth,down1,down2;
+ int i,ncl;
+ char t[201];
+
+ lwidth=cfmt.staffwidth;
+
+ /* write the main title */
+ bskip (cfmt.titlefont.size+cfmt.titlespace);
+ set_font (fp,cfmt.titlefont,1);
+ if (cfmt.withxrefs) PUT1("%d. ", xrefnum)
+ strcpy (t,info.title);
+ if (cfmt.titlecaps) cap_str(t);
+ put_str (t);
+ if (cfmt.titleleft) PUT0(") 0 0 M rshow\n")
+ else PUT1(") %.1f 0 M cshow\n", lwidth/2)
+
+ /* write second title */
+ if (numtitle>=2) {
+ bskip (cfmt.subtitlespace+cfmt.subtitlefont.size);
+ set_font (fp,cfmt.subtitlefont,1);
+ strcpy (t,info.title2);
+ if (cfmt.titlecaps) cap_str(t);
+ put_str (t);
+ if (cfmt.titleleft) PUT0(") 0 0 M rshow\n")
+ else PUT1(") %.1f 0 M cshow\n", lwidth/2)
+ }
+
+ /* write third title */
+ if (numtitle>=3) {
+ bskip (cfmt.subtitlespace+cfmt.subtitlefont.size);
+ set_font (fp,cfmt.subtitlefont,1);
+ strcpy (t,info.title3);
+ if (cfmt.titlecaps) cap_str(t);
+ put_str (t);
+ if (cfmt.titleleft) PUT0(") 0 0 M rshow\n")
+ else PUT1(") %.1f 0 M cshow\n", lwidth/2)
+ }
+
+ /* write composer, origin */
+ if ((info.ncomp>0) || (strlen(info.orig)>0)) {
+ set_font (fp,cfmt.composerfont,0);
+ bskip(cfmt.composerspace);
+ ncl=info.ncomp;
+ if ((strlen(info.orig)>0) && (ncl<1)) ncl=1;
+ for (i=0;i<ncl;i++) {
+ bskip(cfmt.composerfont.size);
+ PUT1("%.1f 0 M (", lwidth)
+ put_str (info.comp[i]);
+ if ((i==ncl-1)&&(strlen(info.orig)>0)) {
+ put_str (" (");
+ put_str (info.orig);
+ put_str (")");
+ }
+ PUT0 (") lshow\n");
+ }
+ down1=cfmt.composerspace+cfmt.musicspace+ncl*cfmt.composerfont.size;
+ }
+ else {
+ bskip(cfmt.composerfont.size+cfmt.composerspace);
+ down1=cfmt.composerspace+cfmt.musicspace+cfmt.composerfont.size;
+ }
+ bskip (cfmt.musicspace);
+
+ /* decide whether we need extra shift for parts and tempo */
+ down2=cfmt.composerspace+cfmt.musicspace;
+ if (strlen(info.parts)>0) down2=down2+cfmt.partsspace+cfmt.partsfont.size;
+ if (strlen(info.tempo)>0) down2=down2+cfmt.partsspace+cfmt.partsfont.size;
+ if (down2>down1) bskip (down2-down1);
+
+ /* write tempo and parts */
+ if (strlen(info.parts)>0 || strlen(info.tempo)>0) {
+
+ if (strlen(info.tempo)>0) {
+ bskip (-0.2*CM);
+ PUT1 (" %.2f 0 T ", cfmt.indent*cfmt.scale)
+ write_tempo(fp, info.tempo, default_meter);
+ PUT1 (" %.2f 0 T ", -cfmt.indent*cfmt.scale)
+ bskip (-cfmt.tempofont.size);
+ }
+
+ if (strlen(info.parts)>0) {
+ bskip (-cfmt.partsspace);
+ set_font (fp,cfmt.partsfont,0);
+ PUT0("0 0 M (")
+ put_str (info.parts);
+ PUT0(") rshow\n")
+ bskip (cfmt.partsspace);
+ }
+
+ if (strlen(info.tempo)>0) bskip (cfmt.tempofont.size+0.3*CM);
+
+ }
+
+
+}
+
+/* ----- write_parts ----- */
+void write_parts (fp)
+FILE *fp;
+{
+ if (strlen(info.parts)>0) {
+ bskip (cfmt.partsfont.size);
+ set_font (fp, cfmt.partsfont,0);
+ PUT0("0 0 M (")
+ put_str (info.parts);
+ PUT0(") rshow\n")
+ bskip(cfmt.partsspace);
+ }
+}
+
+
diff --git a/syms.h b/syms.h
@@ -0,0 +1,1226 @@
+/*
+ * This file is part of abc2ps,
+ * Copyright (C) 1996,1997,1998 Michael Methfessel
+ * See file abc2ps.c for details.
+ */
+
+/* subroutines to define postscript macros which draw symbols */
+
+/* ----- def_misc ------- */
+void def_misc (fp)
+FILE *fp;
+{
+ fprintf (fp,
+ "\n/cshow { %% usage: string cshow - center at current pt\n"
+ " dup stringwidth pop 2 div neg 0 rmoveto\n"
+ " bx {box} if show\n"
+ "} bind def\n"
+ "\n/lshow { %% usage: string lshow - show left-aligned\n"
+ " dup stringwidth pop neg 0 rmoveto bx {box} if show\n"
+ "} bind def\n"
+ "\n/rshow { %% usage: string rshow - show right-aligned\n"
+ " bx {box} if show\n"
+ "} bind def\n"
+ );
+
+ fprintf (fp,
+ "\n/box { %% usage: str box - draw box around string\n"
+ " gsave 0.5 setlinewidth dup stringwidth pop\n"
+ " -2 -2 rmoveto 4 add fh 4 add 2 copy\n"
+ " 0 exch rlineto 0 rlineto neg 0 exch rlineto neg 0 rlineto\n"
+ " stroke grestore\n"
+ "} bind def\n");
+
+ fprintf (fp,
+ "\n/wd { moveto bx {box} if show } bind def\n"
+ "/wln {\n"
+ "dup 3 1 roll moveto gsave 0.6 setlinewidth lineto stroke grestore\…
+ "} bind def\n");
+
+ fprintf (fp,
+ "/whf {moveto gsave 0.5 1.2 scale (-) show grestore} bind def\n");
+
+}
+
+/* ----- def_typset ------- */
+void def_typeset(fp)
+FILE *fp;
+{
+
+ fprintf (fp,
+ "\n/WS { %%usage: w nspaces str WS\n"
+ " dup stringwidth pop 4 -1 roll\n"
+ " sub neg 3 -1 roll div 0 8#040 4 -1 roll\n"
+ " widthshow\n"
+ "} bind def\n");
+
+
+ fprintf (fp,
+ "\n/W1 { show pop pop } bind def\n");
+
+
+ fprintf (fp,
+ "\n/str 50 string def\n"
+ "/W0 {\n"
+ " dup stringwidth pop str cvs exch show ( ) show show pop pop\n"
+ "} bind def\n");
+
+ fprintf (fp,
+ "\n/WC { counttomark 1 sub dup 0 eq { 0 }\n"
+ " { ( ) stringwidth pop neg 0 3 -1 roll\n"
+ " { dup 3 add index stringwidth pop ( ) stringwidth pop add\n"
+ " dup 3 index add 4 index lt 2 index 1 lt or\n"
+ " {3 -1 roll add exch 1 add} {pop exit} ifelse\n"
+ " } repeat } ifelse\n"
+ "} bind def\n");
+
+ fprintf (fp,
+ "\n/P1 {\n"
+ " { WC dup 0 le {exit} if\n"
+ " exch pop gsave { exch show ( ) show } repeat grestore LF\n"
+ " } loop pop pop pop pop\n"
+ "} bind def\n");
+
+ fprintf (fp,
+ "\n/P2 {\n"
+ " { WC dup 0 le {exit} if\n"
+ " dup 1 sub dup 0 eq\n"
+ " { pop exch pop 0.0 }\n"
+ " { 3 2 roll 3 index exch sub exch div } ifelse\n"
+ " counttomark 3 sub 2 index eq { pop 0 } if exch gsave\n"
+ " { 3 2 roll show ( ) show dup 0 rmoveto } repeat\n"
+ " grestore LF pop\n"
+ " } loop pop pop pop pop\n"
+ "} bind def\n");
+
+}
+
+/* ----- define_font ------- */
+void define_font (fp,name,num)
+FILE *fp;
+char name[];
+int num;
+{
+
+ if (!strcmp(name,"Symbol")) {
+ fprintf (fp,
+ "/F%d { 1 eq {/bx true def} { /bx false def} ifelse\n"
+ " dup 0.72 mul /fh exch def\n"
+ " /%s exch selectfont } bind def\n",
+ num, name);
+ return;
+ }
+
+ fprintf (fp,
+ "\n/%s findfont\n"
+ "dup length dict begin\n"
+ " {1 index /FID ne {def} {pop pop} ifelse} forall\n"
+ " /Encoding ISOLatin1Encoding def\n"
+ " currentdict\n"
+ "end\n"
+ "/%s-ISO exch definefont pop\n",
+ name, name);
+
+ fprintf (fp,
+ "/F%d { 1 eq {/bx true def} { /bx false def} ifelse\n"
+ " dup 0.72 mul /fh exch def\n"
+ " /%s-ISO exch selectfont } bind def\n",
+ num, name);
+
+}
+
+
+/* ----- def_tsig ------- */
+void def_tsig (fp)
+FILE *fp;
+{
+ fprintf (fp,
+ "\n/tsig { %% usage: x (top) (bot) tsig -- draw time signature\n"
+ " 3 -1 roll 0 moveto /bx false def\n"
+ " gsave /Times-Bold 16 selectfont 1.2 1 scale\n"
+ " 0 1.0 rmoveto currentpoint 3 -1 roll cshow\n"
+ " moveto 0 12 rmoveto cshow grestore\n"
+ "} bind def\n"
+ );
+}
+
+/* ----- add_cv ------- */
+void add_cv (fp,f1,f2,p,i0,ncv)
+FILE *fp;
+float p[][2],f1,f2;
+int i0,ncv;
+{
+ int i,i1,m;
+
+ i1=i0;
+ for (m=0; m<ncv; m++) {
+ fprintf (fp, " ");
+ for (i=0; i<3; i++)
+ fprintf (fp, " %.2f %.2f",
+ f1*(p[i1+i][0]-p[i1-1][0]),
+ f2*(p[i1+i][1]-p[i1-1][1]));
+ fprintf (fp, " rcurveto\n");
+ i1=i1+3;
+ }
+}
+
+/* ----- add_sg ------- */
+void add_sg (fp,f1,f2,p,i0,nseg)
+FILE *fp;
+float p[][2],f1,f2;
+int i0,nseg;
+{
+ int i;
+ for (i=0; i<nseg; i++)
+ fprintf (fp, " %.2f %.2f rlineto\n",
+ f1*(p[i0+i][0]-p[i0+i-1][0]),
+ f2*(p[i0+i][1]-p[i0+i-1][1]));
+}
+
+/* ----- add_mv ------- */
+void add_mv (fp,f1,f2,p,i0)
+FILE *fp;
+float p[][2],f1,f2;
+int i0;
+{
+ if (i0==0)
+ fprintf (fp, " %.2f %.2f rmoveto\n",
+ f1*p[i0][0], f2*p[i0][1]);
+ else
+ fprintf (fp, " %.2f %.2f rmoveto\n",
+ f1*(p[i0][0]-p[i0-1][0]),
+ f2*(p[i0][1]-p[i0-1][1]));
+}
+
+
+/* ----- def_stems ------- */
+void def_stems (fp)
+FILE *fp;
+{
+ fprintf (fp,
+ "\n/su { %% usage: len su - up stem\n"
+ " x y moveto %.1f %.1f rmoveto %.1f sub 0 exch rlineto stroke\n"
+ "} bind def\n",
+ STEM_XOFF, STEM_YOFF, STEM_YOFF );
+
+ fprintf(fp,
+ "\n/sd { %% usage: len td - down stem\n"
+ " x y moveto %.1f %.1f rmoveto neg %.1f add 0 exch rlineto stroke\n"
+ "} bind def\n",
+ -STEM_XOFF, -STEM_YOFF, STEM_YOFF);
+}
+
+/* ----- def_dot ------- */
+void def_dot (fp)
+FILE *fp;
+{
+ fprintf(fp,
+ "\n/dt { %% usage: dx dy dt - dot shifted by dx,dy\n"
+ " y add exch x add exch 1.2 0 360 arc fill\n"
+ "} bind def\n");
+}
+
+/* ----- def_deco ------- */
+void def_deco (fp)
+FILE *fp;
+{
+
+ float p[7][2] = {
+ {-10,-2},{0,15},{1,-11},{10,2},{0,-15},{-1,11},{-10,-2} };
+
+/* float q[7][2] = {
+ {-13,0},{-2,9},{2,9},{13,0},{3,5},{-3,5},{-13,-0} }; */
+
+/* float q[7][2] = {
+ {-11,0},{-9,10},{9,10},{11,0},{5,7},{-5,7},{-11,-0} }; */
+
+ /* Walsh suggestion, scale 1.8 in y */
+ float q[7][2] = {
+ {-13,0},{-12,9},{12,9},{13,0},{10,7.4},{-10,7.4},{-13,-0} };
+
+ float s[7][2] = {
+ {-8,-4.8},{-6,-5.5},{-3,-4.6},{0,0},{-2.3,-5},{-6,-6.8},{-8.5,-6} };
+
+ float f1,f2;
+ int i;
+
+ f1=0.5;
+ f2=0.5;
+
+ fprintf (fp, "\n/grm { %% usage: y grm - gracing mark\n"
+ " x exch moveto\n");
+ add_mv (fp,f1,f2,p,0);
+ add_cv (fp,f1,f2,p,1,2);
+ fprintf (fp, " fill\n} bind def\n");
+ fprintf (fp, "\n/stc { %% usage: y stc - staccato mark\n"
+ " x exch 1.2 0 360 arc fill } bind def\n");
+
+ fprintf (fp, "\n/hat { %% usage: y hat\n"
+ " x exch moveto\n"
+ " -4 -2 rmoveto 4 6 rlineto currentpoint stroke moveto\n"
+ " 4 -6 rlineto -2 0 rlineto -3 4.5 rlineto fill\n"
+ " } bind def\n");
+
+ fprintf (fp, "\n/att { %% usage: y att\n"
+ " x exch moveto\n"
+ " -4 -3 rmoveto 8 3 rlineto -8 3 rlineto stroke\n"
+ " } bind def\n");
+
+ f2=f2*1.8;
+
+ if (temp_switch==3) { f1=0.8*f1; f2=0.8*f2; }
+ else { f1=0.9*f1; f2=0.9*f2; }
+
+ fprintf (fp, "\n/cpu { %% usage: y cpu - roll sign above head\n"
+ " x exch moveto\n");
+ add_mv (fp,f1,f2,q,0);
+ add_cv (fp,f1,f2,q,1,2);
+ fprintf (fp, " fill\n} bind def\n");
+
+ for (i=0;i<7;i++) q[i][1]=-q[i][1];
+
+ fprintf (fp, "\n/cpd { %% usage: y cpd - roll sign below head\n"
+ " x exch moveto\n");
+ add_mv (fp,f1,f2,q,0);
+ add_cv (fp,f1,f2,q,1,2);
+ fprintf (fp, " fill\n} bind def\n");
+
+ f1=0.9;
+ f2=1.0;
+ fprintf (fp, "\n/sld { %% usage: y dx sld - slide\n"
+ " x exch sub exch moveto\n");
+ add_mv (fp,f1,f2,s,0);
+ add_cv (fp,f1,f2,s,1,2);
+ fprintf (fp, " fill\n} bind def\n");
+
+ fprintf (fp, "\n/emb { %% usage: y emb - empahsis bar\n"
+ " gsave 1.4 setlinewidth 1 setlinecap x exch moveto \n"
+ " -3.5 0 rmoveto 7 0 rlineto stroke grestore\n"
+ "} bind def\n");
+
+ fprintf (fp, "\n/trl { %% usage: y trl - trill sign\n"
+ " gsave /Times-BoldItalic 14 selectfont\n"
+ " x 4 sub exch moveto (tr) show grestore\n"
+ "} bind def\n");
+
+}
+
+
+
+/* ----- def_deco1 ------- */
+void def_deco1 (fp)
+FILE *fp;
+{
+
+ float p[8][2] = { /* for hold sign */
+ {-15,0},{-15,23},{15,23},{15,0},
+ {14.5,0},{12,18},{-12,18},{-14.5,0} };
+
+ float q[8][2] = { /* for down bow sign */
+ {-4,0},{-4,9},{4,9},{4,0},
+ {-4,6},{-4,9},{4,9},{4,6} };
+
+ float r[3][2] = { /* for up bow sign */
+ {-3.2,11},{0,0},{3.2,11} };
+
+ float f1,f2;
+
+ f1=f2=0.5;
+ fprintf (fp, "\n/hld { %% usage: y hld - hold sign\n"
+ " x exch 2 copy 1.5 add 1.3 0 360 arc moveto\n");
+ add_mv (fp,f1,f2,p,0);
+ add_cv (fp,f1,f2,p,1,1);
+ add_sg (fp,f1,f2,p,4,1);
+ add_cv (fp,f1,f2,p,5,1);
+ fprintf (fp, " fill\n} bind def\n");
+
+ f1=f2=0.8;
+ fprintf (fp, "\n/dnb { %% usage: y dnb - down bow\n"
+ " x exch moveto\n");
+ add_mv (fp,f1,f2,q,0);
+ add_sg (fp,f1,f2,q,1,3);
+ fprintf (fp, " currentpoint stroke moveto\n");
+ add_mv (fp,f1,f2,q,4);
+ add_sg (fp,f1,f2,q,5,3);
+ fprintf (fp, " fill\n} bind def\n");
+
+ fprintf (fp, "\n/upb { %% usage: y upb - up bow\n"
+ " x exch moveto\n");
+ add_mv (fp,f1,f2,r,0);
+ add_sg (fp,f1,f2,r,1,2);
+ fprintf (fp, " stroke\n} bind def\n");
+
+}
+
+/* ----- def_hl ------- */
+void def_hl (fp)
+FILE *fp;
+{
+ fprintf(fp,
+ "\n/hl { %% usage: y hl - helper line at height y\n"
+ " gsave 1 setlinewidth x exch moveto \n"
+ " -5.5 0 rmoveto 11 0 rlineto stroke grestore\n"
+ "} bind def\n");
+
+ fprintf(fp,
+ "\n/hl1 { %% usage: y hl1 - longer helper line\n"
+ " gsave 1 setlinewidth x exch moveto \n"
+ " -7 0 rmoveto 14 0 rlineto stroke grestore\n"
+ "} bind def\n");
+}
+
+/* ----- def_beam ------- */
+void def_beam (fp)
+FILE *fp;
+{
+ fprintf(fp,
+ "\n/bm { %% usage: x1 y1 x2 y2 t bm - beam, depth t\n"
+ " 3 1 roll moveto dup 0 exch neg rlineto\n"
+ " dup 4 1 roll sub lineto 0 exch rlineto fill\n"
+ "} bind def\n");
+
+ fprintf(fp,
+ "\n/bnum { %% usage: x y (str) bnum - number on beam\n"
+ " 3 1 roll moveto gsave /Times-Italic 12 selectfont\n"
+ " /bx false def cshow grestore\n"
+ "} bind def\n");
+
+
+ fprintf(fp,
+ "\n/hbr { %% usage: x1 y1 x2 y2 hbr - half bracket\n"
+ " moveto lineto 0 -3 rlineto stroke\n"
+ "} bind def\n");
+}
+
+
+/* ----- def_flags1 ------- */
+void def_flags1 (fp)
+FILE *fp;
+{
+ float p[13][2] = {
+ {0.0, 0.0}, {1.5, -3.0}, {1.0, -2.5}, {4.0, -6.0}, {9.0, -10.0},
+ {9.0, -16.0}, {8.0, -20.0}, {7.0, -24.0}, {4.0, -26.0},
+ {6.5, -21.5}, {9.0, -15.0}, {4.0, -9.0}, {0.0, -8.0} } ;
+
+ float f1,f2;
+ int i;
+
+ f1=f2=6.0/9.0;
+ fprintf (fp, "\n/f1u { %% usage: len f1u - single flag up\n"
+ " y add x %.1f add exch moveto\n", STEM_XOFF);
+ add_mv (fp,f1,f2,p,0);
+ add_cv (fp,f1,f2,p,1,4);
+ fprintf (fp, " fill\n} bind def\n");
+
+ f1=1.2*f1;
+ for (i=0;i<13;i++) p[i][1]=-p[i][1];
+ fprintf (fp, "\n/f1d { %% usage: len f1d - single flag down\n"
+ " neg y add x %.1f sub exch moveto\n", STEM_XOFF);
+ add_mv (fp,f1,f2,p,0);
+ add_cv (fp,f1,f2,p,1,4);
+ fprintf (fp, " fill\n} bind def\n");
+
+}
+
+/* ----- def_flags2 ------- */
+void def_flags2 (fp)
+FILE *fp;
+{
+
+ float p[13][2] = {
+ {0.0, 0.0},
+ {2.0, -5.0}, {9.0, -6.0}, {7.5, -18.0},
+ {7.5, -9.0}, {1.5, -6.5}, {0.0, -6.5},
+ {2.0, -14.0}, {9.0, -14.0}, {7.5, -26.0},
+ {7.5, -17.0}, {1.5, -14.5}, {0.0, -14.0},
+ };
+
+ float f1,f2;
+ int i;
+
+ f1=f2=6.0/9.0; /* up flags */
+ fprintf (fp, "\n/f2u { %% usage: len f2u - double flag up\n"
+ " y add x %.1f add exch moveto\n", STEM_XOFF);
+ add_mv (fp,f1,f2,p,0);
+ add_cv (fp,f1,f2,p,1,4);
+ fprintf (fp, " fill\n} bind def\n");
+
+ f1=1.2*f1; /* down flags */
+ for (i=0;i<13;i++) p[i][1]=-p[i][1];
+ fprintf (fp, "\n/f2d { %% usage: len f2d - double flag down\n"
+ " neg y add x %.1f sub exch moveto\n", STEM_XOFF);
+ add_mv (fp,f1,f2,p,0);
+ add_cv (fp,f1,f2,p,1,4);
+ fprintf (fp, " fill\n} bind def\n");
+
+}
+
+
+
+/* ----- def_xflags ------- */
+void def_xflags (fp)
+FILE *fp;
+{
+
+ float p[7][2] = {
+ {0.0, 0.0},
+ {2.0, -7.5}, {9.0, -7.5}, {7.5, -19.5},
+ {7.5, -10.5}, {1.5, -8.0}, {0.0, -7.5}
+ };
+
+ float f1,f2;
+ int i;
+
+ f1=f2=6.0/9.0; /* extra up flag */
+ fprintf (fp, "\n/xfu { %% usage: len xfu - extra flag up\n"
+ " y add x %.1f add exch moveto\n", STEM_XOFF);
+ add_mv (fp,f1,f2,p,0);
+ add_cv (fp,f1,f2,p,1,2);
+ fprintf (fp, " fill\n} bind def\n");
+
+ f1=1.2*f1; /* extra down flag */
+ for (i=0;i<7;i++) p[i][1]=-p[i][1];
+ fprintf (fp, "\n/xfd { %% usage: len xfd - extra flag down\n"
+ " neg y add x %.1f sub exch moveto\n", STEM_XOFF);
+ add_mv (fp,f1,f2,p,0);
+ add_cv (fp,f1,f2,p,1,2);
+ fprintf (fp, " fill\n} bind def\n");
+
+ fprintf (fp,
+ "\n/f3d {dup f2d 9.5 sub xfd} bind def\n");
+
+ fprintf (fp,
+ "\n/f4d {dup dup f2d 9.5 sub xfd 14.7 sub xfd} bind def\n");
+
+ fprintf (fp,
+ "\n/f3u {dup f2u 9.5 sub xfu} bind def\n");
+
+ fprintf (fp,
+ "\n/f4u {dup dup f2u 9.5 sub xfu 14.7 sub xfu} bind def\n");
+
+}
+
+/* ----- def_acc ------- */
+void def_acc (fp)
+FILE *fp;
+{
+ float p[12][2]={
+ {-2,3},{6,6.5},{6,-1},{-2,-4.5},{4,0},{4,4},{-2,2},{-2,10},{-2,-4}};
+ float q[14][2]={
+ {4,4},{4,7},{-4,5},{-4,2},{4,4},{4,-5},{4,-2},{-4,-4},{-4,-7},{4,-5},
+ {2,-10},{2,11.5},{-2,-11.5},{-2,10} };
+ float r[14][2]={
+ {-2.5,-6}, {2.5,-5}, {2.5,-2}, {-2.5,-3}, {-2.5,6},
+ {-2.5,2}, {2.5,3}, {2.5,6}, {-2.5,5}, {-2.5,2},
+ {-2.5,11}, {-2.5,-5.5},
+ {2.5,5.5}, {2.5,-11} };
+ float s[25][2]={
+ {0.7,0},{3.9,3},{6,3},{6.2,6.2},{3,6},{3,3.9},
+ {0,0.7},{-3,3.9},{-3,6},{-6.2,6.2},{-6,3},{-3.9,3},
+ {-0.7,0},{-3.9,-3},{-6,-3},{-6.2,-6.2},{-3,-6},{-3,-3.9},
+ {0,-0.7},{3,-3.9},{3,-6},{6.2,-6.2},{6,-3},{3.9,-3},
+ {0.7,0} };
+
+
+ float f1,f2;
+
+ f2=8.0/9.0;
+ f1=f2*0.9;
+ fprintf (fp, "\n/ft0 { %% usage: x y ft0 - flat sign\n"
+ " moveto\n");
+ add_mv (fp,f1,f2,p,0);
+ add_cv (fp,f1,f2,p,1,2);
+ fprintf (fp, " currentpoint fill moveto\n");
+ add_mv (fp,f1,f2,p,7);
+ add_sg (fp,f1,f2,p,8,1);
+ fprintf (fp, " stroke\n } bind def\n");
+ fprintf (fp, "/ft { %% usage: dx ft - flat relative to head\n"
+ " neg x add y ft0 } bind def\n");
+
+ f2=8.0/9.0; /* more narrow flat sign for double flat */
+ f1=f2*0.8;
+ fprintf (fp, "\n/ftx { %% usage: x y ftx - narrow flat sign\n"
+ " moveto\n");
+ add_mv (fp,f1,f2,p,0);
+ add_cv (fp,f1,f2,p,1,2);
+ fprintf (fp, " currentpoint fill moveto\n");
+ add_mv (fp,f1,f2,p,7);
+ add_sg (fp,f1,f2,p,8,1);
+ fprintf (fp, " stroke\n } bind def\n");
+
+ fprintf (fp, "/dft0 { %% usage: x y dft0 ft - double flat sign\n"
+ " 2 copy exch 2.5 sub exch ftx exch 1.5 add exch ftx } bind def\n"
+ "/dft { %% usage: dx dft - double flat relative to head\n"
+ " neg x add y dft0 } bind def\n");
+
+
+ f2=6.5/9.0;
+ f1=f2*0.9;
+ fprintf (fp, "\n/sh0 { %% usage: x y sh0 - sharp sign\n"
+ " moveto\n");
+ add_mv (fp,f1,f2,q,0);
+ add_sg (fp,f1,f2,q,1,4);
+ add_mv (fp,f1,f2,q,5);
+ add_sg (fp,f1,f2,q,6,4);
+ fprintf (fp, " currentpoint fill moveto\n");
+ add_mv (fp,f1,f2,q,10);
+ add_sg (fp,f1,f2,q,11,1);
+ fprintf (fp, " currentpoint stroke moveto\n");
+ add_mv (fp,f1,f2,q,12);
+ add_sg (fp,f1,f2,q,13,1);
+ fprintf (fp, " stroke\n } bind def\n");
+ fprintf (fp, "/sh { %% usage: dx sh - sharp relative to head\n"
+ " neg x add y sh0 } bind def\n");
+
+ f2=6.5/9.0;
+ f1=f2*0.9;
+ fprintf (fp, "\n/nt0 { %% usage: x y nt0 - neutral sign\n"
+ " moveto\n");
+ add_mv (fp,f1,f2,r,0);
+ add_sg (fp,f1,f2,r,1,4);
+ add_mv (fp,f1,f2,r,5);
+ add_sg (fp,f1,f2,r,6,4);
+ fprintf (fp, " currentpoint fill moveto\n");
+ add_mv (fp,f1,f2,r,10);
+ add_sg (fp,f1,f2,r,11,1);
+ fprintf (fp, " currentpoint stroke moveto\n");
+ add_mv (fp,f1,f2,r,12);
+ add_sg (fp,f1,f2,r,13,1);
+ fprintf (fp, " stroke\n } bind def\n");
+ fprintf (fp, "/nt { %% usage: dx nt - neutral relative to head\n"
+ " neg x add y nt0 } bind def\n");
+
+ f1=5.0/9.0;
+ f2=f1;
+ fprintf (fp, "\n/dsh0 { %% usage: x y dsh0 - double sharp \n"
+ " moveto\n");
+ add_mv (fp,f1,f2,s,0);
+ add_sg (fp,f1,f2,s,1,24);
+ fprintf (fp, " fill\n } bind def\n");
+ fprintf (fp, "/dsh { %% usage: dx dsh - double sharp relative to head\n"
+ " neg x add y dsh0 } bind def\n");
+}
+
+/* ----- def_rests ------- */
+void def_rests (fp)
+FILE *fp;
+{
+ float p[14][2]={
+ {-1,17}, {15,4}, {-6,8}, {6.5,-5}, {-2,-2}, {-5,-11}, {1,-15},
+ {-9,-11}, {-6,0}, {1,-1}, {-9,7}, {7,5}, {-1,17} };
+ float q[16][2]={
+ {8,14}, {5,9}, {3,5}, {-1.5,4},
+ {4,11}, {-9,14}, {-9,7},
+ {-9,4}, {-6,2}, {-3,2},
+ {4,2}, {5,7}, {7,11},
+ {-1.8,-20}, {-0.5,-20}, {8.5,14}};
+ float r[29][2]={
+ {8,14}, {5,9}, {3,5}, {-1.5,4},
+ {4,11}, {-9,14}, {-9,7},
+ {-9,4}, {-6,2}, {-3,2},
+ {4,2}, {5,7}, {7,11},
+ {8,14}, {5,9}, {3,5}, {-1.5,4},
+ {4,11}, {-9,14}, {-9,7},
+ {-9,4}, {-6,2}, {-3,2},
+ {4,2}, {5,7}, {7.3,11},
+ {-1.8,-21}, {-0.5,-21}, {8.5,14} };
+ float f1,f2;
+ int i;
+
+ fprintf (fp, "\n/r4 { %% usage: x y r4 - quarter rest\n"
+ " dup /y exch def exch dup /x exch def exch moveto\n");
+ f1=f2=6.0/11.5;
+ add_mv (fp,f1,f2,p,0);
+ add_cv (fp,f1,f2,p,1,4);
+ fprintf (fp, " fill\n } bind def\n");
+
+ fprintf (fp, "\n/r8 { %% usage: x y r8 - eighth rest\n"
+ " dup /y exch def exch dup /x exch def exch moveto\n");
+ f1=f2=7/18.0;
+ add_mv (fp,f1,f2,q,0);
+ add_cv (fp,f1,f2,q,1,4);
+ add_sg (fp,f1,f2,q,13,3);
+ fprintf (fp, " fill\n } bind def\n");
+
+ for (i=13;i<26;i++) { r[i][0]-=4.2; r[i][1]-=14; }
+ fprintf (fp, "\n/r16 { %% usage: x y r16 - 16th rest\n"
+ " dup /y exch def exch dup /x exch def exch moveto\n");
+ f1=f2=7/18.0;
+ add_mv (fp,f1,f2,r,0);
+ add_cv (fp,f1,f2,r,1,4);
+ add_sg (fp,f1,f2,r,13,1);
+ add_cv (fp,f1,f2,r,14,4);
+ add_sg (fp,f1,f2,r,26,3);
+ fprintf (fp, " fill\n } bind def\n");
+
+
+ fprintf (fp,
+ "\n/r1 { %% usage: x y r1 - whole rest\n"
+ " dup /y exch def exch dup /x exch def exch moveto\n"
+ " -3 6 rmoveto 0 -3 rlineto 6 0 rlineto 0 3 rlineto fill\n"
+ "} bind def\n");
+
+ fprintf (fp,
+ "\n/r2 { %% usage: x y r2 - half rest\n"
+ " dup /y exch def exch dup /x exch def exch moveto\n"
+ " -3 0 rmoveto 0 3 rlineto 6 0 rlineto 0 -3 rlineto fill\n"
+ "} bind def\n"
+ );
+
+ /* get 32nd, 64th rest by overwriting 8th and 16th rests */
+ fprintf (fp,
+ "\n/r32 {\n"
+ "2 copy r16 5.5 add exch 1.6 add exch r8\n"
+ "} bind def\n");
+ fprintf (fp,
+ "\n/r64 {\n"
+ "2 copy 5.5 add exch 1.6 add exch r16\n"
+ "5.5 sub exch 1.5 sub exch r16\n"
+ "} bind def\n");
+
+}
+
+
+/* ----- def_bars ------ */
+void def_bars (fp)
+FILE *fp;
+{
+
+ fprintf(fp, "\n/bar { %% usage: x bar - single bar\n"
+ " 0 moveto 0 24 rlineto stroke\n"
+ "} bind def\n"
+
+ "\n/dbar { %% usage: x dbar - thin double bar\n"
+ " 0 moveto 0 24 rlineto -3 -24 rmoveto\n"
+ " 0 24 rlineto stroke\n"
+ "} bind def\n"
+
+ "\n/fbar1 { %% usage: x fbar1 - fat double bar at start\n"
+ " 0 moveto 0 24 rlineto 3 0 rlineto 0 -24 rlineto \n"
+ " currentpoint fill moveto\n"
+ " 3 0 rmoveto 0 24 rlineto stroke\n"
+ "} bind def\n"
+
+ "\n/fbar2 { %% usage: x fbar2 - fat double bar at end\n"
+ " 0 moveto 0 24 rlineto -3 0 rlineto 0 -24 rlineto \n"
+ " currentpoint fill moveto\n"
+ " -3 0 rmoveto 0 24 rlineto stroke\n"
+ "} bind def\n"
+
+ "\n/rdots { %% usage: x rdots - repeat dots \n"
+ " 0 moveto 0 9 rmoveto currentpoint 2 copy 1.2 0 360 arc \n"
+ " moveto 0 6 rmoveto currentpoint 1.2 0 360 arc fill\n"
+ "} bind def\n");
+}
+
+/* ----- def_ends ------ */
+void def_ends (fp)
+FILE *fp;
+{
+ /* use dy=20 for tall boxes */
+ int y=50,dy=6;
+
+ fprintf(fp, "\n/end1 { %% usage: x1 x2 (str) end1 - mark first ending\n"
+ " 3 1 roll %d moveto 0 %d rlineto dup %d lineto 0 %d rlineto stroke…
+ " 4 add %d moveto gsave /Times-Roman 13 selectfont 1.2 0.95 scale\n"
+ " show grestore\n"
+ "} bind def\n",
+ y-dy, dy, y, -dy, y-10);
+
+ fprintf(fp, "\n/end2 { %% usage: x1 x2 (str) end2 - mark second ending\n"
+ " 3 1 roll %d moveto dup %d lineto 0 %d rlineto stroke\n"
+ " 4 add %d moveto gsave /Times-Roman 13 selectfont 1.2 0.95 scale\n"
+ " show grestore\n"
+ "} bind def\n",
+ y, y, -dy, y-10);
+}
+
+/* ----- def_gchord ------ */
+void def_gchord (fp)
+FILE *fp;
+{
+ fprintf(fp,"\n/gc { %% usage: x y (str) gc -- draw guitar chord string\n"
+ " 3 1 roll moveto rshow\n"
+ "} bind def\n");
+}
+
+/* ----- def_sl ------ */
+void def_sl (fp)
+FILE *fp;
+{
+/* fprintf(fp, "\n/sl { %% usage: x1 y2 x2 y2 x3 y3 x0 y0 sl\n"
+ " gsave %.1f setlinewidth moveto curveto stroke grestore\n"
+ "} bind def\n", SLURWIDTH); */
+
+ fprintf(fp, "\n/SL { %% usage: pp2x pp1x p1 pp1 pp2 p2 p1 sl\n"
+ " moveto curveto rlineto curveto fill\n"
+ "} bind def\n");
+
+}
+
+/* ----- def_hd1 ------- */
+void def_hd1 (fp)
+FILE *fp;
+{
+ float p[7][2] = {
+ {8.0, 0.0}, {8.0, 8.0}, {-8.0, 8.0}, {-8.0, 0.0}, {-8.0, -8.0},
+ {8.0, -8.0}, {8.0, 0.0} };
+
+ float c,s,xx,yy,f1,f2;
+ int i;
+/*float phi; */
+
+/*phi=0.6;
+ c=cos(phi);
+ s=sin(phi); */
+
+ c=0.825; s=0.565;
+
+ for (i=0;i<7;i++) {
+ xx = c*p[i][0] - s*p[i][1];
+ yy = s*p[i][0] + c*p[i][1];
+ p[i][0]=xx;
+ p[i][1]=yy;
+ }
+
+ f1=f2=6.0/12.0;
+ fprintf (fp, "\n/hd { %% usage: x y hd - full head\n"
+ " dup /y exch def exch dup /x exch def exch moveto\n");
+ add_mv (fp,f1,f2,p,0);
+ add_cv (fp,f1,f2,p,1,2);
+ fprintf (fp, " fill\n} bind def\n");
+}
+
+/* ----- def_hd2 ------- */
+void def_hd2 (fp)
+FILE *fp;
+{
+
+ float p[14][2] = {
+ {8.0, 0.0}, {8.0, 8.5}, {-8.0, 8.5}, {-8.0, 0.0}, {-8.0, -8.5},
+ {8.0, -8.5}, {8.0, 0.0}, {7.0, 0.0}, {7.0, -4.0}, {-7.0, -4.0},
+ {-7.0, 0.0}, {-7.0, 4.0}, {7.0, 4.0}, {7.0, 0.0} };
+
+/* float phi; */
+ float c,s,xx,yy,f1,f2;
+ int i;
+
+/*phi=0.5;
+ c=cos(phi);
+ s=sin(phi); */
+
+ c=0.878; s=0.479;
+
+ for (i=0;i<14;i++) {
+ xx = c*p[i][0] - s*p[i][1];
+ yy = s*p[i][0] + c*p[i][1];
+ p[i][0]=xx;
+ p[i][1]=yy;
+ }
+
+ f1=f2=6.0/12.0;
+ fprintf (fp, "\n/Hd { %% usage: x y Hd - open head for half\n"
+ " dup /y exch def exch dup /x exch def exch moveto\n");
+ add_mv (fp,f1,f2,p,0);
+ add_cv (fp,f1,f2,p,1,2);
+ add_mv (fp,f1,f2,p,7);
+ add_cv (fp,f1,f2,p,8,2);
+ fprintf (fp, " fill\n} bind def\n");
+}
+
+/* ----- def_hd3 ------- */
+void def_hd3 (fp)
+FILE *fp;
+{
+
+ float p[13][2] = {
+ {11.0, 0.0}, {11.0, 2.0}, {6.0, 6.5}, {0.0, 6.5}, {-6.0, 6.5},
+ {-11.0, 2.0}, {-11.0, 0.0}, {-11.0, -2.0}, {-6.0, -6.5},
+ {0.0, -6.5}, {6.0, -6.5}, {11.0, -2.0}, {11.0, 0.0} };
+
+ float q[8][2] = {
+ {11.0, 0.0}, {5.0, 0.0}, {5.0, -5.0}, {-5.0, -5.0}, {-5.0, 0.0},
+ {-5.0, 5.0}, {5.0, 5.0}, {5.0, 0.0}};
+
+/* float phi; */
+ float c,s,xx,yy,f1,f2;
+ int i;
+
+/*phi=2.5;
+ c=cos(phi);
+ s=sin(phi); */
+
+ c=-0.801; s=0.598;
+
+ for (i=1;i<8;i++) {
+ xx = c*q[i][0] - s*q[i][1];
+ yy = s*q[i][0] + c*q[i][1];
+ q[i][0]=xx;
+ q[i][1]=yy;
+ }
+
+ f1=f2=6.5/12.0;
+ fprintf (fp, "\n/HD { %% usage: x y HD - open head for whole\n"
+ " dup /y exch def exch dup /x exch def exch moveto\n");
+ add_mv (fp,f1,f2,p,0);
+ add_cv (fp,f1,f2,p,1,4);
+ add_mv (fp,f1,f2,q,1);
+ add_cv (fp,f1,f2,q,2,2);
+ fprintf (fp, " fill\n} bind def\n");
+
+}
+
+/* ----- def_gnote ------- */
+void def_gnote (fp)
+FILE *fp;
+{
+ float p[7][2] = {
+ {0,10}, {16,10}, {16,-10}, {0,-10}, {-16,-10}, {-16,10}, {0,10} };
+
+/* float phi; */
+ float c,s,xx,yy,f1,f2;
+ int i;
+
+/*phi=0.7;
+ c=cos(phi);
+ s=sin(phi); */
+
+ c=0.765; s=0.644;
+
+ for (i=0;i<7;i++) {
+ xx = c*p[i][0] - s*p[i][1];
+ yy = s*p[i][0] + c*p[i][1];
+ p[i][0]=xx;
+ p[i][1]=yy;
+ }
+
+ f1=f2=2./10.0;
+
+ fprintf (fp, "\n/gn1 { %% usage: x y l gnt - grace note w. tail\n"
+ " 3 1 roll 2 copy moveto\n");
+ add_mv (fp,f1,f2,p,0);
+ add_cv (fp,f1,f2,p,1,2);
+ fprintf (fp, " fill moveto %.2f 0 rmoveto 0 exch rlineto\n"
+ "3 -4 4 -5 2 -8 rcurveto -5 2 rmoveto 7 4 rlineto \n"
+ "stroke\n",
+ GSTEM_XOFF);
+ fprintf (fp, "} bind def\n");
+
+ fprintf (fp, "\n/gnt { %% usage: x y l gnt - grace note\n"
+ " 3 1 roll 2 copy moveto\n");
+ add_mv (fp,f1,f2,p,0);
+ add_cv (fp,f1,f2,p,1,2);
+ fprintf (fp, " fill moveto %.2f 0 rmoveto 0 exch rlineto stroke\n",
+ GSTEM_XOFF);
+ fprintf (fp, "} bind def\n");
+
+ fprintf(fp, "\n/gbm2 { %% usage: x1 y1 x2 y2 gbm2 - double note beam\n"
+ " gsave 1.4 setlinewidth\n"
+ " 4 copy 0.5 sub moveto 0.5 sub lineto stroke\n"
+ " 3.4 sub moveto 3.4 sub lineto stroke grestore\n"
+ "} bind def\n");
+
+ fprintf(fp, "\n/gbm3 { %% usage: x1 y1 x2 y2 gbm3 - triple gnote beam\n"
+ " gsave 1.2 setlinewidth\n"
+ " 4 copy 0.3 sub moveto 0.3 sub lineto stroke\n"
+ " 4 copy 2.5 sub moveto 2.5 sub lineto stroke\n"
+ " 4.7 sub moveto 4.7 sub lineto stroke grestore\n"
+ "} bind def\n");
+
+ fprintf(fp, "\n/ghl { %% usage: x y ghl - grace note helper line\n"
+ " gsave 0.7 setlinewidth moveto \n"
+ " -3 0 rmoveto 6 0 rlineto stroke grestore\n"
+ "} bind def\n");
+
+ fprintf(fp, "\n/gsl { %% usage: x1 y2 x2 y2 x3 y3 x0 y0 gsl\n"
+ " moveto curveto stroke\n"
+ "} bind def\n");
+
+ fprintf(fp, "\n/gsh0 { %% usage: x y gsh0\n"
+ "gsave translate 0.7 0.7 scale 0 0 sh0 grestore\n"
+ "} bind def\n");
+
+ fprintf(fp, "\n/gft0 { %% usage: x y gft0\n"
+ "gsave translate 0.7 0.7 scale 0 0 ft0 grestore\n"
+ "} bind def\n");
+
+ fprintf(fp, "\n/gnt0 { %% usage: x y gnt0\n"
+ "gsave translate 0.7 0.7 scale 0 0 nt0 grestore\n"
+ "} bind def\n");
+
+ fprintf(fp, "\n/gdf0 { %% usage: x y gdf0\n"
+ "gsave translate 0.7 0.6 scale 0 0 dft0 grestore\n"
+ "} bind def\n");
+
+ fprintf(fp, "\n/gds0 { %% usage: x y gds0\n"
+ "gsave translate 0.7 0.7 scale 0 0 dsh0 grestore\n"
+ "} bind def\n");
+}
+
+
+/* ----- def_csig ------- */
+void def_csg (fp)
+FILE *fp;
+{
+ float p[25][2]={
+ {0,26},
+ {4,26}, {11,23}, {11,14},
+ {11,20}, {5,19}, {5,14},
+ {5,9}, {12,9}, {12,15},
+ {12,25}, {6,28}, {0,28},
+ {-15,28}, {-25,17}, {-25,2},
+ {-25,-10}, {-10,-28}, {11,-8},
+ {-6,-20}, {-18,-11}, {-18,2},
+ {-18,14}, {-14,26}, {0,26} };
+
+ float f1,f2;
+ int i;
+
+ for (i=0;i<25;i++) {
+ p[i][0]=p[i][0]+4;
+ p[i][1]=p[i][1]+43;
+ }
+ f1 = f2 = 0.25;
+ fprintf (fp, "\n/csig { %% usage: x csig - C timesig \n"
+ " 0 moveto\n");
+ add_mv (fp,f1,f2,p,0);
+ add_cv (fp,f1,f2,p,1,8);
+ fprintf (fp, " fill\n} bind def\n");
+
+ fprintf (fp, "\n/ctsig { %% usage: x ctsig - C| timesig \n"
+ " dup csig 4 moveto 0 16 rlineto stroke\n"
+ "} bind def\n");
+}
+
+
+/* ----- def_tclef ------- */
+void def_tclef (fp)
+FILE *fp;
+{
+ float p[71][2]={
+ {-6, 16}, {-8, 13}, {-14, 19}, {-10, 35}, {2, 35}, {8, 37},
+ {21, 30}, {21, 17}, {21, 5}, {10, -1}, {0, -1}, {-12, -1},
+ {-23, 5}, {-23, 22}, {-23, 29}, {-22, 37}, {-7, 49}, {10, 61},
+ {10, 68}, {10, 73}, {10, 78}, {9, 82}, {7, 82}, {2, 78},
+ {-2, 68}, {-2, 62}, {-2, 25}, {10, 18}, {11, -8}, {11, -18},
+ {5, -23}, {-4, -23}, {-10, -23}, {-15, -18}, {-15, -13},
+ {-15, -8}, {-12, -4}, {-7, -4}, {3, -4}, {3, -20}, {-6, -17},
+ {-5, -23}, {9, -20}, {9, -9}, {7, 24}, {-5, 30}, {-5, 67},
+ {-5, 78}, {-2, 87}, {7, 91}, {13, 87}, {18, 80}, {17, 73},
+ {17, 62}, {10, 54}, {1, 45}, {-5, 38}, {-15, 33}, {-15, 19},
+ {-15, 7}, {-8, 1}, {0, 1}, {8, 1}, {15, 6}, {15, 14}, {15, 23},
+ {7, 26}, {2, 26}, {-5, 26}, {-9, 21}, {-6, 16} };
+
+ float f1,f2;
+
+ f1 = f2 = 24.0/65.0;
+ fprintf (fp, "\n/tclef { %% usage: x tclef - treble clef \n"
+ " 0 moveto\n");
+ add_mv (fp,f1,f2,p,0);
+ add_sg (fp,f1,f2,p,1,1);
+ add_cv (fp,f1,f2,p,2,23);
+ fprintf (fp, " fill\n} bind def\n");
+ fprintf (fp, "\n/stclef {\n"
+ " 0.85 div gsave 0.85 0.85 scale tclef grestore\n"
+ "} bind def\n");
+}
+
+/* ----- def_bclef ------- */
+void def_bclef (fp)
+FILE *fp;
+{
+ float p[42][2]={
+ {-2.3,3}, {6,7}, {10.5,12}, {10.5,16},
+ {10.5,20.5}, {8.5,23.5}, {6.2,23.3},
+ {5.2,23.5}, {2,23.5}, {0.5,19.5},
+ {2,20}, {4,19.5}, {4,18},
+ {4,17}, {3.5,16}, {2,16},
+ {1,16}, {0,16.9}, {0,18.5},
+ {0,21}, {2.1,24}, {6,24},
+ {10,24}, {13.5,21.5}, {13.5,16.5},
+ {13.5,11}, {7,5.5}, {-2.0,2.8},
+ {14.9,21},
+ {14.9,22.5}, {16.9,22.5}, {16.9,21},
+ {16.9,19.5}, {14.9,19.5}, {14.9,21},
+ {14.9,15},
+ {14.9,16.5}, {16.9,16.5}, {16.9,15},
+ {16.9,13.5}, {14.9,13.5}, {14.9,15} };
+
+ int i;
+ float f1,f2;
+
+ for (i=0;i<42;i++) {p[i][0]-=7.5; p[i][1]-=0.5; }
+ f1 = f2 = 1.0;
+ fprintf (fp, "\n/bclef { %% usage: x bclef - bass clef \n"
+ " 0 moveto\n");
+ add_mv (fp,f1,f2,p,0);
+ add_cv (fp,f1,f2,p,1,9);
+ add_cv (fp,f1,f2,p,1,9);
+
+ add_mv (fp,f1,f2,p,28);
+ add_cv (fp,f1,f2,p,29,2);
+
+ add_mv (fp,f1,f2,p,25);
+ add_cv (fp,f1,f2,p,36,2);
+
+ fprintf (fp, "fill\n} bind def\n");
+
+ fprintf (fp, "\n/sbclef {\n"
+ " 0.85 div gsave 0.85 0.85 scale 0 4 translate bclef grestore\n"
+ "} bind def\n");
+}
+
+/* ----- def_cclef ------- */
+void def_cclef (fp)
+FILE *fp;
+{
+ float p[30][2]={
+ {0,0}, {2,5.5},
+ {9,4.5}, {12,10}, {12,15.5},
+ {12,19.5}, {11,23.3}, {6.5,23.5},
+ {5.2,23.5}, {2,23.5}, {0.5,19.5},
+ {2,20}, {4,19.5}, {4,18},
+ {4,17}, {3.5,16}, {2,16},
+ {1,16}, {0,16.9}, {0,18.5},
+ {0,21}, {2.1,24}, {6,24},
+ {12,24}, {15,21.5}, {15,16.5},
+ {15,10}, {10,4.5}, {4,5},
+ {3,0} };
+ int i;
+ float f1,f2;
+
+ for (i=0;i<30;i++) p[i][1]+=24;
+
+ f1 = 0.6;
+ f2 = 0.5;
+ fprintf (fp, "\n/cchalf {\n"
+ " 0 moveto\n");
+ add_mv (fp,f1,f2,p,0);
+ add_sg (fp,f1,f2,p,1,1);
+ add_cv (fp,f1,f2,p,2,9);
+ add_sg (fp,f1,f2,p,29,1);
+ fprintf (fp, "fill\n} bind def\n");
+
+ fprintf (fp,
+ "\n/cclef { %% usage: x cclef\n"
+ " dup dup dup\n"
+ " cchalf gsave 0 24 translate 1 -1 scale cchalf\n"
+ " 6.5 sub 0 moveto 0 24 rlineto 3 0 rlineto 0 -24 rlineto fill\n"
+ " 1.8 sub 0 moveto 0 24 rlineto 0.8 setlinewidth stroke grestore …
+ "} bind def\n");
+
+ fprintf (fp, "\n/scclef { cclef } bind def\n");
+}
+
+/* ----- def_brace ------- */
+void def_brace (fp)
+FILE *fp;
+{
+ float p[8][2]={
+ {7.2,60}, {-7,39}, {17,17}, {-1,0},
+ {-1.4,0}, {13,13}, {-11,39}, {7,60} };
+
+ float q[8][2]={
+ {-3,0}, {2,0}, {4,1}, {5.5,5},
+ {5.9,4.7}, {4.7,1.2}, {3.2,-.4}, {-1,-1.2} };
+
+ float f1,f2;
+
+ f1 = 0.9;
+ f2 = 1.0;
+ fprintf (fp, "\n/bracehalf {\n");
+ add_mv (fp,f1,f2,p,0);
+ add_cv (fp,f1,f2,p,1,1);
+ add_sg (fp,f1,f2,p,4,1);
+ add_cv (fp,f1,f2,p,5,1);
+ fprintf (fp, " fill\n} bind def\n");
+
+ fprintf (fp,
+ "\n/brace { %% usage: scale x0 y0 brace\n"
+ " 3 copy moveto gsave 1 exch scale bracehalf grestore\n"
+ " moveto gsave neg 1 exch scale bracehalf grestore\n"
+ "} bind def\n");
+
+ f1 = 1.0;
+ f2 = 1.0;
+ fprintf (fp, "\n/brackhead {\n");
+ add_mv (fp,f1,f2,q,0);
+ add_cv (fp,f1,f2,q,1,1);
+ add_sg (fp,f1,f2,q,4,1);
+ add_cv (fp,f1,f2,q,5,1);
+ fprintf (fp, " fill\n} bind def\n");
+
+ fprintf (fp,
+ "\n/bracket { %% usage: h x0 y0 bracket\n"
+ " 3 copy moveto 0 exch rmoveto brackhead\n"
+ " 3 copy moveto pop gsave 1 -1 scale brackhead grestore \n"
+ " moveto -3 0 rlineto 0 exch rlineto 3 0 rlineto fill\n"
+ "} bind def \n");
+
+}
+
+
+/* ----- def_staff ------- */
+void def_staff (fp)
+FILE *fp;
+{
+ fprintf (fp,
+ "\n/staff { %% usage: l staff - draw staff\n"
+ " gsave 0.5 setlinewidth 0 0 moveto\n"
+ " dup 0 rlineto dup neg 6 rmoveto\n"
+ " dup 0 rlineto dup neg 6 rmoveto\n"
+ " dup 0 rlineto dup neg 6 rmoveto\n"
+ " dup 0 rlineto dup neg 6 rmoveto\n"
+ " dup 0 rlineto dup neg 6 rmoveto\n"
+ " pop stroke grestore\n"
+ "} bind def\n");
+}
+
+/* ----- def_sep ------- */
+void def_sep (fp)
+FILE *fp;
+{
+ fprintf (fp,
+ "\n/sep0 { %% usage: x1 x2 sep0 - hline separator \n"
+ " 0 moveto 0 lineto stroke\n"
+ "} bind def\n");
+}
+
+/* ----- define_symbols: write postscript macros to file ------ */
+void define_symbols (fp)
+FILE *fp;
+{
+
+ def_misc (fp);
+ def_tclef (fp);
+ def_bclef (fp);
+ def_cclef (fp);
+ def_hd1 (fp);
+ def_hd2 (fp);
+ def_hd3 (fp);
+ def_stems (fp);
+ def_beam (fp);
+ def_sl (fp);
+ def_dot (fp);
+ def_deco (fp);
+ def_deco1 (fp);
+ def_hl (fp);
+ def_flags1 (fp);
+ def_flags2 (fp);
+ def_xflags (fp);
+ def_acc (fp);
+ def_gchord (fp);
+ def_rests (fp);
+ def_bars (fp);
+ def_ends (fp);
+ def_gnote (fp);
+ def_csg (fp);
+ def_sep (fp);
+ def_tsig (fp);
+ def_staff (fp);
+ def_brace (fp);
+ def_typeset(fp);
+
+}
+
+
diff --git a/trio.abc b/trio.abc
@@ -0,0 +1,44 @@
+%%indent 45pt
+%%leftmargin 1.8cm
+%%voicefont Times-Roman 12
+%%titlecaps
+%%titlefont Times-Roman 24
+%%composerfont Times-Roman 12
+%%staffwidth 18.5cm
+% scale 0.65
+%%musicspace 0.5cm
+%%tempofont Times-Roman
+%%staves 1 2 3
+
+
+X:1
+T: Sonata I
+C: J.S. Bach
+M: C
+Q:"Adagio"
+L: 1/8
+K:C
+V:1 clef=treble name="Violino I" sname="Vl. I"
+V:2 clef=treble name="Violino II" sname="Vl. II" space=+10
+V:3 clef=bass name="Violoncello\\<Vla. da Gamba>" sname="Vc."
+[V:1] g8-|gf/e/ {e}f>g (a/f/d/f/) (A//=B//A//B//TB3//A///B///)|
+[V:2] z8 | z8 |
+[V:3] z cec gGBG | Aa- a/_b/a/g/ f3 g/f/ |
+%
+[V:1] c/gf/ E/ed/ c/c'b/ A/ag/ | ^f/e/d- d/(c/B/A/) G/(e/c/e/) Aa| d2-d/g/_b/a…
+[V:2] c8- | cB/A/ {A}B>c (e/c/A/c/) (E//^F//E//F//TF3//E///F///) | G/(D/G/A/) …
+[V:3] edcB AG^FE | D^FGg c3d/c/| _BG g2-gf/e/ f>g|
+%
+[V:1] Te/>d/e- e/(a/f/d/) TB/>A/B- B/(A//B//c/)d/| TG/>F/G- G/(c/A/F/) DTd/>c/…
+[V:2] dT=c/>=B/ c>f d>e AF-| FTE/>D/ Ec'/-a/ Tf/>e/f- f/d/g/f/ | Te/>d/e/g/- g…
+[V:3] aA a2-a^g a>b| c'c c'2-c'b/>a/ b2-| b>e ag fed=c-|
+%
+[V:1] G/gf/ E/ed/ c/c'b/ A/ag/|^f/a/g/f/ g2-g>e' f2-|f/e^d/ e2-e>c' =d2-|
+[V:2] DG, G/gf/ E/ed/ =c/c'B/|ad'- d'/c'/d'/e'/ Ta/>g/a- a/c'/b/^f/|(g//a//g//…
+[V:3] cB/G/ cC zgac- |cb/>a/ b>c' d'c'd'd| e^fga babB|
+%
+P:
+Q:"Alla breve"
+[V:1] [L:1/4] c4|B4|_B4|A2zd|=BGc2-|cd/e/ f/a/g/f/|e/d/c2B|e3^f|gG/A/Bc|
+[V:2] [L:1/4] zC/D/EF|GDG2-|GF/E/DE|FCF2-|FE/D/EF/G/|AFDB|cgG2-|GA/B/ c/e/d/c/…
+[V:3] [L:1/4] z4|z4|z4|z4|z4|z4|z4|z4|g4|
diff --git a/util.h b/util.h
@@ -0,0 +1,494 @@
+/*
+ * This file is part of abc2ps,
+ * Copyright (C) 1996,1997,1998 Michael Methfessel
+ * See file abc2ps.c for details.
+ */
+
+/* low-level utilities */
+
+
+/* ----- error warning ----- */
+void wng (msg, str)
+char msg[],str[];
+{
+ printf ("+++ %s%s\n", msg, str);
+}
+
+/* ----- error exit ----- */
+void rx (msg, str)
+char msg[],str[];
+{
+ printf ("\n+++ %s%s\n", msg, str);
+ exit (1);
+}
+
+void rx1 (msg, c)
+char msg[];
+char c;
+{
+ printf ("\n+++ %s%c\n", msg, c);
+ exit (1);
+}
+
+void rxi (msg, i)
+char msg[];
+int i;
+{
+ printf ("\n+++ %s%d\n", msg, i);
+ exit (1);
+}
+
+/* ----- bug: print message for internal error and maybe stop ----- */
+void bug (msg,fatal)
+char msg[];
+int fatal;
+{
+ printf ("\n\nThis cannot happen!");
+ if (strlen(msg)>0) printf ("\nInternal error: %s.\n", msg);
+ if (fatal) {
+ printf ("Emergency stop.\n\n");
+ exit (1);
+ }
+ else {
+ printf ("Trying to continue...\n\n");
+ }
+}
+
+/* ----- ranf(x1,x2): return random float between x1 and x2 --- */
+float ranf(x1,x2)
+float x1,x2;
+{
+ static int m=259200; /* generator constants */
+ static int a=421;
+ static int c=54773;
+ static int j=1; /* seed */
+ float r;
+
+ j=(j*a+c)%m;
+ r=x1+(x2-x1)*(double)j/(double)m;
+ return r;
+}
+
+
+/* ----- getline ----- */
+/*
+* Added by jc:
+* This routine reads a line from fp into buf, and trims away any
+* trailing whitespace. We are paranoid about whether isspace(c)
+* returns true for CR, so this routine should work even if the input
+* came from a DOS system.
+*/
+char * getline(buf,len,fp)
+ char* buf;
+ int len;
+ FILE* fp;
+{ char* rp;
+ int c, l;
+ if (rp = fgets(buf,len,fp)) {
+ l = strlen(buf);
+ while ((l > 0) && ((c = buf[l-1]) && isspace(c) || (c == '\r')…
+ buf[--l] = 0;
+ }
+ return rp;
+}
+
+
+/* ----- strip: remove leading and trailing blanks ----- */
+void strip (str1,str)
+char str[],str1[];
+{
+ int l,i,i1,i2;
+ l=strlen(str);
+
+ i1=0;
+ for (i=0; i<l; i++)
+ if ((str[i]!=' ') && (str[i]!='\n')) { i1=i; break; }
+ i2=0;
+ for (i=l-1; i>=0; i--)
+ if ((str[i]!=' ') && (str[i]!='\n')) { i2=i+1; break; }
+ for (i=i1;i<i2;i++) str1[i-i1]=str[i];
+ str1[i2-i1]=0;
+/* printf (" l=%d i1=%d i2=%d <%s> <%s>\n", l, i1, i2, str, str1);*/
+}
+
+
+/* ----- nwords: count words in string ----- */
+int nwords (str)
+char *str;
+{
+ int w,k;
+ char *c;
+ c=str;
+ w=0;
+ for(k=0;k<=50;k++) {
+ while (*c==' ') c++;
+ if (*c=='\0') break;
+ w++;
+ while ((*c!=' ') && (*c!='\0')) c++;
+ if (*c=='\0') break;
+ }
+ return w;
+}
+
+
+
+/* ----- getword: return n-th word from string ---- */
+int getword (iw,str,str1)
+int iw;
+char *str,*str1;
+{
+ int w,k;
+ char *c,*cc;
+ if (iw<0) { *str1='\0'; return 0;}
+ c=str;
+ w=0;
+ for(k=0;k<=50;k++) {
+ while (*c==' ') c++;
+ if (*c=='\0') break;
+ if (w==iw) {
+ cc=str1;
+ while ((*c!=' ')&&(*c!='\0')) { *cc=*c; c++; cc++; }
+ *cc='\0';
+ return 1;
+ }
+ w++;
+ while ((*c!=' ') && (*c!='\0')) c++;
+ if (*c=='\0') break;
+ }
+ *str1='\0';
+ return 0;
+}
+
+
+/* ----- abbrev: check for valid abbreviation ----- */
+int abbrev (str,ab,nchar)
+char str[],ab[];
+int nchar;
+{
+ int i,nc;
+ if (strlen(str) > strlen(ab)) return 0;
+ nc=strlen(str);
+ if (nc<nchar) nc=nchar;
+ for (i=0;i<nc;i++) if (str[i] != ab[i]) return 0;
+ return 1;
+}
+
+/* ----- isdig: checks char for digit ----- */
+int isdig (c)
+char c;
+{
+ if (c == '\0') return 0;
+ if (strchr("0123456789",c)) return 1;
+ return 0;
+}
+
+/* ----- strext: set extension on a file identifier ----- */
+/* force=1 forces change even if fid already has an extension */
+/* force=0 does not change the extension if there already is one */
+void strext (fid1, fid, ext, force)
+char fid[],ext[],fid1[];
+int force;
+{
+ int i,l;
+ char *p,*q;
+
+ strcpy (fid1, fid);
+ l=strlen(fid1);
+ p=fid1;
+ for (i=0;i<l;i++)
+ if (fid1[i]=='/') p=fid1+i;
+
+ if (!force) {
+ q=strchr(p,'.');
+ if (q && (q!=fid1+strlen(fid1)-1)) return;
+ }
+ if (!strchr(p,'.')) strcat (fid1,".");
+ q=strchr(p,'.');
+ if (strlen(ext)>0) q++;
+ *q = 0;
+ strcat(fid1,ext);
+
+}
+
+/* ----- cutext: cut off extension on a file identifier ----- */
+void cutext (fid)
+char fid[];
+{
+ int i,l;
+
+ l=strlen(fid);
+ for (i=0;i<l;i++)
+ if (fid[i]=='.') fid[i]='\0';
+}
+
+/* ----- getext: get extension on a file identifier ----- */
+void getext (fid,ext)
+char fid[],ext[];
+{
+ int i,l,k;
+
+ l=strlen(fid);
+ k=l-1;
+ for (i=0;i<l;i++)
+ if (fid[i]=='.') k=i;
+
+ for (i=k+1;i<l;i++)
+ ext[i-k-1]=fid[i];
+ ext[l-k-1]='\0';
+
+}
+
+
+/* ----- sscanu ----- */
+float scan_u(str)
+char str[];
+{
+ char unit[81];
+ float a,b;
+
+ strcpy(unit,"pt");
+ sscanf(str,"%f%s", &a, unit);
+
+ if (!strcmp(unit,"cm")) b=a*CM;
+ else if (!strcmp(unit,"in")) b=a*IN;
+ else if (!strcmp(unit,"pt")) b=a*PT;
+ else {
+ printf ("+++ Unknown unit \"%s\" in: %s\n",unit,str);
+ exit (3);
+ }
+ return b;
+}
+
+
+/* ----- match ------- */
+int match (str, pat)
+char str[], pat[];
+{
+ char *p,*s;
+ p=pat;
+ s=str;
+
+ if (strlen(pat)==0) return 1;
+
+ while (*p != 0) {
+
+ if (*p == '*') { /* found wildcard '*' in pattern */
+ p++;
+ while (*p == '*') p++;
+ if (*p == 0) return 1; /* trailing '*' matches all */
+ for (;;) { /* find match to char after '*' */
+ if (*s == 0) return 0;
+ if ((*s == *p) || (*p == '+'))
+ if (match(s+1,p+1)) return 1; /* ok if rest matches */
+ s++;
+ }
+ }
+
+ else { /* no wildcard -- char must match */
+ if (*s == 0) return 0;
+ if ((*p != *s) && (*p != '+')) return 0;
+ s++;
+ }
+ p++;
+ }
+
+ if (*s != 0) return 0; /* pattern but not string exhausted */
+ return 1;
+}
+
+/* ----- isblank: check for blank string ---- */
+int isblank (str)
+char str[];
+{
+ int i;
+ for (i=0;i<strlen(str);i++) if (str[i] != ' ') return 0;
+ return 1;
+}
+
+/* ----- cap_str: capitalize a string ----- */
+void cap_str(str)
+char str[];
+{
+ char *c;
+ c=str;
+ while (*c!='\0') {
+ if (*c=='a') *c='A';
+ else if (*c=='b') *c='B';
+ else if (*c=='c') *c='C';
+ else if (*c=='d') *c='D';
+ else if (*c=='e') *c='E';
+ else if (*c=='f') *c='F';
+ else if (*c=='g') *c='G';
+ else if (*c=='h') *c='H';
+ else if (*c=='i') *c='I';
+ else if (*c=='j') *c='J';
+ else if (*c=='k') *c='K';
+ else if (*c=='l') *c='L';
+ else if (*c=='m') *c='M';
+ else if (*c=='n') *c='N';
+ else if (*c=='o') *c='O';
+ else if (*c=='p') *c='P';
+ else if (*c=='q') *c='Q';
+ else if (*c=='r') *c='R';
+ else if (*c=='s') *c='S';
+ else if (*c=='t') *c='T';
+ else if (*c=='u') *c='U';
+ else if (*c=='v') *c='V';
+ else if (*c=='w') *c='W';
+ else if (*c=='x') *c='X';
+ else if (*c=='y') *c='Y';
+ else if (*c=='z') *c='Z';
+ c++;
+ }
+}
+
+
+/* ----- cwid ----- */
+/* These are char widths for Times-Roman */
+float cwid(c)
+char c;
+{
+ float w;
+ if (c=='a') w=44.4;
+ else if (c=='b') w=50.0;
+ else if (c=='c') w=44.4;
+ else if (c=='d') w=50.0;
+ else if (c=='e') w=44.4;
+ else if (c=='f') w=33.3;
+ else if (c=='g') w=50.0;
+ else if (c=='h') w=50.0;
+ else if (c=='i') w=27.8;
+ else if (c=='j') w=27.8;
+ else if (c=='k') w=50.0;
+ else if (c=='l') w=27.8;
+ else if (c=='m') w=77.8;
+ else if (c=='n') w=50.0;
+ else if (c=='o') w=50.0;
+ else if (c=='p') w=50.0;
+ else if (c=='q') w=50.0;
+ else if (c=='r') w=33.3;
+ else if (c=='s') w=38.9;
+ else if (c=='t') w=27.8;
+ else if (c=='u') w=50.0;
+ else if (c=='v') w=50.0;
+ else if (c=='w') w=72.2;
+ else if (c=='x') w=50.0;
+ else if (c=='y') w=50.0;
+ else if (c=='z') w=44.4;
+
+ else if (c=='A') w=72.2;
+ else if (c=='B') w=66.7;
+ else if (c=='C') w=66.7;
+ else if (c=='D') w=72.2;
+ else if (c=='E') w=61.1;
+ else if (c=='F') w=55.6;
+ else if (c=='G') w=72.2;
+ else if (c=='H') w=72.2;
+ else if (c=='I') w=33.3;
+ else if (c=='J') w=38.9;
+ else if (c=='K') w=72.2;
+ else if (c=='L') w=61.1;
+ else if (c=='M') w=88.9;
+ else if (c=='N') w=72.2;
+ else if (c=='O') w=72.2;
+ else if (c=='P') w=55.6;
+ else if (c=='Q') w=72.2;
+ else if (c=='R') w=66.7;
+ else if (c=='S') w=55.6;
+ else if (c=='T') w=61.1;
+ else if (c=='U') w=72.2;
+ else if (c=='V') w=72.2;
+ else if (c=='W') w=94.4;
+ else if (c=='X') w=72.2;
+ else if (c=='Y') w=72.2;
+ else if (c=='Z') w=61.1;
+
+ else if (c=='0') w=50.0;
+ else if (c=='1') w=50.0;
+ else if (c=='2') w=50.0;
+ else if (c=='3') w=50.0;
+ else if (c=='4') w=50.0;
+ else if (c=='5') w=50.0;
+ else if (c=='6') w=50.0;
+ else if (c=='7') w=50.0;
+ else if (c=='8') w=50.0;
+ else if (c=='9') w=50.0;
+
+ else if (c=='~') w=54.1;
+ else if (c=='!') w=33.3;
+ else if (c=='@') w=92.1;
+ else if (c=='#') w=50.0;
+ else if (c=='$') w=50.0;
+ else if (c=='%') w=83.3;
+ else if (c=='^') w=46.9;
+ else if (c=='&') w=77.8;
+ else if (c=='*') w=50.0;
+ else if (c=='(') w=33.3;
+ else if (c==')') w=33.3;
+/*| else if (c=='-') w=33.3; |*/
+ else if (c=='-') w=40.0;
+ else if (c=='_') w=50.0;
+ else if (c=='+') w=56.4;
+ else if (c=='=') w=55.0;
+ else if (c=='[') w=33.3;
+ else if (c==']') w=33.3;
+ else if (c=='{') w=48.0;
+ else if (c=='}') w=48.0;
+ else if (c=='|') w=20.0;
+ else if (c==':') w=27.8;
+ else if (c==';') w=27.8;
+ else if (c=='.') w=27.8;
+ else if (c==',') w=27.8;
+ else if (c=='\\') w=27.8;
+ else if (c=='\'') w=33.3;
+ else if (c=='\"') w=40.8;
+ else if (c=='<') w=56.4;
+ else if (c=='>') w=56.4;
+ else if (c=='?') w=44.4;
+ else if (c=='/') w=27.8;
+ else if (c=='`') w=33.3;
+ else if (c==' ') w=25.0;
+ else w=50.0;
+ return w/100.0;
+}
+
+
+/* ----- get_file_size ------- */
+/* version using standard function stat */
+#include <sys/stat.h>
+int get_file_size (fname)
+char fname[];
+{
+ int m,rc;
+ struct stat statbuf;
+ rc = stat(fname,&statbuf);
+ if (rc == -1) {
+ printf ("Unsuccessful call to stat for file %s\n", fname);
+ return -1;
+ }
+ m=statbuf.st_size;
+ return m;
+}
+
+/* version which counts bytes by hand */
+int get_file_size1 (fname)
+char fname[];
+{
+ int m,i;
+ FILE *fp;
+
+ if ((fp = fopen (fname,"r")) == NULL) {
+ printf ("Cannot open file to determine size: %s", fname);
+ return -1;
+ }
+
+ m=0;
+ i=getc(fp);
+ while (i != EOF) {
+ m++;
+ i=getc(fp);
+ }
+ fclose (fp);
+ return m;
+}
+
diff --git a/voices.abc b/voices.abc
@@ -0,0 +1,151 @@
+%%indent 1cm
+
+X:1
+T: Fairfield Fancy % -----
+C: Trad.
+M: 2/4
+%%sysstaffsep 35
+K:Am
+V:1 name="Intro" snm="In"
+ME2>.E2 .A2.A2 | .c2.c2 e4 | edef edcB | A2E2 {Ec}+E2c2a2+ EE |
+T: % note: force new indentation with empty title field
+V:1 name="Melody" snm="Mel."
+|: "Am"EAA^G A2 AB | c2e2 f2e2 | "G"DGGF G2 GA | B2d2 e2d2|
+"Am"EAA^G A2 AB | cBAc edce | "C"gage "Am"dcAc |1 ecdB A2 EE :|2ecdB A2 ee|
+|: "Am"ea^gb a2 ab | c'aba c'aba | "G"dgfa g2 ga | bgag bgag |
+"Am"ea^gb a2 ab | c'aba c'aba | "C"gage "Am"dcAc |1 ecdB A2 ee :|2 ecdB A2 EE||
+V:acc_1 name="Accomp I" snm="Acc. II"
+L:1/4
+|: (A,C | EA) | (GD | B,G,) | (A, C | E A) | c/G/ A/E/- |1 E/D/ C :|2 E/D/ C |
+|: A2- | A z | G2- | G z |A2- | A z | c/G/ A/E/- |1 E/D/ C :|2 E/D/ C ||
+V:acc_2 name="Accomp II" snm="Acc. II"
+L:1/4
+|: A z |(A/c/ d/c/ |B) z |(G/B/ c/B/ |A) z|A c| e/e/ A|1(E A):|2 (E A)|
+|: (Ac | ea) | (gd | BG) | (Ac | ea) | (ge |1 cA) :|2 cA) ||
+
+
+
+X:2
+T: Tzadik Katamar % -----
+%%indent 0
+C: from Israel
+M: C|
+L: 1/4
+K: C
+V:1 brk=2
+C | "C"E<GG>A | "Am"E<DC>E | "Dm7"FFF<G | "G"D4 | "C"E<GG>A | "Em"B<EE>E |
+ "F"FGA<B | "G"G4 | "F"ABcA | "Em"B<GB>E | "Dm"FGA<B | "C"G4 |
+ "Dm"DEFD | "Em"E<G B2 | "F"ABcA | "G7"B3 G || "C"c3 c | "E7"B3 B |
+ "F"AAA<B | "C"G2 "Am"E2 | "F"FFFG | "C"E<D "Am"C>E | "Dm"FFFD | "G"G<A B>G |
+ "C"c3 c | "E7"B3 B | "F"AAAB | "C"G2 "Am"E2 | "Dm7"FFFG | "C"E<D "Am"C>E |\
+ "Dm"DF "G"A<B | "C"c4 ||
+V:2 gch=0
+C | "C"C<EE>E | "Am"E<FE>E | "Dm7"D2A,2 | "G"B,> G,A,B, |\
+ "C"C<EE>E | "Em"E<B,B,>B, |
+"F"C4 | "G"B,>G,A,B, | "F"FGGF | "Em"E<GG>G | "Dm"FGGF | "C"E4 |
+"Dm"A2FD | "Em"G2E2 | "F"C2F2 | "G7"D2ED || "C"E4 | "E7"D4 |
+"F"C2B,A, | "C"G,2 "Am"C2 | "F"A,C2C | "C"G, " Am"C2C |\
+ "Dm"A,C2C | "G"B,2 CD |
+"C"E4 | "E7"D4 | "F"C2B,A, | "C"G,2 "Am"C2 | "Dm7"A,C2C |\
+ "C"G, " Am"C2C |"Dm"A,2 "G"B,D | "C"E4 ||
+
+
+X:3
+T: Erev Ba % ---
+C: from Israel
+M: C|
+L: 1/4
+K:G
+V:1
+"G"dgf g/b/ | "Am"a3z | "D7"ab c'/d'/ b | "G"b3z | dgf g/b/ | "Am"a3z |
+"D7"ab c'/d'/ b | "B7"b3z | "C"ceg>g | f/g/f/e/ e2 | "Am"Ace>e | "D"d>c B/A/G/…
+"Em"G2 E2 | "Am"A2 "D7"A/B/ G | ("G"G4|G2) z2 | dgf g/b/ | "Am"a3z |
+"D7"ab c'/d'/ b | "G"b3z | dgf g/b/ | "Am"a3z | "D7"ab c'/d'/ b | "B7"b3z |
+"C"ceg>g | f/g/ f/e/ e2 | "Am"Ace>e | "D"d>c B/A/G/F/ | "Em"G2 E2 | "Am"A2 "D7…
+"G"G>A B c/A/ | "G7"d>e =f/d/B/A/ [K:C] ||"C"G2z2| "Dm7"d/e/f/e/ d/c/B/A/ |\
+ "G7"G2z2 | "C"z/ G/c/B/ c/d/e/f/ |
+g g/a/ g2 | "Dm7"f/g/a/g/ f/e/d/c/ | "G7"B/c/d/c/ B/A/ G| "E"^G>B e/d/c/B/|\
+ "F"c2 a>a | g/a/g/f/ .f .e |
+"Dm"d2f>f | "G"e>d c/B/A/B/ | "Am"c/d/c/B/ A/G/F/E/ | "Dm"D/E/F/D/ "G7"G A/B/ …
+ "C"c3 e| .g.a.g e/d/ |
+GcBc/e/ | "Dm7"d3z | "G7"def/g/e| "C"e3z | GcBc/e/ | "Dm7"d3z |
+"G7"def/g/e| "E"e3z | "F"FAc>c| B/c/B/A/ A2| "Dm"DFA>A| "G"G>F E/D/C/E/ |
+"Am"c2A2 | "Dm"d2 "G7"d/e/c | ("C"c4|"Dm"c2) "G7"d/e/c| ("C"c4| c2) z2 |]
+%
+V:2 gch=0
+"G"z4 | "Am"z4 | "D7"z4 | "G"z4 | z4 | "Am"z4 |
+"D7"z4 | "B7"z4 | "C"z4 | z4 | "Am"z4 | "D"z4 |
+"Em"G2Bd | "Am"c2 "D7"c/d/ B | "G"B>ABd | B>A G/A/ B| d2 z2 | "Am"A/B/c/B/ A/G…
+"D7"D2 z2 | "G"z/D/G/F/ G/A/B/c/ | d d/e/ d2| "Am"c/d/e/d/ c/B/A/G/ |\
+ "D7"F/G/A/G/ F/E/D/C/ | "B7"^D/B,/D/F/ B/A/G/F/ |
+"C"c2 e>e | d/e/d/c/ cB| "Am"A2 c>c| "D"B>A G/F/E/F/ |\
+ "Em"G/A/G/F/ E/D/C/E/ | "Am"A/B/c/^c/ "D7"d e/f/ |
+("G"g4|"G7"g2)z2 [K:C] || "C"GcB c/e/ | "Dm7"d3z | "G7"de f/g/ e| "C"e3z |
+GcB c/e/ | "Dm7"d3z | "G7"de f/g/ e| "E"e3z | "F"FAc>c | B/c/B/A/ Az |
+"Dm"DFA>A | "G"G>F E/D/C/D/ | "Am"c2 A2 | "Dm"d2 "G7"d/e/c | ("C"c4|c2) z2 |
+Gede/g/ | "Dm7"f>e f/e/d/c/ | "G7"Bcd/e/c| "C"c c/B/ c/B/c/d/ |\
+ e e/f/ ee | "Dm7"f>e f/e/d/c/ |
+"G7"Bc d/e/ c | "E"B>A ^G/A/B/G/ | "F"F2 A2 | c2 FE | "Dm"D2 F2 | "G"B2 e2|
+"Am"e2c2 | "Dm"f2 "G7"f/g/ e | ("C"e4| "Dm"e2) "G7"f/g/ e | ("C"e4|e2) z2 |]
+
+
+X: 1
+T: Helle Wasser % --- we squeeze this onto one page
+%%musicspace 0cm
+%%topmargin 0.5cm
+%%sysstaffsep 35.0pt
+%%systemsep 55.0pt
+%%titlefont Helvetica 16
+%%subtitlefont Helvetica 12
+%%composerfont Helvetica 10
+%%scale 0.65
+O: Finnland
+M: 6/8
+L: 1/8
+K: Am
+%V:sop name="Sopran" sname="S." bracket=3
+V:sop nm="Sopran" snm="S." brk=3
+"Am"e3-e2 f|e2 c B2 c |"Dm"d3 d3- |d3z3| \
+w: Hel - le Was-ser dun-kle W\"al-der
+"G7"d e2-e3|d-BG A2 B| \\ "Am"A6- |A3z3| \
+w: und die* Sehn - sucht sind mein Haus _
+"F"g a2-a3|"C"g2 e d2 e|"Dm"f3 f3-|f3z3| \\
+w: Komm zu* mir und tei-le mit mir_
+"G7"f g2-g3|f2 d c2 d| "C"e6|"E7"-e3 z2z| \
+w: Tag und* W\"ar-me, K\"al-te auch._
+"Am"a3-a2 g|g g2 e2 d| "Dm"f6| \\ z3 a3| \
+w: Wo* wir ge-hen bl\"uht das Laub, sind |
+"G7"g3-g2 g|e2 d c2 d|"C" e6|"C7"-e3 z2 e| \
+w: We - ge k\"ur-zer Win-ter gr\"un._ In
+"F"f3-f2 g| \\ "Fm"f2 f c2 d|"C"e3-d3|"A7"^c3 z2z| \
+w: dei - nen Au-gen w\"achst mein Le - ben,
+"Dm"d3-d2 e|"G7"e f2 e2 d|"C"c6-|"E7"B3z3 :|
+w: Dein* Ge\- sicht darf nie ver\- gehn.
+%
+V:alto staves=1 name="Alto" sname="A."
+z6 | z6|f3-f2 f|f2 g f2 d|
+B3 B3|z dd cdd|ccc-c3-|c3z3|
+e f2-f3|e2 c B2 c|d3 d3-|d3z3|
+d e2-e3|d2 B A2 B|c6|B6|
+z6|z3 A2 A|d d2 d2 d|d3 f3|
+f3-f2 d| c2 B A2 B|c3-c2 c|B3 _B3|
+A c2-c3|c6|c2 B _B3|A3 z2z|
+z3 c2 c|B B2 G2 G|G6-|^G3z3 :|
+%
+V:tenor name="Tenor" sname="T."
+z6 | z6 |z3 A3|-A3-A2 G|
+G3 G3|-G3 F2 E|E3 E3|z AA A2 B|
+ccc-c3|-c3 z cc|c3 z cc|c3 c3|
+B3 z2z|z GG G2 G|A2 G G3|^G6|
+z6|z6|z3 A2 A|A A2 c2 c|
+B3-B2 G|G2 G G2 G|A2 G G3|-G3 G3|
+A3-A2 A|_A2 A A2 A|G6|G6|
+F3-F2 G|G A2 G2 F|E6-|E3z3 :|
+
+
+
+
+
+
+
+
You are viewing proxied material from vernunftzentrum.de. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.