2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 1998--2014 Han-Wen Nienhuys <hanwen@xs4all.nl>
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.
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.
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/>.
20 #include "engraver.hh"
23 #include "international.hh"
25 #include "note-head.hh"
26 #include "protected-scm.hh"
28 #include "staff-symbol-referencer.hh"
29 #include "stream-event.hh"
30 #include "tie-column.hh"
34 #include "translator.icc"
37 Manufacture ties. Acknowledge note heads, and put them into a
38 priority queue. If we have a TieEvent, connect the notes that finish
39 just at this time, and note that start at this time.
41 TODO: Remove the dependency on musical info. We should tie on the
42 basis of position and duration-log of the heads (not of the events).
45 struct Head_event_tuple
49 Stream_event *tie_stream_event_;
50 Stream_event *tie_event_;
52 // Indicate whether a tie from the same moment has been processed successfully
53 // This is needed for tied chords, e.g. <c e g>~ g, because otherwise the c
54 // and e will trigger a warning for an unterminated tie!
55 bool tie_from_chord_created;
61 tie_stream_event_ = 0;
62 tie_from_chord_created = false;
67 class Tie_engraver : public Engraver
70 Whether tie event has been processed and can be deleted or should
71 be kept for later portions of a split note.
73 bool event_processed_;
75 vector<Grob *> now_heads_;
76 vector<Head_event_tuple> heads_to_tie_;
82 void process_acknowledged ();
83 void stop_translation_timestep ();
84 void start_translation_timestep ();
85 DECLARE_ACKNOWLEDGER (note_head);
86 DECLARE_TRANSLATOR_LISTENER (tie);
87 void process_music ();
88 void typeset_tie (Grob *);
89 void report_unterminated_tie (Head_event_tuple const &);
90 bool has_autosplit_end (Stream_event *event);
92 TRANSLATOR_DECLARATIONS (Tie_engraver);
95 Tie_engraver::Tie_engraver ()
99 event_processed_ = false;
102 IMPLEMENT_TRANSLATOR_LISTENER (Tie_engraver, tie);
104 Tie_engraver::listen_tie (Stream_event *ev)
106 if (!to_boolean (get_property ("skipTypesetting")))
108 ASSIGN_EVENT_ONCE (event_, ev);
112 void Tie_engraver::report_unterminated_tie (Head_event_tuple const &tie_start)
114 // If tie_from_chord_created is set, we have another note at the same
115 // moment that created a tie, so this is not necessarily an unterminated
116 // tie. Happens e.g. for <c e g>~ g
117 if (!tie_start.tie_from_chord_created)
119 tie_start.tie_->warning (_ ("unterminated tie"));
120 tie_start.tie_->suicide ();
125 Determines whether the end of an event was created by
126 a split in Completion_heads_engraver or by user input.
129 Tie_engraver::has_autosplit_end (Stream_event *event)
132 return to_boolean (event->get_property ("autosplit-end"));
137 Tie_engraver::process_music ()
140 for (vsize i = 0; !busy && i < heads_to_tie_.size (); i++)
141 busy |= (heads_to_tie_[i].tie_event_
142 || heads_to_tie_[i].tie_stream_event_);
145 context ()->set_property ("tieMelismaBusy", SCM_BOOL_T);
149 Tie_engraver::acknowledge_note_head (Grob_info i)
153 now_heads_.push_back (h);
154 for (vsize i = 0; i < heads_to_tie_.size (); i++)
156 Grob *th = heads_to_tie_[i].head_;
157 Stream_event *right_ev = Stream_event::unsmob (h->get_property ("cause"));
158 Stream_event *left_ev = Stream_event::unsmob (th->get_property ("cause"));
161 maybe should check positions too.
163 if (!right_ev || !left_ev)
167 Make a tie only if pitches are equal or if event end was not generated by
168 Completion_heads_engraver.
170 if (ly_is_equal (right_ev->get_property ("pitch"), left_ev->get_property ("pitch"))
171 && (!Tie_engraver::has_autosplit_end (left_ev)))
173 Grob *p = heads_to_tie_[i].tie_;
174 Moment end = heads_to_tie_[i].end_moment_;
176 Stream_event *cause = heads_to_tie_[i].tie_event_
177 ? heads_to_tie_[i].tie_event_
178 : heads_to_tie_[i].tie_stream_event_;
180 announce_end_grob (p, cause->self_scm ());
182 Tie::set_head (p, LEFT, th);
183 Tie::set_head (p, RIGHT, h);
185 if (is_direction (cause->get_property ("direction")))
187 Direction d = to_dir (cause->get_property ("direction"));
188 p->set_property ("direction", scm_from_int (d));
192 heads_to_tie_.erase (heads_to_tie_.begin () + i);
195 Prevent all other tied notes ending at the same moment (assume
196 implicitly the notes have also started at the same moment!)
197 from triggering an "unterminated tie" warning. Needed e.g. for
200 for (vsize j = heads_to_tie_.size (); j--;)
202 if (heads_to_tie_[j].end_moment_ == end)
203 heads_to_tie_[j].tie_from_chord_created = true;
210 if (ties_.size () && ! tie_column_)
211 tie_column_ = make_spanner ("TieColumn", ties_[0]->self_scm ());
214 for (vsize i = 0; i < ties_.size (); i++)
215 Tie_column::add_tie (tie_column_, ties_[i]);
219 Tie_engraver::start_translation_timestep ()
221 if (heads_to_tie_.size () && !to_boolean (get_property ("tieWaitForNote")))
223 Moment now = now_mom ();
224 for (vsize i = heads_to_tie_.size (); i--;)
226 if (now > heads_to_tie_[i].end_moment_)
228 report_unterminated_tie (heads_to_tie_[i]);
229 heads_to_tie_.erase (heads_to_tie_.begin () + i);
234 context ()->set_property ("tieMelismaBusy",
235 ly_bool2scm (heads_to_tie_.size ()));
239 Tie_engraver::process_acknowledged ()
241 bool wait = to_boolean (get_property ("tieWaitForNote"));
246 vector<Head_event_tuple>::iterator it = heads_to_tie_.begin ();
247 for (; it < heads_to_tie_.end (); it++)
248 report_unterminated_tie (*it);
249 heads_to_tie_.clear ();
252 for (vsize i = 0; i < ties_.size (); i++)
253 typeset_tie (ties_[i]);
259 vector<Head_event_tuple> new_heads_to_tie;
262 for (vsize i = 0; i < now_heads_.size (); i++)
264 Grob *head = now_heads_[i];
265 Stream_event *left_ev
266 = Stream_event::unsmob (head->get_property ("cause"));
270 // may happen for ambitus
274 // We only want real notes to cause ties, not e.g. pitched trills
275 if (!left_ev->in_event_class ("note-event"))
278 SCM left_articulations = left_ev->get_property ("articulations");
280 Stream_event *tie_event = 0;
281 Stream_event *tie_stream_event = event_;
282 for (SCM s = left_articulations;
283 !tie_event && !tie_stream_event && scm_is_pair (s);
286 Stream_event *ev = Stream_event::unsmob (scm_car (s));
290 if (ev->in_event_class ("tie-event"))
294 if (left_ev && (tie_event || tie_stream_event)
295 && (!Tie_engraver::has_autosplit_end (left_ev)))
297 event_processed_ = true;
299 Head_event_tuple event_tup;
301 event_tup.head_ = head;
302 event_tup.tie_event_ = tie_event;
303 event_tup.tie_stream_event_ = tie_stream_event;
304 event_tup.tie_ = make_spanner ("Tie", tie_event
305 ? tie_event->self_scm ()
306 : tie_stream_event->self_scm ());
308 Moment end = now_mom ();
311 end.grace_part_ += get_event_length (left_ev).main_part_;
315 end += get_event_length (left_ev);
317 event_tup.end_moment_ = end;
319 new_heads_to_tie.push_back (event_tup);
323 if (!wait && new_heads_to_tie.size ())
325 vector<Head_event_tuple>::iterator it = heads_to_tie_.begin ();
326 for (; it < heads_to_tie_.end (); it++)
327 report_unterminated_tie (*it);
328 heads_to_tie_.clear ();
331 // hmmm, how to do with copy () ?
332 for (vsize i = 0; i < new_heads_to_tie.size (); i++)
333 heads_to_tie_.push_back (new_heads_to_tie[i]);
339 Tie_engraver::stop_translation_timestep ()
342 Discard event only if it has been processed with at least one
345 if (event_processed_)
348 event_processed_ = false;
352 Tie_engraver::typeset_tie (Grob *her)
354 if (! (Tie::head (her, LEFT) && Tie::head (her, RIGHT)))
355 warning (_ ("lonely tie"));
357 Drul_array<Grob *> new_head_drul;
358 new_head_drul[LEFT] = Tie::head (her, LEFT);
359 new_head_drul[RIGHT] = Tie::head (her, RIGHT);
360 for (LEFT_and_RIGHT (d))
362 if (!Tie::head (her, d))
363 new_head_drul[d] = Tie::head (her, (Direction) - d);
366 Spanner *sp = dynamic_cast<Spanner *> (her);
367 sp->set_bound (LEFT, new_head_drul[LEFT]);
368 sp->set_bound (RIGHT, new_head_drul[RIGHT]);
371 ADD_ACKNOWLEDGER (Tie_engraver, note_head);
372 ADD_TRANSLATOR (Tie_engraver,
374 "Generate ties between note heads of equal pitch.",