]> git.donarmstrong.com Git - lilypond.git/blob - lily/extender-engraver.cc
Run grand-replace for 2010.
[lilypond.git] / lily / extender-engraver.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1999--2010 Glen Prideaux <glenprideaux@iname.com>,
5   Han-Wen Nienhuys <hanwen@xs4all.nl>,
6   Jan Nieuwenhuizen <janneke@gnu.org>
7
8   LilyPond is free software: you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation, either version 3 of the License, or
11   (at your option) any later version.
12
13   LilyPond is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
20 */
21 #include "context.hh"
22 #include "engraver.hh"
23 #include "international.hh"
24 #include "item.hh"
25 #include "lyric-extender.hh"
26 #include "note-head.hh"
27 #include "pointer-group-interface.hh"
28 #include "stream-event.hh"
29 #include "warn.hh"
30 #include "spanner.hh"
31 #include "paper-column.hh"
32
33 #include "translator.icc"
34
35 void completize_extender (Spanner *sp);
36
37 class Extender_engraver : public Engraver
38 {
39   Stream_event *ev_;
40   Spanner *extender_;
41   Spanner *pending_extender_;
42   bool current_lyric_is_skip_;
43
44 public:
45   TRANSLATOR_DECLARATIONS (Extender_engraver);
46
47 protected:
48   DECLARE_TRANSLATOR_LISTENER (extender);
49   DECLARE_ACKNOWLEDGER (lyric_syllable);
50
51   virtual void finalize ();
52
53   void stop_translation_timestep ();
54   void process_music ();
55 };
56
57 Extender_engraver::Extender_engraver ()
58 {
59   current_lyric_is_skip_ = false;
60   extender_ = 0;
61   pending_extender_ = 0;
62   ev_ = 0;
63 }
64
65 IMPLEMENT_TRANSLATOR_LISTENER (Extender_engraver, extender);
66 void
67 Extender_engraver::listen_extender (Stream_event *ev)
68 {
69   ASSIGN_EVENT_ONCE (ev_, ev);
70 }
71
72 void
73 Extender_engraver::process_music ()
74 {
75   if (ev_)
76     extender_ = make_spanner ("LyricExtender", ev_->self_scm ());
77 }
78
79 void
80 Extender_engraver::acknowledge_lyric_syllable (Grob_info i)
81 {
82   Item *item = i.item ();
83   if (extender_)
84     extender_->set_bound (LEFT, item);
85
86   SCM text = item->get_property ("text");
87   current_lyric_is_skip_ = ly_is_equal (text, scm_from_locale_string (" "));
88
89   if (pending_extender_ && !current_lyric_is_skip_)
90     {
91       pending_extender_->set_object ("next", item->self_scm ());
92       completize_extender (pending_extender_);
93       pending_extender_ = 0;
94     }
95 }
96
97 void
98 Extender_engraver::stop_translation_timestep ()
99 {
100   if (extender_ || pending_extender_)
101     {
102       Context *voice = get_voice_to_lyrics (context ());
103       Grob *h = voice ? get_current_note_head (voice) : 0;
104
105       if (h)
106         {
107           if (extender_)
108             {
109               Pointer_group_interface::add_grob (extender_,
110                                                  ly_symbol2scm ("heads"), h);
111             }
112
113         if (pending_extender_)
114           {
115             Pointer_group_interface::add_grob (pending_extender_,
116                                               ly_symbol2scm ("heads"), h);
117             /*
118               The following check addresses the case where the lyrics end before
119               the associated voice. The current_lyric_is_skip_ check is
120               necessary to handle manual melismata, which should not result in
121               extenders being completized. We also need to make sure that we're not
122               in the middle of a note (happens when this function is called because
123               of an event in a voice other than our associated one).
124             */
125             if (!melisma_busy (voice) && !current_lyric_is_skip_)
126               {
127                 Moment now = voice->now_mom ();
128                 Paper_column *column = (dynamic_cast<Item *> (h))->get_column ();
129                 Moment *start_mom = column ? unsmob_moment (column->get_property ("when")) : 0;
130                 if (!column || (start_mom->main_part_ == now.main_part_))
131                   {
132                     completize_extender (pending_extender_);
133                     pending_extender_ = 0;
134                   }
135               }
136             }
137         }
138       else
139         {
140           if (pending_extender_
141               && !get_property ("extendersOverRests"))
142             {
143               completize_extender (pending_extender_);
144               pending_extender_ = 0;
145             }
146           
147         }
148       if (extender_)
149         {
150           pending_extender_ = extender_;
151           extender_ = 0;
152         }
153     }
154
155   ev_ = 0;
156 }
157
158 void
159 completize_extender (Spanner *sp)
160 {
161   if (!sp->get_bound (RIGHT))
162     {
163       extract_item_set (sp, "heads", heads);
164       if (heads.size ())
165         sp->set_bound (RIGHT, heads.back ());
166     }
167 }
168
169 void
170 Extender_engraver::finalize ()
171 {
172   if (extender_)
173     {
174       completize_extender (extender_);
175
176       if (!extender_->get_bound (RIGHT))
177         extender_->warning (_ ("unterminated extender"));
178       extender_ = 0;
179     }
180
181   if (pending_extender_)
182     {
183       completize_extender (pending_extender_);
184
185       if (!pending_extender_->get_bound (RIGHT))
186         pending_extender_->warning (_ ("unterminated extender"));
187       pending_extender_ = 0;
188     }
189 }
190
191 ADD_ACKNOWLEDGER (Extender_engraver, lyric_syllable);
192 ADD_TRANSLATOR (Extender_engraver,
193                 /* doc */
194                 "Create lyric extenders.",
195
196                 /* create */
197                 "LyricExtender ",
198
199                 /* read */
200                 "extendersOverRests ",
201
202                 /* write */
203                 ""
204                 );