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(<ime); | |
+ strcpy (tstr, ctime(<ime)); | |
+ 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(<ime); | |
+ strcpy (tstr, ctime(<ime)); | |
+ 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 :| | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ |