2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 1997--2015 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"
40 #include "translator.icc"
47 When we catch the note, we predict the end of the note. We keep the
48 events living until we reach the predicted end-time.
50 Every time process_music () is called and there are note events, we
51 figure out how long the note to typeset should be. It should be no
52 longer than what's specified, than what is left to do and it should
53 not cross barlines or sub-bar units.
55 We copy the events into scratch note events, to make sure that we get
56 all durations exactly right.
59 class Completion_heads_engraver : public Engraver
61 vector<Item *> notes_;
62 vector<Item *> prev_notes_;
63 // Must remember notes for explicit ties.
64 vector<Spanner *> ties_;
65 vector<Stream_event *> note_events_;
70 Rational do_nothing_until_;
73 Moment next_moment (Rational const &);
74 Item *make_note_head (Stream_event *);
77 TRANSLATOR_DECLARATIONS (Completion_heads_engraver);
80 virtual void initialize ();
81 void make_tie (Grob *, Grob *);
82 void start_translation_timestep ();
83 void process_music ();
84 void stop_translation_timestep ();
85 DECLARE_TRANSLATOR_LISTENER (note);
89 Completion_heads_engraver::initialize ()
94 IMPLEMENT_TRANSLATOR_LISTENER (Completion_heads_engraver, note);
96 Completion_heads_engraver::listen_note (Stream_event *ev)
98 note_events_.push_back (ev);
101 Moment now = now_mom ();
102 Moment musiclen = get_event_length (ev, now);
104 note_end_mom_ = max (note_end_mom_, (now + musiclen));
105 do_nothing_until_ = Rational (0, 0);
109 The duration _until_ the next bar line or completion unit
112 Completion_heads_engraver::next_moment (Rational const ¬e_len)
114 Moment *e = unsmob<Moment> (get_property ("measurePosition"));
115 Moment *l = unsmob<Moment> (get_property ("measureLength"));
116 if (!e || !l || !to_boolean (get_property ("timing")))
118 return Moment (0, 0);
121 Moment result = *l - *e;
124 programming_error ("invalid measure position: "
125 + e->to_string () + " of " + l->to_string ());
128 Moment const *unit = unsmob<Moment> (get_property ("completionUnit"));
132 Rational const now_unit = e->main_part_ / unit->main_part_;
133 if (now_unit.den () > 1)
136 within a unit - go to the end of that
138 result = unit->main_part_
139 * (Rational (1) - (now_unit - now_unit.trunc_rat ()));
144 at the beginning of a unit:
145 take a power-of-two number of units, but not more than required,
146 since then the Duration constructor destroys the unit structure
148 if (note_len < result.main_part_)
149 result.main_part_ = note_len;
150 Rational const step_unit = result.main_part_ / unit->main_part_;
151 if (step_unit.den () < step_unit.num ())
154 = intlog2 (int (step_unit.num () / step_unit.den ()));
155 result.main_part_ = unit->main_part_ * Rational (1 << log2);
164 Completion_heads_engraver::make_note_head (Stream_event *ev)
166 Item *note = make_item ("NoteHead", ev->self_scm ());
167 Pitch *pit = unsmob<Pitch> (ev->get_property ("pitch"));
169 int pos = pit->steps ();
170 SCM c0 = get_property ("middleCPosition");
171 if (scm_is_number (c0))
172 pos += scm_to_int (c0);
174 note->set_property ("staff-position", scm_from_int (pos));
180 Completion_heads_engraver::process_music ()
182 if (!is_first_ && !left_to_do_)
187 Moment now = now_mom ();
188 if (do_nothing_until_ > now.main_part_)
196 note that note_dur may be strictly less than left_to_do_
197 (say, if left_to_do_ == 5/8)
199 note_dur = Duration (left_to_do_ / factor_, false).compressed (factor_);
203 orig = unsmob<Duration> (note_events_[0]->get_property ("duration"));
205 SCM factor = get_property ("completionFactor");
206 if (ly_is_procedure (factor))
207 factor = scm_call_2 (factor,
208 context ()->self_scm (),
209 note_dur.smobbed_copy ());
210 factor_ = robust_scm2rational (factor, note_dur.factor ());
211 left_to_do_ = orig->get_length ();
213 Moment nb = next_moment (note_dur.get_length ());
214 if (nb.main_part_ && nb < note_dur.get_length ())
216 note_dur = Duration (nb.main_part_ / factor_, false).compressed (factor_);
219 do_nothing_until_ = now.main_part_ + note_dur.get_length ();
221 for (vsize i = 0; left_to_do_ && i < note_events_.size (); i++)
223 bool need_clone = !orig || *orig != note_dur;
224 Stream_event *event = note_events_[i];
227 event = event->clone ();
229 SCM pits = note_events_[i]->get_property ("pitch");
230 event->set_property ("pitch", pits);
231 event->set_property ("duration", note_dur.smobbed_copy ());
232 event->set_property ("length", Moment (note_dur.get_length ()).smobbed_copy ());
233 event->set_property ("duration-log", scm_from_int (note_dur.duration_log ()));
236 The Completion_heads_engraver splits an event into a group of consecutive events.
237 For each event in the group, the property "autosplit-end" denotes whether the current event
238 was truncated during splitting. Based on "autosplit-end", the Tie_engraver decides whether a
239 tie event should be processed.
241 event->set_property ("autosplit-end",
242 ly_bool2scm (left_to_do_ - note_dur.get_length () > Rational (0)));
244 Item *note = make_note_head (event);
247 notes_.push_back (note);
250 if (prev_notes_.size () == notes_.size ())
252 for (vsize i = 0; i < notes_.size (); i++)
253 make_tie (prev_notes_[i], notes_[i]);
256 if (ties_.size () && !tie_column_)
257 tie_column_ = make_spanner ("TieColumn", ties_[0]->self_scm ());
260 for (vsize i = ties_.size (); i--;)
261 Tie_column::add_tie (tie_column_, ties_[i]);
263 left_to_do_ -= note_dur.get_length ();
265 get_global_context ()->add_moment_to_process (now.main_part_ + note_dur.get_length ());
267 don't do complicated arithmetic with grace notes.
269 if (orig && now_mom ().grace_part_)
270 left_to_do_ = Rational (0, 0);
274 Completion_heads_engraver::make_tie (Grob *left, Grob *right)
276 Spanner *p = make_spanner ("Tie", SCM_EOL);
277 Tie::set_head (p, LEFT, left);
278 Tie::set_head (p, RIGHT, right);
279 announce_end_grob (p, SCM_EOL);
284 Completion_heads_engraver::stop_translation_timestep ()
290 prev_notes_ = notes_;
295 Completion_heads_engraver::start_translation_timestep ()
297 Moment now = now_mom ();
298 if (note_end_mom_.main_part_ <= now.main_part_)
300 note_events_.clear ();
301 prev_notes_.clear ();
303 context ()->set_property ("completionBusy",
304 ly_bool2scm (note_events_.size ()));
307 Completion_heads_engraver::Completion_heads_engraver ()
312 ADD_TRANSLATOR (Completion_heads_engraver,
314 "This engraver replaces @code{Note_heads_engraver}. It plays"
315 " some trickery to break long notes and automatically tie them"
316 " into the next measure.",