]> git.donarmstrong.com Git - lilypond.git/blob - lily/completion-rest-engraver.cc
a60b400efce786fcf6c36de6958f8f61d42e2f82
[lilypond.git] / lily / completion-rest-engraver.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1997--2015 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
23 #include "dot-column.hh"
24 #include "dots.hh"
25 #include "duration.hh"
26 #include "global-context.hh"
27 #include "item.hh"
28 #include "output-def.hh"
29 #include "pitch.hh"
30 #include "pqueue.hh"
31 #include "rhythmic-head.hh"
32 #include "score-engraver.hh"
33 #include "spanner.hh"
34 #include "staff-symbol-referencer.hh"
35 #include "stream-event.hh"
36 #include "tie.hh"
37 #include "warn.hh"
38 #include "misc.hh"
39
40 #include "translator.icc"
41
42 using std::vector;
43
44 /*
45   How does this work?
46
47   When we catch the rest, we predict the end of the rest. We keep the
48   events living until we reach the predicted end-time.
49
50   Every time process_music () is called and there are rest events, we
51   figure out how long the rest to typeset should be. It should be no
52   longer than what's specified, than what is left to do and it should
53   not cross barlines or sub-bar units.
54
55   We copy the events into scratch rest events, to make sure that we get
56   all durations exactly right.
57 */
58
59 class Completion_rest_engraver : public Engraver
60 {
61   vector<Item *> 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_ = std::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       rest_dur = Duration (left_to_do_ / factor_, false).compressed (factor_);
189     }
190   else
191     {
192       orig = unsmob<Duration> (rest_events_[0]->get_property ("duration"));
193       rest_dur = *orig;
194       SCM factor = get_property ("completionFactor");
195       if (ly_is_procedure (factor))
196         factor = scm_call_2 (factor,
197                              context ()->self_scm (),
198                              rest_dur.smobbed_copy ());
199       factor_ = robust_scm2rational (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       rest_dur = Duration (nb.main_part_ / factor_, false).compressed (factor_);
206     }
207
208   do_nothing_until_ = now.main_part_ + rest_dur.get_length ();
209
210   for (vsize i = 0; left_to_do_ && i < rest_events_.size (); i++)
211     {
212       bool need_clone = !orig || *orig != rest_dur;
213       Stream_event *event = rest_events_[i];
214
215       if (need_clone)
216         event = event->clone ();
217
218       SCM pits = rest_events_[i]->get_property ("pitch");
219       event->set_property ("pitch", pits);
220       event->set_property ("duration", rest_dur.smobbed_copy ());
221       event->set_property ("length", Moment (rest_dur.get_length ()).smobbed_copy ());
222       event->set_property ("duration-log", scm_from_int (rest_dur.duration_log ()));
223
224       Item *rest = make_rest (event);
225       if (need_clone)
226         event->unprotect ();
227       rests_.push_back (rest);
228     }
229
230   left_to_do_ -= rest_dur.get_length ();
231   if (left_to_do_)
232     get_global_context ()->add_moment_to_process (now.main_part_ + rest_dur.get_length ());
233   /*
234     don't do complicated arithmetic with grace rests.
235   */
236   if (orig && now_mom ().grace_part_)
237     left_to_do_ = Rational (0, 0);
238 }
239
240 void
241 Completion_rest_engraver::stop_translation_timestep ()
242 {
243   rests_.clear ();
244 }
245
246 void
247 Completion_rest_engraver::start_translation_timestep ()
248 {
249   Moment now = now_mom ();
250   if (rest_end_mom_.main_part_ <= now.main_part_)
251     {
252       rest_events_.clear ();
253     }
254   context ()->set_property ("restCompletionBusy",
255                             ly_bool2scm (rest_events_.size ()));
256 }
257
258 Completion_rest_engraver::Completion_rest_engraver ()
259 {
260 }
261
262 ADD_TRANSLATOR (Completion_rest_engraver,
263                 /* doc */
264                 "This engraver replaces @code{Rest_engraver}.  It plays"
265                 " some trickery to break long rests into the next measure.",
266
267                 /* create */
268                 "Rest ",
269
270                 /* read */
271                 "completionFactor "
272                 "completionUnit "
273                 "middleCPosition "
274                 "measurePosition "
275                 "measureLength ",
276
277                 /* write */
278                 "restCompletionBusy "
279                );