2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 1997--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/>.
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<Item *> tie_note_candidates_;
63 vector<Stream_event *> tie_note_candidate_events_;
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;
122 Moment const *unit = unsmob_moment (get_property ("completionUnit"));
126 Rational const now_unit = e->main_part_ / unit->main_part_;
127 if (now_unit.den() > 1)
130 within a unit - go to the end of that
132 result = unit->main_part_
133 * (Rational (1) - (now_unit - now_unit.trunc_rat ()));
138 at the beginning of a unit:
139 take a power-of-two number of units, but not more than required,
140 since then the Duration constructor destroys the unit structure
142 if (note_len < result.main_part_)
143 result.main_part_ = note_len;
144 Rational const step_unit = result.main_part_ / unit->main_part_;
145 if (step_unit.den () < step_unit.num ())
148 = intlog2 (int (step_unit.num () / step_unit.den ()));
149 result.main_part_ = unit->main_part_ * Rational (1 << log2);
158 Completion_heads_engraver::make_note_head (Stream_event *ev)
160 Item *note = make_item ("NoteHead", ev->self_scm ());
161 Pitch *pit = unsmob_pitch (ev->get_property ("pitch"));
163 int pos = pit->steps ();
164 SCM c0 = get_property ("middleCPosition");
165 if (scm_is_number (c0))
166 pos += scm_to_int (c0);
168 note->set_property ("staff-position", scm_from_int (pos));
174 Completion_heads_engraver::process_music ()
176 if (!is_first_ && !left_to_do_)
181 Moment now = now_mom ();
182 if (do_nothing_until_ > now.main_part_)
190 note that note_dur may be strictly less than left_to_do_
191 (say, if left_to_do_ == 5/8)
193 if (factor_.denominator () == 1 && factor_ > Rational (1, 1))
194 note_dur = Duration (left_to_do_, false);
196 note_dur = Duration (left_to_do_ / factor_, false).compressed (factor_);
200 orig = unsmob_duration (note_events_[0]->get_property ("duration"));
202 factor_ = note_dur.factor ();
203 left_to_do_ = orig->get_length ();
205 Moment nb = next_moment (note_dur.get_length ());
206 if (nb.main_part_ && nb < note_dur.get_length ())
208 if (factor_.denominator () == 1 && factor_.numerator () > 1)
209 note_dur = Duration (nb.main_part_, false);
211 note_dur = Duration (nb.main_part_ / factor_, false).compressed (factor_);
214 do_nothing_until_ = now.main_part_ + note_dur.get_length ();
216 for (vsize i = 0; left_to_do_ && i < note_events_.size (); i++)
218 bool need_clone = !orig || *orig != note_dur;
219 Stream_event *event = note_events_[i];
222 event = event->clone ();
224 SCM pits = note_events_[i]->get_property ("pitch");
225 event->set_property ("pitch", pits);
226 event->set_property ("duration", note_dur.smobbed_copy ());
227 event->set_property ("length", Moment (note_dur.get_length ()).smobbed_copy ());
228 event->set_property ("duration-log", scm_from_int (note_dur.duration_log ()));
231 The Completion_heads_engraver splits an event into a group of consecutive events.
232 For each event in the group, the property "autosplit-end" denotes whether the current event
233 was truncated during splitting. Based on "autosplit-end", the Tie_engraver decides whether a
234 tie event should be processed.
236 event->set_property ("autosplit-end",
237 ly_bool2scm (left_to_do_ - note_dur.get_length () > Rational (0)));
239 Item *note = make_note_head (event);
242 notes_.push_back (note);
245 if (prev_notes_.size () == notes_.size ())
247 for (vsize i = 0; i < notes_.size (); i++)
248 make_tie (prev_notes_[i], notes_[i]);
251 if (ties_.size () && !tie_column_)
252 tie_column_ = make_spanner ("TieColumn", ties_[0]->self_scm ());
255 for (vsize i = ties_.size (); i--;)
256 Tie_column::add_tie (tie_column_, ties_[i]);
258 left_to_do_ -= note_dur.get_length ();
260 get_global_context ()->add_moment_to_process (now.main_part_ + note_dur.get_length ());
262 don't do complicated arithmetic with grace notes.
264 if (orig && now_mom ().grace_part_)
265 left_to_do_ = Rational (0, 0);
269 Completion_heads_engraver::make_tie (Grob *left, Grob *right)
271 Grob *p = make_spanner ("Tie", SCM_EOL);
272 Tie::set_head (p, LEFT, left);
273 Tie::set_head (p, RIGHT, right);
278 Completion_heads_engraver::stop_translation_timestep ()
284 prev_notes_ = notes_;
289 Completion_heads_engraver::start_translation_timestep ()
291 Moment now = now_mom ();
292 if (note_end_mom_.main_part_ <= now.main_part_)
294 tie_note_candidate_events_ = note_events_;
295 tie_note_candidates_ = prev_notes_;
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 ()
309 ADD_TRANSLATOR (Completion_heads_engraver,
311 "This engraver replaces @code{Note_heads_engraver}. It plays"
312 " some trickery to break long notes and automatically tie them"
313 " into the next measure.",