2 extender-engraver.cc -- implement Extender_engraver
4 source file of the GNU LilyPond music typesetter
6 (c) 1999--2009 Glen Prideaux <glenprideaux@iname.com>,
7 Han-Wen Nienhuys <hanwen@xs4all.nl>,
8 Jan Nieuwenhuizen <janneke@gnu.org>
11 #include "engraver.hh"
12 #include "international.hh"
14 #include "lyric-extender.hh"
15 #include "note-head.hh"
16 #include "pointer-group-interface.hh"
17 #include "stream-event.hh"
20 #include "paper-column.hh"
22 #include "translator.icc"
24 void completize_extender (Spanner
*sp
);
26 class Extender_engraver
: public Engraver
30 Spanner
*pending_extender_
;
31 bool current_lyric_is_skip_
;
34 TRANSLATOR_DECLARATIONS (Extender_engraver
);
37 DECLARE_TRANSLATOR_LISTENER (extender
);
38 DECLARE_ACKNOWLEDGER (lyric_syllable
);
40 virtual void finalize ();
42 void stop_translation_timestep ();
43 void process_music ();
46 Extender_engraver::Extender_engraver ()
48 current_lyric_is_skip_
= false;
50 pending_extender_
= 0;
54 IMPLEMENT_TRANSLATOR_LISTENER (Extender_engraver
, extender
);
56 Extender_engraver::listen_extender (Stream_event
*ev
)
58 ASSIGN_EVENT_ONCE (ev_
, ev
);
62 Extender_engraver::process_music ()
65 extender_
= make_spanner ("LyricExtender", ev_
->self_scm ());
69 Extender_engraver::acknowledge_lyric_syllable (Grob_info i
)
71 Item
*item
= i
.item ();
73 extender_
->set_bound (LEFT
, item
);
75 SCM text
= item
->get_property ("text");
76 current_lyric_is_skip_
= ly_is_equal (text
, scm_from_locale_string (" "));
78 if (pending_extender_
&& !current_lyric_is_skip_
)
80 pending_extender_
->set_object ("next", item
->self_scm ());
81 completize_extender (pending_extender_
);
82 pending_extender_
= 0;
87 Extender_engraver::stop_translation_timestep ()
89 if (extender_
|| pending_extender_
)
91 Context
*voice
= get_voice_to_lyrics (context ());
92 Grob
*h
= voice
? get_current_note_head (voice
) : 0;
98 Pointer_group_interface::add_grob (extender_
,
99 ly_symbol2scm ("heads"), h
);
102 if (pending_extender_
)
104 Pointer_group_interface::add_grob (pending_extender_
,
105 ly_symbol2scm ("heads"), h
);
107 The following check addresses the case where the lyrics end before
108 the associated voice. The current_lyric_is_skip_ check is
109 necessary to handle manual melismata, which should not result in
110 extenders being completized. We also need to make sure that we're not
111 in the middle of a note (happens when this function is called because
112 of an event in a voice other than our associated one).
114 if (!melisma_busy (voice
) && !current_lyric_is_skip_
)
116 Moment now
= voice
->now_mom ();
117 Paper_column
*column
= (dynamic_cast<Item
*> (h
))->get_column ();
118 Moment
*start_mom
= column
? unsmob_moment (column
->get_property ("when")) : 0;
119 if (!column
|| (start_mom
->main_part_
== now
.main_part_
))
121 completize_extender (pending_extender_
);
122 pending_extender_
= 0;
129 if (pending_extender_
130 && !get_property ("extendersOverRests"))
132 completize_extender (pending_extender_
);
133 pending_extender_
= 0;
139 pending_extender_
= extender_
;
148 completize_extender (Spanner
*sp
)
150 if (!sp
->get_bound (RIGHT
))
152 extract_item_set (sp
, "heads", heads
);
154 sp
->set_bound (RIGHT
, heads
.back ());
159 Extender_engraver::finalize ()
163 completize_extender (extender_
);
165 if (!extender_
->get_bound (RIGHT
))
166 extender_
->warning (_ ("unterminated extender"));
170 if (pending_extender_
)
172 completize_extender (pending_extender_
);
174 if (!pending_extender_
->get_bound (RIGHT
))
175 pending_extender_
->warning (_ ("unterminated extender"));
176 pending_extender_
= 0;
180 ADD_ACKNOWLEDGER (Extender_engraver
, lyric_syllable
);
181 ADD_TRANSLATOR (Extender_engraver
,
183 "Create lyric extenders.",
189 "extendersOverRests ",