2 tuplet-engraver.cc -- implement Tuplet_engraver
4 source file of the GNU LilyPond music typesetter
6 (c) 1998--2009 Han-Wen Nienhuys <hanwen@xs4all.nl>
10 #include "engraver.hh"
11 #include "international.hh"
12 #include "note-column.hh"
14 #include "stream-event.hh"
15 #include "tuplet-bracket.hh"
20 #include "translator.icc"
22 struct Tuplet_description
29 bool full_length_note_
;
37 full_length_note_
= false;
44 class Tuplet_engraver
: public Engraver
47 TRANSLATOR_DECLARATIONS (Tuplet_engraver
);
50 vector
<Tuplet_description
> tuplets_
;
51 vector
<Tuplet_description
> new_tuplets_
;
52 vector
<Tuplet_description
> stopped_tuplets_
;
53 vector
<Spanner
*> last_tuplets_
;
55 DECLARE_ACKNOWLEDGER (note_column
);
56 DECLARE_TRANSLATOR_LISTENER (tuplet_span
);
57 virtual void finalize ();
58 void start_translation_timestep ();
59 void process_music ();
62 IMPLEMENT_TRANSLATOR_LISTENER (Tuplet_engraver
, tuplet_span
);
64 Tuplet_engraver::listen_tuplet_span (Stream_event
*ev
)
66 Direction dir
= to_dir (ev
->get_property ("span-direction"));
72 d
.length_
= robust_scm2moment (d
.event_
->get_property ("length"),
74 d
.start_moment_
= now_mom ();
75 d
.stop_moment_
= now_mom () + d
.length_
;
77 for (vsize i
=0; i
< new_tuplets_
.size (); i
++)
82 if (new_tuplets_
[i
].stop_moment_
== d
.stop_moment_
)
86 new_tuplets_
.push_back (d
);
92 stopped_tuplets_
.push_back (tuplets_
.back ());
95 else if (!to_boolean (get_property ("skipTypesetting")))
96 ev
->origin ()->warning (_ ("No tuplet to end"));
99 ev
->origin ()->programming_error ("direction tuplet-span-event_ invalid.");
103 Tuplet_engraver::process_music ()
106 This may happen if the end of a tuplet is part of a quoted voice.
108 Moment now
= now_mom ();
109 for (vsize i
= tuplets_
.size (); i
--; )
111 if (tuplets_
[i
].stop_moment_
== now
)
113 stopped_tuplets_
.push_back (tuplets_
[i
]);
114 tuplets_
.erase (tuplets_
.begin () + i
);
118 for (vsize i
= 0; i
< stopped_tuplets_
.size (); i
++)
120 Spanner
*bracket
= stopped_tuplets_
[i
].bracket_
;
121 Spanner
*number
= stopped_tuplets_
[i
].number_
;
124 if (stopped_tuplets_
[i
].full_length_
)
127 unsmob_item (stopped_tuplets_
[i
].full_length_note_
128 ? get_property ("currentMusicalColumn")
129 : get_property ("currentCommandColumn"));
131 bracket
->set_bound (RIGHT
, col
);
132 number
->set_bound (RIGHT
, col
);
134 else if (!bracket
->get_bound (RIGHT
))
136 if (bracket
->get_bound (LEFT
))
138 bracket
->set_bound (RIGHT
,
139 bracket
->get_bound (LEFT
));
140 number
->set_bound (RIGHT
,
141 stopped_tuplets_
[i
].bracket_
->get_bound (LEFT
));
144 programming_error ("stopped tuplet bracket has left nor right bound.");
146 // todo: scrap last_tuplets_, use stopped_tuplets_ only.
147 // clear stopped_tuplets_ at start_translation_timestep
148 last_tuplets_
.push_back (bracket
);
149 last_tuplets_
.push_back (number
);
152 stopped_tuplets_
.clear ();
154 concat (tuplets_
, new_tuplets_
);
155 new_tuplets_
.clear ();
156 for (vsize j
= tuplets_
.size (); j
> 0; j
--)
158 /* i goes from size-1 downto 0, inclusively */
162 if (tuplets_
[i
].bracket_
)
165 tuplets_
[i
].full_length_
= to_boolean (get_property ("tupletFullLength"));
166 tuplets_
[i
].full_length_note_
167 = to_boolean (get_property ("tupletFullLengthNote"));
169 tuplets_
[i
].bracket_
= make_spanner ("TupletBracket",
170 tuplets_
[i
].event_
->self_scm ());
171 tuplets_
[i
].number_
= make_spanner ("TupletNumber",
172 tuplets_
[i
].event_
->self_scm ());
173 tuplets_
[i
].number_
->set_object ("bracket", tuplets_
[i
].bracket_
->self_scm ());
174 tuplets_
[i
].bracket_
->set_object ("tuplet-number", tuplets_
[i
].number_
->self_scm ());
175 tuplets_
[i
].stop_moment_
.grace_part_
= 0;
178 if (i
+ 1 < tuplets_
.size () && tuplets_
[i
+ 1].bracket_
)
179 Tuplet_bracket::add_tuplet_bracket (tuplets_
[i
].bracket_
, tuplets_
[i
+ 1].bracket_
);
181 if (i
> 0 && tuplets_
[i
- 1].bracket_
)
182 Tuplet_bracket::add_tuplet_bracket (tuplets_
[i
- 1].bracket_
, tuplets_
[i
].bracket_
);
188 Tuplet_engraver::acknowledge_note_column (Grob_info inf
)
190 for (vsize j
= 0; j
< tuplets_
.size (); j
++)
191 if (tuplets_
[j
].bracket_
)
193 Item
*i
= dynamic_cast<Item
*> (inf
.grob ());
194 Tuplet_bracket::add_column (tuplets_
[j
].bracket_
, i
);
195 add_bound_item (tuplets_
[j
].number_
, i
);
200 Tuplet_engraver::start_translation_timestep ()
202 last_tuplets_
.clear ();
204 May seem superfluous, but necessary for skipTypesetting.
206 new_tuplets_
.clear ();
210 Tuplet_engraver::finalize ()
212 if (to_boolean (get_property ("tupletFullLength")))
213 for (vsize i
= 0; i
< last_tuplets_
.size (); i
++)
215 Item
*col
= unsmob_item (get_property ("currentCommandColumn"));
216 last_tuplets_
[i
]->set_bound (RIGHT
, col
);
220 Tuplet_engraver::Tuplet_engraver ()
224 ADD_ACKNOWLEDGER (Tuplet_engraver
, note_column
);
225 ADD_TRANSLATOR (Tuplet_engraver
,
227 "Catch tuplet events and generate appropriate bracket.",
235 "tupletFullLengthNote ",