]> git.donarmstrong.com Git - lilypond.git/blob - lily/tuplet-engraver.cc
Issue 4550 (1/2) Avoid "using namespace std;" in included files
[lilypond.git] / lily / tuplet-engraver.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1998--2015 Han-Wen Nienhuys <hanwen@xs4all.nl>
5
6   LilyPond is free software: you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation, either version 3 of the License, or
9   (at your option) any later version.
10
11   LilyPond is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "beam.hh"
21 #include "engraver.hh"
22 #include "international.hh"
23 #include "note-column.hh"
24 #include "spanner.hh"
25 #include "stream-event.hh"
26 #include "tuplet-bracket.hh"
27 #include "warn.hh"
28 #include "item.hh"
29 #include "moment.hh"
30
31 #include "translator.icc"
32
33 using std::vector;
34
35 struct Tuplet_description
36 {
37   Stream_event *event_;
38   Spanner *bracket_;
39   Spanner *number_;
40
41   bool full_length_;
42   bool full_length_note_;
43   Moment stop_moment_;
44   Moment start_moment_;
45   Moment length_;
46
47   Tuplet_description ()
48   {
49     event_ = 0;
50     full_length_note_ = false;
51     full_length_ = false;
52     bracket_ = 0;
53     number_ = 0;
54   }
55 };
56
57 class Tuplet_engraver : public Engraver
58 {
59 public:
60   TRANSLATOR_DECLARATIONS (Tuplet_engraver);
61
62 protected:
63   vector<Tuplet_description> tuplets_;
64   vector<Tuplet_description> new_tuplets_;
65   vector<Tuplet_description> stopped_tuplets_;
66   vector<Spanner *> last_tuplets_;
67
68   DECLARE_ACKNOWLEDGER (note_column);
69   DECLARE_ACKNOWLEDGER (script);
70   DECLARE_ACKNOWLEDGER (finger);
71   DECLARE_ACKNOWLEDGER (string_number);
72   DECLARE_TRANSLATOR_LISTENER (tuplet_span);
73   virtual void finalize ();
74   void start_translation_timestep ();
75   void process_music ();
76 };
77
78 IMPLEMENT_TRANSLATOR_LISTENER (Tuplet_engraver, tuplet_span);
79 void
80 Tuplet_engraver::listen_tuplet_span (Stream_event *ev)
81 {
82   Direction dir = to_dir (ev->get_property ("span-direction"));
83   if (dir == START)
84     {
85       Tuplet_description d;
86       d.event_ = ev;
87
88       d.length_ = robust_scm2moment (d.event_->get_property ("length"),
89                                      Moment (0));
90       d.start_moment_ = now_mom ();
91       d.stop_moment_ = now_mom () + d.length_;
92
93       for (vsize i = 0; i < new_tuplets_.size (); i++)
94         {
95           /*
96             discard duplicates.
97           */
98           if (new_tuplets_[i].stop_moment_ == d.stop_moment_)
99             return;
100         }
101
102       new_tuplets_.push_back (d);
103     }
104   else if (dir == STOP)
105     {
106       if (tuplets_.size ())
107         {
108           stopped_tuplets_.push_back (tuplets_.back ());
109           tuplets_.pop_back ();
110         }
111       else if (!to_boolean (get_property ("skipTypesetting")))
112         ev->origin ()->debug_output (_ ("No tuplet to end"));
113     }
114   else
115     ev->origin ()->programming_error ("direction tuplet-span-event_ invalid.");
116 }
117
118 void
119 Tuplet_engraver::process_music ()
120 {
121   /*
122     This may happen if the end of a tuplet is part of a quoted voice.
123    */
124   Moment now = now_mom ();
125   for (vsize i = tuplets_.size (); i--;)
126     {
127       if (tuplets_[i].stop_moment_ == now)
128         {
129           stopped_tuplets_.push_back (tuplets_[i]);
130           tuplets_.erase (tuplets_.begin () + i);
131         }
132     }
133
134   for (vsize i = 0; i < stopped_tuplets_.size (); i++)
135     {
136       Spanner *bracket = stopped_tuplets_[i].bracket_;
137       Spanner *number = stopped_tuplets_[i].number_;
138       if (bracket)
139         {
140           if (stopped_tuplets_[i].full_length_)
141             {
142               Item *col
143                 = unsmob<Item> (stopped_tuplets_[i].full_length_note_
144                                ? get_property ("currentMusicalColumn")
145                                : get_property ("currentCommandColumn"));
146
147               bracket->set_bound (RIGHT, col);
148               number->set_bound (RIGHT, col);
149             }
150           else if (!bracket->get_bound (RIGHT))
151             {
152               if (bracket->get_bound (LEFT))
153                 {
154                   bracket->set_bound (RIGHT,
155                                       bracket->get_bound (LEFT));
156                   number->set_bound (RIGHT,
157                                      stopped_tuplets_[i].bracket_->get_bound (LEFT));
158                 }
159               else
160                 {
161                   warning ("omitting tuplet bracket with neither left nor right bound");
162                   continue;
163                 }
164             }
165           // todo: scrap last_tuplets_, use stopped_tuplets_ only.
166           // clear stopped_tuplets_ at start_translation_timestep
167           last_tuplets_.push_back (bracket);
168           last_tuplets_.push_back (number);
169         }
170     }
171   stopped_tuplets_.clear ();
172
173   concat (tuplets_, new_tuplets_);
174   new_tuplets_.clear ();
175   for (vsize j = tuplets_.size (); j > 0; j--)
176     {
177       /* i goes from size-1 downto 0, inclusively */
178       vsize i = j - 1;
179
180       if (tuplets_[i].bracket_)
181         continue;
182
183       tuplets_[i].full_length_ = to_boolean (get_property ("tupletFullLength"));
184       tuplets_[i].full_length_note_
185         = to_boolean (get_property ("tupletFullLengthNote"));
186
187       tuplets_[i].bracket_ = make_spanner ("TupletBracket",
188                                            tuplets_[i].event_->self_scm ());
189       tuplets_[i].number_ = make_spanner ("TupletNumber",
190                                           tuplets_[i].event_->self_scm ());
191       tuplets_[i].number_->set_object ("bracket", tuplets_[i].bracket_->self_scm ());
192       tuplets_[i].number_->set_parent (tuplets_[i].bracket_, X_AXIS);
193       tuplets_[i].number_->set_parent (tuplets_[i].bracket_, Y_AXIS);
194       tuplets_[i].bracket_->set_object ("tuplet-number", tuplets_[i].number_->self_scm ());
195       tuplets_[i].stop_moment_.grace_part_ = 0;
196
197       if (i + 1 < tuplets_.size () && tuplets_[i + 1].bracket_)
198         Tuplet_bracket::add_tuplet_bracket (tuplets_[i].bracket_, tuplets_[i + 1].bracket_);
199
200       if (i > 0 && tuplets_[i - 1].bracket_)
201         Tuplet_bracket::add_tuplet_bracket (tuplets_[i - 1].bracket_, tuplets_[i].bracket_);
202
203     }
204 }
205
206 void
207 Tuplet_engraver::acknowledge_note_column (Grob_info inf)
208 {
209   for (vsize j = 0; j < tuplets_.size (); j++)
210     if (tuplets_[j].bracket_)
211       {
212         Item *i = dynamic_cast<Item *> (inf.grob ());
213         Tuplet_bracket::add_column (tuplets_[j].bracket_, i);
214         add_bound_item (tuplets_[j].number_, i);
215       }
216 }
217
218 void
219 Tuplet_engraver::acknowledge_script (Grob_info inf)
220 {
221   for (vsize j = 0; j < tuplets_.size (); j++)
222     if (tuplets_[j].bracket_)
223       {
224         Item *i = dynamic_cast<Item *> (inf.grob ());
225         if (!i->internal_has_interface (ly_symbol2scm ("dynamic-interface")))
226           Tuplet_bracket::add_script (tuplets_[j].bracket_, i);
227       }
228 }
229
230 void
231 Tuplet_engraver::acknowledge_finger (Grob_info inf)
232 {
233   for (vsize j = 0; j < tuplets_.size (); j++)
234     if (tuplets_[j].bracket_)
235       {
236         Item *i = dynamic_cast<Item *> (inf.grob ());
237         Tuplet_bracket::add_script (tuplets_[j].bracket_, i);
238       }
239 }
240
241 void
242 Tuplet_engraver::acknowledge_string_number (Grob_info inf)
243 {
244   for (vsize j = 0; j < tuplets_.size (); j++)
245     if (tuplets_[j].bracket_)
246       {
247         Item *i = dynamic_cast<Item *> (inf.grob ());
248         Tuplet_bracket::add_script (tuplets_[j].bracket_, i);
249       }
250 }
251
252 void
253 Tuplet_engraver::start_translation_timestep ()
254 {
255   last_tuplets_.clear ();
256   /*
257     May seem superfluous, but necessary for skipTypesetting.
258    */
259   new_tuplets_.clear ();
260 }
261
262 void
263 Tuplet_engraver::finalize ()
264 {
265   if (to_boolean (get_property ("tupletFullLength")))
266     for (vsize i = 0; i < last_tuplets_.size (); i++)
267       {
268         Item *col = unsmob<Item> (get_property ("currentCommandColumn"));
269         last_tuplets_[i]->set_bound (RIGHT, col);
270       }
271 }
272
273 Tuplet_engraver::Tuplet_engraver ()
274 {
275 }
276
277 ADD_ACKNOWLEDGER (Tuplet_engraver, note_column);
278 ADD_ACKNOWLEDGER (Tuplet_engraver, script);
279 ADD_ACKNOWLEDGER (Tuplet_engraver, finger);
280 ADD_ACKNOWLEDGER (Tuplet_engraver, string_number);
281 ADD_TRANSLATOR (Tuplet_engraver,
282                 /* doc */
283                 "Catch tuplet events and generate appropriate bracket.",
284
285                 /* create */
286                 "TupletBracket "
287                 "TupletNumber ",
288
289                 /* read */
290                 "tupletFullLength "
291                 "tupletFullLengthNote ",
292
293                 /* write */
294                 ""
295                );