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"
45 When we catch the note, we predict the end of the note. We keep the
46 events living until we reach the predicted end-time.
48 Every time process_music () is called and there are note events, we
49 figure out how long the note to typeset should be. It should be no
50 longer than what's specified, than what is left to do and it should
51 not cross barlines or sub-bar units.
53 We copy the events into scratch note events, to make sure that we get
54 all durations exactly right.
57 class Completion_heads_engraver : public Engraver
59 vector<Item *> notes_;
60 vector<Item *> prev_notes_;
61 // Must remember notes for explicit ties.
62 vector<Spanner *> ties_;
63 vector<Stream_event *> note_events_;
68 Rational do_nothing_until_;
71 Moment next_moment (Rational const &);
72 Item *make_note_head (Stream_event *);
75 TRANSLATOR_DECLARATIONS (Completion_heads_engraver);
78 virtual void initialize ();
79 void make_tie (Grob *, Grob *);
80 void start_translation_timestep ();
81 void process_music ();
82 void stop_translation_timestep ();
83 void listen_note (Stream_event *);
87 Completion_heads_engraver::initialize ()
93 Completion_heads_engraver::listen_note (Stream_event *ev)
95 note_events_.push_back (ev);
98 Moment now = now_mom ();
99 Moment musiclen = get_event_length (ev, now);
101 note_end_mom_ = max (note_end_mom_, (now + musiclen));
102 do_nothing_until_ = Rational (0, 0);
106 The duration _until_ the next bar line or completion unit
109 Completion_heads_engraver::next_moment (Rational const ¬e_len)
111 Moment *e = unsmob<Moment> (get_property ("measurePosition"));
112 Moment *l = unsmob<Moment> (get_property ("measureLength"));
113 if (!e || !l || !to_boolean (get_property ("timing")))
115 return Moment (0, 0);
118 Moment result = *l - *e;
121 programming_error ("invalid measure position: "
122 + e->to_string () + " of " + l->to_string ());
125 Moment const *unit = unsmob<Moment> (get_property ("completionUnit"));
129 Rational const now_unit = e->main_part_ / unit->main_part_;
130 if (now_unit.den () > 1)
133 within a unit - go to the end of that
135 result = unit->main_part_
136 * (Rational (1) - (now_unit - now_unit.trunc_rat ()));
141 at the beginning of a unit:
142 take a power-of-two number of units, but not more than required,
143 since then the Duration constructor destroys the unit structure
145 if (note_len < result.main_part_)
146 result.main_part_ = note_len;
147 Rational const step_unit = result.main_part_ / unit->main_part_;
148 if (step_unit.den () < step_unit.num ())
151 = intlog2 (int (step_unit.num () / step_unit.den ()));
152 result.main_part_ = unit->main_part_ * Rational (1 << log2);
161 Completion_heads_engraver::make_note_head (Stream_event *ev)
163 Item *note = make_item ("NoteHead", ev->self_scm ());
164 Pitch *pit = unsmob<Pitch> (ev->get_property ("pitch"));
166 int pos = pit ? pit->steps () : 0;
167 SCM c0 = get_property ("middleCPosition");
168 if (scm_is_number (c0))
169 pos += scm_to_int (c0);
171 note->set_property ("staff-position", scm_from_int (pos));
177 Completion_heads_engraver::process_music ()
179 if (!is_first_ && !left_to_do_)
184 Moment now = now_mom ();
185 if (do_nothing_until_ > now.main_part_)
193 note that note_dur may be strictly less than left_to_do_
194 (say, if left_to_do_ == 5/8)
196 note_dur = Duration (left_to_do_ / factor_, false).compressed (factor_);
200 orig = unsmob<Duration> (note_events_[0]->get_property ("duration"));
202 SCM factor = get_property ("completionFactor");
203 if (ly_is_procedure (factor))
204 factor = scm_call_2 (factor,
205 context ()->self_scm (),
206 note_dur.smobbed_copy ());
207 factor_ = robust_scm2rational (factor, note_dur.factor ());
208 left_to_do_ = orig->get_length ();
210 Moment nb = next_moment (note_dur.get_length ());
211 if (nb.main_part_ && nb < note_dur.get_length ())
213 note_dur = Duration (nb.main_part_ / factor_, false).compressed (factor_);
216 do_nothing_until_ = now.main_part_ + note_dur.get_length ();
218 for (vsize i = 0; left_to_do_ && i < note_events_.size (); i++)
220 bool need_clone = !orig || *orig != note_dur;
221 Stream_event *event = note_events_[i];
224 event = event->clone ();
226 SCM pits = note_events_[i]->get_property ("pitch");
227 event->set_property ("pitch", pits);
228 event->set_property ("duration", note_dur.smobbed_copy ());
229 event->set_property ("length", Moment (note_dur.get_length ()).smobbed_copy ());
230 event->set_property ("duration-log", scm_from_int (note_dur.duration_log ()));
233 The Completion_heads_engraver splits an event into a group of consecutive events.
234 For each event in the group, the property "autosplit-end" denotes whether the current event
235 was truncated during splitting. Based on "autosplit-end", the Tie_engraver decides whether a
236 tie event should be processed.
238 event->set_property ("autosplit-end",
239 ly_bool2scm (left_to_do_ - note_dur.get_length () > Rational (0)));
241 Item *note = make_note_head (event);
244 notes_.push_back (note);
247 if (prev_notes_.size () == notes_.size ())
249 for (vsize i = 0; i < notes_.size (); i++)
250 make_tie (prev_notes_[i], notes_[i]);
253 if (ties_.size () && !tie_column_)
254 tie_column_ = make_spanner ("TieColumn", ties_[0]->self_scm ());
257 for (vsize i = ties_.size (); i--;)
258 Tie_column::add_tie (tie_column_, ties_[i]);
260 left_to_do_ -= note_dur.get_length ();
262 get_global_context ()->add_moment_to_process (now.main_part_ + note_dur.get_length ());
264 don't do complicated arithmetic with grace notes.
266 if (orig && now_mom ().grace_part_)
267 left_to_do_ = Rational (0, 0);
271 Completion_heads_engraver::make_tie (Grob *left, Grob *right)
273 Spanner *p = make_spanner ("Tie", SCM_EOL);
274 Tie::set_head (p, LEFT, left);
275 Tie::set_head (p, RIGHT, right);
276 announce_end_grob (p, SCM_EOL);
281 Completion_heads_engraver::stop_translation_timestep ()
287 prev_notes_ = notes_;
292 Completion_heads_engraver::start_translation_timestep ()
294 Moment now = now_mom ();
295 if (note_end_mom_.main_part_ <= now.main_part_)
297 note_events_.clear ();
298 prev_notes_.clear ();
300 context ()->set_property ("completionBusy",
301 ly_bool2scm (note_events_.size ()));
304 Completion_heads_engraver::Completion_heads_engraver (Context *c)
311 Completion_heads_engraver::boot ()
313 ADD_LISTENER (Completion_heads_engraver, note);
316 ADD_TRANSLATOR (Completion_heads_engraver,
318 "This engraver replaces @code{Note_heads_engraver}. It plays"
319 " some trickery to break long notes and automatically tie them"
320 " into the next measure.",