2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 1997--2014 Han-Wen Nienhuys <hanwen@xs4all.nl>
5 Jan Nieuwenhuizen <janneke@gnu.org>
7 LilyPond is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 LilyPond is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
24 #include "dot-column.hh"
26 #include "duration.hh"
27 #include "global-context.hh"
29 #include "output-def.hh"
32 #include "rhythmic-head.hh"
33 #include "score-engraver.hh"
35 #include "staff-symbol-referencer.hh"
36 #include "stream-event.hh"
41 #include "translator.icc"
46 When we catch the rest, we predict the end of the rest. We keep the
47 events living until we reach the predicted end-time.
49 Every time process_music () is called and there are rest events, we
50 figure out how long the rest to typeset should be. It should be no
51 longer than what's specified, than what is left to do and it should
52 not cross barlines or sub-bar units.
54 We copy the events into scratch rest events, to make sure that we get
55 all durations exactly right.
58 class Completion_rest_engraver : public Engraver
60 vector<Item *> rests_;
61 vector<Stream_event *> rest_events_;
65 Rational do_nothing_until_;
68 Moment next_moment (Rational const &);
69 Item *make_rest (Stream_event *);
72 TRANSLATOR_DECLARATIONS (Completion_rest_engraver);
75 virtual void initialize ();
76 void start_translation_timestep ();
77 void process_music ();
78 void stop_translation_timestep ();
79 DECLARE_TRANSLATOR_LISTENER (rest);
83 Completion_rest_engraver::initialize ()
88 IMPLEMENT_TRANSLATOR_LISTENER (Completion_rest_engraver, rest);
90 Completion_rest_engraver::listen_rest (Stream_event *ev)
92 rest_events_.push_back (ev);
95 Moment now = now_mom ();
96 Moment musiclen = get_event_length (ev, now);
98 rest_end_mom_ = max (rest_end_mom_, (now + musiclen));
99 do_nothing_until_ = Rational (0, 0);
103 The duration _until_ the next barline or completion unit
106 Completion_rest_engraver::next_moment (Rational const ¬e_len)
108 Moment *e = unsmob_moment (get_property ("measurePosition"));
109 Moment *l = unsmob_moment (get_property ("measureLength"));
110 if (!e || !l || !to_boolean (get_property ("timing")))
112 return Moment (0, 0);
115 Moment result = *l - *e;
116 Moment const *unit = unsmob_moment (get_property ("completionUnit"));
120 Rational const now_unit = e->main_part_ / unit->main_part_;
121 if (now_unit.den () > 1)
124 within a unit - go to the end of that
126 result = unit->main_part_
127 * (Rational (1) - (now_unit - now_unit.trunc_rat ()));
132 at the beginning of a unit:
133 take a power-of-two number of units, but not more than required,
134 since then the Duration constructor destroys the unit structure
136 if (note_len < result.main_part_)
137 result.main_part_ = note_len;
138 Rational const step_unit = result.main_part_ / unit->main_part_;
139 if (step_unit.den () < step_unit.num ())
142 = intlog2 (int (step_unit.num () / step_unit.den ()));
143 result.main_part_ = unit->main_part_ * Rational (1 << log2);
152 Completion_rest_engraver::make_rest (Stream_event *ev)
154 Item *rest = make_item ("Rest", ev->self_scm ());
155 if (Pitch *p = unsmob_pitch (ev->get_property ("pitch")))
157 int pos = p->steps ();
158 SCM c0 = get_property ("middleCPosition");
159 if (scm_is_number (c0))
160 pos += scm_to_int (c0);
161 rest->set_property ("staff-position", scm_from_int (pos));
168 Completion_rest_engraver::process_music ()
170 if (!is_first_ && !left_to_do_)
175 Moment now = now_mom ();
176 if (do_nothing_until_ > now.main_part_)
184 note that rest_dur may be strictly less than left_to_do_
185 (say, if left_to_do_ == 5/8)
187 rest_dur = Duration (left_to_do_ / factor_, false).compressed (factor_);
191 orig = unsmob_duration (rest_events_[0]->get_property ("duration"));
193 SCM factor = get_property ("completionFactor");
194 if (ly_is_procedure (factor))
195 factor = scm_call_2 (factor,
196 context ()->self_scm (),
197 rest_dur.smobbed_copy ());
198 factor_ = robust_scm2rational (factor, rest_dur.factor());
199 left_to_do_ = orig->get_length ();
201 Moment nb = next_moment (rest_dur.get_length ());
202 if (nb.main_part_ && nb < rest_dur.get_length ())
204 rest_dur = Duration (nb.main_part_ / factor_, false).compressed (factor_);
207 do_nothing_until_ = now.main_part_ + rest_dur.get_length ();
209 for (vsize i = 0; left_to_do_ && i < rest_events_.size (); i++)
211 bool need_clone = !orig || *orig != rest_dur;
212 Stream_event *event = rest_events_[i];
215 event = event->clone ();
217 SCM pits = rest_events_[i]->get_property ("pitch");
218 event->set_property ("pitch", pits);
219 event->set_property ("duration", rest_dur.smobbed_copy ());
220 event->set_property ("length", Moment (rest_dur.get_length ()).smobbed_copy ());
221 event->set_property ("duration-log", scm_from_int (rest_dur.duration_log ()));
223 Item *rest = make_rest (event);
226 rests_.push_back (rest);
229 left_to_do_ -= rest_dur.get_length ();
231 get_global_context ()->add_moment_to_process (now.main_part_ + rest_dur.get_length ());
233 don't do complicated arithmetic with grace rests.
235 if (orig && now_mom ().grace_part_)
236 left_to_do_ = Rational (0, 0);
240 Completion_rest_engraver::stop_translation_timestep ()
246 Completion_rest_engraver::start_translation_timestep ()
248 Moment now = now_mom ();
249 if (rest_end_mom_.main_part_ <= now.main_part_)
251 rest_events_.clear ();
253 context ()->set_property ("restCompletionBusy",
254 ly_bool2scm (rest_events_.size ()));
257 Completion_rest_engraver::Completion_rest_engraver ()
261 ADD_TRANSLATOR (Completion_rest_engraver,
263 "This engraver replaces @code{Rest_engraver}. It plays"
264 " some trickery to break long rests into the next measure.",
277 "restCompletionBusy "