2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 1998--2012 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 ASSIGN_EVENT_ONCE (event_, ev);
109 void Tie_engraver::report_unterminated_tie (Head_event_tuple const &tie_start)
111 // If tie_from_chord_created is set, we have another note at the same
112 // moment that created a tie, so this is not necessarily an unterminated
113 // tie. Happens e.g. for <c e g>~ g
114 if (!tie_start.tie_from_chord_created)
116 tie_start.tie_->warning (_ ("unterminated tie"));
117 tie_start.tie_->suicide ();
122 Determines whether the end of an event was created by
123 a split in Completion_heads_engraver or by user input.
126 Tie_engraver::has_autosplit_end (Stream_event *event)
129 return to_boolean (event->get_property ("autosplit-end"));
134 Tie_engraver::process_music ()
137 for (vsize i = 0; !busy && i < heads_to_tie_.size (); i++)
138 busy |= (heads_to_tie_[i].tie_event_
139 || heads_to_tie_[i].tie_stream_event_);
142 context ()->set_property ("tieMelismaBusy", SCM_BOOL_T);
146 Tie_engraver::acknowledge_note_head (Grob_info i)
150 now_heads_.push_back (h);
151 for (vsize i = heads_to_tie_.size (); i--;)
153 Grob *th = heads_to_tie_[i].head_;
154 Stream_event *right_ev = unsmob_stream_event (h->get_property ("cause"));
155 Stream_event *left_ev = unsmob_stream_event (th->get_property ("cause"));
158 maybe should check positions too.
160 if (!right_ev || !left_ev)
164 Make a tie only if pitches are equal or if event end was not generated by
165 Completion_heads_engraver.
167 if (ly_is_equal (right_ev->get_property ("pitch"), left_ev->get_property ("pitch"))
168 && (!Tie_engraver::has_autosplit_end (left_ev)))
170 Grob *p = heads_to_tie_[i].tie_;
171 Moment end = heads_to_tie_[i].end_moment_;
173 Stream_event *cause = heads_to_tie_[i].tie_event_
174 ? heads_to_tie_[i].tie_event_
175 : heads_to_tie_[i].tie_stream_event_;
177 announce_end_grob (p, cause->self_scm ());
179 Tie::set_head (p, LEFT, th);
180 Tie::set_head (p, RIGHT, h);
182 if (is_direction (cause->get_property ("direction")))
184 Direction d = to_dir (cause->get_property ("direction"));
185 p->set_property ("direction", scm_from_int (d));
189 heads_to_tie_.erase (heads_to_tie_.begin () + i);
192 Prevent all other tied notes ending at the same moment (assume
193 implicitly the notes have also started at the same moment!)
194 from triggering an "unterminated tie" warning. Needed e.g. for
197 for (vsize j = heads_to_tie_.size (); j--;)
199 if (heads_to_tie_[j].end_moment_ == end)
200 heads_to_tie_[j].tie_from_chord_created = true;
205 if (ties_.size () && ! tie_column_)
206 tie_column_ = make_spanner ("TieColumn", ties_[0]->self_scm ());
209 for (vsize i = ties_.size (); i--;)
210 Tie_column::add_tie (tie_column_, ties_[i]);
214 Tie_engraver::start_translation_timestep ()
216 if (heads_to_tie_.size () && !to_boolean (get_property ("tieWaitForNote")))
218 Moment now = now_mom ();
219 for (vsize i = heads_to_tie_.size (); i--;)
221 if (now > heads_to_tie_[i].end_moment_)
223 report_unterminated_tie (heads_to_tie_[i]);
224 heads_to_tie_.erase (heads_to_tie_.begin () + i);
229 context ()->set_property ("tieMelismaBusy",
230 ly_bool2scm (heads_to_tie_.size ()));
234 Tie_engraver::process_acknowledged ()
236 bool wait = to_boolean (get_property ("tieWaitForNote"));
241 vector<Head_event_tuple>::iterator it = heads_to_tie_.begin ();
242 for (; it < heads_to_tie_.end (); it++)
243 report_unterminated_tie (*it);
244 heads_to_tie_.clear ();
247 for (vsize i = 0; i < ties_.size (); i++)
248 typeset_tie (ties_[i]);
254 vector<Head_event_tuple> new_heads_to_tie;
257 for (vsize i = 0; i < now_heads_.size (); i++)
259 Grob *head = now_heads_[i];
260 Stream_event *left_ev
261 = unsmob_stream_event (head->get_property ("cause"));
265 // may happen for ambitus
269 // We only want real notes to cause ties, not e.g. pitched trills
270 if (!left_ev->in_event_class ("note-event"))
273 SCM left_articulations = left_ev->get_property ("articulations");
275 Stream_event *tie_event = 0;
276 Stream_event *tie_stream_event = event_;
277 for (SCM s = left_articulations;
278 !tie_event && !tie_stream_event && scm_is_pair (s);
281 Stream_event *ev = unsmob_stream_event (scm_car (s));
285 if (ev->in_event_class ("tie-event"))
289 if (left_ev && (tie_event || tie_stream_event)
290 && (!Tie_engraver::has_autosplit_end (left_ev)))
292 event_processed_ = true;
294 Head_event_tuple event_tup;
296 event_tup.head_ = head;
297 event_tup.tie_event_ = tie_event;
298 event_tup.tie_stream_event_ = tie_stream_event;
299 event_tup.tie_ = make_spanner ("Tie", tie_event
300 ? tie_event->self_scm ()
301 : tie_stream_event->self_scm ());
303 Moment end = now_mom ();
306 end.grace_part_ += get_event_length (left_ev).main_part_;
310 end += get_event_length (left_ev);
312 event_tup.end_moment_ = end;
314 new_heads_to_tie.push_back (event_tup);
318 if (!wait && new_heads_to_tie.size ())
320 vector<Head_event_tuple>::iterator it = heads_to_tie_.begin ();
321 for (; it < heads_to_tie_.end (); it++)
322 report_unterminated_tie (*it);
323 heads_to_tie_.clear ();
326 // hmmm, how to do with copy () ?
327 for (vsize i = 0; i < new_heads_to_tie.size (); i++)
328 heads_to_tie_.push_back (new_heads_to_tie[i]);
334 Tie_engraver::stop_translation_timestep ()
337 Discard event only if it has been processed with at least one
340 if (event_processed_)
343 event_processed_ = false;
347 Tie_engraver::typeset_tie (Grob *her)
349 if (! (Tie::head (her, LEFT) && Tie::head (her, RIGHT)))
350 warning (_ ("lonely tie"));
352 Drul_array<Grob *> new_head_drul;
353 new_head_drul[LEFT] = Tie::head (her, LEFT);
354 new_head_drul[RIGHT] = Tie::head (her, RIGHT);
355 for (LEFT_and_RIGHT (d))
357 if (!Tie::head (her, d))
358 new_head_drul[d] = Tie::head (her, (Direction) - d);
361 Spanner *sp = dynamic_cast<Spanner *> (her);
362 sp->set_bound (LEFT, new_head_drul[LEFT]);
363 sp->set_bound (RIGHT, new_head_drul[RIGHT]);
366 ADD_ACKNOWLEDGER (Tie_engraver, note_head);
367 ADD_TRANSLATOR (Tie_engraver,
369 "Generate ties between note heads of equal pitch.",