]> git.donarmstrong.com Git - lilypond.git/blob - lily/completion-rest-engraver.cc
cleanup
[lilypond.git] / lily / completion-rest-engraver.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1997--2012 Han-Wen Nienhuys <hanwen@xs4all.nl>
5                            Jan Nieuwenhuizen <janneke@gnu.org>
6
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.
11
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.
16
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/>.
19 */
20
21 #include <cctype>
22 using namespace std;
23
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"
39 #include "misc.hh"
40
41 #include "translator.icc"
42
43 /*
44   How does this work?
45
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.
48
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.
53
54   We copy the events into scratch rest events, to make sure that we get
55   all durations exactly right.
56 */
57
58 class Completion_rest_engraver : public Engraver
59 {
60   vector<Item *> rests_;
61   vector<Item *> prev_rests_;
62   vector<Stream_event *> rest_events_;
63   Moment rest_end_mom_;
64   bool is_first_;
65   Rational left_to_do_;
66   Rational do_nothing_until_;
67   Rational factor_;
68
69   Moment next_moment (Rational const &);
70   Item *make_rest (Stream_event *);
71
72 public:
73   TRANSLATOR_DECLARATIONS (Completion_rest_engraver);
74
75 protected:
76   virtual void initialize ();
77   void start_translation_timestep ();
78   void process_music ();
79   void stop_translation_timestep ();
80   DECLARE_TRANSLATOR_LISTENER (rest);
81 };
82
83 void
84 Completion_rest_engraver::initialize ()
85 {
86   is_first_ = false;
87 }
88
89 IMPLEMENT_TRANSLATOR_LISTENER (Completion_rest_engraver, rest);
90 void
91 Completion_rest_engraver::listen_rest (Stream_event *ev)
92 {
93   rest_events_.push_back (ev);
94
95   is_first_ = true;
96   Moment now = now_mom ();
97   Moment musiclen = get_event_length (ev, now);
98
99   rest_end_mom_ = max (rest_end_mom_, (now + musiclen));
100   do_nothing_until_ = Rational (0, 0);
101 }
102
103 /*
104   The duration _until_ the next barline or completion unit
105 */
106 Moment
107 Completion_rest_engraver::next_moment (Rational const &note_len)
108 {
109   Moment *e = unsmob_moment (get_property ("measurePosition"));
110   Moment *l = unsmob_moment (get_property ("measureLength"));
111   if (!e || !l || !to_boolean (get_property ("timing")))
112     {
113       return Moment (0, 0);
114     }
115
116   Moment result = *l - *e;
117   Moment const *unit = unsmob_moment (get_property ("completionUnit"));
118
119   if (unit)
120     {
121       Rational const now_unit = e->main_part_ / unit->main_part_;
122       if (now_unit.den () > 1)
123         {
124           /*
125             within a unit - go to the end of that
126           */
127           result = unit->main_part_
128             * (Rational (1) - (now_unit - now_unit.trunc_rat ()));
129         }
130       else
131         {
132           /*
133             at the beginning of a unit:
134             take a power-of-two number of units, but not more than required,
135             since then the Duration constructor destroys the unit structure
136           */
137           if (note_len < result.main_part_)
138             result.main_part_ = note_len;
139           Rational const step_unit = result.main_part_ / unit->main_part_;
140           if (step_unit.den () < step_unit.num ())
141             {
142               int const log2
143                 = intlog2 (int (step_unit.num () / step_unit.den ()));
144               result.main_part_ = unit->main_part_ * Rational (1 << log2);
145             }
146         }
147     }
148
149   return result;
150 }
151
152 Item *
153 Completion_rest_engraver::make_rest (Stream_event *ev)
154 {
155   Item *rest = make_item ("Rest", ev->self_scm ());
156   if (Pitch *p = unsmob_pitch (ev->get_property ("pitch")))
157     {
158       int pos = p->steps ();
159       SCM c0 = get_property ("middleCPosition");
160       if (scm_is_number (c0))
161         pos += scm_to_int (c0);
162       rest->set_property ("staff-position", scm_from_int (pos));
163     }
164
165   return rest;
166 }
167
168 void
169 Completion_rest_engraver::process_music ()
170 {
171   if (!is_first_ && !left_to_do_)
172     return;
173
174   is_first_ = false;
175
176   Moment now = now_mom ();
177   if (do_nothing_until_ > now.main_part_)
178     return;
179
180   Duration rest_dur;
181   Duration *orig = 0;
182   if (left_to_do_)
183     {
184       /*
185         note that rest_dur may be strictly less than left_to_do_
186         (say, if left_to_do_ == 5/8)
187       */
188       if (factor_.denominator () == 1 && factor_ > Rational (1, 1))
189         rest_dur = Duration (left_to_do_, false);
190       else
191         rest_dur = Duration (left_to_do_ / factor_, false).compressed (factor_);
192     }
193   else
194     {
195       orig = unsmob_duration (rest_events_[0]->get_property ("duration"));
196       rest_dur = *orig;
197       factor_ = rest_dur.factor ();
198       left_to_do_ = orig->get_length ();
199     }
200   Moment nb = next_moment (rest_dur.get_length ());
201   if (nb.main_part_ && nb < rest_dur.get_length ())
202     {
203       if (factor_.denominator () == 1 && factor_.numerator () > 1)
204         rest_dur = Duration (nb.main_part_, false);
205       else
206         rest_dur = Duration (nb.main_part_ / factor_, false).compressed (factor_);
207     }
208
209   do_nothing_until_ = now.main_part_ + rest_dur.get_length ();
210
211   for (vsize i = 0; left_to_do_ && i < rest_events_.size (); i++)
212     {
213       bool need_clone = !orig || *orig != rest_dur;
214       Stream_event *event = rest_events_[i];
215
216       if (need_clone)
217         event = event->clone ();
218
219       SCM pits = rest_events_[i]->get_property ("pitch");
220       event->set_property ("pitch", pits);
221       event->set_property ("duration", rest_dur.smobbed_copy ());
222       event->set_property ("length", Moment (rest_dur.get_length ()).smobbed_copy ());
223       event->set_property ("duration-log", scm_from_int (rest_dur.duration_log ()));
224
225       Item *rest = make_rest (event);
226       if (need_clone)
227         event->unprotect ();
228       rests_.push_back (rest);
229     }
230
231   left_to_do_ -= rest_dur.get_length ();
232   if (left_to_do_)
233     get_global_context ()->add_moment_to_process (now.main_part_ + rest_dur.get_length ());
234   /*
235     don't do complicated arithmetic with grace rests.
236   */
237   if (orig && now_mom ().grace_part_)
238     left_to_do_ = Rational (0, 0);
239 }
240
241 void
242 Completion_rest_engraver::stop_translation_timestep ()
243 {
244   if (rests_.size ())
245     prev_rests_ = rests_;
246   rests_.clear ();
247 }
248
249 void
250 Completion_rest_engraver::start_translation_timestep ()
251 {
252   Moment now = now_mom ();
253   if (rest_end_mom_.main_part_ <= now.main_part_)
254     {
255       rest_events_.clear ();
256       prev_rests_.clear ();
257     }
258   context ()->set_property ("restCompletionBusy",
259                             ly_bool2scm (rest_events_.size ()));
260 }
261
262 Completion_rest_engraver::Completion_rest_engraver ()
263 {
264 }
265
266 ADD_TRANSLATOR (Completion_rest_engraver,
267                 /* doc */
268                 "This engraver replaces @code{Rest_engraver}.  It plays"
269                 " some trickery to break long rests into the next measure.",
270
271                 /* create */
272                 "Rest ",
273
274                 /* read */
275                 "completionUnit "
276                 "middleCPosition "
277                 "measurePosition "
278                 "measureLength ",
279
280                 /* write */
281                 "restCompletionBusy "
282                );