-2004-01-01 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+2004-01-02 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+
+ * 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.
@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
@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
\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]
PACKAGE_NAME=LilyPond
MAJOR_VERSION=2
MINOR_VERSION=1
-PATCH_LEVEL=4
-MY_PATCH_LEVEL=hwn1
+PATCH_LEVEL=5
+MY_PATCH_LEVEL=
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
+++ /dev/null
-
-\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?
- }
- >>
- >>
-}
-
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
-#(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 }
>>
}
\score {
\addlyrics
\context Voice = "v" \notes \relative c'' {
- \property Staff.automaticMelismata = ##t
\autoBeamOff
a a a8 ( a) a4
}
\context ChordNames \accompaniment
\addlyrics
\context Staff = one {
- \property Staff.autoBeaming = ##f
- \property Staff.automaticMelismata = ##t
+ \autoBeamOff
\melody
}
\context Lyrics \text
<<
\addlyrics
\context Staff = mel {
- \property Staff.autoBeaming = ##f
- \property Staff.automaticMelismata = ##t
+ \autoBeamOff
\melody
}
\context Lyrics \text
\score { \notes
\context StaffGroup <<
- \property Score.automaticMelismata = ##t
\context Lyrics = sopLyrs { s1 }
\context Staff = women { s1 }
\context Lyrics = altoLyrs { s1 }
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);
}
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);
Jan Nieuwenhuizen <janneke@gnu.org>
*/
-#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);
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<Item*> (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<Item*> (i.grob_));
- }
+ if (extender_)
+ extender_->set_bound (LEFT, item);
+
+ if (finished_extender_ && !finished_extender_->get_bound (RIGHT))
+ finished_extender_->set_bound (RIGHT, item);
}
}
bool
Extender_engraver::try_music (Music* r)
{
- if (req_)
+ if (ev_)
return false;
- req_ = r;
+ ev_ = r;
return true;
}
{
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());
}
}
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;
}
/* descr */ "Create lyric extenders",
/* creats*/ "LyricExtender",
/* accepts */ "extender-event",
-/* acks */ "lyric-syllable-interface",
+/* acks */ "lyric-syllable-interface",
/* reads */ "",
/* write */ "");
#include "music.hh"
#include "translator-group.hh"
-Grob_info::Grob_info (Grob*s)
-{
- grob_ = s;
- origin_trans_ = 0;
-}
-
Grob_info::Grob_info ()
{
Music*
Grob_info::music_cause ()
-
{
SCM cause = grob_->get_grob_property ("cause");
return unsmob_music (cause);
#include "spanner.hh"
#include "item.hh"
+
MAKE_SCHEME_CALLBACK (Hyphen_spanner,set_spacing_rods,1);
SCM
Hyphen_spanner::set_spacing_rods (SCM smob)
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");
public:
Music * music_cause ();
Link_array<Translator> origin_transes (Translator*) const;
- Grob_info (Grob*);
Grob_info ();
};
+++ /dev/null
-/*
- lyric-phrasing-engraver.hh -- declare Lyric_phrasing_engraver
-
- source file of the GNU LilyPond music typesetter
-
- (c) 2000--2003 Glen Prideaux <glenprideaux@iname.com>
-*/
-
-
-#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<Grob> 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
#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);
}
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");
-/*
- 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 <glenprideaux@iname.com>
-*/
-#include <string.h>
+(c) 2003--2004 Han-Wen Nienhuys <hanwen@xs4all.nl>
-#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<Grob> lyrics_;
+ Link_array<Grob> heads_;
+ Link_array<Spanner> past_extenders_;
+ Link_array<Spanner> 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<Phrasing_association> 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<Spanner*> (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<Item*> (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",
+ "");
+
+++ /dev/null
-/*
- new-phrasing-engraver.cc -- implement New_phrasing_engraver
-
-source file of the GNU LilyPond music typesetter
-
-(c) 2003--2004 Han-Wen Nienhuys <hanwen@xs4all.nl>
-
- */
-
-#include "translator-group.hh"
-#include "engraver.hh"
-#include "note-head.hh"
-#include "grob.hh"
-
-struct Phrasing_association
-{
- String name_;
- Link_array<Grob> lyrics_;
- Link_array<Grob> 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<Phrasing_association> 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",
- "");
-
%type <music> shorthand_command_req
%type <music> post_event tagged_post_event
%type <music> command_req verbose_command_req
-%type <music> extender_req
%type <music> hyphen_req
%type <music> string_number_event
%type <scm> string bare_number number_expression number_term number_factor
;
shorthand_command_req:
- extender_req {
- $$ = $1;
- }
- | hyphen_req {
+ hyphen_req {
$$ = $1;
}
| BREATHE {
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));
-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 ())
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);
}
}
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);
*/
return true;
-
}
else if (d == STOP)
{
}
void
-Slur_engraver::process_acknowledged_grobs ()
+Slur_engraver::process_music ()
{
Link_array<Grob> start_slurs;
for (int i=0; i< new_slur_evs_.size (); i++)
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 ();
}
Slur_engraver::start_translation_timestep ()
{
new_slur_evs_.clear ();
- SCM m = get_property ("automaticMelismata");
- if (to_boolean (m))
- {
- set_melisma (slur_stack_.size ());
- }
}
+++ /dev/null
-#include <string.h>
-
-#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<Spanner*> (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 <? translate;
- }
-
- translate *= alignment_ ;
- }
- return translate;
-}
-
-
-/** determine what alignment we want.
- Rules: if property alignment is set it specifies the alignment
- if first_in_phrase_b_ is set, then alignment is LEFT.
- otherwise if each syllable ends in punctuation, then alignment is RIGHT
- otherwise alignment is centre.
-*/
-int
-Syllable_group::appropriate_alignment (const char *punc)
-{
- SCM s=this->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 ("#<Syllable_group>", 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");
-
void
Tie_engraver::process_music ()
{
- if (event_ && to_boolean (get_property ("automaticMelismata")))
+ if (event_)
daddy_trans_->set_property ("tieMelismaBusy", SCM_BOOL_T);
}
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 ()));
}
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_);
melismaEnd = \property Staff.melismaBusy = ##f
-\include "engraver-init.ly"
\include "grace-init.ly"
% ugh
% setup for Request->Element conversion. Guru-only
%
-StaffContext=\translator {
+\translator {
\type "Engraver_group_engraver"
\name Staff
}
-StaffContainerContext = \translator {
+\translator {
\type Engraver_group_engraver
\consists "Axis_group_engraver"
minimumVerticalExtent = ##f
\name StaffContainer
}
-InnerChoirStaffContext = \translator {
+\translator {
\type "Engraver_group_engraver"
\name InnerChoirStaff
\consists "System_start_delimiter_engraver"
\accepts "ChordNames"
}
-ChoirStaffContext = \translator {
+\translator {
\InnerChoirStaffContext
\name ChoirStaff
}
-RhythmicStaffContext=\translator{
+\translator{
\type "Engraver_group_engraver"
\consists "Output_property_engraver"
}
-VoiceContext = \translator {
+\translator {
\type "Engraver_group_engraver"
\name Voice
\accepts Thread % bug if you leave out this!
}
-ThreadContext = \translator{
+\translator{
\type Engraver_group_engraver
\name Thread
localKeySignature = #'()
}
-
-GrandStaffContext=\translator{
+\translator{
\type "Engraver_group_engraver"
\name GrandStaff
localKeySignature = #'()
\accepts "Staff"
}
-PianoStaffContext = \translator{
+\translator{
\GrandStaffContext
\name "PianoStaff"
\alias "GrandStaff"
% \consistsend "Axis_group_engraver"
}
-InnerStaffGroupContext= \translator {
+\translator {
\type "Engraver_group_engraver"
\name InnerStaffGroup
localKeySignature = #'()
\accepts "ChordNames"
}
-StaffGroupContext = \translator {
+\translator {
\InnerStaffGroupContext
\name StaffGroup
% UGH! JUNKME
-LyricsVoiceContext= \translator{
+\translator{
\type "Engraver_group_engraver"
\consistsend "Hara_kiri_engraver"
minimumVerticalExtent = #'(-1.2 . 2.4)
\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"
\consists "Separating_line_group_engraver"
}
-LyricsContext = \translator {
+\translator {
\type "Engraver_group_engraver"
\name Lyrics
\description "Typesets lyrics."
}
-ChordNamesContext = \translator {
+\translator {
\type "Engraver_group_engraver"
\name ChordNames
\description "Typesets chord names."
}
-RemoveEmptyStaffContext = \translator {
+RemoveEmptyStaffContext= \translator {
\StaffContext
\remove "Axis_group_engraver"
\consistsend "Hara_kiri_engraver"
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 = #'()
centralCPosition = #-6
automaticPhrasing = ##t
- automaticMelismata = ##t
+ phrasingPunctuation = #".,:!?\""
defaultBarType = #"|"
barNumberVisibility = #default-bar-number-visibility
\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 = #'()
-FiguredBassContext = \translator {
+\translator {
\type "Engraver_group_engraver"
\name FiguredBass
\consists "Figured_bass_engraver"
\consistsend "Hara_kiri_engraver"
}
-TabVoiceContext = \translator {
+\translator {
\VoiceContext
\name "TabVoice"
\denies "Thread"
\remove Accidental_engraver
}
-TabStaffContext = \translator {
+\translator {
\StaffContext
\alias "Staff"
\name "TabStaff"
% TRANSLATOR: \translator { \VaticanaStaffContext }" in
% gregorian-init.ly. --jr
-VaticanaVoiceContext = \translator {
+\translator {
\VoiceContext
\name "VaticanaVoice"
\alias "Voice"
TextSpanner \set #'edge-text = #'("" . "")
}
-VaticanaStaffContext = \translator {
+\translator {
\StaffContext
\name "VaticanaStaff"
\alias "Staff"
% Score.barAlways = ##t
}
-GregorianTranscriptionVoiceContext = \translator {
+\translator {
\VoiceContext
\name "GregorianTranscriptionVoice"
\alias "Voice"
TextSpanner \set #'enclose-bounds = ##t
TextSpanner \set #'edge-text = #'("" . "")
}
-
-GregorianTranscriptionStaffContext = \translator {
+ \translator {
\StaffContext
\name "GregorianTranscriptionStaff"
\alias "Staff"
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 }
%%
))
+
+\include "engraver-init.ly"
%
% setup for Request->Element conversion. Guru-only
%
-StaffContext = \translator {
+\translator {
\type "Staff_performer"
\name Staff
\accepts Voice
}
-VoiceContext = \translator {
+\translator {
\type "Performer_group_performer"
\name Voice
\consists "Dynamic_performer"
\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
\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 }
"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.
(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))))
))
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.
")
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