]> git.donarmstrong.com Git - lilypond.git/blob - lily/extender-engraver.cc
Issue 4938 (1/3) Add Audio_item and Midi_item subclasses for control changes
[lilypond.git] / lily / extender-engraver.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1999--2015 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
22 #include "context.hh"
23 #include "engraver.hh"
24 #include "international.hh"
25 #include "item.hh"
26 #include "lyric-extender.hh"
27 #include "note-head.hh"
28 #include "pointer-group-interface.hh"
29 #include "stream-event.hh"
30 #include "warn.hh"
31 #include "spanner.hh"
32 #include "translator.icc"
33
34 void completize_extender (Spanner *sp);
35
36 class Extender_engraver : public Engraver
37 {
38   Stream_event *ev_;
39   Spanner *extender_;
40   Spanner *pending_extender_;
41
42 public:
43   TRANSLATOR_DECLARATIONS (Extender_engraver);
44
45 protected:
46   void listen_extender (Stream_event *);
47   void listen_completize_extender (Stream_event *);
48   void acknowledge_lyric_syllable (Grob_info);
49
50   virtual void finalize ();
51
52   void stop_translation_timestep ();
53   void process_music ();
54 };
55
56 Extender_engraver::Extender_engraver ()
57 {
58   extender_ = 0;
59   pending_extender_ = 0;
60   ev_ = 0;
61 }
62
63 void
64 Extender_engraver::listen_extender (Stream_event *ev)
65 {
66   ASSIGN_EVENT_ONCE (ev_, ev);
67 }
68
69 /*
70   A CompletizeExtenderEvent is sent at the end of each lyrics block
71   to ensure any pending extender can be correctly terminated if the lyrics
72   end before the associated voice (this prevents the right bound being extended
73   to the next note-column if no lyric follows the extender)
74 */
75 void
76 Extender_engraver::listen_completize_extender (Stream_event * /* ev */)
77 {
78   if (pending_extender_)
79     {
80       completize_extender (pending_extender_);
81       pending_extender_ = 0;
82     }
83 }
84
85 void
86 Extender_engraver::process_music ()
87 {
88   if (ev_)
89     extender_ = make_spanner ("LyricExtender", ev_->self_scm ());
90 }
91
92 void
93 Extender_engraver::acknowledge_lyric_syllable (Grob_info i)
94 {
95   Item *item = i.item ();
96   if (extender_)
97     extender_->set_bound (LEFT, item);
98
99   if (pending_extender_)
100     {
101       pending_extender_->set_object ("next", item->self_scm ());
102       completize_extender (pending_extender_);
103       pending_extender_ = 0;
104     }
105 }
106
107 void
108 Extender_engraver::stop_translation_timestep ()
109 {
110   if (extender_ || pending_extender_)
111     {
112       Context *voice = get_voice_to_lyrics (context ());
113       Grob *h = voice ? get_current_note_head (voice) : 0;
114
115       if (h)
116         {
117           if (extender_)
118             {
119               Pointer_group_interface::add_grob (extender_,
120                                                  ly_symbol2scm ("heads"), h);
121             }
122
123           if (pending_extender_)
124             {
125               Pointer_group_interface::add_grob (pending_extender_,
126                                                  ly_symbol2scm ("heads"), h);
127             }
128         }
129       else
130         {
131           if (pending_extender_
132               && !get_property ("extendersOverRests"))
133             {
134               completize_extender (pending_extender_);
135               pending_extender_ = 0;
136             }
137         }
138       if (extender_)
139         {
140           pending_extender_ = extender_;
141           extender_ = 0;
142         }
143     }
144
145   ev_ = 0;
146 }
147
148 void
149 completize_extender (Spanner *sp)
150 {
151   if (!sp->get_bound (RIGHT))
152     {
153       extract_item_set (sp, "heads", heads);
154       if (heads.size ())
155         sp->set_bound (RIGHT, heads.back ());
156     }
157 }
158
159 void
160 Extender_engraver::finalize ()
161 {
162   if (extender_)
163     {
164       completize_extender (extender_);
165
166       if (!extender_->get_bound (RIGHT))
167         extender_->warning (_ ("unterminated extender"));
168       extender_ = 0;
169     }
170
171   if (pending_extender_)
172     {
173       completize_extender (pending_extender_);
174
175       if (!pending_extender_->get_bound (RIGHT))
176         pending_extender_->warning (_ ("unterminated extender"));
177       pending_extender_ = 0;
178     }
179 }
180
181 void
182 Extender_engraver::boot ()
183 {
184   ADD_LISTENER (Extender_engraver, extender);
185   ADD_LISTENER (Extender_engraver, completize_extender);
186   ADD_ACKNOWLEDGER (Extender_engraver, lyric_syllable);
187 }
188
189 ADD_TRANSLATOR (Extender_engraver,
190                 /* doc */
191                 "Create lyric extenders.",
192
193                 /* create */
194                 "LyricExtender ",
195
196                 /* read */
197                 "extendersOverRests ",
198
199                 /* write */
200                 ""
201                );