From 321cc8ec6586cadfda33dc650198f83906008d36 Mon Sep 17 00:00:00 2001 From: Han-Wen Nienhuys Date: Thu, 1 Jan 2004 23:47:44 +0000 Subject: [PATCH] * lily/lyric-phrasing-engraver.cc: move from new-phrasing-engraver.cc, remove old cruft (syllable-group, lyric-phrasing-engraver.hh) * lyric-align.ly: remove file * scripts/convert-ly.py (FatalConversionError.func): add removal rule for automaticMelismata * ly/engraver-init.ly (ScoreContext): switch on New_phrasing_engraver by default. * lily/slur-engraver.cc (class Slur_engraver): process_acknowledged_grobs -> process_music. (try_music): signal melismata correctly. * lily/lyric-extender.cc (brew_molecule): cleanup. Junk word-space, right-trim-amount, and extend past right bound only for note heads. * lily/new-phrasing-engraver.cc (acknowledge_grob): add lyric-extender support: add note-heads to the extender automatically. * lily/parser.yy: extender is now post_event. * lily/accidental-engraver.cc (number_accidentals): remove spurious warning about non-parent contexts. * scm/define-grobs.scm (all-grob-descriptions): change clef - staffbar distance. --- ChangeLog | 28 +- Documentation/topdocs/NEWS.texi | 20 ++ Documentation/user/refman.itely | 11 +- VERSION | 4 +- input/mutopia/F.Schubert/standchen.ly | 3 +- input/regression/lyric-align.ly | 82 ----- input/regression/lyric-combine.ly | 1 - input/regression/lyric-extender.ly | 8 +- input/regression/lyric-phrasing.ly | 1 - input/template/melody-lyrics-chords.ly | 3 +- input/template/piano-melody-lyrics.ly | 3 +- input/template/satb.ly | 1 - lily/beam-engraver.cc | 4 +- lily/engraver.cc | 3 +- lily/extender-engraver.cc | 91 ++--- lily/grob-info.cc | 7 - lily/hyphen-spanner.cc | 7 +- lily/include/grob-info.hh | 1 - lily/include/lyric-phrasing-engraver.hh | 128 ------- lily/lyric-extender.cc | 51 ++- lily/lyric-phrasing-engraver.cc | 447 ++++++++---------------- lily/new-phrasing-engraver.cc | 188 ---------- lily/parser.yy | 19 +- lily/score-engraver.cc | 9 +- lily/slur-engraver.cc | 17 +- lily/syllable-group.cc | 323 ----------------- lily/tie-engraver.cc | 7 +- lily/translator-group.cc | 2 +- ly/declarations-init.ly | 1 - ly/engraver-init.ly | 61 ++-- ly/params-init.ly | 26 +- ly/performer-init.ly | 29 +- scm/define-grob-properties.scm | 1 - scm/define-grobs.scm | 3 +- scm/define-translator-properties.scm | 5 - scripts/convert-ly.py | 17 +- 36 files changed, 354 insertions(+), 1258 deletions(-) delete mode 100644 input/regression/lyric-align.ly delete mode 100644 lily/include/lyric-phrasing-engraver.hh delete mode 100644 lily/new-phrasing-engraver.cc delete mode 100644 lily/syllable-group.cc diff --git a/ChangeLog b/ChangeLog index 4f92a2899c..bc577d684a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,30 @@ -2004-01-01 Han-Wen Nienhuys +2004-01-02 Han-Wen Nienhuys + + * lily/lyric-phrasing-engraver.cc: move from + new-phrasing-engraver.cc, remove old cruft (syllable-group, + lyric-phrasing-engraver.hh) + + * lyric-align.ly: remove file + + * scripts/convert-ly.py (FatalConversionError.func): add removal + rule for automaticMelismata + + * ly/engraver-init.ly (ScoreContext): switch on + New_phrasing_engraver by default. + + * lily/slur-engraver.cc (class Slur_engraver): + process_acknowledged_grobs -> process_music. + (try_music): signal melismata correctly. + + * lily/lyric-extender.cc (brew_molecule): cleanup. Junk + word-space, right-trim-amount, and extend past right bound only + for note heads. + + * lily/new-phrasing-engraver.cc (acknowledge_grob): add + lyric-extender support: add note-heads to the extender + automatically. + + * lily/parser.yy: extender is now post_event. * lily/accidental-engraver.cc (number_accidentals): remove spurious warning about non-parent contexts. diff --git a/Documentation/topdocs/NEWS.texi b/Documentation/topdocs/NEWS.texi index 325bdd1896..e73e449985 100644 --- a/Documentation/topdocs/NEWS.texi +++ b/Documentation/topdocs/NEWS.texi @@ -8,6 +8,26 @@ @chapter New features in 2.1 since 2.0 @itemize +@item +Lyrics are now aligned under note heads conforming engraving +standards. The responsible code has been rewritten, and is drastically +simpler from the previous version. To aid this rewrite, the syntactic +function of the extender line ( __ ) is been changed: it is now attached +to the lyric syllable. + +@item +When redefining a context, the associated identifier is also +updated. For example, after reading following the snippet, +@example + \translator @{ + \ScoreContext + autoBeaming = ##f + @} +@end example +the definition of @code{ScoreContext} is updated to include the changed +setting. + + @item The weight of the stafflines is now heavier at smaller staff sizes. The font has been modified to match this look: at smaller sizes, the diff --git a/Documentation/user/refman.itely b/Documentation/user/refman.itely index 7006f6860e..cd4f16279a 100644 --- a/Documentation/user/refman.itely +++ b/Documentation/user/refman.itely @@ -3474,10 +3474,10 @@ melisma on the last note in a melody is not printed. @cindex phrasing, in lyrics -When multiple stanzas are printed underneath each other, the vertical -groups of syllables should be aligned around punctuation. This can be -done automatically when corresponding lyric lines and melodies are -marked. + +The lyrics should be aligned with the note heads of the melody. To +achieve this, each line of lyrics should be marked to correspond with +the melodic line. To this end, give the @internalsref{Voice} context an identity: @example @@ -3496,9 +3496,6 @@ that identity followed by a dash. In the preceding example, the \context LyricsVoice = "duet-2" @{ Ooooo, ch\'e -- ri, je t'aime. @} @end example -The convention for naming @internalsref{LyricsVoice} and -@internalsref{Voice} must also be used to get melismata correct in -conjunction with rests. The complete example is shown here: @lilypond[singleline,verbatim] diff --git a/VERSION b/VERSION index 9f1c3eb43e..ddf68a2fd3 100644 --- a/VERSION +++ b/VERSION @@ -1,6 +1,6 @@ PACKAGE_NAME=LilyPond MAJOR_VERSION=2 MINOR_VERSION=1 -PATCH_LEVEL=4 -MY_PATCH_LEVEL=hwn1 +PATCH_LEVEL=5 +MY_PATCH_LEVEL= diff --git a/input/mutopia/F.Schubert/standchen.ly b/input/mutopia/F.Schubert/standchen.ly index 5601bc1f60..06892f7294 100644 --- a/input/mutopia/F.Schubert/standchen.ly +++ b/input/mutopia/F.Schubert/standchen.ly @@ -396,8 +396,7 @@ lyricStaff = \context Lyrics { vocals = \context Voice \notes { \clef treble % certainly no auto-beaming for vocals - \property Voice.autoBeaming = ##f - \property Staff.automaticMelismata= ##t + \autoBeamOff \dynamicUp % duh 1 != 3/4 diff --git a/input/regression/lyric-align.ly b/input/regression/lyric-align.ly deleted file mode 100644 index 2fe34573f6..0000000000 --- a/input/regression/lyric-align.ly +++ /dev/null @@ -1,82 +0,0 @@ - -\version "1.9.8" -\header{ - texidoc=" - - Lyric alignment is adjustable both in terms of alignment between - stanzas and on notehead. - - If the property alignment is not set, there is automatic - determination of alignment type based on punctuation (, see - lyric-phrasing.ly). - -" -} - -%\paper { raggedright = ##t} -\score { -<< \context Voice = "v" \notes \relative c'' { - \property Staff.automaticMelismata = ##t - \cadenzaOn - a\breve \bar "||" a1 \bar "|" a \bar "|" a \bar "||" \break a \bar "|" a \bar "|" a \bar "|" a \bar "||" \break a \bar "|" a \bar "|." - } - \context Lyrics << - \context LyricsVoice = "v-1" \lyrics { -% \property LyricsVoice . stanza = "1:" - \property Lyrics . LyricText \override #'ignore-length-mismatch = ##t - \property Lyrics . LyricText \override #'alignment = #-1 - \property Lyrics . LyricText \override #'begin-alignment = #8 - - "Particularly useful for reciting notes "\breve - left1 - - \property Lyrics . LyricText \override #'alignment = #0 - centered - - \property Lyrics . LyricText \override #'alignment = #1 - - right - - \property Lyrics . LyricText \override #'alignment = #-1 - \property Lyrics . LyricText \override #'begin-alignment = #2 - - left_half_way - - \property Lyrics . LyricText \override #'begin-alignment = #4 - - left_one_quarter - - \property Lyrics . LyricText \override #'begin-alignment = #10 - - left_one_tenth - - \property Lyrics . LyricText \override #'begin-alignment = #1 - - left_one_whole - - \property Lyrics . LyricText \override #'ignore-length-mismatch = ##f - \property Lyrics . LyricText \override #'begin-alignment = #4 - - Very_short_lyrics_remain_in_touch_with_their_note - - \property Lyrics . LyricText \override #'alignment = #1 - \property Lyrics . LyricText \override #'end-alignment = #1.1 - \property Lyrics . LyricText \override #'ignore-length-mismatch = ##t - - - Unless_ignore-length-mismatch_is_true - - } - \context LyricsVoice = "v-2" \lyrics { -% \property LyricsVoice . stanza = "2:" - " with many syllables under them."\breve - l1 c r1 l - l1 l x x x - - % note' true' - %% ? what are the last 2 for? - } - >> - >> -} - diff --git a/input/regression/lyric-combine.ly b/input/regression/lyric-combine.ly index 0d0d1c6489..f162738f8d 100644 --- a/input/regression/lyric-combine.ly +++ b/input/regression/lyric-combine.ly @@ -18,7 +18,6 @@ to work." m = \notes \relative c'' { - \property Staff.automaticMelismata = ##t \autoBeamOff g8( a) r8 \times 2/3 { g'8( f e) } r8 \grace { d16[ c b] } e4 \emptyText diff --git a/input/regression/lyric-extender.ly b/input/regression/lyric-extender.ly index 839a056fd8..bd962a554f 100644 --- a/input/regression/lyric-extender.ly +++ b/input/regression/lyric-extender.ly @@ -1,12 +1,14 @@ -#(ly:set-option 'old-relative) \version "1.9.8" + \header { texidoc= "Tests lyric extenders. "} \paper { raggedright= ##t } \score{ \notes \relative c' << - \context Staff { c (c) (c) c } - \context Lyrics \lyrics { bla __ alb xxx __ yyy } + \context Staff { + c8[ ( d] ) + r4 f4 } + \context Lyrics \lyrics { xxx __ \skip 4 x } >> } diff --git a/input/regression/lyric-phrasing.ly b/input/regression/lyric-phrasing.ly index cd369a9133..2e6bea12de 100644 --- a/input/regression/lyric-phrasing.ly +++ b/input/regression/lyric-phrasing.ly @@ -26,7 +26,6 @@ \score { \addlyrics \context Voice = "v" \notes \relative c'' { - \property Staff.automaticMelismata = ##t \autoBeamOff a a a8 ( a) a4 } diff --git a/input/template/melody-lyrics-chords.ly b/input/template/melody-lyrics-chords.ly index ba2c709cf0..291b9502a6 100644 --- a/input/template/melody-lyrics-chords.ly +++ b/input/template/melody-lyrics-chords.ly @@ -21,8 +21,7 @@ accompaniment = \chords { \context ChordNames \accompaniment \addlyrics \context Staff = one { - \property Staff.autoBeaming = ##f - \property Staff.automaticMelismata = ##t + \autoBeamOff \melody } \context Lyrics \text diff --git a/input/template/piano-melody-lyrics.ly b/input/template/piano-melody-lyrics.ly index b7be9188f9..5870d37ea3 100644 --- a/input/template/piano-melody-lyrics.ly +++ b/input/template/piano-melody-lyrics.ly @@ -25,8 +25,7 @@ lower = \notes\relative c { << \addlyrics \context Staff = mel { - \property Staff.autoBeaming = ##f - \property Staff.automaticMelismata = ##t + \autoBeamOff \melody } \context Lyrics \text diff --git a/input/template/satb.ly b/input/template/satb.ly index c8036a40be..08aa43ff32 100644 --- a/input/template/satb.ly +++ b/input/template/satb.ly @@ -20,7 +20,6 @@ bassWords = \lyrics { ho4 ho ho ho } \score { \notes \context StaffGroup << - \property Score.automaticMelismata = ##t \context Lyrics = sopLyrs { s1 } \context Staff = women { s1 } \context Lyrics = altoLyrs { s1 } diff --git a/lily/beam-engraver.cc b/lily/beam-engraver.cc index 2ee7b31778..43f7cbecbe 100644 --- a/lily/beam-engraver.cc +++ b/lily/beam-engraver.cc @@ -127,10 +127,8 @@ Beam_engraver::try_music (Music *m) void Beam_engraver::set_melisma (bool ml) { - SCM m = get_property ("automaticMelismata"); SCM b = get_property ("autoBeaming"); - - if (to_boolean (m) && !to_boolean (b)) + if (!to_boolean (b)) daddy_trans_->set_property ("beamMelismaBusy", ml ? SCM_BOOL_T :SCM_BOOL_F); } diff --git a/lily/engraver.cc b/lily/engraver.cc index 22a70a6807..c49e76062e 100644 --- a/lily/engraver.cc +++ b/lily/engraver.cc @@ -35,7 +35,8 @@ Engraver::announce_grob (Grob* e, SCM cause) if (unsmob_music (cause) || unsmob_grob (cause)) e->set_grob_property ("cause", cause); - Grob_info i (e); + Grob_info i; + i.grob_ = e; if (!i.origin_trans_) i.origin_trans_ = this; get_daddy_grav ()->announce_grob (i); diff --git a/lily/extender-engraver.cc b/lily/extender-engraver.cc index 25ca7a65b9..8e60f9f9e3 100644 --- a/lily/extender-engraver.cc +++ b/lily/extender-engraver.cc @@ -8,32 +8,16 @@ Jan Nieuwenhuizen */ -#include "flower-proto.hh" -#include "event.hh" +#include "warn.hh" #include "lyric-extender.hh" -#include "paper-column.hh" #include "item.hh" #include "engraver.hh" -#include "drul-array.hh" -#include "lyric-extender.hh" -#include "pqueue.hh" - -/** - Generate an centred extender. Should make a Extender_spanner that - typesets a nice centred extender of varying length depending on the - gap between syllables. - - We remember the last Item that come across. When we get a - event, we create the spanner, and attach the left point to the - last lyrics, and the right point to any lyrics we receive by - then. */ class Extender_engraver : public Engraver { - Grob *last_lyric_; - Grob *current_lyric_; - Music* req_; + Music* ev_; Spanner* extender_; + Spanner * finished_extender_; public: TRANSLATOR_DECLARATIONS(Extender_engraver); @@ -53,25 +37,23 @@ private: Extender_engraver::Extender_engraver () { - current_lyric_ = 0; - last_lyric_ = 0; extender_ = 0; - req_ = 0; + finished_extender_ = 0; + ev_ = 0; } void Extender_engraver::acknowledge_grob (Grob_info i) { + Item * item = dynamic_cast (i.grob_); // -> text_item - if (i.grob_->internal_has_interface (ly_symbol2scm ("lyric-syllable-interface"))) + if (item && item->internal_has_interface (ly_symbol2scm ("lyric-syllable-interface"))) { - current_lyric_ = i.grob_; - if (extender_ - && !extender_->get_bound (RIGHT) - ) - { - Lyric_extender::set_textitem (extender_, RIGHT, dynamic_cast (i.grob_)); - } + if (extender_) + extender_->set_bound (LEFT, item); + + if (finished_extender_ && !finished_extender_->get_bound (RIGHT)) + finished_extender_->set_bound (RIGHT, item); } } @@ -79,10 +61,10 @@ Extender_engraver::acknowledge_grob (Grob_info i) bool Extender_engraver::try_music (Music* r) { - if (req_) + if (ev_) return false; - req_ = r; + ev_ = r; return true; } @@ -91,27 +73,25 @@ Extender_engraver::finalize () { if (extender_) { - req_->origin ()->warning (_ ("unterminated extender")); - extender_->set_bound (RIGHT, unsmob_grob (get_property ("currentCommandColumn"))); + extender_->warning (_ ("unterminated extender")); + typeset_grob (extender_); + extender_ = 0; + } + if (finished_extender_) + { + finished_extender_->warning (_("unterminated extender")); + typeset_grob (finished_extender_); + finished_extender_ =0; } } void Extender_engraver::process_music () { - if (req_ && ! extender_) + if (ev_) { - if (!last_lyric_) - { - req_->origin ()->warning (_ ("Nothing to connect extender to on the left. Ignoring extender event.")); - return; - } - extender_ = new Spanner (get_property ("LyricExtender")); - - - Lyric_extender::set_textitem (extender_, LEFT, last_lyric_); - announce_grob(extender_, req_->self_scm()); + announce_grob (extender_, ev_->self_scm()); } } @@ -119,23 +99,28 @@ Extender_engraver::process_music () void Extender_engraver::stop_translation_timestep () { - if (extender_) + if (finished_extender_ && finished_extender_->get_bound (RIGHT)) { - typeset_grob (extender_); - extender_ = 0; + typeset_grob (finished_extender_); + finished_extender_ = 0; } - if (current_lyric_) + if (finished_extender_ && extender_) { - last_lyric_ = current_lyric_; - current_lyric_ =0; + programming_error ("Haven't finished extender yet."); + typeset_grob (finished_extender_); + finished_extender_ =0; } + + if (extender_) + finished_extender_ = extender_; + extender_ = 0; } void Extender_engraver::start_translation_timestep () { - req_ = 0; + ev_ = 0; } @@ -143,6 +128,6 @@ ENTER_DESCRIPTION(Extender_engraver, /* descr */ "Create lyric extenders", /* creats*/ "LyricExtender", /* accepts */ "extender-event", -/* acks */ "lyric-syllable-interface", +/* acks */ "lyric-syllable-interface", /* reads */ "", /* write */ ""); diff --git a/lily/grob-info.cc b/lily/grob-info.cc index d3a6378206..e47d73e9ed 100644 --- a/lily/grob-info.cc +++ b/lily/grob-info.cc @@ -11,12 +11,6 @@ #include "music.hh" #include "translator-group.hh" -Grob_info::Grob_info (Grob*s) -{ - grob_ = s; - origin_trans_ = 0; -} - Grob_info::Grob_info () { @@ -26,7 +20,6 @@ Grob_info::Grob_info () Music* Grob_info::music_cause () - { SCM cause = grob_->get_grob_property ("cause"); return unsmob_music (cause); diff --git a/lily/hyphen-spanner.cc b/lily/hyphen-spanner.cc index c3bea14259..094137bef7 100644 --- a/lily/hyphen-spanner.cc +++ b/lily/hyphen-spanner.cc @@ -19,6 +19,7 @@ #include "spanner.hh" #include "item.hh" + MAKE_SCHEME_CALLBACK (Hyphen_spanner,set_spacing_rods,1); SCM Hyphen_spanner::set_spacing_rods (SCM smob) @@ -145,8 +146,6 @@ Hyphen_spanner::Hyphen_spanner (Spanner*s) ADD_INTERFACE (Hyphen_spanner, "lyric-hyphen-interface", - "A centred hyphen is a simple line between lyrics used to divide " -"syllables. The length of the hyphen line should stretch based on the " -"size of the gap between syllables.", - "thickness height minimum-length maximum-length word-space"); + "A centred hyphen is a simple line between lyrics used to divide syllables", + "thickness height minimum-length maximum-length word-space"); diff --git a/lily/include/grob-info.hh b/lily/include/grob-info.hh index 0db710cd40..6fe603077b 100644 --- a/lily/include/grob-info.hh +++ b/lily/include/grob-info.hh @@ -26,7 +26,6 @@ struct Grob_info { public: Music * music_cause (); Link_array origin_transes (Translator*) const; - Grob_info (Grob*); Grob_info (); }; diff --git a/lily/include/lyric-phrasing-engraver.hh b/lily/include/lyric-phrasing-engraver.hh deleted file mode 100644 index e5c578a2ae..0000000000 --- a/lily/include/lyric-phrasing-engraver.hh +++ /dev/null @@ -1,128 +0,0 @@ -/* - lyric-phrasing-engraver.hh -- declare Lyric_phrasing_engraver - - source file of the GNU LilyPond music typesetter - - (c) 2000--2003 Glen Prideaux -*/ - - -#ifndef LYRIC_PHRASING_ENGRAVER_HH -#define LYRIC_PHRASING_ENGRAVER_HH - -#include "lily-proto.hh" -#include "engraver.hh" -#include "item.hh" -#include "smobs.hh" -#include "protected-scm.hh" - -class Syllable_group; - - -/** - Align lyrics with noteheads, left aligning beginning of phrases, - right aligning end of phrases, centering others under their notes. - */ - -/* -* Build an engraver that catches noteheads and lyrics. - - (It needs to be in a context above Staff and Lyrics, eg. in Score -context.) - -* Determine which heads belong to which lyrics - - (eg. by looking at the names of their originating contexts, or maybe -some \properties) - -* Attach the lyrics to the appropriate heads - - (by doing lyric->set_parent (head, X_AXIS), that will fix the current -noteheadwidth guessing kludge) - -* Check if the lyric syllables end or start a phrase. - - (eg. check if the syllable ends with punctuation, and remember that -fact for the next one.) - -* Adjust their alignment accordingly. - - (eg. by doing lyric->add_offset_callback (centered_on_parent,X_AXIS) -and setting self-alignment-X) - -* Add a property to switch on/off the engraver (for multi stanza - vs. single stanza music) - -Maybe this engraver could also take care of correct lyric alignment -for melismas as well. - - - */ - - -class Lyric_phrasing_engraver : public Engraver -{ -protected: - virtual void acknowledge_grob (Grob_info); - virtual void process_acknowledged_grobs (); - virtual void stop_translation_timestep (); - virtual void finalize (); -private: - void record_notehead (const String &context_id, Grob * notehead); - void record_lyric (const String &context_id, Grob * lyric); - void record_melisma (const String &context_id); - void record_extender (const String &context_id, Grob * extender); - Syllable_group * lookup_context_id (const String &context_id); - -public: - - ~Lyric_phrasing_engraver (); - TRANSLATOR_DECLARATIONS( Lyric_phrasing_engraver); - -private: - /** association list of Syllable_group smobs - - fixme: should use property. - - */ - Protected_scm voice_alist_; - Grob * any_notehead_; -}; - - -class Syllable_group -{ - bool first_in_phrase_b_; - Grob * notehead_; - Link_array lyrics_; - Grob * longest_lyric_; - Grob * shortest_lyric_; - int alignment_; - bool melisma_b_; - Real group_translation_; -public: - static SCM make_entry (); - void set_first_in_phrase (bool f); - void set_notehead (Grob * notehead); - void add_lyric (Grob * lyric); - void add_extender (Grob * extender); - void set_melisma () { melisma_b_ = true; } - bool get_melisma () { return melisma_b_; } - int lyric_count () { return lyrics_.size (); } - void clear (); - bool is_empty (); - bool set_lyric_align (const char *punc, Grob *default_notehead); - void adjust_melisma_align (); - int appropriate_alignment (const char *punc); - Real amount_to_translate (); - void next_lyric (); - void copy (Syllable_group *); -private: - Syllable_group (); - DECLARE_SIMPLE_SMOBS (Syllable_group,); -} ; - -DECLARE_UNSMOB(Syllable_group,voice_entry); - - -#endif // LYRIC_PHRASING_ENGRAVER_HH diff --git a/lily/lyric-extender.cc b/lily/lyric-extender.cc index 7d1166c063..01c3fda293 100644 --- a/lily/lyric-extender.cc +++ b/lily/lyric-extender.cc @@ -14,53 +14,44 @@ #include "paper-column.hh" #include "paper-def.hh" #include "lyric-extender.hh" - +#include "note-head.hh" MAKE_SCHEME_CALLBACK (Lyric_extender,brew_molecule,1) SCM Lyric_extender::brew_molecule (SCM smob) { - Spanner *sp = unsmob_spanner (smob); - Item* l = sp->get_bound (LEFT); - Item*r = sp->get_bound (RIGHT); + Spanner *me = unsmob_spanner (smob); + Item *l = me->get_bound (LEFT); + Item *r = me->get_bound (RIGHT); + Grob *common = l->common_refpoint (r, X_AXIS); - Real leftext = l->extent (l, X_AXIS).length (); + Real left_point = l->extent (common, X_AXIS)[RIGHT]; - Real sl = sp->get_paper ()->get_realvar (ly_symbol2scm ("linethickness")); - Real righttrim = 0.5; // default to half a space gap on the right + Real sl = me->get_paper ()->get_realvar (ly_symbol2scm ("linethickness")); /* - If we're broken, we shouldn't extend past the end of the line. + It seems that short extenders are even lengthened to go past the note head, but + haven't found a pattern in it yet. --hwn 1/1/04 + */ - if (r->break_status_dir () == CENTER) - { - SCM righttrim_scm = sp->get_grob_property ("right-trim-amount"); - if (gh_number_p (righttrim_scm)) - { - righttrim = gh_scm2double (righttrim_scm); - } - } + Real right_point = r->extent (common, X_AXIS) + [(Note_head::has_interface (r)) ? RIGHT : LEFT]; - // The extender can exist in the word space of the left lyric ... - SCM space = sp->get_bound (LEFT)->get_grob_property ("word-space"); - if (gh_number_p (space)) - { - leftext -= gh_scm2double (space); - } - Real w = sp->spanner_length () - leftext - righttrim; + Real w = right_point - left_point; + + Real h = sl * gh_scm2double (me->get_grob_property ("thickness")); - Real h = sl * gh_scm2double (sp->get_grob_property ("height")); Molecule mol (Lookup::filledbox (Box (Interval (0,w), Interval (0,h)))); - mol.translate (Offset (leftext, 0)); + mol.translate_axis (left_point - me->relative_coordinate (common, X_AXIS), X_AXIS); return mol.smobbed_copy (); } void -Lyric_extender::set_textitem (Spanner*sp, Direction d, Grob*s) +Lyric_extender::set_textitem (Spanner *me, Direction d, Grob *s) { - sp->set_bound (d, s); - sp->add_dependency (s); + me->set_bound (d, s); + me->add_dependency (s); } @@ -68,5 +59,5 @@ Lyric_extender::set_textitem (Spanner*sp, Direction d, Grob*s) ADD_INTERFACE (Lyric_extender,"lyric-extender-interface", "The extender is a simple line at the baseline of the lyric " -" that helps show the length of a melissima (tied/slurred note).", - "word-space height right-trim-amount"); + " that helps show the length of a melissima (tied/slurred note).", + "thickness"); diff --git a/lily/lyric-phrasing-engraver.cc b/lily/lyric-phrasing-engraver.cc index b3275a5705..c813a5a91d 100644 --- a/lily/lyric-phrasing-engraver.cc +++ b/lily/lyric-phrasing-engraver.cc @@ -1,366 +1,211 @@ -/* - lyric-phrasing-engraver.cc -- implement Lyric_phrasing_engraver +/* + new-phrasing-engraver.cc -- implement New_phrasing_engraver - source file of the GNU LilyPond music typesetter +source file of the GNU LilyPond music typesetter - (c) 2000--2003 Glen Prideaux -*/ -#include +(c) 2003--2004 Han-Wen Nienhuys -#include "lyric-phrasing-engraver.hh" -#include "note-head.hh" -#include "translator-group.hh" -#include "spanner.hh" -#include "warn.hh" - - -String get_context_id (Translator_group * ancestor, SCM); -String trim_suffix (String &id); - - - -/* - TODO: this code is too hairy, and does things that should be in the - backend. Fixme. -*/ + */ -/* - TODO: - shared lyrics should be vertically centered: +#include "translator-group.hh" +#include "engraver.hh" +#include "note-head.hh" +#include "lyric-extender.hh" +#include "item.hh" +struct Phrasing_association +{ + String name_; + Link_array lyrics_; + Link_array heads_; + Link_array past_extenders_; + Link_array new_extenders_; - - > 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 - accordingly. - - Also, lyrics at start of melismata should be left aligned. - (is that only lyrics that are followed by `__'? Because - that seems to be the case now -- jcn) - - - | | | | | - x| 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. - + bool melisma_; - Alignment and melismata - - I've taken [a different] approach: - | | - | | - O O <-- second note throws a melisma score element - \____/ - - ^ ^ - | | - 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. -*/ + Phrasing_association() + { + melisma_ = false; + } + +}; -Lyric_phrasing_engraver::Lyric_phrasing_engraver () +class Lyric_phrasing_engraver : public Engraver { - voice_alist_ = SCM_EOL; - any_notehead_ = 0; -} - -Lyric_phrasing_engraver::~Lyric_phrasing_engraver () +public: + ~Lyric_phrasing_engraver (); + TRANSLATOR_DECLARATIONS(Lyric_phrasing_engraver); +protected: + virtual void acknowledge_grob (Grob_info); + virtual void process_acknowledged_grobs (); + virtual void stop_translation_timestep (); + +private: + void add_lyric_phrasing (Grob_info); + void add_voice_phrasing (Grob_info); + void add_lyric_extender (Grob_info); + Phrasing_association *get_phrasing_assoc (String nm); + String get_voice_name_for_lyric (Translator_group*tr); + Link_array assocs_; +}; + +Lyric_phrasing_engraver::Lyric_phrasing_engraver() { - /* - No need to delete alist_; that's what Garbage collection is for. - */ } void -Lyric_phrasing_engraver::finalize () +Lyric_phrasing_engraver::acknowledge_grob (Grob_info i) { - /* - but do need to unprotect alist_, since Engravers are gc'd now. - */ + Grob *h = i.grob_; - voice_alist_ = SCM_EOL; + if (Note_head::has_interface (h)) + add_voice_phrasing (i); + else if (h->internal_has_interface (ly_symbol2scm ("lyric-syllable-interface"))) + add_lyric_phrasing (i); + else if (Lyric_extender::has_interface (h)) + add_lyric_extender (i); } - -Syllable_group * -Lyric_phrasing_engraver::lookup_context_id (const String &context_id) +Phrasing_association * +Lyric_phrasing_engraver::get_phrasing_assoc (String nm) { - SCM key = scm_makfrom0str (context_id.to_str0 ()); - if (! gh_null_p (voice_alist_)) + Phrasing_association * a=0; + for (int i=0 ; !a && i < assocs_.size (); i++) { - 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 (assocs_[i]->name_ == nm) + a = assocs_[i]; } - // ((alist_entry . old_entry) . previous_entry) - SCM val = gh_cons (gh_cons (Syllable_group::make_entry (), SCM_BOOL_F), - Syllable_group::make_entry ()); - voice_alist_ = scm_acons (key, val, voice_alist_); - return unsmob_voice_entry (ly_caar (val)); + if (!a) + { + a = new Phrasing_association ; + a->name_ = nm; + assocs_.push (a); + } + return a; } -void -Lyric_phrasing_engraver::record_notehead (const String &context_id, - Grob * notehead) -{ - Syllable_group * v = lookup_context_id (context_id); - v->set_notehead (notehead); - if (!any_notehead_) - any_notehead_ = notehead; -} - -void -Lyric_phrasing_engraver::record_lyric (const String &context_id, Grob * lyric) -{ - Syllable_group * v = lookup_context_id (context_id); - v->add_lyric (lyric); -} -void -Lyric_phrasing_engraver::record_extender (const String &context_id, Grob * extender) +String +Lyric_phrasing_engraver::get_voice_name_for_lyric (Translator_group*tr) { - SCM key = scm_makfrom0str (context_id.to_str0 ()); - if (! gh_null_p (voice_alist_)) + SCM voice = tr->get_property ("associatedVoice"); + String nm = tr->id_string_; + if (gh_string_p (voice)) + nm = ly_scm2string (voice); + else { - 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); - } - } + int idx = nm.index_last ('-'); + if (idx >= 0) + nm = nm.left_string (idx); } -} -void -Lyric_phrasing_engraver::record_melisma (const String &context_id) -{ - Syllable_group * v = lookup_context_id (context_id); - v->set_melisma (); + return nm; } -/* - TODO: this engraver is always on, also for orchestral scores. That - is a waste of time and space. This should be switched on - automatically at the first Lyrics found. - */ + void -Lyric_phrasing_engraver::acknowledge_grob (Grob_info i) +Lyric_phrasing_engraver::add_lyric_extender (Grob_info inf) { - SCM p = get_property ("automaticPhrasing"); - if (!to_boolean (p)) - return; + Translator_group * tr = inf.origin_trans_->daddy_trans_; + while (tr && !tr->is_alias (ly_symbol2scm ("LyricsVoice"))) + tr = tr->daddy_trans_; + if (!tr) + return; - Grob *h = i.grob_; - - 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_->daddy_trans_, ly_symbol2scm ("Voice")); - record_notehead (voice_context_id, h); + + Phrasing_association *a = get_phrasing_assoc (get_voice_name_for_lyric (tr)); + a->new_extenders_.push (dynamic_cast (inf.grob_)); +} - /* is it in a melisma ? */ - if (melisma_busy (i.origin_trans_)) - { - record_melisma (voice_context_id); - } - return; - } - /* now try for a lyric */ - if (h->internal_has_interface (ly_symbol2scm ("lyric-syllable-interface"))) - { +void +Lyric_phrasing_engraver::add_voice_phrasing (Grob_info inf) +{ + Translator_group * tr = inf.origin_trans_->daddy_trans_; + while (tr && !tr->is_alias (ly_symbol2scm ("Voice"))) + tr = tr->daddy_trans_; - /* what's its LyricsVoice context name? */ - String voice_context_id; - SCM voice_context_scm = i.origin_trans_->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_->daddy_trans_,ly_symbol2scm ( "LyricsVoice")); - voice_context_id = trim_suffix (voice_context_id); - } - record_lyric (voice_context_id, h); - return; - } + if (!tr) + 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 - the corresponding context (if any). - This has the effect of finishing the extender under the last note - of the melisma, instead of extending it to the next lyric. - - Problem: the extender event is thrown at the same moment as the next lyric, - by which time we have already passed the last note of the melisma. - However, the Lyric_phrasing_engraver remembers the last note, so just - attach it to that, provided it was melismatic. If it was not melismatic, - 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_->daddy_trans_, ly_symbol2scm ("LyricsVoice")); - record_extender (trim_suffix (voice_context_id), h); - return; - } + Phrasing_association *a = get_phrasing_assoc (tr->id_string_); + a->heads_.push (inf.grob_); + a->melisma_ = melisma_busy (inf.origin_trans_); } -String -get_context_id (Translator_group * ancestor, SCM type) +void +Lyric_phrasing_engraver::add_lyric_phrasing (Grob_info inf) { - while (ancestor && !ancestor->is_alias(type)) - { - ancestor = ancestor->daddy_trans_; - } + Translator_group * tr = inf.origin_trans_->daddy_trans_; + while (tr && !tr->is_alias (ly_symbol2scm ("LyricsVoice"))) + tr = tr->daddy_trans_; + + if (!tr) + return; - if (ancestor) - { - return ancestor->id_string_; - } - return ""; + Phrasing_association *a = get_phrasing_assoc (get_voice_name_for_lyric (tr)); + a->lyrics_.push (inf.grob_); + a->past_extenders_.clear (); } -String -trim_suffix (String &id) +void +Lyric_phrasing_engraver::stop_translation_timestep () { - int index = id.index ('-'); - if (index >= 0) + for (int i = assocs_.size (); i--; ) { - return id.left_string (index); + assocs_[i]->heads_.clear (); + assocs_[i]->lyrics_.clear (); + assocs_[i]->past_extenders_.concat (assocs_[i]->new_extenders_) ; + assocs_[i]->new_extenders_.clear (); } - return id; } - void -Lyric_phrasing_engraver::process_acknowledged_grobs () +Lyric_phrasing_engraver::process_acknowledged_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. - */ - String punc; - 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)) + for (int i = 0; i < assocs_.size (); i++) { - 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.to_str0 (), any_notehead_)) - warning (_ ("lyrics found without any matching notehead")); - - // is this note melismatic? If so adjust alignment of previous one. - if (entry->get_melisma ()) + Phrasing_association * a = assocs_[i]; + if (! (a->heads_.size() && (a->lyrics_.size () || a->past_extenders_.size ()))) + continue; + + Grob *h = a->heads_[0]; + Direction alignment = CENTER; + if (a->melisma_) + alignment = LEFT; + + for (int j = 0; j < a->lyrics_.size (); j++) + { + Grob *l = a->lyrics_[j]; + if (!l->get_parent (X_AXIS)) { - 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 (); - } + l->set_parent (h, X_AXIS); + if (alignment) + l->set_grob_property ("self-alignment-X", gh_int2scm (alignment)); } } + + for (int j = a->past_extenders_.size(); j--;) + a->past_extenders_[j]->set_bound (RIGHT, dynamic_cast (h)); } } - -void -Lyric_phrasing_engraver::stop_translation_timestep () +Lyric_phrasing_engraver::~Lyric_phrasing_engraver () { - 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 (); - } - any_notehead_ = 0; + for (int i =assocs_.size(); i--;) + delete assocs_[i]; } - - ENTER_DESCRIPTION(Lyric_phrasing_engraver, - /* descr */ -"This engraver combines note heads and lyrics for alignment. " -"\n\n" -"This engraver is switched on by default. Turn it off for faster " -"processing of orchestral scores. ", - /* creats*/ "", - /* accepts */ "", -/* acks */ "lyric-syllable-interface note-head-interface lyric-extender-interface", - /* reads */ "automaticPhrasing associatedVoice phrasingPunctuation", - /* write */ ""); + "This engraver combines note heads and lyrics for alignment. ", + "", + "", + "lyric-syllable-interface note-head-interface lyric-extender-interface", + "automaticPhrasing associatedVoice", + ""); + diff --git a/lily/new-phrasing-engraver.cc b/lily/new-phrasing-engraver.cc deleted file mode 100644 index b0e4931ee1..0000000000 --- a/lily/new-phrasing-engraver.cc +++ /dev/null @@ -1,188 +0,0 @@ -/* - new-phrasing-engraver.cc -- implement New_phrasing_engraver - -source file of the GNU LilyPond music typesetter - -(c) 2003--2004 Han-Wen Nienhuys - - */ - -#include "translator-group.hh" -#include "engraver.hh" -#include "note-head.hh" -#include "grob.hh" - -struct Phrasing_association -{ - String name_; - Link_array lyrics_; - Link_array heads_; - bool melisma_; - - Phrasing_association() - { - melisma_ = false; - } - - void clear () { - lyrics_.clear (); - heads_.clear (); - } - -}; - -class New_phrasing_engraver : public Engraver -{ -public: - ~New_phrasing_engraver (); - TRANSLATOR_DECLARATIONS(New_phrasing_engraver); -protected: - virtual void acknowledge_grob (Grob_info); - virtual void process_acknowledged_grobs (); - virtual void stop_translation_timestep (); - - Link_array assocs_; - void add_lyric_phrasing (Grob_info); - void add_voice_phrasing (Grob_info); -}; - -New_phrasing_engraver::New_phrasing_engraver() -{ - -} - -void -New_phrasing_engraver::acknowledge_grob (Grob_info i) -{ - Grob *h = i.grob_; - - if (Note_head::has_interface (h)) - { - add_voice_phrasing (i); - } - else if (h->internal_has_interface (ly_symbol2scm ("lyric-syllable-interface"))) - { - add_lyric_phrasing (i); - } -} - -void -New_phrasing_engraver::add_voice_phrasing (Grob_info inf) -{ - Translator_group * tr = inf.origin_trans_->daddy_trans_; - while (tr && !tr->is_alias (ly_symbol2scm ("Voice"))) - tr = tr->daddy_trans_; - - if (!tr) - return; - - /* - should use dict? - */ - Phrasing_association *a =0; - for (int i =0; !a && i < assocs_.size (); i++) - { - if (assocs_[i]->name_ == tr->id_string_) - a = assocs_[i]; - } - - if (!a) - { - a = new Phrasing_association ; - a->name_ = tr->id_string_; - assocs_.push (a); - } - - a->heads_.push (inf.grob_); - a->melisma_ = melisma_busy (inf.origin_trans_); -} - -void -New_phrasing_engraver::add_lyric_phrasing (Grob_info inf) -{ - Translator_group * tr = inf.origin_trans_->daddy_trans_; - while (tr && !tr->is_alias (ly_symbol2scm ("LyricsVoice"))) - tr = tr->daddy_trans_; - - if (!tr) - return; - - SCM voice = get_property ("associatedVoice"); - String nm = tr->id_string_; - if (gh_string_p (voice)) - nm = ly_scm2string (voice); - else - { - int idx = nm.index_last ('-'); - if (idx >= 0) - nm = nm.left_string (idx); - } - - Phrasing_association * a=0; - for (int i=0 ; !a && i < assocs_.size (); i++) - { - if (assocs_[i]->name_ == nm) - a = assocs_[i]; - } - - if (!a) - { - a = new Phrasing_association ; - a->name_ = nm; - assocs_.push (a); - } - - a->lyrics_.push (inf.grob_); -} - -void -New_phrasing_engraver::stop_translation_timestep () -{ - for (int i = assocs_.size (); i--; ) - { - assocs_[i]->clear (); - } -} - -void -New_phrasing_engraver::process_acknowledged_grobs () -{ - for (int i = 0; i < assocs_.size (); i++) - { - Phrasing_association * a = assocs_[i]; - if (!a->heads_.size() || !a->lyrics_.size ()) - continue; - - Grob *h = a->heads_[0]; - Direction alignment = CENTER; - if (a->melisma_) - alignment = LEFT; - - for (int j = 0; j < a->lyrics_.size (); j++) - { - - Grob *l = a->lyrics_[j]; - if (!l->get_parent (X_AXIS)) - { - l->set_parent (h, X_AXIS); - if (alignment) - l->set_grob_property ("self-alignment-X", gh_int2scm (alignment)); - } - } - } -} - -New_phrasing_engraver::~New_phrasing_engraver () -{ - for (int i =assocs_.size(); i--;) - delete assocs_[i]; -} - -ENTER_DESCRIPTION(New_phrasing_engraver, - "This engraver combines note heads and lyrics for alignment. ", - "", - "", - "lyric-syllable-interface note-head-interface lyric-extender-interface", - "automaticPhrasing associatedVoice", - ""); - diff --git a/lily/parser.yy b/lily/parser.yy index e66f77bd92..0b0993c502 100644 --- a/lily/parser.yy +++ b/lily/parser.yy @@ -383,7 +383,6 @@ yylex (YYSTYPE *s, void * v) %type shorthand_command_req %type post_event tagged_post_event %type command_req verbose_command_req -%type extender_req %type hyphen_req %type string_number_event %type string bare_number number_expression number_term number_factor @@ -1489,10 +1488,7 @@ command_req: ; shorthand_command_req: - extender_req { - $$ = $1; - } - | hyphen_req { + hyphen_req { $$ = $1; } | BREATHE { @@ -1570,6 +1566,11 @@ post_event: direction_less_event { $$ = $1; } + | EXTENDER { + if (!THIS->lexer_->lyric_state_b ()) + THIS->parser_error (_ ("Have to be in Lyric mode for lyrics")); + $$ = MY_MAKE_MUSIC("ExtenderEvent"); + } | script_dir direction_reqd_event { if ($1) $2->set_mus_property ("direction", gh_int2scm ($1)); @@ -1725,14 +1726,6 @@ pitch_also_in_chords: -extender_req: - EXTENDER { - if (!THIS->lexer_->lyric_state_b ()) - THIS->parser_error (_ ("Have to be in Lyric mode for lyrics")); - $$ = MY_MAKE_MUSIC("ExtenderEvent"); - } - ; - hyphen_req: HYPHEN { if (!THIS->lexer_->lyric_state_b ()) diff --git a/lily/score-engraver.cc b/lily/score-engraver.cc index d7e740850f..94d5b6ae04 100644 --- a/lily/score-engraver.cc +++ b/lily/score-engraver.cc @@ -49,13 +49,16 @@ Score_engraver::make_columns () command_column_->set_grob_property ("breakable", SCM_BOOL_T); - Grob_info i1 (command_column_); + Grob_info i1; + i1.grob_ = command_column_; i1.origin_trans_ = this; - Grob_info i2 (musical_column_); + announce_grob (i1); + + Grob_info i2; + i2.grob_ = musical_column_; i2.origin_trans_ = this; - announce_grob (i1); announce_grob (i2); } } diff --git a/lily/slur-engraver.cc b/lily/slur-engraver.cc index 7441f52425..baeda35fda 100644 --- a/lily/slur-engraver.cc +++ b/lily/slur-engraver.cc @@ -31,7 +31,7 @@ protected: virtual void stop_translation_timestep (); virtual void start_translation_timestep (); virtual void finalize (); - virtual void process_acknowledged_grobs (); + virtual void process_music (); public: TRANSLATOR_DECLARATIONS (Slur_engraver); @@ -79,7 +79,6 @@ Slur_engraver::try_music (Music *ev) */ return true; - } else if (d == STOP) { @@ -139,7 +138,7 @@ Slur_engraver::finalize () } void -Slur_engraver::process_acknowledged_grobs () +Slur_engraver::process_music () { Link_array start_slurs; for (int i=0; i< new_slur_evs_.size (); i++) @@ -179,8 +178,11 @@ Slur_engraver::process_acknowledged_grobs () announce_grob (slur, slur_ev->self_scm ()); } } - for (int i=0; i < start_slurs.size (); i++) - slur_stack_.push (start_slurs[i]); + + slur_stack_.concat (start_slurs); + + set_melisma (slur_stack_.size ()); + new_slur_evs_.clear (); } @@ -198,11 +200,6 @@ void Slur_engraver::start_translation_timestep () { new_slur_evs_.clear (); - SCM m = get_property ("automaticMelismata"); - if (to_boolean (m)) - { - set_melisma (slur_stack_.size ()); - } } diff --git a/lily/syllable-group.cc b/lily/syllable-group.cc deleted file mode 100644 index e4bf7a8f52..0000000000 --- a/lily/syllable-group.cc +++ /dev/null @@ -1,323 +0,0 @@ -#include - -#include "lyric-phrasing-engraver.hh" -#include "note-head.hh" -#include "translator-group.hh" -#include "side-position-interface.hh" -#include "ly-smobs.icc" -#include "spanner.hh" -#include "paper-def.hh" - - -/* - Syllable_group is a class to be smobbed and entered as data in the - association list member of the Lyric_phrasing_engraver class. -*/ - -Syllable_group::Syllable_group () -{ - first_in_phrase_b_=true; - melisma_b_ = false; - clear (); -} - -void -Syllable_group::clear () -{ - notehead_=0; - lyrics_.clear (); - longest_lyric_=0; - shortest_lyric_=0; - melisma_b_ = false; - group_translation_ = 0.0; -} - -void -Syllable_group::copy (Syllable_group *from) -{ - notehead_ = from->notehead_; - lyrics_ = from->lyrics_; - longest_lyric_ = from->longest_lyric_; - shortest_lyric_ = from->shortest_lyric_; - melisma_b_ = from->melisma_b_; - alignment_ = from->alignment_; - first_in_phrase_b_ = from->first_in_phrase_b_; - group_translation_ = from->group_translation_; -} - -void -Syllable_group::set_first_in_phrase (bool f) -{ - first_in_phrase_b_ = f; -} - -void -Syllable_group::set_notehead (Grob * notehead) -{ - if (!notehead_) - { - /* there should only be a single notehead, so silently ignore - any extras */ - notehead_=notehead; - } -} - -void -Syllable_group::add_lyric (Grob * lyric) -{ - lyrics_.push (lyric); - /* record longest and shortest lyrics */ - if (longest_lyric_) - { - if (lyric->extent (lyric,X_AXIS).length () > (longest_lyric_->extent (longest_lyric_, X_AXIS)).length ()) - longest_lyric_ = lyric; - if (lyric->extent (lyric, X_AXIS).length () < (shortest_lyric_->extent (shortest_lyric_, X_AXIS)).length ()) - shortest_lyric_ = lyric; - } - else - longest_lyric_ = shortest_lyric_ = lyric; -} - -void -Syllable_group::add_extender (Grob * extender) -{ - if (notehead_ && melisma_b_) - { - dynamic_cast (extender)->set_bound (RIGHT, notehead_); - // should the extender finish at the right of the last note of the melisma, or the left? - // Comments in lyric-extender.hh say left, but right looks better to me. GP. - - // Left: - // extender->set_grob_property ("right-trim-amount", gh_double2scm (0.0)); - - // Right: - Real ss = 1.0; - extender->set_grob_property ("right-trim-amount", - gh_double2scm (-notehead_->extent (notehead_, X_AXIS).length ()/ss)); - } -} - -bool -Syllable_group::set_lyric_align (const char *punc, Grob *default_notehead) -{ - if (lyrics_.size () <= 0) - { - // No lyrics: nothing to do. - return true; - } - - Grob * lyric; - alignment_ = appropriate_alignment (punc); - - /* If there was no notehead in the matching voice context, use the - first notehead caught from any voice context (any port in a storm). - - - Is this wise? Can't the lyric simply be set on a the paper-column, - and be done with it. That's just as correct, and won't give strange - results if the port-in-the-storms happesn to be involved in a - note-collision? --hwn. - */ - if (!notehead_) - { - notehead_ = default_notehead; - } - - group_translation_ = amount_to_translate (); - - // set the x alignment of each lyric - for (int l = 0; l < lyrics_.size (); l++) - { - lyric = lyrics_[l]; - lyric->set_grob_property ("self-alignment-X", gh_int2scm (alignment_)); - if (notehead_) - { - /* - Centering on parent is done by default (see - grob-description.scm); we only have to set the parent. - */ - lyric->set_parent (notehead_, X_AXIS); - lyric->translate_axis (group_translation_, X_AXIS); - } - } - return (notehead_); -} - -/** determine the distance to translate lyrics to get correct alignment - Rules: If alignment is centre, translate = 0 - Otherwise, - If (length of longest lyric) < (property {begin,end}-alignment) * (length of shortest lyric), - - centre longest lyric on notehead - Otherwise - - move so shortest lyric just reaches notehead centre -*/ -Real -Syllable_group::amount_to_translate () -{ - Real translate = 0.0; - if (alignment_ != CENTER) - { - switch (alignment_) - { - // FIXME: do we really know the lyric extent here? Some font sizing comes later? - case LEFT: - translate = longest_lyric_->extent (longest_lyric_, X_AXIS).length () / gh_scm2double (longest_lyric_->get_grob_property("begin-alignment")); - break; - case RIGHT: - translate = longest_lyric_->extent (longest_lyric_, X_AXIS).length () / gh_scm2double (longest_lyric_->get_grob_property("end-alignment")); - break; - } - if (!gh_scm2bool(longest_lyric_->get_grob_property("ignore-length-mismatch"))) - { - Real l = shortest_lyric_->extent (shortest_lyric_, X_AXIS).length (); - translate = l longest_lyric_->get_grob_property ("alignment"); - if (s!=SCM_EOL) - { - return gh_scm2int (s); - } - - if (first_in_phrase_b_) - return LEFT; - - Grob * lyric; - bool end_phrase = true; - - for (int l = 0; l < lyrics_.size () && end_phrase; l++) - { - lyric = lyrics_[l]; - SCM lyric_scm = lyric->get_grob_property ("text"); - String lyric_string = gh_string_p (lyric_scm)?ly_scm2string (lyric_scm):""; - char lastchar; - if (lyric_string.length ()>0) - { - lastchar = lyric_string[lyric_string.length ()-1]; - /* If it doesn't end in punctuation then it ain't an end of phrase */ - if (! strchr (punc, lastchar)) - { - /* - FIXME: Document this. - - Special case: trailing space. Here examine the - previous character and reverse the sense of the test - (i.e. trailing space makes a break without - punctuation, or suppresses a break with punctuation). - This behaviour can be suppressed by including a space - in the phrasingPunctuation property, in which case - trailing space always means the same as punctuation. - - FIXME: The extra space throws alignment out a bit. - */ - if (lastchar == ' ') - { - if (lyric_string.length ()>1) - { - lastchar = lyric_string[lyric_string.length ()-2]; - if (strchr (punc, lastchar)) - end_phrase=false; - } - } - else - end_phrase=false; - } - } - } - if (end_phrase) - return RIGHT; - - return CENTER; -} - -/** We don't know about the melisma until after the initial alignment work is done, so go - back and fix the alignment when we DO know. -*/ -void -Syllable_group::adjust_melisma_align () -{ - if (notehead_ && lyrics_.size ()) - { - // override any previous offset adjustments - Real translation = -group_translation_; - // melisma aligning: - switch (alignment_) - { - // case LEFT: // that's all - case CENTER: // move right so smallest lyric is left-aligned on notehead - translation += (shortest_lyric_->extent (shortest_lyric_, X_AXIS)).length ()/2; - break; - case RIGHT: // move right so smallest lyric is left-aligned on notehead - translation += (shortest_lyric_->extent (shortest_lyric_, X_AXIS)).length (); - break; - } - group_translation_ += translation; - for (int l = 0; l < lyrics_.size (); l++) - { - lyrics_[l]->translate_axis (translation, X_AXIS); - } - } -} - - -bool -Syllable_group::is_empty () -{ - return lyrics_.size ()==0; -} - -void -Syllable_group::next_lyric () -{ - first_in_phrase_b_ = (alignment_ == RIGHT); - clear (); -} - -/* SMOB */ -SCM -Syllable_group::mark_smob (SCM) -{ - return SCM_EOL; -} - -int -Syllable_group::print_smob (SCM, SCM port, scm_print_state *) -{ - scm_puts ("#", port); - return 1; -} - - -IMPLEMENT_SIMPLE_SMOBS (Syllable_group); -IMPLEMENT_DEFAULT_EQUAL_P (Syllable_group); - -SCM -Syllable_group::make_entry () -{ - Syllable_group *vi = new Syllable_group; - return vi->smobbed_self (); -} - -struct Lyric_syllable -{ - static bool has_interface (Grob*); -}; -ADD_INTERFACE (Lyric_syllable,"lyric-syllable-interface", - "a single piece of lyrics", - "word-space alignment ignore-length-mismatch begin-alignment end-alignment"); - diff --git a/lily/tie-engraver.cc b/lily/tie-engraver.cc index 087b2d25ca..bc3da26174 100644 --- a/lily/tie-engraver.cc +++ b/lily/tie-engraver.cc @@ -83,7 +83,7 @@ Tie_engraver::try_music (Music *mus) void Tie_engraver::process_music () { - if (event_ && to_boolean (get_property ("automaticMelismata"))) + if (event_) daddy_trans_->set_property ("tieMelismaBusy", SCM_BOOL_T); } @@ -137,9 +137,8 @@ Tie_engraver::process_acknowledged_grobs () void Tie_engraver::start_translation_timestep () { - if (to_boolean (get_property ("automaticMelismata"))) - daddy_trans_->set_property ("tieMelismaBusy", - gh_bool2scm (heads_to_tie_.size ())); + daddy_trans_->set_property ("tieMelismaBusy", + gh_bool2scm (heads_to_tie_.size ())); } diff --git a/lily/translator-group.cc b/lily/translator-group.cc index e85ced8d6d..eda211406f 100644 --- a/lily/translator-group.cc +++ b/lily/translator-group.cc @@ -228,7 +228,7 @@ Translator_group::get_default_interpreter () Translator_def *t = unsmob_translator_def (st); if (!t) { - warning (_f ("can't find or create: `%s'", ly_scm2string (nm).to_str0 ())); + warning (_f ("can't find or create: `%s'", ly_symbol2string (nm).to_str0 ())); t = unsmob_translator_def (this->definition_); } Translator_group *tg = t->instantiate (output_def_); diff --git a/ly/declarations-init.ly b/ly/declarations-init.ly index c0b714dfe1..79ea3a6a44 100644 --- a/ly/declarations-init.ly +++ b/ly/declarations-init.ly @@ -35,7 +35,6 @@ melisma = \property Staff.melismaBusy = ##t melismaEnd = \property Staff.melismaBusy = ##f -\include "engraver-init.ly" \include "grace-init.ly" % ugh diff --git a/ly/engraver-init.ly b/ly/engraver-init.ly index a00f20e0dc..43db20f3bd 100644 --- a/ly/engraver-init.ly +++ b/ly/engraver-init.ly @@ -5,7 +5,7 @@ % setup for Request->Element conversion. Guru-only % -StaffContext=\translator { +\translator { \type "Engraver_group_engraver" \name Staff @@ -59,7 +59,7 @@ StaffContext=\translator { } -StaffContainerContext = \translator { +\translator { \type Engraver_group_engraver \consists "Axis_group_engraver" minimumVerticalExtent = ##f @@ -71,7 +71,7 @@ StaffContainerContext = \translator { \name StaffContainer } -InnerChoirStaffContext = \translator { +\translator { \type "Engraver_group_engraver" \name InnerChoirStaff \consists "System_start_delimiter_engraver" @@ -86,7 +86,7 @@ InnerChoirStaffContext = \translator { \accepts "ChordNames" } -ChoirStaffContext = \translator { +\translator { \InnerChoirStaffContext \name ChoirStaff @@ -98,7 +98,7 @@ ChoirStaffContext = \translator { } -RhythmicStaffContext=\translator{ +\translator{ \type "Engraver_group_engraver" \consists "Output_property_engraver" @@ -136,7 +136,7 @@ RhythmicStaffContext=\translator{ } -VoiceContext = \translator { +\translator { \type "Engraver_group_engraver" \name Voice @@ -196,7 +196,7 @@ VoiceContext = \translator { \accepts Thread % bug if you leave out this! } -ThreadContext = \translator{ +\translator{ \type Engraver_group_engraver \name Thread localKeySignature = #'() @@ -215,8 +215,7 @@ ThreadContext = \translator{ } - -GrandStaffContext=\translator{ +\translator{ \type "Engraver_group_engraver" \name GrandStaff localKeySignature = #'() @@ -233,7 +232,7 @@ GrandStaffContext=\translator{ \accepts "Staff" } -PianoStaffContext = \translator{ +\translator{ \GrandStaffContext \name "PianoStaff" \alias "GrandStaff" @@ -254,7 +253,7 @@ PianoStaffContext = \translator{ % \consistsend "Axis_group_engraver" } -InnerStaffGroupContext= \translator { +\translator { \type "Engraver_group_engraver" \name InnerStaffGroup localKeySignature = #'() @@ -274,7 +273,7 @@ InnerStaffGroupContext= \translator { \accepts "ChordNames" } -StaffGroupContext = \translator { +\translator { \InnerStaffGroupContext \name StaffGroup @@ -293,7 +292,7 @@ StaffGroupContext = \translator { % UGH! JUNKME -LyricsVoiceContext= \translator{ +\translator{ \type "Engraver_group_engraver" \consistsend "Hara_kiri_engraver" minimumVerticalExtent = #'(-1.2 . 2.4) @@ -313,10 +312,9 @@ LyricsVoiceContext= \translator{ \consists "Stanza_number_engraver" \consists "Instrument_name_engraver" \consists "Skip_event_swallow_translator" - phrasingPunctuation = #".,:!?\"" SeparationItem \set #'padding = #0.5 } -NoteNamesContext = \translator { +\translator { \type "Engraver_group_engraver" \name NoteNames \consistsend "Axis_group_engraver" @@ -334,7 +332,7 @@ NoteNamesContext = \translator { \consists "Separating_line_group_engraver" } -LyricsContext = \translator { +\translator { \type "Engraver_group_engraver" \name Lyrics \description "Typesets lyrics." @@ -350,7 +348,7 @@ LyricsContext = \translator { } -ChordNamesContext = \translator { +\translator { \type "Engraver_group_engraver" \name ChordNames \description "Typesets chord names." @@ -368,7 +366,7 @@ ChordNamesContext = \translator { } -RemoveEmptyStaffContext = \translator { +RemoveEmptyStaffContext= \translator { \StaffContext \remove "Axis_group_engraver" \consistsend "Hara_kiri_engraver" @@ -378,13 +376,15 @@ RemoveEmptyStaffContext = \translator { Beam \override #'auto-knee-gap = #'() } -RemoveEmptyStaffContext = \translator { +AncientRemoveEmptyStaffContext = \translator { + %% why not add by default? + \RemoveEmptyStaffContext \accepts "VaticanaVoice" \accepts "GregorianTranscriptionVoice" } -ScoreContext = \translator { +\translator { \type Score_engraver \name Score localKeySignature = #'() @@ -450,7 +450,7 @@ ScoreContext = \translator { centralCPosition = #-6 automaticPhrasing = ##t - automaticMelismata = ##t + phrasingPunctuation = #".,:!?\"" defaultBarType = #"|" barNumberVisibility = #default-bar-number-visibility @@ -562,11 +562,11 @@ ScoreContext = \translator { \grobdescriptions #all-grob-descriptions } -OrchestralScoreContext= \translator { +\translator { \ScoreContext } -EasyNotation = \translator { +EasyNotation = \translator { \ScoreContext NoteHead \override #'molecule-callback = #Note_head::brew_ez_molecule NoteHead \override #'Y-extent-callback = #'() @@ -575,7 +575,7 @@ EasyNotation = \translator { -FiguredBassContext = \translator { +\translator { \type "Engraver_group_engraver" \name FiguredBass \consists "Figured_bass_engraver" @@ -586,7 +586,7 @@ FiguredBassContext = \translator { \consistsend "Hara_kiri_engraver" } -TabVoiceContext = \translator { +\translator { \VoiceContext \name "TabVoice" \denies "Thread" @@ -607,7 +607,7 @@ TabVoiceContext = \translator { \remove Accidental_engraver } -TabStaffContext = \translator { +\translator { \StaffContext \alias "Staff" \name "TabStaff" @@ -650,7 +650,7 @@ TabStaffContext = \translator { % TRANSLATOR: \translator { \VaticanaStaffContext }" in % gregorian-init.ly. --jr -VaticanaVoiceContext = \translator { +\translator { \VoiceContext \name "VaticanaVoice" \alias "Voice" @@ -697,7 +697,7 @@ VaticanaVoiceContext = \translator { TextSpanner \set #'edge-text = #'("" . "") } -VaticanaStaffContext = \translator { +\translator { \StaffContext \name "VaticanaStaff" \alias "Staff" @@ -737,7 +737,7 @@ VaticanaStaffContext = \translator { % Score.barAlways = ##t } -GregorianTranscriptionVoiceContext = \translator { +\translator { \VoiceContext \name "GregorianTranscriptionVoice" \alias "Voice" @@ -782,8 +782,7 @@ GregorianTranscriptionVoiceContext = \translator { TextSpanner \set #'enclose-bounds = ##t TextSpanner \set #'edge-text = #'("" . "") } - -GregorianTranscriptionStaffContext = \translator { + \translator { \StaffContext \name "GregorianTranscriptionStaff" \alias "Staff" diff --git a/ly/params-init.ly b/ly/params-init.ly index 2d92144942..3b87492108 100644 --- a/ly/params-init.ly +++ b/ly/params-init.ly @@ -31,30 +31,6 @@ blotdiameter = 0.35 \pt interscoreline = 4. \mm -\translator { \NoteNamesContext } -\translator { \ScoreContext } -\translator { \ChoirStaffContext} -\translator { \InnerChoirStaffContext} - -\translator { \RhythmicStaffContext} -\translator { \StaffContext } -\translator { \VoiceContext} -\translator { \StaffGroupContext } -\translator { \InnerStaffGroupContext } -\translator { \ChordNamesContext } -\translator { \GrandStaffContext} -\translator { \LyricsContext } -\translator { \ThreadContext} -\translator { \PianoStaffContext} -\translator { \LyricsVoiceContext } -\translator { \StaffContainerContext } -\translator { \FiguredBassContext } -\translator { \TabStaffContext } -\translator { \TabVoiceContext } -\translator { \VaticanaStaffContext } -\translator { \VaticanaVoiceContext } -\translator { \GregorianTranscriptionStaffContext } -\translator { \GregorianTranscriptionVoiceContext } %% @@ -69,3 +45,5 @@ interscoreline = 4. \mm )) + +\include "engraver-init.ly" diff --git a/ly/performer-init.ly b/ly/performer-init.ly index 51c90fd780..0d21c2d45f 100644 --- a/ly/performer-init.ly +++ b/ly/performer-init.ly @@ -3,7 +3,7 @@ % % setup for Request->Element conversion. Guru-only % -StaffContext = \translator { +\translator { \type "Staff_performer" \name Staff \accepts Voice @@ -14,7 +14,7 @@ StaffContext = \translator { } -VoiceContext = \translator { +\translator { \type "Performer_group_performer" \name Voice \consists "Dynamic_performer" @@ -24,44 +24,44 @@ VoiceContext = \translator { \accepts "Thread" } -ThreadContext = \translator { +\translator { \type "Performer_group_performer" \name Thread \consists "Note_performer" } -FiguredBassContext = \translator { +\translator { \type "Performer_group_performer" \name FiguredBass \consists "Swallow_performer" } -GrandStaffContext = \translator { +\translator { \type "Performer_group_performer" \name GrandStaff \accepts RhythmicStaff \accepts Staff } -PianoStaffContext = \translator { +\translator { \type "Performer_group_performer" \name "PianoStaff" \accepts Staff } -TabVoiceContext = \translator { +\translator { \type "Performer_group_performer" \name "TabVoice" \consists "Swallow_performer" } -TabStaffContext = \translator { +\translator { \type "Performer_group_performer" \name "TabStaff" \accepts "TabVoice" } -ScoreContext = \translator { +\translator { \type "Score_performer" \name Score @@ -126,15 +126,6 @@ ScoreContext = \translator { \accepts Staff } +\translator { \StaffContext \name RhythmicStaff } -\translator { \ScoreContext } -\translator { \StaffContext } -\translator { \StaffContext \name RhythmicStaff } -\translator { \VoiceContext } -\translator { \ThreadContext } -\translator { \PianoStaffContext } -\translator { \TabVoiceContext } -\translator { \TabStaffContext } -\translator { \GrandStaffContext } -\translator { \FiguredBassContext } diff --git a/scm/define-grob-properties.scm b/scm/define-grob-properties.scm index 878968ef8b..3303f0014c 100644 --- a/scm/define-grob-properties.scm +++ b/scm/define-grob-properties.scm @@ -378,7 +378,6 @@ as a real penalty.") "Remove the first staff of a orchestral score?") (grob-property-description 'right-padding ly:dimension? "space right of accs.") (grob-property-description 'right-position number? "position of right part of spanner.") -(grob-property-description 'right-trim-amount ly:dimension? "shortening of the lyric extender on the right.") (grob-property-description 'script-priority number? "A sorting key that determines in what order a script is within a stack of scripts.") (grob-property-description 'self-alignment-X number-or-grob? "real number: -1 = left aligned, 0 = center, 1 right-aligned in X direction. diff --git a/scm/define-grobs.scm b/scm/define-grobs.scm index 9e4c10bccb..b3cfa72bb7 100644 --- a/scm/define-grobs.scm +++ b/scm/define-grobs.scm @@ -481,8 +481,7 @@ (LyricExtender . ( (molecule-callback . ,Lyric_extender::brew_molecule) - (height . 0.8) ; stafflinethickness; - (right-trim-amount . 0.5) + (thickness . 0.8) ; stafflinethickness; (Y-extent-callback . ,Grob::point_dimension_callback) (meta . ((interfaces . (lyric-extender-interface spanner-interface)))) )) diff --git a/scm/define-translator-properties.scm b/scm/define-translator-properties.scm index b3abc1366d..fa2ebec41b 100644 --- a/scm/define-translator-properties.scm +++ b/scm/define-translator-properties.scm @@ -112,11 +112,6 @@ X-. This feature is turned on by default. See the example file @file{lyrics-multi-stanza.ly}. ") -(translator-property-description 'automaticMelismata boolean? " If -set, \\addlyrics will assume that beams, slurs and ties signal -melismata, and align lyrics accordingly. -") - (translator-property-description 'barAlways boolean? "If set to true a bar line is drawn after each note. ") diff --git a/scripts/convert-ly.py b/scripts/convert-ly.py index bdcce0cb97..758314b0de 100644 --- a/scripts/convert-ly.py +++ b/scripts/convert-ly.py @@ -1624,7 +1624,22 @@ def conv (str): str =re.sub (r"\.\s+stz=", ". instr ", str) return str -conversions.append (((2,1,2), conv, """ly:get-music-length -> ly:music-length""")) +conversions.append (((2,1,3), conv, """stanza -> instrument""")) + +def conv (str): + def func (match): + c = match.group (1) + b = match.group (2) + + if b == 't' and c <> 'Score': + return r"\unset \property %s.melismaBusyProperties" % c + elif b == 'f': + return r"\property %s.melismaBusyProperties = #'(melismaBusy)" % c + + str =re.sub (r"\\property ([a-zA-Z]+)\s*\.\s*automaticMelismata\s*=\s*##([ft])", func, str) + return str + +conversions.append (((2,1,4), conv, """removal of automaticMelismata; use melismaBusyProperties instead.""")) ################################ # END OF CONVERSIONS -- 2.39.2