- for(SCM v=voice_alist_; gh_pair_p(v); v = gh_cdr(v)) {
- SCM entry_scm = gh_cdar(v);
- // ((alist_entry . entry_is_old) . previous_entry)
- Syllable_group * entry = unsmob_voice_entry(gh_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(gh_cdar(entry_scm))) {
- Syllable_group * previous_entry = unsmob_voice_entry(gh_cdr(entry_scm));
- previous_entry->copy(entry);
- entry_scm = gh_cons(gh_cons(gh_caar(entry_scm), SCM_BOOL_T), gh_cdr(entry_scm));
- voice_alist_ = scm_assoc_set_x(voice_alist_, gh_caar(v), entry_scm);
- }
- entry->next_lyric();
- }
- any_notehead_l_ = 0;
-}
-
-
-
-/*=========================================================================================*/
-
-/** 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_l_=0;
- lyric_list_.clear();
- longest_lyric_l_=0;
- shortest_lyric_l_=0;
- melisma_b_ = false;
- group_translation_f_ = 0.0;
-}
-
-void
-Syllable_group::copy( Syllable_group *from)
-{
- notehead_l_ = from->notehead_l_;
- lyric_list_ = from->lyric_list_;
- longest_lyric_l_ = from->longest_lyric_l_;
- shortest_lyric_l_ = from->shortest_lyric_l_;
- melisma_b_ = from->melisma_b_;
- alignment_i_ = from->alignment_i_;
- first_in_phrase_b_ = from->first_in_phrase_b_;
- group_translation_f_ = from->group_translation_f_;
-}
-
-void
-Syllable_group::set_first_in_phrase(bool f)
-{
- first_in_phrase_b_ = f;
-}
-
-void
-Syllable_group::set_notehead(Score_element * notehead)
-{
- if(!notehead_l_) {
- /* there should only be a single notehead, so silently ignore any extras */
- notehead_l_=notehead;
- }
-}
-
-void
-Syllable_group::add_lyric(Score_element * lyric)
-{
- lyric_list_.push(lyric);
- /* record longest and shortest lyrics */
- if( longest_lyric_l_ ) {
- if(lyric->extent(X_AXIS).length() > (longest_lyric_l_->extent(X_AXIS)).length())
- longest_lyric_l_ = lyric;
- if(lyric->extent(X_AXIS).length() < (shortest_lyric_l_->extent(X_AXIS)).length())
- shortest_lyric_l_ = lyric;
- }
- else
- longest_lyric_l_ = shortest_lyric_l_ = lyric;
-}
-
-void
-Syllable_group::add_extender(Score_element * extender)
-{
- if(notehead_l_ && melisma_b_) {
- dynamic_cast<Spanner*>(extender)->set_bound (RIGHT, notehead_l_);
- // 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_elt_property("right-trim-amount", gh_double2scm(0.0));
-
- // Right:
- Real ss = extender->paper_l ()->get_var ("staffspace");
- extender->set_elt_property("right-trim-amount",
- gh_double2scm(-notehead_l_->extent(X_AXIS).length()/ss));
- }
-}
-
-bool
-Syllable_group::set_lyric_align(const char *punc, Score_element *default_notehead_l)
-{
- if(lyric_list_.size()==0) {
- // No lyrics: nothing to do.
- return true;
- }
-
- Score_element * lyric;
- alignment_i_ = 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).
- if(!notehead_l_) {
- notehead_l_ = default_notehead_l;
- }
-
- group_translation_f_ = amount_to_translate();
-
- // set the x alignment of each lyric
- for(int l = 0; l < lyric_list_.size(); l++) {
- lyric = lyric_list_[l];
- lyric->set_elt_property("self-alignment-X", gh_int2scm(alignment_i_));
- // centre on notehead ... if we have one.
- if(notehead_l_) {
- lyric->set_parent(notehead_l_, X_AXIS);
- lyric->add_offset_callback (Side_position::centered_on_parent, X_AXIS);
- // reference is on the right of the notehead; move it left half way, and add translation
- lyric->translate_axis (group_translation_f_-(notehead_l_->extent(X_AXIS)).center(), X_AXIS);
- }
- }
- return (notehead_l_);
-}
-
-/** determine the distance to translate lyrics to get correct alignment
- Rules: If alignment is centre, translate = 0
- Otherwise,
- If (length of longest lyric) < 2 * (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_i_ != CENTER) {
- // FIXME: do we really know the lyric extent here? Some font sizing comes later?
- if((longest_lyric_l_->extent(X_AXIS)).length() <
- (shortest_lyric_l_->extent(X_AXIS)).length() * 2 )
- translate = alignment_i_*(longest_lyric_l_->extent(X_AXIS)).length()/2;
- else
- translate = alignment_i_*(shortest_lyric_l_->extent(X_AXIS)).length();
- }
- return translate;
-}
-
-
-/** determine what alignment we want.
- Rules: 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)
-{
- if(first_in_phrase_b_)
- return LEFT;
-
- Score_element * lyric;
- bool end_phrase = true;
-
- for(int l = 0; l < lyric_list_.size() && end_phrase; l++) {
- lyric = lyric_list_[l];
- SCM lyric_scm = lyric->get_elt_property("text");
- String lyric_str = gh_string_p(lyric_scm)?ly_scm2string(lyric_scm):"";
- char lastchar;
- if(lyric_str.length_i()>0) {
- lastchar = lyric_str[lyric_str.length_i()-1];
- /* If it doesn't end in punctuation then it ain't an end of phrase */
- if(! strchr(punc, lastchar)) {
- /* 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_str.length_i()>1) {
- lastchar = lyric_str[lyric_str.length_i()-2];
- if(strchr(punc, lastchar))
- end_phrase=false;
- }