2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 1997--2011 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"
40 #include "translator.icc"
45 When we catch the rest, we predict the end of the rest. We keep the
46 events living until we reach the predicted end-time.
48 Every time process_music () is called and there are rest events, we
49 figure out how long the rest to typeset should be. It should be no
50 longer than what's specified, than what is left to do and it should
53 We copy the events into scratch rest events, to make sure that we get
54 all durations exactly right.
57 class Completion_rest_engraver : public Engraver
60 vector<Item*> prev_rests_;
61 vector<Stream_event*> rest_events_;
65 Rational do_nothing_until_;
68 Moment next_barline_moment ();
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.
106 Completion_rest_engraver::next_barline_moment ()
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);
119 Completion_rest_engraver::make_rest (Stream_event *ev)
121 Item *rest = make_item ("Rest", ev->self_scm ());
122 if (Pitch *p = unsmob_pitch (ev->get_property ("pitch")))
124 int pos = p->steps ();
125 SCM c0 = get_property ("middleCPosition");
126 if (scm_is_number (c0))
127 pos += scm_to_int (c0);
128 rest->set_property ("staff-position", scm_from_int (pos));
135 Completion_rest_engraver::process_music ()
137 if (!is_first_ && !left_to_do_)
142 Moment now = now_mom ();
143 if (do_nothing_until_ > now.main_part_)
152 rest that rest_dur may be strictly less than left_to_do_
153 (say, if left_to_do_ == 5/8)
155 if (factor_.denominator () == 1 && factor_ > Rational (1, 1))
156 rest_dur = Duration (left_to_do_, false);
158 rest_dur = Duration (left_to_do_ / factor_, false).compressed (factor_);
159 appearance = Duration (left_to_do_, false);
163 orig = unsmob_duration (rest_events_[0]->get_property ("duration"));
165 factor_ = rest_dur.factor ();
166 left_to_do_ = orig->get_length ();
168 Moment nb = next_barline_moment ();
169 if (nb.main_part_ && nb < rest_dur.get_length ())
171 if (factor_.denominator () == 1 && factor_ > Rational (1, 1))
172 rest_dur = Duration (nb.main_part_, false);
174 rest_dur = Duration (nb.main_part_ / factor_, false).compressed (factor_);
177 do_nothing_until_ = now.main_part_ + rest_dur.get_length ();
179 for (vsize i = 0; left_to_do_ && i < rest_events_.size (); i++)
181 bool need_clone = !orig || *orig != rest_dur;
182 Stream_event *event = rest_events_[i];
185 event = event->clone ();
187 SCM pits = rest_events_[i]->get_property ("pitch");
188 event->set_property ("pitch", pits);
189 event->set_property ("duration", rest_dur.smobbed_copy ());
190 event->set_property ("length", Moment (rest_dur.get_length ()).smobbed_copy ());
191 event->set_property ("duration-log", scm_from_int (rest_dur.duration_log ()));
193 Item *rest = make_rest (event);
196 rests_.push_back (rest);
199 left_to_do_ -= rest_dur.get_length ();
201 get_global_context ()->add_moment_to_process (now.main_part_ + rest_dur.get_length());
203 don't do complicated arithmetic with grace rests.
205 if (orig && now_mom ().grace_part_)
206 left_to_do_ = Rational (0, 0);
210 Completion_rest_engraver::stop_translation_timestep ()
213 prev_rests_ = rests_;
218 Completion_rest_engraver::start_translation_timestep ()
220 Moment now = now_mom ();
221 if (rest_end_mom_.main_part_ <= now.main_part_)
223 rest_events_.clear ();
224 prev_rests_.clear ();
226 context ()->set_property ("restCompletionBusy",
227 ly_bool2scm (rest_events_.size ()));
230 Completion_rest_engraver::Completion_rest_engraver ()
234 ADD_TRANSLATOR (Completion_rest_engraver,
236 "This engraver replaces @code{Rest_engraver}. It plays"
237 " some trickery to break long rests into the next measure."
248 "restCompletionBusy "