LilyPond uses a versioning scheme similar to the Linux kernel. In a
version "x.y.z", an even second number 'y' denotes a stable version.
-For development versions 'y' is odd. Sh, in theory, version 1.2 is stable,
+For development versions 'y' is odd. So, in theory, version 1.2 is stable,
which means that there are no glaring errors in it. In practice 1.2.x is also
unmaintained.
@email{gnu-music-discuss@@gnu.org}. Please consult the FAQ and
installation instructions before mailing your problems.
-@section CDROM distributions
-
-If you have received LilyPond on a cdrom, chances are that development
-has moved some patchlevels up. Please check the latest version of
-LilyPond before reporting bugs.
@bye
cd $(outdir) && rm -f lilypond && ln -s . lilypond
cd $(outdir) && rm -f lilypond-internals && ln -s . lilypond-internals
cd $(outdir) && $(foreach i, $(LILYPOND_LINKS),\
- rm -f $(i) && ln -s $(i) lilypond.html &&) true
+ rm -f $(i) && ln -s lilypond.html $(i) &&) true
endif
@itemize @bullet
-@item @strong{important:} a sample input which causes the error.
+@item a sample input which causes the error. This is @strong{important
+} to determine the cause of the problem.
(and you will do us a favor if send a @strong{small} sample file)
-@item @strong{important:} which LilyPond version you use.
+@item which LilyPond version you use. This is @strong{important information}
+
This information tells us if you've found a new bug, or an old one.
@c -*-texinfo-*-
-@node Convert-ly
-@section Convert-ly
+@node convert-ly
+@section convert-ly
Convert-ly sequentially applies different
@menu
* Conversion stages:: Lilypond is a multi-pass program.
+* Moment::
* Grobs:: Graphical object
* Engraver::
* Music_iterator::
* Music::
* Molecules:: Molecules are stand-alone descriptions of output
+* Font metrics:: Font metrics
@end menu
@node Conversion stages
@end table
+@node Moment
+@section Moment
+
+Moment is a rational number. Since GUILE doesn't support them natively,
+so we created our own rational data type.
+
+@defun moment?
+@end defun
+
+@defun make-moment num den
+create the rational number @var{num}/@var{den}.
+@end defun
@node Grobs
@section Grobs
* Setting grob properties::
* Items and Spanners::
* Pointer substitution::
+* Grob Scheme functions::
@end menu
@node What is a grob?
the grob is made. A substitution process redirects all grob-reference
so that spanner grob will only reference other grobs in the same line.
+@node Grob Scheme functions
+@unnumberedsubsec Grob Scheme functions
+
+
+@defun ly-get-grob-property g sym
+ Get the value of a value in grob @var{g} of property @var{sym}. It
+will return @code{'()} (end-of-list) if not true.
+@end defun
+
+@defun ly-set-grob-property g sym val
+@end defun
+
+@defun ly-get-spanner-bound spanner dir
+@end defun
+
+@defun ly-grob? g
+@end defun
+
+
+
@node Engraver
@section Engraver
be a Scheme function taking one argument (the grob) and returning a
Molecule.
+@defun molecule? m
+@end defun
+
+@defun ly-combine-molecule-at-edge mol1 axis dir mol2 padding
+@end defun
+
+@defun molecule? m
+@end defun
+
+@defun ly-get-molecule-extent! mol axis
+@end defun
+
+@defun ly-set-molecule-extent! mol axis extent
+@end defun
+
+@node Font metrics
+@section Font metrics
+
+The font object represents the metric information of a font. Every font
+that is loaded into LilyPond can be accessed via Scheme.
+
+[tfm vs. afm]
+
+
+@defun ly-get-default-font gr
+This returns the default font for grob @var{gr}.
+@end defun
+
+@defun ly-find-glyph-by-name font name
+This function retrieves a Molecule for the glyph named @var{name} in
+@var{font}. The font must be available as a afm file.
+@cindex afm file
+
+@end defun
@node Development
@uref{http://www.cs.uu.nl/~hanwen/lily-devel,Han-Wen}. Modifying
LilyPond almost always requires patches to the C++ part.
+If you still don't have any idea what to do, you might want to browse
+the mailing lists; Users do lots of feature requests, and you could
+implement any of them.
+
+
There are also numerous other interesting projects that are more or less
related to LilyPond
* Bug reports:: Where to report bugs.
* Reference Manual:: Reference Manual.
* Features:: Features, tips and tricks.
-* Internals:(lilypond-internals). Auto generated detailed documentation.
-* Programs:: External programs.
+* Utility programs:: External programs.
* Internals:: How it all works.
* Development:: On developing code for LilyPond.
-* Index:: Unified index.
+* Index of internals:(lilypond-internals). Auto generated detailed documentation.
+* Index:: Unified index.
+* Function Index:: Function index.
@end menu
@contents
@printindex cp
+@node Function Index
+@unnumbered Function Index
+
+@printindex fn
+
+
+
@bye
@c -*-texinfo-*-
-@node Ly2dvi
-@section Ly2dvi
+@node ly2dvi
+@section ly2dvi
Ly2dvi is a Python script which creates input file for La@TeX{},
based on information from the output files from LilyPond.
@c -*-texinfo-*-
-@node Midi2ly
-@section Midi2ly
+@node midi2ly
+@section midi2ly
Midi2ly translates a MIDI input file to a LilyPond source file.
Midi2ly is part of the GNU LilyPond music typesetting package.
@c -*-texinfo-*-
-@node Programs
-@chapter Programs
+@node Utility programs
+@chapter Utility programs
@menu
-* Ly2dvi:: Generating nice output with titles.
-* Convert-ly:: Upgrading input files.
-* Midi2ly:: Converting from MIDI input.
+* ly2dvi:: Generating nice output with titles.
+* convert-ly:: Upgrading input files.
+* midi2ly:: Converting from MIDI input.
@end menu
@mbinclude ly2dvi.itexi
--- /dev/null
+
+% y-pos of f is wrong
+
+\score {
+ \notes \relative c' \context Voice = viola {
+ <c4-\f g' c>
+ \stemDown g'8. b,16
+ s1 s2. r4
+ g }
+}
-\score
-{
- \context StaffGroup = a <
- \context PianoStaff = b <
- \context Staff = "c" \notes\relative c'' { b4 b \bar "empty"; \break b b }
- \context Staff = "d" \notes\relative c'' { b4 b b b }
- >
- >
- \paper {
- indent=100.0\mm;
- linewidth=150.0\mm;
- \translator {
- \StaffContext
- \consists "Instrument_name_engraver";
- numberOfStaffLines = #1
- marginScriptPadding = #30 % urg: this is in PT
- instrument = #"Foo"
- instr = #"Bar"
- }
- \translator {
- \StaffGroupContext
- \consists "Instrument_name_engraver";
- marginScriptPadding = #10 % urg: this is in PT
- instrument = #"Piano in het midden"
- }
- }
-}
\header{
texidoc="
-As a last resort, the placement of items can be adjusted manually, by
-setting the @code{extra-offset} of an output object.
+As a last resort, the placement of grobs can be adjusted manually, by
+setting the @code{extra-offset} of a grob.
";
}
}
\paper{
linewidth=-1.0;
- \translator {
- \ScoreContext
- \consists "Mark_engraver";
- }
}
}
\header{
-texidoc="
-Simple glissando lines between notes are supported. The first two glissandi are not consecutive.
+
+texidoc=" Simple glissando lines between notes are supported.
+The first two glissandi are not consecutive.
+
+The engraver does no time-keeping, so it involves some trickery to get
+< @{ s8 s8 s4 @} @{ c4 \\gliss d4 @} > working correctly.
+
";
}
\score{
\context Staff=one \notes\relative c''{
- % gliss non gliss and
- c \glissando d e \glissando f\break
+ % gliss non gliss and
+ c4 \glissando d e \glissando f \glissando \break
% consecutive
- c \glissando d \glissando e f
+ c \glissando d \glissando e
+ < { \stemUp e8 \glissando g8 }
+ \context Voice = VB {\stemDown \repeat unfold 4 d16 } >
+
}
\paper{
linewidth = 70.\mm;
% \remove Clef_engraver;
}
}
-}
\ No newline at end of file
+}
-% :-(
x = {
-\outputproperty #(make-type-checker 'Note_head) #'extra-offset = #'(-1 . 0)
+\outputproperty #(make-type-checker 'note-head-interface) #'extra-offset = #'(-1 . 0)
}
\score{
linewidth=-1.0\mm;
\translator{
\VoiceContext
-slurVerticalDirection = #1
-stemVerticalDirection = #-1
+Slur \override #'direction = #1
+Stem \override #'direction = #-1
}
}
}
\version "1.3.117";
\score{
\context Voice\notes \relative c''{
- %%?
- \property Voice.textVerticalDirection = #1
- %% burp, is this in staff or half spaces, or what?
- \property Voice.textScriptPadding = #15
+ \property Voice.Text \set #'direction = #1
+ \property Voice.TextScript \set #'padding = #5
a1:4^":4" a:8^":8" c:16^":16" a:32^":32" a^"x" a:^":"
a4:4 c:8 a:16 c:32 a a: a2:
\break
\include "paper16.ly";
+stemdown = \property Voice.Stem \override #'direction = #-1
+stemup = \property Voice.Stem \override #'direction = #1
+stemboth = \property Voice.Stem \revert #'direction
+
viola = \notes \relative c' \context Voice = viola {
<c4-\f g' c>
- \property Voice.verticalDirection = \down g'8. b,16
+ \stemdown g'8. b,16
s1 s2. r4
g
}
\context Voice = oboeTwo {
\stemdown
\grace {
- \property Grace.verticalDirection = \down
+ \property Grace.Stem \override #'direction = #-1
[f,16 g] }
f8 e e2
} >
[<c16( e> < )e8. g>] <c8 e,>
}
-hoomPah = \notes \transpose c' {
- c8 \translator Staff = top \stemdown
- c'8 \translator Staff = bottom \stemup }
-
-hoomPahHoomPah = { [\hoomPah \hoomPah] }
+hoomPah = \notes \repeat unfold 8 \transpose c' { c8 \stemdown c'8 \stemup }
bassvoices = \notes \relative c' {
c4 g8. b,16
- \hoomPahHoomPah \hoomPahHoomPah \hoomPahHoomPah \hoomPahHoomPah
+ \autochange Staff \hoomPah o
+ \translator Staff = down
\stemdown [c8 c'8] r4
<g d'> r4
< {\stemup r2 <e4 c'> <c8 g'> }
\score {
\context PianoStaff \notes <
- \context Staff = top < \time 2/2;
- \context Voice = viola \viola
+ \context Staff = up < \time 2/2;
+ \viola
\oboes
>
- \context Staff = bottom < \time 2/2; \clef bass;
+ \context Staff = down < \time 2/2; \clef bass;
\bassvoices
>
>
indent = 0.0;
linewidth = 15.0 \cm; }
}
-
-
-
--- /dev/null
+
+accompMotif = \notes \relative c {
+ \times 2/3 { c8 g' es' }
+ \times 2/3 { c' es, g, }
+}
+
+accomp = \notes \relative c' \autochange Staff {
+ \autoBeamOff
+ <c2-\arpeggio es g>
+ r8 d-.
+ \showStaffSwitch
+ f, b,
+ \hideStaffSwitch
+ \autoBeamOn
+ \repeat unfold 2 \accompMotif
+}
+piano = \context PianoStaff \notes <
+ \context Staff = up <
+ s1*2
+ \accomp
+ >
+ \context Staff = down { \clef bass; s1*2 }
+>
+
+saw = \context Staff \notes {
+ \property Staff.clefOctavation = #7
+ r1 b'''2 - \glissando ais'''2
+}
+
+\score {
+ < \saw \piano >
+}
+
--- /dev/null
+
+\score {
+
+\notes {\notes \reletive c' {
+ \times 2/3 { [fis8 fis8 fis8] }
+ \times 2/3 { [b b b] }
+ bes4
+}
*/
-#include "auto-change-music.hh"
+#include "music.hh"
#include "auto-change-iterator.hh"
#include "translator-group.hh"
#include "musical-request.hh"
{
where_dir_ = s;
String to_id = (s >= 0) ? "up" : "down";
- Auto_change_music const * auto_mus = dynamic_cast<Auto_change_music const* > (music_l_);
-
- String wh = ly_scm2string (auto_mus->get_mus_property ("what"));
+ String wh = ly_scm2string (music_l_->get_mus_property ("what"));
change_to (child_iter_p_, wh, to_id);
}
}
child_iter_p_ = 0;
}
+Chord_tremolo_iterator::Chord_tremolo_iterator (Chord_tremolo_iterator const &src)
+ : Music_iterator (src)
+{
+ child_iter_p_ = src.child_iter_p_? src.child_iter_p_->clone () : 0;
+}
+
void
Chord_tremolo_iterator::process (Moment m)
{
delete alternative_iter_p_;
}
+Folded_repeat_iterator::Folded_repeat_iterator (Folded_repeat_iterator const &src)
+ : Music_iterator (src)
+{
+ main_iter_p_ = src.main_iter_p_ ? src.main_iter_p_->clone () : 0;
+ alternative_iter_p_ = src.alternative_iter_p_ ? src.alternative_iter_p_->clone () : 0;
+ main_length_mom_ = src.main_length_mom_;
+}
+
Moment
Folded_repeat_iterator::pending_moment () const
{
main_iter_p_ = get_iterator_p (mus->body ());
if (!main_iter_p_->ok())
{
- leave_body ();
+ leave_body ();
enter_alternative ();
}
}
-/*
- auto-change-music.hh -- declare Auto_change_music
-
- source file of the GNU LilyPond music typesetter
-
- (c) 1999--2000 Han-Wen Nienhuys <hanwen@cs.uu.nl>
-
- */
-
-#ifndef AUTO_CHANGE_MUSIC_HH
-#define AUTO_CHANGE_MUSIC_HH
-
-#include "music-wrapper.hh"
-
-
-class Auto_change_music : public Music_wrapper
-{
-public:
- Auto_change_music (SCM);
-
-};
-
-
-#endif /* AUTO_CHANGE_MUSIC_HH */
-
+#error
VIRTUAL_COPY_CONS (Music_iterator);
static SCM constructor_cxx_function;
Chord_tremolo_iterator ();
-
+ Chord_tremolo_iterator (Chord_tremolo_iterator const & );
protected:
virtual ~Chord_tremolo_iterator ();
virtual Moment pending_moment () const;
public:
VIRTUAL_COPY_CONS (Music_iterator);
static SCM constructor_cxx_function;
-
+
+ Folded_repeat_iterator (Folded_repeat_iterator const &src);
Folded_repeat_iterator ();
~Folded_repeat_iterator ();
private:
Music_iterator * main_iter_p_;
Music_iterator * alternative_iter_p_;
- int count_;
+
Moment main_length_mom_;
};
#endif /* FOLDED_REPEAT_ITERATOR_HH */
public:
VIRTUAL_COPY_CONS (Music_iterator);
Lyric_combine_music_iterator ();
+ Lyric_combine_music_iterator (Lyric_combine_music_iterator const&src);
static SCM constructor_cxx_function;
protected:
virtual void construct_children ();
class Glissando_req : public Request
{
+public:
VIRTUAL_COPY_CONS (Music);
};
static SCM constructor_cxx_function;
protected:
virtual ~Part_combine_music_iterator ();
-
+ Part_combine_music_iterator (Part_combine_music_iterator const &);
virtual void construct_children ();
virtual Moment pending_moment () const;
virtual void process (Moment);
SCM alternative_cons_;
~Unfolded_repeat_iterator();
Unfolded_repeat_iterator ();
-
+ Unfolded_repeat_iterator (Unfolded_repeat_iterator const &);
protected:
virtual void construct_children ();
virtual Moment pending_moment () const;
delete music_iter_p_;
}
+Lyric_combine_music_iterator::Lyric_combine_music_iterator (Lyric_combine_music_iterator const & src)
+ : Music_iterator (src)
+{
+
+ lyric_iter_p_ = src.lyric_iter_p_ ? src.lyric_iter_p_->clone () : 0;
+ music_iter_p_ = src.music_iter_p_ ? src.music_iter_p_->clone () : 0;
+}
Music_iterator*
Lyric_combine_music_iterator::try_music_in_children (Music *m) const
{
init_moments ()
{
scm_make_gsubr ("make-moment", 2 , 0, 0, (Scheme_function_unknown) make_rational);
- scm_make_gsubr ("make-moment", 2 , 0, 0, (Scheme_function_unknown) make_rational);
}
ADD_SCM_INIT_FUNC(moms,init_moments);
Music_iterator::Music_iterator ()
{
- // clone_i_ = 0;
}
Music_iterator::Music_iterator (Music_iterator const& src)
{
- // clone_i_ = src.clone_i_ + 1;
handle_ = *src.handle_.clone ();
music_l_ = src.music_l_;
music_length_ = src.music_length_;
/**
Create line-spanner grobs for glissandi (and possibly other) lines
that connect note heads.
- */
+
+ TODO: have the line commit suicide if the notes are connected with
+ either slur or beam.
+
+*/
class Note_head_line_engraver : public Engraver
{
public:
{
if (Rhythmic_head::has_interface (info.elem_l_))
{
- last_head_ = head_;
head_ = info.elem_l_;
if (to_boolean (get_property ("followThread")))
{
- Translator* staff = daddy_trans_l_ && daddy_trans_l_->daddy_trans_l_
- ? daddy_trans_l_->daddy_trans_l_->daddy_trans_l_ : 0;
- if (staff != last_staff_)
+ Translator_group * tr = daddy_trans_l_;
+ while (tr && tr->type_str_ != "Staff")
+ tr = tr->daddy_trans_l_ ;
+
+ if (tr && tr->type_str_ == "Staff" && tr != last_staff_)
{
if (last_head_)
follow_ = true;
- last_staff_ = staff;
+ last_staff_ = tr;
}
}
}
}
-static Grob*
-beam_l (Grob *h)
-{
- if (Grob *s = Rhythmic_head::stem_l (h))
- return Stem::beam_l (s);
- return 0;
-}
void
Note_head_line_engraver::create_grobs ()
if (!line_ && (follow_ || last_req_) && last_head_ && head_
&& (last_head_ != head_))
{
- /* Don't follow if there's a beam.
+ /* TODO: Don't follow if there's a beam.
- Hmm, this doesn't work, as head_ does not yet have a beam.
+ We can't do beam-stuff here, since beam doesn't exist yet.
Should probably store follow_ in line_, and suicide at some
later point */
- if (!(follow_
- && beam_l (last_head_) && beam_l (last_head_) == beam_l (head_)))
- {
- if (follow_)
- line_ = new Spanner (get_property ("FollowThread"));
- else
- line_ = new Spanner (get_property ("Glissando"));
+ if (follow_)
+ line_ = new Spanner (get_property ("FollowThread"));
+ else
+ line_ = new Spanner (get_property ("Glissando"));
- line_->set_bound (LEFT, last_head_);
- line_->set_bound (RIGHT, head_);
+ line_->set_bound (LEFT, last_head_);
+ line_->set_bound (RIGHT, head_);
/* Note, mustn't set y-parent of breakable symbol to simple item:
one of the two broken parts won't have an y-parent! */
/* X parent is set by set_bound */
- line_->set_parent (Staff_symbol_referencer::staff_symbol_l (last_head_),
- Y_AXIS);
+ line_->set_parent (Staff_symbol_referencer::staff_symbol_l (last_head_),
+ Y_AXIS);
- announce_grob (line_, last_req_);
- }
+ announce_grob (line_, last_req_);
+ last_req_ = 0;
- last_head_ = 0;
- if (!follow_ && !req_)
- head_ = 0;
-
- last_req_ = 0;
follow_ = false;
}
}
typeset_grob (line_);
line_ = 0;
}
- last_req_ = req_;
- req_ = 0;
+ if (head_)
+ last_head_ = head_;
+ head_ = 0;
+
+ if (req_)
+ {
+ last_req_ = req_;
+ req_ =0;
+ }
}
#include "repeated-music.hh"
#include "lilypond-input-version.hh"
#include "grace-music.hh"
-#include "auto-change-music.hh"
#include "part-combine-music.hh"
#include "scm-hash.hh"
+#include "auto-change-iterator.hh"
#include "chord.hh"
$$ = csm;
}
| AUTOCHANGE STRING Music {
- Auto_change_music * chm = new Auto_change_music (SCM_EOL);
+ Music * chm = new Music_wrapper (SCM_EOL);
chm->set_mus_property ("element", $3->self_scm ());
+ chm->set_mus_property ("iterator-ctor", Auto_change_iterator::constructor_cxx_function);
scm_unprotect_object ($3->self_scm ());
chm->set_mus_property ("what", $2);
a->set_spot (THIS->here_input ());
$$ = a;
}
+ /*
+duh, junk this syntax from the parser, if possible.
+ */
| ARPEGGIO {
Arpeggio_req *a = new Arpeggio_req;
a->set_spot (THIS->here_input ());
delete first_iter_p_;
}
+Part_combine_music_iterator::Part_combine_music_iterator (Part_combine_music_iterator const &src)
+ : Music_iterator (src)
+{
+ second_iter_p_ = src.second_iter_p_ ? src.second_iter_p_->clone () : 0;
+ first_iter_p_ = src.first_iter_p_ ? src.first_iter_p_->clone () : 0;
+
+ first_until_ = src.first_until_;
+ second_until_ = src.second_until_;
+ state_ = src.state_;
+ suffix_ = src.suffix_;
+}
+
Moment
Part_combine_music_iterator::pending_moment () const
{
score_global_array.clear();
inclusion_global_array.clear ();
- scm_unprotect_object (global_header_p ->self_scm ());
+ if (global_header_p)
+ scm_unprotect_object (global_header_p ->self_scm ());
global_header_p =0;
}
delete current_iter_p_;
}
+Unfolded_repeat_iterator::Unfolded_repeat_iterator (Unfolded_repeat_iterator const &src)
+ : Music_iterator (src)
+{
+ done_count_ = src.done_count_;
+ current_iter_p_ = (src.current_iter_p_)? src.current_iter_p_->clone () : 0;
+ do_main_b_ = src.do_main_b_;
+ volta_b_ = src.volta_b_;
+ alternative_count_i_ = src.alternative_count_i_;
+ alternative_cons_ = src.alternative_cons_;
+}
+
Unfolded_repeat_iterator::Unfolded_repeat_iterator ()
{
done_count_ =0;
volta_b_ = false;
do_main_b_ = false;
alternative_count_i_ =0;
+ alternative_cons_ = SCM_EOL;
}
/**
\name Grace;
\consists "Note_performer";
\consists "Tie_performer";
- weAreGraceContext = "1";
+ \consists "Swallow_performer";
+
+ weAreGraceContext = #t
}
\translator
autoBeamOff = \property Voice.noAutoBeaming = ##t
autoBeamOn = \property Voice.noAutoBeaming = ##f
-
emptyText = \property Voice.textNonEmpty = ##f
fatText = \property Voice.textNonEmpty = ##t
+showStaffSwitch = \property Thread.followThread = ##t
+hideStaffSwitch = \property Thread.followThread = ##f
+
+
% To remove a Volta bracet or some other graphical object,
-% set it to turnOff. Example: \property Staff.VoltaBracket = turnOff
+% set it to turnOff. Example: \property Staff.VoltaBracket = \turnOff
turnOff = #'((meta . ((interfaces . ()))))
(eval-string (ly-gulp-file "engraver-documentation-lib.scm"))
(eval-string (ly-gulp-file "backend-documentation-lib.scm"))
-
-
;;(define no-copies #t) ; from 490 to 410K, but doesn't look nice yet
;;
;; Also, copies of interfaces use up lots more space, but that's
("LilyPond context properties" . "context properties")
("LilyPond backend" . "Detailed description of all Grobs")
("LilyPond interfaces" . "Grob Interfaces")
- ("LilyPond backend properties" . "Grob properties")))
+ ("LilyPond backend properties" . "Grob properties")
+ ("Index" . "index")
+ ))
doc
+
+ "@node Index
+@unnumbered Concept index
+
+@printindex cp
+
+@unnumbered Variable index
+
+@printindex vr
+
+@unnumbered Function index
+
+@printindex fn
+
+"
+
+
"\n@bye")
out))
'Note_head_line_engraver
(engraver-description
"Note_head_line_engraver"
- "Engrave a line between two note heads."
- '(Glissando FollowThread)
- '(
- )))
+ "Engrave a line between two note heads, for example a glissando.
+If followThread is set, staff switches also generate a line."
+ '(Glissando)
+ '(followThread)))
(cons
'Note_name_engraver
%s
}
>
-\end{lilypond}""",
- 'output-lilypond':r"""\begin[%s]{lilypond}
+\end{lilypond}""",
+ 'output-filename' : r'''
+
+\verb+%s+:''',
+ 'output-lilypond': r"""\begin[%s]{lilypond}
%s
\end{lilypond}""",
'output-verbatim': "\\begin{verbatim}%s\\end{verbatim}",
%s
@end lilypond
""",
+ 'output-filename' : r'''
+
+@file{%s}:''',
'output-lilypond-fragment': """@lilypond[%s]
\context Staff\context Voice{ %s }
@end lilypond """,
read_files = []
def find_file (name):
"""
- Search the include path for NAME. If found, return the contents of teh file.
+ Search the include path for NAME. If found, return the (CONTENTS, PATH) of the file.
"""
+
f = None
+ nm = ''
for a in include_path:
try:
nm = os.path.join (a, name)
pass
if f:
sys.stderr.write ("Reading `%s'\n" % nm)
- return f.read ()
+ return (f.read (), nm)
else:
error ("File not found `%s'\n" % name)
- return ''
+ return ('', '')
def do_ignore(match_object):
return [('ignore', match_object.group('code'))]
(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 = m.group('options')
else:
options = ''
+ (content, nm) = find_file(m.group('filename'))
+ options = "filename=%s," % nm + options
+
return [('input', get_output('output-lilypond') %
- (options, find_file(m.group('filename'))))]
+ (options, content))]
def make_lilypond_block(m):
if m.group('options'):
def read_doc_file (filename):
"""Read the input file, find verbatim chunks and do \input and \include
"""
- str = find_file(filename)
+ (str, path) = find_file(filename)
determine_format (str)
chunks = [('input', str)]
if 'png' in needed_filetypes and f(pathbase, '.eps', '.png'):
todo.append('png')
newbody = ''
+
+ if 'printfilename' in opts:
+ for o in opts:
+ m= re.match ("filename=(.*)", o)
+ if m:
+ newbody = newbody + get_output ("output-filename") % m.group(1)
+ break
+
+
if 'verbatim' in opts:
newbody = output_verbatim (body)
(type, body, opts, todo, basename) = c;
pathbase = os.path.join (g_outdir, basename)
if os.path.isfile (pathbase + '.texidoc'):
- body = '\n@include %s.texidoc' % basename + body
+ body = '\n@include %s.texidoc\n' % basename + body
c = (type, body, opts, todo, basename)
n.append (c)
return n