Fixes Issue 1504, allowing feather beam line breaking.
[lilypond/patrick.git] / lily / completion-rest-engraver.cc
blob3d8d7211ff97393e5978370bb126c43dd3449a0e
1 /*
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/>.
21 #include <cctype>
22 using namespace std;
24 #include "dot-column.hh"
25 #include "dots.hh"
26 #include "duration.hh"
27 #include "global-context.hh"
28 #include "item.hh"
29 #include "output-def.hh"
30 #include "pitch.hh"
31 #include "pqueue.hh"
32 #include "rhythmic-head.hh"
33 #include "score-engraver.hh"
34 #include "spanner.hh"
35 #include "staff-symbol-referencer.hh"
36 #include "stream-event.hh"
37 #include "tie.hh"
38 #include "warn.hh"
40 #include "translator.icc"
43 How does this work?
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
51 not cross barlines.
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
59 vector<Item*> rests_;
60 vector<Item*> prev_rests_;
61 vector<Stream_event*> rest_events_;
62 Moment rest_end_mom_;
63 bool is_first_;
64 Rational left_to_do_;
65 Rational do_nothing_until_;
66 Rational factor_;
68 Moment next_barline_moment ();
69 Item *make_rest (Stream_event*);
71 public:
72 TRANSLATOR_DECLARATIONS (Completion_rest_engraver);
74 protected:
75 virtual void initialize ();
76 void start_translation_timestep ();
77 void process_music ();
78 void stop_translation_timestep ();
79 DECLARE_TRANSLATOR_LISTENER (rest);
82 void
83 Completion_rest_engraver::initialize ()
85 is_first_ = false;
88 IMPLEMENT_TRANSLATOR_LISTENER (Completion_rest_engraver, rest);
89 void
90 Completion_rest_engraver::listen_rest (Stream_event *ev)
92 rest_events_.push_back (ev);
94 is_first_ = true;
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.
105 Moment
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);
115 return (*l - *e);
118 Item*
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));
131 return rest;
134 void
135 Completion_rest_engraver::process_music ()
137 if (!is_first_ && !left_to_do_)
138 return;
140 is_first_ = false;
142 Moment now = now_mom ();
143 if (do_nothing_until_ > now.main_part_)
144 return;
146 Duration rest_dur;
147 Duration appearance;
148 Duration *orig = 0;
149 if (left_to_do_)
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);
157 else
158 rest_dur = Duration (left_to_do_ / factor_, false).compressed (factor_);
159 appearance = Duration (left_to_do_, false);
161 else
163 orig = unsmob_duration (rest_events_[0]->get_property ("duration"));
164 rest_dur = *orig;
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);
173 else
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];
184 if (need_clone)
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);
194 if (need_clone)
195 event->unprotect ();
196 rests_.push_back (rest);
199 left_to_do_ -= rest_dur.get_length ();
200 if (left_to_do_)
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);
209 void
210 Completion_rest_engraver::stop_translation_timestep ()
212 if (rests_.size ())
213 prev_rests_ = rests_;
214 rests_.clear ();
217 void
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,
235 /* doc */
236 "This engraver replaces @code{Rest_engraver}. It plays"
237 " some trickery to break long rests into the next measure."
239 /* create */
240 "Rest "
242 /* read */
243 "middleCPosition "
244 "measurePosition "
245 "measureLength "
247 /* write */
248 "restCompletionBusy "