]> git.donarmstrong.com Git - lilypond.git/blob - lily/completion-rest-engraver.cc
2d7dcfb8e5d2eb8c6c249e42ac147df1bcbc05a3
[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 appearance;
182   Duration *orig = 0;
183   if (left_to_do_)
184     {
185       /*
186         rest that rest_dur may be strictly less than left_to_do_
187         (say, if left_to_do_ == 5/8)
188       */
189       if (factor_.denominator () == 1 && factor_ > Rational (1, 1))
190         rest_dur = Duration (left_to_do_, false);
191       else
192         rest_dur = Duration (left_to_do_ / factor_, false).compressed (factor_);
193       appearance = Duration (left_to_do_, false);
194     }
195   else
196     {
197       orig = unsmob_duration (rest_events_[0]->get_property ("duration"));
198       rest_dur = *orig;
199       factor_ = rest_dur.factor ();
200       left_to_do_ = orig->get_length ();
201     }
202   Moment nb = next_moment (rest_dur.get_length ());
203   if (nb.main_part_ && nb < rest_dur.get_length ())
204     {
205       if (factor_.denominator () == 1 && factor_.numerator () > 1)
206         rest_dur = Duration (nb.main_part_, false);
207       else
208         rest_dur = Duration (nb.main_part_ / factor_, false).compressed (factor_);
209     }
210
211   do_nothing_until_ = now.main_part_ + rest_dur.get_length ();
212
213   for (vsize i = 0; left_to_do_ && i < rest_events_.size (); i++)
214     {
215       bool need_clone = !orig || *orig != rest_dur;
216       Stream_event *event = rest_events_[i];
217
218       if (need_clone)
219         event = event->clone ();
220
221       SCM pits = rest_events_[i]->get_property ("pitch");
222       event->set_property ("pitch", pits);
223       event->set_property ("duration", rest_dur.smobbed_copy ());
224       event->set_property ("length", Moment (rest_dur.get_length ()).smobbed_copy ());
225       event->set_property ("duration-log", scm_from_int (rest_dur.duration_log ()));
226
227       Item *rest = make_rest (event);
228       if (need_clone)
229         event->unprotect ();
230       rests_.push_back (rest);
231     }
232
233   left_to_do_ -= rest_dur.get_length ();
234   if (left_to_do_)
235     get_global_context ()->add_moment_to_process (now.main_part_ + rest_dur.get_length ());
236   /*
237     don't do complicated arithmetic with grace rests.
238   */
239   if (orig && now_mom ().grace_part_)
240     left_to_do_ = Rational (0, 0);
241 }
242
243 void
244 Completion_rest_engraver::stop_translation_timestep ()
245 {
246   if (rests_.size ())
247     prev_rests_ = rests_;
248   rests_.clear ();
249 }
250
251 void
252 Completion_rest_engraver::start_translation_timestep ()
253 {
254   Moment now = now_mom ();
255   if (rest_end_mom_.main_part_ <= now.main_part_)
256     {
257       rest_events_.clear ();
258       prev_rests_.clear ();
259     }
260   context ()->set_property ("restCompletionBusy",
261                             ly_bool2scm (rest_events_.size ()));
262 }
263
264 Completion_rest_engraver::Completion_rest_engraver ()
265 {
266 }
267
268 ADD_TRANSLATOR (Completion_rest_engraver,
269                 /* doc */
270                 "This engraver replaces @code{Rest_engraver}.  It plays"
271                 " some trickery to break long rests into the next measure.",
272
273                 /* create */
274                 "Rest ",
275
276                 /* read */
277                 "completionUnit "
278                 "middleCPosition "
279                 "measurePosition "
280                 "measureLength ",
281
282                 /* write */
283                 "restCompletionBusy "
284                );