2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 1997--2011 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/>.
23 #include "dot-column.hh"
25 #include "duration.hh"
26 #include "global-context.hh"
28 #include "output-def.hh"
30 #include "rhythmic-head.hh"
31 #include "score-engraver.hh"
33 #include "staff-symbol-referencer.hh"
34 #include "stream-event.hh"
36 #include "tie-column.hh"
39 #include "translator.icc"
44 When we catch the note, we predict the end of the note. We keep the
45 events living until we reach the predicted end-time.
47 Every time process_music () is called and there are note events, we
48 figure out how long the note to typeset should be. It should be no
49 longer than what's specified, than what is left to do and it should
52 We copy the events into scratch note events, to make sure that we get
53 all durations exactly right.
56 class Completion_heads_engraver : public Engraver
58 vector<Item *> notes_;
59 vector<Item *> prev_notes_;
60 // Must remember notes for explicit ties.
61 vector<Item *> tie_note_candidates_;
62 vector<Stream_event *> tie_note_candidate_events_;
64 vector<Stream_event *> note_events_;
69 Rational do_nothing_until_;
72 Moment next_barline_moment ();
73 Item *make_note_head (Stream_event *);
76 TRANSLATOR_DECLARATIONS (Completion_heads_engraver);
79 virtual void initialize ();
80 void make_tie (Grob *, Grob *);
81 void start_translation_timestep ();
82 void process_music ();
83 void stop_translation_timestep ();
84 DECLARE_TRANSLATOR_LISTENER (note);
88 Completion_heads_engraver::initialize ()
93 IMPLEMENT_TRANSLATOR_LISTENER (Completion_heads_engraver, note);
95 Completion_heads_engraver::listen_note (Stream_event *ev)
97 note_events_.push_back (ev);
100 Moment now = now_mom ();
101 Moment musiclen = get_event_length (ev, now);
103 note_end_mom_ = max (note_end_mom_, (now + musiclen));
104 do_nothing_until_ = Rational (0, 0);
108 The duration _until_ the next bar line.
111 Completion_heads_engraver::next_barline_moment ()
113 Moment *e = unsmob_moment (get_property ("measurePosition"));
114 Moment *l = unsmob_moment (get_property ("measureLength"));
115 if (!e || !l || !to_boolean (get_property ("timing")))
117 return Moment (0, 0);
124 Completion_heads_engraver::make_note_head (Stream_event *ev)
126 Item *note = make_item ("NoteHead", ev->self_scm ());
127 Pitch *pit = unsmob_pitch (ev->get_property ("pitch"));
129 int pos = pit->steps ();
130 SCM c0 = get_property ("middleCPosition");
131 if (scm_is_number (c0))
132 pos += scm_to_int (c0);
134 note->set_property ("staff-position", scm_from_int (pos));
140 Completion_heads_engraver::process_music ()
142 if (!is_first_ && !left_to_do_)
147 Moment now = now_mom ();
148 if (do_nothing_until_ > now.main_part_)
156 note that note_dur may be strictly less than left_to_do_
157 (say, if left_to_do_ == 5/8)
159 if (factor_.denominator () == 1 && factor_ > Rational (1, 1))
160 note_dur = Duration (left_to_do_, false);
162 note_dur = Duration (left_to_do_ / factor_, false).compressed (factor_);
166 orig = unsmob_duration (note_events_[0]->get_property ("duration"));
168 factor_ = note_dur.factor ();
169 left_to_do_ = orig->get_length ();
171 Moment nb = next_barline_moment ();
172 if (nb.main_part_ && nb < note_dur.get_length ())
174 if (factor_.denominator () == 1 && factor_ > Rational (1, 1))
175 note_dur = Duration (nb.main_part_, false);
177 note_dur = Duration (nb.main_part_ / factor_, false).compressed (factor_);
180 do_nothing_until_ = now.main_part_ + note_dur.get_length ();
182 for (vsize i = 0; left_to_do_ && i < note_events_.size (); i++)
184 bool need_clone = !orig || *orig != note_dur;
185 Stream_event *event = note_events_[i];
188 event = event->clone ();
190 SCM pits = note_events_[i]->get_property ("pitch");
191 event->set_property ("pitch", pits);
192 event->set_property ("duration", note_dur.smobbed_copy ());
193 event->set_property ("length", Moment (note_dur.get_length ()).smobbed_copy ());
194 event->set_property ("duration-log", scm_from_int (note_dur.duration_log ()));
197 The Completion_heads_engraver splits an event into a group of consecutive events.
198 For each event in the group, the property "autosplit-end" denotes whether the current event
199 was truncated during splitting. Based on "autosplit-end", the Tie_engraver decides whether a
200 tie event should be processed.
202 event->set_property ("autosplit-end",
203 ly_bool2scm (left_to_do_ - note_dur.get_length () > Rational (0)));
205 Item *note = make_note_head (event);
208 notes_.push_back (note);
211 if (prev_notes_.size () == notes_.size ())
213 for (vsize i = 0; i < notes_.size (); i++)
214 make_tie (prev_notes_[i], notes_[i]);
217 if (ties_.size () && !tie_column_)
218 tie_column_ = make_spanner ("TieColumn", ties_[0]->self_scm ());
221 for (vsize i = ties_.size (); i--;)
222 Tie_column::add_tie (tie_column_, ties_[i]);
224 left_to_do_ -= note_dur.get_length ();
226 get_global_context ()->add_moment_to_process (now.main_part_ + note_dur.get_length ());
228 don't do complicated arithmetic with grace notes.
230 if (orig && now_mom ().grace_part_)
231 left_to_do_ = Rational (0, 0);
235 Completion_heads_engraver::make_tie (Grob *left, Grob *right)
237 Grob *p = make_spanner ("Tie", SCM_EOL);
238 Tie::set_head (p, LEFT, left);
239 Tie::set_head (p, RIGHT, right);
244 Completion_heads_engraver::stop_translation_timestep ()
250 prev_notes_ = notes_;
255 Completion_heads_engraver::start_translation_timestep ()
257 Moment now = now_mom ();
258 if (note_end_mom_.main_part_ <= now.main_part_)
260 tie_note_candidate_events_ = note_events_;
261 tie_note_candidates_ = prev_notes_;
263 note_events_.clear ();
264 prev_notes_.clear ();
266 context ()->set_property ("completionBusy",
267 ly_bool2scm (note_events_.size ()));
270 Completion_heads_engraver::Completion_heads_engraver ()
275 ADD_TRANSLATOR (Completion_heads_engraver,
277 "This engraver replaces @code{Note_heads_engraver}. It plays"
278 " some trickery to break long notes and automatically tie them"
279 " into the next measure.",