* Documentation/user/lilypond-book.itely: Update.
* make/ly-rules.make: Update lilypond-book commands.
* Documentation/user/GNUmakefile: Update makeinfo commands,
lilypond-book flags.
* scripts/lilypond-book.py: Rewrite (was: filter-lilypond-book.ly).
* scripts/old-lilypond-book.py: New file (was: lilypond-book.ly).
* scripts/filter-lilypond-book.py: Remove.
+2004-02-05 Jan Nieuwenhuizen <janneke@gnu.org>
+
+ * Documentation/topdocs/NEWS.texi: Add item about lilypond-book.
+
+ * Documentation/user/lilypond-book.itely: Update.
+
+ * make/ly-rules.make: Update lilypond-book commands.
+
+ * Documentation/user/GNUmakefile: Update makeinfo commands,
+ lilypond-book flags.
+
+ * scripts/lilypond-book.py: Rewrite (was: filter-lilypond-book.ly).
+
+ * scripts/old-lilypond-book.py: New file (was: lilypond-book.ly).
+
+ * scripts/filter-lilypond-book.py: Remove.
+
+ * Documentation/user/*tely: Update options for new lilypond-book.
+
+ * tex/texinfo.tex: New file; from texinfo CVS. This fixes build
+ with @macros in @includes.
+
2004-02-05 Han-Wen Nienhuys <hanwen@xs4all.nl>
* lily/drum-note-performer.cc: new file: perform drum notes.
@end ignore
@itemize @bullet
+
+@item The lilypond-book script has been rewritten. It now supports
+running convert-ly on the lilypond snippets like so:
+@example
+ lilypond-book --filter='convert-ly --from=2.0.0' my-book.tely
+@end example
+It is also twice as short and thrice as fast. The special construct
+@code{mbinclude} has been removed, plain @code{@@include} or
+@code{\\input} can be used now.
+
@item The @code{Lyrics} context has been removed. Lyrics should only
be constructed in @code{LyricsVoice}.
OMF_FILES += $(outdir)/lilypond-internals.html.omf
LOCALSTEPMAKE_TEMPLATES=lilypond ly
-LILYPOND_BOOK_FLAGS=--extra-options '-e "(ly:set-option (quote internal-type-checking) \#t)"'
+LILYPOND_BOOK_FLAGS = --process="lilypond-bin -I $(srcdir)/input/test -e '(ly:set-option (quote internal-type-checking) \#t)'"
include $(depth)/make/stepmake.make
-# Ugh,ugh.
-# emacs cannot fix the menu structure when @mbinclude is used
-# lilypond.tely uses mbinclude
-TEXINFO_SOURCES := $(filter-out lilypond.tely, $(TEXINFO_SOURCES))
-
dvi: $(DVI_FILES)
ps: $(PS_FILES)
# $(outdir)/%/%.html: $(outdir)/%.texi
$(outdir)/lilypond/lilypond.html: $(outdir)/lilypond.texi
mkdir -p $(dir $@)
- $(MAKEINFO) --output=$(outdir)/lilypond --html $<
- $(MAKEINFO) -I $(outdir) --output=$@ --html --no-split --no-headers $<
+ $(MAKEINFO) -I$(outdir) --output=$(outdir)/lilypond --html $<
+ $(MAKEINFO) -I$(outdir) --output=$@ --html --no-split --no-headers $<
-ln -f $(outdir)/*.png $(outdir)/*.ly $(outdir)/lilypond/
$(outdir)/lilypond-internals/lilypond-internals.html: $(outdir)/lilypond-internals.texi
mkdir -p $(dir $@)
$(MAKEINFO) --output=$(outdir)/lilypond-internals --html $<
- $(MAKEINFO) -I $(outdir) --output=$@ --html --no-split --no-headers $<
+ $(MAKEINFO) -I$(outdir) --output=$@ --html --no-split --no-headers $<
ifeq ($(SPLITTING_MAKEINFO),yes)
@item @code{1 2 8 16}
@tab durations
@tab
-@lilypond[relative 1, notime]
+@lilypond[relative=1,notime]
\property Staff.autoBeaming = ##f
\property Staff.Clef = \turnOff
c1 c2 c8 c16
@item @code{c4. c4..}
@tab augmentation dots
@tab
-@lilypond[relative 1, notime]
+@lilypond[relative=1,notime]
\property Staff.Clef = \turnOff
c4. c4..
@end lilypond
@item @code{c d e f g a b }
@tab scale
@tab
-@lilypond[relative 1, notime]
+@lilypond[relative=1,notime]
c d e f g a b
@end lilypond
@item @code{fis bes}
@tab alteration
@tab
-@lilypond[relative 0, notime]
+@lilypond[relative,notime]
fis bes
@end lilypond
@item @code{r4 r8}
@tab rest
@tab
-@lilypond[relative 1, notime]
+@lilypond[relative=1,notime]
\property Staff.Clef = \turnOff
r4 r8
@end lilypond
@item @code{d ~ d}
@tab tie
@tab
-@lilypond[relative 1, notime]
+@lilypond[relative=1,notime]
\property Score.timing = ##f
\property Staff.autoBeaming = ##f
d ~ d
@item @var{note}@code{'}
@tab raise octave
@tab
-@lilypond[relative 1, notime]
+@lilypond[relative=1,notime]
\property Score.timing = ##f
\property Staff.autoBeaming = ##f
a a'
@item @var{note}@code{,}
@tab lower octave
@tab
-@lilypond[relative 1, notime]
+@lilypond[relative=1,notime]
\property Score.timing = ##f
\property Staff.autoBeaming = ##f
c c,
@item @code{c( d e)}
@tab slur
@tab
-@lilypond[fragment, relative 1]
+@lilypond[fragment,relative=1]
\property Score.timing = ##f
\property Staff.TimeSignature = \turnOff
\property Staff.autoBeaming = ##f
@item @code{c\( c( d) e\)}
@tab phrasing slur
@tab
-@lilypond[fragment, relative 1]
+@lilypond[fragment,relative=1]
\property Score.timing = ##f
\property Staff.TimeSignature = \turnOff
\property Staff.autoBeaming = ##f
@item @code{a8[ b]}
@tab beam
@tab
-@lilypond[fragment, relative 1]
+@lilypond[fragment,relative=1]
\property Score.timing = ##f
\property Staff.TimeSignature = \turnOff
\property Staff.autoBeaming = ##f
@item @code{c-> c-.}
@tab articulations
@tab
-@lilypond[fragment, relative 1]
+@lilypond[fragment,relative=1]
\property Staff.TimeSignature = \turnOff
c-> c-.
@end lilypond
@item @code{c\mf c\sfz}
@tab dynamics
@tab
-@lilypond[fragment, relative 1]
+@lilypond[fragment,relative=1]
\property Staff.TimeSignature = \turnOff
c\mf c\sfz
@end lilypond
@item @code{a\< b\!}
@tab crescendo
@tab
-@lilypond[fragment, relative 1]
+@lilypond[fragment,relative=1]
\property Score.timing = ##f
\property Staff.TimeSignature = \turnOff
\property Staff.autoBeaming = ##f
@item @code{a\> b\!}
@tab decrescendo
@tab
-@lilypond[fragment, relative 1]
+@lilypond[fragment,relative=1]
\property Score.timing = ##f
\property Staff.TimeSignature = \turnOff
\property Staff.autoBeaming = ##f
@item @code{< >}
@tab chord
@tab
-@lilypond[fragment, relative 1]
+@lilypond[fragment,relative=1]
<c e>
@end lilypond
@item @code{\partial 8}
@tab upstep
@tab
-@lilypond[fragment,relative 1]
+@lilypond[fragment,relative=1]
\partial 8
f8 c2 d e
@end lilypond
@item @code{\times 2/3 @{f g a@}}
@tab triplets
@tab
-@lilypond[relative 1,fragment]
+@lilypond[relative=1,fragment]
\times 2/3 { f8 g a }
@end lilypond
@item @code{\grace}
@tab grace notes
@tab
-@lilypond[relative 1,fragment]
+@lilypond[relative=1,fragment]
\context Voice { \grace b16 c4 }
@end lilypond
@item @code{twin -- kle}
@tab lyric hyphen
@tab
-@lilypond[fragment,relative 1]
+@lilypond[fragment,relative=1]
\notes { g'4 g }
\lyricsto "" \new LyricsVoice \lyrics { twin -- kle }
@end lilypond
@item @code{\chords @{ c:dim f:maj7 @}}
@tab chords
@tab
-@lilypond[fragment,relative 1]
+@lilypond[fragment,relative=1]
\chords { c:dim f:maj7 }
@end lilypond
@item @code{\context ChordNames}
@tab printing chord names
@tab
-@lilypond[fragment,relative 1]
+@lilypond[fragment,relative=1]
\context ChordNames \chords { c:dim f:maj7 }
@end lilypond
@item @code{<<@{e f@} \\@{c d@}>>}
@tab polyphony
@tab
-@lilypond[fragment,relative 2]
+@lilypond[fragment,relative=2]
\context Staff <<{e f} \\ {c d}>>
@end lilypond
of type @var{contexttype} (with name @var{contextname} if specified).
If no such context exists, it will be created:
-@lilypond[verbatim,singleline]
+@lilypond[verbatim,raggedright]
\score {
\notes \relative c'' {
c4 <<d4 \context Staff = "another" e4>> f
context. The notes contained therein inherit the @code{goUp} context
from the enclosing music expression.
-@lilypond[verbatim,singleline]
+@lilypond[verbatim,raggedright]
\notes \context Voice = goUp { c'4 d' e' }
@end lilypond
Second, contexts are created automatically to be able to interpret the
music expressions. Consider the following example:
-@lilypond[verbatim, singleline]
+@lilypond[verbatim,raggedright]
\score { \notes { c'4-( d' e'-) } }
@end lilypond
from the Staff context. The result is a staff without a clef, where
the central C is at its default position, the center line:
-@lilypond[verbatim,singleline]
+@lilypond[verbatim,raggedright]
\score {
\notes {
c'4 f'4
An example is a function that reverses the order of elements in
its argument:
-@lilypond[verbatim,singleline]
+@lilypond[verbatim,raggedright]
#(define (rev-music-1 m)
(ly:set-mus-property! m 'elements (reverse
(ly:get-mus-property m 'elements)))
Music is specified like this:
@example
-@@lilypond[options, go, here]
+@@lilypond[options,go,here]
YOUR LILYPOND CODE
@@end lilypond
-@@lilypond[options, go, here]@{ YOUR LILYPOND CODE @}
-@@lilypondfile[options, go, here]@{@var{filename}@}
+@@lilypond[options,go,here]@{ YOUR LILYPOND CODE @}
+@@lilypondfile[options,go,here]@{@var{filename}@}
@end example
When lilypond-book is run on it, this results in a texinfo file. We
show two simple examples here. First a complete block:
@example
-@@lilypond[26pt]
+@@lilypond[staffsize=26]
c' d' e' f' g'2 g'
@@end lilypond
@end example
Then the short version:
@example
-@@lilypond[11pt]@{<c' e' g'>@}
+@@lilypond[staffsize=11]@{<c' e' g'>@}
@end example
@noindent
produces
-@lilypond[11pt]{ <c' e' g'> }
-
-@command{lilypond-book} knows the default margins and a few paper
-sizes. One of these commands should be in the beginning of the document:
-
-@itemize @bullet
-@item @code{@@afourpaper}
-@item @code{@@afourlatex}
-@item @code{@@afourwide}
-@item @code{@@smallbook}
-@end itemize
-
-@noindent
-@code{@@pagesizes} are not yet supported.
+@lilypond[staffsize=11]{ <c' e' g'> }
When producing texinfo, lilypond-book also generates bitmaps of the
music, so you can make a HTML document with embedded music.
-
@c @TeX{} in node name seems to barf
@node Integrating LaTeX and music
@section Integrating LaTeX and music
For La@TeX{}, music is entered using
@example
-\begin[options, go, here]@{lilypond@}
+\begin[options,go,here]@{lilypond@}
YOUR LILYPOND CODE
\end@{lilypond@}
@end example
@example
-\lilypondfile[options, go,here]@{@var{filename}@}
+\lilypondfile[options,go,here]@{@var{filename}@}
@end example
@noindent
We show some examples here:
@example
-\begin[26pt]@{lilypond@}
+\begin[staffsize=26]@{lilypond@}
c' d' e' f' g'2 g'2
\end@{lilypond@}
@end example
@noindent
produces
-@lilypond[26pt]
+@lilypond[staffsize=26]
c' d' e' f' g'2 g'2
@end lilypond
Then the short version:
@example
-\lilypond[11pt]@{<c' e' g'>@}
+\lilypond[staffsize=11]@{<c' e' g'>@}
@end example
@noindent
produces
-@lilypond[11pt]{<c' e' g'>}
+@lilypond[staffsize=11]{<c' e' g'>}
The linewidth of the music will be adjust by examining the commands in
the document preamble, the part of the document before
the music fragments are adjusted to the text width.
After @code{\begin@{document@}}, the column changing commands
-@code{\onecolumn} , @code{\twocolumn} commands and the
-@code{multicols} environment from the multicol package are also
-interpreted.
+@code{\onecolumn}, @code{\twocolumn} commands
+@ignore
+and the
+@code{multicols} environment from the multicol package
+@end ignore
+are also interpreted.
The titling from the @code{\header} section of the fragments can be
imported by adding the following to the top of the La@TeX{} file:
Music is entered using
@example
-<lilypond relative1 verbatim>
+<lilypond relative=1 verbatim>
\key c \minor r8 c16 b c8 g as c16 b c8 d | g,4
</lilypond>
@end example
music fragments:
@example
-<lilypond relative1 verbatim>
+<lilypond relative=1 verbatim>
\key c \minor r8 c16 b c8 g as c16 b c8 d | g,4
</lilypond>
@end example
-@lilypond[relative1]
+@lilypond[relative=1]
\key c \minor r8 c16 b c8 g as c16 b c8 d | g,4
@end lilypond
@code{ @@lilypond@{ CONTENTS @} } and @code{ \lilypond@{ CONTENTS @} }
-@item smallverbatim
-works like @code{verbatim}, but in a smaller font.
-
-@item intertext="@var{text}"
-is used in conjunction with @code{verbatim} option: This puts
-@var{text} between the code and the music (without indentation).
-
@item filename=@var{filename}
name the file (for @code{printfilename} option). The argument should
be unquoted.
-@item 11pt
-@lilypond[11pt]
-\relative c' {
- r16 c[ d e] f[ d e c] g'8[ c] b[\prall c] |
- d16[ g, a b] c[ a b g] d'8[ g f\prall g]
-}
-@end lilypond
-
-@item 13pt
-@lilypond[13pt]
+@item staffsize=POINTS
+@lilypond[staffsize=31.41592658]
\relative c' {
r16 c[ d e] f[ d e c] g'8[ c] b[\prall c] |
d16[ g, a b] c[ a b g] d'8[ g f\prall g]
}
@end lilypond
-@item 16pt
-@lilypond[16pt]
-\relative c' {
- r16 c[ d e] f[ d e c] g'8[ c] b[\prall c] |
-}
-@end lilypond
-
-@item 20pt
-@lilypond[20pt]
-\relative c' {
- r16 c[ d e] f[ d e c] g'8[ c] b[\prall c] |
-}
-@end lilypond
-
-@item 26pt
-@lilypond[26pt]
-\relative c' {
- r16 c[ d e] f[ d e c] g'8[ c] b[\prall c] |
-}
-@end lilypond
-
@item raggedright
produces naturally spaced lines (i.e., @code{raggedright = ##t}); this
works well for small music fragments.
-@item multiline
-is the opposite of @code{singleline}: it justifies and breaks lines.
-
-@item linewidth=@var{size}@var{unit}
+@item linewidth=@var{size}\\@var{unit}
sets linewidth to @var{size}, where @var{unit} = cm, mm, in, or pt.
This option affects LilyPond output, not the text layout.
prevents printing time signature.
@item fragment
-@itemx nofragment
+@item nofragment
overrides @command{lilypond-book} auto detection of what type of code is
in the LilyPond block, voice contents or complete code.
-@item indent=@var{size}@var{unit}
+@item indent=@var{size}\\@var{unit}
sets indentation of the first music system to @var{size},
where @var{unit} = cm, mm, in, or pt. This option affects LilyPond,
not the text layout. For single-line fragments the default is to
For example
@example
- \begin[indent=5cm,raggedright]@{lilypond@}
+ \begin[indent=\\5cm,raggedright]@{lilypond@}
...
\end@{lilypond@}
@end example
\score @{ \notes @{ c'4 @} @}
@end example
-@item quote
-instructs @command{lilypond-book} to put La@TeX{} and Texinfo output
-into a quotation block.
-
-@item printfilename
-prints the file name before the music example. Useful in conjunction
-with @code{\lilypondfile}.
-
-@item relative, relative @var{N}
+@item relative, relative=@var{N}
uses relative octave mode. By default, notes are specified relative
central C. The optional integer argument specifies the octave of the
starting note, where the default @code{1} is central C.
@end example
@noindent
-or to use the @option{--outdir} command line option, and change to
+or to use the @option{--output} command line option, and change to
that director before running La@TeX{} or @file{makeinfo}:
@example
-lilypond-book --outdir=out yourfile.tex
-cd out && latex yourfile.latex
+lilypond-book --output=out yourfile.lytex
+cd out && latex yourfile.tex
@end example
version, the format
@code{texi-html} must be used.
-@item @option{--default-music-fontsize=@var{sz}pt}
-Set the music font size to use if no fontsize is given as option.
+@item @option{-F @var{filter}}, @option{--filter=@var{filter}}
+Pipe snippets through @var{filter}.
-@item @option{--force-music-fontsize=@var{sz}pt}
-Force all music to use this fontsize, overriding options given to
-@code{\begin@{lilypond@}}.
+For example:
+@example
+ lilypond-book --filter='convert-ly --from=2.0.0' my-book.tely
+@end example
+
+@item @option{--help}
+Print a short help message.
@item @option{-I @var{dir}}, @option{--include=@var{dir}}
Add @var{DIR} to the include path.
-@item @option{-M}, @option{--dependencies}
-Write dependencies to @file{filename.dep}.
-
-@item @option{--dep-prefix=@var{pref}}
-Prepend @var{pref} before each @option{-M} dependency.
-
-@item @option{-n}, @option{--no-lily}
-Generate the @code{.ly} files, but do not process them.
-
-@item @option{--no-music}
-Strip all music from the input file.
+@item @option{-o @var{dir}}, @option{--output=@var{dir}}
+Place generated files in @var{dir}.
-@item @option{--no-pictures}
-Do not generate pictures when processing Texinfo.
+@item @option{-P @var{process}}, @option{--process=@var{COMMAND}}
+Process lilypond snippets using @var{command}. The default command is
+@var{lilypon-bin}.
-@item @option{--outname=@var{file}}
-The name of La@TeX{} file to output. If this option is not given,
-the output name is derived from the input name.
-
-@item @option{--outdir=@var{dir}}
-Place generated files in @var{dir}.
+@item @option{--verbose}
+Be verbose.
@item @option{--version}
Print version information.
-
-@item @option{--help}
-Print a short help message.
@end table
-
For La@TeX{} input, the file to give to La@TeX{} has extension
@file{.latex}. Texinfo input will be written to a file with extension
@file{.texi}.
Only the first @code{\score} of a LilyPond block is processed.
+@c CHECKME--FIXME
The size of a music block is limited to 1.5 kb, due to technical
-problems with the Python regular expression engine. For longer files,
-use @code{\lilypondfile}. Using @code{\lilypondfile} also makes
-upgrading files (through convert-ly, see @ref{Invoking convert-ly})
-easier.
+problems with the Python regular expression engine. For longer files,
+use @code{\lilypondfile}.
@command{lilypond-book} processes all music fragments in one big run.
The state of the GUILE interpreter is not reset between fragments;
@afourpaper
@end iftex
-
-
@ignore
Distributions will want to install lilypond.info doing:
@vskip 20pt
-@lilypond[singleline]
-\score { \context LyricsVoice \notes {
- \property Score.RehearsalMark \set #'self-alignment-X = #LEFT
-
-\mark #(ly:export (string-append "(For LilyPond version "
-(lilypond-version) ")"))
-s2
- }
- \paper { indent = 0.0\pt
- raggedright = ##t
- }
+@lilypond[raggedright]
+\score {
+ \context LyricsVoice \notes {
+ \property Score.RehearsalMark \set #'self-alignment-X = #LEFT
+ \mark #(ly:export (string-append
+ "(For LilyPond version " (lilypond-version) ")"))
+ s2
+ }
+ \paper {
+ indent = 0.0\pt
+ raggedright = ##t
+ }
}
@end lilypond
@uref{http://www.lilypond.org/}. The website contains on-line copies of
this and other documentation.
-@mbinclude dedication.itely
+@include dedication.itely
@menu
* Preface:: Preface.
@end menu
@end ifnottex
-
@contents
-@mbinclude macros.itexi
-@mbinclude preface.itely
-@mbinclude introduction.itely
-@mbinclude tutorial.itely
-@mbinclude refman.itely
-@mbinclude literature.itely
-@mbinclude internals.itely
-@mbinclude invoking.itexi
-@mbinclude lilypond-book.itely
-@mbinclude converters.itely
+
+@include macros.itexi
+@include preface.itely
+@include introduction.itely
+@include tutorial.itely
+@include refman.itely
+@include literature.itely
+@include internals.itely
+@include invoking.itexi
+@include lilypond-book.itely
+@include converters.itely
@c FIXME: Index has two alphabetically sorted lists @code vs plain?
@printindex cp
-@mbinclude appendices.itely
-@mbinclude cheatsheet.itely
-@mbinclude fdl.itexi
+@include appendices.itely
+@include cheatsheet.itely
+@include fdl.itexi
@bye
@c -*-texinfo-*-
-
@c Reference GLOSsary
@macro rglos {NAME}
@ifhtml
@heading Syntax
@end macro
+
music of the baroque era, has been one of the most popular polyphonic
composition methods.
-@lilypond[11pt,noquote]
+@lilypond[staffsize=11,noquote]
\property Score.TimeSignature \override #'style = #'()
\notes\context PianoStaff <<
\context Staff = SA \relative c' {
The church modes are used in gregorial chant and pre baroque early music but
also to some extent in newer jazz music.
-@lilypond[notime,linewidth=110mm]
+@lilypond[notime,linewidth=110\mm]
\property Score.automaticBars = ##f
%\property Score.LyricText \set #'font-style = #'large
%\property Score.TextScript \set #'font-style = #'large
@cindex quarter tones
@cindex semi-flats, semi-sharps
-@lilypond[verbatim,relative 2]
+@lilypond[verbatim,relative=2]
ceses4
ceseh
ces
Rests are entered like notes, with the note name @code{r}:
-@lilypond[singleline,verbatim]
+@lilypond[raggedright,verbatim]
r1 r2 r4 r8
@end lilypond
formatting in polyphonic music easier. Rest collision testing will
leave these rests alone:
-@lilypond[singleline,verbatim]
+@lilypond[raggedright,verbatim]
a'4\rest d'4\rest
@end lilypond
An invisible rest (also called a `skip') can be entered like a note
with note name `@code{s}' or with @code{\skip @var{duration}}:
-@lilypond[singleline,verbatim]
+@lilypond[raggedright,verbatim]
a2 s4 a4 \skip 1 a4
@end lilypond
The @code{s} syntax is only available in Note mode and Chord mode. In
other situations, you should use the @code{\skip} command:
-@lilypond[singleline,verbatim]
+@lilypond[raggedright,verbatim]
\score {
\new Staff <<
{ \time 4/8 \skip 2 \time 4/4 }
will not affect the appearance of the notes or rests produced.
In the following example, the first three notes take up exactly two
beats:
-@lilypond[fragment,relative 2,verbatim]
+@lilypond[fragment,relative=2,verbatim]
\time 2/4
a4*2/3 gis4*2/3 a4*2/3
a4
to the augmentation dot; in the following example there are two ways of
notating exactly the same concept:
@c
-@lilypond[fragment, singleline,quote]
+@lilypond[fragment,raggedright,quote]
\time 3/4 c'2. c'2 ~ c'4
@end lilypond
If you need to tie a lot of notes over bars, it may be easier to use automatic
example, there are two triplets shown, while @code{\times} was only
used once:
-@lilypond[fragment, relative, singleline, verbatim]
+@lilypond[fragment,relative,raggedright,verbatim]
\property Voice.tupletSpannerDuration = #(ly:make-moment 1 4)
\times 2/3 { c'8 c c c c c }
@end lilypond
predecessor of the first note of @var{musicexpr}.
Here is the relative mode shown in action:
-@lilypond[fragment,singleline,verbatim,center]
+@lilypond[fragment,raggedright,verbatim,center]
\relative c'' {
b c d c b c bes a
}
This can be used to skip over the parts of a score that have already
been checked for errors:
-@lilypond[fragment,singleline,verbatim]
+@lilypond[fragment,raggedright,verbatim]
\relative c'' { c8 d
\property Score.skipTypesetting = ##t
e f g a g c, f e d
Partial measures, for example in upsteps, are entered using the
@code{\partial} command:
-@lilypond[fragment,verbatim,relative 1]
+@lilypond[fragment,verbatim,relative=1]
\partial 16*5 c16 cis d dis e | a2. c,4 | b2
@end lilypond
@end lilypond
The following bar types are available:
-@lilypond[fragment, relative, singleline, verbatim]
+@lilypond[fragment,relative,raggedright,verbatim]
c4
\bar "|" c
\bar "" c
automatically applied to all staves. The resulting bar lines are
connected between different staves of a @internalsref{StaffGroup}:
@c
-@lilypond[fragment, verbatim]
+@lilypond[fragment,verbatim]
<< \context StaffGroup <<
\new Staff { e'4 d'
\bar "||"
a stem directions and horizontal shift for each part:
@c
-@lilypond[singleline, verbatim]
+@lilypond[raggedright,verbatim]
\relative c''
\context Staff << \new Voice { \voiceOne cis2 b }
\new Voice { \voiceThree b4 ais ~ ais4 gis4 }
Normally, note heads with a different number of dots are not merged, but
when the object property @code{merge-differently-dotted} is set in
the @internalsref{NoteCollision} object, they are merged:
-@lilypond[verbatim,fragment,singleline]
+@lilypond[verbatim,fragment,raggedright]
\relative c'' \context Voice << {
g8 g8
\property Staff.NoteCollision \override
Similarly, you can merge half note heads with eighth notes, by setting
@code{merge-differently-headed}:
-@lilypond[fragment, relative=2,verbatim]
+@lilypond[fragment,relative=2,verbatim]
\context Voice << {
c8 c4.
\property Staff.NoteCollision
LilyPond also vertically shifts rests that are opposite of a stem:
-@lilypond[singleline,fragment,verbatim]
+@lilypond[raggedright,fragment,verbatim]
\context Voice << c''4 \\ r4 >>
@end lilypond
Beams are used to group short notes into chunks that are aligned with
the metrum. They are inserted automatically in most cases:
-@lilypond[fragment,verbatim, relative=2]
+@lilypond[fragment,verbatim,relative=2]
\time 2/4 c8 c c c \time 6/8 c c c c8. c16 c8
@end lilypond
end at 3 eights; the third beam can only be corrected by specifying
manual beaming.
-@lilypond[singleline,fragment,relative,noverbatim,quote]
+@lilypond[raggedright,fragment,relative,noverbatim,quote]
\property Voice.autoBeamSettings
\override #'(end * * * *) = #(ly:make-moment 3 8)
% rather show case where it goes wrong
>>
@}
@end example
-@lilypond[singleline]
+@lilypond[raggedright]
\score {
\notes \relative c'' <<
\new Staff { cis4 d e2 }
This leads to some weird and often unwanted results
because accidentals from one voice do not get cancelled in other
voices:
-@lilypond[singleline,relative,fragment,verbatim,quote]
+@lilypond[raggedright,relative,fragment,verbatim,quote]
\context Staff <<
\voiceAccidentals
<<
You get all the same accidentals, but temporary
accidentals also get cancelled in other octaves. Furthermore,
in the same octave, they also get cancelled in the following measure:
-@lilypond[singleline,fragment,verbatim]
+@lilypond[raggedright,fragment,verbatim]
\modernAccidentals
cis' c'' cis'2 | c'' c'
@end lilypond
``extra'' accidentals (the ones not typeset by
@code{\defaultAccidentals}) are typeset as cautionary accidentals.
They are printed in reduced size or with parentheses:
-@lilypond[singleline,fragment,verbatim]
+@lilypond[raggedright,fragment,verbatim]
\modernCautionaries
cis' c'' cis'2 | c'' c'
@end lilypond
@cindex @code{\noResetKey}
Same as @code{\defaultAccidentals} but with accidentals lasting
``forever'' and not only until the next measure:
-@lilypond[singleline,fragment,verbatim,relative]
+@lilypond[raggedright,fragment,verbatim,relative]
\noResetKey
c1 cis cis c
@end lilypond
are not remembered at all---and hence all accidentals are
typeset relative to the key signature, regardless of what was
before in the music:
-@lilypond[singleline,fragment,verbatim,relative]
+@lilypond[raggedright,fragment,verbatim,relative]
\forgetAccidentals
\key d\major c4 c cis cis d d dis dis
@end lilypond
accidentals depending on the order in which the notes occur in the
input file:
-@lilypond[singleline,fragment,verbatim]
+@lilypond[raggedright,fragment,verbatim]
\property Staff.autoAccidentals = #'( Staff (any-octave . 0) )
cis'4 <c'' c'> r2 | cis'4 <c' c''> r2
| <cis' c''> r | <c'' cis'> r |
@syntax
They are entered using parentheses:
-@lilypond[relative 1,fragment,verbatim,center]
+@lilypond[relative=1,fragment,verbatim,center]
f( g)( a) a8 b( a4 g2 f4)
<c e>2( <b d>2)
@end lilypond
@internalsref{Staff} context. A bracket is started with
@code{\startGroup} and closed with @code{\stopGroup}:
-@lilypond[singleline,verbatim]
+@lilypond[raggedright,verbatim]
\score { \notes \relative c'' {
c4\startGroup\startGroup
c4\stopGroup
The script is automatically placed, but if you need to force
directions, you can use @code{_} to force them down, or @code{^} to
put them up:
-@lilypond[fragment, verbatim]
+@lilypond[fragment,verbatim]
c''4^^ c''4_^
@end lilypond
can be forced up or down using @code{^} and @code{_},
eg.
-@lilypond[verbatim,fragment,relative 2]
+@lilypond[verbatim,fragment,relative=2]
c\fermata c^\fermata c_\fermata
@end lilypond
@end example
For finger changes, use markup texts:
@c
-@lilypond[verbatim, singleline, fragment]
+@lilypond[verbatim,raggedright,fragment]
c'4-1 c'4-2 c'4-3 c'4-4
c'^\markup { \fontsize #-3 \number "2-3" }
@end lilypond
You can use the thumb-script to indicate that a note should be
played with the thumb (e.g. in cello music):
-@lilypond[verbatim, singleline, fragment]
+@lilypond[verbatim,raggedright,fragment]
<a' a''-3>8(_\thumb <b' b''-3>)_\thumb
<c'' c'''-3>(_\thumb <d'' d'''-3>)_\thumb
@end lilypond
Fingerings for chords can also be added to individual notes
of the chord by adding them after the pitches:
-@lilypond[verbatim,singleline,fragment,relative=1]
+@lilypond[verbatim,raggedright,fragment,relative=1]
< c-1 e-2 g-3 b-5 > 4
@end lilypond
In this case, setting @code{fingeringOrientations} will put fingerings next
to note heads:
-@lilypond[verbatim,singleline,fragment,relative=1]
+@lilypond[verbatim,raggedright,fragment,relative=1]
\property Voice.fingeringOrientations = #'(left down)
<c-1 es-2 g-4 bes-5 > 4
\property Voice.fingeringOrientations = #'(up right down)
note spacing, but by using the command @code{\fatText}, the widths
will be taken into account:
@c
-@lilypond[fragment,singleline,verbatim] \relative c' {
+@lilypond[fragment,raggedright,verbatim] \relative c' {
c4^"longtext" \fatText c4_"longlongtext" c4 }
@end lilypond
denotes the logical time, one denotes the grace timing. The above
example is shown here with timing tuples:
-@lilypond[singleline]
+@lilypond[raggedright]
<<
\relative c''{
c4 \grace c16 c4 \grace {
If you want to end a note with a grace, then the standard trick
is to put the grace notes after a ``space note'', e.g.
-@lilypond[fragment,verbatim, relative=2]
+@lilypond[fragment,verbatim,relative=2]
\context Voice {
<< { d1^\trill ( }
{ s2 \grace { c16[ d] } } >>
for example, to produce smaller type, and set directions. Hence, when
introducing layout tweaks, they should be inside the grace section,
for example,
-@lilypond[fragment,verbatim,relative 1]
+@lilypond[fragment,verbatim,relative=1]
\new Voice {
\acciaccatura {
\property Voice.Stem \override #'direction = #-1
@code{\fff}, @code{\fff}, @code{\fp}, @code{\sf}, @code{\sff},
@code{\sp}, @code{\spp}, @code{\sfz}, and @code{\rfz}:
-@lilypond[verbatim,singleline,fragment,relative]
+@lilypond[verbatim,raggedright,fragment,relative]
c'\ppp c\pp c \p c\mp c\mf c\f c\ff c\fff
c2\sf c\rfz
@end lilypond
alternative is assumed to be played more than once.
Normal notation repeats are used like this:
-@lilypond[fragment,verbatim,relative 1]
+@lilypond[fragment,verbatim,relative=1]
c1
\repeat volta 2 { c4 d e f }
\repeat volta 2 { f e d c }
@end lilypond
With alternative endings:
-@lilypond[fragment,verbatim,relative 1]
+@lilypond[fragment,verbatim,relative=1]
c1
\repeat volta 2 {c4 d e f}
\alternative { {d2 d} {f f,} }
@end lilypond
-@lilypond[fragment,verbatim,relative 1]
+@lilypond[fragment,verbatim,relative=1]
\context Staff {
\partial 4
\repeat volta 4 { e | c2 d2 | e2 f2 | }
stops a running volta bracket:
@end table
-@lilypond[verbatim, fragment,relative 2]
+@lilypond[verbatim,fragment,relative=2]
c4
\property Score.repeatCommands = #'((volta "93") end-repeat)
c4 c4
To place tremolo marks between notes, use @code{\repeat} with tremolo
style:
-@lilypond[verbatim,singleline]
+@lilypond[verbatim,raggedright]
\score {
\context Voice \notes\relative c' {
\repeat "tremolo" 8 { c16 d16 }
Tremolo marks can also be put on a single note. In this case, the
note should not be surrounded by braces.
-@lilypond[verbatim,singleline]
+@lilypond[verbatim,raggedright]
\repeat "tremolo" 4 c16
@end lilypond
Patterns of a one and two measures are replaced by percent-like signs,
patterns that divide the measure length are replaced by slashes:
-@lilypond[verbatim,singleline]
+@lilypond[verbatim,raggedright]
\context Voice { \repeat "percent" 4 { c'4 }
\repeat "percent" 2 { c'2 es'2 f'4 fis'4 g'4 c''4 }
}
@menu
+* Showing melody rhythms::
* Percussion staves::
-* Percussion MIDI output::
@end menu
similar to @code{notes}. Each piece of percussion has a full name and
an abbreviated name, and both be used in input files:
-@lilypond[singleline]
+@lilypond[raggedright]
\drums { hihat4 hh4 }
@end lilypond
@internalsref{DrumStaff} and @internalsref{DrumVoice} contexts:
@c
-@lilypond[singleline,verbatim,quote]
+@lilypond[raggedright,verbatim,quote]
up = \drums { crashcymbal4 hihat8 halfopenhihat hh hh hh openhihat }
down = \drums { bassdrum4 snare8 bd r bd sn4 }
\score {
@item timbales-style
to typeset timbales on a two line staff:
-@lilypond[singleline]
+@lilypond[raggedright]
nam = \lyrics { timh ssh timl ssl cb }
mus = \drums { timh ssh timl ssl cb s16 }
\score {
@item congas-style
to typeset congas on a two line staff:
-@lilypond[singleline]
+@lilypond[raggedright]
nam = \lyrics { cgh cgho cghm ssh cgl cglo cglm ssl }
mus = \drums { cgh cgho cghm ssh cgl cglo cglm ssl s16 }
\score {
@item bongos-style
to typeset bongos on a two line staff:
-@lilypond[singleline]
+@lilypond[raggedright]
nam = \lyrics { boh boho bohm ssh bol bolo bolm ssl }
mus = \drums { boh boho bohm ssh bol bolo bolm ssl s16 }
\score {
@item percussion-style
to typeset all kinds of simple percussion on one line staves:
-@lilypond[singleline]
+@lilypond[raggedright]
nam = \lyrics { tri trio trim gui guis guil cb cl tamb cab mar hc }
mus = \drums { tri trio trim gui guis guil cb cl tamb cab mar hc s16 }
\score {
If you do not like any of the predefined lists you can define your own
list at the top of your file:
-@lilypond[singleline, verbatim]
+@lilypond[raggedright,verbatim]
#(define mydrums '(
(bassdrum default #f -1)
(snare default #f 0)
point), and it looks ahead skipping over rests to switch in
advance. Here is a practical example:
-@lilypond[verbatim,singleline,quote]
+@lilypond[verbatim,raggedright,quote]
\score { \notes \context PianoStaff <<
\context Staff = "up" {
\autochange \new Voice \relative c' {
@code{\melisma} after the first note of the group, and
@code{\melismaEnd} after the last one, e.g.
-@lilypond[relative 1, singleline, fragment,verbatim]
+@lilypond[relative=1,raggedright,fragment,verbatim]
<< \context Voice = "lala" { \time 3/4
f4 g8
\melisma
@end example
The complete example is shown here:
-@lilypond[singleline,verbatim]
+@lilypond[raggedright,verbatim]
\score {
<< \notes \relative c'' \context Voice = duet { \time 3/4
g2 e4 a2 f4 g2. }
@end example
This results in the following output:
-@lilypond[singleline]
+@lilypond[raggedright]
upper = \notes \relative c {
\clef "treble"
\key c \minor
set of pitches, so they can be transposed:
-@lilypond[verbatim,singleline]
+@lilypond[verbatim,raggedright]
twoWays = \notes \transpose c c' {
\chords {
c1 f:sus4 bes/f
names. It is introduced by the keyword @code{\chords}.
In chords mode, a chord is entered by the root, which is entered
like a common pitch:
-@lilypond[fragment,verbatim,quote, relative=1]
+@lilypond[fragment,verbatim,quote,relative=1]
\chords { es4. d8 c2 }
@end lilypond
@cindex chord entry
The chords may be entered either using the notation
described above, or directly using @code{<} and @code{>}:
-@lilypond[verbatim,singleline]
+@lilypond[verbatim,raggedright]
scheme = \notes {
\chords {a1 b c} <d' f' a'> <e' g' b'>
}
display chord names when there is a change in the chords scheme and at
the start of a new line:
-@lilypond[verbatim, linewidth=9cm]
+@lilypond[verbatim,linewidth=9\cm]
scheme = \chords {
c1:m c:m \break c:m c:m d
}
example, @code{markFormatter} is set to a canned procedure. After a
few measures, it is set to function that produces a boxed number.
-@lilypond[verbatim,fragment,relative 1]
+@lilypond[verbatim,fragment,relative=1]
\property Score.markFormatter = #format-mark-numbers
c1 \mark \default
c1 \mark \default
used, for the next ones @code{instr} is used:
@quotation
-@lilypond[verbatim,singleline]
+@lilypond[verbatim,raggedright]
\property Staff.instrument = "ploink " { c''4 }
@end lilypond
@end quotation
names:
@quotation
-@lilypond[fragment,verbatim,singleline]
+@lilypond[fragment,verbatim,raggedright]
\notes {
\property Staff.instrument = \markup {
\column < "Clarinetti"
@code{\transpose c des} will transpose up half a tone. The first
version will print sharps and the second version will print flats:
-@lilypond[singleline, verbatim]
+@lilypond[raggedright,verbatim]
mus =\notes { \key d \major cis d fis g }
\score { \notes \context Staff {
\clef "F" \mus
combiner: putting parts on one staff, and setting stem directions and
polyphony:
-@lilypond[verbatim,singleline,fragment,relative 1]
+@lilypond[verbatim,raggedright,fragment,relative=1]
\new Staff \partcombine
{
g a( b) r
If you just want the merging parts, and not the textual markings, you
may set the property @var{soloADue} to false:
-@lilypond[verbatim,singleline,fragment]
+@lilypond[verbatim,raggedright,fragment]
\new Staff <<
\property Staff.soloADue = ##f
\partcombine
The following example demonstrates the @code{neo_mensural} style:
-@lilypond[fragment,singleline,verbatim]
+@lilypond[fragment,raggedright,verbatim]
\property Voice.NoteHead \set #'style = #'neo_mensural
a'\longa a'\breve a'1 a'2 a'4 a'8 a'16
@end lilypond
select ancient accidentals. Supported styles are
@code{mensural}, @code{vaticana}, @code{hufnagel} and @code{medicaea}.
-@lilypond[singleline,26pt]
+@lilypond[raggedright,staffsize=26]
\score {
\notes {
\fatText
The following example demonstrates the @code{neo_mensural} style:
-@lilypond[fragment,singleline,verbatim]
+@lilypond[fragment,raggedright,verbatim]
\property Voice.Rest \set #'style = #'neo_mensural
r\longa r\breve r1 r2 r4 r8 r16
@end lilypond
modern style mensural C clef @tab
@code{neo_mensural_c1}, @code{neo_mensural_c2},
@code{neo_mensural_c3}, @code{neo_mensural_c4} @tab
-@lilypond[relative 0, notime]
+@lilypond[relative,notime]
\property Staff.TimeSignature \set #'transparent = ##t
\clef "neo_mensural_c2" c
@end lilypond
@code{petrucci_c5}
@tab
-@lilypond[relative 0, notime]
+@lilypond[relative,notime]
\property Staff.TimeSignature \set #'transparent = ##t
\clef "petrucci_c2" c
@end lilypond
@code{clefs-petrucci_f} @tab
petrucci style mensural F clef @tab
@code{petrucci_f} @tab
-@lilypond[relative 0, notime]
+@lilypond[relative,notime]
\property Staff.TimeSignature \set #'transparent = ##t
\clef "petrucci_f" c
@end lilypond
@code{clefs-petrucci_g} @tab
petrucci style mensural G clef @tab
@code{petrucci_g} @tab
-@lilypond[relative 0, notime]
+@lilypond[relative,notime]
\property Staff.TimeSignature \set #'transparent = ##t
\clef "petrucci_g" c
@end lilypond
historic style mensural C clef @tab
@code{mensural_c1}, @code{mensural_c2}, @code{mensural_c3},
@code{mensural_c4} @tab
-@lilypond[relative 0, notime]
+@lilypond[relative,notime]
\property Staff.TimeSignature \set #'transparent = ##t
\clef "mensural_c2" c
@end lilypond
@code{clefs-mensural_f} @tab
historic style mensural F clef @tab
@code{mensural_f} @tab
-@lilypond[relative 0, notime]
+@lilypond[relative,notime]
\property Staff.TimeSignature \set #'transparent = ##t
\clef "mensural_f" c
@end lilypond
@code{clefs-mensural_g} @tab
historic style mensural G clef @tab
@code{mensural_g} @tab
-@lilypond[relative 0, notime]
+@lilypond[relative,notime]
\property Staff.TimeSignature \set #'transparent = ##t
\clef "mensural_g" c
@end lilypond
@code{clefs-vaticana_do} @tab
Editio Vaticana style do clef @tab
@code{vaticana_do1}, @code{vaticana_do2}, @code{vaticana_do3} @tab
-@lilypond[relative 0, notime]
+@lilypond[relative,notime]
\property Staff.StaffSymbol \set #'line-count = #4
\property Staff.TimeSignature \set #'transparent = ##t
\clef "vaticana_do2" c
@code{clefs-vaticana_fa} @tab
Editio Vaticana style fa clef @tab
@code{vaticana_fa1}, @code{vaticana_fa2} @tab
-@lilypond[relative 0, notime]
+@lilypond[relative,notime]
\property Staff.StaffSymbol \set #'line-count = #4
\property Staff.TimeSignature \set #'transparent = ##t
\clef "vaticana_fa2" c
@code{clefs-medicaea_do} @tab
Editio Medicaea style do clef @tab
@code{medicaea_do1}, @code{medicaea_do2}, @code{medicaea_do3} @tab
-@lilypond[relative 0, notime]
+@lilypond[relative,notime]
\property Staff.StaffSymbol \set #'line-count = #4
\property Staff.TimeSignature \set #'transparent = ##t
\clef "medicaea_do2" c
@code{clefs-medicaea_fa} @tab
Editio Medicaea style fa clef @tab
@code{medicaea_fa1}, @code{medicaea_fa2} @tab
-@lilypond[relative 0, notime]
+@lilypond[relative,notime]
\property Staff.StaffSymbol \set #'line-count = #4
\property Staff.TimeSignature \set #'transparent = ##t
\clef "medicaea_fa2" c
@code{clefs-hufnagel_do} @tab
historic style hufnagel do clef @tab
@code{hufnagel_do1}, @code{hufnagel_do2}, @code{hufnagel_do3} @tab
-@lilypond[relative 0, notime]
+@lilypond[relative,notime]
\property Staff.StaffSymbol \set #'line-count = #4
\property Staff.TimeSignature \set #'transparent = ##t
\clef "hufnagel_do2" c
@code{clefs-hufnagel_fa} @tab
historic style hufnagel fa clef @tab
@code{hufnagel_fa1}, @code{hufnagel_fa2} @tab
-@lilypond[relative 0, notime]
+@lilypond[relative,notime]
\property Staff.StaffSymbol \set #'line-count = #4
\property Staff.TimeSignature \set #'transparent = ##t
\clef "hufnagel_fa2" c
@code{clefs-hufnagel_do_fa} @tab
historic style hufnagel combined do/fa clef @tab
@code{hufnagel_do_fa} @tab
-@lilypond[relative 0, notime]
+@lilypond[relative,notime]
\property Staff.TimeSignature \set #'transparent = ##t
\clef "hufnagel_do_fa" c
@end lilypond
select ancient flags. Besides the @code{default} flag style,
only @code{mensural} style is supported:
-@lilypond[fragment,singleline,verbatim]
+@lilypond[fragment,raggedright,verbatim]
\property Voice.Stem \set #'flag-style = #'mensural
\property Voice.Stem \set #'thickness = #1.0
\property Voice.NoteHead \set #'style = #'mensural
of the end of each flare is different between notes on staff lines and
notes between staff lines:
-@lilypond[fragment,singleline]
+@lilypond[fragment,raggedright]
\property Voice.Stem \set #'flag-style = #'mensural
\property Voice.Stem \set #'thickness = #1.0
\property Voice.Stem \set #'adjust-if-on-staffline = ##f
By default, the @internalsref{LigatureBracket} engraver just puts a
square bracket above the ligature:
-@lilypond[singleline,verbatim]
+@lilypond[raggedright,verbatim]
\score {
\notes \transpose c c' {
\[ g c a f d' \]
s4
\[ e1 f1 a\breve g\longa \]
@end example
-@lilypond[singleline]
+@lilypond[raggedright]
\score {
\notes \transpose c c' {
\property Score.timing = ##f
@internalsref{Mensural_ligature_engraver}, the same music transcribes
to the following:
-@lilypond[singleline]
+@lilypond[raggedright]
\score {
\notes \transpose c c' {
\property Score.timing = ##f
@item
@code{1. Punctum}
@tab
-@lilypond[noindent, 26pt, nofragment, linewidth=1.5cm]
+@lilypond[noindent,staffsize=26,nofragment,linewidth=1.5\cm]
\include "gregorian-init.ly"
\score {
\notes \transpose c c' {
}
@end lilypond
@tab
-@lilypond[noindent, 26pt, nofragment, linewidth=2.5cm]
+@lilypond[noindent,staffsize=26,nofragment,linewidth=2.5\cm]
\include "gregorian-init.ly"
\score {
\notes \transpose c c' {
}
@end lilypond
@tab
-@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm]
+@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm]
\include "gregorian-init.ly"
\score {
\notes \transpose c c' {
@item
@code{2. Virga}
@tab
-@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm]
+@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm]
\include "gregorian-init.ly"
\score {
\notes \transpose c c' {
@item
@code{3. Apostropha vel Stropha}
@tab
-@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm]
+@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm]
\include "gregorian-init.ly"
\score {
\notes \transpose c c' {
}
@end lilypond
@tab
-@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm]
+@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm]
\include "gregorian-init.ly"
\score {
\notes \transpose c c' {
@item
@code{4. Oriscus}
@tab
-@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm]
+@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm]
\include "gregorian-init.ly"
\score {
\notes \transpose c c' {
@item
@code{5. Clivis vel Flexa}
@tab
-@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm]
+@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm]
\include "gregorian-init.ly"
\score {
\notes \transpose c c' {
}
@end lilypond
@tab
-@lilypond[noindent, 26pt, nofragment, linewidth=2.0cm]
+@lilypond[noindent,staffsize=26,nofragment,linewidth=2.0\cm]
\include "gregorian-init.ly"
\score {
\notes \transpose c c' {
}
@end lilypond
@tab
-@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm]
+@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm]
\include "gregorian-init.ly"
\score {
\notes \transpose c c' {
@item
@code{6. Podatus vel Pes}
@tab
-@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm]
+@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm]
\include "gregorian-init.ly"
\score {
\notes \transpose c c' {
}
@end lilypond
@tab
-@lilypond[noindent, 26pt, nofragment, linewidth=2.0cm]
+@lilypond[noindent,staffsize=26,nofragment,linewidth=2.0\cm]
\include "gregorian-init.ly"
\score {
\notes \transpose c c' {
}
@end lilypond
@tab
-@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm]
+@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm]
\include "gregorian-init.ly"
\score {
\notes \transpose c c' {
@item
@code{7. Pes Quassus}
@tab
-@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm]
+@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm]
\include "gregorian-init.ly"
\score {
\notes \transpose c c' {
}
@end lilypond
@tab
-@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm]
+@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm]
\include "gregorian-init.ly"
\score {
\notes \transpose c c' {
@item
@code{8. Quilisma Pes}
@tab
-@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm]
+@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm]
\include "gregorian-init.ly"
\score {
\notes \transpose c c' {
}
@end lilypond
@tab
-@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm]
+@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm]
\include "gregorian-init.ly"
\score {
\notes \transpose c c' {
@item
@code{9. Podatus Initio Debilis}
@tab
-@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm]
+@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm]
\include "gregorian-init.ly"
\score {
\notes \transpose c c' {
}
@end lilypond
@tab
-@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm]
+@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm]
\include "gregorian-init.ly"
\score {
\notes \transpose c c' {
@item
@code{10. Torculus}
@tab
-@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm]
+@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm]
\include "gregorian-init.ly"
\score {
\notes \transpose c c' {
}
@end lilypond
@tab
-@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm]
+@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm]
\include "gregorian-init.ly"
\score {
\notes \transpose c c' {
}
@end lilypond
@tab
-@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm]
+@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm]
\include "gregorian-init.ly"
\score {
\notes \transpose c c' {
@item
@code{11. Torculus Initio Debilis}
@tab
-@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm]
+@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm]
\include "gregorian-init.ly"
\score {
\notes \transpose c c' {
}
@end lilypond
@tab
-@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm]
+@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm]
\include "gregorian-init.ly"
\score {
\notes \transpose c c' {
}
@end lilypond
@tab
-@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm]
+@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm]
\include "gregorian-init.ly"
\score {
\notes \transpose c c' {
@item
@code{12. Porrectus}
@tab
-@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm]
+@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm]
\include "gregorian-init.ly"
\score {
\notes \transpose c c' {
}
@end lilypond
@tab
-@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm]
+@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm]
\include "gregorian-init.ly"
\score {
\notes \transpose c c' {
}
@end lilypond
@tab
-@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm]
+@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm]
\include "gregorian-init.ly"
\score {
\notes \transpose c c' {
@item
@code{13. Climacus}
@tab
-@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm]
+@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm]
\include "gregorian-init.ly"
\score {
\notes \transpose c c' {
}
@end lilypond
@tab
-@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm]
+@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm]
\include "gregorian-init.ly"
\score {
\notes \transpose c c' {
}
@end lilypond
@tab
-@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm]
+@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm]
\include "gregorian-init.ly"
\score {
\notes \transpose c c' {
@item
@code{14. Scandicus}
@tab
-@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm]
+@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm]
\include "gregorian-init.ly"
\score {
\notes \transpose c c' {
}
@end lilypond
@tab
-@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm]
+@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm]
\include "gregorian-init.ly"
\score {
\notes \transpose c c' {
}
@end lilypond
@tab
-@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm]
+@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm]
\include "gregorian-init.ly"
\score {
\notes \transpose c c' {
@item
@code{15. Salicus}
@tab
-@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm]
+@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm]
\include "gregorian-init.ly"
\score {
\notes \transpose c c' {
}
@end lilypond
@tab
-@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm]
+@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm]
\include "gregorian-init.ly"
\score {
\notes \transpose c c' {
@item
@code{16. Trigonus}
@tab
-@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm]
+@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm]
\include "gregorian-init.ly"
\score {
\notes \transpose c c' {
cluster-notes. Cluster notes are created by applying the function
@code{notes-to-clusters} to a sequence of chords, e.g.
@c
-@lilypond[relative 1,verbatim]
+@lilypond[relative=1,verbatim]
\apply #notes-to-clusters { <c e > <b f'> }
@end lilypond
The following are supported
-@lilypond[singleline]
+@lilypond[raggedright]
\score {
<< \addlyrics \notes {
b'
The following example demonstrates its use.
-@lilypond[verbatim,fragment,singleline,relative 1]
+@lilypond[verbatim,fragment,raggedright,relative=1]
\context Voice
\applyoutput
#(add-balloon-text 'NoteHead "heads, or tails?"
The `easy play' note head includes a note name inside the head. It is
used in music aimed at beginners:
-@lilypond[singleline,verbatim,26pt]
+@lilypond[raggedright,verbatim,staffsize=26]
\score {
\notes { c'2 e'4 f' | g'1 }
\paper { \translator { \EasyNotation } }
In the following example, only one @internalsref{Stem} object is
changed from its original setting:
-@lilypond[verbatim, fragment, relative=1]
+@lilypond[verbatim,fragment,relative=1]
c4
\once \property Voice.Stem \set #'thickness = #4
c4
For example, the following piece contains lots of half, quarter and
8th notes, the eighth note is followed by 1 note head width (NHW).
The quarter note is followed by 2 NHW, the half by 3 NHW, etc.
-@lilypond[fragment, verbatim, relative=1] c2 c4. c8 c4. c8 c4. c8 c8
+@lilypond[fragment,verbatim,relative=1] c2 c4. c8 c4. c8 c4. c8 c8
c8 c4 c4 c4
@end lilypond
only a few 16th notes to the example above, they would be followed by
half a NHW:
-@lilypond[fragment, verbatim, relative=2]
+@lilypond[fragment,verbatim,relative=2]
c2 c4. c8 c4. c16[ c] c4. c8 c8 c8 c4 c4 c4
@end lilypond
@cindex @code{interscorelinefill}
If the variable @code{lastpagefill} is defined,
-@c fixme: this should only be done if lastpagefill == #t
+@c fixme: this should only be done if lastpagefill= #t
systems are evenly distributed vertically on the last page. This
might produce ugly results in case there are not enough systems on the
last page. The @command{lilypond-book} command ignores
LilyPond input that was used to generate that image.
@ifhtml
For example, consider the following input:
-@c TODO: intertext fixme
-@lilypond[relative 1,singleline,verbatim,intertext="with the following output:"]
+@example
+ c'^\markup @{ \bold \huge @{ Click on this image! @} @}
+@end example
+@c @lily pond[relative=1,raggedright,with the following output:]
+with the following output:
+@lilypond[relative=1,raggedright]
c'^\markup { \bold \huge { Click on this image! } }
@end lilypond
@c \transpose c c' { c d e f g a b }
@c @lily pond[notime]
@c \property Score.timing = ##f
-@lilypond[notime, relative=2]
+@lilypond[notime,relative=2]
c d e f g a b
@end lilypond
s16_" "
@end lilypond
-Notes and commands like @code{\clef} and @code{\time} , are enclosed
+Notes and commands like @code{\clef} and @code{\time}, are enclosed
in @code{\notes @{@dots{}@}}. This indicates that music (as opposed
to @rglos{lyrics}) follows:
A tie is created by adding a tilde ``@code{~}'' to the first note
being tied:
@quotation
-@lilypond[fragment,verbatim,relative 2]
+@lilypond[fragment,verbatim,relative=2]
g4~ g a2~ a4
@end lilypond
@end quotation
put, they can be entered by hand. Mark the first note to be beamed
with @code{[} and the last one with @code{]}:
@quotation
-@lilypond[fragment,relative 1, verbatim]
+@lilypond[fragment,relative=1,verbatim]
a8[ ais] d[ es r d]
@end lilypond
@end quotation
@separate
An example of the use of quotes is in the following Mozart fragment:
-@lilypond[singleline,fragment,verbatim]
+@lilypond[raggedright,fragment,verbatim]
\key a \major
\time 6/8
cis''8. d''16 cis''8 e''4 e''8
most convenient way to copy existing music. To use relative mode, add
@code{\relative} before the piece of music. You must also give a note
from which relative starts, in this case @code{c''}. If you do not
-use octavation quotes (i.e. do not add ' or , after a note), relative
-mode chooses the note that is closest to the previous one.
-For example, @code{c f} goes up while @code{c g} goes down:
+use octavation quotes (i.e. do not add @code{'} or @code{,} after a
+note), relative mode chooses the note that is closest to the previous
+one. For example, @code{c f} goes up while @code{c g} goes down:
@quotation
@example
without octavation quotes in relative mode. The previous example is
entered as
@c
-@lilypond[singleline,fragment,verbatim]
+@lilypond[raggedright,fragment,verbatim]
\relative c'' {
\key a \major
\time 6/8
We can now typeset a melody with two staves:
@quotation
-@lilypond[verbatim,singleline]
+@lilypond[verbatim,raggedright]
\score {
\notes
<< \new Staff {
Like mathematical expressions, music expressions can be nested
arbitrarily deep, e.g.
-@lilypond[verbatim,relative 1]
+@lilypond[verbatim,relative=1]
{ c <<c e>>
<< { e f } { c <<b d>> }
>>
Common accents can be added to a note using a dash (`@code{-}') and a
single character:
@quotation
-@lilypond[verbatim,relative 1]
+@lilypond[verbatim,relative=1]
c-. c-- c-> c-^ c-+ c-_
@end lilypond
@end quotation
Similarly, fingering indications can be added to a note using a dash
(`@code{-}') and the digit to be printed:
@c
-@lilypond[verbatim,relative 1]
+@lilypond[verbatim,relative=1]
c-3 e-5 b-2 a-1
@end lilypond
Dynamic signs are made by adding the markings to the note:
@quotation
-@lilypond[verbatim,relative 1]
+@lilypond[verbatim,relative=1]
c\ff c\mf
@end lilypond
@end quotation
@code{\>}. The command @code{\!} finishes a crescendo on the note it
is attached to:
@quotation
-@lilypond[verbatim,relative 1]
+@lilypond[verbatim,relative=1]
c2\< c2\!\ff\> c2 c2\!
@end lilypond
@end quotation
``@code{(}'' and a ``@code{)}'' respectively:
@quotation
-@lilypond[fragment,relative 1, verbatim]
+@lilypond[fragment,relative=1,verbatim]
d4( c16)( cis d e c cis d e)( d4)
@end lilypond
@end quotation
and can be used on larger groups of notes. Slurs and ties are also
nested in practice:
@c
-@lilypond[fragment, relative=1]
+@lilypond[fragment,relative=1]
c2~( c8 fis fis4 ~ fis2 g2)
@end lilypond
@code{\)}.
@quotation
-@lilypond[fragment,relative 1, verbatim]
+@lilypond[fragment,relative=1,verbatim]
a8(\( ais b c) cis2 b'2 a4 cis, c\)
@end lilypond
@end quotation
Chords can be made by
surrounding pitches with @code{<} and @code{>}:
@quotation
-@lilypond[relative 0, fragment,verbatim]
+@lilypond[,fragment,verbatim]
r4 <c e g>4 <c f a>8
@end lilypond
@end quotation
You can combine beams and ties with chords. Beam and tie markings
must be placed outside the chord markers:
@quotation
-@lilypond[relative 0, fragment,verbatim]
+@lilypond[,fragment,verbatim]
r4 <c e g>8[ <c f a>]~ <c f a>
@end lilypond
@end quotation
@example
r4 <c e g>8\>( <c e g> <c e g> <c f a>8\!)
@end example
-@lilypond[relative 0, fragment]
+@lilypond[,fragment]
\slurUp
r4 <c e g>8\>( <c e g> <c e g> <c f a>8\!)
@end lilypond
A pickup (or upstep) is entered with the keyword @code{\partial}. It
is followed by a duration: @code{\partial 4} is a quarter note upstep
and @code{\partial 8} an eighth note:
-@lilypond[relative 1,verbatim,fragment]
+@lilypond[relative=1,verbatim,fragment]
\partial 8
f8 c2 d e
@end lilypond
of music is multiplied by the fraction. Triplets make notes occupy
2/3 of their notated duration, so a triplet has 2/3 as its fraction:
@c
-@lilypond[relative 0,verbatim,fragment]
+@lilypond[,verbatim,fragment]
\times 2/3 { f8 g a }
\times 2/3 { c r c }
@end lilypond
@cindex appoggiatura
@cindex acciaccatura
-@lilypond[relative 1, verbatim,fragment]
+@lilypond[relative=1,verbatim,fragment]
c4 \appoggiatura b16 c4
c4 \acciaccatura b16 c4
@end lilypond
empty.
The final result is
-@lilypond[verbatim,linewidth=6.0cm]
+@lilypond[verbatim,linewidth=6.0\cm]
\score {
\notes <<
\relative c' \new Voice {
@example
Twin -- kle twin -- kle
@end example
-@lilypond[singleline]
+@lilypond[raggedright]
\score {
<< \notes \relative f' { \time 2/4
f4 f c' c' }
<< @{ a4 g2 f4~ f4 @} \\
@{ r4 g4 f2 f4 @} >>
@end example
-@lilypond[relative 1]
+@lilypond[relative=1]
\context Staff << { a4 g2 f4~ f4 } \\
{ r4 g4 f2 f4 } >>
@end lilypond
<< @{ a4 g2 f4~ f4 @} \\
@{ s4 g4 f2 f4 @} >>
@end example
-@lilypond[relative 1]
+@lilypond[relative=1]
\context Staff << { a4 g2 f4~ f4 } \\
{ s4 g4 f2 f4 } >>
@end lilypond
Here is a full-fledged example:
-@lilypond[relative 0,fragment]
+@lilypond[,fragment]
\new PianoStaff
<< \new Staff { \time 2/4
c4 c g' g }
this point in the music to @code{##f}, which means `false'. This
property controls whether beams are printed automatically:
@c
-@lilypond[relative 1,fragment,verbatim]
+@lilypond[relative=1,fragment,verbatim]
c8 c c c
\property Staff.autoBeaming = ##f
c8 c c c
@emph{layout properties}. By changing these variables from their
values, we can alter the look of a formatted score:
-@lilypond[verbatim,relative 0]
+@lilypond[verbatim,]
c4
\property Voice.Stem \override #'thickness = #3.0
c4 c4 c4
\once \property Voice.Stem \set #'thickness = #3.0
@end example
-@lilypond[relative 0]
+@lilypond[relative]
c4
\once \property Voice.Stem \set #'thickness = #3.0
c4 c4 c4
low-level feature: the formatting engine is completely oblivious to
these offsets.
-In the following example example, the second fingering is moved a
-little to the left, and 1.8 staff space downwards:
+In the following example, the second fingering is moved a little to
+the left, and 1.8 staff space downwards:
@cindex setting object properties
-@lilypond[relative 1,verbatim]
+@lilypond[relative=1,verbatim]
\stemUp
f-5
\once \property Voice.Fingering
voice. By introducing a tie in a different voice, and blanking a stem
in that voice, the tie appears to cross voices:
-@lilypond[fragment,relative 1,verbatim]
+@lilypond[fragment,relative=1,verbatim]
c4 << {
\once \property Voice.Stem \set #'transparent = ##t
b8~ b8
example; a more elaborate explanation is in @ref{Constructing a
tweak}:
-@lilypond[relative 1,verbatim]
+@lilypond[relative=1,verbatim]
c2\fermata
\property Voice.Script \set #'padding = #3
b2\fermata
In the next example, a two note motive is repeated two times by using
variable substitution:
-@lilypond[singleline,verbatim]
+@lilypond[raggedright,verbatim]
seufzer = \notes {
dis'8 e'8
}
corresponds with tuning of a normal French Horn in F. The
transposition can be seen in the following output:
-@lilypond[singleline]
+@lilypond[raggedright]
\score {
\notes \transpose f c' \notes \relative c {
\time 2/4
Prepending the rest and the property setting above, leads to the
following result:
-@lilypond[singleline]
+@lilypond[raggedright]
\score {\notes { \transpose f c' \relative c { \time 2/4
\property Score.skipBars = ##t
R2*3
This would lead to the simple score depicted below:
-@lilypond[singleline]
+@lilypond[raggedright]
\score {
\notes \relative c \simultaneous {
\new Staff { \time 2/4
\verb+\score+ block was added, and the line width was set to natural
length. You can specify options by putting them in brackets:
-\begin[26pt,verbatim]@{lilypond@}
+\begin[staffsize=26,verbatim]@{lilypond@}
c'4 f16
\end@{lilypond@}
@example
$ cd input/tutorial
$ mkdir -p out/
-$ lilypond-book --outdir=out/ lilbook.tex
-lilypond-book (GNU LilyPond) 1.7.23
-Reading `input/tutorial/lilbook.tex'
+$ lilypond-book --output=out/ lilybook.tex
+lilypond-book (GNU LilyPond) 2.1.19
+Reading `input/tutorial/lilybook.tex'
Reading `input/screech-boink6.ly'
@var{lots of stuff deleted}
-Writing `out/lilbook.latex'
+Writing `out/lilybook.latex'
$ cd out
-$ latex lilbook.latex
+$ latex lilybook.latex
@var{lots of stuff deleted}
-$ xdvi lilbook
+$ xdvi lilybook
@end example
To convert the file into a nice PDF document, run the following
commands:
@example
-$ dvips -Ppdf -u +lilypond lilbook
-$ ps2pdf lilbook.ps
+$ dvips -Ppdf -u +lilypond lilybook
+$ ps2pdf lilybook.ps
@end example
In the example you see here, two things happened: a
@code{score} block was added, and the line width was set to natural
-length. You can specify options by putting them in brackets:
+length. You can specify options by putting them in brackets:
-@lilypond[26pt,verbatim]
+@lilypond[staffsize=26,verbatim]
c'4 f16
@end lilypond
-.SUFFIXES: .doc .dvi .mudtex .tely .texi .ly
+.SUFFIXES: .doc .dvi .tely .texi .ly
$(outdir)/%.latex: %.doc
if [ -f $@ ]; then chmod a+w $@; fi
- $(PYTHON) $(LILYPOND_BOOK) $(LILYPOND_BOOK_INCLUDES) $(LILYPOND_BOOK_FLAGS) --verbose --dependencies --outdir=$(outdir) $<
+ $(PYTHON) $(LILYPOND_BOOK) $(LILYPOND_BOOK_INCLUDES) --process='$(LILYPOND) $(LILYPOND_BOOK_INCLUDES)' --output=$(outdir) --verbose $(LILYPOND_BOOK_FLAGS) $<
chmod -w $@
# don't do ``cd $(outdir)'', and assume that $(outdir)/.. is the src dir.
$(outdir)/%.texi: %.tely
if [ -f $@ ]; then chmod a+w $@; fi
set|egrep '(TEX|LILY)' # ugh, what's this?
- $(PYTHON) $(LILYPOND_BOOK) $(LILYPOND_BOOK_INCLUDES) --dependencies --outdir=$(outdir) --format=$(LILYPOND_BOOK_FORMAT) --verbose $(LILYPOND_BOOK_FLAGS) $<
+ $(PYTHON) $(LILYPOND_BOOK) $(LILYPOND_BOOK_INCLUDES) --process='$(LILYPOND) $(LILYPOND_BOOK_INCLUDES)' --output=$(outdir) --format=$(LILYPOND_BOOK_FORMAT) --verbose $(LILYPOND_BOOK_FLAGS) $<
chmod -w $@
$(outdir)/%.texi: $(outdir)/%.tely
if [ -f $@ ]; then chmod a+w $@; fi
# debugging:
# set|egrep '(TEX|LILY)'
- $(PYTHON) $(LILYPOND_BOOK) $(LILYPOND_BOOK_INCLUDES) --dependencies --outdir=$(outdir) --format=$(LILYPOND_BOOK_FORMAT) --verbose $(LILYPOND_BOOK_FLAGS) $<
+ $(PYTHON) $(LILYPOND_BOOK) $(LILYPOND_BOOK_INCLUDES) --process='$(LILYPOND) $(LILYPOND_BOOK_INCLUDES)' --output=$(outdir) --format=$(LILYPOND_BOOK_FORMAT) --verbose $(LILYPOND_BOOK_FLAGS) $<
#
# DON'T REMOVE SOURCE FILES, otherwise the .TEXI ALWAYS OUT OF DATE.
# rm -f $<
# for plain info doco: don't run lily
$(outdir)/%.nexi: %.tely
if [ -f $@ ]; then chmod a+w $@; fi
- $(PYTHON) $(LILYPOND_BOOK) $(LILYPOND_BOOK_INCLUDES) --dependencies --outdir=$(outdir) --format=$(LILYPOND_BOOK_FORMAT) --no-lily $(LILYPOND_BOOK_FLAGS) -o $(notdir $@) $<
+ $(PYTHON) $(LILYPOND_BOOK) $(LILYPOND_BOOK_INCLUDES) --output=$(outdir) --format=$(LILYPOND_BOOK_FORMAT) --verbose $(LILYPOND_BOOK_FLAGS) --process='true' $<
+ mv $(outdir)/$*.texinfo $@ 2>/dev/null || mv $(outdir)/$*.texi $@
chmod -w $@
# nfo: info from non-lily texi
$(outdir)/%.info: $(outdir)/%.nexi
- $(MAKEINFO) --output=$(outdir)/$(*F).info $<
+ $(MAKEINFO) -I $(outdir) --output=$(outdir)/$(*F).info $<
# nfo: info from non-lily texi
#$(outdir)/%.nfo: $(outdir)/%.nexi
+++ /dev/null
-#!@PYTHON@
-
-'''
-TODO:
- ly-options: intertext, quote ?
- --linewidth?
- eps in latex?
- check latex parameters, twocolumn
- multicolumn?
- papersizes?
- ly2dvi/notexidoc?
-
-Example usage:
-
-test:
- filter-lilypond-book --filter="tr '[a-z]' '[A-Z]'" BOOK
-
-convert-ly on book:
- filter-lilypond-book --filter="convert-ly --no-version --from=1.6.11 -" BOOK
-
-classic lilypond-book:
- filter-lilypond-book --process="lilypond-bin" BOOK.tely
-
- must substitute:
- @mbinclude foo.itely -> @include foo.itely
- \mbinput -> \input
-
-'''
-
-import string
-import __main__
-
-################################################################
-# Users of python modules should include this snippet
-# and customize variables below.
-
-# We'll suffer this path init stuff as long as we don't install our
-# python packages in <prefix>/lib/pythonx.y (and don't kludge around
-# it as we do with teTeX on Red Hat Linux: set some environment var
-# (PYTHONPATH) in profile)
-
-# If set, LILYPONDPREFIX must take prevalence
-# if datadir is not set, we're doing a build and LILYPONDPREFIX
-import getopt, os, sys
-datadir = '@local_lilypond_datadir@'
-if not os.path.isdir (datadir):
- datadir = '@lilypond_datadir@'
-if os.environ.has_key ('LILYPONDPREFIX') :
- datadir = os.environ['LILYPONDPREFIX']
- while datadir[-1] == os.sep:
- datadir= datadir[:-1]
-
-sys.path.insert (0, os.path.join (datadir, 'python'))
-
-# Customize these
-#if __name__ == '__main__':
-
-import lilylib as ly
-global _;_=ly._
-global re;re = ly.re
-
-# lilylib globals
-program_version = '@TOPLEVEL_VERSION@'
-#program_name = 'new-book'
-program_name = 'filter-lilypond-book'
-verbose_p = 0
-pseudo_filter_p = 0
-original_dir = os.getcwd ()
-
-
-# help_summary = _ ("Process LilyPond snippets in hybrid html, LaTeX or texinfo document")
-help_summary = _ ("""Process ly snippets from lilypond-book source. Example usage:
-
- filter-lilypond-book --filter="tr '[a-z]' '[A-Z]'" BOOK
- filter-lilypond-book --filter="convert-ly --no-version --from=1.6.11 -" BOOK
-
-""")
-copyright = ('Jan Nieuwenhuizen <janneke@gnu.org>>',
- 'Han-Wen Nienhuys <hanwen@cs.uu.nl>')
-
-option_definitions = [
- (_ ("EXT"), 'f', 'format', _ ("use output format EXT (texi [default], texi-html, latex, html)")),
- (_ ("FILTER"), 'F', 'filter', _ ("pipe snippets through FILTER [convert-ly -n -]")),
- ('', 'h', 'help', _ ("print this help")),
- (_ ("DIR"), 'I', 'include', _ ("add DIR to include path")),
- (_ ("COMMAND"), 'P', 'process', _ ("process ly_files using COMMAND FILE...")),
- (_ ("FILE"), 'o', 'output', _ ("write output to FILE")),
- ('', 'V', 'verbose', _ ("be verbose")),
- ('', 'v', 'version', _ ("print version information")),
- ('', 'w', 'warranty', _ ("show warranty and copyright")),
- ('', 'M', 'dependencies', _ ("TODO")),
- (_ ("DIR"), '', 'outdir', _ ("DEPRECATED, use --output")),
- ]
-
-include_path = [ly.abspath (os.getcwd ())]
-
-lilypond_binary = os.path.join ('@bindir@', 'lilypond-bin')
-
-# only use installed binary when we're installed too.
-if '@bindir@' == ('@' + 'bindir@') or not os.path.exists (lilypond_binary):
- lilypond_binary = 'lilypond-bin'
-
-
-use_hash_p = 1
-format = 0
-output_name = 0
-latex_filter_cmd = 'latex "\\nonstopmode \input /dev/stdin"'
-##filter_cmd = 'convert-ly --no-version --from=2.0.0 -'
-filter_cmd = 0
-
-#process_cmd = 'convert-ly --no-version --from=2.0.0'
-#process_cmd = 0
-# process_cmd = 'lilypond-bin'
-process_cmd = 'lilypond-bin -I ../../../input/test'
-default_ly_options = { }
-
-LATEX = 'latex'
-HTML = 'html'
-TEXINFO = 'texinfo'
-BEFORE = 'before'
-OUTPUT = 'output'
-AFTER = 'after'
-VERBATIM = 'verbatim'
-LINEWIDTH = 'linewidth'
-
-## lilypond-book heritage. to be cleaned
-
-################################################################
-# Recognize special sequences in the input
-
-
-# Warning: This uses extended regular expressions. Tread with care.
-#
-# legenda
-#
-# (?P<name>regex) -- assign result of REGEX to NAME
-# *? -- match non-greedily.
-# (?m) -- multiline regex: make ^ and $ match at each line
-# (?s) -- make the dot match all characters including newline
-no_match = 'a\ba'
-snippet_res = {
- HTML: {
- #'header': no_match,
- #'input': no_match,
- #'landscape': no_match,
- #'ly2dvi': r'(?m)(?P<match><ly2dvifile(?P<options>[^>]+)?>\s*(?P<filename>[^<]+)\s*</ly2dvifile>)',
- #'multicols': no_match,
- #'numcols': no_match,
- 'include': no_match,
- 'lilypond' : '(?m)(?P<match><lilypond((?P<options>[^:]*):)(?P<code>.*?)/>)',
- 'lilypond-block': r'''(?ms)(?P<match><lilypond(?P<options>[^>]+)?>(?P<code>.*?)</lilypond>)''',
- 'lilypond-file': r'(?m)(?P<match><lilypondfile(?P<options>[^>]+)?>\s*(?P<filename>[^<]+)\s*</lilypondfile>)',
- 'multiline-comment': r"(?sm)\s*(?!@c\s+)(?P<code><!--\s.*?!-->)\s",
- 'singleline-comment': no_match,
- 'verb': r'''(?P<code><pre>.*?</pre>)''',
- 'verbatim': r'''(?s)(?P<code><pre>\s.*?</pre>\s)''',
- },
-
- LATEX: {
- #'def-post-re': r"\\def\\postLilyPondExample",
- #'def-pre-re': r"\\def\\preLilyPondExample",
- #'header': r"\n*\\documentclass\s*(\[.*?\])?",
- #'ly2dvi': no_match,
- #'multicols': r"(?P<code>\\(?P<be>begin|end)\s*{multicols}({(?P<num>\d+)?})?)",
- #'numcols': r"(?P<code>\\(?P<num>one|two)column)",
- #'usepackage-graphics': r"\usepackage\s*{graphics}",
- 'include': r'(?m)^[^%\n]*?(?P<match>\\input{(?P<filename>[^}]+)})',
- 'lilypond' : r'(?m)^[^%\n]*?(?P<match>\\lilypond\s*(\[(?P<options>.*?)\])?\s*{(?P<code>.*?)})',
- 'lilypond-block': r"(?sm)^[^%\n]*?(?P<match>\\begin\s*(\[(?P<options>.*?)\])?\s*{lilypond}(?P<code>.*?)\\end{lilypond})",
- 'lilypond-file': r'(?m)^[^%\n]*?(?P<match>\\lilypondfile\s*(\[(?P<options>.*?)\])?\s*\{(?P<filename>.+)})',
- 'multiline-comment': no_match,
- 'singleline-comment': r"(?m)^.*?(?P<match>(?P<code>^%.*$\n+))",
- 'verb': r"(?P<code>\\verb(?P<del>.).*?(?P=del))",
- 'verbatim': r"(?s)(?P<code>\\begin\s*{verbatim}.*?\\end{verbatim})",
- },
-
- TEXINFO: {
- #'header': no_match,
- #'landscape': no_match,
- #'multicols': no_match,
- #'numcols': no_match,
- 'include': '(?m)^[^%\n]*?(?P<match>@include\s+(?P<filename>\S*))',
- 'lilypond' : '(?m)^(?P<match>@lilypond(\[(?P<options>[^]]*)\])?{(?P<code>.*?)})',
- 'lilypond-block': r'''(?ms)^(?P<match>@lilypond(\[(?P<options>[^]]*)\])?\s(?P<code>.*?)@end lilypond)\s''',
- 'lilypond-file': '(?m)^(?P<match>@lilypondfile(\[(?P<options>[^]]*)\])?{(?P<filename>[^}]+)})',
- 'multiline-comment': r"(?sm)^\s*(?!@c\s+)(?P<code>@ignore\s.*?@end ignore)\s",
- 'singleline-comment': r"(?m)^.*?(?P<match>(?P<code>@c([ \t][^\n]*|)\n))",
- 'verb': r'''(?P<code>@code{.*?})''',
- 'verbatim': r'''(?s)(?P<code>@example\s.*?@end example\s)''',
- },
- }
-
-format_res = {
- HTML: {
- 'option-sep' : '\s*',
- 'intertext': r',?\s*intertext=\".*?\"',
- },
- LATEX: {
- 'intertext': r',?\s*intertext=\".*?\"',
- 'option-sep' : ',\s*',
- },
- TEXINFO: {
- 'intertext': r',?\s*intertext=\".*?\"',
- 'option-sep' : ',\s*',
- },
- }
-
-NOTES = 'body'
-PREAMBLE = 'preamble'
-PAPER = 'paper'
-
-ly_options = {
- NOTES: {
- #'xrelative': r'''\relative #(ly:make-pitch %(relative)s 0 0)''',
- 'relative': r'''\relative c%(relative_quotes)s''',
- },
- PAPER: {
- 'indent' : r'''
- indent = %(indent)s''',
- 'linewidth' : r'''
- linewidth = %(linewidth)s''',
- 'noindent' : r'''
- indent = 0.0\mm''',
- 'notime' : r'''
- \translator {
- \StaffContext
- \remove Time_signature_engraver
- }''',
- 'raggedright' : r'''
- indent = 0.0\mm
- raggedright = ##t''',
- },
- PREAMBLE: {
- 'staffsize': r'''
-#(set-global-staff-size %(staffsize)s)''',
- },
- }
-
-output = {
- HTML : {
- AFTER: '',
- BEFORE: '',
- OUTPUT: r'''<img align="center" valign="center"
-border="0" src="%(base)s.png" alt="[picture of music]">''',
- VERBATIM: r'''<pre>
-%(verb)s</pre>''',
- },
-
- LATEX : {
- AFTER: '',
- BEFORE: '',
- OUTPUT: r'''{\parindent 0pt
-\catcode`\@=12
-\ifx\preLilyPondExample\preLilyPondExample\fi
-\def\lilypondbook{}
-\input %(base)s.tex
-\ifx\preLilyPondExample\postLilyPondExample\fi
-\catcode`\@=0}''',
- VERBATIM: r'''\begin{verbatim}
-%(verb)s\end{verbatim}
-''',
- },
-
- TEXINFO : {
- BEFORE: '',
- AFTER: '',
- VERBATIM: r'''@example
-%(verb)s@end example''',
-
- },
-
- }
-
-PREAMBLE_LY = r'''%% Generated by %(program_name)s
-%% Options: [%(option_string)s]
-%(preamble_string)s
-\paper {%(paper_string)s
-}
-'''
-
-FRAGMENT_LY = r'''\score{
- \notes%(notes_string)s{
- %(code)s }
-}'''
-FULL_LY = '%(code)s'
-
-def classic_lilypond_book_compatibility (o):
- if o == 'singleline':
- return 'raggedright'
- m = re.search ('relative\s*([-0-9])', o)
- if m:
- return 'relative=%s' % m.group (1)
- m = re.match ('([0-9]+)pt', o)
- if m:
- return 'staffsize=%s' % m.group (1)
- m = re.match ('indent=([-.0-9]+)(cm|in|mm|pt)', o)
- if m:
- f = float (m.group (1))
- return 'indent=%f\\%s' % (f, m.group (2))
- m = re.match ('linewidth=([-.0-9]+)(cm|in|mm|pt)', o)
- if m:
- f = float (m.group (1))
- return 'linewidth=%f\\%s' % (f, m.group (2))
- return None
-
-def compose_ly (code, option_string):
- options = []
- # urg
- for i in default_ly_options.keys ():
- options.append (i)
- vars ()[i] = default_ly_options[i]
-
- if option_string:
- options = options + split_options (option_string)
-
- m = re.search (r'''\\score''', code)
- if not m and (not options \
- or not 'nofragment' in options \
- or 'fragment' in options):
- options.append ('raggedright')
- body = FRAGMENT_LY
- else:
- body = FULL_LY
-
- # defaults
- relative = 0
- staffsize = '16'
-
- notes_options = []
- paper_options = []
- preamble_options = []
- for i in options:
- c = classic_lilypond_book_compatibility (i)
- if c:
- ly.warning (_ ("deprecated ly-option used: %s" % i))
- ly.warning (_ ("compatibility mode translation: %s" \
- % c))
- i = c
-
- if string.find (i, '=') > 0:
- key, value = string.split (i, '=')
- # hmm
- vars ()[key] = value
- else:
- key = i
-
- if key in ly_options[NOTES].keys ():
- notes_options.append (ly_options[NOTES][key])
- elif key in ly_options[PREAMBLE].keys ():
- preamble_options.append (ly_options[PREAMBLE][key])
- elif key in ly_options[PAPER].keys ():
- paper_options.append (ly_options[PAPER][key])
- elif key not in ('fragment', 'nofragment',
- 'relative', 'verbatim'):
- ly.warning (_("ignoring unknown ly option: %s") % i)
-
- relative_quotes = (",,,", ",,", ",", "", "'", "''", "'''")[relative-3]
- program_name = __main__.program_name
- notes_string = string.join (notes_options, '\n ') % vars ()
- paper_string = string.join (paper_options, '\n ') % vars ()
- preamble_string = string.join (preamble_options, '\n ') % vars ()
- return (PREAMBLE_LY + body) % vars ()
-
-
-# BARF
-# use lilypond-bin for latex (.lytex) books,
-# and lilypond --preview for html, texinfo books?
-def to_eps (file):
- cmd = r'latex "\nonstopmode \input %s"' % file
- # Ugh. (La)TeX writes progress and error messages on stdout
- # Redirect to stderr
- cmd = '(( %s >&2 ) >&- )' % cmd
- ly.system (cmd)
- ly.system ('dvips -Ppdf -u+lilypond.map -E -o %s.eps %s' \
- % (file, file))
-
-def find_file (name):
- for i in include_path:
- full = os.path.join (i, name)
- if os.path.exists (full):
- return full
- ly.error (_ ('file not found: %s\n' % name))
- ly.exit (1)
- return ''
-
-def verbatim_html (s):
- return re.sub ('>', '>',
- re.sub ('<', '<',
- re.sub ('&', '&', s)))
-
-def verbatim_texinfo (s):
- return re.sub ('{', '@{',
- re.sub ('}', '@}',
- re.sub ('@', '@@', s)))
-
-def split_options (option_string):
- return re.split (format_res[format]['option-sep'], option_string)
-
-
-## make index static of Snippet?
-index = 0
-
-class Snippet:
- def __init__ (self, type, source, index, match):
- self.type = type
- self.source = source
- self.index = index
- self.match = match
- self.hash = 0
-
- def start (self, s):
- return self.index + self.match.start (s)
-
- def end (self, s):
- return self.index + self.match.end (s)
-
- def substring (self, s):
- return self.source[self.start (s):self.end (s)]
-
- def ly (self):
- s = ''
- if self.type == 'lilypond-block' or self.type == 'lilypond':
- s = self.substring ('code')
- elif self.type == 'lilypond-file':
- name = self.substring ('filename')
- s = open (find_file (name)).read ()
- return s
-
- def full_ly (self):
- s = self.ly ()
- if s:
- return compose_ly (s, self.match.group ('options'))
- return ''
-
- def get_hash (self):
- if not self.hash:
- self.hash = abs (hash (self.ly ()))
- if not self.hash:
- print 'TYPE:: ' + self.type
- print 'CODE:: ' + self.substring (0)
- raise 'URG'
- return self.hash
-
- def basename (self):
- if use_hash_p:
- return 'lily-%d' % self.get_hash ()
- raise 'to be done'
-
- def write_ly (self):
- if self.type == 'lilypond-block' or self.type == 'lilypond'\
- or self.type == 'lilypond-file':
- h = open (self.basename () + '.ly', 'w')
- h.write (self.full_ly ())
-
- def output_html (self):
- base = self.basename ()
- option_string = self.match.group ('options')
- if option_string and VERBATIM in split_options (option_string)\
- and format == HTML:
- verb = verbatim_html (self.substring ('code'))
- h.write (output[HTML][VERBATIM] % vars ())
- h.write (output[HTML][BEFORE])
- h.write (output[HTML][OUTPUT] % vars ())
- h.write (output[HTML][AFTER])
-
- def output_latex (self):
- option_string = self.match.group ('options')
- if option_string and VERBATIM in split_options (option_string)\
- and format == LATEX:
- verb = self.substring ('code')
- h.write (output[LATEX][VERBATIM] % vars ())
- h.write (output[LATEX][BEFORE])
- base = self.basename ()
- h.write (output[LATEX][OUTPUT] % vars ())
- h.write (output[LATEX][AFTER])
-
- def output_texinfo (self):
- option_string = self.match.group ('options')
- if option_string and VERBATIM in split_options (option_string):
- verb = verbatim_texinfo (self.substring ('code'))
- h.write (output[TEXINFO][VERBATIM] % vars ())
- h.write ('\n@tex\n')
- self.output_latex ()
- h.write ('\n@end tex\n')
-
- h.write ('\n@html\n')
- self.output_html ()
- h.write ('\n@end html\n')
-
- def outdated_p (self):
- if self.type != 'lilypond-block' and self.type != 'lilypond'\
- and self.type != 'lilypond-file':
- return None
- base = self.basename ()
- if os.path.exists (base + '.ly') \
- and os.path.exists (base + '.tex') \
- and (use_hash_p \
- or self.ly () == open (base + '.ly').read ()):
- # TODO: something smart with target formats
- # (ps, png) and m/ctimes
- return None
- return self
-
- def filter_code (self):
- global index
- # Hmm, why is verbatim's group called 'code'; rename to 'verb'?
- #if snippet.match.group ('code'):
- # urg
- if self.type == 'lilypond' or self.type == 'lilypond-block':
- h.write (self.source[index:self.start ('code')])
- h.write (run_filter (self.substring ('code')))
- h.write (self.source[self.end ('code'):self.end (0)])
- else:
- h.write (self.source[index:self.end (0)])
- index = self.end (0)
-
- def compile_output (self):
- global index
- # Hmm, why is verbatim's group called 'code'; rename to 'verb'?
- # if snippet.match.group ('code'):
- # urg
- if self.type == 'lilypond' \
- or self.type == 'lilypond-block'\
- or self.type == 'lilypond-file':
- h.write (self.source[index:self.start (0)])
- snippet_output = eval ("Snippet.output_" + format)
- snippet_output (self)
- elif self.type == 'include':
- h.write (self.source[index:self.start ('filename')])
- base = os.path.splitext (self.substring ('filename'))[0]
- h.write (base + format2ext[format])
- h.write (self.source[self.end ('filename'):self.end (0)])
- else:
- h.write (self.source[index:self.end (0)])
- index = self.end (0)
-
-def find_toplevel_snippets (s, types):
- res = {}
- for i in types:
- res[i] = ly.re.compile (snippet_res[format][i])
-
- snippets = []
- index = 0
- found = {}.fromkeys (types)
- while 1:
- first = 0
- endex = 1 << 30
- for i in types:
- if not found[i] or found[i].start (0) < index:
- found[i] = 0
- m = res[i].search (s[index:endex])
- if m:
- found[i] = Snippet (i, s, index, m)
- if found[i] \
- and (not first \
- or found[i].start (0) < found[first].start (0)):
- first = i
- endex = found[first].start (0)
- if not first:
- break
- snippets.append (found[first])
- index = found[first].end (0)
-
- return snippets
-
-def filter_pipe (input, cmd):
- if verbose_p:
- ly.progress (_ ("Opening filter `%s\'") % cmd)
-
- stdin, stdout, stderr = os.popen3 (cmd)
- stdin.write (input)
- status = stdin.close ()
-
- if not status:
- status = 0
- output = stdout.read ()
- status = stdout.close ()
- error = stderr.read ()
-
- if not status:
- status = 0
- signal = 0x0f & status
- if status or (not output and error):
- exit_status = status >> 8
- ly.error (_ ("`%s\' failed (%d)") % (cmd, exit_status))
- ly.error (_ ("The error log is as follows:"))
- sys.stderr.write (error)
- sys.stderr.write (stderr.read ())
- ly.exit (status)
-
- if verbose_p:
- ly.progress ('\n')
-
- return output
-
-def run_filter (s):
- return filter_pipe (s, filter_cmd)
-
-def process_snippets (cmd, snippets):
- names = filter (lambda x:x, map (Snippet.basename, snippets))
- if names:
- ly.system (string.join ([cmd] + names))
-
- if format == HTML or format == TEXINFO:
- for i in names:
- to_eps (i)
- ly.make_ps_images (i + '.eps', resolution=110)
-
-LATEX_DOCUMENT = r'''
-%(preamble)s
-\begin{document}
-\typeout{textwidth=\the\textwidth}
-\typeout{columnsep=\the\columnsep}
-\makeatletter\if@twocolumn\typeout{columns=2}\fi\makeatother
-\end{document}
-'''
-#need anything else besides textwidth?
-def get_latex_textwidth (source):
- m = re.search (r'''(?P<preabmle>\\begin\s*{document})''', source)
- preamble = source[:m.start (0)]
- latex_document = LATEX_DOCUMENT % vars ()
- parameter_string = filter_pipe (latex_document, latex_filter_cmd)
-
- columns = 0
- m = re.search ('columns=([0-9.]*)', parameter_string)
- if m:
- columns = string.atoi (m.group (1))
-
- columnsep = 0
- m = re.search ('columnsep=([0-9.]*)pt', parameter_string)
- if m:
- columnsep = string.atof (m.group (1))
-
- textwidth = 0
- m = re.search('textwidth=([0-9.]*)pt', parameter_string)
- if m:
- textwidth = string.atof (m.group (1))
- if columns:
- textwidth = (textwidth - columnsep) / columns
-
- return textwidth
-
-
-ext2format = {
- '.html' : HTML,
- '.itely' : TEXINFO,
- '.lytex' : LATEX,
- '.tely' : TEXINFO,
- '.tex': LATEX,
- '.texi' : TEXINFO,
- '.texinfo' : TEXINFO,
- '.xml' : HTML,
- }
-
-format2ext = {
- HTML: '.html',
- #TEXINFO: '.texinfo',
- TEXINFO: '.texi',
- LATEX: '.tex',
- }
-
-def do_file (input_filename):
- #ugh
- global format
- if not format:
- e = os.path.splitext (input_filename)[1]
- if e in ext2format.keys ():
- #FIXME
- format = ext2format[e]
- else:
- ly.error (_ ("cannot determine format for: %s" \
- % input_filename))
-
- ly.progress (_ ("Reading %s...") % input_filename)
- if not input_filename or input_filename == '-':
- ih = sys.stdin
- else:
- ih = open (input_filename)
- source = ih.read ()
- ly.progress ('\n')
-
- ly.progress (_ ("Dissecting..."))
- #snippets = find_toplevel_snippets (source, snippet_res[format].keys ())
- snippet_types = (
- 'lilypond-block',
- 'verb',
- 'verbatim',
- 'singleline-comment',
- 'multiline-comment',
- 'lilypond-file',
- 'include',
- 'lilypond', )
-
- snippets = find_toplevel_snippets (source, snippet_types)
- ly.progress ('\n')
-
- global h
- if output_name == '-' or not output_name:
- h = sys.stdout
- output_filename = '-'
- else:
- if not os.path.isdir (output_name):
- os.mkdir (output_name, 0777)
- if input_filename == '-':
- input_base = 'stdin'
- else:
- input_base = os.path.splitext (input_filename)[0]
- output_filename = output_name + '/' + input_base \
- + format2ext[format]
- h = open (output_filename, 'w')
- os.chdir (output_name)
-
- global default_ly_options
- textwidth = 0
- if format == LATEX and LINEWIDTH not in default_ly_options.keys ():
- textwidth = get_latex_textwidth (source)
- default_ly_options[LINEWIDTH] = '''%.0f\pt''' % textwidth
-
- global index
- if filter_cmd:
- index = 0
- map (Snippet.filter_code, snippets)
- h.write (source[index:])
- elif process_cmd:
- outdated = filter (lambda x:x,
- map (Snippet.outdated_p, snippets))
- ly.progress (_ ("Writing snippets..."))
- map (Snippet.write_ly, snippets)
- ly.progress ('\n')
-
- if outdated:
- ly.progress (_ ("Processing..."))
- process_snippets (process_cmd, outdated)
- else:
- ly.progress (_ ("All snippets are up to date..."))
- ly.progress ('\n')
-
- ly.progress (_ ("Compiling %s...") % output_filename)
- index = 0
- map (Snippet.compile_output, snippets)
- h.write (source[index:])
- ly.progress ('\n')
-
- if h != sys.stdout:
- h.close ()
-
- def process_include (snippet):
- os.chdir (original_dir)
- name = snippet.substring ('filename')
- ly.progress (_ ('Processing include: %s') % name)
- ly.progress ('\n')
- do_file (name)
-
- map (process_include, filter (lambda x: x.type == 'include', snippets))
-
-def do_options ():
- global format, output_name
- global filter_cmd, process_cmd, verbose_p
-
- (sh, long) = ly.getopt_args (option_definitions)
- try:
- (options, files) = getopt.getopt (sys.argv[1:], sh, long)
- except getopt.error, s:
- sys.stderr.write ('\n')
- ly.error (_ ("getopt says: `%s\'" % s))
- sys.stderr.write ('\n')
- ly.help ()
- ly.exit (2)
-
- for opt in options:
- o = opt[0]
- a = opt[1]
-
- if 0:
- pass
- elif o == '--version' or o == '-v':
- ly.identify (sys.stdout)
- sys.exit (0)
- elif o == '--verbose' or o == '-V':
- verbose_p = 1
- elif o == '--filter' or o == '-F':
- filter_cmd = a
- process_cmd = 0
- elif o == '--format' or o == '-f':
- format = a
- if a == 'texi-html' or a == 'texi':
- format = TEXINFO
- elif o == '--help' or o == '-h':
- ly.help ()
- sys.exit (0)
- elif o == '--include' or o == '-I':
- include_path.append (os.path.join (original_dir,
- ly.abspath (a)))
- elif o == '--output' or o == '-o':
- output_name = a
- elif o == '--outdir':
- output_name = a
- elif o == '--process' or o == '-P':
- process_cmd = a
- filter_cmd = 0
- elif o == '--warranty' or o == '-w':
- if 1 or status:
- ly.warranty ()
- sys.exit (0)
- return files
-
-def main ():
- files = do_options ()
- ly.identify (sys.stderr)
- ly.setup_environment ()
- if files:
- do_file (files[0])
-
-if __name__ == '__main__':
- main ()
#!@PYTHON@
-# vim: set noexpandtab:
-"""
-
- TODO:
- * junk --outdir for--output
- * Figure out clean set of options.
- *
- * texinfo: add support for @pagesize
-
- todo: dimension handling (all the x2y) is clumsy. (tca: Thats
- because the values are taken directly from texinfo.tex,
- geometry.sty and article.cls. Give me a hint, and I'll
- fix it.)
-
-
- TODO: magnification support should also work for texinfo -> html: eg. add as option to dvips.
-
-
-
- This is a slightly hairy program. The general approach is as follows
- The input string is chopped up in chunks, i.e. , a list of tuples
-
- with the format (TAG_STR, MAIN_STR, OPTIONS, TODO, BASE)
-
- This list is built step by step: first ignore and verbatim commands
- are handled, delivering a list of chunks.
-
- then all chunks containing lilypond commands are chopped up
-
- when all chunks have their final form, all bodies from lilypond blocks are
- extracted, and if applicable, written do disk and run through lilypond.
-
-
-tags supported
-
- ignore
- lilypond
- input
- verb
- verbatim
- multicols
- numcols
-
-
-
-
-"""
-
-# This is was the idea for handling of comments:
-# Multiline comments, @ignore .. @end ignore is scanned for
-# in read_doc_file, and the chunks are marked as 'ignore', so
-# lilypond-book will not touch them any more. The content of the
-# chunks are written to the output file. Also 'include' and 'input'
-# regex has to check if they are commented out.
-#
-
-# Then it is scanned for 'lilypond', 'lilypond-file' and 'lilypond-block'.
-# These three regex's has to check if they are on a commented line,
-# % for latex, @c for texinfo.
-#
-# Then lines that are commented out with % (latex) and @c (Texinfo)
-# are put into chunks marked 'ignore'. This cannot be done before
-# searching for the lilypond-blocks because % is also the comment character
-# for lilypond.
-#
-# The the rest of the rexeces are searched for. They don't have to test
-# if they are on a commented out line.
+'''
+TODO:
+ ly-options: intertext, quote ?
+ --linewidth?
+ eps in latex?
+ check latex parameters, twocolumn
+ multicolumn?
+ papersizes?
+ ly2dvi/notexidoc?
+
+Example usage:
+
+test:
+ filter-lilypond-book --filter="tr '[a-z]' '[A-Z]'" BOOK
+
+convert-ly on book:
+ filter-lilypond-book --filter="convert-ly --no-version --from=1.6.11 -" BOOK
+
+classic lilypond-book:
+ filter-lilypond-book --process="lilypond-bin" BOOK.tely
+
+ must substitute:
+ @mbinclude foo.itely -> @include foo.itely
+ \mbinput -> \input
+
+'''
-import glob
-import stat
import string
-
+import __main__
################################################################
# Users of python modules should include this snippet
global _;_=ly._
global re;re = ly.re
+
# lilylib globals
program_version = '@TOPLEVEL_VERSION@'
program_name = 'lilypond-book'
original_dir = os.getcwd ()
-preview_resolution = 90
+help_summary = _ ("""Process LilyPond snippets in hybrid HTML, LaTeX or texinfo document. Example usage:
+
+ filter-lilypond-book --filter="tr '[a-z]' '[A-Z]'" BOOK
+ filter-lilypond-book --filter="convert-ly --no-version --from=2.0.0 -" BOOK
+ filter-lilypond-book --process='lilypond-bin -I include' BOOK
-## FIXME
-## do -P or -p by default?
-##help_summary = _ ("Run LilyPond using LaTeX for titling")
-help_summary = _ ("Process LilyPond snippets in hybrid html, LaTeX or texinfo document")
-copyright = ('Tom Cato Amundsen <tca@gnu.org>',
+""")
+
+copyright = ('Jan Nieuwenhuizen <janneke@gnu.org>>',
'Han-Wen Nienhuys <hanwen@cs.uu.nl>')
option_definitions = [
(_ ("EXT"), 'f', 'format', _ ("use output format EXT (texi [default], texi-html, latex, html)")),
- (_ ("DIM"), '', 'default-music-fontsize', _ ("default fontsize for music. DIM is assumed to be in points")),
- (_ ("DIM"), '', 'default-lilypond-fontsize', _ ("deprecated, use --default-music-fontsize")),
- (_ ("OPT"), '', 'extra-options', _ ("pass OPT quoted to the lilypond command line")),
- (_ ("DIM"), '', 'force-music-fontsize', _ ("force fontsize for all inline lilypond. DIM is assumed to be in points")),
- (_ ("DIM"), '', 'force-lilypond-fontsize', _ ("deprecated, use --force-music-fontsize")),
+ (_ ("FILTER"), 'F', 'filter', _ ("pipe snippets through FILTER [convert-ly -n -]")),
('', 'h', 'help', _ ("print this help")),
- (_ ("DIR"), 'I', 'include', _ ("include path")),
- ('', 'M', 'dependencies', _ ("write dependencies")),
- (_ ("PREF"), '', 'dep-prefix', _ ("prepend PREF before each -M dependency")),
- ('', 'n', 'no-lily', _ ("don't run lilypond")),
- ('', '', 'no-pictures', _ ("don't generate pictures")),
- ('', '', 'no-music', _ ("strip all lilypond blocks from output")),
- (_ ("FILE"), 'o', 'outname', _ ("filename main output file")),
- (_ ("FILE"), '', 'outdir', _ ("where to place generated files")),
- (_ ('RES'), '', 'preview-resolution',
- _ ("set the resolution of the preview to RES")),
+ (_ ("DIR"), 'I', 'include', _ ("add DIR to include path")),
+ (_ ("COMMAND"), 'P', 'process', _ ("process ly_files using COMMAND FILE...")),
+ (_ ("DIR"), 'o', 'output', _ ("write output to DIR")),
('', 'V', 'verbose', _ ("be verbose")),
('', 'v', 'version', _ ("print version information")),
('', 'w', 'warranty', _ ("show warranty and copyright")),
]
-# format specific strings, ie. regex-es for input, and % strings for output
-
-# global variables
-
-include_path = [os.getcwd ()]
-
-#lilypond_binary = 'valgrind --suppressions=/home/hanwen/usr/src/guile-1.6.supp --num-callers=10 /home/hanwen/usr/src/lilypond/lily/out/lilypond'
-
+include_path = [ly.abspath (os.getcwd ())]
lilypond_binary = os.path.join ('@bindir@', 'lilypond-bin')
# only use installed binary when we're installed too.
lilypond_binary = 'lilypond-bin'
+use_hash_p = 1
+format = 0
+output_name = 0
+latex_filter_cmd = 'latex "\\nonstopmode \input /dev/stdin"'
+filter_cmd = 0
+process_cmd = lilypond_binary
+default_ly_options = { }
-ly2dvi_binary = os.path.join ('@bindir@', 'ly2dvi')
-
-# only use installed binary when we're installed too.
-if '@bindir@' == ('@' + 'bindir@') or not os.path.exists (lilypond_binary):
- ly2dvi_binary = 'ly2dvi'
-
-
-
-g_extra_opts = ''
-g_here_dir = os.getcwd ()
-g_dep_prefix = ''
-g_outdir = ''
-g_force_music_fontsize = 0
-g_do_pictures = 1
-g_do_music = 1
-g_make_html = 0
-
-format = ''
-g_run_lilypond = 1
-no_match = 'a\ba'
+AFTER = 'after'
+BEFORE = 'before'
+HTML = 'html'
+LATEX = 'latex'
+LINEWIDTH = 'linewidth'
+NOTES = 'body'
+OUTPUT = 'output'
+PAPER = 'paper'
+PREAMBLE = 'preamble'
+TEXINFO = 'texinfo'
+VERBATIM = 'verbatim'
-default_music_fontsize = 16
-default_text_fontsize = 12
-paperguru = None
-################################################################
-# Dimension handling for LaTeX.
-#
-class LatexPaper:
- def __init__ (self):
- self.m_document_preamble = []
- self.m_num_cols = 1
- self.m_multicols = 1
-
- def find_latex_dims (self):
- if g_outdir:
- fname = os.path.join (g_outdir, "lily-tmp.tex")
- else:
- fname = "lily-tmp.tex"
- try:
- f = open (fname, "w")
- except IOError:
- error ("Error creating temporary file '%s'" % fname)
-
- for s in self.m_document_preamble:
- f.write (s)
- f.write (r"""
-\begin{document}
-\typeout{---}
-\typeout{\columnsep \the\columnsep}
-\typeout{\textwidth \the\textwidth}
-\typeout{---}
-\end{document}
- """)
- f.close ()
- re_dim = re.compile (r"\\(\w+)\s+(\d+\.\d+)")
-
- cmd = "latex '\\nonstopmode \input %s'" % fname
- # Ugh. (La)TeX writes progress and error messages on stdout
- # Redirect to stderr
- cmd = '(( %s >&2 ) >&- )' % cmd
- status = ly.system (cmd, ignore_error = 1)
- signal = 0xf & status
- exit_status = status >> 8
-
- if status:
- ly.error (_ ("LaTeX failed."))
- ly.error (_ ("The error log is as follows:"))
-
- #URG see lilypond
- try:
- lns = open ('lily-tmp.log').readlines ()
- except:
- lns = ''
- countdown = -3
- for ln in lns:
- sys.stderr.write (ln)
- if re.match ('^!', ln):
- countdown = 3
-
- if countdown == 0:
- break
-
- if countdown > 0:
- countdown = countdown -1
-
- sys.stderr.write (" ... (further messages elided)...\n")
- sys.exit (1)
-
- lns = open ('lily-tmp.log').readlines ()
- for ln in lns:
- ln = string.strip (ln)
- m = re_dim.match (ln)
- if m:
- if m.groups ()[0] in ('textwidth', 'columnsep'):
- self.__dict__['m_%s' % m.groups ()[0]] = float (m.groups ()[1])
-
- try:
- os.remove (fname)
- os.remove (os.path.splitext (fname)[0]+".aux")
- os.remove (os.path.splitext (fname)[0]+".log")
- except:
- pass
-
- if not self.__dict__.has_key ('m_textwidth'):
- raise 'foo!'
-
- def get_linewidth (self):
- if self.m_num_cols == 1:
- w = self.m_textwidth
- else:
- w = (self.m_textwidth - self.m_columnsep)/2
- if self.m_multicols > 1:
- return (w - self.m_columnsep* (self.m_multicols-1)) \
- / self.m_multicols
- return w
-
-
-class HtmlPaper:
- def __init__ (self):
- self.m_papersize = 'letterpaper'
- self.m_fontsize = 12
- def get_linewidth (self):
- return html_linewidths[self.m_papersize][self.m_fontsize]
-
-class TexiPaper:
- def __init__ (self):
- self.m_papersize = 'letterpaper'
- self.m_fontsize = 12
- def get_linewidth (self):
- return texi_linewidths[self.m_papersize][self.m_fontsize]
-
-def mm2pt (x):
- return x * 2.8452756
-def in2pt (x):
- return x * 72.26999
-def em2pt (x, fontsize = 10):
- return {10: 10.00002, 11: 10.8448, 12: 11.74988}[fontsize] * x
-def ex2pt (x, fontsize = 10):
- return {10: 4.30554, 11: 4.7146, 12: 5.16667}[fontsize] * x
-
-def pt2pt (x):
- return x
-
-dimension_conversion_dict ={
- 'mm': mm2pt,
- 'cm': lambda x: mm2pt (10*x),
- 'in': in2pt,
- 'em': em2pt,
- 'ex': ex2pt,
- 'pt': pt2pt
- }
-
-# Convert numeric values, with or without specific dimension, to floats.
-# Keep other strings
-def conv_dimen_to_float (value):
- if type (value) == type (""):
- m = re.match ("([0-9.]+)(cm|in|pt|mm|em|ex)",value)
- if m:
- unit = m.group (2)
- num = string.atof (m.group (1))
- conv = dimension_conversion_dict[m.group (2)]
-
- value = conv (num)
-
- elif re.match ("^[0-9.]+$",value):
- value = float (value)
-
- return value
-
-texi_linewidths = {
- 'afourpaper': {12: mm2pt (160)},
- 'afourwide': {12: in2pt (6.5)},
- 'afourlatex': {12: mm2pt (150)},
- 'smallbook': {12: in2pt (5)},
- 'letterpaper': {12: in2pt (6)}}
-
-html_linewidths = {
- 'afourpaper': {12: mm2pt (160)},
- 'afourwide': {12: in2pt (6.5)},
- 'afourlatex': {12: mm2pt (150)},
- 'smallbook': {12: in2pt (5)},
- 'letterpaper': {12: in2pt (6)}}
-
-
-################################################################
-# How to output various structures.
-output_dict= {
-
-
- 'html' : {
-
- 'output-filename' : r'''
-<!-- %s >
-<a href="%s">
-<pre>%s</pre></a>:''',
- 'output-lilypond-fragment': '''<lilypond%s>
-\context Staff\context Voice{ %s }
-</lilypond>''',
- 'output-noinline': r'''
-<!-- generated: %(fn)s.png !-->
-''',
- ## maybe <hr> ?
- 'pagebreak': None,
- # Verbatim text is always finished with \n. FIXME: For HTML,
- # this newline should be removed.
- 'output-verbatim': r'''<pre>
-%s</pre>''',
- # Verbatim text is always finished with \n. FIXME: For HTML,
- # this newline should be removed.
- 'output-small-verbatim': r'''<font size=-1><pre>
-%s</pre></font>''',
- ## Ugh we need to differentiate on origin:
- ## lilypond-block origin wants an extra <p>, but
- ## inline music doesn't.
- ## possibly other center options?
- 'output-html': r'''
-%(htmlimages)s''',
- },
-
-
- 'latex': {
-
- 'output-lilypond-fragment' : r'''\begin[singleline,%s]{lilypond}
- \context Voice{
- %s
- }
-\end{lilypond}''',
- 'output-filename' : r'''\verb+%s+:\\
-%% %s
-%% %s
-''',
-
- # verbatim text is always finished with \n
- 'output-verbatim': r'''\begin{verbatim}
-%s\end{verbatim}
-''',
- # verbatim text is always finished with \n
- 'output-small-verbatim': r'''{\small\begin{verbatim}
-%s\end{verbatim}}
-''',
- 'output-default-post': "\\def\postLilyPondExample{}\n",
- 'output-default-pre': "\\def\preLilyPondExample{}\n",
- 'usepackage-graphics': '\\usepackage{graphics}\n',
- 'output-eps': '\\noindent\includegraphics{%(fn)s}',
- 'output-noinline': r'''
-%% generated: %(fn)s.eps
-''',
- 'output-latex-quoted': r'''{\preLilyPondExample
-\def\lilypondbook{}
-\input %(fn)s.tex
-\postLilyPondExample}''',
- 'output-latex-noquote': r'''{\parindent 0pt
-\preLilyPondExample
-\def\lilypondbook{}
-\input %(fn)s.tex
-\postLilyPondExample}''',
- 'pagebreak': r'\pagebreak',
- },
-
-
- 'texi' : {
-
-
- 'output-filename' : r'''
-@ifnothtml
-@file{%s}:@*
-@end ifnothtml
-@ifhtml
-@uref{%s,@file{%s}}
-@end ifhtml
-''',
- 'output-lilypond-fragment': '''@lilypond[%s]
-\context Staff\context Voice{ %s }
-@end lilypond ''',
- 'output-noinline': r'''
-@c generated: %(fn)s.png
-''',
- 'pagebreak': None,
- # verbatim text is always finished with \n
- 'output-small-verbatim': r'''@smallexample
-%s@end smallexample
-''',
- # verbatim text is always finished with \n
- 'output-verbatim': r'''@example
-%s@end example
-''',
- # do some tweaking: @ is needed in some ps stuff.
- #
- # ugh, the <p> below breaks inline images...
- 'output-texi-noquote': r'''@tex
-\catcode`\@=12
-\parindent 0pt
-\def\lilypondbook{}
-\input %(fn)s.tex
-\catcode`\@=0
-@end tex
-@html
-<p>%(htmlimages)s
-<p>
-@end html
-''',
- 'output-texi-quoted': r'''@quotation
-@tex
-\catcode`\@=12
-\def\lilypondbook{}
-\input %(fn)s.tex
-\catcode`\@=0
-@end tex
-@html
-<p>%(htmlimages)s
-<p>
-@end html
-@end quotation
-''',
- }
-
- }
-
-def output_verbatim (body, small):
- global format
- if format == 'html':
- body = re.sub ('&', '&', body)
- body = re.sub ('>', '>', body)
- body = re.sub ('<', '<', body)
- elif format == 'texi':
- # clumsy workaround for python 2.2 pre bug.
- body = re.sub ('@', '@@', body)
- body = re.sub ('{', '@{', body)
- body = re.sub ('}', '@}', body)
-
- if small:
- key = 'output-small-verbatim'
- else:
- key = 'output-verbatim'
- return get_output (key) % body
-
-
-################################################################
# Recognize special sequences in the input
-
-
-# Warning: This uses extended regular expressions. Tread with care.
-#
-# legenda
#
# (?P<name>regex) -- assign result of REGEX to NAME
# *? -- match non-greedily.
# (?m) -- multiline regex: make ^ and $ match at each line
# (?s) -- make the dot match all characters including newline
-re_dict = {
- 'html': {
- 'include': no_match,
- 'input': no_match,
- 'header': no_match,
- 'preamble-end': no_match,
- 'landscape': no_match,
- 'verbatim': r'''(?s)(?P<code><pre>\s.*?</pre>\s)''',
- 'verb': r'''(?P<code><pre>.*?</pre>)''',
- 'lilypond-file': r'(?m)(?P<match><lilypondfile(?P<options>[^>]+)?>\s*(?P<filename>[^<]+)\s*</lilypondfile>)',
- 'lilypond' : '(?m)(?P<match><lilypond((?P<options>[^:]*):)(?P<code>.*?)/>)',
- 'lilypond-block': r'''(?ms)(?P<match><lilypond(?P<options>[^>]+)?>(?P<code>.*?)</lilypond>)''',
- 'option-sep' : '\s*',
- 'intertext': r',?\s*intertext=\".*?\"',
- 'multiline-comment': r"(?sm)\s*(?!@c\s+)(?P<code><!--\s.*?!-->)\s",
- 'singleline-comment': no_match,
- 'numcols': no_match,
- 'multicols': no_match,
- 'ly2dvi': r'(?m)(?P<match><ly2dvifile(?P<options>[^>]+)?>\s*(?P<filename>[^<]+)\s*</ly2dvifile>)',
- },
-
- 'latex': {
- 'input': r'(?m)^[^%\n]*?(?P<match>\\mbinput{?([^}\t \n}]*))',
- 'include': r'(?m)^[^%\n]*?(?P<match>\\mbinclude{(?P<filename>[^}]+)})',
- 'option-sep' : ',\s*',
- 'header': r"\n*\\documentclass\s*(\[.*?\])?",
- 'preamble-end': r'(?P<code>\\begin\s*{document})',
- 'verbatim': r"(?s)(?P<code>\\begin\s*{verbatim}.*?\\end{verbatim})",
- 'verb': r"(?P<code>\\verb(?P<del>.).*?(?P=del))",
- 'lilypond-file': r'(?m)^[^%\n]*?(?P<match>\\lilypondfile\s*(\[(?P<options>.*?)\])?\s*\{(?P<filename>.+)})',
- 'lilypond' : r'(?m)^[^%\n]*?(?P<match>\\lilypond\s*(\[(?P<options>.*?)\])?\s*{(?P<code>.*?)})',
- 'lilypond-block': r"(?sm)^[^%\n]*?(?P<match>\\begin\s*(\[(?P<options>.*?)\])?\s*{lilypond}(?P<code>.*?)\\end{lilypond})",
- 'def-post-re': r"\\def\\postLilyPondExample",
- 'def-pre-re': r"\\def\\preLilyPondExample",
- 'usepackage-graphics': r"\usepackage\s*{graphics}",
- 'intertext': r',?\s*intertext=\".*?\"',
- 'multiline-comment': no_match,
- 'singleline-comment': r"(?m)^.*?(?P<match>(?P<code>^%.*$\n+))",
- 'numcols': r"(?P<code>\\(?P<num>one|two)column)",
- 'multicols': r"(?P<code>\\(?P<be>begin|end)\s*{multicols}({(?P<num>\d+)?})?)",
- 'ly2dvi': no_match,
-
- },
-
- # why do we have distinction between @mbinclude and @include?
-
- 'texi': {
- 'include': '(?m)^[^%\n]*?(?P<match>@mbinclude\s+(?P<filename>\S*))',
- 'input': no_match,
- 'header': no_match,
- 'preamble-end': no_match,
- 'landscape': no_match,
- 'verbatim': r'''(?s)(?P<code>@example\s.*?@end example\s)''',
- 'verb': r'''(?P<code>@code{.*?})''',
- 'lilypond-file': '(?m)^(?P<match>@lilypondfile(\[(?P<options>[^]]*)\])?{(?P<filename>[^}]+)})',
- 'lilypond' : '(?m)^(?P<match>@lilypond(\[(?P<options>[^]]*)\])?{(?P<code>.*?)})',
- 'lilypond-block': r'''(?ms)^(?P<match>@lilypond(\[(?P<options>[^]]*)\])?\s(?P<code>.*?)@end lilypond)\s''',
- 'option-sep' : ',\s*',
- 'intertext': r',?\s*intertext=\".*?\"',
- 'multiline-comment': r"(?sm)^\s*(?!@c\s+)(?P<code>@ignore\s.*?@end ignore)\s",
- 'singleline-comment': r"(?m)^.*?(?P<match>(?P<code>@c.*$\n+))",
- 'numcols': no_match,
- 'multicols': no_match,
- 'ly2dvi': no_match,
- }
+no_match = 'a\ba'
+snippet_res = {
+ HTML: {
+ 'include': no_match,
+ 'lilypond' : '(?m)(?P<match><lilypond((?P<options>[^:]*):)(?P<code>.*?)/>)',
+ 'lilypond-block': r'''(?ms)(?P<match><lilypond(?P<options>[^>]+)?>(?P<code>.*?)</lilypond>)''',
+ 'lilypond-file': r'(?m)(?P<match><lilypondfile(?P<options>[^>]+)?>\s*(?P<filename>[^<]+)\s*</lilypondfile>)',
+ 'multiline-comment': r"(?sm)\s*(?!@c\s+)(?P<code><!--\s.*?!-->)\s",
+ 'singleline-comment': no_match,
+ 'verb': r'''(?P<code><pre>.*?</pre>)''',
+ 'verbatim': r'''(?s)(?P<code><pre>\s.*?</pre>\s)''',
+ },
+
+ LATEX: {
+ 'include': r'(?m)^[^%\n]*?(?P<match>\\input{(?P<filename>[^}]+)})',
+ 'lilypond' : r'(?m)^[^%\n]*?(?P<match>\\lilypond\s*(\[(?P<options>.*?)\])?\s*{(?P<code>.*?)})',
+ 'lilypond-block': r"(?sm)^[^%\n]*?(?P<match>\\begin\s*(\[(?P<options>.*?)\])?\s*{lilypond}(?P<code>.*?)\\end{lilypond})",
+ 'lilypond-file': r'(?m)^[^%\n]*?(?P<match>\\lilypondfile\s*(\[(?P<options>.*?)\])?\s*\{(?P<filename>.+)})',
+ 'multiline-comment': no_match,
+ 'singleline-comment': r"(?m)^.*?(?P<match>(?P<code>^%.*$\n+))",
+ 'verb': r"(?P<code>\\verb(?P<del>.).*?(?P=del))",
+ 'verbatim': r"(?s)(?P<code>\\begin\s*{verbatim}.*?\\end{verbatim})",
+ },
+
+ TEXINFO: {
+ 'include': '(?m)^[^%\n]*?(?P<match>@include\s+(?P<filename>\S*))',
+ 'lilypond' : '(?m)^(?P<match>@lilypond(\[(?P<options>[^]]*)\])?{(?P<code>.*?)})',
+ 'lilypond-block': r'''(?ms)^(?P<match>@lilypond(\[(?P<options>[^]]*)\])?\s(?P<code>.*?)@end lilypond)\s''',
+ 'lilypond-file': '(?m)^(?P<match>@lilypondfile(\[(?P<options>[^]]*)\])?{(?P<filename>[^}]+)})',
+ 'multiline-comment': r"(?sm)^\s*(?!@c\s+)(?P<code>@ignore\s.*?@end ignore)\s",
+ 'singleline-comment': r"(?m)^.*?(?P<match>(?P<code>@c([ \t][^\n]*|)\n))",
+ 'verb': r'''(?P<code>@code{.*?})''',
+ 'verbatim': r'''(?s)(?P<code>@example\s.*?@end example\s)''',
+ },
}
+format_res = {
+ HTML: {
+ 'option-sep' : '\s*',
+ 'intertext': r',?\s*intertext=\".*?\"',
+ },
+ LATEX: {
+ 'intertext': r',?\s*intertext=\".*?\"',
+ 'option-sep' : ',\s*',
+ },
+ TEXINFO: {
+ 'intertext': r',?\s*intertext=\".*?\"',
+ 'option-sep' : ',\s*',
+ },
+ }
-for r in re_dict.keys ():
- olddict = re_dict[r]
- newdict = {}
- for k in olddict.keys ():
- try:
- newdict[k] = re.compile (olddict[k])
- except:
- print 'invalid regexp: %s' % olddict[k]
-
- ## we'd like to catch and reraise a more
- ## detailed error, but alas, the exceptions
- ## changed across the 1.5/2.1 boundary.
-
- raise "Invalid re"
- re_dict[r] = newdict
-
-
-def uniq (list):
- list.sort ()
- s = list
- list = []
- for x in s:
- if x not in list:
- list.append (x)
- return list
-
-
-def get_output (name):
- return output_dict[format][name]
-
-def get_re (name):
- return re_dict[format][name]
-
-def bounding_box_dimensions (fname):
- if g_outdir:
- fname = os.path.join (g_outdir, fname)
- try:
- fd = open (fname)
- except IOError:
- error ("Error opening `%s'" % fname)
- str = fd.read ()
- s = re.search ('%%BoundingBox: ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+)', str)
- if s:
-
- gs = map (lambda x: string.atoi (x), s.groups ())
- return (int (gs[2] - gs[0] + 0.5),
- int (gs[3] - gs[1] + 0.5))
- else:
- return (0,0)
-
-def error (str):
- sys.stderr.write ("\n\n" + str + "\nExiting ... \n\n")
- raise 'Exiting.'
-
-
-def compose_full_body (body, opts):
- '''Construct the lilypond code to send to LilyPond.
- Add stuff to BODY using OPTS as options.'''
- music_size = default_music_fontsize
- if g_force_music_fontsize:
- music_size = g_force_music_fontsize
- indent = ''
- linewidth = ''
- notime = ''
- for o in opts:
- if not g_force_music_fontsize:
- m = re.match ('([0-9]+)pt', o)
- if m:
- music_size = string.atoi (m.group (1))
-
- m = re.match ('indent=([-.0-9]+)(cm|in|mm|pt)', o)
- if m:
- f = float (m.group (1))
- indent = 'indent = %f\\%s' % (f, m.group (2))
-
- m = re.match ('linewidth=([-.0-9]+)(cm|in|mm|pt)', o)
- if m:
- f = float (m.group (1))
- linewidth = 'linewidth = %f\\%s' % (f, m.group (2))
-
- if re.search ('\\\\score', body):
- is_fragment = 0
- else:
- is_fragment = 1
- if 'fragment' in opts:
- is_fragment = 1
- if 'nofragment' in opts:
- is_fragment = 0
-
- if is_fragment and not 'multiline' in opts:
- opts.append ('singleline')
-
- if 'raggedright' in opts or 'singleline' in opts:
- if not linewidth:
- linewidth = 'raggedright = ##t'
- if not indent:
- indent = 'indent = 0.0\mm'
- elif not linewidth:
- global paperguru
- l = paperguru.get_linewidth ()
- linewidth = 'linewidth = %f\pt' % l
-
- if 'noindent' in opts:
- indent = 'indent = 0.0\mm'
-
- if 'notime' in opts:
- notime = r'''
-\translator {
- \StaffContext
- \remove Time_signature_engraver
-}
-'''
-
- orig_name = ''
- for o in opts:
- m= re.search ('relative(.*)', o)
- v = 0
- if m:
- try:
- v = string.atoi (m.group (1))
- except ValueError:
- pass
-
- v = v + 1
- pitch = 'c'
- if v < 0:
- pitch = pitch + '\,' * v
- elif v > 0:
- pitch = pitch + '\'' * v
-
- body = '\\relative %s { %s }' % (pitch, body)
- m =re.search ("filename=(.*)", o)
- if m:
- orig_name = m.group (1)
-
- if is_fragment:
- body = r'''
-\score {
- \notes {
-%s
- }
-}
-''' % body
-
- opts = uniq (opts)
- optstring = string.join (opts, ' ')
- optstring = re.sub ('\n', ' ', optstring)
- body = r'''
-%% Generated automatically by: lilypond-book.py
-%% options are %s
-#(set-global-staff-size %d)
-
-\paper {
- %s
- %s
- %s
-}
-''' % (optstring, music_size, linewidth, indent, notime) + body
+ly_options = {
+ NOTES: {
+ 'relative': r'''\relative c%(relative_quotes)s''',
+ },
+ PAPER: {
+ 'indent' : r'''
+ indent = %(indent)s''',
+ 'linewidth' : r'''
+ linewidth = %(linewidth)s''',
+ 'noindent' : r'''
+ indent = 0.0\mm''',
+ 'notime' : r'''
+ \translator {
+ \StaffContext
+ \remove Time_signature_engraver
+ }''',
+ 'raggedright' : r'''
+ indent = 0.0\mm
+ raggedright = ##t''',
+ },
+ PREAMBLE: {
+ 'staffsize': r'''
+#(set-global-staff-size %(staffsize)s)''',
+ },
+ }
- if orig_name:
- body = '\\renameinput \"%s\"\n%s' % (orig_name, body)
+output = {
+ HTML : {
+ AFTER: '',
+ BEFORE: '',
+ OUTPUT: r'''<img align="center" valign="center"
+border="0" src="%(base)s.png" alt="[picture of music]">''',
+ VERBATIM: r'''<pre>
+%(verb)s</pre>''',
+ },
-
- # ughUGH not original options
- return body
-
-def scan_html_preamble (chunks):
- return
-
-def scan_latex_preamble (chunks):
- # First we want to scan the \documentclass line
- # it should be the first non-comment line.
- # The only thing we really need to know about the \documentclass line
- # is if there are one or two columns to begin with.
- idx = 0
- while 1:
- if chunks[idx][0] == 'ignore':
- idx = idx + 1
- continue
- m = get_re ('header').match (chunks[idx][1])
- if not m:
- error ("Latex documents must start with a \documentclass command")
- if m.group (1):
- options = re.split (r',\s*', m.group (1)[1:-1])
- else:
- options = []
- if 'twocolumn' in options:
- paperguru.m_num_cols = 2
- break
-
-
- # Then we add everything before \begin{document} to
- # paperguru.m_document_preamble so that we can later write this header
- # to a temporary file in find_latex_dims() to find textwidth.
- while idx < len (chunks) and chunks[idx][0] != 'preamble-end':
- if chunks[idx] == 'ignore':
- idx = idx + 1
- continue
- paperguru.m_document_preamble.append (chunks[idx][1])
- idx = idx + 1
-
- if len (chunks) == idx:
- error ("Didn't find end of preamble (\\begin{document})")
-
- paperguru.find_latex_dims ()
-
-def scan_texi_preamble (chunks):
- # this is not bulletproof..., it checks the first 10 chunks
- for c in chunks[:10]:
- if c[0] == 'input':
- for s in ('afourpaper', 'afourwide', 'letterpaper',
- 'afourlatex', 'smallbook'):
- if string.find (c[1], "@%s" % s) != -1:
- paperguru.m_papersize = s
-
-
-def scan_preamble (chunks):
- global format
- if format == 'html':
- scan_html_preamble (chunks)
- elif format == 'latex':
- scan_latex_preamble (chunks)
- elif format == 'texi':
- scan_texi_preamble (chunks)
-
-
-def completize_preamble (chunks):
- global format
- if format != 'latex':
- return chunks
- pre_b = post_b = graphics_b = None
- for chunk in chunks:
- if chunk[0] == 'preamble-end':
- break
- if chunk[0] == 'input':
- m = get_re ('def-pre-re').search (chunk[1])
- if m:
- pre_b = 1
- if chunk[0] == 'input':
- m = get_re ('def-post-re').search (chunk[1])
- if m:
- post_b = 1
-
- if chunk[0] == 'input':
- m = get_re ('usepackage-graphics').search (chunk[1])
- if m:
- graphics_b = 1
- x = 0
- while x < len (chunks) and chunks[x][0] != 'preamble-end':
- x = x + 1
-
- if x == len (chunks):
- return chunks
-
- if not pre_b:
- chunks.insert (x, ('input', get_output ('output-default-pre')))
- if not post_b:
- chunks.insert (x, ('input', get_output ('output-default-post')))
- if not graphics_b:
- chunks.insert (x, ('input', get_output ('usepackage-graphics')))
-
- return chunks
-
-
-read_files = []
-def find_file (name):
- '''
- Search the include path for NAME. If found, return the (CONTENTS, PATH) of the file.
- '''
-
- if name == '-':
- return (sys.stdin.read (), '<stdin>')
- f = None
- nm = ''
- for a in include_path:
- try:
- nm = os.path.join (a, name)
- f = open (nm)
- global read_files
- read_files.append (nm)
- break
- except IOError:
- pass
- if f:
- sys.stderr.write ("Reading `%s'\n" % nm)
- return (f.read (), nm)
- else:
- error ("File not found `%s'\n" % name)
- return ('', '')
-
-def do_ignore (match_object):
- return [('ignore', match_object.group ('code'))]
-def do_preamble_end (match_object):
- return [('preamble-end', match_object.group ('code'))]
-
-def make_verbatim (match_object):
- return [('verbatim', match_object.group ('code'))]
-
-def make_verb (match_object):
- return [('verb', match_object.group ('code'))]
-
-def do_include_file (m):
- "m: MatchObject"
- return [('input', get_output ('pagebreak'))] \
- + read_doc_file (m.group ('filename')) \
- + [('input', get_output ('pagebreak'))]
-
-def do_input_file (m):
- return read_doc_file (m.group ('filename'))
-
-def make_lilypond (m):
- if m.group ('options'):
- options = m.group ('options')
- else:
- options = ''
- return [('input', get_output ('output-lilypond-fragment') %
- (options, m.group ('code')))]
-
-def make_lilypond_file (m):
- '''
-
- Find @lilypondfile{bla.ly} occurences and substitute bla.ly
- into a @lilypond .. @end lilypond block.
-
- '''
-
- if m.group ('options'):
- options = get_re ('option-sep').split (m.group ('options'))
- else:
- options = []
- (content, nm) = find_file (m.group ('filename'))
- options.append ("filename=%s" % nm)
- (path, base) = os.path.split (nm)
+ LATEX : {
+ AFTER: '',
+ BEFORE: '',
+ OUTPUT: r'''{\parindent 0pt
+\catcode`\@=12
+\ifx\preLilyPondExample\preLilyPondExample\fi
+\def\lilypondbook{}
+\input %(base)s.tex
+\ifx\preLilyPondExample\postLilyPondExample\fi
+\catcode`\@=0}''',
+ VERBATIM: r'''\begin{verbatim}
+%(verb)s\end{verbatim}
+''',
+ },
- if path not in include_path:
- include_path.append (path)
-
- return [('lilypond', content, options)]
+ TEXINFO : {
+ BEFORE: '',
+ AFTER: '',
+ VERBATIM: r'''@example
+%(verb)s@end example''',
+ },
+
+ }
-def make_ly2dvi_block (m):
- '''
-
- Find <ly2dvifile .. >
- '''
-
- return [('ly2dvi', m.group ('filename'), m.group ('options'))]
-
-
-def make_lilypond_block (m):
- if not g_do_music:
- return []
-
- if m.group ('options'):
- options = get_re ('option-sep').split (m.group ('options'))
- else:
- options = []
- options = filter (lambda s: s != '', options)
- return [('lilypond', m.group ('code'), options)]
-
-
-def do_columns (m):
- global format
- if format != 'latex':
- return []
- if m.group ('num') == 'one':
- return [('numcols', m.group ('code'), 1)]
- if m.group ('num') == 'two':
- return [('numcols', m.group ('code'), 2)]
-
-def do_multicols (m):
- global format
- if format != 'latex':
- return []
- if m.group ('be') == 'begin':
- return [('multicols', m.group ('code'), int (m.group ('num')))]
+PREAMBLE_LY = r'''%% Generated by %(program_name)s
+%% Options: [%(option_string)s]
+%(preamble_string)s
+\paper {%(paper_string)s
+}
+'''
+
+FRAGMENT_LY = r'''\score{
+ \notes%(notes_string)s{
+ %(code)s }
+}'''
+FULL_LY = '%(code)s'
+
+def classic_lilypond_book_compatibility (o):
+ if o == 'singleline':
+ return 'raggedright'
+ m = re.search ('relative\s*([-0-9])', o)
+ if m:
+ return 'relative=%s' % m.group (1)
+ m = re.match ('([0-9]+)pt', o)
+ if m:
+ return 'staffsize=%s' % m.group (1)
+ m = re.match ('indent=([-.0-9]+)(cm|in|mm|pt)', o)
+ if m:
+ f = float (m.group (1))
+ return 'indent=%f\\%s' % (f, m.group (2))
+ m = re.match ('linewidth=([-.0-9]+)(cm|in|mm|pt)', o)
+ if m:
+ f = float (m.group (1))
+ return 'linewidth=%f\\%s' % (f, m.group (2))
+ return None
+
+def compose_ly (code, option_string):
+ options = []
+ # urg
+ for i in default_ly_options.keys ():
+ options.append (i)
+ vars ()[i] = default_ly_options[i]
+
+ if option_string:
+ options = options + split_options (option_string)
+
+ m = re.search (r'''\\score''', code)
+ if not m and (not options \
+ or not 'nofragment' in options \
+ or 'fragment' in options):
+ options.append ('raggedright')
+ body = FRAGMENT_LY
else:
- return [('multicols', m.group ('code'), 1)]
- return []
-
-def chop_chunks (chunks, re_name, func, use_match=0):
- newchunks = []
- for c in chunks:
- if c[0] == 'input':
- str = c[1]
- while str:
- m = get_re (re_name).search (str)
- if m == None:
- newchunks.append (('input', str))
- str = ''
- else:
- if use_match:
- newchunks.append (('input', str[:m.start ('match')]))
- else:
- newchunks.append (('input', str[:m.start (0)]))
- #newchunks.extend (func (m))
- # python 1.5 compatible:
- newchunks = newchunks + func (m)
- str = str [m.end (0):]
+ body = FULL_LY
+
+ # defaults
+ relative = 0
+ staffsize = '16'
+
+ notes_options = []
+ paper_options = []
+ preamble_options = []
+ for i in options:
+ c = classic_lilypond_book_compatibility (i)
+ if c:
+ ly.warning (_ ("deprecated ly-option used: %s" % i))
+ ly.warning (_ ("compatibility mode translation: %s" \
+ % c))
+ i = c
+
+ if string.find (i, '=') > 0:
+ key, value = string.split (i, '=')
+ # hmm
+ vars ()[key] = value
else:
- newchunks.append (c)
- return newchunks
+ key = i
+
+ if key in ly_options[NOTES].keys ():
+ notes_options.append (ly_options[NOTES][key])
+ elif key in ly_options[PREAMBLE].keys ():
+ preamble_options.append (ly_options[PREAMBLE][key])
+ elif key in ly_options[PAPER].keys ():
+ paper_options.append (ly_options[PAPER][key])
+ elif key not in ('fragment', 'nofragment',
+ 'relative', 'verbatim'):
+ ly.warning (_("ignoring unknown ly option: %s") % i)
+
+ relative_quotes = (",,,", ",,", ",", "", "'", "''", "'''")[relative-3]
+ program_name = __main__.program_name
+ notes_string = string.join (notes_options, '\n ') % vars ()
+ paper_string = string.join (paper_options, '\n ') % vars ()
+ preamble_string = string.join (preamble_options, '\n ') % vars ()
+ return (PREAMBLE_LY + body) % vars ()
+
+
+# BARF
+# use lilypond-bin for latex (.lytex) books,
+# and lilypond --preview for html, texinfo books?
+def to_eps (file):
+ cmd = r'latex "\nonstopmode \input %s"' % file
+ # Ugh. (La)TeX writes progress and error messages on stdout
+ # Redirect to stderr
+ cmd = '(( %s >&2 ) >&- )' % cmd
+ ly.system (cmd)
+ ly.system ('dvips -Ppdf -u+lilypond.map -E -o %s.eps %s' \
+ % (file, file))
-def determine_format (str):
- """
-
- SIDE EFFECT! This sets FORMAT and PAPERGURU
-
- """
+def find_file (name):
+ for i in include_path:
+ full = os.path.join (i, name)
+ if os.path.exists (full):
+ return full
+ ly.error (_ ('file not found: %s\n' % name))
+ ly.exit (1)
+ return ''
- global format
- if format == '':
- html = re.search ('(?i)<[dh]tml', str[:200])
- latex = re.search (r'''\\document''', str[:200])
- texi = re.search ('@node|@setfilename', str[:200])
-
- f = ''
- g = None
-
- if html and not latex and not texi:
- f = 'html'
- elif latex and not html and not texi:
- f = 'latex'
- elif texi and not html and not latex:
- f = 'texi'
- else:
- error ("can't determine format, please specify")
- format = f
-
- global paperguru
- if paperguru == None:
- if format == 'html':
- g = HtmlPaper ()
- elif format == 'latex':
- g = LatexPaper ()
- elif format == 'texi':
- g = TexiPaper ()
-
- paperguru = g
-
-
-def read_doc_file (filename):
- '''Read the input file, find verbatim chunks and do \input and \include
- '''
- (str, path) = find_file (filename)
- determine_format (str)
-
- chunks = [('input', str)]
-
- # we have to check for verbatim before doing include,
- # because we don't want to include files that are mentioned
- # inside a verbatim environment
- chunks = chop_chunks (chunks, 'verbatim', make_verbatim)
-
- chunks = chop_chunks (chunks, 'verb', make_verb)
- chunks = chop_chunks (chunks, 'multiline-comment', do_ignore)
- #ugh fix input
- chunks = chop_chunks (chunks, 'include', do_include_file, 1)
- chunks = chop_chunks (chunks, 'input', do_input_file, 1)
- return chunks
-
-
-taken_file_names = {}
-
-def unique_file_name (body):
- return 'lily-' + `abs (hash (body))`
-
-def schedule_lilypond_block (chunk):
- '''Take the body and options from CHUNK, figure out how the
- real .ly should look. The .ly is written, and scheduled in
- TODO.
-
- Return: a single chunk.
-
- The chunk pertaining to the lilypond output
- has the format (TYPE_STR, MAIN_STR, OPTIONS, TODO, BASE),
- where TODO has format [basename, extension, extension, ... ]
- '''
-
- (type, body, opts) = chunk
- assert type == 'lilypond'
- file_body = compose_full_body (body, opts)
- ## Hmm, we should hash only lilypond source, and skip the
- ## %options are ...
- ## comment line
- basename = unique_file_name (file_body)
- for o in opts:
- m = re.search ('filename="(.*?)"', o)
- if m:
- basename = m.group (1)
- if not taken_file_names.has_key (basename):
- taken_file_names[basename] = 0
- else:
- taken_file_names[basename] = taken_file_names[basename] + 1
- basename = basename + "-t%i" % taken_file_names[basename]
- update_file (file_body, os.path.join (g_outdir, basename) + '.ly')
- needed_filetypes = ['tex']
-
- if format == 'html' or g_make_html:
- needed_filetypes.append ('eps')
- needed_filetypes.append ('png')
- if 'eps' in opts and not ('eps' in needed_filetypes):
- needed_filetypes.append ('eps')
-
- pathbase = os.path.join (g_outdir, basename)
- def must_rebuild (base, ext1, ext2):
-
- f2 = base + ext2
- f1 = base + ext1
- fp2 = base + '-page1' + ext2
-
- isfile2 = os.path.isfile (f2)
+def verbatim_html (s):
+ return re.sub ('>', '>',
+ re.sub ('<', '<',
+ re.sub ('&', '&', s)))
+
+def verbatim_texinfo (s):
+ return re.sub ('{', '@{',
+ re.sub ('}', '@}',
+ re.sub ('@', '@@', s)))
+
+def split_options (option_string):
+ return re.split (format_res[format]['option-sep'], option_string)
+
+
+## make index static of Snippet?
+index = 0
+
+class Snippet:
+ def __init__ (self, type, source, index, match):
+ self.type = type
+ self.source = source
+ self.index = index
+ self.match = match
+ self.hash = 0
+
+ def start (self, s):
+ return self.index + self.match.start (s)
+
+ def end (self, s):
+ return self.index + self.match.end (s)
+
+ def substring (self, s):
+ return self.source[self.start (s):self.end (s)]
+
+ def ly (self):
+ s = ''
+ if self.type == 'lilypond-block' or self.type == 'lilypond':
+ s = self.substring ('code')
+ elif self.type == 'lilypond-file':
+ name = self.substring ('filename')
+ s = open (find_file (name)).read ()
+ return s
- if not isfile2 and os.path.isfile (fp2):
- f2 = fp2
- isfile2 = os.path.isfile (fp2)
+ def full_ly (self):
+ s = self.ly ()
+ if s:
+ return compose_ly (s, self.match.group ('options'))
+ return ''
+
+ def get_hash (self):
+ if not self.hash:
+ self.hash = abs (hash (self.ly ()))
+ return self.hash
+
+ def basename (self):
+ if use_hash_p:
+ return 'lily-%d' % self.get_hash ()
+ raise 'to be done'
+
+ def write_ly (self):
+ if self.type == 'lilypond-block' or self.type == 'lilypond'\
+ or self.type == 'lilypond-file':
+ h = open (self.basename () + '.ly', 'w')
+ h.write (self.full_ly ())
+
+ def output_html (self):
+ base = self.basename ()
+ option_string = self.match.group ('options')
+ if option_string and VERBATIM in split_options (option_string)\
+ and format == HTML:
+ verb = verbatim_html (self.substring ('code'))
+ h.write (output[HTML][VERBATIM] % vars ())
+ h.write (output[HTML][BEFORE])
+ h.write (output[HTML][OUTPUT] % vars ())
+ h.write (output[HTML][AFTER])
- if (os.path.isfile (f2) and isfile2 and
- os.stat (f1)[stat.ST_MTIME] >
- os.stat (f2)[stat.ST_MTIME]) or \
- not isfile2:
-
- return 1
+ def output_latex (self):
+ option_string = self.match.group ('options')
+ if option_string and VERBATIM in split_options (option_string)\
+ and format == LATEX:
+ verb = self.substring ('code')
+ h.write (output[LATEX][VERBATIM] % vars ())
+ h.write (output[LATEX][BEFORE])
+ base = self.basename ()
+ h.write (output[LATEX][OUTPUT] % vars ())
+ h.write (output[LATEX][AFTER])
+
+ def output_texinfo (self):
+ option_string = self.match.group ('options')
+ if option_string and VERBATIM in split_options (option_string):
+ verb = verbatim_texinfo (self.substring ('code'))
+ h.write (output[TEXINFO][VERBATIM] % vars ())
+ h.write ('\n@tex\n')
+ self.output_latex ()
+ h.write ('\n@end tex\n')
- todo = []
- if 'tex' in needed_filetypes and must_rebuild (pathbase, '.ly', '.tex'):
- todo.append ('tex')
- if 'eps' in needed_filetypes and must_rebuild (pathbase, '.tex', '.eps'):
- todo.append ('eps')
- if 'png' in needed_filetypes and must_rebuild (pathbase, '.eps', '.png'):
- todo.append ('png')
-
- return ('lilypond', body, opts, todo, basename)
-
-def format_lilypond_block (chunk):
- """
-
- Figure out what should be left MAIN_STR (meant
- for the main file) from a lilypond chunk: process
- verbatim, and other options. Return: multiple chunks.
-
-
- """
-
-
- return_chunks = []
-
- (type, body, opts, todo, basename) = chunk
- assert type == 'lilypond'
-
-
- newbody = ''
- filename_chunk = None
- if 'printfilename' in opts:
- for o in opts:
- m= re.match ("filename=(.*)", o)
- if m:
- template = get_output ("output-filename")
- b = basename + '.ly'
- human_base = os.path.basename (m.group (1))
-
- ## todo: include path, but strip
- ## first part of the path.
- filename_chunk = ('input', template % (human_base, b,human_base))
- break
-
-
- if 'smallverbatim' in opts:
- newbody += output_verbatim (body, 1)
- elif 'verbatim' in opts:
- newbody += output_verbatim (body, 0)
-
- for o in opts:
- m = re.search ('intertext="(.*?)"', o)
- if m:
- newbody = newbody + "\n"
- if format == 'texi':
- newbody = newbody + "@noindent\n"
- elif format == 'latex':
- newbody = newbody + "\\noindent\n"
- newbody = newbody + m.group (1) + "\n"
-
- if 'noinline' in opts:
- s = 'output-noinline'
- elif format == 'latex':
- if 'quote' in opts:
- s = 'output-latex-quoted'
- elif 'eps' in opts:
- s = 'output-eps'
+ h.write ('\n@html\n')
+ self.output_html ()
+ h.write ('\n@end html\n')
+
+ def outdated_p (self):
+ if self.type != 'lilypond-block' and self.type != 'lilypond'\
+ and self.type != 'lilypond-file':
+ return None
+ base = self.basename ()
+ if os.path.exists (base + '.ly') \
+ and os.path.exists (base + '.tex') \
+ and (use_hash_p \
+ or self.ly () == open (base + '.ly').read ()):
+ # TODO: something smart with target formats
+ # (ps, png) and m/ctimes
+ return None
+ return self
+
+ def filter_code (self):
+ global index
+ # Hmm, why is verbatim's group called 'code'; rename to 'verb'?
+ #if snippet.match.group ('code'):
+ # urg
+ if self.type == 'lilypond' or self.type == 'lilypond-block':
+ h.write (self.source[index:self.start ('code')])
+ h.write (run_filter (self.substring ('code')))
+ h.write (self.source[self.end ('code'):self.end (0)])
else:
- s = 'output-latex-noquote'
- elif format == 'texi':
- if 'quote' in opts:
- s = 'output-texi-quoted'
+ h.write (self.source[index:self.end (0)])
+ index = self.end (0)
+
+ def compile_output (self):
+ global index
+ # Hmm, why is verbatim's group called 'code'; rename to 'verb'?
+ # if snippet.match.group ('code'):
+ # urg
+ if self.type == 'lilypond' \
+ or self.type == 'lilypond-block'\
+ or self.type == 'lilypond-file':
+ h.write (self.source[index:self.start (0)])
+ snippet_output = eval ("Snippet.output_" + format)
+ snippet_output (self)
+ elif self.type == 'include':
+ h.write (self.source[index:self.start ('filename')])
+ base = os.path.splitext (self.substring ('filename'))[0]
+ h.write (base + format2ext[format])
+ h.write (self.source[self.end ('filename'):self.end (0)])
else:
- s = 'output-texi-noquote'
- else: # format == 'html'
- s = 'output-html'
+ h.write (self.source[index:self.end (0)])
+ index = self.end (0)
+
+def find_toplevel_snippets (s, types):
+ res = {}
+ for i in types:
+ res[i] = ly.re.compile (snippet_res[format][i])
- def html_pages (basename):
- pat = os.path.join (g_outdir, "%s-page*.png"% basename)
+ snippets = []
+ index = 0
+ found = {}.fromkeys (types)
+ while 1:
+ first = 0
+ endex = 1 << 30
+ for i in types:
+ if not found[i] or found[i].start (0) < index:
+ found[i] = 0
+ m = res[i].search (s[index:endex])
+ if m:
+ found[i] = Snippet (i, s, index, m)
+ if found[i] \
+ and (not first \
+ or found[i].start (0) < found[first].start (0)):
+ first = i
+ endex = found[first].start (0)
+ if not first:
+ break
+ snippets.append (found[first])
+ index = found[first].end (0)
- files = glob.glob (pat)
+ return snippets
+
+def filter_pipe (input, cmd):
+ if verbose_p:
+ ly.progress (_ ("Opening filter `%s\'") % cmd)
+ stdin, stdout, stderr = os.popen3 (cmd)
+ stdin.write (input)
+ status = stdin.close ()
+
+ if not status:
+ status = 0
+ output = stdout.read ()
+ status = stdout.close ()
+ error = stderr.read ()
- template = '''<img align="center" valign="center"
- border="0" src="%s" alt="[picture of music]">'''
-
- str = ''
- if files == []:
- files = [basename+'.png' ]
- else:
- files = map (os.path.basename, files)
-
- for f in files:
- str += template % f
-
- str = '<a href="%s.ly">%s</a>' % (basename, str)
-
- return str
-
+ if not status:
+ status = 0
+ signal = 0x0f & status
+ if status or (not output and error):
+ exit_status = status >> 8
+ ly.error (_ ("`%s\' failed (%d)") % (cmd, exit_status))
+ ly.error (_ ("The error log is as follows:"))
+ sys.stderr.write (error)
+ sys.stderr.write (stderr.read ())
+ ly.exit (status)
- newbody = newbody + get_output (s) % {'fn': basename,
- 'htmlimages': html_pages(basename)
- }
+ if verbose_p:
+ ly.progress ('\n')
- if filename_chunk:
- return_chunks += [filename_chunk]
+ return output
- return_chunks += [('lilypond', newbody, opts, todo, basename)]
-
- return return_chunks
-
-def format_lilypond_output_bodies (chunks):
- newchunks = []
- for c in chunks:
+def run_filter (s):
+ return filter_pipe (s, filter_cmd)
+
+def process_snippets (cmd, snippets):
+ names = filter (lambda x:x, map (Snippet.basename, snippets))
+ if names:
+ ly.system (string.join ([cmd] + names))
+
+ if format == HTML or format == TEXINFO:
+ for i in names:
+ if os.path.exists (i + '.tex'):
+ to_eps (i)
+ ly.make_ps_images (i + '.eps', resolution=110)
+
+LATEX_DOCUMENT = r'''
+%(preamble)s
+\begin{document}
+\typeout{textwidth=\the\textwidth}
+\typeout{columnsep=\the\columnsep}
+\makeatletter\if@twocolumn\typeout{columns=2}\fi\makeatother
+\end{document}
+'''
+#need anything else besides textwidth?
+def get_latex_textwidth (source):
+ m = re.search (r'''(?P<preabmle>\\begin\s*{document})''', source)
+ preamble = source[:m.start (0)]
+ latex_document = LATEX_DOCUMENT % vars ()
+ parameter_string = filter_pipe (latex_document, latex_filter_cmd)
+
+ columns = 0
+ m = re.search ('columns=([0-9.]*)', parameter_string)
+ if m:
+ columns = string.atoi (m.group (1))
+
+ columnsep = 0
+ m = re.search ('columnsep=([0-9.]*)pt', parameter_string)
+ if m:
+ columnsep = string.atof (m.group (1))
+
+ textwidth = 0
+ m = re.search('textwidth=([0-9.]*)pt', parameter_string)
+ if m:
+ textwidth = string.atof (m.group (1))
+ if columns:
+ textwidth = (textwidth - columnsep) / columns
+
+ return textwidth
+
+
+ext2format = {
+ '.html' : HTML,
+ '.itely' : TEXINFO,
+ '.lytex' : LATEX,
+ '.tely' : TEXINFO,
+ '.tex': LATEX,
+ '.texi' : TEXINFO,
+ '.texinfo' : TEXINFO,
+ '.xml' : HTML,
+ }
+
+format2ext = {
+ HTML: '.html',
+ #TEXINFO: '.texinfo',
+ TEXINFO: '.texi',
+ LATEX: '.tex',
+ }
- if c[0] == 'lilypond':
- newchunks += format_lilypond_block (c)
+def do_file (input_filename):
+ #ugh
+ global format
+ if not format:
+ e = os.path.splitext (input_filename)[1]
+ if e in ext2format.keys ():
+ #FIXME
+ format = ext2format[e]
else:
- newchunks.append (c)
-
- return newchunks
+ ly.error (_ ("cannot determine format for: %s" \
+ % input_filename))
-
-
-def process_lilypond_blocks (chunks):#ugh rename
- newchunks = []
- # Count sections/chapters.
- for c in chunks:
- if c[0] == 'lilypond':
- c = schedule_lilypond_block (c)
- elif c[0] == 'numcols':
- paperguru.m_num_cols = c[2]
- elif c[0] == 'multicols':
- paperguru.m_multicols = c[2]
-
- newchunks.append (c)
-
- return newchunks
-
-def process_ly2dvi_blocks (chunks):
+ ly.progress (_ ("Reading %s...") % input_filename)
+ if not input_filename or input_filename == '-':
+ ih = sys.stdin
+ else:
+ ih = open (input_filename)
+ source = ih.read ()
+ ly.progress ('\n')
+
+ ly.progress (_ ("Dissecting..."))
+ #snippets = find_toplevel_snippets (source, snippet_res[format].keys ())
+ snippet_types = (
+ 'lilypond-block',
+ 'verb',
+ 'verbatim',
+ 'singleline-comment',
+ 'multiline-comment',
+ 'lilypond-file',
+ 'include',
+ 'lilypond', )
- def process_ly2dvi_block (chunk):
- """
-
-Run ly2dvi script on filename specified in CHUNK.
-This is only supported for HTML output.
-
-In HTML output it will leave a download menu with ps/pdf/midi etc. in
-a separate HTML file, and a title + preview in the main html file,
-linking to the menu.
-
- """
- (tag, name, opts) = chunk
- assert format == 'html'
- (content, original_name) = find_file (name)
-
- original_name = os.path.basename (original_name)
-
- base = unique_file_name (content)
- outname = base + '.ly'
- changed = update_file (content, outname)
-
- preview = base + ".preview.png"
- preview_page = base + '-page1.png'
-
- if changed or not (os.path.isfile (preview) or
- os.path.isfile (preview_page)):
-
- ly.system ('%s --preview --postscript --verbose %s ' % (ly2dvi_binary, base) )
-
- ly.make_ps_images (base + '.ps')
- ly.system ('gzip -9 - < %s.ps > %s.ps.gz' % (base, base))
-
- def size_str (fn):
- b = os.stat(fn)[stat.ST_SIZE]
- if b < 1024:
- return '%d bytes' % b
- elif b < (2 << 20):
- return '%d kb' % (b >> 10)
- else:
- return '%d mb' % (b >> 20)
-
- exts = {
- 'pdf' : "Print (PDF, %s)",
- 'ps.gz' : "Print (gzipped PostScript, %s)",
- 'png' : "View (PNG, %s)",
- 'midi' : "Listen (MIDI, %s)",
- 'ly' : "View source code (%s)",
- }
-
- menu = ''
- page_files = glob.glob ('%s-page*.png' % base)
-
- for p in page_files:
- p = p.strip()
- if os.path.isfile (p):
- sz = size_str (p)
- page = re.sub ('.*page([0-9])+.*', 'View page \\1 (PNG picture, %s)\n', p)
- page = page % sz
- menu += '<li><a href="%s">%s</a>' % (p, page)
-
- ext_order = ['ly', 'pdf', 'ps.gz', 'midi']
- for e in ext_order:
- fn = base + '.' + e
- print 'checking,' , fn
- if not os.path.isfile (fn):
- continue
-
- entry = exts[e] % size_str (fn)
-
- ## TODO: do something like
- ## this for texinfo/latex as well ?
-
- menu += '<li><a href="%s">%s</a>\n\n' % (fn, entry)
+ snippets = find_toplevel_snippets (source, snippet_types)
+ ly.progress ('\n')
-
- explanatory_para = """The pictures are 90dpi
-anti-aliased snapshots of the printed output, in PNG format. Both PDF and PS
-use scalable fonts and should look OK at any resolution."""
-
- separate_menu =r'''
-<title>LilyPond example %s</title>
-
-<h1>%s</h1>
-<p><img src="%s">
-<p>%s
-<p>
-<ul>%s</ul>''' % (original_name,original_name, preview, explanatory_para, menu)
-
- open (base + '.html','w'). write (separate_menu)
-
- inline_menu = '<p/><a href="%s.html"><img alt="%s" src="%s"></a><p/>' % (base, original_name, preview)
-
- return ('ly2dvi', inline_menu)
-
- newchunks = []
- for c in chunks:
- if c[0] == 'ly2dvi':
- c = process_ly2dvi_block (c)
- newchunks.append (c)
-
- return newchunks
-
-def compile_all_files (chunks):
- global foutn
- eps = []
- tex = []
- png = []
-
- for c in chunks:
- if c[0] != 'lilypond':
- continue
-
- base = c[4]
- exts = c[3]
- for e in exts:
- if e == 'eps':
- eps.append (base)
- elif e == 'tex':
- #ugh
- if base + '.ly' not in tex:
- tex.append (base + '.ly')
- elif e == 'png' and g_do_pictures:
- png.append (base)
- d = os.getcwd ()
- if g_outdir:
- os.chdir (g_outdir)
- if tex:
- # fixme: be sys-independent.
- def incl_opt (x):
- if g_outdir and x[0] != '/' :
- x = os.path.join (g_here_dir, x)
- return ' -I %s' % x
-
- incs = map (incl_opt, include_path)
- lilyopts = string.join (incs)
- if do_deps:
- lilyopts += ' --dependencies'
- if g_outdir:
- lilyopts += ' --dep-prefix=' + g_outdir + '/'
- lilyopts += ' --header=texidoc'
- texfiles = string.join (tex)
- cmd = string.join ((lilypond_binary, lilyopts, g_extra_opts,
- texfiles))
-
- ly.lilypond_version_check (lilypond_binary, '@TOPLEVEL_VERSION@')
-
- ly.system (cmd, ignore_error = 0, progress_p = 1)
-
- #
- # Ugh, fixing up dependencies for .tex generation
- #
- if do_deps:
- depfiles=map (lambda x: re.sub ('(.*)\.ly', '\\1.dep',
- x), tex)
-
- for i in depfiles:
- f =open (i)
- text=f.read ()
- f.close ()
- text=re.sub ('\n([^:\n]*):',
- '\n' + foutn + ':', text)
- f = open (i, 'w')
- f.write (text)
- f.close ()
-
- def to_eps (file):
- cmd = r"latex '\nonstopmode \input %s'" % file
- # Ugh. (La)TeX writes progress and error messages on stdout
- # Redirect to stderr
- cmd = '(( %s >&2 ) >&- )' % cmd
+ global h
+ if output_name == '-' or not output_name:
+ h = sys.stdout
+ output_filename = '-'
+ else:
+ if not os.path.isdir (output_name):
+ os.mkdir (output_name, 0777)
+ if input_filename == '-':
+ input_base = 'stdin'
+ else:
+ input_base = os.path.splitext (input_filename)[0]
+ output_filename = output_name + '/' + input_base \
+ + format2ext[format]
+ h = open (output_filename, 'w')
+ os.chdir (output_name)
+
+ global default_ly_options
+ textwidth = 0
+ if format == LATEX and LINEWIDTH not in default_ly_options.keys ():
+ textwidth = get_latex_textwidth (source)
+ default_ly_options[LINEWIDTH] = '''%.0f\pt''' % textwidth
+
+ global index
+ if filter_cmd:
+ index = 0
+ map (Snippet.filter_code, snippets)
+ h.write (source[index:])
+ elif process_cmd:
+ outdated = filter (lambda x:x,
+ map (Snippet.outdated_p, snippets))
+ ly.progress (_ ("Writing snippets..."))
+ map (Snippet.write_ly, snippets)
+ ly.progress ('\n')
- ly.system (cmd)
- ly.system ("dvips -Ppdf -u+lilypond.map -E -o %s.eps %s" % (file, file))
- map (to_eps, eps)
-
- for p in png:
- ly.make_ps_images (p + '.eps', resolution=110)
- os.chdir (d)
-
-
-def update_file (body, name):
- '''
- write the body if it has changed. Return whether BODY has changed.
- '''
- same = 0
- try:
- f = open (name)
- fs = f.read (-1)
- same = (fs == body)
- except:
- pass
-
- if not same:
- f = open (name , 'w')
- f.write (body)
- f.close ()
-
- return not same
-
-
-def write_deps (fn, target, chunks):
- global read_files
- sys.stderr.write ('Writing `%s\'\n' % os.path.join (g_outdir, fn))
- f = open (os.path.join (g_outdir, fn), 'w')
- f.write ('%s%s: ' % (g_dep_prefix, target))
- for d in read_files:
- f.write ('%s ' % d)
-
-
- ## There used to be code to write .tex dependencies, but
- ## that is silly: lilypond-book has its own dependency scheme
- ## to ensure that all lily-XXX.tex files are there
+ if outdated:
+ ly.progress (_ ("Processing..."))
+ process_snippets (process_cmd, outdated)
+ else:
+ ly.progress (_ ("All snippets are up to date..."))
+ ly.progress ('\n')
-
- f.write ('\n')
- f.close ()
- read_files = []
-
-def check_texidoc (chunks):
- ## TODO: put file name in front of texidoc.
- ##
- n = []
- for c in chunks:
- if c[0] == 'lilypond':
- (type, body, opts, todo, basename) = c;
- pathbase = os.path.join (g_outdir, basename)
- if os.path.isfile (pathbase + '.texidoc') \
- and 'notexidoc' not in opts:
- n.append( ('input', '\n@include %s.texidoc\n\n' % basename))
- n.append (c)
- return n
-
-
-## what's this? Docme --hwn
-##
-def fix_epswidth (chunks):
- newchunks = []
- for c in chunks:
- if c[0] != 'lilypond' or 'eps' not in c[2]:
- newchunks.append (c)
- continue
-
- mag = 1.0
- for o in c[2]:
- m = re.match ('magnification=([0-9.]+)', o)
- if m:
- mag = string.atof (m.group (1))
-
- def replace_eps_dim (match, lmag = mag):
- filename = match.group (1)
- dims = bounding_box_dimensions (filename)
-
- return '%fpt' % (dims[0] *lmag)
-
- body = re.sub (r'''\\lilypondepswidth{(.*?)}''', replace_eps_dim, c[1])
- newchunks.append (('lilypond', body, c[2], c[3], c[4]))
-
- return newchunks
-
-
-##docme: why global?
-foutn=""
-
-def do_file (input_filename):
- chunks = read_doc_file (input_filename)
- chunks = chop_chunks (chunks, 'ly2dvi', make_ly2dvi_block, 1)
- chunks = chop_chunks (chunks, 'lilypond', make_lilypond, 1)
- chunks = chop_chunks (chunks, 'lilypond-file', make_lilypond_file, 1)
- chunks = chop_chunks (chunks, 'lilypond-block', make_lilypond_block, 1)
- chunks = chop_chunks (chunks, 'singleline-comment', do_ignore, 1)
- chunks = chop_chunks (chunks, 'preamble-end', do_preamble_end)
- chunks = chop_chunks (chunks, 'numcols', do_columns)
- chunks = chop_chunks (chunks, 'multicols', do_multicols)
+ ly.progress (_ ("Compiling %s...") % output_filename)
+ index = 0
+ map (Snippet.compile_output, snippets)
+ h.write (source[index:])
+ ly.progress ('\n')
+
+ if h != sys.stdout:
+ h.close ()
+
+ def process_include (snippet):
+ os.chdir (original_dir)
+ name = snippet.substring ('filename')
+ ly.progress (_ ('Processing include: %s') % name)
+ ly.progress ('\n')
+ do_file (name)
+
+ map (process_include, filter (lambda x: x.type == 'include', snippets))
+
+def do_options ():
+ global format, output_name
+ global filter_cmd, process_cmd, verbose_p
- scan_preamble (chunks)
- chunks = process_lilypond_blocks (chunks)
- chunks = process_ly2dvi_blocks (chunks)
-
- # Do It.
- global g_run_lilypond
- if g_run_lilypond:
- compile_all_files (chunks)
- chunks = fix_epswidth (chunks)
-
-
- chunks = format_lilypond_output_bodies (chunks)
- global format
- if format == 'texi':
- chunks = check_texidoc (chunks)
-
-
- x = 0
- chunks = completize_preamble (chunks)
-
- global foutn
-
- if outname:
- my_outname = outname
- elif input_filename == '-' or input_filename == "/dev/stdin":
- my_outname = '-'
- else:
- my_outname = os.path.basename (os.path.splitext (input_filename)[0]) + '.' + format
- my_depname = my_outname + '.dep'
-
- if my_outname == '-' or my_outname == '/dev/stdout':
- fout = sys.stdout
- foutn = "<stdout>"
- global do_deps
- do_deps = 0
- else:
- foutn = os.path.join (g_outdir, my_outname)
- sys.stderr.write ("Writing `%s'\n" % foutn)
- fout = open (foutn, 'w')
- for c in chunks:
- fout.write (c[1])
- fout.close ()
- # should chmod -w
-
- if do_deps:
- write_deps (my_depname, foutn, chunks)
-
-outname = ''
-try:
(sh, long) = ly.getopt_args (option_definitions)
- (options, files) = getopt.getopt (sys.argv[1:], sh, long)
-
-except getopt.error, msg:
- sys.stderr.write ('\n')
- ly.error (_ ("getopt says: `%s\'" % s))
- sys.stderr.write ('\n')
- ly.help ()
- ly.exit (2)
-
-do_deps = 0
-for opt in options:
- o = opt[0]
- a = opt[1]
-
- if o == '--include' or o == '-I':
- include_path.append (a)
- elif o == '--version' or o == '-v':
- ly.identify (sys.stdout)
- sys.exit (0)
- elif o == '--verbose' or o == '-V':
- verbose_p = 1
- elif o == '--format' or o == '-f':
- format = a
- if a == 'texi-html':
- format = 'texi'
- g_make_html = 1
- elif o == '--outname' or o == '-o':
- if len (files) > 1:
- #HACK
- sys.stderr.write ("lilypond-book is confused by --outname on multiple files")
- sys.exit (1)
- outname = a
- elif o == '--help' or o == '-h':
+ try:
+ (options, files) = getopt.getopt (sys.argv[1:], sh, long)
+ except getopt.error, s:
+ sys.stderr.write ('\n')
+ ly.error (_ ("getopt says: `%s\'" % s))
+ sys.stderr.write ('\n')
ly.help ()
- sys.exit (0)
- elif o == '--no-lily' or o == '-n':
- g_run_lilypond = 0
- elif o == '--preview-resolution':
- preview_resolution = string.atoi (a)
- elif o == '--dependencies' or o == '-M':
- do_deps = 1
- elif o == '--default-music-fontsize':
- default_music_fontsize = string.atoi (a)
- elif o == '--default-lilypond-fontsize':
- print "--default-lilypond-fontsize is deprecated, use --default-music-fontsize"
- default_music_fontsize = string.atoi (a)
- elif o == '--extra-options':
- g_extra_opts = a
- elif o == '--force-music-fontsize':
- g_force_music_fontsize = string.atoi (a)
- elif o == '--force-lilypond-fontsize':
- print "--force-lilypond-fontsize is deprecated, use --default-lilypond-fontsize"
- g_force_music_fontsize = string.atoi (a)
- elif o == '--dep-prefix':
- g_dep_prefix = a
- elif o == '--no-pictures':
- g_do_pictures = 0
- elif o == '--no-music':
- g_do_music = 0
- elif o == '--outdir':
- g_outdir = a
- elif o == '--warranty' or o == '-w':
- #status = os.system ('lilypond -w')
- if 1 or status:
- ly.warranty ()
- sys.exit (0)
-
-ly.identify (sys.stderr)
-
-if g_outdir:
- if os.path.isfile (g_outdir):
- error ("outdir is a file: %s" % g_outdir)
- if not os.path.exists (g_outdir):
- os.mkdir (g_outdir)
-
-if not files:
- ly.help ()
- ly.error (_ ("no files specified on command line"))
- ly.exit (2)
-
-ly.setup_environment ()
+ ly.exit (2)
+ for opt in options:
+ o = opt[0]
+ a = opt[1]
-for input_filename in files:
- do_file (input_filename)
-
-
-#
-# Petr, ik zou willen dat ik iets zinvoller deed,
-# maar wat ik kan ik doen, het verandert toch niets?
-# --hwn 20/aug/99
+ if 0:
+ pass
+ elif o == '--filter' or o == '-F':
+ filter_cmd = a
+ process_cmd = 0
+ elif o == '--format' or o == '-f':
+ format = a
+ if a == 'texi-html' or a == 'texi':
+ format = TEXINFO
+ elif o == '--help' or o == '-h':
+ ly.help ()
+ sys.exit (0)
+ elif o == '--include' or o == '-I':
+ include_path.append (os.path.join (original_dir,
+ ly.abspath (a)))
+ elif o == '--output' or o == '-o':
+ output_name = a
+ elif o == '--outdir':
+ output_name = a
+ elif o == '--process' or o == '-P':
+ process_cmd = a
+ filter_cmd = 0
+ elif o == '--version' or o == '-v':
+ ly.identify (sys.stdout)
+ sys.exit (0)
+ elif o == '--verbose' or o == '-V':
+ verbose_p = 1
+ elif o == '--warranty' or o == '-w':
+ if 1 or status:
+ ly.warranty ()
+ sys.exit (0)
+ return files
+
+def main ():
+ files = do_options ()
+ ly.identify (sys.stderr)
+ ly.setup_environment ()
+ if files:
+ do_file (files[0])
+
+if __name__ == '__main__':
+ main ()
--- /dev/null
+#!@PYTHON@
+# vim: set noexpandtab:
+
+"""
+
+ TODO:
+ * junk --outdir for--output
+ * Figure out clean set of options.
+ *
+ * texinfo: add support for @pagesize
+
+ todo: dimension handling (all the x2y) is clumsy. (tca: Thats
+ because the values are taken directly from texinfo.tex,
+ geometry.sty and article.cls. Give me a hint, and I'll
+ fix it.)
+
+
+ TODO: magnification support should also work for texinfo -> html: eg. add as option to dvips.
+
+
+
+ This is a slightly hairy program. The general approach is as follows
+ The input string is chopped up in chunks, i.e. , a list of tuples
+
+ with the format (TAG_STR, MAIN_STR, OPTIONS, TODO, BASE)
+
+ This list is built step by step: first ignore and verbatim commands
+ are handled, delivering a list of chunks.
+
+ then all chunks containing lilypond commands are chopped up
+
+ when all chunks have their final form, all bodies from lilypond blocks are
+ extracted, and if applicable, written do disk and run through lilypond.
+
+
+tags supported
+
+ ignore
+ lilypond
+ input
+ verb
+ verbatim
+ multicols
+ numcols
+
+
+
+
+"""
+
+# This is was the idea for handling of comments:
+# Multiline comments, @ignore .. @end ignore is scanned for
+# in read_doc_file, and the chunks are marked as 'ignore', so
+# lilypond-book will not touch them any more. The content of the
+# chunks are written to the output file. Also 'include' and 'input'
+# regex has to check if they are commented out.
+#
+
+# Then it is scanned for 'lilypond', 'lilypond-file' and 'lilypond-block'.
+# These three regex's has to check if they are on a commented line,
+# % for latex, @c for texinfo.
+#
+# Then lines that are commented out with % (latex) and @c (Texinfo)
+# are put into chunks marked 'ignore'. This cannot be done before
+# searching for the lilypond-blocks because % is also the comment character
+# for lilypond.
+#
+# The the rest of the rexeces are searched for. They don't have to test
+# if they are on a commented out line.
+
+import glob
+import stat
+import string
+
+
+################################################################
+# Users of python modules should include this snippet
+# and customize variables below.
+
+# We'll suffer this path init stuff as long as we don't install our
+# python packages in <prefix>/lib/pythonx.y (and don't kludge around
+# it as we do with teTeX on Red Hat Linux: set some environment var
+# (PYTHONPATH) in profile)
+
+# If set, LILYPONDPREFIX must take prevalence
+# if datadir is not set, we're doing a build and LILYPONDPREFIX
+import getopt, os, sys
+datadir = '@local_lilypond_datadir@'
+if not os.path.isdir (datadir):
+ datadir = '@lilypond_datadir@'
+if os.environ.has_key ('LILYPONDPREFIX') :
+ datadir = os.environ['LILYPONDPREFIX']
+ while datadir[-1] == os.sep:
+ datadir= datadir[:-1]
+
+sys.path.insert (0, os.path.join (datadir, 'python'))
+
+# Customize these
+#if __name__ == '__main__':
+
+import lilylib as ly
+global _;_=ly._
+global re;re = ly.re
+
+# lilylib globals
+program_version = '@TOPLEVEL_VERSION@'
+program_name = 'lilypond-book'
+verbose_p = 0
+pseudo_filter_p = 0
+original_dir = os.getcwd ()
+
+
+preview_resolution = 90
+
+## FIXME
+## do -P or -p by default?
+##help_summary = _ ("Run LilyPond using LaTeX for titling")
+help_summary = _ ("Process LilyPond snippets in hybrid html, LaTeX or texinfo document")
+copyright = ('Tom Cato Amundsen <tca@gnu.org>',
+ 'Han-Wen Nienhuys <hanwen@cs.uu.nl>')
+
+option_definitions = [
+ (_ ("EXT"), 'f', 'format', _ ("use output format EXT (texi [default], texi-html, latex, html)")),
+ (_ ("DIM"), '', 'default-music-fontsize', _ ("default fontsize for music. DIM is assumed to be in points")),
+ (_ ("DIM"), '', 'default-lilypond-fontsize', _ ("deprecated, use --default-music-fontsize")),
+ (_ ("OPT"), '', 'extra-options', _ ("pass OPT quoted to the lilypond command line")),
+ (_ ("DIM"), '', 'force-music-fontsize', _ ("force fontsize for all inline lilypond. DIM is assumed to be in points")),
+ (_ ("DIM"), '', 'force-lilypond-fontsize', _ ("deprecated, use --force-music-fontsize")),
+ ('', 'h', 'help', _ ("print this help")),
+ (_ ("DIR"), 'I', 'include', _ ("include path")),
+ ('', 'M', 'dependencies', _ ("write dependencies")),
+ (_ ("PREF"), '', 'dep-prefix', _ ("prepend PREF before each -M dependency")),
+ ('', 'n', 'no-lily', _ ("don't run lilypond")),
+ ('', '', 'no-pictures', _ ("don't generate pictures")),
+ ('', '', 'no-music', _ ("strip all lilypond blocks from output")),
+ (_ ("FILE"), 'o', 'outname', _ ("filename main output file")),
+ (_ ("FILE"), '', 'outdir', _ ("where to place generated files")),
+ (_ ('RES'), '', 'preview-resolution',
+ _ ("set the resolution of the preview to RES")),
+ ('', 'V', 'verbose', _ ("be verbose")),
+ ('', 'v', 'version', _ ("print version information")),
+ ('', 'w', 'warranty', _ ("show warranty and copyright")),
+ ]
+
+# format specific strings, ie. regex-es for input, and % strings for output
+
+# global variables
+
+include_path = [os.getcwd ()]
+
+#lilypond_binary = 'valgrind --suppressions=/home/hanwen/usr/src/guile-1.6.supp --num-callers=10 /home/hanwen/usr/src/lilypond/lily/out/lilypond'
+
+lilypond_binary = os.path.join ('@bindir@', 'lilypond-bin')
+
+# only use installed binary when we're installed too.
+if '@bindir@' == ('@' + 'bindir@') or not os.path.exists (lilypond_binary):
+ lilypond_binary = 'lilypond-bin'
+
+
+
+ly2dvi_binary = os.path.join ('@bindir@', 'ly2dvi')
+
+# only use installed binary when we're installed too.
+if '@bindir@' == ('@' + 'bindir@') or not os.path.exists (lilypond_binary):
+ ly2dvi_binary = 'ly2dvi'
+
+
+
+g_extra_opts = ''
+g_here_dir = os.getcwd ()
+g_dep_prefix = ''
+g_outdir = ''
+g_force_music_fontsize = 0
+g_do_pictures = 1
+g_do_music = 1
+g_make_html = 0
+
+format = ''
+g_run_lilypond = 1
+no_match = 'a\ba'
+
+default_music_fontsize = 16
+default_text_fontsize = 12
+paperguru = None
+
+################################################################
+# Dimension handling for LaTeX.
+#
+class LatexPaper:
+ def __init__ (self):
+ self.m_document_preamble = []
+ self.m_num_cols = 1
+ self.m_multicols = 1
+
+ def find_latex_dims (self):
+ if g_outdir:
+ fname = os.path.join (g_outdir, "lily-tmp.tex")
+ else:
+ fname = "lily-tmp.tex"
+ try:
+ f = open (fname, "w")
+ except IOError:
+ error ("Error creating temporary file '%s'" % fname)
+
+ for s in self.m_document_preamble:
+ f.write (s)
+ f.write (r"""
+\begin{document}
+\typeout{---}
+\typeout{\columnsep \the\columnsep}
+\typeout{\textwidth \the\textwidth}
+\typeout{---}
+\end{document}
+ """)
+ f.close ()
+ re_dim = re.compile (r"\\(\w+)\s+(\d+\.\d+)")
+
+ cmd = "latex '\\nonstopmode \input %s'" % fname
+ # Ugh. (La)TeX writes progress and error messages on stdout
+ # Redirect to stderr
+ cmd = '(( %s >&2 ) >&- )' % cmd
+ status = ly.system (cmd, ignore_error = 1)
+ signal = 0xf & status
+ exit_status = status >> 8
+
+ if status:
+ ly.error (_ ("LaTeX failed."))
+ ly.error (_ ("The error log is as follows:"))
+
+ #URG see lilypond
+ try:
+ lns = open ('lily-tmp.log').readlines ()
+ except:
+ lns = ''
+ countdown = -3
+ for ln in lns:
+ sys.stderr.write (ln)
+ if re.match ('^!', ln):
+ countdown = 3
+
+ if countdown == 0:
+ break
+
+ if countdown > 0:
+ countdown = countdown -1
+
+ sys.stderr.write (" ... (further messages elided)...\n")
+ sys.exit (1)
+
+ lns = open ('lily-tmp.log').readlines ()
+ for ln in lns:
+ ln = string.strip (ln)
+ m = re_dim.match (ln)
+ if m:
+ if m.groups ()[0] in ('textwidth', 'columnsep'):
+ self.__dict__['m_%s' % m.groups ()[0]] = float (m.groups ()[1])
+
+ try:
+ os.remove (fname)
+ os.remove (os.path.splitext (fname)[0]+".aux")
+ os.remove (os.path.splitext (fname)[0]+".log")
+ except:
+ pass
+
+ if not self.__dict__.has_key ('m_textwidth'):
+ raise 'foo!'
+
+ def get_linewidth (self):
+ if self.m_num_cols == 1:
+ w = self.m_textwidth
+ else:
+ w = (self.m_textwidth - self.m_columnsep)/2
+ if self.m_multicols > 1:
+ return (w - self.m_columnsep* (self.m_multicols-1)) \
+ / self.m_multicols
+ return w
+
+
+class HtmlPaper:
+ def __init__ (self):
+ self.m_papersize = 'letterpaper'
+ self.m_fontsize = 12
+ def get_linewidth (self):
+ return html_linewidths[self.m_papersize][self.m_fontsize]
+
+class TexiPaper:
+ def __init__ (self):
+ self.m_papersize = 'letterpaper'
+ self.m_fontsize = 12
+ def get_linewidth (self):
+ return texi_linewidths[self.m_papersize][self.m_fontsize]
+
+def mm2pt (x):
+ return x * 2.8452756
+def in2pt (x):
+ return x * 72.26999
+def em2pt (x, fontsize = 10):
+ return {10: 10.00002, 11: 10.8448, 12: 11.74988}[fontsize] * x
+def ex2pt (x, fontsize = 10):
+ return {10: 4.30554, 11: 4.7146, 12: 5.16667}[fontsize] * x
+
+def pt2pt (x):
+ return x
+
+dimension_conversion_dict ={
+ 'mm': mm2pt,
+ 'cm': lambda x: mm2pt (10*x),
+ 'in': in2pt,
+ 'em': em2pt,
+ 'ex': ex2pt,
+ 'pt': pt2pt
+ }
+
+# Convert numeric values, with or without specific dimension, to floats.
+# Keep other strings
+def conv_dimen_to_float (value):
+ if type (value) == type (""):
+ m = re.match ("([0-9.]+)(cm|in|pt|mm|em|ex)",value)
+ if m:
+ unit = m.group (2)
+ num = string.atof (m.group (1))
+ conv = dimension_conversion_dict[m.group (2)]
+
+ value = conv (num)
+
+ elif re.match ("^[0-9.]+$",value):
+ value = float (value)
+
+ return value
+
+texi_linewidths = {
+ 'afourpaper': {12: mm2pt (160)},
+ 'afourwide': {12: in2pt (6.5)},
+ 'afourlatex': {12: mm2pt (150)},
+ 'smallbook': {12: in2pt (5)},
+ 'letterpaper': {12: in2pt (6)}}
+
+html_linewidths = {
+ 'afourpaper': {12: mm2pt (160)},
+ 'afourwide': {12: in2pt (6.5)},
+ 'afourlatex': {12: mm2pt (150)},
+ 'smallbook': {12: in2pt (5)},
+ 'letterpaper': {12: in2pt (6)}}
+
+
+################################################################
+# How to output various structures.
+output_dict= {
+
+
+ 'html' : {
+
+ 'output-filename' : r'''
+<!-- %s >
+<a href="%s">
+<pre>%s</pre></a>:''',
+ 'output-lilypond-fragment': '''<lilypond%s>
+\context Staff\context Voice{ %s }
+</lilypond>''',
+ 'output-noinline': r'''
+<!-- generated: %(fn)s.png !-->
+''',
+ ## maybe <hr> ?
+ 'pagebreak': None,
+ # Verbatim text is always finished with \n. FIXME: For HTML,
+ # this newline should be removed.
+ 'output-verbatim': r'''<pre>
+%s</pre>''',
+ # Verbatim text is always finished with \n. FIXME: For HTML,
+ # this newline should be removed.
+ 'output-small-verbatim': r'''<font size=-1><pre>
+%s</pre></font>''',
+ ## Ugh we need to differentiate on origin:
+ ## lilypond-block origin wants an extra <p>, but
+ ## inline music doesn't.
+ ## possibly other center options?
+ 'output-html': r'''
+%(htmlimages)s''',
+ },
+
+
+ 'latex': {
+
+ 'output-lilypond-fragment' : r'''\begin[singleline,%s]{lilypond}
+ \context Voice{
+ %s
+ }
+\end{lilypond}''',
+ 'output-filename' : r'''\verb+%s+:\\
+%% %s
+%% %s
+''',
+
+ # verbatim text is always finished with \n
+ 'output-verbatim': r'''\begin{verbatim}
+%s\end{verbatim}
+''',
+ # verbatim text is always finished with \n
+ 'output-small-verbatim': r'''{\small\begin{verbatim}
+%s\end{verbatim}}
+''',
+ 'output-default-post': "\\def\postLilyPondExample{}\n",
+ 'output-default-pre': "\\def\preLilyPondExample{}\n",
+ 'usepackage-graphics': '\\usepackage{graphics}\n',
+ 'output-eps': '\\noindent\includegraphics{%(fn)s}',
+ 'output-noinline': r'''
+%% generated: %(fn)s.eps
+''',
+ 'output-latex-quoted': r'''{\preLilyPondExample
+\def\lilypondbook{}
+\input %(fn)s.tex
+\postLilyPondExample}''',
+ 'output-latex-noquote': r'''{\parindent 0pt
+\preLilyPondExample
+\def\lilypondbook{}
+\input %(fn)s.tex
+\postLilyPondExample}''',
+ 'pagebreak': r'\pagebreak',
+ },
+
+
+ 'texi' : {
+
+
+ 'output-filename' : r'''
+@ifnothtml
+@file{%s}:@*
+@end ifnothtml
+@ifhtml
+@uref{%s,@file{%s}}
+@end ifhtml
+''',
+ 'output-lilypond-fragment': '''@lilypond[%s]
+\context Staff\context Voice{ %s }
+@end lilypond ''',
+ 'output-noinline': r'''
+@c generated: %(fn)s.png
+''',
+ 'pagebreak': None,
+ # verbatim text is always finished with \n
+ 'output-small-verbatim': r'''@smallexample
+%s@end smallexample
+''',
+ # verbatim text is always finished with \n
+ 'output-verbatim': r'''@example
+%s@end example
+''',
+ # do some tweaking: @ is needed in some ps stuff.
+ #
+ # ugh, the <p> below breaks inline images...
+ 'output-texi-noquote': r'''@tex
+\catcode`\@=12
+\parindent 0pt
+\def\lilypondbook{}
+\input %(fn)s.tex
+\catcode`\@=0
+@end tex
+@html
+<p>%(htmlimages)s
+<p>
+@end html
+''',
+ 'output-texi-quoted': r'''@quotation
+@tex
+\catcode`\@=12
+\def\lilypondbook{}
+\input %(fn)s.tex
+\catcode`\@=0
+@end tex
+@html
+<p>%(htmlimages)s
+<p>
+@end html
+@end quotation
+''',
+ }
+
+ }
+
+def output_verbatim (body, small):
+ global format
+ if format == 'html':
+ body = re.sub ('&', '&', body)
+ body = re.sub ('>', '>', body)
+ body = re.sub ('<', '<', body)
+ elif format == 'texi':
+ # clumsy workaround for python 2.2 pre bug.
+ body = re.sub ('@', '@@', body)
+ body = re.sub ('{', '@{', body)
+ body = re.sub ('}', '@}', body)
+
+ if small:
+ key = 'output-small-verbatim'
+ else:
+ key = 'output-verbatim'
+ return get_output (key) % body
+
+
+################################################################
+# Recognize special sequences in the input
+
+
+# Warning: This uses extended regular expressions. Tread with care.
+#
+# legenda
+#
+# (?P<name>regex) -- assign result of REGEX to NAME
+# *? -- match non-greedily.
+# (?m) -- multiline regex: make ^ and $ match at each line
+# (?s) -- make the dot match all characters including newline
+re_dict = {
+ 'html': {
+ 'include': no_match,
+ 'input': no_match,
+ 'header': no_match,
+ 'preamble-end': no_match,
+ 'landscape': no_match,
+ 'verbatim': r'''(?s)(?P<code><pre>\s.*?</pre>\s)''',
+ 'verb': r'''(?P<code><pre>.*?</pre>)''',
+ 'lilypond-file': r'(?m)(?P<match><lilypondfile(?P<options>[^>]+)?>\s*(?P<filename>[^<]+)\s*</lilypondfile>)',
+ 'lilypond' : '(?m)(?P<match><lilypond((?P<options>[^:]*):)(?P<code>.*?)/>)',
+ 'lilypond-block': r'''(?ms)(?P<match><lilypond(?P<options>[^>]+)?>(?P<code>.*?)</lilypond>)''',
+ 'option-sep' : '\s*',
+ 'intertext': r',?\s*intertext=\".*?\"',
+ 'multiline-comment': r"(?sm)\s*(?!@c\s+)(?P<code><!--\s.*?!-->)\s",
+ 'singleline-comment': no_match,
+ 'numcols': no_match,
+ 'multicols': no_match,
+ 'ly2dvi': r'(?m)(?P<match><ly2dvifile(?P<options>[^>]+)?>\s*(?P<filename>[^<]+)\s*</ly2dvifile>)',
+ },
+
+ 'latex': {
+ 'input': r'(?m)^[^%\n]*?(?P<match>\\mbinput{?([^}\t \n}]*))',
+ 'include': r'(?m)^[^%\n]*?(?P<match>\\mbinclude{(?P<filename>[^}]+)})',
+ 'option-sep' : ',\s*',
+ 'header': r"\n*\\documentclass\s*(\[.*?\])?",
+ 'preamble-end': r'(?P<code>\\begin\s*{document})',
+ 'verbatim': r"(?s)(?P<code>\\begin\s*{verbatim}.*?\\end{verbatim})",
+ 'verb': r"(?P<code>\\verb(?P<del>.).*?(?P=del))",
+ 'lilypond-file': r'(?m)^[^%\n]*?(?P<match>\\lilypondfile\s*(\[(?P<options>.*?)\])?\s*\{(?P<filename>.+)})',
+ 'lilypond' : r'(?m)^[^%\n]*?(?P<match>\\lilypond\s*(\[(?P<options>.*?)\])?\s*{(?P<code>.*?)})',
+ 'lilypond-block': r"(?sm)^[^%\n]*?(?P<match>\\begin\s*(\[(?P<options>.*?)\])?\s*{lilypond}(?P<code>.*?)\\end{lilypond})",
+ 'def-post-re': r"\\def\\postLilyPondExample",
+ 'def-pre-re': r"\\def\\preLilyPondExample",
+ 'usepackage-graphics': r"\usepackage\s*{graphics}",
+ 'intertext': r',?\s*intertext=\".*?\"',
+ 'multiline-comment': no_match,
+ 'singleline-comment': r"(?m)^.*?(?P<match>(?P<code>^%.*$\n+))",
+ 'numcols': r"(?P<code>\\(?P<num>one|two)column)",
+ 'multicols': r"(?P<code>\\(?P<be>begin|end)\s*{multicols}({(?P<num>\d+)?})?)",
+ 'ly2dvi': no_match,
+
+ },
+
+ # why do we have distinction between @mbinclude and @include?
+
+ 'texi': {
+ 'include': '(?m)^[^%\n]*?(?P<match>@mbinclude\s+(?P<filename>\S*))',
+ 'input': no_match,
+ 'header': no_match,
+ 'preamble-end': no_match,
+ 'landscape': no_match,
+ 'verbatim': r'''(?s)(?P<code>@example\s.*?@end example\s)''',
+ 'verb': r'''(?P<code>@code{.*?})''',
+ 'lilypond-file': '(?m)^(?P<match>@lilypondfile(\[(?P<options>[^]]*)\])?{(?P<filename>[^}]+)})',
+ 'lilypond' : '(?m)^(?P<match>@lilypond(\[(?P<options>[^]]*)\])?{(?P<code>.*?)})',
+ 'lilypond-block': r'''(?ms)^(?P<match>@lilypond(\[(?P<options>[^]]*)\])?\s(?P<code>.*?)@end lilypond)\s''',
+ 'option-sep' : ',\s*',
+ 'intertext': r',?\s*intertext=\".*?\"',
+ 'multiline-comment': r"(?sm)^\s*(?!@c\s+)(?P<code>@ignore\s.*?@end ignore)\s",
+ 'singleline-comment': r"(?m)^.*?(?P<match>(?P<code>@c.*$\n+))",
+ 'numcols': no_match,
+ 'multicols': no_match,
+ 'ly2dvi': no_match,
+ }
+ }
+
+
+for r in re_dict.keys ():
+ olddict = re_dict[r]
+ newdict = {}
+ for k in olddict.keys ():
+ try:
+ newdict[k] = re.compile (olddict[k])
+ except:
+ print 'invalid regexp: %s' % olddict[k]
+
+ ## we'd like to catch and reraise a more
+ ## detailed error, but alas, the exceptions
+ ## changed across the 1.5/2.1 boundary.
+
+ raise "Invalid re"
+ re_dict[r] = newdict
+
+
+def uniq (list):
+ list.sort ()
+ s = list
+ list = []
+ for x in s:
+ if x not in list:
+ list.append (x)
+ return list
+
+
+def get_output (name):
+ return output_dict[format][name]
+
+def get_re (name):
+ return re_dict[format][name]
+
+def bounding_box_dimensions (fname):
+ if g_outdir:
+ fname = os.path.join (g_outdir, fname)
+ try:
+ fd = open (fname)
+ except IOError:
+ error ("Error opening `%s'" % fname)
+ str = fd.read ()
+ s = re.search ('%%BoundingBox: ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+)', str)
+ if s:
+
+ gs = map (lambda x: string.atoi (x), s.groups ())
+ return (int (gs[2] - gs[0] + 0.5),
+ int (gs[3] - gs[1] + 0.5))
+ else:
+ return (0,0)
+
+def error (str):
+ sys.stderr.write ("\n\n" + str + "\nExiting ... \n\n")
+ raise 'Exiting.'
+
+
+def compose_full_body (body, opts):
+ '''Construct the lilypond code to send to LilyPond.
+ Add stuff to BODY using OPTS as options.'''
+ music_size = default_music_fontsize
+ if g_force_music_fontsize:
+ music_size = g_force_music_fontsize
+ indent = ''
+ linewidth = ''
+ notime = ''
+ for o in opts:
+ if not g_force_music_fontsize:
+ m = re.match ('([0-9]+)pt', o)
+ if m:
+ music_size = string.atoi (m.group (1))
+
+ m = re.match ('indent=([-.0-9]+)(cm|in|mm|pt)', o)
+ if m:
+ f = float (m.group (1))
+ indent = 'indent = %f\\%s' % (f, m.group (2))
+
+ m = re.match ('linewidth=([-.0-9]+)(cm|in|mm|pt)', o)
+ if m:
+ f = float (m.group (1))
+ linewidth = 'linewidth = %f\\%s' % (f, m.group (2))
+
+ if re.search ('\\\\score', body):
+ is_fragment = 0
+ else:
+ is_fragment = 1
+ if 'fragment' in opts:
+ is_fragment = 1
+ if 'nofragment' in opts:
+ is_fragment = 0
+
+ if is_fragment and not 'multiline' in opts:
+ opts.append ('singleline')
+
+ if 'raggedright' in opts or 'singleline' in opts:
+ if not linewidth:
+ linewidth = 'raggedright = ##t'
+ if not indent:
+ indent = 'indent = 0.0\mm'
+ elif not linewidth:
+ global paperguru
+ l = paperguru.get_linewidth ()
+ linewidth = 'linewidth = %f\pt' % l
+
+ if 'noindent' in opts:
+ indent = 'indent = 0.0\mm'
+
+ if 'notime' in opts:
+ notime = r'''
+\translator {
+ \StaffContext
+ \remove Time_signature_engraver
+}
+'''
+
+ orig_name = ''
+ for o in opts:
+ m= re.search ('relative(.*)', o)
+ v = 0
+ if m:
+ try:
+ v = string.atoi (m.group (1))
+ except ValueError:
+ pass
+
+ v = v + 1
+ pitch = 'c'
+ if v < 0:
+ pitch = pitch + '\,' * v
+ elif v > 0:
+ pitch = pitch + '\'' * v
+
+ body = '\\relative %s { %s }' % (pitch, body)
+ m =re.search ("filename=(.*)", o)
+ if m:
+ orig_name = m.group (1)
+
+ if is_fragment:
+ body = r'''
+\score {
+ \notes {
+%s
+ }
+}
+''' % body
+
+ opts = uniq (opts)
+ optstring = string.join (opts, ' ')
+ optstring = re.sub ('\n', ' ', optstring)
+ body = r'''
+%% Generated automatically by: lilypond-book.py
+%% options are %s
+#(set-global-staff-size %d)
+
+\paper {
+ %s
+ %s
+ %s
+}
+''' % (optstring, music_size, linewidth, indent, notime) + body
+
+ if orig_name:
+ body = '\\renameinput \"%s\"\n%s' % (orig_name, body)
+
+
+ # ughUGH not original options
+ return body
+
+def scan_html_preamble (chunks):
+ return
+
+def scan_latex_preamble (chunks):
+ # First we want to scan the \documentclass line
+ # it should be the first non-comment line.
+ # The only thing we really need to know about the \documentclass line
+ # is if there are one or two columns to begin with.
+ idx = 0
+ while 1:
+ if chunks[idx][0] == 'ignore':
+ idx = idx + 1
+ continue
+ m = get_re ('header').match (chunks[idx][1])
+ if not m:
+ error ("Latex documents must start with a \documentclass command")
+ if m.group (1):
+ options = re.split (r',\s*', m.group (1)[1:-1])
+ else:
+ options = []
+ if 'twocolumn' in options:
+ paperguru.m_num_cols = 2
+ break
+
+
+ # Then we add everything before \begin{document} to
+ # paperguru.m_document_preamble so that we can later write this header
+ # to a temporary file in find_latex_dims() to find textwidth.
+ while idx < len (chunks) and chunks[idx][0] != 'preamble-end':
+ if chunks[idx] == 'ignore':
+ idx = idx + 1
+ continue
+ paperguru.m_document_preamble.append (chunks[idx][1])
+ idx = idx + 1
+
+ if len (chunks) == idx:
+ error ("Didn't find end of preamble (\\begin{document})")
+
+ paperguru.find_latex_dims ()
+
+def scan_texi_preamble (chunks):
+ # this is not bulletproof..., it checks the first 10 chunks
+ for c in chunks[:10]:
+ if c[0] == 'input':
+ for s in ('afourpaper', 'afourwide', 'letterpaper',
+ 'afourlatex', 'smallbook'):
+ if string.find (c[1], "@%s" % s) != -1:
+ paperguru.m_papersize = s
+
+
+def scan_preamble (chunks):
+ global format
+ if format == 'html':
+ scan_html_preamble (chunks)
+ elif format == 'latex':
+ scan_latex_preamble (chunks)
+ elif format == 'texi':
+ scan_texi_preamble (chunks)
+
+
+def completize_preamble (chunks):
+ global format
+ if format != 'latex':
+ return chunks
+ pre_b = post_b = graphics_b = None
+ for chunk in chunks:
+ if chunk[0] == 'preamble-end':
+ break
+ if chunk[0] == 'input':
+ m = get_re ('def-pre-re').search (chunk[1])
+ if m:
+ pre_b = 1
+ if chunk[0] == 'input':
+ m = get_re ('def-post-re').search (chunk[1])
+ if m:
+ post_b = 1
+
+ if chunk[0] == 'input':
+ m = get_re ('usepackage-graphics').search (chunk[1])
+ if m:
+ graphics_b = 1
+ x = 0
+ while x < len (chunks) and chunks[x][0] != 'preamble-end':
+ x = x + 1
+
+ if x == len (chunks):
+ return chunks
+
+ if not pre_b:
+ chunks.insert (x, ('input', get_output ('output-default-pre')))
+ if not post_b:
+ chunks.insert (x, ('input', get_output ('output-default-post')))
+ if not graphics_b:
+ chunks.insert (x, ('input', get_output ('usepackage-graphics')))
+
+ return chunks
+
+
+read_files = []
+def find_file (name):
+ '''
+ Search the include path for NAME. If found, return the (CONTENTS, PATH) of the file.
+ '''
+
+ if name == '-':
+ return (sys.stdin.read (), '<stdin>')
+ f = None
+ nm = ''
+ for a in include_path:
+ try:
+ nm = os.path.join (a, name)
+ f = open (nm)
+ global read_files
+ read_files.append (nm)
+ break
+ except IOError:
+ pass
+ if f:
+ sys.stderr.write ("Reading `%s'\n" % nm)
+ return (f.read (), nm)
+ else:
+ error ("File not found `%s'\n" % name)
+ return ('', '')
+
+def do_ignore (match_object):
+ return [('ignore', match_object.group ('code'))]
+def do_preamble_end (match_object):
+ return [('preamble-end', match_object.group ('code'))]
+
+def make_verbatim (match_object):
+ return [('verbatim', match_object.group ('code'))]
+
+def make_verb (match_object):
+ return [('verb', match_object.group ('code'))]
+
+def do_include_file (m):
+ "m: MatchObject"
+ return [('input', get_output ('pagebreak'))] \
+ + read_doc_file (m.group ('filename')) \
+ + [('input', get_output ('pagebreak'))]
+
+def do_input_file (m):
+ return read_doc_file (m.group ('filename'))
+
+def make_lilypond (m):
+ if m.group ('options'):
+ options = m.group ('options')
+ else:
+ options = ''
+ return [('input', get_output ('output-lilypond-fragment') %
+ (options, m.group ('code')))]
+
+def make_lilypond_file (m):
+ '''
+
+ Find @lilypondfile{bla.ly} occurences and substitute bla.ly
+ into a @lilypond .. @end lilypond block.
+
+ '''
+
+ if m.group ('options'):
+ options = get_re ('option-sep').split (m.group ('options'))
+ else:
+ options = []
+ (content, nm) = find_file (m.group ('filename'))
+ options.append ("filename=%s" % nm)
+ (path, base) = os.path.split (nm)
+
+ if path not in include_path:
+ include_path.append (path)
+
+ return [('lilypond', content, options)]
+
+
+def make_ly2dvi_block (m):
+ '''
+
+ Find <ly2dvifile .. >
+ '''
+
+ return [('ly2dvi', m.group ('filename'), m.group ('options'))]
+
+
+def make_lilypond_block (m):
+ if not g_do_music:
+ return []
+
+ if m.group ('options'):
+ options = get_re ('option-sep').split (m.group ('options'))
+ else:
+ options = []
+ options = filter (lambda s: s != '', options)
+ return [('lilypond', m.group ('code'), options)]
+
+
+def do_columns (m):
+ global format
+ if format != 'latex':
+ return []
+ if m.group ('num') == 'one':
+ return [('numcols', m.group ('code'), 1)]
+ if m.group ('num') == 'two':
+ return [('numcols', m.group ('code'), 2)]
+
+def do_multicols (m):
+ global format
+ if format != 'latex':
+ return []
+ if m.group ('be') == 'begin':
+ return [('multicols', m.group ('code'), int (m.group ('num')))]
+ else:
+ return [('multicols', m.group ('code'), 1)]
+ return []
+
+def chop_chunks (chunks, re_name, func, use_match=0):
+ newchunks = []
+ for c in chunks:
+ if c[0] == 'input':
+ str = c[1]
+ while str:
+ m = get_re (re_name).search (str)
+ if m == None:
+ newchunks.append (('input', str))
+ str = ''
+ else:
+ if use_match:
+ newchunks.append (('input', str[:m.start ('match')]))
+ else:
+ newchunks.append (('input', str[:m.start (0)]))
+ #newchunks.extend (func (m))
+ # python 1.5 compatible:
+ newchunks = newchunks + func (m)
+ str = str [m.end (0):]
+ else:
+ newchunks.append (c)
+ return newchunks
+
+def determine_format (str):
+ """
+
+ SIDE EFFECT! This sets FORMAT and PAPERGURU
+
+ """
+
+ global format
+ if format == '':
+ html = re.search ('(?i)<[dh]tml', str[:200])
+ latex = re.search (r'''\\document''', str[:200])
+ texi = re.search ('@node|@setfilename', str[:200])
+
+ f = ''
+ g = None
+
+ if html and not latex and not texi:
+ f = 'html'
+ elif latex and not html and not texi:
+ f = 'latex'
+ elif texi and not html and not latex:
+ f = 'texi'
+ else:
+ error ("can't determine format, please specify")
+ format = f
+
+ global paperguru
+ if paperguru == None:
+ if format == 'html':
+ g = HtmlPaper ()
+ elif format == 'latex':
+ g = LatexPaper ()
+ elif format == 'texi':
+ g = TexiPaper ()
+
+ paperguru = g
+
+
+def read_doc_file (filename):
+ '''Read the input file, find verbatim chunks and do \input and \include
+ '''
+ (str, path) = find_file (filename)
+ determine_format (str)
+
+ chunks = [('input', str)]
+
+ # we have to check for verbatim before doing include,
+ # because we don't want to include files that are mentioned
+ # inside a verbatim environment
+ chunks = chop_chunks (chunks, 'verbatim', make_verbatim)
+
+ chunks = chop_chunks (chunks, 'verb', make_verb)
+ chunks = chop_chunks (chunks, 'multiline-comment', do_ignore)
+ #ugh fix input
+ chunks = chop_chunks (chunks, 'include', do_include_file, 1)
+ chunks = chop_chunks (chunks, 'input', do_input_file, 1)
+ return chunks
+
+
+taken_file_names = {}
+
+def unique_file_name (body):
+ return 'lily-' + `abs (hash (body))`
+
+def schedule_lilypond_block (chunk):
+ '''Take the body and options from CHUNK, figure out how the
+ real .ly should look. The .ly is written, and scheduled in
+ TODO.
+
+ Return: a single chunk.
+
+ The chunk pertaining to the lilypond output
+ has the format (TYPE_STR, MAIN_STR, OPTIONS, TODO, BASE),
+ where TODO has format [basename, extension, extension, ... ]
+ '''
+
+ (type, body, opts) = chunk
+ assert type == 'lilypond'
+ file_body = compose_full_body (body, opts)
+ ## Hmm, we should hash only lilypond source, and skip the
+ ## %options are ...
+ ## comment line
+ basename = unique_file_name (file_body)
+ for o in opts:
+ m = re.search ('filename="(.*?)"', o)
+ if m:
+ basename = m.group (1)
+ if not taken_file_names.has_key (basename):
+ taken_file_names[basename] = 0
+ else:
+ taken_file_names[basename] = taken_file_names[basename] + 1
+ basename = basename + "-t%i" % taken_file_names[basename]
+ update_file (file_body, os.path.join (g_outdir, basename) + '.ly')
+ needed_filetypes = ['tex']
+
+ if format == 'html' or g_make_html:
+ needed_filetypes.append ('eps')
+ needed_filetypes.append ('png')
+ if 'eps' in opts and not ('eps' in needed_filetypes):
+ needed_filetypes.append ('eps')
+
+ pathbase = os.path.join (g_outdir, basename)
+ def must_rebuild (base, ext1, ext2):
+
+ f2 = base + ext2
+ f1 = base + ext1
+ fp2 = base + '-page1' + ext2
+
+ isfile2 = os.path.isfile (f2)
+
+ if not isfile2 and os.path.isfile (fp2):
+ f2 = fp2
+ isfile2 = os.path.isfile (fp2)
+
+ if (os.path.isfile (f2) and isfile2 and
+ os.stat (f1)[stat.ST_MTIME] >
+ os.stat (f2)[stat.ST_MTIME]) or \
+ not isfile2:
+
+ return 1
+
+ todo = []
+ if 'tex' in needed_filetypes and must_rebuild (pathbase, '.ly', '.tex'):
+ todo.append ('tex')
+ if 'eps' in needed_filetypes and must_rebuild (pathbase, '.tex', '.eps'):
+ todo.append ('eps')
+ if 'png' in needed_filetypes and must_rebuild (pathbase, '.eps', '.png'):
+ todo.append ('png')
+
+ return ('lilypond', body, opts, todo, basename)
+
+def format_lilypond_block (chunk):
+ """
+
+ Figure out what should be left MAIN_STR (meant
+ for the main file) from a lilypond chunk: process
+ verbatim, and other options. Return: multiple chunks.
+
+
+ """
+
+
+ return_chunks = []
+
+ (type, body, opts, todo, basename) = chunk
+ assert type == 'lilypond'
+
+
+ newbody = ''
+ filename_chunk = None
+ if 'printfilename' in opts:
+ for o in opts:
+ m= re.match ("filename=(.*)", o)
+ if m:
+ template = get_output ("output-filename")
+ b = basename + '.ly'
+ human_base = os.path.basename (m.group (1))
+
+ ## todo: include path, but strip
+ ## first part of the path.
+ filename_chunk = ('input', template % (human_base, b,human_base))
+ break
+
+
+ if 'smallverbatim' in opts:
+ newbody += output_verbatim (body, 1)
+ elif 'verbatim' in opts:
+ newbody += output_verbatim (body, 0)
+
+ for o in opts:
+ m = re.search ('intertext="(.*?)"', o)
+ if m:
+ newbody = newbody + "\n"
+ if format == 'texi':
+ newbody = newbody + "@noindent\n"
+ elif format == 'latex':
+ newbody = newbody + "\\noindent\n"
+ newbody = newbody + m.group (1) + "\n"
+
+ if 'noinline' in opts:
+ s = 'output-noinline'
+ elif format == 'latex':
+ if 'quote' in opts:
+ s = 'output-latex-quoted'
+ elif 'eps' in opts:
+ s = 'output-eps'
+ else:
+ s = 'output-latex-noquote'
+ elif format == 'texi':
+ if 'quote' in opts:
+ s = 'output-texi-quoted'
+ else:
+ s = 'output-texi-noquote'
+ else: # format == 'html'
+ s = 'output-html'
+
+ def html_pages (basename):
+ pat = os.path.join (g_outdir, "%s-page*.png"% basename)
+
+ files = glob.glob (pat)
+
+
+ template = '''<img align="center" valign="center"
+ border="0" src="%s" alt="[picture of music]">'''
+
+ str = ''
+ if files == []:
+ files = [basename+'.png' ]
+ else:
+ files = map (os.path.basename, files)
+
+ for f in files:
+ str += template % f
+
+ str = '<a href="%s.ly">%s</a>' % (basename, str)
+
+ return str
+
+
+ newbody = newbody + get_output (s) % {'fn': basename,
+ 'htmlimages': html_pages(basename)
+ }
+
+ if filename_chunk:
+ return_chunks += [filename_chunk]
+
+ return_chunks += [('lilypond', newbody, opts, todo, basename)]
+
+ return return_chunks
+
+def format_lilypond_output_bodies (chunks):
+ newchunks = []
+ for c in chunks:
+
+ if c[0] == 'lilypond':
+ newchunks += format_lilypond_block (c)
+ else:
+ newchunks.append (c)
+
+ return newchunks
+
+
+
+def process_lilypond_blocks (chunks):#ugh rename
+ newchunks = []
+ # Count sections/chapters.
+ for c in chunks:
+ if c[0] == 'lilypond':
+ c = schedule_lilypond_block (c)
+ elif c[0] == 'numcols':
+ paperguru.m_num_cols = c[2]
+ elif c[0] == 'multicols':
+ paperguru.m_multicols = c[2]
+
+ newchunks.append (c)
+
+ return newchunks
+
+def process_ly2dvi_blocks (chunks):
+
+ def process_ly2dvi_block (chunk):
+ """
+
+Run ly2dvi script on filename specified in CHUNK.
+This is only supported for HTML output.
+
+In HTML output it will leave a download menu with ps/pdf/midi etc. in
+a separate HTML file, and a title + preview in the main html file,
+linking to the menu.
+
+ """
+ (tag, name, opts) = chunk
+ assert format == 'html'
+ (content, original_name) = find_file (name)
+
+ original_name = os.path.basename (original_name)
+
+ base = unique_file_name (content)
+ outname = base + '.ly'
+ changed = update_file (content, outname)
+
+ preview = base + ".preview.png"
+ preview_page = base + '-page1.png'
+
+ if changed or not (os.path.isfile (preview) or
+ os.path.isfile (preview_page)):
+
+ ly.system ('%s --preview --postscript --verbose %s ' % (ly2dvi_binary, base) )
+
+ ly.make_ps_images (base + '.ps')
+ ly.system ('gzip -9 - < %s.ps > %s.ps.gz' % (base, base))
+
+ def size_str (fn):
+ b = os.stat(fn)[stat.ST_SIZE]
+ if b < 1024:
+ return '%d bytes' % b
+ elif b < (2 << 20):
+ return '%d kb' % (b >> 10)
+ else:
+ return '%d mb' % (b >> 20)
+
+ exts = {
+ 'pdf' : "Print (PDF, %s)",
+ 'ps.gz' : "Print (gzipped PostScript, %s)",
+ 'png' : "View (PNG, %s)",
+ 'midi' : "Listen (MIDI, %s)",
+ 'ly' : "View source code (%s)",
+ }
+
+ menu = ''
+ page_files = glob.glob ('%s-page*.png' % base)
+
+ for p in page_files:
+ p = p.strip()
+ if os.path.isfile (p):
+ sz = size_str (p)
+ page = re.sub ('.*page([0-9])+.*', 'View page \\1 (PNG picture, %s)\n', p)
+ page = page % sz
+ menu += '<li><a href="%s">%s</a>' % (p, page)
+
+ ext_order = ['ly', 'pdf', 'ps.gz', 'midi']
+ for e in ext_order:
+ fn = base + '.' + e
+ print 'checking,' , fn
+ if not os.path.isfile (fn):
+ continue
+
+ entry = exts[e] % size_str (fn)
+
+ ## TODO: do something like
+ ## this for texinfo/latex as well ?
+
+ menu += '<li><a href="%s">%s</a>\n\n' % (fn, entry)
+
+
+ explanatory_para = """The pictures are 90dpi
+anti-aliased snapshots of the printed output, in PNG format. Both PDF and PS
+use scalable fonts and should look OK at any resolution."""
+
+ separate_menu =r'''
+<title>LilyPond example %s</title>
+
+<h1>%s</h1>
+<p><img src="%s">
+<p>%s
+<p>
+<ul>%s</ul>''' % (original_name,original_name, preview, explanatory_para, menu)
+
+ open (base + '.html','w'). write (separate_menu)
+
+ inline_menu = '<p/><a href="%s.html"><img alt="%s" src="%s"></a><p/>' % (base, original_name, preview)
+
+ return ('ly2dvi', inline_menu)
+
+ newchunks = []
+ for c in chunks:
+ if c[0] == 'ly2dvi':
+ c = process_ly2dvi_block (c)
+ newchunks.append (c)
+
+ return newchunks
+
+def compile_all_files (chunks):
+ global foutn
+ eps = []
+ tex = []
+ png = []
+
+ for c in chunks:
+ if c[0] != 'lilypond':
+ continue
+
+ base = c[4]
+ exts = c[3]
+ for e in exts:
+ if e == 'eps':
+ eps.append (base)
+ elif e == 'tex':
+ #ugh
+ if base + '.ly' not in tex:
+ tex.append (base + '.ly')
+ elif e == 'png' and g_do_pictures:
+ png.append (base)
+ d = os.getcwd ()
+ if g_outdir:
+ os.chdir (g_outdir)
+ if tex:
+ # fixme: be sys-independent.
+ def incl_opt (x):
+ if g_outdir and x[0] != '/' :
+ x = os.path.join (g_here_dir, x)
+ return ' -I %s' % x
+
+ incs = map (incl_opt, include_path)
+ lilyopts = string.join (incs)
+ if do_deps:
+ lilyopts += ' --dependencies'
+ if g_outdir:
+ lilyopts += ' --dep-prefix=' + g_outdir + '/'
+ lilyopts += ' --header=texidoc'
+ texfiles = string.join (tex)
+ cmd = string.join ((lilypond_binary, lilyopts, g_extra_opts,
+ texfiles))
+
+ ly.lilypond_version_check (lilypond_binary, '@TOPLEVEL_VERSION@')
+
+ ly.system (cmd, ignore_error = 0, progress_p = 1)
+
+ #
+ # Ugh, fixing up dependencies for .tex generation
+ #
+ if do_deps:
+ depfiles=map (lambda x: re.sub ('(.*)\.ly', '\\1.dep',
+ x), tex)
+
+ for i in depfiles:
+ f =open (i)
+ text=f.read ()
+ f.close ()
+ text=re.sub ('\n([^:\n]*):',
+ '\n' + foutn + ':', text)
+ f = open (i, 'w')
+ f.write (text)
+ f.close ()
+
+ def to_eps (file):
+ cmd = r"latex '\nonstopmode \input %s'" % file
+ # Ugh. (La)TeX writes progress and error messages on stdout
+ # Redirect to stderr
+ cmd = '(( %s >&2 ) >&- )' % cmd
+
+ ly.system (cmd)
+ ly.system ("dvips -Ppdf -u+lilypond.map -E -o %s.eps %s" % (file, file))
+ map (to_eps, eps)
+
+ for p in png:
+ ly.make_ps_images (p + '.eps', resolution=110)
+ os.chdir (d)
+
+
+def update_file (body, name):
+ '''
+ write the body if it has changed. Return whether BODY has changed.
+ '''
+ same = 0
+ try:
+ f = open (name)
+ fs = f.read (-1)
+ same = (fs == body)
+ except:
+ pass
+
+ if not same:
+ f = open (name , 'w')
+ f.write (body)
+ f.close ()
+
+ return not same
+
+
+def write_deps (fn, target, chunks):
+ global read_files
+ sys.stderr.write ('Writing `%s\'\n' % os.path.join (g_outdir, fn))
+ f = open (os.path.join (g_outdir, fn), 'w')
+ f.write ('%s%s: ' % (g_dep_prefix, target))
+ for d in read_files:
+ f.write ('%s ' % d)
+
+
+ ## There used to be code to write .tex dependencies, but
+ ## that is silly: lilypond-book has its own dependency scheme
+ ## to ensure that all lily-XXX.tex files are there
+
+
+ f.write ('\n')
+ f.close ()
+ read_files = []
+
+def check_texidoc (chunks):
+ ## TODO: put file name in front of texidoc.
+ ##
+ n = []
+ for c in chunks:
+ if c[0] == 'lilypond':
+ (type, body, opts, todo, basename) = c;
+ pathbase = os.path.join (g_outdir, basename)
+ if os.path.isfile (pathbase + '.texidoc') \
+ and 'notexidoc' not in opts:
+ n.append( ('input', '\n@include %s.texidoc\n\n' % basename))
+ n.append (c)
+ return n
+
+
+## what's this? Docme --hwn
+##
+def fix_epswidth (chunks):
+ newchunks = []
+ for c in chunks:
+ if c[0] != 'lilypond' or 'eps' not in c[2]:
+ newchunks.append (c)
+ continue
+
+ mag = 1.0
+ for o in c[2]:
+ m = re.match ('magnification=([0-9.]+)', o)
+ if m:
+ mag = string.atof (m.group (1))
+
+ def replace_eps_dim (match, lmag = mag):
+ filename = match.group (1)
+ dims = bounding_box_dimensions (filename)
+
+ return '%fpt' % (dims[0] *lmag)
+
+ body = re.sub (r'''\\lilypondepswidth{(.*?)}''', replace_eps_dim, c[1])
+ newchunks.append (('lilypond', body, c[2], c[3], c[4]))
+
+ return newchunks
+
+
+##docme: why global?
+foutn=""
+
+def do_file (input_filename):
+ chunks = read_doc_file (input_filename)
+ chunks = chop_chunks (chunks, 'ly2dvi', make_ly2dvi_block, 1)
+ chunks = chop_chunks (chunks, 'lilypond', make_lilypond, 1)
+ chunks = chop_chunks (chunks, 'lilypond-file', make_lilypond_file, 1)
+ chunks = chop_chunks (chunks, 'lilypond-block', make_lilypond_block, 1)
+ chunks = chop_chunks (chunks, 'singleline-comment', do_ignore, 1)
+ chunks = chop_chunks (chunks, 'preamble-end', do_preamble_end)
+ chunks = chop_chunks (chunks, 'numcols', do_columns)
+ chunks = chop_chunks (chunks, 'multicols', do_multicols)
+
+ scan_preamble (chunks)
+ chunks = process_lilypond_blocks (chunks)
+ chunks = process_ly2dvi_blocks (chunks)
+
+ # Do It.
+ global g_run_lilypond
+ if g_run_lilypond:
+ compile_all_files (chunks)
+ chunks = fix_epswidth (chunks)
+
+
+ chunks = format_lilypond_output_bodies (chunks)
+ global format
+ if format == 'texi':
+ chunks = check_texidoc (chunks)
+
+
+ x = 0
+ chunks = completize_preamble (chunks)
+
+ global foutn
+
+ if outname:
+ my_outname = outname
+ elif input_filename == '-' or input_filename == "/dev/stdin":
+ my_outname = '-'
+ else:
+ my_outname = os.path.basename (os.path.splitext (input_filename)[0]) + '.' + format
+ my_depname = my_outname + '.dep'
+
+ if my_outname == '-' or my_outname == '/dev/stdout':
+ fout = sys.stdout
+ foutn = "<stdout>"
+ global do_deps
+ do_deps = 0
+ else:
+ foutn = os.path.join (g_outdir, my_outname)
+ sys.stderr.write ("Writing `%s'\n" % foutn)
+ fout = open (foutn, 'w')
+ for c in chunks:
+ fout.write (c[1])
+ fout.close ()
+ # should chmod -w
+
+ if do_deps:
+ write_deps (my_depname, foutn, chunks)
+
+outname = ''
+try:
+ (sh, long) = ly.getopt_args (option_definitions)
+ (options, files) = getopt.getopt (sys.argv[1:], sh, long)
+
+except getopt.error, msg:
+ sys.stderr.write ('\n')
+ ly.error (_ ("getopt says: `%s\'" % s))
+ sys.stderr.write ('\n')
+ ly.help ()
+ ly.exit (2)
+
+do_deps = 0
+for opt in options:
+ o = opt[0]
+ a = opt[1]
+
+ if o == '--include' or o == '-I':
+ include_path.append (a)
+ elif o == '--version' or o == '-v':
+ ly.identify (sys.stdout)
+ sys.exit (0)
+ elif o == '--verbose' or o == '-V':
+ verbose_p = 1
+ elif o == '--format' or o == '-f':
+ format = a
+ if a == 'texi-html':
+ format = 'texi'
+ g_make_html = 1
+ elif o == '--outname' or o == '-o':
+ if len (files) > 1:
+ #HACK
+ sys.stderr.write ("lilypond-book is confused by --outname on multiple files")
+ sys.exit (1)
+ outname = a
+ elif o == '--help' or o == '-h':
+ ly.help ()
+ sys.exit (0)
+ elif o == '--no-lily' or o == '-n':
+ g_run_lilypond = 0
+ elif o == '--preview-resolution':
+ preview_resolution = string.atoi (a)
+ elif o == '--dependencies' or o == '-M':
+ do_deps = 1
+ elif o == '--default-music-fontsize':
+ default_music_fontsize = string.atoi (a)
+ elif o == '--default-lilypond-fontsize':
+ print "--default-lilypond-fontsize is deprecated, use --default-music-fontsize"
+ default_music_fontsize = string.atoi (a)
+ elif o == '--extra-options':
+ g_extra_opts = a
+ elif o == '--force-music-fontsize':
+ g_force_music_fontsize = string.atoi (a)
+ elif o == '--force-lilypond-fontsize':
+ print "--force-lilypond-fontsize is deprecated, use --default-lilypond-fontsize"
+ g_force_music_fontsize = string.atoi (a)
+ elif o == '--dep-prefix':
+ g_dep_prefix = a
+ elif o == '--no-pictures':
+ g_do_pictures = 0
+ elif o == '--no-music':
+ g_do_music = 0
+ elif o == '--outdir':
+ g_outdir = a
+ elif o == '--warranty' or o == '-w':
+ #status = os.system ('lilypond -w')
+ if 1 or status:
+ ly.warranty ()
+ sys.exit (0)
+
+ly.identify (sys.stderr)
+
+if g_outdir:
+ if os.path.isfile (g_outdir):
+ error ("outdir is a file: %s" % g_outdir)
+ if not os.path.exists (g_outdir):
+ os.mkdir (g_outdir)
+
+if not files:
+ ly.help ()
+ ly.error (_ ("no files specified on command line"))
+ ly.exit (2)
+
+ly.setup_environment ()
+
+
+for input_filename in files:
+ do_file (input_filename)
+
+
+#
+# Petr, ik zou willen dat ik iets zinvoller deed,
+# maar wat ik kan ik doen, het verandert toch niets?
+# --hwn 20/aug/99