2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 1997--2015 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 void listen_rest (Stream_event *);
83 Completion_rest_engraver::initialize ()
89 Completion_rest_engraver::listen_rest (Stream_event *ev)
91 rest_events_.push_back (ev);
94 Moment now = now_mom ();
95 Moment musiclen = get_event_length (ev, now);
97 rest_end_mom_ = max (rest_end_mom_, (now + musiclen));
98 do_nothing_until_ = Rational (0, 0);
102 The duration _until_ the next barline or completion unit
105 Completion_rest_engraver::next_moment (Rational const ¬e_len)
107 Moment *e = unsmob<Moment> (get_property ("measurePosition"));
108 Moment *l = unsmob<Moment> (get_property ("measureLength"));
109 if (!e || !l || !to_boolean (get_property ("timing")))
111 return Moment (0, 0);
114 Moment result = *l - *e;
115 Moment const *unit = unsmob<Moment> (get_property ("completionUnit"));
119 Rational const now_unit = e->main_part_ / unit->main_part_;
120 if (now_unit.den () > 1)
123 within a unit - go to the end of that
125 result = unit->main_part_
126 * (Rational (1) - (now_unit - now_unit.trunc_rat ()));
131 at the beginning of a unit:
132 take a power-of-two number of units, but not more than required,
133 since then the Duration constructor destroys the unit structure
135 if (note_len < result.main_part_)
136 result.main_part_ = note_len;
137 Rational const step_unit = result.main_part_ / unit->main_part_;
138 if (step_unit.den () < step_unit.num ())
141 = intlog2 (int (step_unit.num () / step_unit.den ()));
142 result.main_part_ = unit->main_part_ * Rational (1 << log2);
151 Completion_rest_engraver::make_rest (Stream_event *ev)
153 Item *rest = make_item ("Rest", ev->self_scm ());
154 if (Pitch *p = unsmob<Pitch> (ev->get_property ("pitch")))
156 int pos = p->steps ();
157 SCM c0 = get_property ("middleCPosition");
158 if (scm_is_number (c0))
159 pos += scm_to_int (c0);
160 rest->set_property ("staff-position", scm_from_int (pos));
167 Completion_rest_engraver::process_music ()
169 if (!is_first_ && !left_to_do_)
174 Moment now = now_mom ();
175 if (do_nothing_until_ > now.main_part_)
183 note that rest_dur may be strictly less than left_to_do_
184 (say, if left_to_do_ == 5/8)
186 rest_dur = Duration (left_to_do_ / factor_, false).compressed (factor_);
190 orig = unsmob<Duration> (rest_events_[0]->get_property ("duration"));
192 SCM factor = get_property ("completionFactor");
193 if (ly_is_procedure (factor))
194 factor = scm_call_2 (factor,
195 context ()->self_scm (),
196 rest_dur.smobbed_copy ());
197 factor_ = robust_scm2rational (factor, rest_dur.factor());
198 left_to_do_ = orig->get_length ();
200 Moment nb = next_moment (rest_dur.get_length ());
201 if (nb.main_part_ && nb < rest_dur.get_length ())
203 rest_dur = Duration (nb.main_part_ / factor_, false).compressed (factor_);
206 do_nothing_until_ = now.main_part_ + rest_dur.get_length ();
208 for (vsize i = 0; left_to_do_ && i < rest_events_.size (); i++)
210 bool need_clone = !orig || *orig != rest_dur;
211 Stream_event *event = rest_events_[i];
214 event = event->clone ();
216 SCM pits = rest_events_[i]->get_property ("pitch");
217 event->set_property ("pitch", pits);
218 event->set_property ("duration", rest_dur.smobbed_copy ());
219 event->set_property ("length", Moment (rest_dur.get_length ()).smobbed_copy ());
220 event->set_property ("duration-log", scm_from_int (rest_dur.duration_log ()));
222 Item *rest = make_rest (event);
225 rests_.push_back (rest);
228 left_to_do_ -= rest_dur.get_length ();
230 get_global_context ()->add_moment_to_process (now.main_part_ + rest_dur.get_length ());
232 don't do complicated arithmetic with grace rests.
234 if (orig && now_mom ().grace_part_)
235 left_to_do_ = Rational (0, 0);
239 Completion_rest_engraver::stop_translation_timestep ()
245 Completion_rest_engraver::start_translation_timestep ()
247 Moment now = now_mom ();
248 if (rest_end_mom_.main_part_ <= now.main_part_)
250 rest_events_.clear ();
252 context ()->set_property ("restCompletionBusy",
253 ly_bool2scm (rest_events_.size ()));
256 Completion_rest_engraver::Completion_rest_engraver ()
261 Completion_rest_engraver::boot ()
263 ADD_LISTENER (Completion_rest_engraver, rest);
266 ADD_TRANSLATOR (Completion_rest_engraver,
268 "This engraver replaces @code{Rest_engraver}. It plays"
269 " some trickery to break long rests into the next measure.",
282 "restCompletionBusy "