* Repeats::
* Rhythmic music::
* Piano music::
-* Tablatures::
+* Tablatures::
* Lyrics::
* Chords::
* Writing parts::
Producing nice slurs is a difficult problem, and LilyPond currently
uses a simple, empiric method to produce slurs. In some cases, the
results of this method don't look too good. This is reflected by the
-@code{beautiful} parameter. It is an arbitrary parameter in the slur
-formatter. Useful values can only be determined by trial and error.
+@code{beautiful} property, which it is an arbitrary parameter in the
+slur formatter. Useful values can only be determined by trial and
+error.
@cindex Adjusting slurs
-@cindex Grace music
@cindex @code{\grace}
@cindex ornaments
@cindex grace notes
-@cindex @code{graceAlignPosition}
+Grace notes are ornaments are written out ornaments
+@lilypond[relative=2,fragment]
+ c4 \grace c16 c4 \grace { [c16 d16] } c4
+@end lilypond
+
+In normal notation, grace notes are supposed to take up no logical
+time in a measure. Such an idea is practical for normal notation, but
+is not strict enough to put it into a program. The model that LilyPond
+uses for grace notes internally is that all timing is done in two
+steps:
+
+Every point in musical time consists of two rational numbers: one
+denotes the logical time, one denotes the grace timing. The above
+example is shown here with timing tuples.
+
+@lilypond[relative=2,fragment]
+ c4^"(0,0)" \grace c16^"(1/4,-1/16)" c4^"(1/4,0)" \grace {
+ [c16^"(2/4,-1/8)" d16^"(2/4,-1/16)" ] } c4^"(2/4,0)"
+@end lilypond
+
+The advantage of this approach is that you can use almost any lilypond
+construction together with grace notes, for example slurs and clef
+changes may appear halfway in between grace notes:
+
+@lilypond[relative=2,fragment]
+ c4 \grace { [ c16 c, \clef bass c, b(] } )c4
+@end lilypond
-Grace notes are ornaments that are written out, but do not take up any
-logical time in a measure. LilyPond has limited support for grace notes.
-The syntax is as follows.
+The placement of these grace notes is synchronized between different
+staffs, using this grace timing.
+
+@lilypond[relative=2,fragment]
+\context Staff = SA { e4 \grace { c16 d e f } e4 }
+\context Staff = SB { c4 \grace { g8 b } c4 }
+@end lilypond
+
+
+The syntax is as follows.
@example
\grace @var{musicexpr}
@end example
@refbugs
+
+Grace note synchronization can also lead to surprises. Staff notation,
+such as key signatures, barlines, etc. are also synchronized. Take
+care when you mix staffs with grace notes and staffs without.
+
+@lilypond[relative=2,fragment]
+\context Staff = SA { e4 \bar "|:" \grace c16 d4 }
+\context Staff = SB { c4 \bar "|:" d4 }
+@end lilypond
+
Nesting @code{\grace} notes is not supported. The following may cause
-run-time errors: @example
+run-time errors:
+@c
+@example
@code{\grace @{ \grace c32 c16 @} c4}
@end example
Since the meaning of such a construct is unclear, we don't consider this
@section Tablatures
@menu
-* Tablatures basic::
-* Non-guitar tablatures::
-* Tablature in addition to normal staff::
+* Tablatures basic::
+* Non-guitar tablatures::
+* Tablature in addition to normal staff::
@end menu
@node Tablatures basic
It is not possible to have bar numbers printed at regular intervals
only.
+Barnumbers can collide with the StaffGroup, if there is one at the
+top. To solve this, You have to twiddle with the padding-property of
+the bar-number if your score starts with a staff-group.
+
@node Instrument names
@subsection Instrument names
* Text markup::
* Invisible grobs::
* Dirty tricks::
+* Spacing::
@end menu
@node Tuning groups of grobs
}
@end lilypond
+@node Spacing
+@subsection Spacing
+
+TODO: Move this section.
+
+
+@refbugs
+
+
+Generating optically pleasing spacing is black magic. LilyPond tries
+to deal with a number of frequent cases. Here is an example that is
+not handled correctly, due to the combination of chord collisions and
+kneed stems.
+
+@lilypond
+\score {
+ \context PianoStaff \notes \transpose c''' <
+ \context Staff = up { s1 }
+ \context Staff = down { [c8 c \translator Staff=up <c d> c
+\translator Staff=down c c c] }
+ >
+ \paper { linewidth = -1 }
+}
+@end lilypond
+
+
@c . {Page layout}
@node Page layout
@lilypond[fragment]
\property Score.timing = ##f
\property Staff.TimeSignature = \turnOff
-\property Staff.noAutoBeaming = ##t
+\property Staff.autoBeaming = ##f
%\property Staff.Clef = \turnOff
\transpose c'' { a1 a2 a4 a16 a32 }
s16_" "
@lilypond[fragment, relative 1]
\property Score.timing = ##f
\property Staff.TimeSignature = \turnOff
-\property Staff.noAutoBeaming = ##t
+\property Staff.autoBeaming = ##f
\property Staff.Clef = \turnOff
[a8 b]
@end lilypond
@lilypond[fragment, relative 1]
\property Score.timing = ##f
\property Staff.TimeSignature = \turnOff
-\property Staff.noAutoBeaming = ##t
+\property Staff.autoBeaming = ##f
\property Staff.Clef = \turnOff
d ~ d
@end lilypond
@lilypond[fragment, relative 1]
\property Score.timing = ##f
\property Staff.TimeSignature = \turnOff
-\property Staff.noAutoBeaming = ##t
+\property Staff.autoBeaming = ##f
\property Staff.Clef = \turnOff
c( d )e
@end lilypond
@lilypond[fragment, relative 1]
\property Score.timing = ##f
\property Staff.TimeSignature = \turnOff
-\property Staff.noAutoBeaming = ##t
+\property Staff.autoBeaming = ##f
\property Staff.Clef = \turnOff
a a'
@end lilypond
@lilypond[fragment, relative 1]
\property Score.timing = ##f
\property Staff.TimeSignature = \turnOff
-\property Staff.noAutoBeaming = ##t
+\property Staff.autoBeaming = ##f
\property Staff.Clef = \turnOff
c c,
@end lilypond
@lilypond[fragment, relative 1]
\property Score.timing = ##f
\property Staff.TimeSignature = \turnOff
-\property Staff.noAutoBeaming = ##t
+\property Staff.autoBeaming = ##f
\property Staff.Clef = \turnOff
\context Voice { <a c> }
@end lilypond
@lilypond[fragment, relative 1]
\property Score.timing = ##f
\property Staff.TimeSignature = \turnOff
-\property Staff.noAutoBeaming = ##t
+\property Staff.autoBeaming = ##f
\property Staff.Clef = \turnOff
a\< a \!a
@end lilypond
@lilypond[fragment, relative 1]
\property Score.timing = ##f
\property Staff.TimeSignature = \turnOff
-\property Staff.noAutoBeaming = ##t
+\property Staff.autoBeaming = ##f
\property Staff.Clef = \turnOff
a\> a \!a
@end lilypond
\addlyrics
\context Staff = mel @{
- \property Staff.noAutoBeaming = ##t
+ \property Staff.autoBeaming = ##f
\property Staff.automaticMelismata = ##t
\melody
@}
\addlyrics
\context Staff = mel {
- \property Staff.noAutoBeaming = ##t
+ \property Staff.autoBeaming = ##f
\property Staff.automaticMelismata = ##t
\melody
}
@separate
@example
- \property Staff.noAutoBeaming = ##t
+ \property Staff.autoBeaming = ##f
@end example
@cindex \property
@cindex context variables
@cindex setting context variables
An interpretation context has variables, called properties, that tune
-its behavior. One of the variables is @code{noAutoBeaming}. Setting
-this @code{Staff}'s property to @code{##t}, which is the boolean value
-@var{true}, turns the automatic beaming mechanism off for the current
+its behavior. One of the variables is @code{autoBeaming}. Setting
+this @code{Staff}'s property to @code{##f}, which is the boolean value
+@var{false}, turns the automatic beaming mechanism off for the current
staff.
@cindex GUILE
@cindex Scheme
-> About lyrics, it happens that there are common words for many bars, like
-> for a refrain say. When there is an even number of lyrics lines, I do not
-> know how to force the positioning of the common lyric line in the plain
-> middle of the others, because this is in between lines. Not a big matter,
-> but it would be a bit nicer if this was doable.
+ > About lyrics, it happens that there are common words for many bars, like
+ > for a refrain say. When there is an even number of lyrics lines, I do not
+ > know how to force the positioning of the common lyric line in the plain
+ > middle of the others, because this is in between lines. Not a big matter,
+ > but it would be a bit nicer if this was doable.
- */
+*/
/*
We find start and end of phrases, and align lyrics of multiple stanzas
that seems to be the case now -- jcn)
- | | | | |
- x| x| x| x| x|
+ | | | | |
+ x| x| x| x| x|
- 1: Start sentence melisma end.
- 2: x x x_____ x
+ 1: Start sentence melisma end.
+ 2: x x x_____ x
Only lyrics that are followed by '__' while there's a melisma,
are left-aligned, in this case the third x.
Alignment and melismata
I've taken [a different] approach:
- | |
- | |
- O O <-- second note throws a melisma score element
- \____/
+ | |
+ | |
+ O O <-- second note throws a melisma score element
+ \____/
- ^ ^
- | |
- Lyric (None)
+ ^ ^
+ | |
+ Lyric (None)
Lyric_phrasing_engraver keeps track of the current and previous notes and
lyrics for each voice, and when it catches a melisma, it adjusts the
alignment of the lyrics of the previous note. I hope this isn't
unnecessarily convoluted.
- */
+*/
Lyric_phrasing_engraver::Lyric_phrasing_engraver ()
{
{
/*
No need to delete alist_; that's what Garbage collection is for.
- */
+ */
}
void
{
/*
but do need to unprotect alist_, since Engravers are gc'd now.
- */
+ */
voice_alist_ = SCM_EOL;
}
Lyric_phrasing_engraver::lookup_context_id (const String &context_id)
{
SCM key = ly_str02scm (context_id.ch_C ());
- if (! gh_null_p (voice_alist_)) {
- SCM s = scm_assoc (key, voice_alist_);
- if (! (gh_boolean_p (s) && !to_boolean (s))) {
- /* match found */
- // (key . ((alist_entry . old_entry) . previous_entry))
- if (to_boolean (ly_cdadr (s))) { // it's an old entry ... make it a new one
- SCM val = gh_cons (gh_cons (ly_caadr (s), SCM_BOOL_F), ly_cddr (s));
- voice_alist_ = scm_assoc_set_x (voice_alist_, ly_car (s), val);
- return unsmob_voice_entry (ly_caar (val));
- }
- else { // the entry is current ... return it.
- SCM entry_scm = ly_caadr (s);
- return unsmob_voice_entry (entry_scm);
- }
+ if (! gh_null_p (voice_alist_))
+ {
+ SCM s = scm_assoc (key, voice_alist_);
+ if (! (gh_boolean_p (s) && !to_boolean (s)))
+ {
+ /* match found */
+ // (key . ((alist_entry . old_entry) . previous_entry))
+ if (to_boolean (ly_cdadr (s)))
+ { // it's an old entry ... make it a new one
+ SCM val = gh_cons (gh_cons (ly_caadr (s), SCM_BOOL_F), ly_cddr (s));
+ voice_alist_ = scm_assoc_set_x (voice_alist_, ly_car (s), val);
+ return unsmob_voice_entry (ly_caar (val));
+ }
+ else { // the entry is current ... return it.
+ SCM entry_scm = ly_caadr (s);
+ return unsmob_voice_entry (entry_scm);
+ }
+ }
}
- }
// ((alist_entry . old_entry) . previous_entry)
SCM val = gh_cons (gh_cons (Syllable_group::make_entry (), SCM_BOOL_F),
- Syllable_group::make_entry ());
+ Syllable_group::make_entry ());
voice_alist_ = scm_acons (key, val, voice_alist_);
return unsmob_voice_entry (ly_caar (val));
void
Lyric_phrasing_engraver::record_notehead (const String &context_id,
- Grob * notehead)
+ Grob * notehead)
{
Syllable_group * v = lookup_context_id (context_id);
v->set_notehead (notehead);
Lyric_phrasing_engraver::record_extender (const String &context_id, Grob * extender)
{
SCM key = ly_str02scm (context_id.ch_C ());
- if (! gh_null_p (voice_alist_)) {
- SCM s = scm_assoc (key, voice_alist_);
- if (! (gh_boolean_p (s) && !to_boolean (s))) {
- /* match found */
- // (key . ((alist_entry . old_entry) . previous_entry))
- SCM previous_scm = ly_cddr (s);
- if (previous_scm != SCM_EOL) {
- Syllable_group * v = unsmob_voice_entry (previous_scm);
- v->add_extender (extender);
- }
+ if (! gh_null_p (voice_alist_))
+ {
+ SCM s = scm_assoc (key, voice_alist_);
+ if (! (gh_boolean_p (s) && !to_boolean (s)))
+ {
+ /* match found */
+ // (key . ((alist_entry . old_entry) . previous_entry))
+ SCM previous_scm = ly_cddr (s);
+ if (previous_scm != SCM_EOL)
+ {
+ Syllable_group * v = unsmob_voice_entry (previous_scm);
+ v->add_extender (extender);
+ }
+ }
}
- }
}
void
Grob *h = i.grob_l_;
- if (Note_head::has_interface (h)) {
- /* caught a note head ... do something with it */
+ if (Note_head::has_interface (h))
+ {
+ /* caught a note head ... do something with it */
- /* what's its Voice context name? */
- String voice_context_id = get_context_id (i.origin_trans_l_->daddy_trans_l_, "Voice");
- record_notehead (voice_context_id, h);
+ /* what's its Voice context name? */
+ String voice_context_id = get_context_id (i.origin_trans_l_->daddy_trans_l_, "Voice");
+ record_notehead (voice_context_id, h);
- /* is it in a melisma ? */
- if (to_boolean (i.origin_trans_l_->get_property ("melismaEngraverBusy"))) {
- record_melisma (voice_context_id);
+ /* is it in a melisma ? */
+ if (to_boolean (i.origin_trans_l_->get_property ("melismaEngraverBusy")))
+ {
+ record_melisma (voice_context_id);
+ }
+ return;
}
- return;
- }
/* now try for a lyric */
- if (h->internal_has_interface (ly_symbol2scm ("lyric-syllable-interface"))) {
-
- /* what's its LyricsVoice context name? */
- String voice_context_id;
- SCM voice_context_scm = i.origin_trans_l_->get_property ("associatedVoice");
- if (gh_string_p (voice_context_scm)) {
- voice_context_id = ly_scm2string (voice_context_scm);
- }
- else {
- voice_context_id = get_context_id (i.origin_trans_l_->daddy_trans_l_, "LyricsVoice");
- voice_context_id = trim_suffix (voice_context_id);
+ if (h->internal_has_interface (ly_symbol2scm ("lyric-syllable-interface")))
+ {
+
+ /* what's its LyricsVoice context name? */
+ String voice_context_id;
+ SCM voice_context_scm = i.origin_trans_l_->get_property ("associatedVoice");
+ if (gh_string_p (voice_context_scm))
+ {
+ voice_context_id = ly_scm2string (voice_context_scm);
+ }
+ else {
+ voice_context_id = get_context_id (i.origin_trans_l_->daddy_trans_l_, "LyricsVoice");
+ voice_context_id = trim_suffix (voice_context_id);
+ }
+ record_lyric (voice_context_id, h);
+ return;
}
- record_lyric (voice_context_id, h);
- return;
- }
/* Catch any extender items and then if we have a melisma,
set the RIGHT item of the extender spanner to the melismatic note in
then ignore it and let the Extender_engraver take care of it (i.e. finish at next
lyric).
*/
- if (h->internal_has_interface (ly_symbol2scm ("lyric-extender-interface"))) {
- String voice_context_id = get_context_id (i.origin_trans_l_->daddy_trans_l_, "LyricsVoice");
- record_extender (trim_suffix (voice_context_id), h);
- return;
- }
+ if (h->internal_has_interface (ly_symbol2scm ("lyric-extender-interface")))
+ {
+ String voice_context_id = get_context_id (i.origin_trans_l_->daddy_trans_l_, "LyricsVoice");
+ record_extender (trim_suffix (voice_context_id), h);
+ return;
+ }
}
String
get_context_id (Translator_group * ancestor, const char *type)
{
- while (ancestor != 0 && ancestor->type_str_ != type) {
- ancestor = ancestor->daddy_trans_l_;
- }
+ while (ancestor != 0 && ancestor->type_str_ != type)
+ {
+ ancestor = ancestor->daddy_trans_l_;
+ }
- if (ancestor != 0) {
- return ancestor->id_str_;
- }
+ if (ancestor != 0)
+ {
+ return ancestor->id_str_;
+ }
return "";
}
trim_suffix (String &id)
{
int index = id.index_i ('-');
- if (index >= 0) {
- return id.left_str (index);
- }
+ if (index >= 0)
+ {
+ return id.left_str (index);
+ }
return id;
}
-void Lyric_phrasing_engraver::create_grobs ()
+void
+Lyric_phrasing_engraver::create_grobs ()
{
+ SCM p = get_property ("automaticPhrasing");
+ if (!to_boolean (p))
+ return;
+
+
/* iterate through entries in voice_alist_
for each, call set_lyric_align (alignment). Issue a warning if this returns false.
*/
SCM sp = get_property ("phrasingPunctuation");
punc = gh_string_p (sp) ? ly_scm2string (sp) : ".,;:?!\"";
- for (SCM v=voice_alist_; gh_pair_p (v); v = ly_cdr (v)) {
- SCM v_entry = ly_cdar (v);
- // ((current . oldflag) . previous)
- if (!to_boolean (ly_cdar (v_entry))) { // not an old entry left over from a prior note ...
- Syllable_group *entry = unsmob_voice_entry (ly_caar (v_entry));
-
- /*
- TODO: give context for warning.
- */
- if (! entry->set_lyric_align (punc.ch_C (), any_notehead_l_))
- warning (_ ("lyrics found without any matching notehead"));
-
- // is this note melismatic? If so adjust alignment of previous one.
- if (entry->get_melisma ()) {
- if (entry->lyric_count ())
- warning (_ ("Huh? Melismatic note found to have associated lyrics."));
- SCM previous_scm = ly_cdr (v_entry);
- if (previous_scm != SCM_EOL) {
- Syllable_group *previous = unsmob_voice_entry (previous_scm);
- if (previous->lyric_count ())
- previous->adjust_melisma_align ();
+ for (SCM v=voice_alist_; gh_pair_p (v); v = ly_cdr (v))
+ {
+ SCM v_entry = ly_cdar (v);
+ // ((current . oldflag) . previous)
+ if (!to_boolean (ly_cdar (v_entry)))
+ { // not an old entry left over from a prior note ...
+ Syllable_group *entry = unsmob_voice_entry (ly_caar (v_entry));
+
+ /*
+ TODO: give context for warning.
+ */
+ if (! entry->set_lyric_align (punc.ch_C (), any_notehead_l_))
+ warning (_ ("lyrics found without any matching notehead"));
+
+ // is this note melismatic? If so adjust alignment of previous one.
+ if (entry->get_melisma ())
+ {
+ if (entry->lyric_count ())
+ warning (_ ("Huh? Melismatic note found to have associated lyrics."));
+ SCM previous_scm = ly_cdr (v_entry);
+ if (previous_scm != SCM_EOL)
+ {
+ Syllable_group *previous = unsmob_voice_entry (previous_scm);
+ if (previous->lyric_count ())
+ previous->adjust_melisma_align ();
+ }
+ }
}
- }
}
- }
}
void
Lyric_phrasing_engraver::stop_translation_timestep ()
{
- for (SCM v=voice_alist_; gh_pair_p (v); v = ly_cdr (v)) {
- SCM entry_scm = ly_cdar (v);
- // ((alist_entry . entry_is_old) . previous_entry)
- Syllable_group * entry = unsmob_voice_entry (ly_caar (entry_scm));
-
- // set previous_entry, set entry_is_old, and resave it to alist_
- // but only change if this current was not old.
- if (! to_boolean (ly_cdar (entry_scm))) {
- Syllable_group * previous_entry = unsmob_voice_entry (ly_cdr (entry_scm));
- previous_entry->copy (entry);
- entry_scm = gh_cons (gh_cons (ly_caar (entry_scm), SCM_BOOL_T), ly_cdr (entry_scm));
- voice_alist_ = scm_assoc_set_x (voice_alist_, ly_caar (v), entry_scm);
+ for (SCM v=voice_alist_; gh_pair_p (v); v = ly_cdr (v))
+ {
+ SCM entry_scm = ly_cdar (v);
+ // ((alist_entry . entry_is_old) . previous_entry)
+ Syllable_group * entry = unsmob_voice_entry (ly_caar (entry_scm));
+
+ // set previous_entry, set entry_is_old, and resave it to alist_
+ // but only change if this current was not old.
+ if (! to_boolean (ly_cdar (entry_scm)))
+ {
+ Syllable_group * previous_entry = unsmob_voice_entry (ly_cdr (entry_scm));
+ previous_entry->copy (entry);
+ entry_scm = gh_cons (gh_cons (ly_caar (entry_scm), SCM_BOOL_T), ly_cdr (entry_scm));
+ voice_alist_ = scm_assoc_set_x (voice_alist_, ly_caar (v), entry_scm);
+ }
+ entry->next_lyric ();
}
- entry->next_lyric ();
- }
any_notehead_l_ = 0;
}
ENTER_DESCRIPTION(Lyric_phrasing_engraver,
-/* descr */ "",
-/* creats*/ "",
-/* acks */ "lyric-syllable-interface note-head-interface lyric-extender-interface",
-/* reads */ "automaticPhrasing melismaEngraverBusy associatedVoice phrasingPunctuation",
-/* write */ "");
+ /* descr */ "",
+ /* creats*/ "",
+ /* acks */ "lyric-syllable-interface note-head-interface lyric-extender-interface",
+ /* reads */ "automaticPhrasing melismaEngraverBusy associatedVoice phrasingPunctuation",
+ /* write */ "");